ExamplesPlaygroundReference Source

coral-spectrum/coral-component-textarea/src/scripts/Textarea.js

  1. /**
  2. * Copyright 2019 Adobe. All rights reserved.
  3. * This file is licensed to you under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License. You may obtain a copy
  5. * of the License at http://www.apache.org/licenses/LICENSE-2.0
  6. *
  7. * Unless required by applicable law or agreed to in writing, software distributed under
  8. * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
  9. * OF ANY KIND, either express or implied. See the License for the specific language
  10. * governing permissions and limitations under the License.
  11. */
  12.  
  13. import {BaseComponent} from '../../../coral-base-component';
  14. import {BaseFormField} from '../../../coral-base-formfield';
  15. // todo ideally there should be a coral-base-textfield to inherit from
  16. import '../../../coral-component-textfield';
  17. import {transform, validate, commons} from '../../../coral-utils';
  18. import {Decorator} from '../../../coral-decorator';
  19.  
  20. const CLASSNAME = '_coral-Textfield';
  21.  
  22. /**
  23. Enumeration for {@link Textarea} variants.
  24.  
  25. @typedef {Object} TextareaVariantEnum
  26.  
  27. @property {String} DEFAULT
  28. A default textarea.
  29. @property {String} QUIET
  30. A textarea with no border or background.
  31. */
  32. const variant = {
  33. DEFAULT: 'default',
  34. QUIET: 'quiet'
  35. };
  36.  
  37. // Builds a string containing all possible variant classnames. This will be used to remove classnames when the variant
  38. // changes
  39. const ALL_VARIANT_CLASSES = [];
  40. for (const variantValue in variant) {
  41. ALL_VARIANT_CLASSES.push(`${CLASSNAME}--${variant[variantValue]}`);
  42. }
  43.  
  44. /**
  45. @class Coral.Textarea
  46. @classdesc A Textarea component is the default multi-line text form field.
  47. @htmltag coral-textarea
  48. @htmlbasetag textarea
  49. @extends {HTMLTextAreaElement}
  50. @extends {BaseComponent}
  51. @extends {BaseFormField}
  52. */
  53. const Textarea = Decorator(class extends BaseFormField(BaseComponent(HTMLTextAreaElement)) {
  54. /** @ignore */
  55. constructor() {
  56. super();
  57.  
  58. this._delegateEvents(commons.extend(this._events, {
  59. input: '_onInput'
  60. }));
  61. }
  62.  
  63. /**
  64. The textarea's variant. See {@link TextareaVariantEnum}.
  65.  
  66. @type {String}
  67. @default TextareaVariantEnum.DEFAULT
  68. @htmlattribute variant
  69. @htmlattributereflected
  70. */
  71. get variant() {
  72. return this._variant || variant.DEFAULT;
  73. }
  74.  
  75. set variant(value) {
  76. value = transform.string(value).toLowerCase();
  77. this._variant = validate.enumeration(variant)(value) && value || variant.DEFAULT;
  78. this._reflectAttribute('variant', this._variant);
  79.  
  80. // removes every existing variant
  81. this.classList.remove(...ALL_VARIANT_CLASSES);
  82.  
  83. if (this._variant !== variant.DEFAULT) {
  84. this.classList.add(`${CLASSNAME}--${this._variant}`);
  85. }
  86.  
  87. // Restore the original height
  88. if (this._variant === variant.QUIET) {
  89. this._defaultHeight = this._defaultHeight || this.style.height;
  90. } else {
  91. this.style.height = this._defaultHeight;
  92. this._defaultHeight = undefined;
  93. }
  94.  
  95. this._onInput();
  96. }
  97.  
  98. /**
  99. Inherited from {@link BaseFormField#reset}.
  100. */
  101. reset() {
  102. // The textarea uses the textContent to save the old value and not the value attribute
  103. /** @ignore */
  104. this.value = this.textContent;
  105.  
  106. // Reset height if quiet variant
  107. this._onInput();
  108. }
  109.  
  110. /** @private */
  111. _onInput() {
  112. if (this.variant === variant.QUIET) {
  113. requestAnimationFrame(() => {
  114. this.style.height = 'auto';
  115. this.style.height = `${this.scrollHeight}px`;
  116. });
  117. }
  118. }
  119.  
  120. /**
  121. Returns {@link Textarea} variants.
  122.  
  123. @return {TextareaVariantEnum}
  124. */
  125. static get variant() {
  126. return variant;
  127. }
  128.  
  129. /** @ignore */
  130. static get observedAttributes() {
  131. return super._nativeObservedAttributes.concat(['variant']);
  132. }
  133.  
  134. /** @ignore */
  135. render() {
  136. super.render();
  137.  
  138. this.classList.add(CLASSNAME, `${CLASSNAME}--multiline`);
  139.  
  140. // Default reflected attributes
  141. if (!this._variant) {
  142. this.variant = variant.DEFAULT;
  143. }
  144. }
  145. });
  146.  
  147. export default Textarea;