UNPKG

@elastic/eui

Version:

Elastic UI Component Library

260 lines (257 loc) 11.8 kB
"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); var _typeof = require("@babel/runtime/helpers/typeof"); Object.defineProperty(exports, "__esModule", { value: true }); exports.EuiTextTruncate = void 0; var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray")); var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends")); var _objectWithoutProperties2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutProperties")); var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _classnames = _interopRequireDefault(require("classnames")); var _services = require("../../services"); var _resize_observer = require("../observer/resize_observer"); var _tool_tip = require("../tool_tip"); var _utils = require("./utils"); var _text_truncate = require("./text_truncate.styles"); var _react2 = require("@emotion/react"); var _excluded = ["width", "onResize"], _excluded2 = ["width", "children", "text", "truncation", "truncationOffset", "truncationPosition", "ellipsis", "calculationDelayMs", "containerRef", "className"], _excluded3 = ["onResize"]; /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; } var TRUNCATION_TYPES = ['end', 'start', 'startEnd', 'middle']; var EuiTextTruncate = exports.EuiTextTruncate = function EuiTextTruncate(_ref) { var width = _ref.width, onResize = _ref.onResize, props = (0, _objectWithoutProperties2.default)(_ref, _excluded); return width != null ? (0, _react2.jsx)(EuiTextTruncateWithWidth, (0, _extends2.default)({ width: width }, props)) : (0, _react2.jsx)(EuiTextTruncateWithResizeObserver, (0, _extends2.default)({ onResize: onResize }, props)); }; EuiTextTruncate.propTypes = { className: _propTypes.default.string, "aria-label": _propTypes.default.string, "data-test-subj": _propTypes.default.string, css: _propTypes.default.any, /** * The full text string to truncate */ text: _propTypes.default.string.isRequired, /** * The truncation type desired. Determines where the ellipses are placed. */ truncation: _propTypes.default.any, /** * This prop **only** applies to the `start` and `end` truncation types. * It allows preserving a certain number of characters of either the * starting or ending text. * * If the passed offset is greater than the total text length, * the offset will be ignored. */ truncationOffset: _propTypes.default.number, /** * This prop **only** applies to the `startEnd` truncation type. * It allows customizing the anchor position of the displayed text, * which otherwise defaults to the middle of the text string. * * The primary use case for this prop for is search highlighting - e.g., if * a user searches for a specific word in the text, pass the index of that * found word to ensure it is always visible. * * This behavior will intelligently detect when positions are close to the start * or end of the text, and omit leading or trailing ellipses when necessary. * If the passed position is greater than the total text length, * the truncation will simply default to `start` instead. */ truncationPosition: _propTypes.default.number, /** * Defaults to the horizontal ellipsis character. * Can be optionally configured to use other punctuation, * e.g. spaces, brackets, hyphens, asterisks, etc. */ ellipsis: _propTypes.default.string, /** * By default, EuiTextTruncate will render a resize observer to detect the * available width it has. For performance reasons (e.g. multiple truncated * text items within the same container), you may opt to pass in your own * container width, which will skip initializing a resize observer. */ width: _propTypes.default.number, /** * Optional callback that fires when the default resizer observer both mounts and * registers a size change. This callback will **not** fire if `width` is passed. */ onResize: _propTypes.default.func, /** * By default, EuiTextTruncate will render the truncated string directly. * You can optionally pass a render prop function to the component, which * allows for more flexible text rendering, e.g. adding custom markup * or highlighting */ children: _propTypes.default.func, /** * For some edge case scenarios, EuiTextTruncate's calculations may be off until * fonts are done loading or layout is done shifting or settling. Adding a delay * may help resolve any rendering issues. */ calculationDelayMs: _propTypes.default.number }; var EuiTextTruncateWithWidth = function EuiTextTruncateWithWidth(_ref2) { var width = _ref2.width, children = _ref2.children, text = _ref2.text, _ref2$truncation = _ref2.truncation, _truncation = _ref2$truncation === void 0 ? 'end' : _ref2$truncation, _ref2$truncationOffse = _ref2.truncationOffset, _truncationOffset = _ref2$truncationOffse === void 0 ? 0 : _ref2$truncationOffse, truncationPosition = _ref2.truncationPosition, _ref2$ellipsis = _ref2.ellipsis, ellipsis = _ref2$ellipsis === void 0 ? '…' : _ref2$ellipsis, calculationDelayMs = _ref2.calculationDelayMs, containerRef = _ref2.containerRef, className = _ref2.className, rest = (0, _objectWithoutProperties2.default)(_ref2, _excluded2); // Note: This needs to be a state and not a ref to trigger a rerender on mount var _useState = (0, _react.useState)(null), _useState2 = (0, _slicedToArray2.default)(_useState, 2), containerEl = _useState2[0], setContainerEl = _useState2[1]; var refs = (0, _services.useCombinedRefs)([setContainerEl, containerRef]); // If necessary, wait a tick on mount before truncating var _useState3 = (0, _react.useState)(!calculationDelayMs), _useState4 = (0, _slicedToArray2.default)(_useState3, 2), ready = _useState4[0], setReady = _useState4[1]; (0, _react.useEffect)(function () { if (calculationDelayMs) { var timerId = setTimeout(function () { return setReady(true); }, calculationDelayMs); return function () { return clearTimeout(timerId); }; } }, [calculationDelayMs]); // Handle exceptions where we need to override the passed props var _useMemo = (0, _react.useMemo)(function () { var truncation = _truncation; var truncationOffset = 0; if (_truncation === 'end' || _truncation === 'start') { if (0 < _truncationOffset && _truncationOffset < text.length) { truncationOffset = _truncationOffset; } } else if (_truncation === 'startEnd' && truncationPosition != null) { if (truncationPosition <= 0) { truncation = 'end'; } else if (truncationPosition >= text.length) { truncation = 'start'; } } return { truncation: truncation, truncationOffset: truncationOffset }; }, [_truncation, _truncationOffset, truncationPosition, text.length]), truncation = _useMemo.truncation, truncationOffset = _useMemo.truncationOffset; var truncatedText = (0, _react.useMemo)(function () { var truncatedText = ''; if (!ready || !containerEl) return text; if (!width) return truncatedText; var utils = new _utils.TruncationUtils({ fullText: text, ellipsis: ellipsis, container: containerEl, availableWidth: width }); if (utils.checkIfTruncationIsNeeded() === false) { truncatedText = text; } else if (utils.checkSufficientEllipsisWidth(truncation) === false) { truncatedText = ''; } else { switch (truncation) { case 'end': truncatedText = utils.truncateEnd(truncationOffset); break; case 'start': truncatedText = utils.truncateStart(truncationOffset); break; case 'startEnd': if (truncationPosition == null) { truncatedText = utils.truncateStartEndAtMiddle(); } else { truncatedText = utils.truncateStartEndAtPosition(truncationPosition); } break; case 'middle': truncatedText = utils.truncateMiddle(); break; } } return truncatedText; }, [ready, width, text, truncation, truncationOffset, truncationPosition, ellipsis, containerEl]); var isTruncating = truncatedText !== text; var styles = (0, _services.useEuiMemoizedStyles)(_text_truncate.euiTextTruncateStyles); var content = (0, _react2.jsx)("div", (0, _extends2.default)({ className: (0, _classnames.default)('euiTextTruncate', className), css: styles.euiTextTruncate, ref: refs }, rest), isTruncating ? (0, _react2.jsx)(_react.default.Fragment, null, (0, _react2.jsx)("span", { className: "euiTextTruncate__truncatedText", css: styles.euiTextTruncate__truncatedText, "aria-hidden": true, "data-test-subj": "truncatedText" }, children ? children(truncatedText) : truncatedText), (0, _react2.jsx)("span", { className: "euiTextTruncate__fullText", css: styles.euiTextTruncate__fullText, "data-test-subj": "fullText" }, text)) : (0, _react2.jsx)("span", { className: "euiTextTruncate__fullText", "data-test-subj": "fullText" }, children ? children(text) : text)); return isTruncating ? (0, _react2.jsx)(_tool_tip.EuiToolTip, { content: text, disableScreenReaderOutput: true, display: "block" }, content) : content; }; EuiTextTruncateWithWidth.propTypes = { width: _propTypes.default.number.isRequired, containerRef: _propTypes.default.any }; var EuiTextTruncateWithResizeObserver = function EuiTextTruncateWithResizeObserver(_ref3) { var _onResize = _ref3.onResize, props = (0, _objectWithoutProperties2.default)(_ref3, _excluded3); var _useState5 = (0, _react.useState)(0), _useState6 = (0, _slicedToArray2.default)(_useState5, 2), width = _useState6[0], setWidth = _useState6[1]; var onResize = (0, _react.useCallback)(function (_ref4) { var width = _ref4.width; setWidth(width); _onResize === null || _onResize === void 0 || _onResize(width); }, [_onResize]); return (0, _react2.jsx)(_resize_observer.EuiResizeObserver, { onResize: onResize }, function (ref) { return (0, _react2.jsx)(EuiTextTruncateWithWidth, (0, _extends2.default)({ width: width, containerRef: ref }, props, { "data-resize-observer": "true" })); }); };