@elastic/eui
Version:
Elastic UI Component Library
260 lines (257 loc) • 11.8 kB
JavaScript
"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"
}));
});
};