@wix/design-system
Version:
@wix/design-system
414 lines (413 loc) • 15.1 kB
JavaScript
"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