@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
285 lines (229 loc) • 9.16 kB
JavaScript
"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;