wix-style-react
Version:
489 lines (396 loc) • 19.8 kB
JavaScript
"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;