@0xchain/expandable-text 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,7 @@
1
+ # @0xchain/expandable-text
2
+
3
+ This library was generated with [Nx](https://nx.dev).
4
+
5
+ ## Running unit tests
6
+
7
+ Run `nx test @0xchain/expandable-text` to execute the unit tests via [Vitest](https://vitest.dev/).
@@ -0,0 +1,70 @@
1
+ import { default as React } from 'react';
2
+ interface ExpandableTextProps {
3
+ /**
4
+ * 要显示的文本内容
5
+ */
6
+ text?: string;
7
+ /**
8
+ * 最大显示行数,默认为2行
9
+ */
10
+ maxLines?: number;
11
+ /**
12
+ * 展开按钮的文本(可选,默认使用国际化文案)
13
+ */
14
+ expandText?: string;
15
+ /**
16
+ * 收起按钮的文本(可选,默认使用国际化文案)
17
+ */
18
+ collapseText?: string;
19
+ /**
20
+ * 自定义样式类名
21
+ */
22
+ className?: string;
23
+ /**
24
+ * 是否显示展开/收起按钮
25
+ */
26
+ showToggle?: boolean;
27
+ /**
28
+ * 文本截断时的省略号样式
29
+ */
30
+ ellipsis?: string;
31
+ /**
32
+ * 是否显示加载骨架(可选,外部可强制)
33
+ */
34
+ loading?: boolean;
35
+ /**
36
+ * 是否在省略时展示 tooltip(使用 title 简化版)
37
+ */
38
+ tooltip?: boolean;
39
+ /**
40
+ * 展开时触发
41
+ */
42
+ onExpand?: () => void;
43
+ /**
44
+ * 收起时触发
45
+ */
46
+ onCollapse?: () => void;
47
+ /**
48
+ * 自定义展开文案/节点(默认取国际化)
49
+ */
50
+ expandSymbol?: React.ReactNode;
51
+ /**
52
+ * 自定义收起文案/节点(默认取国际化)
53
+ */
54
+ collapseSymbol?: React.ReactNode;
55
+ /**
56
+ * 溢出状态回调(对齐 antd 的 onEllipsis 语义)
57
+ */
58
+ onEllipsis?: (ellipsis: boolean) => void;
59
+ /**
60
+ * 字符级裁剪时追加的后缀(如 “...更多” 里的固定 suffix)
61
+ */
62
+ suffix?: string;
63
+ /**
64
+ * 是否可展开(等价 antd 的 ellipsis.expandable)
65
+ */
66
+ expandable?: boolean;
67
+ }
68
+ export declare const ExpandableText: React.FC<ExpandableTextProps>;
69
+ export default ExpandableText;
70
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAI3D,UAAU,mBAAmB;IAC3B;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IACd;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;OAEG;IACH,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;IACtB;;OAEG;IACH,UAAU,CAAC,EAAE,MAAM,IAAI,CAAC;IACxB;;OAEG;IACH,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC/B;;OAEG;IACH,cAAc,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACjC;;OAEG;IACH,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,KAAK,IAAI,CAAC;IACzC;;OAEG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;OAEG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA0MxD,CAAC;AAEF,eAAe,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,143 @@
1
+ 'use client';
2
+ import { jsxs as S, jsx as u } from "react/jsx-runtime";
3
+ import { useState as b, useRef as G, useEffect as te } from "react";
4
+ import { useTranslations as ne } from "next-intl";
5
+ import { twMerge as F } from "tailwind-merge";
6
+ const le = ({
7
+ text: s,
8
+ maxLines: f = 2,
9
+ expandText: W,
10
+ collapseText: z,
11
+ className: J,
12
+ showToggle: g = !0,
13
+ ellipsis: w = "...",
14
+ loading: K,
15
+ onExpand: y,
16
+ onCollapse: $,
17
+ expandSymbol: H,
18
+ collapseSymbol: P,
19
+ onEllipsis: x,
20
+ suffix: i = "",
21
+ expandable: k = !0
22
+ }) => {
23
+ const [t, Q] = b(!1), [l, U] = b(!1), [c, V] = b(!1), [I, C] = b(null), j = G(null), B = G(null), h = ne("common.expandableText"), M = W || h("expand");
24
+ te(() => {
25
+ const a = j.current, e = B.current;
26
+ if (!a || !e) return;
27
+ const m = !g || !k ? "" : typeof H == "string" ? String(H) : W || h("expand"), L = g && k && !t, q = (n) => {
28
+ const r = getComputedStyle(n), o = parseFloat(r.lineHeight);
29
+ return isNaN(o) ? parseFloat(r.fontSize) * 1.2 : o;
30
+ }, Y = () => {
31
+ const n = getComputedStyle(a);
32
+ [
33
+ "font",
34
+ "fontFamily",
35
+ "fontSize",
36
+ "fontWeight",
37
+ "lineHeight",
38
+ "letterSpacing",
39
+ "wordBreak",
40
+ "wordWrap",
41
+ "whiteSpace",
42
+ "textTransform",
43
+ "textIndent",
44
+ "textRendering"
45
+ ].forEach((o) => {
46
+ e.style[o] = n[o];
47
+ }), e.style.width = `${a.clientWidth}px`;
48
+ }, Z = (n) => {
49
+ const r = L && m ? `${n} ${m}` : n;
50
+ e.textContent = r;
51
+ const T = q(e) * f;
52
+ return e.scrollHeight <= T + 0.5;
53
+ }, A = () => {
54
+ Y();
55
+ const n = `${s ?? ""}${i || ""}`, r = L && m ? `${n} ${m}` : n;
56
+ e.textContent = r;
57
+ const T = q(e) * f, v = e.scrollHeight > T + 0.5;
58
+ if (U((d) => (d !== v && (x == null || x(v)), v)), v && !t && s) {
59
+ const d = `${s}${i || ""}`;
60
+ let O = 0, R = d.length, D = 0;
61
+ for (; O <= R; ) {
62
+ const p = Math.floor((O + R) / 2), ee = `${d.slice(0, p)}${w || ""}`;
63
+ Z(ee) ? (D = p, O = p + 1) : R = p - 1;
64
+ }
65
+ const E = `${d.slice(0, D)}${w || ""}`;
66
+ C(E);
67
+ } else
68
+ C(null);
69
+ V(!0);
70
+ }, _ = setTimeout(A, 0), N = new ResizeObserver(A);
71
+ return N.observe(a), N.observe(e), () => {
72
+ clearTimeout(_), N.disconnect();
73
+ };
74
+ }, [s, f, i, w, t]);
75
+ const X = () => {
76
+ Q((a) => {
77
+ const e = !a;
78
+ return e ? y == null || y() : $ == null || $(), e;
79
+ });
80
+ };
81
+ return s ? /* @__PURE__ */ S("div", { className: F("relative", J), children: [
82
+ (K || !c) && /* @__PURE__ */ S("div", { className: F("animate-pulse"), children: [
83
+ /* @__PURE__ */ u("div", { className: "h-4 bg-module rounded w-full mb-2" }),
84
+ /* @__PURE__ */ u("div", { className: "h-4 bg-module rounded w-3/4" })
85
+ ] }),
86
+ /* @__PURE__ */ u(
87
+ "div",
88
+ {
89
+ ref: B,
90
+ className: "absolute left-0 top-0 pointer-events-none whitespace-pre-wrap break-words",
91
+ style: {
92
+ visibility: "hidden",
93
+ position: "absolute",
94
+ zIndex: -1,
95
+ width: "100%",
96
+ WebkitLineClamp: "unset",
97
+ display: "block",
98
+ overflow: "visible"
99
+ }
100
+ }
101
+ ),
102
+ /* @__PURE__ */ S(
103
+ "div",
104
+ {
105
+ ref: j,
106
+ className: F(
107
+ "transition-all duration-300 ease-in-out align-justify space-x-1"
108
+ ),
109
+ style: {
110
+ visibility: c ? "visible" : "hidden",
111
+ position: c ? "static" : "absolute",
112
+ left: c ? void 0 : 0,
113
+ top: c ? void 0 : 0,
114
+ width: c ? void 0 : "100%",
115
+ display: !t && l ? "-webkit-box" : "block",
116
+ WebkitLineClamp: !t && l ? f : "unset",
117
+ WebkitBoxOrient: "vertical",
118
+ overflow: !t && l ? "hidden" : "visible",
119
+ textOverflow: !t && l ? "ellipsis" : "clip"
120
+ },
121
+ "aria-label": s,
122
+ children: [
123
+ /* @__PURE__ */ u("span", { children: !t && l && I != null ? I : `${s ?? ""}${t && i ? i : ""}` }),
124
+ l && g && k && /* @__PURE__ */ u(
125
+ "button",
126
+ {
127
+ type: "button",
128
+ onClick: X,
129
+ className: "text-primary hover:underline focus:outline-none text-sm",
130
+ "aria-expanded": t,
131
+ "aria-label": t ? z || h("collapse") : M,
132
+ children: t ? P ?? z ?? h("collapse") : H ?? M
133
+ }
134
+ )
135
+ ]
136
+ }
137
+ )
138
+ ] }) : null;
139
+ };
140
+ export {
141
+ le as ExpandableText,
142
+ le as default
143
+ };
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@0xchain/expandable-text",
3
+ "version": "0.0.1",
4
+ "type": "module",
5
+ "main": "./dist/index.js",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ "./package.json": "./package.json",
10
+ ".": {
11
+ "types": "./dist/index.d.ts",
12
+ "import": "./dist/index.js",
13
+ "default": "./dist/index.js"
14
+ }
15
+ },
16
+ "devDependencies": {
17
+ "rollup-plugin-preserve-use-client": "3.0.1"
18
+ },
19
+ "files": [
20
+ "dist",
21
+ "!**/*.tsbuildinfo"
22
+ ],
23
+ "dependencies": {
24
+ "react": "19.1.1",
25
+ "react-dom": "19.1.1",
26
+ "tailwind-merge": "3.3.1",
27
+ "next-intl": "4.6.1"
28
+ },
29
+ "publishConfig": {
30
+ "access": "public"
31
+ }
32
+ }