UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

285 lines (229 loc) 9.16 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); exports.__esModule = true; exports.getTruncatedContent = getTruncatedContent; exports.default = exports.Truncate = void 0; var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _inheritsLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/inheritsLoose")); var _react = _interopRequireDefault(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _getValidProps = _interopRequireDefault(require("@helpscout/react-utils/dist/getValidProps")); var _EventListener = _interopRequireDefault(require("../EventListener")); var _Tooltip = _interopRequireDefault(require("../Tooltip")); var _Truncate = require("./Truncate.css"); var _Truncate2 = require("./Truncate.utils"); var _jsxRuntime = require("react/jsx-runtime"); var Truncate = /*#__PURE__*/function (_React$PureComponent) { (0, _inheritsLoose2.default)(Truncate, _React$PureComponent); function Truncate(_props) { var _this; _this = _React$PureComponent.call(this, _props) || this; _this.node = null; _this.contentNode = null; _this._isMounted = false; _this.handleOnResize = function () { if (!_this.props.showTooltipOnTruncate) return; var isTruncated = _this.isTruncated(_this.props); if (isTruncated === _this.state.isTruncated) return; _this.setState({ isTruncated: isTruncated }); }; _this.isTruncated = function (props) { if (props === void 0) { props = _this.props; } if (props.type !== 'auto') { return _this.getText(props) !== _this.getTruncatedContent(props); } else { if (!_this.node || !_this.contentNode) return false; var isContentTruncated = props.splitter ? _this.isSplitContentTruncated(_this.contentNode, _this.node) : _this.contentNode.scrollWidth > _this.node.offsetWidth; return isContentTruncated; } }; _this.isSplitContentTruncated = function (contentNode, node) { return contentNode.offsetWidth < node.querySelector("." + _Truncate2.TRUNCATED_CLASSNAMES.firstChunk).scrollWidth + node.querySelector("." + _Truncate2.TRUNCATED_CLASSNAMES.secondChunk).scrollWidth; }; _this.getText = function (props) { if (props === void 0) { props = _this.props; } return _this.props.text || _this.props.children; }; _this.getTruncatedContent = function (props) { if (props === void 0) { props = _this.props; } return getTruncatedContent((0, _extends2.default)({}, props, { text: _this.getText(props) })); }; _this.state = { isTruncated: !!_props.type }; return _this; } var _proto = Truncate.prototype; _proto.componentDidMount = function componentDidMount() { var _this2 = this; this._isMounted = true; // The timeout is necessary to ensure the `isTruncated` calculation // happens after the content has been rendered to the page. The // _isMounted guard is necessary because sometimes the callback // will run after the component has been unmounted, which results // in a warning. setTimeout(function () { if (_this2.props.type === 'auto' && _this2._isMounted) { _this2.setState({ isTruncated: _this2.isTruncated(_this2.props) }); } }, 0); }; _proto.componentWillUnmount = function componentWillUnmount() { this.node = null; this.contentNode = null; this._isMounted = false; }; _proto.UNSAFE_componentWillReceiveProps = function UNSAFE_componentWillReceiveProps(nextProps) { if (nextProps.type !== this.props.type) { this.setState({ isTruncated: this.isTruncated(nextProps) }); } }; _proto.render = function render() { var _this3 = this; var _this$props = this.props, children = _this$props.children, className = _this$props.className, ellipsis = _this$props.ellipsis, limit = _this$props.limit, showTooltipOnTruncate = _this$props.showTooltipOnTruncate, splitter = _this$props.splitter, tooltipPlacement = _this$props.tooltipPlacement, tooltipProps = _this$props.tooltipProps, tooltipModifiers = _this$props.tooltipModifiers, title = _this$props.title, text = _this$props.text, type = _this$props.type, rest = (0, _objectWithoutPropertiesLoose2.default)(_this$props, ["children", "className", "ellipsis", "limit", "showTooltipOnTruncate", "splitter", "tooltipPlacement", "tooltipProps", "tooltipModifiers", "title", "text", "type"]); var componentClassName = (0, _classnames.default)('c-Truncate', type && "is-" + type, className); var shouldShowTooltip = showTooltipOnTruncate && this.state.isTruncated; var truncatedText; if (splitter) { var str = text || children; var _str$split = str.split(splitter), first = _str$split[0], second = _str$split[1]; truncatedText = /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Truncate.TruncateWithSplitterUI, { className: _Truncate2.TRUNCATED_CLASSNAMES.component + " " + _Truncate2.TRUNCATED_CLASSNAMES.withSplitter, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "" + _Truncate2.TRUNCATED_CLASSNAMES.firstChunk, children: first }), /*#__PURE__*/(0, _jsxRuntime.jsxs)("span", { className: "" + _Truncate2.TRUNCATED_CLASSNAMES.secondChunk, children: [splitter, second] })] }); } else { truncatedText = this.getTruncatedContent(); } var textMarkup = /*#__PURE__*/(0, _jsxRuntime.jsx)("span", { className: "c-Truncate__content", ref: function ref(_ref) { return _this3.contentNode = _ref; }, children: truncatedText }); var content = shouldShowTooltip ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Tooltip.default, (0, _extends2.default)({ closeOnContentClick: true }, tooltipProps, { placement: tooltipPlacement, title: title || this.getText(), children: textMarkup })) : textMarkup; return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_Truncate.TruncateUI, (0, _extends2.default)({}, (0, _getValidProps.default)(rest), { className: componentClassName, ref: function ref(_ref2) { return _this3.node = _ref2; }, children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_EventListener.default, { event: "resize", handler: this.handleOnResize }), content] })); }; return Truncate; }(_react.default.PureComponent); /** * Generates the truncated content based on props. * * @param {Object} props Component props. * @returns {string} The truncated content. */ exports.Truncate = Truncate; function getTruncatedContent(props) { var ellipsis = props.ellipsis, limit = props.limit, type = props.type, text = props.text; var truncateStart; var truncateEnd; switch (type) { case 'start': truncateStart = 0; truncateEnd = limit; break; case 'middle': truncateStart = Math.floor(limit / 2); truncateEnd = Math.floor(limit / 2); break; default: truncateStart = limit; truncateEnd = 0; } var word = type !== 'auto' ? (0, _Truncate2.truncateMiddle)(text, truncateStart, truncateEnd, ellipsis) : text; return word; } Truncate.defaultProps = { 'data-cy': 'Truncate', ellipsis: '…', limit: 0, showTooltipOnTruncate: false, tooltipModifiers: {}, tooltipPlacement: 'top-start', tooltipProps: {}, type: 'auto' }; Truncate.propTypes = { /** Data attr for Cypress tests. */ 'data-cy': _propTypes.default.string, /** Custom class names to be added to the component. */ className: _propTypes.default.string, /** Characters to show during truncation. */ ellipsis: _propTypes.default.string, /** The amount of characters to keep before truncation. */ limit: _propTypes.default.number, /** Renders a [Tooltip](../Tooltip) if content is truncated. Default `false`. */ showTooltipOnTruncate: _propTypes.default.bool, /** Char to split string on for truncating mid-string, `longEma...@email.com`. */ splitter: _propTypes.default.string, /** Location of truncation. * `auto` Uses CSS truncation. This is the default. * `start` Truncates beginning of string. * `middle` Truncates middle of string. * `end` Truncates end of string. */ type: _propTypes.default.oneOf(['auto', 'start', 'middle', 'end']), end: _propTypes.default.number, start: _propTypes.default.number, text: _propTypes.default.string, title: _propTypes.default.string, tooltipProps: _propTypes.default.object, tooltipPlacement: _propTypes.default.string, tooltipModifiers: _propTypes.default.object }; var _default = Truncate; exports.default = _default;