@turinhub/atomix-common-ui 0.5.0 → 0.6.0
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/dist/AuthPanel-CTKx618F.cjs +2 -0
- package/dist/AuthPanel-CTKx618F.cjs.map +1 -0
- package/dist/{AuthPanel-D2HFX8eN.js → AuthPanel-Cn_WwmjX.js} +259 -212
- package/dist/AuthPanel-Cn_WwmjX.js.map +1 -0
- package/dist/PDFSidebar-4DtXqqzN.cjs +2 -0
- package/dist/PDFSidebar-4DtXqqzN.cjs.map +1 -0
- package/dist/PDFSidebar-ClnrF4Br.js +239 -0
- package/dist/PDFSidebar-ClnrF4Br.js.map +1 -0
- package/dist/auth.cjs +1 -1
- package/dist/auth.js +1 -1
- package/dist/components/AuthLoginPanel.d.ts.map +1 -1
- package/dist/components/AuthRegisterPanel.d.ts.map +1 -1
- package/dist/components/AuthVisualCarousel.d.ts +2 -0
- package/dist/components/AuthVisualCarousel.d.ts.map +1 -1
- package/dist/components/DataTable.d.ts.map +1 -1
- package/dist/components/ImageReader.d.ts.map +1 -1
- package/dist/components/MarkdownReader.d.ts.map +1 -1
- package/dist/components/PDFReader.d.ts.map +1 -1
- package/dist/components/PDFSidebar.d.ts.map +1 -1
- package/dist/components/SimplePDFReader.d.ts.map +1 -1
- package/dist/components/TableHeader.d.ts.map +1 -1
- package/dist/components/TablePagination.d.ts +2 -1
- package/dist/components/TablePagination.d.ts.map +1 -1
- package/dist/components/VideoReader.d.ts.map +1 -1
- package/dist/components/ui/switch.d.ts +5 -0
- package/dist/components/ui/switch.d.ts.map +1 -0
- package/dist/data-table.cjs.map +1 -1
- package/dist/data-table.js.map +1 -1
- package/dist/file-upload.cjs +1 -1
- package/dist/file-upload.cjs.map +1 -1
- package/dist/file-upload.js +36 -36
- package/dist/file-upload.js.map +1 -1
- package/dist/image-reader.cjs +1 -1
- package/dist/image-reader.cjs.map +1 -1
- package/dist/image-reader.js +1 -0
- package/dist/image-reader.js.map +1 -1
- package/dist/index.cjs +1 -1
- package/dist/index.js +1 -1
- package/dist/markdown-reader.cjs +1 -1
- package/dist/markdown-reader.cjs.map +1 -1
- package/dist/markdown-reader.js +28 -24
- package/dist/markdown-reader.js.map +1 -1
- package/dist/pdf-reader.cjs +1 -1
- package/dist/pdf-reader.cjs.map +1 -1
- package/dist/pdf-reader.js +169 -120
- package/dist/pdf-reader.js.map +1 -1
- package/dist/pdf-sidebar.cjs +1 -1
- package/dist/pdf-sidebar.js +1 -1
- package/dist/simple-pdf-reader.cjs +1 -1
- package/dist/simple-pdf-reader.cjs.map +1 -1
- package/dist/simple-pdf-reader.js +137 -104
- package/dist/simple-pdf-reader.js.map +1 -1
- package/dist/table-header.cjs +1 -1
- package/dist/table-header.cjs.map +1 -1
- package/dist/table-header.js +42 -34
- package/dist/table-header.js.map +1 -1
- package/dist/table-pagination.cjs +1 -1
- package/dist/table-pagination.cjs.map +1 -1
- package/dist/table-pagination.js +49 -43
- package/dist/table-pagination.js.map +1 -1
- package/dist/types/component-types.d.ts +1 -0
- package/dist/types/component-types.d.ts.map +1 -1
- package/dist/video-reader.cjs.map +1 -1
- package/dist/video-reader.js.map +1 -1
- package/package.json +2 -1
- package/dist/AuthPanel-C_2JBE7t.cjs +0 -2
- package/dist/AuthPanel-C_2JBE7t.cjs.map +0 -1
- package/dist/AuthPanel-D2HFX8eN.js.map +0 -1
- package/dist/PDFSidebar-BBtucLK6.js +0 -232
- package/dist/PDFSidebar-BBtucLK6.js.map +0 -1
- package/dist/PDFSidebar-Di0D-yPS.cjs +0 -2
- package/dist/PDFSidebar-Di0D-yPS.cjs.map +0 -1
|
@@ -1,145 +1,147 @@
|
|
|
1
1
|
import { j as t } from "./jsx-runtime-B4hRZ52C.js";
|
|
2
|
-
import { ZoomOut as pe, ZoomIn as ve, Minimize2 as je, Maximize2 as he, ChevronLeft as ye, ChevronRight as
|
|
3
|
-
import { useState as
|
|
4
|
-
function
|
|
5
|
-
url:
|
|
6
|
-
initialPage:
|
|
7
|
-
initialScale:
|
|
2
|
+
import { ZoomOut as pe, ZoomIn as ve, Minimize2 as je, Maximize2 as he, ChevronLeft as ye, ChevronRight as be } from "lucide-react";
|
|
3
|
+
import { useState as o, useRef as B, useMemo as we, useCallback as x, useEffect as k } from "react";
|
|
4
|
+
function De({
|
|
5
|
+
url: N,
|
|
6
|
+
initialPage: V = 1,
|
|
7
|
+
initialScale: X = 1,
|
|
8
8
|
scale: p,
|
|
9
|
-
onScaleChange:
|
|
9
|
+
onScaleChange: l,
|
|
10
10
|
minScale: D = 0.5,
|
|
11
|
-
maxScale:
|
|
11
|
+
maxScale: M = 3,
|
|
12
12
|
currentPage: v,
|
|
13
13
|
onPageChange: y,
|
|
14
14
|
showToolbar: K = !0,
|
|
15
15
|
showPagination: O = !0,
|
|
16
|
-
enableHotkeys:
|
|
17
|
-
className:
|
|
18
|
-
containerClassName:
|
|
19
|
-
pageClassName:
|
|
20
|
-
components:
|
|
21
|
-
onLoadSuccess:
|
|
22
|
-
onLoadError:
|
|
23
|
-
loadingText:
|
|
16
|
+
enableHotkeys: Z = !0,
|
|
17
|
+
className: J,
|
|
18
|
+
containerClassName: Q,
|
|
19
|
+
pageClassName: Y,
|
|
20
|
+
components: C,
|
|
21
|
+
onLoadSuccess: b,
|
|
22
|
+
onLoadError: u,
|
|
23
|
+
loadingText: _ = "加载中...",
|
|
24
24
|
errorText: H = "加载失败"
|
|
25
25
|
}) {
|
|
26
|
-
const [G, L] =
|
|
27
|
-
const e = [
|
|
28
|
-
return
|
|
29
|
-
}, [
|
|
26
|
+
const [G, L] = o(null), [S, U] = o(V), [ee, W] = o(X), [te, w] = o(!0), [P, F] = o(null), [a, ne] = o(0), [g, se] = o(!1), I = B(null), j = B(null), [m, re] = o(null), i = v ?? S, c = p ?? ee, ie = we(() => {
|
|
27
|
+
const e = [i];
|
|
28
|
+
return i > 1 && e.push(i - 1), i < a && e.push(i + 1), e;
|
|
29
|
+
}, [i, a]), f = x(
|
|
30
30
|
(e) => {
|
|
31
|
-
const n = Math.max(
|
|
31
|
+
const n = Math.max(a, 1), s = Math.min(Math.max(e, 1), n);
|
|
32
32
|
v === void 0 && U(s), y == null || y(s);
|
|
33
33
|
},
|
|
34
|
-
[
|
|
35
|
-
),
|
|
36
|
-
|
|
37
|
-
}, [
|
|
38
|
-
|
|
39
|
-
}, [
|
|
40
|
-
const e = Math.min(
|
|
41
|
-
p === void 0 && W(e),
|
|
42
|
-
}, [
|
|
43
|
-
const e = Math.max(
|
|
44
|
-
p === void 0 && W(e),
|
|
45
|
-
}, [
|
|
34
|
+
[a, v, y]
|
|
35
|
+
), E = x(() => {
|
|
36
|
+
i > 1 && f(i - 1);
|
|
37
|
+
}, [i, f]), R = x(() => {
|
|
38
|
+
i < a && f(i + 1);
|
|
39
|
+
}, [i, a, f]), T = x(() => {
|
|
40
|
+
const e = Math.min(c + 0.25, M);
|
|
41
|
+
p === void 0 && W(e), l == null || l(e);
|
|
42
|
+
}, [c, M, p, l]), z = x(() => {
|
|
43
|
+
const e = Math.max(c - 0.25, D);
|
|
44
|
+
p === void 0 && W(e), l == null || l(e);
|
|
45
|
+
}, [c, D, p, l]), A = x(async () => {
|
|
46
46
|
var e, n, s;
|
|
47
47
|
if (!(typeof document > "u")) {
|
|
48
48
|
if (!document.fullscreenElement) {
|
|
49
|
-
await ((n = (e =
|
|
49
|
+
await ((n = (e = I.current) == null ? void 0 : e.requestFullscreen) == null ? void 0 : n.call(e));
|
|
50
50
|
return;
|
|
51
51
|
}
|
|
52
52
|
await ((s = document.exitFullscreen) == null ? void 0 : s.call(document));
|
|
53
53
|
}
|
|
54
54
|
}, []);
|
|
55
|
-
if (
|
|
55
|
+
if (k(() => {
|
|
56
56
|
let e = !0;
|
|
57
57
|
return (async () => {
|
|
58
58
|
try {
|
|
59
59
|
const s = await import("react-pdf");
|
|
60
60
|
if (typeof window < "u") {
|
|
61
|
-
const
|
|
62
|
-
|
|
61
|
+
const r = s.pdfjs, d = r == null ? void 0 : r.version;
|
|
62
|
+
r != null && r.GlobalWorkerOptions && d && (r.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${d}/build/pdf.worker.min.mjs`);
|
|
63
63
|
}
|
|
64
64
|
e && re(s);
|
|
65
65
|
} catch (s) {
|
|
66
66
|
if (e) {
|
|
67
|
-
const
|
|
68
|
-
F(
|
|
67
|
+
const r = s instanceof Error ? s : new Error("无法加载 react-pdf 库");
|
|
68
|
+
F(r), w(!1), u == null || u(r);
|
|
69
69
|
}
|
|
70
70
|
}
|
|
71
71
|
})(), () => {
|
|
72
72
|
e = !1;
|
|
73
73
|
};
|
|
74
|
-
}, []),
|
|
75
|
-
if (!m || !
|
|
74
|
+
}, []), k(() => {
|
|
75
|
+
if (!m || !N) return;
|
|
76
76
|
let e = !0;
|
|
77
77
|
return (async () => {
|
|
78
|
-
|
|
78
|
+
w(!0), F(null);
|
|
79
79
|
try {
|
|
80
80
|
const { Document: s } = m;
|
|
81
81
|
if (!s)
|
|
82
82
|
throw new Error("react-pdf Document 组件不可用");
|
|
83
|
-
const
|
|
84
|
-
j.current =
|
|
85
|
-
const d = await
|
|
83
|
+
const r = m.pdfjs.getDocument(N);
|
|
84
|
+
j.current = r;
|
|
85
|
+
const d = await r.promise;
|
|
86
86
|
e && (L(d), ne(d.numPages), v === void 0 && U(
|
|
87
87
|
(xe) => Math.max(1, Math.min(xe, d.numPages))
|
|
88
|
-
),
|
|
88
|
+
), w(!1), b == null || b(d));
|
|
89
89
|
} catch (s) {
|
|
90
90
|
if (e) {
|
|
91
|
-
const
|
|
92
|
-
F(
|
|
91
|
+
const r = s instanceof Error ? s : new Error("PDF 加载失败");
|
|
92
|
+
F(r), w(!1), u == null || u(r);
|
|
93
93
|
}
|
|
94
94
|
}
|
|
95
95
|
})(), () => {
|
|
96
96
|
e = !1, j.current && typeof j.current.destroy == "function" && (j.current.destroy(), j.current = null);
|
|
97
97
|
};
|
|
98
|
-
}, [m,
|
|
98
|
+
}, [m, N, v, b, u]), k(() => {
|
|
99
99
|
if (typeof document > "u") return;
|
|
100
100
|
const e = () => {
|
|
101
|
-
se(document.fullscreenElement ===
|
|
101
|
+
se(document.fullscreenElement === I.current);
|
|
102
102
|
};
|
|
103
103
|
return document.addEventListener("fullscreenchange", e), () => {
|
|
104
104
|
document.removeEventListener("fullscreenchange", e);
|
|
105
105
|
};
|
|
106
|
-
}, []),
|
|
107
|
-
if (!
|
|
106
|
+
}, []), k(() => {
|
|
107
|
+
if (!Z) return;
|
|
108
108
|
const e = (n) => {
|
|
109
|
-
const s = document.activeElement;
|
|
110
|
-
s && (s.tagName === "INPUT" || s.
|
|
109
|
+
const s = document.activeElement, r = s == null ? void 0 : s.getAttribute("role");
|
|
110
|
+
s && (s.tagName === "INPUT" || s.tagName === "TEXTAREA" || s.tagName === "SELECT" || s.isContentEditable || r === "textbox" || r === "spinbutton") || ((n.ctrlKey || n.metaKey) && (n.key === "=" || n.key === "+") ? (n.preventDefault(), T()) : (n.ctrlKey || n.metaKey) && n.key === "-" ? (n.preventDefault(), z()) : n.key === "ArrowLeft" ? (n.preventDefault(), E()) : n.key === "ArrowRight" ? (n.preventDefault(), R()) : (n.key === "f" || n.key === "F") && (n.preventDefault(), A()));
|
|
111
111
|
};
|
|
112
112
|
return document.addEventListener("keydown", e), () => {
|
|
113
113
|
document.removeEventListener("keydown", e);
|
|
114
114
|
};
|
|
115
115
|
}, [
|
|
116
|
-
|
|
117
|
-
E,
|
|
116
|
+
Z,
|
|
118
117
|
T,
|
|
119
|
-
|
|
118
|
+
z,
|
|
119
|
+
E,
|
|
120
120
|
R,
|
|
121
|
-
|
|
122
|
-
]), !
|
|
121
|
+
A
|
|
122
|
+
]), !C)
|
|
123
123
|
return /* @__PURE__ */ t.jsx("div", { className: "p-4 text-center text-destructive", children: "错误:请通过 components prop 注入 UI 组件" });
|
|
124
124
|
const {
|
|
125
|
-
Card:
|
|
126
|
-
CardContent:
|
|
125
|
+
Card: ae,
|
|
126
|
+
CardContent: le,
|
|
127
127
|
Button: h,
|
|
128
|
-
Input:
|
|
129
|
-
Skeleton:
|
|
130
|
-
} =
|
|
128
|
+
Input: $,
|
|
129
|
+
Skeleton: q
|
|
130
|
+
} = C, ce = () => K ? /* @__PURE__ */ t.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
131
131
|
/* @__PURE__ */ t.jsx(
|
|
132
132
|
h,
|
|
133
133
|
{
|
|
134
134
|
variant: "outline",
|
|
135
135
|
size: "sm",
|
|
136
|
-
onClick:
|
|
137
|
-
disabled:
|
|
136
|
+
onClick: z,
|
|
137
|
+
disabled: c <= D,
|
|
138
|
+
"aria-label": "缩小",
|
|
139
|
+
title: "缩小",
|
|
138
140
|
children: /* @__PURE__ */ t.jsx(pe, {})
|
|
139
141
|
}
|
|
140
142
|
),
|
|
141
143
|
/* @__PURE__ */ t.jsxs("span", { className: "text-sm", children: [
|
|
142
|
-
Math.round(
|
|
144
|
+
Math.round(c * 100),
|
|
143
145
|
"%"
|
|
144
146
|
] }),
|
|
145
147
|
/* @__PURE__ */ t.jsx(
|
|
@@ -147,8 +149,10 @@ function ge({
|
|
|
147
149
|
{
|
|
148
150
|
variant: "outline",
|
|
149
151
|
size: "sm",
|
|
150
|
-
onClick:
|
|
151
|
-
disabled:
|
|
152
|
+
onClick: T,
|
|
153
|
+
disabled: c >= M,
|
|
154
|
+
"aria-label": "放大",
|
|
155
|
+
title: "放大",
|
|
152
156
|
children: /* @__PURE__ */ t.jsx(ve, {})
|
|
153
157
|
}
|
|
154
158
|
),
|
|
@@ -158,46 +162,58 @@ function ge({
|
|
|
158
162
|
variant: "outline",
|
|
159
163
|
size: "icon",
|
|
160
164
|
onClick: () => {
|
|
161
|
-
|
|
165
|
+
A();
|
|
162
166
|
},
|
|
163
|
-
|
|
167
|
+
"aria-label": g ? "退出全屏" : "进入全屏",
|
|
168
|
+
title: g ? "退出全屏" : "进入全屏",
|
|
169
|
+
children: g ? /* @__PURE__ */ t.jsx(je, {}) : /* @__PURE__ */ t.jsx(he, {})
|
|
164
170
|
}
|
|
165
171
|
)
|
|
166
|
-
] }) : null,
|
|
172
|
+
] }) : null, oe = () => O ? /* @__PURE__ */ t.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
167
173
|
/* @__PURE__ */ t.jsx(
|
|
168
174
|
h,
|
|
169
175
|
{
|
|
170
176
|
variant: "outline",
|
|
171
177
|
size: "icon",
|
|
172
|
-
onClick:
|
|
173
|
-
disabled:
|
|
178
|
+
onClick: E,
|
|
179
|
+
disabled: i <= 1,
|
|
180
|
+
"aria-label": "上一页",
|
|
181
|
+
title: "上一页",
|
|
174
182
|
children: /* @__PURE__ */ t.jsx(ye, {})
|
|
175
183
|
}
|
|
176
184
|
),
|
|
177
|
-
|
|
178
|
-
|
|
185
|
+
$ ? /* @__PURE__ */ t.jsx(
|
|
186
|
+
$,
|
|
179
187
|
{
|
|
180
188
|
type: "number",
|
|
189
|
+
name: "simple-pdf-page",
|
|
181
190
|
min: 1,
|
|
182
|
-
max: Math.max(
|
|
183
|
-
value:
|
|
191
|
+
max: Math.max(a, 1),
|
|
192
|
+
value: i,
|
|
184
193
|
onChange: (e) => f(parseInt(e.target.value, 10) || 1),
|
|
185
|
-
className: "w-16 text-center"
|
|
194
|
+
className: "w-16 text-center",
|
|
195
|
+
"aria-label": "当前页码",
|
|
196
|
+
inputMode: "numeric",
|
|
197
|
+
autoComplete: "off"
|
|
186
198
|
}
|
|
187
199
|
) : /* @__PURE__ */ t.jsx(
|
|
188
200
|
"input",
|
|
189
201
|
{
|
|
190
202
|
type: "number",
|
|
203
|
+
name: "simple-pdf-page",
|
|
191
204
|
min: 1,
|
|
192
|
-
max: Math.max(
|
|
193
|
-
value:
|
|
205
|
+
max: Math.max(a, 1),
|
|
206
|
+
value: i,
|
|
194
207
|
onChange: (e) => f(parseInt(e.target.value, 10) || 1),
|
|
195
|
-
className: "w-16 rounded-md border border-input bg-background px-2 text-center text-sm"
|
|
208
|
+
className: "w-16 rounded-md border border-input bg-background px-2 text-center text-sm",
|
|
209
|
+
"aria-label": "当前页码",
|
|
210
|
+
inputMode: "numeric",
|
|
211
|
+
autoComplete: "off"
|
|
196
212
|
}
|
|
197
213
|
),
|
|
198
214
|
/* @__PURE__ */ t.jsxs("span", { className: "text-sm text-muted-foreground", children: [
|
|
199
215
|
"/ ",
|
|
200
|
-
|
|
216
|
+
a
|
|
201
217
|
] }),
|
|
202
218
|
/* @__PURE__ */ t.jsx(
|
|
203
219
|
h,
|
|
@@ -205,47 +221,64 @@ function ge({
|
|
|
205
221
|
variant: "outline",
|
|
206
222
|
size: "icon",
|
|
207
223
|
onClick: R,
|
|
208
|
-
disabled:
|
|
209
|
-
|
|
224
|
+
disabled: i >= a,
|
|
225
|
+
"aria-label": "下一页",
|
|
226
|
+
title: "下一页",
|
|
227
|
+
children: /* @__PURE__ */ t.jsx(be, {})
|
|
210
228
|
}
|
|
211
229
|
)
|
|
212
|
-
] }) : null,
|
|
230
|
+
] }) : null, ue = () => !K && !O ? null : /* @__PURE__ */ t.jsxs(
|
|
213
231
|
"div",
|
|
214
232
|
{
|
|
215
233
|
"data-testid": "pdf-operations-bar",
|
|
216
234
|
className: "flex items-center justify-between gap-4 border-b px-4 py-2",
|
|
217
235
|
children: [
|
|
218
|
-
|
|
219
|
-
|
|
236
|
+
ce(),
|
|
237
|
+
oe()
|
|
238
|
+
]
|
|
239
|
+
}
|
|
240
|
+
), de = () => /* @__PURE__ */ t.jsxs(
|
|
241
|
+
"div",
|
|
242
|
+
{
|
|
243
|
+
className: "flex flex-col items-center justify-center space-y-4 p-8",
|
|
244
|
+
role: "status",
|
|
245
|
+
"aria-live": "polite",
|
|
246
|
+
children: [
|
|
247
|
+
/* @__PURE__ */ t.jsx(q, { className: "h-8 w-32" }),
|
|
248
|
+
/* @__PURE__ */ t.jsx(q, { className: "h-64 w-full max-w-2xl" }),
|
|
249
|
+
/* @__PURE__ */ t.jsx("p", { className: "text-sm text-muted-foreground", children: _ })
|
|
220
250
|
]
|
|
221
251
|
}
|
|
222
|
-
),
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
252
|
+
), me = () => /* @__PURE__ */ t.jsx(
|
|
253
|
+
"div",
|
|
254
|
+
{
|
|
255
|
+
className: "flex flex-col items-center justify-center space-y-4 p-8",
|
|
256
|
+
role: "alert",
|
|
257
|
+
children: /* @__PURE__ */ t.jsxs("div", { className: "text-center text-destructive", children: [
|
|
258
|
+
/* @__PURE__ */ t.jsx("p", { className: "font-medium", children: H }),
|
|
259
|
+
P && /* @__PURE__ */ t.jsx("p", { className: "mt-2 text-sm text-muted-foreground", children: P.message })
|
|
260
|
+
] })
|
|
261
|
+
}
|
|
262
|
+
), fe = () => {
|
|
230
263
|
if (!m || !G) return null;
|
|
231
264
|
const { Page: e } = m;
|
|
232
265
|
return /* @__PURE__ */ t.jsx(
|
|
233
266
|
"div",
|
|
234
267
|
{
|
|
235
|
-
className: `flex flex-col items-center justify-center ${
|
|
268
|
+
className: `flex flex-col items-center justify-center ${g ? "h-[calc(100vh-56px)] overflow-auto" : "overflow-visible"}`,
|
|
236
269
|
children: ie.map((n) => /* @__PURE__ */ t.jsx(
|
|
237
270
|
"div",
|
|
238
271
|
{
|
|
239
|
-
className:
|
|
272
|
+
className: Y,
|
|
240
273
|
style: {
|
|
241
|
-
display: n ===
|
|
274
|
+
display: n === i ? "block" : "none"
|
|
242
275
|
},
|
|
243
276
|
children: /* @__PURE__ */ t.jsx(
|
|
244
277
|
e,
|
|
245
278
|
{
|
|
246
279
|
pdf: G,
|
|
247
280
|
pageNumber: n,
|
|
248
|
-
scale:
|
|
281
|
+
scale: c,
|
|
249
282
|
renderTextLayer: !1,
|
|
250
283
|
renderAnnotationLayer: !1,
|
|
251
284
|
className: "shadow-md"
|
|
@@ -257,12 +290,12 @@ function ge({
|
|
|
257
290
|
}
|
|
258
291
|
);
|
|
259
292
|
};
|
|
260
|
-
return /* @__PURE__ */ t.jsx("div", { ref:
|
|
261
|
-
|
|
262
|
-
/* @__PURE__ */ t.jsx(
|
|
293
|
+
return /* @__PURE__ */ t.jsx("div", { ref: I, children: /* @__PURE__ */ t.jsxs(ae, { className: J, children: [
|
|
294
|
+
ue(),
|
|
295
|
+
/* @__PURE__ */ t.jsx(le, { className: Q, children: te ? de() : P ? me() : fe() })
|
|
263
296
|
] }) });
|
|
264
297
|
}
|
|
265
298
|
export {
|
|
266
|
-
|
|
299
|
+
De as SimplePDFReader
|
|
267
300
|
};
|
|
268
301
|
//# sourceMappingURL=simple-pdf-reader.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"simple-pdf-reader.js","sources":["../src/components/SimplePDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useMemo, useCallback, useEffect, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\n/**\n * react-pdf 类型定义\n * 这些类型由 @types/react-pdf 提供,这里我们定义必要的接口\n */\nexport interface PDFDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<any>;\n}\n\n/**\n * SimplePDFReader UI 组件接口\n */\nexport interface SimplePDFReaderUIComponents {\n Card: CardComponent;\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n Input?: InputComponent;\n Skeleton: SkeletonComponent;\n}\n\n/**\n * SimplePDFReader 组件 Props\n */\nexport interface SimplePDFReaderProps {\n // PDF 数据源\n url: string;\n\n // 初始状态\n initialPage?: number;\n initialScale?: number;\n\n // 缩放控制\n scale?: number;\n onScaleChange?: (scale: number) => void;\n minScale?: number;\n maxScale?: number;\n\n // 页面导航\n currentPage?: number;\n onPageChange?: (page: number) => void;\n\n // 功能开关\n showToolbar?: boolean; // 默认 true\n showPagination?: boolean; // 默认 true\n enableHotkeys?: boolean; // 默认 true\n\n // 样式定制\n className?: string;\n containerClassName?: string;\n pageClassName?: string;\n\n // UI 组件注入\n components: SimplePDFReaderUIComponents;\n\n // 回调函数\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n onLoadError?: (error: Error) => void;\n\n // 加载状态文本\n loadingText?: string; // 默认 \"加载中...\"\n errorText?: string; // 默认 \"加载失败\"\n}\n\n/**\n * SimplePDFReader 组件\n *\n * 用于在 React 应用中展示和浏览 PDF 文档。\n * 支持从 URL 加载 PDF,提供基础的浏览功能(翻页、缩放),并包含性能优化。\n *\n * @example\n * ```tsx\n * import { SimplePDFReader } from '@turinhub/atomix-common-ui/simple-pdf-reader';\n * import { Card, Button, Skeleton } from '@/components/ui';\n *\n * <SimplePDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Skeleton,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showToolbar={true}\n * showPagination={true}\n * enableHotkeys={true}\n * onPageChange={(page) => console.log('Current page:', page)}\n * />\n *\n * Keyboard Shortcuts:\n * - Arrow Left/Right: Navigate pages\n * - Ctrl/Cmd + +/-: Zoom in/out\n * - F: Toggle fullscreen\n * ```\n */\nexport function SimplePDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n scale: controlledScale,\n onScaleChange,\n minScale = 0.5,\n maxScale = 3.0,\n currentPage: controlledPage,\n onPageChange,\n showToolbar = true,\n showPagination = true,\n enableHotkeys = true,\n className,\n containerClassName,\n pageClassName,\n components,\n onLoadSuccess,\n onLoadError,\n loadingText = '加载中...',\n errorText = '加载失败',\n}: SimplePDFReaderProps) {\n // ==================== React Hooks (必须在最顶部) ====================\n\n // 状态管理\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const readerRef = useRef<HTMLDivElement>(null);\n const loadingTaskRef = useRef<any>(null);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n\n // 预渲染相邻页面以提升翻页体验\n const pagesToPreload = useMemo(() => {\n const pages = [currentPage];\n if (currentPage > 1) pages.push(currentPage - 1);\n if (currentPage < totalPages) pages.push(currentPage + 1);\n return pages;\n }, [currentPage, totalPages]);\n\n // 页面导航处理\n const goToPage = useCallback(\n (page: number) => {\n const maxPage = Math.max(totalPages, 1);\n const targetPage = Math.min(Math.max(page, 1), maxPage);\n if (controlledPage === undefined) {\n setInternalPage(targetPage);\n }\n onPageChange?.(targetPage);\n },\n [totalPages, controlledPage, onPageChange]\n );\n\n const handlePreviousPage = useCallback(() => {\n if (currentPage > 1) {\n goToPage(currentPage - 1);\n }\n }, [currentPage, goToPage]);\n\n const handleNextPage = useCallback(() => {\n if (currentPage < totalPages) {\n goToPage(currentPage + 1);\n }\n }, [currentPage, totalPages, goToPage]);\n\n // 缩放控制处理\n const handleZoomIn = useCallback(() => {\n const newScale = Math.min(scale + 0.25, maxScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, maxScale, controlledScale, onScaleChange]);\n\n const handleZoomOut = useCallback(() => {\n const newScale = Math.max(scale - 0.25, minScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, minScale, controlledScale, onScaleChange]);\n\n const handleToggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n await readerRef.current?.requestFullscreen?.();\n return;\n }\n\n await document.exitFullscreen?.();\n }, []);\n\n // 动态导入 react-pdf 和设置 worker\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n }\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // 加载 PDF 文档\n useEffect(() => {\n if (!ReactPDF || !url) return;\n\n let isMounted = true;\n\n const loadPDF = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { Document } = ReactPDF;\n if (!Document) {\n throw new Error('react-pdf Document 组件不可用');\n }\n\n // 使用 react-pdf 的 Document 组件内部加载逻辑\n // 我们创建一个加载器来获取 PDF 文档信息\n const loadingTask = (ReactPDF.pdfjs as any).getDocument(url);\n loadingTaskRef.current = loadingTask;\n const pdf = await loadingTask.promise;\n\n if (isMounted) {\n setPdfDocument(pdf as PDFDocumentProxy);\n setTotalPages(pdf.numPages);\n if (controlledPage === undefined) {\n setInternalPage((prev) =>\n Math.max(1, Math.min(prev, pdf.numPages))\n );\n }\n setIsLoading(false);\n onLoadSuccess?.(pdf as PDFDocumentProxy);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('PDF 加载失败');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadPDF();\n\n return () => {\n isMounted = false;\n if (\n loadingTaskRef.current &&\n typeof loadingTaskRef.current.destroy === 'function'\n ) {\n loadingTaskRef.current.destroy();\n loadingTaskRef.current = null;\n }\n };\n }, [ReactPDF, url, controlledPage, onLoadSuccess, onLoadError]);\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === readerRef.current);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n // Don't handle hotkeys if input is focused\n const activeElement = document.activeElement;\n if (\n activeElement &&\n (activeElement.tagName === 'INPUT' ||\n activeElement.getAttribute('role') === 'input')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n handleZoomIn();\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n handleZoomOut();\n }\n // 左箭头: 上一页\n else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handlePreviousPage();\n }\n // 右箭头: 下一页\n else if (e.key === 'ArrowRight') {\n e.preventDefault();\n handleNextPage();\n }\n // F 键: 全屏切换\n else if (e.key === 'f' || e.key === 'F') {\n e.preventDefault();\n void handleToggleFullscreen();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [\n enableHotkeys,\n handleZoomIn,\n handleZoomOut,\n handlePreviousPage,\n handleNextPage,\n handleToggleFullscreen,\n ]);\n\n // ==================== 组件验证和渲染 ====================\n\n // 验证 components\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n Button,\n Input: InputComponentInjected,\n Skeleton,\n } = components;\n\n // 渲染工具栏\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomOut}\n disabled={scale <= minScale}\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"text-sm\">{Math.round(scale * 100)}%</span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomIn}\n disabled={scale >= maxScale}\n >\n <ZoomInIcon />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => {\n void handleToggleFullscreen();\n }}\n >\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n </div>\n );\n };\n\n // 渲染分页控制\n const renderPagination = () => {\n if (!showPagination) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handlePreviousPage}\n disabled={currentPage <= 1}\n >\n <ChevronLeftIcon />\n </Button>\n {InputComponentInjected ? (\n <InputComponentInjected\n type=\"number\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 text-center\"\n />\n ) : (\n <input\n type=\"number\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 rounded-md border border-input bg-background px-2 text-center text-sm\"\n />\n )}\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handleNextPage}\n disabled={currentPage >= totalPages}\n >\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n const renderOperations = () => {\n if (!showToolbar && !showPagination) return null;\n\n return (\n <div\n data-testid=\"pdf-operations-bar\"\n className=\"flex items-center justify-between gap-4 border-b px-4 py-2\"\n >\n {renderToolbar()}\n {renderPagination()}\n </div>\n );\n };\n\n // 渲染加载状态\n const renderLoading = () => (\n <div className=\"flex flex-col items-center justify-center space-y-4 p-8\">\n <Skeleton className=\"h-8 w-32\" />\n <Skeleton className=\"h-64 w-full max-w-2xl\" />\n <p className=\"text-sm text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // 渲染错误状态\n const renderError = () => (\n <div className=\"flex flex-col items-center justify-center space-y-4 p-8\">\n <div className=\"text-center text-destructive\">\n <p className=\"font-medium\">{errorText}</p>\n {error && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{error.message}</p>\n )}\n </div>\n </div>\n );\n\n // 渲染 PDF 文档\n const renderPDFDocument = () => {\n if (!ReactPDF || !pdfDocument) return null;\n\n const { Page } = ReactPDF;\n\n return (\n <div\n className={`flex flex-col items-center justify-center ${\n isFullscreen\n ? 'h-[calc(100vh-56px)] overflow-auto'\n : 'overflow-visible'\n }`}\n >\n {pagesToPreload.map((pageNum) => (\n <div\n key={pageNum}\n className={pageClassName}\n style={{\n display: pageNum === currentPage ? 'block' : 'none',\n }}\n >\n <Page\n pdf={pdfDocument}\n pageNumber={pageNum}\n scale={scale}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n className=\"shadow-md\"\n />\n </div>\n ))}\n </div>\n );\n };\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderOperations()}\n <CardContent className={containerClassName}>\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"names":["SimplePDFReader","url","initialPage","initialScale","controlledScale","onScaleChange","minScale","maxScale","controlledPage","onPageChange","showToolbar","showPagination","enableHotkeys","className","containerClassName","pageClassName","components","onLoadSuccess","onLoadError","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","readerRef","useRef","loadingTaskRef","ReactPDF","setReactPDF","currentPage","scale","pagesToPreload","useMemo","pages","goToPage","useCallback","page","maxPage","targetPage","handlePreviousPage","handleNextPage","handleZoomIn","newScale","handleZoomOut","handleToggleFullscreen","_b","_a","_c","useEffect","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","Document","loadingTask","pdf","prev","handleFullscreenChange","handleKeyDown","e","activeElement","jsx","Card","CardContent","Button","InputComponentInjected","Skeleton","renderToolbar","jsxs","ZoomOutIcon","ZoomInIcon","Minimize2Icon","Maximize2Icon","renderPagination","ChevronLeftIcon","ChevronRightIcon","renderOperations","renderLoading","renderError","renderPDFDocument","Page","pageNum"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"simple-pdf-reader.js","sources":["../src/components/SimplePDFReader.tsx"],"sourcesContent":["import {\n ChevronLeft as ChevronLeftIcon,\n ChevronRight as ChevronRightIcon,\n Maximize2 as Maximize2Icon,\n Minimize2 as Minimize2Icon,\n ZoomIn as ZoomInIcon,\n ZoomOut as ZoomOutIcon,\n} from 'lucide-react';\nimport { useState, useMemo, useCallback, useEffect, useRef } from 'react';\nimport type { HTMLAttributes } from 'react';\n\nimport type {\n CardComponent,\n ButtonComponent,\n InputComponent,\n SkeletonComponent,\n} from '../types/component-types';\n\n/**\n * react-pdf 类型定义\n * 这些类型由 @types/react-pdf 提供,这里我们定义必要的接口\n */\nexport interface PDFDocumentProxy {\n numPages: number;\n getPage(pageNumber: number): Promise<any>;\n}\n\n/**\n * SimplePDFReader UI 组件接口\n */\nexport interface SimplePDFReaderUIComponents {\n Card: CardComponent;\n CardContent: React.ComponentType<HTMLAttributes<HTMLDivElement>>;\n Button: ButtonComponent;\n Input?: InputComponent;\n Skeleton: SkeletonComponent;\n}\n\n/**\n * SimplePDFReader 组件 Props\n */\nexport interface SimplePDFReaderProps {\n // PDF 数据源\n url: string;\n\n // 初始状态\n initialPage?: number;\n initialScale?: number;\n\n // 缩放控制\n scale?: number;\n onScaleChange?: (scale: number) => void;\n minScale?: number;\n maxScale?: number;\n\n // 页面导航\n currentPage?: number;\n onPageChange?: (page: number) => void;\n\n // 功能开关\n showToolbar?: boolean; // 默认 true\n showPagination?: boolean; // 默认 true\n enableHotkeys?: boolean; // 默认 true\n\n // 样式定制\n className?: string;\n containerClassName?: string;\n pageClassName?: string;\n\n // UI 组件注入\n components: SimplePDFReaderUIComponents;\n\n // 回调函数\n onLoadSuccess?: (pdf: PDFDocumentProxy) => void;\n onLoadError?: (error: Error) => void;\n\n // 加载状态文本\n loadingText?: string; // 默认 \"加载中...\"\n errorText?: string; // 默认 \"加载失败\"\n}\n\n/**\n * SimplePDFReader 组件\n *\n * 用于在 React 应用中展示和浏览 PDF 文档。\n * 支持从 URL 加载 PDF,提供基础的浏览功能(翻页、缩放),并包含性能优化。\n *\n * @example\n * ```tsx\n * import { SimplePDFReader } from '@turinhub/atomix-common-ui/simple-pdf-reader';\n * import { Card, Button, Skeleton } from '@/components/ui';\n *\n * <SimplePDFReader\n * url=\"/documents/sample.pdf\"\n * components={{\n * Card,\n * CardContent: Card.Content,\n * Button,\n * Skeleton,\n * }}\n * initialPage={1}\n * initialScale={1.0}\n * showToolbar={true}\n * showPagination={true}\n * enableHotkeys={true}\n * onPageChange={(page) => console.log('Current page:', page)}\n * />\n *\n * Keyboard Shortcuts:\n * - Arrow Left/Right: Navigate pages\n * - Ctrl/Cmd + +/-: Zoom in/out\n * - F: Toggle fullscreen\n * ```\n */\nexport function SimplePDFReader({\n url,\n initialPage = 1,\n initialScale = 1.0,\n scale: controlledScale,\n onScaleChange,\n minScale = 0.5,\n maxScale = 3.0,\n currentPage: controlledPage,\n onPageChange,\n showToolbar = true,\n showPagination = true,\n enableHotkeys = true,\n className,\n containerClassName,\n pageClassName,\n components,\n onLoadSuccess,\n onLoadError,\n loadingText = '加载中...',\n errorText = '加载失败',\n}: SimplePDFReaderProps) {\n // ==================== React Hooks (必须在最顶部) ====================\n\n // 状态管理\n const [pdfDocument, setPdfDocument] = useState<PDFDocumentProxy | null>(null);\n const [internalPage, setInternalPage] = useState(initialPage);\n const [internalScale, setInternalScale] = useState(initialScale);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [totalPages, setTotalPages] = useState(0);\n const [isFullscreen, setIsFullscreen] = useState(false);\n const readerRef = useRef<HTMLDivElement>(null);\n const loadingTaskRef = useRef<any>(null);\n\n // 动态导入 react-pdf\n const [ReactPDF, setReactPDF] = useState<any>(null);\n\n // 使用受控或非受控模式\n const currentPage = controlledPage ?? internalPage;\n const scale = controlledScale ?? internalScale;\n\n // 预渲染相邻页面以提升翻页体验\n const pagesToPreload = useMemo(() => {\n const pages = [currentPage];\n if (currentPage > 1) pages.push(currentPage - 1);\n if (currentPage < totalPages) pages.push(currentPage + 1);\n return pages;\n }, [currentPage, totalPages]);\n\n // 页面导航处理\n const goToPage = useCallback(\n (page: number) => {\n const maxPage = Math.max(totalPages, 1);\n const targetPage = Math.min(Math.max(page, 1), maxPage);\n if (controlledPage === undefined) {\n setInternalPage(targetPage);\n }\n onPageChange?.(targetPage);\n },\n [totalPages, controlledPage, onPageChange]\n );\n\n const handlePreviousPage = useCallback(() => {\n if (currentPage > 1) {\n goToPage(currentPage - 1);\n }\n }, [currentPage, goToPage]);\n\n const handleNextPage = useCallback(() => {\n if (currentPage < totalPages) {\n goToPage(currentPage + 1);\n }\n }, [currentPage, totalPages, goToPage]);\n\n // 缩放控制处理\n const handleZoomIn = useCallback(() => {\n const newScale = Math.min(scale + 0.25, maxScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, maxScale, controlledScale, onScaleChange]);\n\n const handleZoomOut = useCallback(() => {\n const newScale = Math.max(scale - 0.25, minScale);\n if (controlledScale === undefined) {\n setInternalScale(newScale);\n }\n onScaleChange?.(newScale);\n }, [scale, minScale, controlledScale, onScaleChange]);\n\n const handleToggleFullscreen = useCallback(async () => {\n if (typeof document === 'undefined') return;\n\n if (!document.fullscreenElement) {\n await readerRef.current?.requestFullscreen?.();\n return;\n }\n\n await document.exitFullscreen?.();\n }, []);\n\n // 动态导入 react-pdf 和设置 worker\n useEffect(() => {\n let isMounted = true;\n\n const loadReactPDF = async () => {\n try {\n // 动态导入 react-pdf\n const pdfModule = await import('react-pdf');\n // 设置 worker\n if (typeof window !== 'undefined') {\n const pdfjs = (pdfModule as any).pdfjs;\n const workerVersion = pdfjs?.version;\n if (pdfjs?.GlobalWorkerOptions && workerVersion) {\n pdfjs.GlobalWorkerOptions.workerSrc = `https://cdn.jsdelivr.net/npm/pdfjs-dist@${workerVersion}/build/pdf.worker.min.mjs`;\n }\n }\n if (isMounted) {\n setReactPDF(pdfModule);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('无法加载 react-pdf 库');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadReactPDF();\n\n return () => {\n isMounted = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, []);\n\n // 加载 PDF 文档\n useEffect(() => {\n if (!ReactPDF || !url) return;\n\n let isMounted = true;\n\n const loadPDF = async () => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { Document } = ReactPDF;\n if (!Document) {\n throw new Error('react-pdf Document 组件不可用');\n }\n\n // 使用 react-pdf 的 Document 组件内部加载逻辑\n // 我们创建一个加载器来获取 PDF 文档信息\n const loadingTask = (ReactPDF.pdfjs as any).getDocument(url);\n loadingTaskRef.current = loadingTask;\n const pdf = await loadingTask.promise;\n\n if (isMounted) {\n setPdfDocument(pdf as PDFDocumentProxy);\n setTotalPages(pdf.numPages);\n if (controlledPage === undefined) {\n setInternalPage((prev) =>\n Math.max(1, Math.min(prev, pdf.numPages))\n );\n }\n setIsLoading(false);\n onLoadSuccess?.(pdf as PDFDocumentProxy);\n }\n } catch (err) {\n if (isMounted) {\n const loadError =\n err instanceof Error ? err : new Error('PDF 加载失败');\n setError(loadError);\n setIsLoading(false);\n onLoadError?.(loadError);\n }\n }\n };\n\n loadPDF();\n\n return () => {\n isMounted = false;\n if (\n loadingTaskRef.current &&\n typeof loadingTaskRef.current.destroy === 'function'\n ) {\n loadingTaskRef.current.destroy();\n loadingTaskRef.current = null;\n }\n };\n }, [ReactPDF, url, controlledPage, onLoadSuccess, onLoadError]);\n\n useEffect(() => {\n if (typeof document === 'undefined') return;\n\n const handleFullscreenChange = () => {\n setIsFullscreen(document.fullscreenElement === readerRef.current);\n };\n\n document.addEventListener('fullscreenchange', handleFullscreenChange);\n\n return () => {\n document.removeEventListener('fullscreenchange', handleFullscreenChange);\n };\n }, []);\n\n // ==================== 键盘快捷键 ====================\n useEffect(() => {\n if (!enableHotkeys) return;\n\n const handleKeyDown = (e: KeyboardEvent) => {\n const activeElement = document.activeElement as HTMLElement | null;\n const role = activeElement?.getAttribute('role');\n if (\n activeElement &&\n (activeElement.tagName === 'INPUT' ||\n activeElement.tagName === 'TEXTAREA' ||\n activeElement.tagName === 'SELECT' ||\n activeElement.isContentEditable ||\n role === 'textbox' ||\n role === 'spinbutton')\n ) {\n return;\n }\n\n // Ctrl/Cmd + 加号: 放大\n if ((e.ctrlKey || e.metaKey) && (e.key === '=' || e.key === '+')) {\n e.preventDefault();\n handleZoomIn();\n }\n // Ctrl/Cmd + 减号: 缩小\n else if ((e.ctrlKey || e.metaKey) && e.key === '-') {\n e.preventDefault();\n handleZoomOut();\n }\n // 左箭头: 上一页\n else if (e.key === 'ArrowLeft') {\n e.preventDefault();\n handlePreviousPage();\n }\n // 右箭头: 下一页\n else if (e.key === 'ArrowRight') {\n e.preventDefault();\n handleNextPage();\n }\n // F 键: 全屏切换\n else if (e.key === 'f' || e.key === 'F') {\n e.preventDefault();\n void handleToggleFullscreen();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => {\n document.removeEventListener('keydown', handleKeyDown);\n };\n }, [\n enableHotkeys,\n handleZoomIn,\n handleZoomOut,\n handlePreviousPage,\n handleNextPage,\n handleToggleFullscreen,\n ]);\n\n // ==================== 组件验证和渲染 ====================\n\n // 验证 components\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const {\n Card,\n CardContent,\n Button,\n Input: InputComponentInjected,\n Skeleton,\n } = components;\n\n // 渲染工具栏\n const renderToolbar = () => {\n if (!showToolbar) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomOut}\n disabled={scale <= minScale}\n aria-label=\"缩小\"\n title=\"缩小\"\n >\n <ZoomOutIcon />\n </Button>\n <span className=\"text-sm\">{Math.round(scale * 100)}%</span>\n <Button\n variant=\"outline\"\n size=\"sm\"\n onClick={handleZoomIn}\n disabled={scale >= maxScale}\n aria-label=\"放大\"\n title=\"放大\"\n >\n <ZoomInIcon />\n </Button>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={() => {\n void handleToggleFullscreen();\n }}\n aria-label={isFullscreen ? '退出全屏' : '进入全屏'}\n title={isFullscreen ? '退出全屏' : '进入全屏'}\n >\n {isFullscreen ? <Minimize2Icon /> : <Maximize2Icon />}\n </Button>\n </div>\n );\n };\n\n // 渲染分页控制\n const renderPagination = () => {\n if (!showPagination) return null;\n\n return (\n <div className=\"flex items-center gap-2\">\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handlePreviousPage}\n disabled={currentPage <= 1}\n aria-label=\"上一页\"\n title=\"上一页\"\n >\n <ChevronLeftIcon />\n </Button>\n {InputComponentInjected ? (\n <InputComponentInjected\n type=\"number\"\n name=\"simple-pdf-page\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 text-center\"\n aria-label=\"当前页码\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n />\n ) : (\n <input\n type=\"number\"\n name=\"simple-pdf-page\"\n min={1}\n max={Math.max(totalPages, 1)}\n value={currentPage}\n onChange={(e) => goToPage(parseInt(e.target.value, 10) || 1)}\n className=\"w-16 rounded-md border border-input bg-background px-2 text-center text-sm\"\n aria-label=\"当前页码\"\n inputMode=\"numeric\"\n autoComplete=\"off\"\n />\n )}\n <span className=\"text-sm text-muted-foreground\">/ {totalPages}</span>\n <Button\n variant=\"outline\"\n size=\"icon\"\n onClick={handleNextPage}\n disabled={currentPage >= totalPages}\n aria-label=\"下一页\"\n title=\"下一页\"\n >\n <ChevronRightIcon />\n </Button>\n </div>\n );\n };\n\n const renderOperations = () => {\n if (!showToolbar && !showPagination) return null;\n\n return (\n <div\n data-testid=\"pdf-operations-bar\"\n className=\"flex items-center justify-between gap-4 border-b px-4 py-2\"\n >\n {renderToolbar()}\n {renderPagination()}\n </div>\n );\n };\n\n // 渲染加载状态\n const renderLoading = () => (\n <div\n className=\"flex flex-col items-center justify-center space-y-4 p-8\"\n role=\"status\"\n aria-live=\"polite\"\n >\n <Skeleton className=\"h-8 w-32\" />\n <Skeleton className=\"h-64 w-full max-w-2xl\" />\n <p className=\"text-sm text-muted-foreground\">{loadingText}</p>\n </div>\n );\n\n // 渲染错误状态\n const renderError = () => (\n <div\n className=\"flex flex-col items-center justify-center space-y-4 p-8\"\n role=\"alert\"\n >\n <div className=\"text-center text-destructive\">\n <p className=\"font-medium\">{errorText}</p>\n {error && (\n <p className=\"mt-2 text-sm text-muted-foreground\">{error.message}</p>\n )}\n </div>\n </div>\n );\n\n // 渲染 PDF 文档\n const renderPDFDocument = () => {\n if (!ReactPDF || !pdfDocument) return null;\n\n const { Page } = ReactPDF;\n\n return (\n <div\n className={`flex flex-col items-center justify-center ${\n isFullscreen\n ? 'h-[calc(100vh-56px)] overflow-auto'\n : 'overflow-visible'\n }`}\n >\n {pagesToPreload.map((pageNum) => (\n <div\n key={pageNum}\n className={pageClassName}\n style={{\n display: pageNum === currentPage ? 'block' : 'none',\n }}\n >\n <Page\n pdf={pdfDocument}\n pageNumber={pageNum}\n scale={scale}\n renderTextLayer={false}\n renderAnnotationLayer={false}\n className=\"shadow-md\"\n />\n </div>\n ))}\n </div>\n );\n };\n\n return (\n <div ref={readerRef}>\n <Card className={className}>\n {renderOperations()}\n <CardContent className={containerClassName}>\n {isLoading\n ? renderLoading()\n : error\n ? renderError()\n : renderPDFDocument()}\n </CardContent>\n </Card>\n </div>\n );\n}\n"],"names":["SimplePDFReader","url","initialPage","initialScale","controlledScale","onScaleChange","minScale","maxScale","controlledPage","onPageChange","showToolbar","showPagination","enableHotkeys","className","containerClassName","pageClassName","components","onLoadSuccess","onLoadError","loadingText","errorText","pdfDocument","setPdfDocument","useState","internalPage","setInternalPage","internalScale","setInternalScale","isLoading","setIsLoading","error","setError","totalPages","setTotalPages","isFullscreen","setIsFullscreen","readerRef","useRef","loadingTaskRef","ReactPDF","setReactPDF","currentPage","scale","pagesToPreload","useMemo","pages","goToPage","useCallback","page","maxPage","targetPage","handlePreviousPage","handleNextPage","handleZoomIn","newScale","handleZoomOut","handleToggleFullscreen","_b","_a","_c","useEffect","isMounted","pdfModule","pdfjs","workerVersion","err","loadError","Document","loadingTask","pdf","prev","handleFullscreenChange","handleKeyDown","e","activeElement","role","jsx","Card","CardContent","Button","InputComponentInjected","Skeleton","renderToolbar","jsxs","ZoomOutIcon","ZoomInIcon","Minimize2Icon","Maximize2Icon","renderPagination","ChevronLeftIcon","ChevronRightIcon","renderOperations","renderLoading","renderError","renderPDFDocument","Page","pageNum"],"mappings":"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"}
|
package/dist/table-header.cjs
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./jsx-runtime-BB_1_6y_.cjs"),d=require("lucide-react");function R({title:
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("./jsx-runtime-BB_1_6y_.cjs"),d=require("lucide-react"),E=require("react");function R({title:c,searchPlaceholder:n="搜索...",searchValue:p="",onSearchChange:i,onSearch:t,showSearch:j=!0,action:r,actionLabel:x,onActionClick:m,loading:l=!1,components:o}){const a=E.useId();if(!o)return e.jsxRuntimeExports.jsx("div",{className:"p-4 text-center text-destructive",children:"错误:请通过 components prop 注入 UI 组件"});const{Input:f,Button:u}=o,v=s=>{s.nativeEvent.isComposing||s.nativeEvent.isComposing||s.key==="Enter"&&t&&t()};return e.jsxRuntimeExports.jsxs("div",{className:"flex min-w-0 flex-col gap-4 p-1",children:[e.jsxRuntimeExports.jsxs("div",{className:"flex min-w-0 flex-col gap-3 sm:flex-row sm:items-center sm:justify-between",children:[e.jsxRuntimeExports.jsx("div",{className:"min-w-0 break-words text-lg font-semibold leading-tight text-foreground",children:c}),e.jsxRuntimeExports.jsxs("div",{className:"flex shrink-0 items-center gap-2",children:[r&&e.jsxRuntimeExports.jsx("div",{className:"flex min-w-0 items-center gap-2",children:r}),!r&&x&&m&&e.jsxRuntimeExports.jsxs(u,{onClick:m,disabled:l,size:"sm",children:[e.jsxRuntimeExports.jsx(d.Plus,{className:"mr-2 h-4 w-4"}),x]})]})]}),j&&e.jsxRuntimeExports.jsxs("div",{className:"flex min-w-0 flex-col gap-2 sm:flex-row sm:items-center",children:[e.jsxRuntimeExports.jsxs("div",{className:"relative min-w-0 flex-1 sm:max-w-sm",children:[e.jsxRuntimeExports.jsx("label",{htmlFor:a,className:"sr-only",children:n}),e.jsxRuntimeExports.jsx(d.Search,{className:"absolute left-2 top-2.5 h-4 w-4 text-muted-foreground"}),e.jsxRuntimeExports.jsx(f,{id:a,name:"table-search",type:"search",placeholder:n,value:p,onChange:s=>i==null?void 0:i(s.target.value),onKeyDown:v,className:"h-9 pl-8",disabled:l,autoComplete:"off",spellCheck:!1})]}),t&&e.jsxRuntimeExports.jsx(u,{onClick:t,disabled:l,variant:"secondary",size:"sm",children:"搜索"})]})]})}exports.TableHeader=R;
|
|
2
2
|
//# sourceMappingURL=table-header.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"table-header.cjs","sources":["../src/components/TableHeader.tsx"],"sourcesContent":["import { Plus, Search } from 'lucide-react';\nimport { ReactNode } from 'react';\n\nimport type { InputComponent, ButtonComponent } from '../types/component-types';\n\n/**\n * UI 组件适配器接口\n */\nexport interface HeaderUIComponents {\n Input: InputComponent;\n Button: ButtonComponent;\n}\n\nexport interface TableHeaderProps {\n title: ReactNode;\n searchPlaceholder?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n onSearch?: () => void;\n showSearch?: boolean;\n action?: ReactNode;\n actionLabel?: string;\n onActionClick?: () => void;\n loading?: boolean;\n\n // UI 组件注入\n components?: HeaderUIComponents;\n}\n\n/**\n * 表格头部组件\n * 支持搜索框和操作按钮\n */\nexport function TableHeader({\n title,\n searchPlaceholder = '搜索...',\n searchValue = '',\n onSearchChange,\n onSearch,\n showSearch = true,\n action,\n actionLabel,\n onActionClick,\n loading = false,\n components,\n}: TableHeaderProps) {\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const { Input, Button } = components;\n\n const
|
|
1
|
+
{"version":3,"file":"table-header.cjs","sources":["../src/components/TableHeader.tsx"],"sourcesContent":["import { Plus, Search } from 'lucide-react';\nimport { ReactNode, useId } from 'react';\n\nimport type { InputComponent, ButtonComponent } from '../types/component-types';\n\n/**\n * UI 组件适配器接口\n */\nexport interface HeaderUIComponents {\n Input: InputComponent;\n Button: ButtonComponent;\n}\n\nexport interface TableHeaderProps {\n title: ReactNode;\n searchPlaceholder?: string;\n searchValue?: string;\n onSearchChange?: (value: string) => void;\n onSearch?: () => void;\n showSearch?: boolean;\n action?: ReactNode;\n actionLabel?: string;\n onActionClick?: () => void;\n loading?: boolean;\n\n // UI 组件注入\n components?: HeaderUIComponents;\n}\n\n/**\n * 表格头部组件\n * 支持搜索框和操作按钮\n */\nexport function TableHeader({\n title,\n searchPlaceholder = '搜索...',\n searchValue = '',\n onSearchChange,\n onSearch,\n showSearch = true,\n action,\n actionLabel,\n onActionClick,\n loading = false,\n components,\n}: TableHeaderProps) {\n const searchInputId = useId();\n\n if (!components) {\n return (\n <div className=\"p-4 text-center text-destructive\">\n 错误:请通过 components prop 注入 UI 组件\n </div>\n );\n }\n\n const { Input, Button } = components;\n\n const handleKeyDown = (e: React.KeyboardEvent) => {\n const isComposing =\n e.nativeEvent.isComposing ||\n (e.nativeEvent as KeyboardEvent & { isComposing?: boolean }).isComposing;\n if (isComposing) {\n return;\n }\n if (e.key === 'Enter' && onSearch) {\n onSearch();\n }\n };\n\n return (\n <div className=\"flex min-w-0 flex-col gap-4 p-1\">\n <div className=\"flex min-w-0 flex-col gap-3 sm:flex-row sm:items-center sm:justify-between\">\n <div className=\"min-w-0 break-words text-lg font-semibold leading-tight text-foreground\">\n {title}\n </div>\n <div className=\"flex shrink-0 items-center gap-2\">\n {action && (\n <div className=\"flex min-w-0 items-center gap-2\">{action}</div>\n )}\n {!action && actionLabel && onActionClick && (\n <Button onClick={onActionClick} disabled={loading} size=\"sm\">\n <Plus className=\"mr-2 h-4 w-4\" />\n {actionLabel}\n </Button>\n )}\n </div>\n </div>\n {showSearch && (\n <div className=\"flex min-w-0 flex-col gap-2 sm:flex-row sm:items-center\">\n <div className=\"relative min-w-0 flex-1 sm:max-w-sm\">\n <label htmlFor={searchInputId} className=\"sr-only\">\n {searchPlaceholder}\n </label>\n <Search className=\"absolute left-2 top-2.5 h-4 w-4 text-muted-foreground\" />\n <Input\n id={searchInputId}\n name=\"table-search\"\n type=\"search\"\n placeholder={searchPlaceholder}\n value={searchValue}\n onChange={(e: React.ChangeEvent<HTMLInputElement>) =>\n onSearchChange?.(e.target.value)\n }\n onKeyDown={handleKeyDown}\n className=\"h-9 pl-8\"\n disabled={loading}\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n {onSearch && (\n <Button\n onClick={onSearch}\n disabled={loading}\n variant=\"secondary\"\n size=\"sm\"\n >\n 搜索\n </Button>\n )}\n </div>\n )}\n </div>\n );\n}\n"],"names":["TableHeader","title","searchPlaceholder","searchValue","onSearchChange","onSearch","showSearch","action","actionLabel","onActionClick","loading","components","searchInputId","useId","jsx","Input","Button","handleKeyDown","e","jsxs","Plus","Search"],"mappings":"2KAiCO,SAASA,EAAY,CAC1B,MAAAC,EACA,kBAAAC,EAAoB,QACpB,YAAAC,EAAc,GACd,eAAAC,EACA,SAAAC,EACA,WAAAC,EAAa,GACb,OAAAC,EACA,YAAAC,EACA,cAAAC,EACA,QAAAC,EAAU,GACV,WAAAC,CACF,EAAqB,CACnB,MAAMC,EAAgBC,EAAAA,MAAA,EAEtB,GAAI,CAACF,EACH,OACEG,EAAAA,kBAAAA,IAAC,MAAA,CAAI,UAAU,mCAAmC,SAAA,kCAElD,EAIJ,KAAM,CAAE,MAAAC,EAAO,OAAAC,CAAA,EAAWL,EAEpBM,EAAiBC,GAA2B,CAE9CA,EAAE,YAAY,aACbA,EAAE,YAA0D,aAI3DA,EAAE,MAAQ,SAAWb,GACvBA,EAAA,CAEJ,EAEA,OACEc,EAAAA,kBAAAA,KAAC,MAAA,CAAI,UAAU,kCACb,SAAA,CAAAA,EAAAA,kBAAAA,KAAC,MAAA,CAAI,UAAU,6EACb,SAAA,CAAAL,EAAAA,kBAAAA,IAAC,MAAA,CAAI,UAAU,0EACZ,SAAAb,EACH,EACAkB,EAAAA,kBAAAA,KAAC,MAAA,CAAI,UAAU,mCACZ,SAAA,CAAAZ,GACCO,EAAAA,kBAAAA,IAAC,MAAA,CAAI,UAAU,kCAAmC,SAAAP,EAAO,EAE1D,CAACA,GAAUC,GAAeC,GACzBU,EAAAA,kBAAAA,KAACH,EAAA,CAAO,QAASP,EAAe,SAAUC,EAAS,KAAK,KACtD,SAAA,CAAAI,EAAAA,kBAAAA,IAACM,EAAAA,KAAA,CAAK,UAAU,cAAA,CAAe,EAC9BZ,CAAA,CAAA,CACH,CAAA,CAAA,CAEJ,CAAA,EACF,EACCF,GACCa,EAAAA,kBAAAA,KAAC,MAAA,CAAI,UAAU,0DACb,SAAA,CAAAA,EAAAA,kBAAAA,KAAC,MAAA,CAAI,UAAU,sCACb,SAAA,CAAAL,wBAAC,QAAA,CAAM,QAASF,EAAe,UAAU,UACtC,SAAAV,EACH,EACAY,EAAAA,kBAAAA,IAACO,EAAAA,OAAA,CAAO,UAAU,uDAAA,CAAwD,EAC1EP,EAAAA,kBAAAA,IAACC,EAAA,CACC,GAAIH,EACJ,KAAK,eACL,KAAK,SACL,YAAaV,EACb,MAAOC,EACP,SAAWe,GACTd,GAAA,YAAAA,EAAiBc,EAAE,OAAO,OAE5B,UAAWD,EACX,UAAU,WACV,SAAUP,EACV,aAAa,MACb,WAAY,EAAA,CAAA,CACd,EACF,EACCL,GACCS,EAAAA,kBAAAA,IAACE,EAAA,CACC,QAASX,EACT,SAAUK,EACV,QAAQ,YACR,KAAK,KACN,SAAA,IAAA,CAAA,CAED,CAAA,CAEJ,CAAA,EAEJ,CAEJ"}
|