UNPKG

antd-v5

Version:

An enterprise-class UI design language and React components implementation

168 lines (167 loc) 6.92 kB
"use strict"; "use client"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var React = _interopRequireWildcard(require("react")); var _toArray = _interopRequireDefault(require("rc-util/lib/Children/toArray")); var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect")); function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (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 && Object.prototype.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; } function cuttable(node) { const type = typeof node; return type === 'string' || type === 'number'; } function getNodesLen(nodeList) { let totalLen = 0; nodeList.forEach(node => { if (cuttable(node)) { totalLen += String(node).length; } else { totalLen += 1; } }); return totalLen; } function sliceNodes(nodeList, len) { let currLen = 0; const currentNodeList = []; for (let i = 0; i < nodeList.length; i += 1) { // Match to return if (currLen === len) { return currentNodeList; } const node = nodeList[i]; const canCut = cuttable(node); const nodeLen = canCut ? String(node).length : 1; const nextLen = currLen + nodeLen; // Exceed but current not which means we need cut this // This will not happen on validate ReactElement if (nextLen > len) { const restLen = len - currLen; currentNodeList.push(String(node).slice(0, restLen)); return currentNodeList; } currentNodeList.push(node); currLen = nextLen; } return nodeList; } const NONE = 0; const PREPARE = 1; const WALKING = 2; const DONE_WITH_ELLIPSIS = 3; const DONE_WITHOUT_ELLIPSIS = 4; const Ellipsis = _ref => { let { enabledMeasure, children, text, width, fontSize, rows, onEllipsis } = _ref; const [[startLen, midLen, endLen], setCutLength] = React.useState([0, 0, 0]); // record last done with ellipsis width const [lastLen, setLastLen] = React.useState(0); const [walkingState, setWalkingState] = React.useState(NONE); const [singleRowHeight, setSingleRowHeight] = React.useState(0); const singleRowRef = React.useRef(null); const midRowRef = React.useRef(null); const nodeList = React.useMemo(() => (0, _toArray.default)(text), [text]); const totalLen = React.useMemo(() => getNodesLen(nodeList), [nodeList]); const mergedChildren = React.useMemo(() => { if (!enabledMeasure || walkingState !== DONE_WITH_ELLIPSIS) { // if has lastLen, use it as temporary width to avoid lots of text to squeeze space. if (lastLen && walkingState !== DONE_WITHOUT_ELLIPSIS && enabledMeasure) return children(sliceNodes(nodeList, lastLen), lastLen < totalLen); return children(nodeList, false); } return children(sliceNodes(nodeList, midLen), midLen < totalLen); }, [enabledMeasure, walkingState, children, nodeList, midLen, totalLen]); // ======================== Walk ======================== (0, _useLayoutEffect.default)(() => { if (enabledMeasure && width && fontSize && totalLen) { setWalkingState(PREPARE); setCutLength([0, Math.ceil(totalLen / 2), totalLen]); } }, [enabledMeasure, width, fontSize, text, totalLen, rows]); (0, _useLayoutEffect.default)(() => { var _a; if (walkingState === PREPARE) { setSingleRowHeight(((_a = singleRowRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) || 0); } }, [walkingState]); (0, _useLayoutEffect.default)(() => { var _a, _b; if (singleRowHeight) { if (walkingState === PREPARE) { // Ignore if position is enough const midHeight = ((_a = midRowRef.current) === null || _a === void 0 ? void 0 : _a.offsetHeight) || 0; const maxHeight = rows * singleRowHeight; if (midHeight <= maxHeight) { setWalkingState(DONE_WITHOUT_ELLIPSIS); onEllipsis(false); } else { setWalkingState(WALKING); } } else if (walkingState === WALKING) { if (startLen !== endLen) { const midHeight = ((_b = midRowRef.current) === null || _b === void 0 ? void 0 : _b.offsetHeight) || 0; const maxHeight = rows * singleRowHeight; let nextStartLen = startLen; let nextEndLen = endLen; // We reach the last round if (startLen === endLen - 1) { nextEndLen = startLen; } else if (midHeight <= maxHeight) { nextStartLen = midLen; } else { nextEndLen = midLen; } const nextMidLen = Math.ceil((nextStartLen + nextEndLen) / 2); setCutLength([nextStartLen, nextMidLen, nextEndLen]); } else { setWalkingState(DONE_WITH_ELLIPSIS); setLastLen(midLen); onEllipsis(true); } } } }, [walkingState, startLen, endLen, rows, singleRowHeight]); // ======================= Render ======================= const measureStyle = { width, whiteSpace: 'normal', margin: 0, padding: 0 }; const renderMeasure = (content, ref, style) => ( /*#__PURE__*/React.createElement("span", { "aria-hidden": true, ref: ref, style: Object.assign({ position: 'fixed', display: 'block', left: 0, top: 0, zIndex: -9999, visibility: 'hidden', pointerEvents: 'none', fontSize: Math.ceil(fontSize / 2) * 2 }, style) }, content)); const renderMeasureSlice = (len, ref) => { const sliceNodeList = sliceNodes(nodeList, len); return renderMeasure(children(sliceNodeList, true), ref, measureStyle); }; return /*#__PURE__*/React.createElement(React.Fragment, null, mergedChildren, enabledMeasure && walkingState !== DONE_WITH_ELLIPSIS && walkingState !== DONE_WITHOUT_ELLIPSIS && ( /*#__PURE__*/React.createElement(React.Fragment, null, renderMeasure('lg', singleRowRef, { wordBreak: 'keep-all', whiteSpace: 'nowrap' }), walkingState === PREPARE ? renderMeasure(children(nodeList, false), midRowRef, measureStyle) : renderMeasureSlice(midLen, midRowRef)))); }; if (process.env.NODE_ENV !== 'production') { Ellipsis.displayName = 'Ellipsis'; } var _default = exports.default = Ellipsis;