antd-v5
Version:
An enterprise-class UI design language and React components implementation
168 lines (167 loc) • 6.92 kB
JavaScript
"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;
;