UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

202 lines (157 loc) 6.37 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.default = exports.InputResizer = exports.OFFSET_CHAR = void 0; var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _react = _interopRequireDefault(require("react")); var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps")); var _propTypes = _interopRequireDefault(require("prop-types")); var _EventListener = _interopRequireDefault(require("../EventListener")); var _classnames = _interopRequireDefault(require("classnames")); var _InputResizer = require("./Input.Resizer.css"); var _jsxRuntime = require("react/jsx-runtime"); // Thanks Stephen <3 var OFFSET_CHAR = 'R'; exports.OFFSET_CHAR = OFFSET_CHAR; var ENTITIES_TO_REPLACE = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '\n': '<br>' }; var REPLACE_REGEX = /[\n&<>]/g; var InputResizer = /*#__PURE__*/function (_React$PureComponent) { (0, _inheritsLoose2.default)(InputResizer, _React$PureComponent); function InputResizer() { var _this; for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _this = _React$PureComponent.call.apply(_React$PureComponent, [this].concat(args)) || this; _this.contentNode = void 0; _this.minimumLinesNode = void 0; _this._isMounted = false; _this.handleOnResize = function () { if (!_this.contentNode || !_this.minimumLinesNode) return; var contentHeight = _this.contentNode.offsetHeight; var minimumHeight = _this.minimumLinesNode ? _this.minimumLinesNode.offsetHeight : 0; var newHeight = Math.max(contentHeight, minimumHeight); var _this$props = _this.props, currentHeight = _this$props.currentHeight, onResize = _this$props.onResize; if (newHeight !== currentHeight) { onResize(newHeight); } }; _this.setMinimumLinesNode = function (node) { return _this.minimumLinesNode = node; }; _this.setContentNodeRef = function (node) { return _this.contentNode = node; }; return _this; } var _proto = InputResizer.prototype; _proto.componentDidMount = function componentDidMount() { var _this2 = this; this._isMounted = true; this.handleOnResize(); // Re-trigger to help recalculate when used within heavier components/views. requestAnimationFrame(function () { if (_this2._isMounted) { _this2.handleOnResize(); } }); }; _proto.componentWillUnmount = function componentWillUnmount() { this._isMounted = false; }; _proto.componentDidUpdate = function componentDidUpdate() { this.handleOnResize(); }; _proto.getClassName = function getClassName() { var className = this.props.className; return (0, _classnames.default)(InputResizer.className, className); }; _proto.getContentClassName = function getContentClassName() { var seamless = this.props.seamless; return (0, _classnames.default)('c-InputGhost', 'c-InputGhost--characters', seamless && 'is-seamless'); } // Ignoring as height calculation isn't possible with JSDOM // (which is what Enzyme uses for tests) ; _proto.replaceEntity = function replaceEntity(entity) { return ENTITIES_TO_REPLACE[entity] || entity; }; _proto.getContentsForMinimumLines = function getContentsForMinimumLines(minimumLines) { var content = ''; for (var line = 0; line < minimumLines; line++) { content += '<br>'; } return content; }; _proto.getFinalContents = function getFinalContents(contents) { var charOffset = OFFSET_CHAR.repeat(this.props.offsetAmount); return contents ? contents.replace(REPLACE_REGEX, this.replaceEntity).concat(charOffset) + "<br>" : '<br>'; }; _proto.renderMinimumLines = function renderMinimumLines() { var minimumLines = this.props.minimumLines; if (!minimumLines) return; return /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputResizer.GhostUI, { ref: this.setMinimumLinesNode, className: this.getContentClassName(), dangerouslySetInnerHTML: { __html: this.getContentsForMinimumLines(minimumLines) } }); }; _proto.render = function render() { var _this$props2 = this.props, contents = _this$props2.contents, rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props2, ["contents"]); return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_InputResizer.ResizerUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), { "aria-hidden": true, className: this.getClassName(), children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_EventListener.default, { event: "resize", handler: this.handleOnResize }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_InputResizer.GhostUI, { ref: this.setContentNodeRef, className: this.getContentClassName(), dangerouslySetInnerHTML: { __html: this.getFinalContents(contents) } }), this.renderMinimumLines()] })); }; return InputResizer; }(_react.default.PureComponent); exports.InputResizer = InputResizer; InputResizer.className = 'c-InputResizer'; function noop() {} InputResizer.defaultProps = { contents: '', currentHeight: null, 'data-cy': 'InputResizer', minimumLines: 1, offsetAmount: 0, onResize: noop, seamless: false }; InputResizer.propTypes = { /** Custom class names to be added to the component. */ className: _propTypes.default.string, contents: _propTypes.default.string, currentHeight: _propTypes.default.number, minimumLines: _propTypes.default.number, /** Number of characters to offset (bottom-right) for multiline resizing. */ offsetAmount: _propTypes.default.number, /** Callback when input is resized. */ onResize: _propTypes.default.func, /** Removes the border around the input. */ seamless: _propTypes.default.bool, /** Data attr for Cypress tests. */ 'data-cy': _propTypes.default.string }; var _default = InputResizer; exports.default = _default;