@nutui/nutui-react-taro
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
248 lines (247 loc) • 10.6 kB
JavaScript
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
};