UNPKG

@wix/design-system

Version:

@wix/design-system

414 lines (413 loc) 15.1 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _StatusIndicator = _interopRequireDefault(require("../StatusIndicator")); var _StatusIndicator2 = require("../StatusIndicator/StatusIndicator.constants"); var _clamp = _interopRequireDefault(require("lodash/clamp")); var _debounce = _interopRequireDefault(require("lodash/debounce")); var _isNaN = _interopRequireDefault(require("lodash/isNaN")); var _InputAreaSt = require("./InputArea.st.css.js"); var _constants = require("./constants"); var _filterObject = require("../utils/filterObject"); var _StatusContext = require("../FormField/StatusContext"); var _InputArea2 = _interopRequireDefault(require("./InputArea.semanticClassNames")); var _jsxFileName = "/home/builduser/work/57e038ea7326c1ec/packages/wix-design-system/dist/cjs/InputArea/InputArea.tsx", _InputArea; /** * General inputArea container */ class InputArea extends _react.default.PureComponent { constructor() { super(...arguments); this.textArea = null; this._computedStyle = null; this._defaultLineHeight = void 0; this.state = { focus: false, counter: (this.props.value || this.props.defaultValue || '').length, computedRows: this.props.minRowsAutoGrow }; // For testing purposes only this._getDataAttr = _ref => { var { statusContext } = _ref; var { size, status, disabled, resizable, forceHover, forceFocus } = this.props; return (0, _filterObject.filterObject)({ [_constants.dataAttr.SIZE]: size, [_constants.dataAttr.STATUS]: !disabled ? (0, _StatusContext.getStatusFromContext)(statusContext, status) : null, [_constants.dataAttr.DISABLED]: !!disabled, [_constants.dataAttr.RESIZABLE]: !!resizable && !disabled, [_constants.dataAttr.HOVER]: !!forceHover, [_constants.dataAttr.FOCUS]: !!(forceFocus || this.state.focus) }, (_, value) => !!value); }; this.focus = () => { var _this$textArea; (_this$textArea = this.textArea) == null || _this$textArea.focus(); }; this.blur = () => { var _this$textArea2; (_this$textArea2 = this.textArea) == null || _this$textArea2.blur(); }; this.select = () => { var _this$textArea3; (_this$textArea3 = this.textArea) == null || _this$textArea3.select(); }; this.calculateComputedRows = () => { var { minRowsAutoGrow, maxRowsAutoGrow } = this.props; this.setState({ computedRows: 1 }, () => { var rowsCount = this._getRowsCount(); var computedRows = (0, _clamp.default)(rowsCount, minRowsAutoGrow || InputArea.MIN_ROWS, maxRowsAutoGrow || InputArea.MAX_ROWS); this.setState({ computedRows }); }); }; this._onFocus = e => { this.setState({ focus: true }); this.props.onFocus && this.props.onFocus(e); if (this.props.autoSelect) { // Set timeout is needed here since onFocus is called before react // gets the reference for the input (specifically when autoFocus // is on. So setTimeout ensures we have the ref.input needed in select) setTimeout(() => this.select(), 0); } }; this._onBlur = e => { this.setState({ focus: false }); this.props.onBlur && this.props.onBlur(e); }; this._onKeyDown = e => { this.props.onKeyDown && this.props.onKeyDown(e); if (e.key === 'Enter') { this.props.onEnterPressed && this.props.onEnterPressed(e); } else if (e.key === 'Escape') { this.props.onEscapePressed && this.props.onEscapePressed(); } }; this._onChange = e => { this.props.onChange && this.props.onChange(e); }; this._onInput = () => { this.calculateComputedRows(); }; this._updateComputedStyle = (0, _debounce.default)(() => { if (this.textArea) { this._computedStyle = window.getComputedStyle(this.textArea); } }, 500, { leading: true }); this._getComputedStyle = () => { this._updateComputedStyle(); return this._computedStyle; }; this._getRowsCount = () => { var _computedStyle$getPro, _computedStyle$getPro2, _this$textArea$scroll, _this$textArea4; var computedStyle = this._getComputedStyle(); var fontSize = parseInt((_computedStyle$getPro = computedStyle == null ? void 0 : computedStyle.getPropertyValue('font-size')) !== null && _computedStyle$getPro !== void 0 ? _computedStyle$getPro : '', 10); var lineHeight = parseInt((_computedStyle$getPro2 = computedStyle == null ? void 0 : computedStyle.getPropertyValue('line-height')) !== null && _computedStyle$getPro2 !== void 0 ? _computedStyle$getPro2 : '', 10); var lineHeightValue; if ((0, _isNaN.default)(lineHeight)) { var _this$_getDefaultLine; if ((0, _isNaN.default)(fontSize)) { return InputArea.MIN_ROWS; } lineHeightValue = (_this$_getDefaultLine = this._getDefaultLineHeight()) !== null && _this$_getDefaultLine !== void 0 ? _this$_getDefaultLine : 0 * fontSize; } else { lineHeightValue = lineHeight; } return Math.floor(((_this$textArea$scroll = (_this$textArea4 = this.textArea) == null ? void 0 : _this$textArea4.scrollHeight) !== null && _this$textArea$scroll !== void 0 ? _this$textArea$scroll : 0) / lineHeightValue); }; this._getDefaultLineHeight = () => { if (!this._defaultLineHeight && this.textArea) { var _tempElement$parentNo; var { parentNode } = this.textArea; var computedStyles = this._getComputedStyle(); var fontFamily = computedStyles == null ? void 0 : computedStyles.getPropertyValue('font-family'); var fontSize = computedStyles == null ? void 0 : computedStyles.getPropertyValue('font-size'); var tempElement = document.createElement('span'); var defaultStyles = 'position:absolute;display:inline;border:0;margin:0;padding:0;line-height:normal;'; tempElement.setAttribute('style', "".concat(defaultStyles, "font-family:").concat(fontFamily, ";font-size:").concat(fontSize, ";")); tempElement.innerText = 'M'; parentNode == null || parentNode.appendChild(tempElement); this._defaultLineHeight = parseInt(tempElement.clientHeight.toString(), 10) / parseInt(fontSize !== null && fontSize !== void 0 ? fontSize : '0', 10); (_tempElement$parentNo = tempElement.parentNode) == null || _tempElement$parentNo.removeChild(tempElement); } return this._defaultLineHeight; }; } componentDidMount() { var { autoFocus, autoGrow, value } = this.props; autoFocus && this._onFocus(); if (autoGrow) { this.calculateComputedRows(); } /* * autoFocus doesn't automatically selects text like focus do. * Therefore we set the selection range, but in order to support prior implementation we set the start position as the end in order to place the cursor there. */ if (autoFocus && !!value) { var _this$textArea5; (_this$textArea5 = this.textArea) == null || _this$textArea5.setSelectionRange(value.length, value.length); } } componentDidUpdate(prevProps) { var { minRowsAutoGrow, maxRowsAutoGrow, value, defaultValue, autoGrow, hasCounter } = this.props; if (autoGrow && (prevProps.minRowsAutoGrow !== minRowsAutoGrow || prevProps.maxRowsAutoGrow !== maxRowsAutoGrow)) { this.calculateComputedRows(); } if (hasCounter && prevProps.value !== value) { this.setState({ counter: (value || defaultValue || '').length }); } } componentWillUnmount() { this._updateComputedStyle.cancel(); } render() { var { dataHook, className, autoFocus, defaultValue, disabled, forceFocus, forceHover, id, name, onKeyUp, placeholder, readOnly, tabIndex, rows, autoGrow, value, required, minHeight, maxHeight, maxLength, resizable, hasCounter, size, tooltipPlacement, status, statusMessage, children, onCompositionStart, onCompositionEnd, dir } = this.props; var inlineStyle = {}; var rowsAttr = rows ? rows : autoGrow ? this.state.computedRows : undefined; var onInput = !rows && autoGrow ? this._onInput : undefined; if (minHeight) { inlineStyle.minHeight = minHeight; } if (maxHeight) { inlineStyle.maxHeight = maxHeight; } var ariaAttribute = {}; Object.keys(this.props).filter(key => key.startsWith('aria')).map(key => ariaAttribute['aria-' + key.substr(4).toLowerCase()] = this.props[key]); return /*#__PURE__*/_react.default.createElement(_StatusContext.StatusContext.Consumer, { __self: this, __source: { fileName: _jsxFileName, lineNumber: 224, columnNumber: 7 } }, statusContext => { var finalStatus = (0, _StatusContext.getStatusFromContext)(statusContext, status); return /*#__PURE__*/_react.default.createElement("div", (0, _extends2.default)({ "data-hook": dataHook, className: (0, _InputAreaSt.st)(_InputAreaSt.classes.root, { disabled, size, status: finalStatus, hasFocus: forceFocus || this.state.focus, forceHover, resizable, readOnly }, className) }, this._getDataAttr({ statusContext }), { __self: this, __source: { fileName: _jsxFileName, lineNumber: 229, columnNumber: 13 } }), /*#__PURE__*/_react.default.createElement("div", { className: (0, _InputAreaSt.st)(_InputAreaSt.classes.inputArea, _InputArea2.default.inputContainer), __self: this, __source: { fileName: _jsxFileName, lineNumber: 247, columnNumber: 15 } }, typeof children === 'function' ? children({ className: '', rows: rowsAttr || 0, ref: _ref2 => this.textArea = _ref2, onFocus: e => this._onFocus(e), onBlur: e => this._onBlur(e), onKeyDown: e => this._onKeyDown(e), onInput, dir }) : /*#__PURE__*/_react.default.createElement("textarea", (0, _extends2.default)({ rows: rowsAttr, maxLength: maxLength, ref: _ref3 => this.textArea = _ref3, id: id, name: name, style: inlineStyle, defaultValue: defaultValue, disabled: disabled, value: value, required: required, onFocus: this._onFocus, onBlur: this._onBlur, onKeyDown: this._onKeyDown, onChange: this._onChange, onInput: onInput, placeholder: placeholder, tabIndex: tabIndex, autoFocus: autoFocus, onKeyUp: onKeyUp }, (0, _StatusContext.getAriaAttributesFromContext)(statusContext), ariaAttribute, { readOnly: readOnly, onCompositionStart: onCompositionStart, onCompositionEnd: onCompositionEnd, dir: dir, __self: this, __source: { fileName: _jsxFileName, lineNumber: 270, columnNumber: 19 } })), hasCounter && maxLength && /*#__PURE__*/_react.default.createElement("span", { className: _InputAreaSt.classes.counter, "data-hook": "counter", __self: this, __source: { fileName: _jsxFileName, lineNumber: 301, columnNumber: 19 } }, this.state.counter, "/", maxLength)), /*#__PURE__*/_react.default.createElement("div", { className: _InputAreaSt.classes.status, __self: this, __source: { fileName: _jsxFileName, lineNumber: 308, columnNumber: 15 } }, (!!status || finalStatus === _StatusIndicator2.STATUS.LOADING) && !disabled && /*#__PURE__*/_react.default.createElement(_StatusIndicator.default, { dataHook: _constants.dataHooks.tooltip, status: finalStatus !== null && finalStatus !== void 0 ? finalStatus : undefined, message: statusMessage, tooltipProps: { placement: tooltipPlacement }, __self: this, __source: { fileName: _jsxFileName, lineNumber: 310, columnNumber: 19 } }))); }); } } _InputArea = InputArea; // For autoGrow prop min rows is 2 so the textarea does not look like an input InputArea.MIN_ROWS = 2; // For autoGrow prop max rows is Infinity to keep backwards compatibility InputArea.MAX_ROWS = Number.POSITIVE_INFINITY; InputArea.displayName = 'InputArea'; InputArea.defaultProps = { minRowsAutoGrow: _InputArea.MIN_ROWS, maxRowsAutoGrow: _InputArea.MAX_ROWS, size: 'medium' }; InputArea.propTypes = { dataHook: _propTypes.default.string, className: _propTypes.default.string, children: _propTypes.default.func, ariaControls: _propTypes.default.string, ariaDescribedby: _propTypes.default.string, ariaLabel: _propTypes.default.string, autoFocus: _propTypes.default.bool, size: _propTypes.default.oneOf(['small', 'medium']), defaultValue: _propTypes.default.string, disabled: _propTypes.default.bool, status: _propTypes.default.oneOf(['error', 'warning', 'loading']), statusMessage: _propTypes.default.node, forceFocus: _propTypes.default.bool, forceHover: _propTypes.default.bool, hasCounter: _propTypes.default.bool, id: _propTypes.default.string, name: _propTypes.default.string, maxHeight: _propTypes.default.string, maxLength: _propTypes.default.number, minHeight: _propTypes.default.string, onBlur: _propTypes.default.func, onChange: _propTypes.default.func, onEnterPressed: _propTypes.default.func, onEscapePressed: _propTypes.default.func, onFocus: _propTypes.default.func, onKeyDown: _propTypes.default.func, onKeyUp: _propTypes.default.func, onCompositionStart: _propTypes.default.func, onCompositionEnd: _propTypes.default.func, placeholder: _propTypes.default.string, readOnly: _propTypes.default.bool, resizable: _propTypes.default.bool, rows: _propTypes.default.number, autoGrow: _propTypes.default.bool, minRowsAutoGrow: _propTypes.default.number, maxRowsAutoGrow: _propTypes.default.number, tabIndex: _propTypes.default.number, tooltipPlacement: _propTypes.default.string, value: _propTypes.default.string, required: _propTypes.default.bool, dir: _propTypes.default.oneOf(['ltr', 'rtl', 'auto']) }; var _default = exports.default = InputArea; //# sourceMappingURL=InputArea.js.map