coral-spectrum/coral-component-textarea/src/scripts/Textarea.js
/**
* Copyright 2019 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import {BaseComponent} from '../../../coral-base-component';
import {BaseFormField} from '../../../coral-base-formfield';
// todo ideally there should be a coral-base-textfield to inherit from
import '../../../coral-component-textfield';
import {transform, validate, commons} from '../../../coral-utils';
import {Decorator} from '../../../coral-decorator';
const CLASSNAME = '_coral-Textfield';
/**
Enumeration for {@link Textarea} variants.
@typedef {Object} TextareaVariantEnum
@property {String} DEFAULT
A default textarea.
@property {String} QUIET
A textarea with no border or background.
*/
const variant = {
DEFAULT: 'default',
QUIET: 'quiet'
};
// Builds a string containing all possible variant classnames. This will be used to remove classnames when the variant
// changes
const ALL_VARIANT_CLASSES = [];
for (const variantValue in variant) {
ALL_VARIANT_CLASSES.push(`${CLASSNAME}--${variant[variantValue]}`);
}
/**
@class Coral.Textarea
@classdesc A Textarea component is the default multi-line text form field.
@htmltag coral-textarea
@htmlbasetag textarea
@extends {HTMLTextAreaElement}
@extends {BaseComponent}
@extends {BaseFormField}
*/
const Textarea = Decorator(class extends BaseFormField(BaseComponent(HTMLTextAreaElement)) {
/** @ignore */
constructor() {
super();
this._delegateEvents(commons.extend(this._events, {
input: '_onInput'
}));
}
/**
The textarea's variant. See {@link TextareaVariantEnum}.
@type {String}
@default TextareaVariantEnum.DEFAULT
@htmlattribute variant
@htmlattributereflected
*/
get variant() {
return this._variant || variant.DEFAULT;
}
set variant(value) {
value = transform.string(value).toLowerCase();
this._variant = validate.enumeration(variant)(value) && value || variant.DEFAULT;
this._reflectAttribute('variant', this._variant);
// removes every existing variant
this.classList.remove(...ALL_VARIANT_CLASSES);
if (this._variant !== variant.DEFAULT) {
this.classList.add(`${CLASSNAME}--${this._variant}`);
}
// Restore the original height
if (this._variant === variant.QUIET) {
this._defaultHeight = this._defaultHeight || this.style.height;
} else {
this.style.height = this._defaultHeight;
this._defaultHeight = undefined;
}
this._onInput();
}
/**
Inherited from {@link BaseFormField#reset}.
*/
reset() {
// The textarea uses the textContent to save the old value and not the value attribute
/** @ignore */
this.value = this.textContent;
// Reset height if quiet variant
this._onInput();
}
/** @private */
_onInput() {
if (this.variant === variant.QUIET) {
requestAnimationFrame(() => {
this.style.height = 'auto';
this.style.height = `${this.scrollHeight}px`;
});
}
}
/**
Returns {@link Textarea} variants.
@return {TextareaVariantEnum}
*/
static get variant() {
return variant;
}
/** @ignore */
static get observedAttributes() {
return super._nativeObservedAttributes.concat(['variant']);
}
/** @ignore */
render() {
super.render();
this.classList.add(CLASSNAME, `${CLASSNAME}--multiline`);
// Default reflected attributes
if (!this._variant) {
this.variant = variant.DEFAULT;
}
}
});
export default Textarea;