UNPKG

wix-style-react

Version:
489 lines (396 loc) • 19.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck")); var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass")); var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized")); var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits")); var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn")); var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf")); var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _deprecationLog = _interopRequireDefault(require("../utils/deprecationLog")); var _StatusIndicator = _interopRequireDefault(require("../StatusIndicator")); var _debounce = _interopRequireDefault(require("lodash/debounce")); var _isNaN = _interopRequireDefault(require("lodash/isNaN")); var _InputAreaSt = require("./InputArea.st.css"); var _constants = require("./constants"); var _filterObject2 = require("../utils/filterObject"); var _context = require("../FontUpgrade/context"); function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; } function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } /** * General inputArea container */ var InputArea = /*#__PURE__*/function (_React$PureComponent) { (0, _inherits2["default"])(InputArea, _React$PureComponent); var _super = _createSuper(InputArea); // For autoGrow prop min rows is 2 so the textarea does not look like an input function InputArea(props) { var _this; (0, _classCallCheck2["default"])(this, InputArea); _this = _super.call(this, props); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_computedStyle", null); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "state", { focus: false, counter: (_this.props.value || _this.props.defaultValue || '').length, computedRows: _this.props.minRowsAutoGrow }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getDataAttr", function () { var _filterObject; var _this$props = _this.props, size = _this$props.size, status = _this$props.status, disabled = _this$props.disabled, resizable = _this$props.resizable, forceHover = _this$props.forceHover, forceFocus = _this$props.forceFocus; return (0, _filterObject2.filterObject)((_filterObject = {}, (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.SIZE, size), (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.STATUS, !!status && !disabled), (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.DISABLED, !!disabled), (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.RESIZABLE, !!resizable && !disabled), (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.HOVER, !!forceHover), (0, _defineProperty2["default"])(_filterObject, _constants.dataAttr.FOCUS, !!(forceFocus || _this.state.focus)), _filterObject), function (key, value) { return !!value; }); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "focus", function () { _this.textArea && _this.textArea.focus(); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "blur", function () { _this.textArea && _this.textArea.blur(); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "select", function () { _this.textArea && _this.textArea.select(); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_onFocus", function (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(function () { return _this.select(); }, 0); } }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_onBlur", function (e) { _this.setState({ focus: false }); _this.props.onBlur && _this.props.onBlur(e); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_onKeyDown", function (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(); } }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_onChange", function (e) { _this.props.onChange && _this.props.onChange(e); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_onInput", function () { _this._calculateComputedRows(); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_calculateComputedRows", function () { var minRowsAutoGrow = _this.props.minRowsAutoGrow; _this.setState({ computedRows: 1 }, function () { var rowsCount = _this._getRowsCount(); var computedRows = Math.max(minRowsAutoGrow, rowsCount); _this.setState({ computedRows: computedRows }); }); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_updateComputedStyle", (0, _debounce["default"])(function () { _this._computedStyle = window.getComputedStyle(_this.textArea); }, 500, { leading: true })); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getComputedStyle", function () { _this._updateComputedStyle(); return _this._computedStyle; }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getRowsCount", function () { var computedStyle = _this._getComputedStyle(); var fontSize = parseInt(computedStyle.getPropertyValue('font-size'), 10); var lineHeight = parseInt(computedStyle.getPropertyValue('line-height'), 10); var lineHeightValue; if ((0, _isNaN["default"])(lineHeight)) { if ((0, _isNaN["default"])(fontSize)) { return InputArea.MIN_ROWS; } lineHeightValue = _this._getDefaultLineHeight() * fontSize; } else { lineHeightValue = lineHeight; } return Math.floor(_this.textArea.scrollHeight / lineHeightValue); }); (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "_getDefaultLineHeight", function () { if (!_this._defaultLineHeight) { var parentNode = _this.textArea.parentNode; var computedStyles = _this._getComputedStyle(); var fontFamily = computedStyles.getPropertyValue('font-family'); var fontSize = 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.appendChild(tempElement); _this._defaultLineHeight = parseInt(tempElement.clientHeight, 10) / parseInt(fontSize, 10); tempElement.parentNode.removeChild(tempElement); } return _this._defaultLineHeight; }); if (props.size === 'normal') { (0, _deprecationLog["default"])('<InputArea/> - change prop size="normal" to size="medium"'); } return _this; } // For testing purposes only (0, _createClass2["default"])(InputArea, [{ key: "componentDidMount", value: function componentDidMount() { var _this$props2 = this.props, autoFocus = _this$props2.autoFocus, autoGrow = _this$props2.autoGrow, value = _this$props2.value; 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) { this.textArea.setSelectionRange(value.length, value.length); } } }, { key: "componentDidUpdate", value: function componentDidUpdate(prevProps) { var _this$props3 = this.props, minRowsAutoGrow = _this$props3.minRowsAutoGrow, value = _this$props3.value, defaultValue = _this$props3.defaultValue, autoGrow = _this$props3.autoGrow, hasCounter = _this$props3.hasCounter; if (autoGrow && prevProps.minRowsAutoGrow !== minRowsAutoGrow) { this._calculateComputedRows(); } if (hasCounter && prevProps.value !== value) { this.setState({ counter: (value || defaultValue || '').length }); } } }, { key: "componentWillUnmount", value: function componentWillUnmount() { this._updateComputedStyle.cancel(); } }, { key: "render", value: function render() { var _this2 = this; var _this$props4 = this.props, dataHook = _this$props4.dataHook, className = _this$props4.className, autoFocus = _this$props4.autoFocus, defaultValue = _this$props4.defaultValue, disabled = _this$props4.disabled, forceFocus = _this$props4.forceFocus, forceHover = _this$props4.forceHover, id = _this$props4.id, name = _this$props4.name, onKeyUp = _this$props4.onKeyUp, placeholder = _this$props4.placeholder, readOnly = _this$props4.readOnly, tabIndex = _this$props4.tabIndex, rows = _this$props4.rows, autoGrow = _this$props4.autoGrow, value = _this$props4.value, required = _this$props4.required, minHeight = _this$props4.minHeight, maxHeight = _this$props4.maxHeight, maxLength = _this$props4.maxLength, resizable = _this$props4.resizable, hasCounter = _this$props4.hasCounter, size = _this$props4.size, tooltipPlacement = _this$props4.tooltipPlacement, status = _this$props4.status, statusMessage = _this$props4.statusMessage, children = _this$props4.children; 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(function (key) { return key.startsWith('aria'); }).map(function (key) { return ariaAttribute['aria-' + key.substr(4).toLowerCase()] = _this2.props[key]; }); return /*#__PURE__*/_react["default"].createElement(_context.FontUpgradeContext.Consumer, null, function (_ref) { var isMadefor = _ref.active; return /*#__PURE__*/_react["default"].createElement("div", (0, _extends2["default"])({ "data-hook": dataHook, className: (0, _InputAreaSt.st)(_InputAreaSt.classes.root, { isMadefor: isMadefor, disabled: disabled, size: size, status: status, hasFocus: forceFocus || _this2.state.focus, forceHover: forceHover, resizable: resizable, readOnly: readOnly }, className) }, _this2._getDataAttr()), /*#__PURE__*/_react["default"].createElement("div", { className: _InputAreaSt.classes.inputArea }, typeof children === 'function' ? children({ rows: rowsAttr, ref: function ref(_ref2) { return _this2.textArea = _ref2; }, onFocus: _this2._onFocus, onBlur: _this2._onBlur, onKeyDown: _this2._onKeyDown, onInput: onInput }) : /*#__PURE__*/_react["default"].createElement("textarea", (0, _extends2["default"])({ rows: rowsAttr, maxLength: maxLength, ref: function ref(_ref3) { return _this2.textArea = _ref3; }, id: id, name: name, style: inlineStyle, defaultValue: defaultValue, disabled: disabled, value: value, required: required, onFocus: _this2._onFocus, onBlur: _this2._onBlur, onKeyDown: _this2._onKeyDown, onChange: _this2._onChange, onInput: onInput, placeholder: placeholder, tabIndex: tabIndex, autoFocus: autoFocus, onKeyUp: onKeyUp }, ariaAttribute, { readOnly: readOnly })), hasCounter && maxLength && /*#__PURE__*/_react["default"].createElement("span", { className: _InputAreaSt.classes.counter, "data-hook": "counter" }, _this2.state.counter, "/", maxLength)), /*#__PURE__*/_react["default"].createElement("div", { className: _InputAreaSt.classes.status }, !!status && !disabled && /*#__PURE__*/_react["default"].createElement(_StatusIndicator["default"], { dataHook: _constants.dataHooks.tooltip, status: status, message: statusMessage, tooltipPlacement: tooltipPlacement }))); }); } }]); return InputArea; }(_react["default"].PureComponent); (0, _defineProperty2["default"])(InputArea, "MIN_ROWS", 2); InputArea.displayName = 'InputArea'; InputArea.defaultProps = { minRowsAutoGrow: InputArea.MIN_ROWS, size: 'medium' }; InputArea.propTypes = { /** Applies a data-hook HTML attribute that can be used in the tests. */ dataHook: _propTypes["default"].string, /** Specifies a CSS class name to be appended to the component’s root element. */ className: _propTypes["default"].string, /** Specifies custom textarea render function */ children: _propTypes["default"].func, /** Associate a control with the regions that it controls. */ ariaControls: _propTypes["default"].string, /** Associate a region with its descriptions. Similar to aria-controls but instead associating descriptions to the region and description identifiers are separated with a space. */ ariaDescribedby: _propTypes["default"].string, /** Define a string that labels the current element in case where a text label is not visible on the screen. */ ariaLabel: _propTypes["default"].string, /** Focus the element on mount (standard React input autoFocus). */ autoFocus: _propTypes["default"].bool, /** Select the entire text of the element on focus (standard React input autoSelect). */ autoSelect: _propTypes["default"].bool, /** Controls the size of the input. */ size: _propTypes["default"].oneOf(['small', 'medium']), /** Sets a default value for those who want to use this component un-controlled. */ defaultValue: _propTypes["default"].string, /** Specifies whether input should be disabled. */ disabled: _propTypes["default"].bool, /** Specifies the status of a field. */ status: _propTypes["default"].oneOf(['error', 'warning', 'loading']), /** Defines the message to display on status icon hover. If not given or empty there will be no tooltip. */ statusMessage: _propTypes["default"].node, /** USED FOR TESTING. Forces focus state on the input. */ forceFocus: _propTypes["default"].bool, /** USED FOR TESTING. Forces hover state on the input. */ forceHover: _propTypes["default"].bool, /** Specifies whether character count is enabled. */ hasCounter: _propTypes["default"].bool, /** Assigns an unique identifier for the root element. */ id: _propTypes["default"].string, /** Reference element data when a form is submitted. */ name: _propTypes["default"].string, /** Sets the maximum height of an area in pixels. */ maxHeight: _propTypes["default"].string, /** Defines the maximum text length in number of characters. */ maxLength: _propTypes["default"].number, /** Sets the minimum height of an area in pixels. */ minHeight: _propTypes["default"].string, /** Defines a standard input onBlur callback */ onBlur: _propTypes["default"].func, /** Defines a standard input onChange callback. */ onChange: _propTypes["default"].func, /** Defines a callback handler that is called when user presses enter. */ onEnterPressed: _propTypes["default"].func, /** Defines a callback handler that is called when user presses escape. */ onEscapePressed: _propTypes["default"].func, /** Defines a standard input onFocus callback. */ onFocus: _propTypes["default"].func, /** Defines a standard input onKeyDown callback. */ onKeyDown: _propTypes["default"].func, /** Defines a standard input onKeyUp callback. */ onKeyUp: _propTypes["default"].func, /** Sets a placeholder message to display. */ placeholder: _propTypes["default"].string, /** Specifies whether input is read only. */ readOnly: _propTypes["default"].bool, /** Specifies whether area can be manually resized by the user. */ resizable: _propTypes["default"].bool, /** Sets initial height of an area to fit a specified number of rows. */ rows: _propTypes["default"].number, /** Specifies whether area should grow and shrink according to user input. */ autoGrow: _propTypes["default"].bool, /** Sets the minimum amount of rows the component can have in `autoGrow` mode */ minRowsAutoGrow: _propTypes["default"].number, /** Indicates that element can be focused and where it participates in sequential keyboard navigation. */ tabIndex: _propTypes["default"].number, /** Controls placement of a status tooltip. */ tooltipPlacement: _propTypes["default"].string, /** Defines input value. */ value: _propTypes["default"].string, /** Specifies whether the input area is a mandatory field. */ required: _propTypes["default"].bool }; var _default = InputArea; exports["default"] = _default;