UNPKG

@nutui/nutui-react-taro

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

248 lines (247 loc) 10.6 kB
import { _ as __rest, a as __awaiter } from "./tslib.es6-iWu3F_1J.js"; import React__default, { useRef, useState, useEffect } from "react"; import { nextTick, createSelectorQuery } from "@tarojs/taro"; import classNames from "classnames"; import { View } from "@tarojs/components"; import { g as getRectByTaro } from "./get-rect-by-taro-D0h6aiDr.js"; import { C as ComponentDefaults } from "./typings-DV9RBfhj.js"; import { a as useRtl } from "./configprovider.taro-DpK4IiCE.js"; const defaultProps = Object.assign(Object.assign({}, ComponentDefaults), { content: "", direction: "end", rows: 1, expandText: "", collapseText: "", symbol: "...", lineHeight: "20", width: "auto" }); const classPrefix = `nut-ellipsis`; const Ellipsis = (props) => { var _a, _b, _c, _d; const _e = Object.assign(Object.assign({}, defaultProps), props), { children, content, direction, rows, className, expandText, collapseText, symbol, lineHeight, width, onClick, onChange } = _e, rest = __rest(_e, ["children", "content", "direction", "rows", "className", "expandText", "collapseText", "symbol", "lineHeight", "width", "onClick", "onChange"]); const maxHeight = useRef(0); const [exceeded, setExceeded] = useState(false); const [expanded, setExpanded] = useState(false); const [cacled, setCacled] = useState(false); const ellipsis = useRef({ leading: "", tailing: "" }); const root = useRef(null); const rootContain = useRef(null); const symbolContain = useRef(null); const [contentCopy, setContentCopy] = useState(content); const lineH = useRef(0); const originHeight = useRef(0); const refRandomId = useRef(Math.random().toString(36).slice(-8)); const widthRef = useRef("auto"); const widthBase = useRef([14, 10, 7, 8.4, 10]); const symbolTextWidth = useRef(widthBase.current[0] * 0.7921); const chineseReg = /^[\u4e00-\u9fa5]+$/; const digitReg = /^[0-9]+$/; const letterUpperReg = /^[A-Z]+$/; const letterLowerReg = /^[a-z]+$/; const rtl = useRtl(); const rtlClasses = classNames({ [`${classPrefix}-rtl`]: rtl }); const classes = classNames(classPrefix, width ? `${classPrefix}-width` : "", rtlClasses, className); useEffect(() => { setContentCopy(content); nextTick(() => { getSymbolInfo(); getReference(); }); return () => { setCacled(false); }; }, [content]); const getSymbolInfo = () => __awaiter(void 0, void 0, void 0, function* () { const refe = yield getRectByTaro(symbolContain === null || symbolContain === void 0 ? void 0 : symbolContain.current); symbolTextWidth.current = refe.width ? Math.ceil(refe.width) : Math.ceil(widthBase.current[0] * 0.7921); }); const symbolText = () => { if (direction === "end" || direction === "middle") { return `${symbol}${expandText}`; } return `${symbol}${expandText}${symbol}`; }; const getReference = () => __awaiter(void 0, void 0, void 0, function* () { const query = createSelectorQuery(); query.select(`#root${refRandomId.current}`) && query.select(`#root${refRandomId.current}`).fields({ computedStyle: [ "width", "height", "lineHeight", "paddingTop", "paddingBottom", "fontSize" ] }, (res) => { if (!res) return; lineH.current = pxToNumber(res.lineHeight === "normal" ? lineHeight : res.lineHeight); maxHeight.current = Math.floor(lineH.current * (Number(rows) + 0.5) + pxToNumber(res.paddingTop) + pxToNumber(res.paddingBottom)); originHeight.current = pxToNumber(res.height); widthRef.current = res.width; const bsize = pxToNumber(res.fontSize); widthBase.current = [ bsize, bsize * 0.72, bsize * 0.53, bsize * 0.4, bsize * 0.75 ]; if (rootContain.current && rootContain.current.style) { rootContain.current.style.fontSize = `${bsize}px`; } calcEllipse(); }).exec(); }); const calcEllipse = () => __awaiter(void 0, void 0, void 0, function* () { const refe = yield getRectByTaro(rootContain.current); if (refe.height <= maxHeight.current) { setExceeded(false); setCacled(true); } else { const rowNum = Math.floor(content.length / (originHeight.current / lineH.current - 1)); if (direction === "middle") { const end = content.length; ellipsis.current.leading = tailorContent(0, rowNum * (Number(rows) + 0.5), "end"); ellipsis.current.tailing = tailorContent(content.length - rowNum * (Number(rows) + 0.5), end, "start"); } else if (direction === "end") { const end = rowNum * (Number(rows) + 0.5); ellipsis.current.leading = tailorContent(0, end); } else { const start = content.length - rowNum * (Number(rows) + 0.5) - 5; ellipsis.current.tailing = tailorContent(start, content.length); } assignContent(); setTimeout(() => { verifyEllipsis(); }, 100); } }); const verifyEllipsis = () => __awaiter(void 0, void 0, void 0, function* () { var _a2, _b2, _c2, _d2, _e2, _f, _g; const refe = yield getRectByTaro(rootContain.current); if (refe && refe.height && refe.height > maxHeight.current) { if (direction === "end") { ellipsis.current.leading = (_b2 = (_a2 = ellipsis.current) === null || _a2 === void 0 ? void 0 : _a2.leading) === null || _b2 === void 0 ? void 0 : _b2.slice(0, (((_d2 = (_c2 = ellipsis.current) === null || _c2 === void 0 ? void 0 : _c2.leading) === null || _d2 === void 0 ? void 0 : _d2.length) || 0) - 1); } else { ellipsis.current.tailing = (_f = (_e2 = ellipsis.current) === null || _e2 === void 0 ? void 0 : _e2.tailing) === null || _f === void 0 ? void 0 : _f.slice(1, (_g = ellipsis.current) === null || _g === void 0 ? void 0 : _g.tailing.length); } assignContent(); setTimeout(() => { verifyEllipsis(); }, 100); } }); const assignContent = () => { var _a2, _b2, _c2, _d2; const newContent = `${((_a2 = ellipsis.current) === null || _a2 === void 0 ? void 0 : _a2.leading) || ""}${((_b2 = ellipsis.current) === null || _b2 === void 0 ? void 0 : _b2.leading) ? symbol : ""}${expandText || ""}${((_c2 = ellipsis.current) === null || _c2 === void 0 ? void 0 : _c2.tailing) ? symbol : ""}${((_d2 = ellipsis.current) === null || _d2 === void 0 ? void 0 : _d2.tailing) || ""}`; setContentCopy(newContent); }; const tailorContent = (left, right, type = "") => { const threeDotWidth = symbolTextWidth.current; const direc = direction === "middle" && type ? type : direction; setExceeded(true); let widthPart = -1; const start = left; const end = right; let cutoff = 0; let marking = 0; if (direc === "end") { marking = start; cutoff = end; } else { marking = end; cutoff = start; } const contentWidth = pxToNumber(widthRef.current) * Number(rows) - threeDotWidth; const contentPartWidth = direction === "middle" ? contentWidth / 2 : contentWidth; while (widthPart < contentPartWidth) { const zi = content[marking]; if (chineseReg.test(zi)) { widthPart = Number(widthPart + widthBase.current[0]); } else if (letterUpperReg.test(zi)) { widthPart = Number(widthPart + widthBase.current[1]); } else if (letterLowerReg.test(zi)) { widthPart = Number(widthPart + widthBase.current[2]); } else if (digitReg.test(zi)) { widthPart = Number(widthPart + widthBase.current[3]); } else { widthPart = Number(widthPart + widthBase.current[4]); } cutoff = marking; direc === "end" ? marking++ : marking--; } if (direc === "end") { return content.slice(0, cutoff); } return content.slice(cutoff, end); }; const pxToNumber = (value) => { if (!value) return 0; const match = value.match(/^\d*(\.\d*)?/); return match ? Number(match[0]) : 0; }; const clickHandle = (type) => { if (type === 1) { setExpanded(true); onChange && onChange("expand"); } else { setExpanded(false); onChange && onChange("collapse"); } }; const handleClick = () => { onClick && onClick(); }; return React__default.createElement( React__default.Fragment, null, React__default.createElement( "div", Object.assign({ className: classes, onClick: handleClick, ref: root, id: `root${refRandomId.current}` }, rest), React__default.createElement( View, null, !exceeded ? React__default.createElement(View, { className: "nut-ellipsis-wordbreak", style: { width: `${!Number.isNaN(Number(width)) ? `${width}px` : "auto"}`, minHeight: "20px", height: cacled ? "auto" : "20px", overflow: "hidden" } }, content) : null, exceeded && !expanded ? React__default.createElement( View, { className: "nut-ellipsis-wordbreak", style: { width: `${!Number.isNaN(Number(width)) ? `${width}px` : "auto"}` } }, (_a = ellipsis.current) === null || _a === void 0 ? void 0 : _a.leading, ((_b = ellipsis.current) === null || _b === void 0 ? void 0 : _b.leading) && symbol, expandText ? React__default.createElement("span", { className: "nut-ellipsis-text", onClick: (e) => { e.stopPropagation(); clickHandle(1); } }, expandText) : null, ((_c = ellipsis.current) === null || _c === void 0 ? void 0 : _c.tailing) && symbol, (_d = ellipsis.current) === null || _d === void 0 ? void 0 : _d.tailing ) : null, exceeded && expanded ? React__default.createElement( View, { style: { width: `${!Number.isNaN(Number(width)) ? `${width}px` : "auto"}` } }, content, expandText ? React__default.createElement("span", { className: "nut-ellipsis-text", onClick: (e) => { e.stopPropagation(); clickHandle(2); } }, collapseText) : null ) : null ) ), React__default.createElement( View, { className: "nut-ellipsis-copy", ref: rootContain, id: `rootContain${refRandomId.current}`, style: { width: `${widthRef.current}` } }, React__default.createElement(View, null, contentCopy) ), React__default.createElement(View, { className: "nut-ellipsis-copy", ref: symbolContain, id: `symbolContain${refRandomId.current}`, style: { display: "inline" } }, symbolText()) ); }; Ellipsis.displayName = "NutEllipsis"; export { Ellipsis as E };