@hypercard-ai/hyper-jump 0.3.2 → 1.0.2
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 +135 -32
- package/dist/index.css +1 -139
- package/dist/index.css.map +1 -1
- package/dist/index.d.ts +4 -28
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +40 -306
- package/dist/index.js.map +1 -1
- package/dist/lib/types.d.ts +31 -0
- package/dist/lib/types.d.ts.map +1 -0
- package/dist/lib/use-element-size.d.ts +6 -0
- package/dist/lib/use-element-size.d.ts.map +1 -0
- package/dist/pdf/constants.d.ts +3 -0
- package/dist/pdf/constants.d.ts.map +1 -0
- package/dist/pdf/controls.d.ts +13 -0
- package/dist/pdf/controls.d.ts.map +1 -0
- package/dist/pdf/error-page.d.ts +3 -0
- package/dist/pdf/error-page.d.ts.map +1 -0
- package/dist/pdf/index.css +148 -0
- package/dist/pdf/index.css.map +1 -0
- package/dist/pdf/index.d.ts +3 -0
- package/dist/pdf/index.d.ts.map +1 -0
- package/dist/pdf/index.js +315 -0
- package/dist/pdf/index.js.map +1 -0
- package/dist/pdf/loading-page.d.ts +3 -0
- package/dist/pdf/loading-page.d.ts.map +1 -0
- package/dist/pdf/pdf-viewer.d.ts +13 -0
- package/dist/pdf/pdf-viewer.d.ts.map +1 -0
- package/dist/pdf/renderer.d.ts +8 -0
- package/dist/pdf/renderer.d.ts.map +1 -0
- package/dist/pdf/utils.d.ts +6 -0
- package/dist/pdf/utils.d.ts.map +1 -0
- package/dist/pdf/viewer.stories.d.ts +11 -0
- package/dist/pdf/viewer.stories.d.ts.map +1 -0
- package/dist/video/index.css +18 -0
- package/dist/video/index.css.map +1 -0
- package/dist/video/index.d.ts +3 -0
- package/dist/video/index.d.ts.map +1 -0
- package/dist/video/index.js +48 -0
- package/dist/video/index.js.map +1 -0
- package/dist/video/video-viewer.d.ts +10 -0
- package/dist/video/video-viewer.d.ts.map +1 -0
- package/dist/video/viewer.stories.d.ts +9 -0
- package/dist/video/viewer.stories.d.ts.map +1 -0
- package/dist/viewer/viewer.d.ts +20 -0
- package/dist/viewer/viewer.d.ts.map +1 -0
- package/package.json +26 -9
package/dist/index.js
CHANGED
|
@@ -1,145 +1,7 @@
|
|
|
1
|
-
|
|
1
|
+
// src/viewer/viewer.tsx
|
|
2
|
+
import { useMemo } from "react";
|
|
2
3
|
|
|
3
|
-
// src/
|
|
4
|
-
import {
|
|
5
|
-
useCallback as useCallback2,
|
|
6
|
-
useEffect,
|
|
7
|
-
useImperativeHandle,
|
|
8
|
-
useMemo,
|
|
9
|
-
useRef as useRef2,
|
|
10
|
-
useState as useState2
|
|
11
|
-
} from "react";
|
|
12
|
-
import { Document, pdfjs } from "react-pdf";
|
|
13
|
-
import "react-pdf/dist/Page/AnnotationLayer.css";
|
|
14
|
-
import "react-pdf/dist/Page/TextLayer.css";
|
|
15
|
-
import { List } from "react-window";
|
|
16
|
-
|
|
17
|
-
// src/controls.tsx
|
|
18
|
-
import { jsx, jsxs } from "react/jsx-runtime";
|
|
19
|
-
var ZOOM_OPTIONS = [
|
|
20
|
-
{ label: "Auto Width", value: "automatic" },
|
|
21
|
-
{ label: "50%", value: "0.5" },
|
|
22
|
-
{ label: "75%", value: "0.75" },
|
|
23
|
-
{ label: "100%", value: "1" },
|
|
24
|
-
{ label: "125%", value: "1.25" },
|
|
25
|
-
{ label: "150%", value: "1.5" },
|
|
26
|
-
{ label: "200%", value: "2" },
|
|
27
|
-
{ label: "300%", value: "3" },
|
|
28
|
-
{ label: "400%", value: "4" }
|
|
29
|
-
];
|
|
30
|
-
function ChevronLeft() {
|
|
31
|
-
return /* @__PURE__ */ jsxs(
|
|
32
|
-
"svg",
|
|
33
|
-
{
|
|
34
|
-
width: "16",
|
|
35
|
-
height: "16",
|
|
36
|
-
viewBox: "0 0 24 24",
|
|
37
|
-
fill: "none",
|
|
38
|
-
stroke: "currentColor",
|
|
39
|
-
strokeWidth: "2",
|
|
40
|
-
strokeLinecap: "round",
|
|
41
|
-
strokeLinejoin: "round",
|
|
42
|
-
children: [
|
|
43
|
-
/* @__PURE__ */ jsx("title", { children: "Previous Page" }),
|
|
44
|
-
/* @__PURE__ */ jsx("path", { d: "M15 18l-6-6 6-6" })
|
|
45
|
-
]
|
|
46
|
-
}
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
function ChevronRight() {
|
|
50
|
-
return /* @__PURE__ */ jsxs(
|
|
51
|
-
"svg",
|
|
52
|
-
{
|
|
53
|
-
width: "16",
|
|
54
|
-
height: "16",
|
|
55
|
-
viewBox: "0 0 24 24",
|
|
56
|
-
fill: "none",
|
|
57
|
-
stroke: "currentColor",
|
|
58
|
-
strokeWidth: "2",
|
|
59
|
-
strokeLinecap: "round",
|
|
60
|
-
strokeLinejoin: "round",
|
|
61
|
-
children: [
|
|
62
|
-
/* @__PURE__ */ jsx("title", { children: "Next Page" }),
|
|
63
|
-
/* @__PURE__ */ jsx("path", { d: "M9 18l6-6-6 6" })
|
|
64
|
-
]
|
|
65
|
-
}
|
|
66
|
-
);
|
|
67
|
-
}
|
|
68
|
-
function PDFViewerControls(props) {
|
|
69
|
-
const {
|
|
70
|
-
onChangeZoom,
|
|
71
|
-
pageIndex,
|
|
72
|
-
numPages,
|
|
73
|
-
zoomConfig,
|
|
74
|
-
onNextPage,
|
|
75
|
-
onPrevPage
|
|
76
|
-
} = props;
|
|
77
|
-
const zoomValue = zoomConfig.mode === "automatic" || zoomConfig.mode === "page-width" ? zoomConfig.mode : zoomConfig.value.toString();
|
|
78
|
-
return /* @__PURE__ */ jsx("div", { className: "hj-controls", children: /* @__PURE__ */ jsxs("div", { className: "hj-controls-bar", children: [
|
|
79
|
-
/* @__PURE__ */ jsxs("div", { className: "hj-controls-group", children: [
|
|
80
|
-
/* @__PURE__ */ jsx(
|
|
81
|
-
"button",
|
|
82
|
-
{
|
|
83
|
-
type: "button",
|
|
84
|
-
className: "hj-icon-btn",
|
|
85
|
-
onClick: onPrevPage,
|
|
86
|
-
disabled: pageIndex <= 0,
|
|
87
|
-
"aria-label": "Previous Page",
|
|
88
|
-
children: /* @__PURE__ */ jsx(ChevronLeft, {})
|
|
89
|
-
}
|
|
90
|
-
),
|
|
91
|
-
/* @__PURE__ */ jsxs("span", { className: "hj-page-indicator", children: [
|
|
92
|
-
pageIndex + 1,
|
|
93
|
-
" / ",
|
|
94
|
-
numPages
|
|
95
|
-
] }),
|
|
96
|
-
/* @__PURE__ */ jsx(
|
|
97
|
-
"button",
|
|
98
|
-
{
|
|
99
|
-
type: "button",
|
|
100
|
-
className: "hj-icon-btn",
|
|
101
|
-
onClick: onNextPage,
|
|
102
|
-
disabled: pageIndex >= numPages - 1,
|
|
103
|
-
"aria-label": "Next Page",
|
|
104
|
-
children: /* @__PURE__ */ jsx(ChevronRight, {})
|
|
105
|
-
}
|
|
106
|
-
)
|
|
107
|
-
] }),
|
|
108
|
-
/* @__PURE__ */ jsx("div", { className: "hj-divider" }),
|
|
109
|
-
/* @__PURE__ */ jsx(
|
|
110
|
-
"select",
|
|
111
|
-
{
|
|
112
|
-
className: "hj-select",
|
|
113
|
-
value: zoomValue,
|
|
114
|
-
onChange: (e) => onChangeZoom(e.target.value),
|
|
115
|
-
"aria-label": "Zoom Level",
|
|
116
|
-
children: ZOOM_OPTIONS.map((opt) => /* @__PURE__ */ jsx("option", { value: opt.value, children: opt.label }, opt.value))
|
|
117
|
-
}
|
|
118
|
-
)
|
|
119
|
-
] }) });
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// src/error-page.tsx
|
|
123
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
124
|
-
function PDFErrorPage() {
|
|
125
|
-
return /* @__PURE__ */ jsx2("div", { className: "hj-error", children: "Error loading file" });
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
// src/loading-page.tsx
|
|
129
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
130
|
-
function PDFLoadingPage() {
|
|
131
|
-
return /* @__PURE__ */ jsx3("div", { className: "hj-loading", children: /* @__PURE__ */ jsx3("div", { className: "hj-spinner" }) });
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
// src/renderer.tsx
|
|
135
|
-
import { Page } from "react-pdf";
|
|
136
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
137
|
-
function PDFPageRenderer(props) {
|
|
138
|
-
const { index, style, scale } = props;
|
|
139
|
-
return /* @__PURE__ */ jsx4("div", { className: "hj-page", style, children: /* @__PURE__ */ jsx4(Page, { pageIndex: index, scale, loading: PDFLoadingPage }) });
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// src/use-element-size.ts
|
|
4
|
+
// src/lib/use-element-size.ts
|
|
143
5
|
import { useCallback, useRef, useState } from "react";
|
|
144
6
|
function useElementSize() {
|
|
145
7
|
const [size, setSize] = useState({ width: 0, height: 0 });
|
|
@@ -164,178 +26,50 @@ function useElementSize() {
|
|
|
164
26
|
return { ref, width: size.width, height: size.height };
|
|
165
27
|
}
|
|
166
28
|
|
|
167
|
-
// src/
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
const viewport = page.getViewport({ scale });
|
|
178
|
-
const { height, width } = viewport;
|
|
179
|
-
dims.push({ height, width });
|
|
180
|
-
} catch (error) {
|
|
181
|
-
console.error("Failed to get page dimensions", error);
|
|
182
|
-
dims.push({
|
|
183
|
-
width: PAGE_WIDTH,
|
|
184
|
-
height: PAGE_HEIGHT
|
|
185
|
-
});
|
|
186
|
-
}
|
|
29
|
+
// src/viewer/viewer.tsx
|
|
30
|
+
import { jsx } from "react/jsx-runtime";
|
|
31
|
+
function getExtension(url) {
|
|
32
|
+
try {
|
|
33
|
+
const pathname = new URL(url, "https://placeholder.com").pathname;
|
|
34
|
+
const dot = pathname.lastIndexOf(".");
|
|
35
|
+
if (dot === -1) return null;
|
|
36
|
+
return pathname.slice(dot + 1).toLowerCase();
|
|
37
|
+
} catch {
|
|
38
|
+
return null;
|
|
187
39
|
}
|
|
188
|
-
return dims;
|
|
189
40
|
}
|
|
190
|
-
|
|
191
|
-
// src/viewer.tsx
|
|
192
|
-
import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
193
|
-
pdfjs.GlobalWorkerOptions.workerSrc = new URL(
|
|
194
|
-
"pdfjs-dist/build/pdf.worker.min.mjs",
|
|
195
|
-
import.meta.url
|
|
196
|
-
).toString();
|
|
197
|
-
var PAGE_MARGIN = 12;
|
|
198
41
|
function HyperJumpViewer(props) {
|
|
199
42
|
const {
|
|
200
43
|
url,
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
44
|
+
type,
|
|
45
|
+
renderers,
|
|
46
|
+
ref,
|
|
47
|
+
initialPosition,
|
|
48
|
+
onPositionChange,
|
|
49
|
+
rendererProps
|
|
205
50
|
} = props;
|
|
206
|
-
const
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
const scrollToPage = useCallback2(
|
|
227
|
-
(target) => {
|
|
228
|
-
if (numPages === 0 || pageDimensions.length !== numPages) return;
|
|
229
|
-
const clamped = Math.max(0, Math.min(Math.floor(target), numPages - 1));
|
|
230
|
-
listRef.current?.scrollToRow({
|
|
231
|
-
index: clamped,
|
|
232
|
-
align: "start",
|
|
233
|
-
behavior: scrollBehavior
|
|
234
|
-
});
|
|
235
|
-
setPageIndex(clamped);
|
|
236
|
-
},
|
|
237
|
-
[numPages, pageDimensions, scrollBehavior]
|
|
238
|
-
);
|
|
239
|
-
useImperativeHandle(ref, () => ({ jumpToPage: scrollToPage }), [
|
|
240
|
-
scrollToPage
|
|
241
|
-
]);
|
|
242
|
-
const hasAppliedInitialPage = useRef2(false);
|
|
243
|
-
const onLoadSuccess = useCallback2((response) => {
|
|
244
|
-
hasAppliedInitialPage.current = false;
|
|
245
|
-
setDocument(response);
|
|
246
|
-
}, []);
|
|
247
|
-
useEffect(() => {
|
|
248
|
-
if (!hasAppliedInitialPage.current && initialPage !== void 0 && pageDimensions.length === numPages && numPages > 0) {
|
|
249
|
-
hasAppliedInitialPage.current = true;
|
|
250
|
-
const id = requestAnimationFrame(() => scrollToPage(initialPage));
|
|
251
|
-
return () => cancelAnimationFrame(id);
|
|
252
|
-
}
|
|
253
|
-
}, [initialPage, pageDimensions, numPages, scrollToPage]);
|
|
254
|
-
const file = useMemo(() => {
|
|
255
|
-
return { url };
|
|
256
|
-
}, [url]);
|
|
257
|
-
const onPrevPage = useCallback2(() => {
|
|
258
|
-
if (pageIndex > 0) {
|
|
259
|
-
const newPageIndex = pageIndex - 1;
|
|
260
|
-
listRef.current?.scrollToRow({
|
|
261
|
-
index: newPageIndex,
|
|
262
|
-
align: "start",
|
|
263
|
-
behavior: scrollBehavior
|
|
264
|
-
});
|
|
265
|
-
setPageIndex(newPageIndex);
|
|
266
|
-
}
|
|
267
|
-
}, [pageIndex, scrollBehavior]);
|
|
268
|
-
const onNextPage = useCallback2(() => {
|
|
269
|
-
if (pageIndex < numPages - 1) {
|
|
270
|
-
const newPageIndex = pageIndex + 1;
|
|
271
|
-
listRef.current?.scrollToRow({
|
|
272
|
-
index: newPageIndex,
|
|
273
|
-
align: "start",
|
|
274
|
-
behavior: scrollBehavior
|
|
275
|
-
});
|
|
276
|
-
setPageIndex(newPageIndex);
|
|
277
|
-
}
|
|
278
|
-
}, [pageIndex, numPages, scrollBehavior]);
|
|
279
|
-
const onChangeZoom = useCallback2((value) => {
|
|
280
|
-
if (value === "automatic") {
|
|
281
|
-
setZoomConfig({ mode: "automatic", value: 1 });
|
|
282
|
-
} else {
|
|
283
|
-
setZoomConfig({ mode: "manual", value: Number.parseFloat(value) });
|
|
51
|
+
const {
|
|
52
|
+
ref: containerRef,
|
|
53
|
+
width: containerWidth,
|
|
54
|
+
height: containerHeight
|
|
55
|
+
} = useElementSize();
|
|
56
|
+
const renderer = useMemo(() => {
|
|
57
|
+
const ext = type ?? getExtension(url);
|
|
58
|
+
if (!ext) return null;
|
|
59
|
+
return renderers.find((r) => r.type === ext || r.extensions.includes(ext));
|
|
60
|
+
}, [url, type, renderers]);
|
|
61
|
+
return /* @__PURE__ */ jsx("div", { className: "hj-viewer", ref: containerRef, children: renderer ? /* @__PURE__ */ jsx(
|
|
62
|
+
renderer.Component,
|
|
63
|
+
{
|
|
64
|
+
ref,
|
|
65
|
+
url,
|
|
66
|
+
containerWidth,
|
|
67
|
+
containerHeight,
|
|
68
|
+
initialPosition,
|
|
69
|
+
onPositionChange,
|
|
70
|
+
...rendererProps
|
|
284
71
|
}
|
|
285
|
-
|
|
286
|
-
const getItemSize = useCallback2(
|
|
287
|
-
(index) => {
|
|
288
|
-
if (pageDimensions[index]) {
|
|
289
|
-
return pageDimensions[index].height + PAGE_MARGIN;
|
|
290
|
-
}
|
|
291
|
-
return 0;
|
|
292
|
-
},
|
|
293
|
-
[pageDimensions]
|
|
294
|
-
);
|
|
295
|
-
const onRowsRendered = useCallback2(
|
|
296
|
-
(visibleRows) => {
|
|
297
|
-
const prev = scrollPageRef.current;
|
|
298
|
-
scrollPageRef.current = visibleRows.startIndex;
|
|
299
|
-
if (visibleRows.startIndex !== prev) {
|
|
300
|
-
setPageIndex(visibleRows.startIndex);
|
|
301
|
-
onPageChange?.(visibleRows.startIndex);
|
|
302
|
-
}
|
|
303
|
-
},
|
|
304
|
-
[onPageChange]
|
|
305
|
-
);
|
|
306
|
-
return /* @__PURE__ */ jsxs2("div", { className: "hj-viewer", ref: containerRef, children: [
|
|
307
|
-
file ? /* @__PURE__ */ jsx5(
|
|
308
|
-
Document,
|
|
309
|
-
{
|
|
310
|
-
file,
|
|
311
|
-
onLoadSuccess,
|
|
312
|
-
error: PDFErrorPage,
|
|
313
|
-
loading: PDFLoadingPage,
|
|
314
|
-
children: pageDimensions.length > 0 && pageDimensions.length === numPages && /* @__PURE__ */ jsx5(
|
|
315
|
-
List,
|
|
316
|
-
{
|
|
317
|
-
listRef,
|
|
318
|
-
rowCount: numPages,
|
|
319
|
-
rowHeight: getItemSize,
|
|
320
|
-
onRowsRendered,
|
|
321
|
-
rowProps: { scale: zoomConfig.value },
|
|
322
|
-
rowComponent: PDFPageRenderer
|
|
323
|
-
}
|
|
324
|
-
)
|
|
325
|
-
}
|
|
326
|
-
) : /* @__PURE__ */ jsx5(PDFLoadingPage, {}),
|
|
327
|
-
/* @__PURE__ */ jsx5(
|
|
328
|
-
PDFViewerControls,
|
|
329
|
-
{
|
|
330
|
-
pageIndex,
|
|
331
|
-
numPages,
|
|
332
|
-
onPrevPage,
|
|
333
|
-
onNextPage,
|
|
334
|
-
zoomConfig,
|
|
335
|
-
onChangeZoom
|
|
336
|
-
}
|
|
337
|
-
)
|
|
338
|
-
] });
|
|
72
|
+
) : /* @__PURE__ */ jsx("div", { className: "hj-error", children: "Unsupported file type" }) });
|
|
339
73
|
}
|
|
340
74
|
export {
|
|
341
75
|
HyperJumpViewer
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/viewer.tsx","../src/controls.tsx","../src/error-page.tsx","../src/loading-page.tsx","../src/renderer.tsx","../src/use-element-size.ts","../src/constants.ts","../src/utils.ts"],"sourcesContent":["import type { PDFDocumentProxy } from \"pdfjs-dist\";\nimport {\n\tuseCallback,\n\tuseEffect,\n\tuseImperativeHandle,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport { Document, pdfjs } from \"react-pdf\";\nimport \"react-pdf/dist/Page/AnnotationLayer.css\";\nimport \"react-pdf/dist/Page/TextLayer.css\";\nimport type { OnDocumentLoadSuccess } from \"react-pdf/dist/shared/types.js\";\nimport { List, type ListImperativeAPI } from \"react-window\";\nimport PDFViewerControls from \"./controls\";\nimport PDFErrorPage from \"./error-page\";\nimport PDFLoadingPage from \"./loading-page\";\nimport PDFPageRenderer from \"./renderer\";\nimport \"./styles.css\";\nimport type { ZoomConfig } from \"./types\";\nimport { useElementSize } from \"./use-element-size\";\nimport { getPageDimensions } from \"./utils\";\n\npdfjs.GlobalWorkerOptions.workerSrc = new URL(\n\t\"pdfjs-dist/build/pdf.worker.min.mjs\",\n\timport.meta.url,\n).toString();\n\nconst PAGE_MARGIN = 12;\n\nexport interface HyperJumpViewerAPI {\n\t/** Imperatively scroll to a page (0-indexed). Clamps to valid range. */\n\tjumpToPage: (page: number) => void;\n}\n\nexport type ScrollBehavior = \"auto\" | \"instant\" | \"smooth\";\n\nexport interface HyperJumpViewerProps {\n\t/** URL of the PDF file to display */\n\turl: string;\n\t/** Page to show when the document first loads (0-indexed) */\n\tinitialPage?: number;\n\t/** Called when the visible page changes (0-indexed) */\n\tonPageChange?: (page: number) => void;\n\t/** Scroll behavior when navigating between pages (default: \"instant\") */\n\tscrollBehavior?: ScrollBehavior;\n\t/** Ref exposing imperative jumpToPage method */\n\tref?: React.Ref<HyperJumpViewerAPI>;\n}\n\nexport function HyperJumpViewer(props: HyperJumpViewerProps) {\n\tconst {\n\t\turl,\n\t\tinitialPage,\n\t\tonPageChange,\n\t\tscrollBehavior = \"instant\",\n\t\tref,\n\t} = props;\n\tconst [document, setDocument] = useState<PDFDocumentProxy>();\n\tconst [pageIndex, setPageIndex] = useState(0);\n\tconst [pageDimensions, setPageDimensions] = useState<\n\t\t{ width: number; height: number }[]\n\t>([]);\n\tconst [zoomConfig, setZoomConfig] = useState<ZoomConfig>({\n\t\tmode: \"automatic\",\n\t\tvalue: 1,\n\t});\n\tconst scrollPageRef = useRef(0);\n\n\tconst { ref: containerRef } = useElementSize();\n\tconst listRef = useRef<ListImperativeAPI>(null);\n\n\tconst numPages = useMemo(() => {\n\t\treturn document?.numPages || 0;\n\t}, [document]);\n\n\tuseEffect(() => {\n\t\tif (document) {\n\t\t\tgetPageDimensions(document, zoomConfig.value).then((value) => {\n\t\t\t\tsetPageDimensions(value);\n\t\t\t});\n\t\t}\n\t}, [document, zoomConfig]);\n\n\tconst scrollToPage = useCallback(\n\t\t(target: number) => {\n\t\t\tif (numPages === 0 || pageDimensions.length !== numPages) return;\n\t\t\tconst clamped = Math.max(0, Math.min(Math.floor(target), numPages - 1));\n\t\t\tlistRef.current?.scrollToRow({\n\t\t\t\tindex: clamped,\n\t\t\t\talign: \"start\",\n\t\t\t\tbehavior: scrollBehavior,\n\t\t\t});\n\t\t\tsetPageIndex(clamped);\n\t\t},\n\t\t[numPages, pageDimensions, scrollBehavior],\n\t);\n\n\tuseImperativeHandle(ref, () => ({ jumpToPage: scrollToPage }), [\n\t\tscrollToPage,\n\t]);\n\n\tconst hasAppliedInitialPage = useRef(false);\n\n\tconst onLoadSuccess: OnDocumentLoadSuccess = useCallback((response) => {\n\t\thasAppliedInitialPage.current = false;\n\t\tsetDocument(response);\n\t}, []);\n\n\t// Scroll to initialPage once when dimensions are first available.\n\t// Deferred by a frame so the List's scroll container is fully initialized.\n\tuseEffect(() => {\n\t\tif (\n\t\t\t!hasAppliedInitialPage.current &&\n\t\t\tinitialPage !== undefined &&\n\t\t\tpageDimensions.length === numPages &&\n\t\t\tnumPages > 0\n\t\t) {\n\t\t\thasAppliedInitialPage.current = true;\n\t\t\tconst id = requestAnimationFrame(() => scrollToPage(initialPage));\n\t\t\treturn () => cancelAnimationFrame(id);\n\t\t}\n\t}, [initialPage, pageDimensions, numPages, scrollToPage]);\n\n\tconst file = useMemo(() => {\n\t\treturn { url };\n\t}, [url]);\n\n\tconst onPrevPage = useCallback(() => {\n\t\tif (pageIndex > 0) {\n\t\t\tconst newPageIndex = pageIndex - 1;\n\t\t\tlistRef.current?.scrollToRow({\n\t\t\t\tindex: newPageIndex,\n\t\t\t\talign: \"start\",\n\t\t\t\tbehavior: scrollBehavior,\n\t\t\t});\n\t\t\tsetPageIndex(newPageIndex);\n\t\t}\n\t}, [pageIndex, scrollBehavior]);\n\n\tconst onNextPage = useCallback(() => {\n\t\tif (pageIndex < numPages - 1) {\n\t\t\tconst newPageIndex = pageIndex + 1;\n\t\t\tlistRef.current?.scrollToRow({\n\t\t\t\tindex: newPageIndex,\n\t\t\t\talign: \"start\",\n\t\t\t\tbehavior: scrollBehavior,\n\t\t\t});\n\t\t\tsetPageIndex(newPageIndex);\n\t\t}\n\t}, [pageIndex, numPages, scrollBehavior]);\n\n\tconst onChangeZoom = useCallback((value: string) => {\n\t\tif (value === \"automatic\") {\n\t\t\tsetZoomConfig({ mode: \"automatic\", value: 1 });\n\t\t} else {\n\t\t\tsetZoomConfig({ mode: \"manual\", value: Number.parseFloat(value) });\n\t\t}\n\t}, []);\n\n\tconst getItemSize = useCallback(\n\t\t(index: number) => {\n\t\t\tif (pageDimensions[index]) {\n\t\t\t\treturn pageDimensions[index].height + PAGE_MARGIN;\n\t\t\t}\n\t\t\treturn 0;\n\t\t},\n\t\t[pageDimensions],\n\t);\n\n\tconst onRowsRendered = useCallback(\n\t\t(visibleRows: { startIndex: number; stopIndex: number }) => {\n\t\t\tconst prev = scrollPageRef.current;\n\t\t\tscrollPageRef.current = visibleRows.startIndex;\n\t\t\tif (visibleRows.startIndex !== prev) {\n\t\t\t\tsetPageIndex(visibleRows.startIndex);\n\t\t\t\tonPageChange?.(visibleRows.startIndex);\n\t\t\t}\n\t\t},\n\t\t[onPageChange],\n\t);\n\n\treturn (\n\t\t<div className=\"hj-viewer\" ref={containerRef}>\n\t\t\t{file ? (\n\t\t\t\t<Document\n\t\t\t\t\tfile={file}\n\t\t\t\t\tonLoadSuccess={onLoadSuccess}\n\t\t\t\t\terror={PDFErrorPage}\n\t\t\t\t\tloading={PDFLoadingPage}\n\t\t\t\t>\n\t\t\t\t\t{pageDimensions.length > 0 && pageDimensions.length === numPages && (\n\t\t\t\t\t\t<List\n\t\t\t\t\t\t\tlistRef={listRef}\n\t\t\t\t\t\t\trowCount={numPages}\n\t\t\t\t\t\t\trowHeight={getItemSize}\n\t\t\t\t\t\t\tonRowsRendered={onRowsRendered}\n\t\t\t\t\t\t\trowProps={{ scale: zoomConfig.value }}\n\t\t\t\t\t\t\trowComponent={PDFPageRenderer}\n\t\t\t\t\t\t/>\n\t\t\t\t\t)}\n\t\t\t\t</Document>\n\t\t\t) : (\n\t\t\t\t<PDFLoadingPage />\n\t\t\t)}\n\t\t\t<PDFViewerControls\n\t\t\t\tpageIndex={pageIndex}\n\t\t\t\tnumPages={numPages}\n\t\t\t\tonPrevPage={onPrevPage}\n\t\t\t\tonNextPage={onNextPage}\n\t\t\t\tzoomConfig={zoomConfig}\n\t\t\t\tonChangeZoom={onChangeZoom}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n","import type { ZoomConfig } from \"./types\";\n\nconst ZOOM_OPTIONS = [\n\t{ label: \"Auto Width\", value: \"automatic\" },\n\t{ label: \"50%\", value: \"0.5\" },\n\t{ label: \"75%\", value: \"0.75\" },\n\t{ label: \"100%\", value: \"1\" },\n\t{ label: \"125%\", value: \"1.25\" },\n\t{ label: \"150%\", value: \"1.5\" },\n\t{ label: \"200%\", value: \"2\" },\n\t{ label: \"300%\", value: \"3\" },\n\t{ label: \"400%\", value: \"4\" },\n];\n\ninterface IProps {\n\tonChangeZoom(value: string): void;\n\tpageIndex: number;\n\tnumPages: number;\n\tzoomConfig: ZoomConfig;\n\tonNextPage(): void;\n\tonPrevPage(): void;\n}\n\nfunction ChevronLeft() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<title>Previous Page</title>\n\t\t\t<path d=\"M15 18l-6-6 6-6\" />\n\t\t</svg>\n\t);\n}\n\nfunction ChevronRight() {\n\treturn (\n\t\t<svg\n\t\t\twidth=\"16\"\n\t\t\theight=\"16\"\n\t\t\tviewBox=\"0 0 24 24\"\n\t\t\tfill=\"none\"\n\t\t\tstroke=\"currentColor\"\n\t\t\tstrokeWidth=\"2\"\n\t\t\tstrokeLinecap=\"round\"\n\t\t\tstrokeLinejoin=\"round\"\n\t\t>\n\t\t\t<title>Next Page</title>\n\t\t\t<path d=\"M9 18l6-6-6 6\" />\n\t\t</svg>\n\t);\n}\n\nexport default function PDFViewerControls(props: IProps) {\n\tconst {\n\t\tonChangeZoom,\n\t\tpageIndex,\n\t\tnumPages,\n\t\tzoomConfig,\n\t\tonNextPage,\n\t\tonPrevPage,\n\t} = props;\n\n\tconst zoomValue =\n\t\tzoomConfig.mode === \"automatic\" || zoomConfig.mode === \"page-width\"\n\t\t\t? zoomConfig.mode\n\t\t\t: zoomConfig.value.toString();\n\n\treturn (\n\t\t<div className=\"hj-controls\">\n\t\t\t<div className=\"hj-controls-bar\">\n\t\t\t\t<div className=\"hj-controls-group\">\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hj-icon-btn\"\n\t\t\t\t\t\tonClick={onPrevPage}\n\t\t\t\t\t\tdisabled={pageIndex <= 0}\n\t\t\t\t\t\taria-label=\"Previous Page\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronLeft />\n\t\t\t\t\t</button>\n\t\t\t\t\t<span className=\"hj-page-indicator\">\n\t\t\t\t\t\t{pageIndex + 1} / {numPages}\n\t\t\t\t\t</span>\n\t\t\t\t\t<button\n\t\t\t\t\t\ttype=\"button\"\n\t\t\t\t\t\tclassName=\"hj-icon-btn\"\n\t\t\t\t\t\tonClick={onNextPage}\n\t\t\t\t\t\tdisabled={pageIndex >= numPages - 1}\n\t\t\t\t\t\taria-label=\"Next Page\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<ChevronRight />\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t\t<div className=\"hj-divider\" />\n\t\t\t\t<select\n\t\t\t\t\tclassName=\"hj-select\"\n\t\t\t\t\tvalue={zoomValue}\n\t\t\t\t\tonChange={(e) => onChangeZoom(e.target.value)}\n\t\t\t\t\taria-label=\"Zoom Level\"\n\t\t\t\t>\n\t\t\t\t\t{ZOOM_OPTIONS.map((opt) => (\n\t\t\t\t\t\t<option key={opt.value} value={opt.value}>\n\t\t\t\t\t\t\t{opt.label}\n\t\t\t\t\t\t</option>\n\t\t\t\t\t))}\n\t\t\t\t</select>\n\t\t\t</div>\n\t\t</div>\n\t);\n}\n","export default function PDFErrorPage() {\n\treturn <div className=\"hj-error\">Error loading file</div>;\n}\n","export default function PDFLoadingPage() {\n\treturn (\n\t\t<div className=\"hj-loading\">\n\t\t\t<div className=\"hj-spinner\" />\n\t\t</div>\n\t);\n}\n","import { Page } from \"react-pdf\";\nimport type { RowComponentProps } from \"react-window\";\nimport PDFLoadingPage from \"./loading-page\";\n\ninterface RowProps {\n\tscale: number;\n}\n\nexport default function PDFPageRenderer(props: RowComponentProps<RowProps>) {\n\tconst { index, style, scale } = props;\n\treturn (\n\t\t<div className=\"hj-page\" style={style}>\n\t\t\t<Page pageIndex={index} scale={scale} loading={PDFLoadingPage} />\n\t\t</div>\n\t);\n}\n","import { useCallback, useRef, useState } from \"react\";\n\nexport function useElementSize<T extends HTMLElement = HTMLDivElement>() {\n\tconst [size, setSize] = useState({ width: 0, height: 0 });\n\tconst observerRef = useRef<ResizeObserver | null>(null);\n\n\tconst ref = useCallback((node: T | null) => {\n\t\tif (observerRef.current) {\n\t\t\tobserverRef.current.disconnect();\n\t\t\tobserverRef.current = null;\n\t\t}\n\n\t\tif (node) {\n\t\t\tconst observer = new ResizeObserver(([entry]) => {\n\t\t\t\tconst { width, height } = entry.contentRect;\n\t\t\t\tsetSize((prev) => {\n\t\t\t\t\tif (prev.width === width && prev.height === height) return prev;\n\t\t\t\t\treturn { width, height };\n\t\t\t\t});\n\t\t\t});\n\t\t\tobserver.observe(node);\n\t\t\tobserverRef.current = observer;\n\t\t}\n\t}, []);\n\n\treturn { ref, width: size.width, height: size.height };\n}\n","export const PAGE_HEIGHT = 842;\nexport const PAGE_WIDTH = 595;\n","import type { PDFDocumentProxy } from \"pdfjs-dist\";\nimport { PAGE_HEIGHT, PAGE_WIDTH } from \"./constants\";\n\nexport async function getPageDimensions(\n\tdocument: PDFDocumentProxy,\n\tscale: number,\n) {\n\tconst dims = [];\n\tfor (let i = 1; i <= document.numPages; i++) {\n\t\ttry {\n\t\t\tconst page = await document.getPage(i);\n\t\t\tconst viewport = page.getViewport({ scale });\n\t\t\tconst { height, width } = viewport;\n\t\t\tdims.push({ height, width });\n\t\t} catch (error) {\n\t\t\tconsole.error(\"Failed to get page dimensions\", error);\n\t\t\tdims.push({\n\t\t\t\twidth: PAGE_WIDTH,\n\t\t\t\theight: PAGE_HEIGHT,\n\t\t\t});\n\t\t}\n\t}\n\treturn dims;\n}\n"],"mappings":"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","names":["useCallback","useRef","useState","jsx","jsx","jsx","jsx","jsxs","useState","useRef","useCallback"]}
|
|
1
|
+
{"version":3,"sources":["../src/viewer/viewer.tsx","../src/lib/use-element-size.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport type { FileRenderer, HyperJumpAPI } from \"../lib/types\";\nimport { useElementSize } from \"../lib/use-element-size\";\nimport \"./viewer.css\";\n\nexport interface HyperJumpViewerProps<\n\tT extends Record<string, unknown> = Record<string, unknown>,\n> {\n\t/** URL of the file to display */\n\turl: string;\n\t/** Explicit file type override (e.g. \"pdf\", \"video\"). If omitted, detected from URL extension. */\n\ttype?: string;\n\t/** Renderers that this viewer can use. The first matching renderer wins. */\n\trenderers: FileRenderer[];\n\t/** Ref forwarded to the active renderer (e.g. for imperative APIs like jump). */\n\tref?: React.Ref<HyperJumpAPI>;\n\t/** Initial position to show when the content first loads. Meaning depends on renderer (page index for PDF, seconds for video). */\n\tinitialPosition?: number;\n\t/** Called when the current position changes. Meaning depends on renderer (page index for PDF, seconds for video). */\n\tonPositionChange?: (position: number) => void;\n\t/** Additional props forwarded to the matched renderer. */\n\trendererProps?: T;\n}\n\nfunction getExtension(url: string): string | null {\n\ttry {\n\t\tconst pathname = new URL(url, \"https://placeholder.com\").pathname;\n\t\tconst dot = pathname.lastIndexOf(\".\");\n\t\tif (dot === -1) return null;\n\t\treturn pathname.slice(dot + 1).toLowerCase();\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nexport function HyperJumpViewer<\n\tT extends Record<string, unknown> = Record<string, unknown>,\n>(props: HyperJumpViewerProps<T>) {\n\tconst {\n\t\turl,\n\t\ttype,\n\t\trenderers,\n\t\tref,\n\t\tinitialPosition,\n\t\tonPositionChange,\n\t\trendererProps,\n\t} = props;\n\n\tconst {\n\t\tref: containerRef,\n\t\twidth: containerWidth,\n\t\theight: containerHeight,\n\t} = useElementSize();\n\n\tconst renderer = useMemo(() => {\n\t\tconst ext = type ?? getExtension(url);\n\t\tif (!ext) return null;\n\t\treturn renderers.find((r) => r.type === ext || r.extensions.includes(ext));\n\t}, [url, type, renderers]);\n\n\treturn (\n\t\t<div className=\"hj-viewer\" ref={containerRef}>\n\t\t\t{renderer ? (\n\t\t\t\t<renderer.Component\n\t\t\t\t\tref={ref}\n\t\t\t\t\turl={url}\n\t\t\t\t\tcontainerWidth={containerWidth}\n\t\t\t\t\tcontainerHeight={containerHeight}\n\t\t\t\t\tinitialPosition={initialPosition}\n\t\t\t\t\tonPositionChange={onPositionChange}\n\t\t\t\t\t{...rendererProps}\n\t\t\t\t/>\n\t\t\t) : (\n\t\t\t\t<div className=\"hj-error\">Unsupported file type</div>\n\t\t\t)}\n\t\t</div>\n\t);\n}\n","import { useCallback, useRef, useState } from \"react\";\n\nexport function useElementSize<T extends HTMLElement = HTMLDivElement>() {\n\tconst [size, setSize] = useState({ width: 0, height: 0 });\n\tconst observerRef = useRef<ResizeObserver | null>(null);\n\n\tconst ref = useCallback((node: T | null) => {\n\t\tif (observerRef.current) {\n\t\t\tobserverRef.current.disconnect();\n\t\t\tobserverRef.current = null;\n\t\t}\n\n\t\tif (node) {\n\t\t\tconst observer = new ResizeObserver(([entry]) => {\n\t\t\t\tconst { width, height } = entry.contentRect;\n\t\t\t\tsetSize((prev) => {\n\t\t\t\t\tif (prev.width === width && prev.height === height) return prev;\n\t\t\t\t\treturn { width, height };\n\t\t\t\t});\n\t\t\t});\n\t\t\tobserver.observe(node);\n\t\t\tobserverRef.current = observer;\n\t\t}\n\t}, []);\n\n\treturn { ref, width: size.width, height: size.height };\n}\n"],"mappings":";AAAA,SAAS,eAAe;;;ACAxB,SAAS,aAAa,QAAQ,gBAAgB;AAEvC,SAAS,iBAAyD;AACxE,QAAM,CAAC,MAAM,OAAO,IAAI,SAAS,EAAE,OAAO,GAAG,QAAQ,EAAE,CAAC;AACxD,QAAM,cAAc,OAA8B,IAAI;AAEtD,QAAM,MAAM,YAAY,CAAC,SAAmB;AAC3C,QAAI,YAAY,SAAS;AACxB,kBAAY,QAAQ,WAAW;AAC/B,kBAAY,UAAU;AAAA,IACvB;AAEA,QAAI,MAAM;AACT,YAAM,WAAW,IAAI,eAAe,CAAC,CAAC,KAAK,MAAM;AAChD,cAAM,EAAE,OAAO,OAAO,IAAI,MAAM;AAChC,gBAAQ,CAAC,SAAS;AACjB,cAAI,KAAK,UAAU,SAAS,KAAK,WAAW,OAAQ,QAAO;AAC3D,iBAAO,EAAE,OAAO,OAAO;AAAA,QACxB,CAAC;AAAA,MACF,CAAC;AACD,eAAS,QAAQ,IAAI;AACrB,kBAAY,UAAU;AAAA,IACvB;AAAA,EACD,GAAG,CAAC,CAAC;AAEL,SAAO,EAAE,KAAK,OAAO,KAAK,OAAO,QAAQ,KAAK,OAAO;AACtD;;;ADqCI;AAvCJ,SAAS,aAAa,KAA4B;AACjD,MAAI;AACH,UAAM,WAAW,IAAI,IAAI,KAAK,yBAAyB,EAAE;AACzD,UAAM,MAAM,SAAS,YAAY,GAAG;AACpC,QAAI,QAAQ,GAAI,QAAO;AACvB,WAAO,SAAS,MAAM,MAAM,CAAC,EAAE,YAAY;AAAA,EAC5C,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAEO,SAAS,gBAEd,OAAgC;AACjC,QAAM;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI;AAEJ,QAAM;AAAA,IACL,KAAK;AAAA,IACL,OAAO;AAAA,IACP,QAAQ;AAAA,EACT,IAAI,eAAe;AAEnB,QAAM,WAAW,QAAQ,MAAM;AAC9B,UAAM,MAAM,QAAQ,aAAa,GAAG;AACpC,QAAI,CAAC,IAAK,QAAO;AACjB,WAAO,UAAU,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,EAAE,WAAW,SAAS,GAAG,CAAC;AAAA,EAC1E,GAAG,CAAC,KAAK,MAAM,SAAS,CAAC;AAEzB,SACC,oBAAC,SAAI,WAAU,aAAY,KAAK,cAC9B,qBACA;AAAA,IAAC,SAAS;AAAA,IAAT;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACC,GAAG;AAAA;AAAA,EACL,IAEA,oBAAC,SAAI,WAAU,YAAW,mCAAqB,GAEjD;AAEF;","names":[]}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
type ZoomMode = "automatic" | "page-width" | "manual";
|
|
2
|
+
export interface ZoomConfig {
|
|
3
|
+
mode: ZoomMode;
|
|
4
|
+
value: number;
|
|
5
|
+
}
|
|
6
|
+
/** Props that the core viewer passes to every renderer. */
|
|
7
|
+
export interface RendererProps {
|
|
8
|
+
url: string;
|
|
9
|
+
containerWidth: number;
|
|
10
|
+
containerHeight: number;
|
|
11
|
+
/** Initial position to show when the content first loads. Meaning depends on renderer (page index for PDF, seconds for video). */
|
|
12
|
+
initialPosition?: number;
|
|
13
|
+
/** Called when the current position changes. Meaning depends on renderer (page index for PDF, seconds for video). */
|
|
14
|
+
onPositionChange?: (position: number) => void;
|
|
15
|
+
}
|
|
16
|
+
/** Imperative API shared by all renderers. Exposed via ref on HyperJumpViewer. */
|
|
17
|
+
export interface HyperJumpAPI {
|
|
18
|
+
/** Jump to a position. Meaning depends on renderer (page index for PDF, seconds for video). */
|
|
19
|
+
jump: (position: number) => void;
|
|
20
|
+
}
|
|
21
|
+
/** A renderer descriptor that tells the core viewer how to handle a file type. */
|
|
22
|
+
export interface FileRenderer {
|
|
23
|
+
/** Unique identifier for this renderer type (e.g. "pdf", "video"). */
|
|
24
|
+
type: string;
|
|
25
|
+
/** File extensions this renderer handles, without dots (e.g. ["pdf"]). */
|
|
26
|
+
extensions: string[];
|
|
27
|
+
/** The component that renders the file. */
|
|
28
|
+
Component: React.ComponentType<RendererProps & Record<string, unknown>>;
|
|
29
|
+
}
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/lib/types.ts"],"names":[],"mappings":"AAAA,KAAK,QAAQ,GAAG,WAAW,GAAG,YAAY,GAAG,QAAQ,CAAC;AAEtD,MAAM,WAAW,UAAU;IAC1B,IAAI,EAAE,QAAQ,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACd;AAED,2DAA2D;AAC3D,MAAM,WAAW,aAAa;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,cAAc,EAAE,MAAM,CAAC;IACvB,eAAe,EAAE,MAAM,CAAC;IACxB,kIAAkI;IAClI,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,qHAAqH;IACrH,gBAAgB,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CAC9C;AAED,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC5B,+FAA+F;IAC/F,IAAI,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;CACjC;AAED,kFAAkF;AAClF,MAAM,WAAW,YAAY;IAC5B,sEAAsE;IACtE,IAAI,EAAE,MAAM,CAAC;IACb,0EAA0E;IAC1E,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,2CAA2C;IAC3C,SAAS,EAAE,KAAK,CAAC,aAAa,CAAC,aAAa,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;CACxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-element-size.d.ts","sourceRoot":"","sources":["../../src/lib/use-element-size.ts"],"names":[],"mappings":"AAEA,wBAAgB,cAAc,CAAC,CAAC,SAAS,WAAW,GAAG,cAAc;gBAIrC,CAAC,GAAG,IAAI;;;EAoBvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/pdf/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,MAAM,CAAC;AAC/B,eAAO,MAAM,UAAU,MAAM,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import "./controls.css";
|
|
2
|
+
import type { ZoomConfig } from "../lib/types";
|
|
3
|
+
interface IProps {
|
|
4
|
+
onChangeZoom(value: string): void;
|
|
5
|
+
pageIndex: number;
|
|
6
|
+
numPages: number;
|
|
7
|
+
zoomConfig: ZoomConfig;
|
|
8
|
+
onNextPage(): void;
|
|
9
|
+
onPrevPage(): void;
|
|
10
|
+
}
|
|
11
|
+
export default function PDFViewerControls(props: IProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=controls.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"controls.d.ts","sourceRoot":"","sources":["../../src/pdf/controls.tsx"],"names":[],"mappings":"AAAA,OAAO,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAc/C,UAAU,MAAM;IACf,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,UAAU,CAAC;IACvB,UAAU,IAAI,IAAI,CAAC;IACnB,UAAU,IAAI,IAAI,CAAC;CACnB;AAsCD,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,KAAK,EAAE,MAAM,2CAyDtD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-page.d.ts","sourceRoot":"","sources":["../../src/pdf/error-page.tsx"],"names":[],"mappings":"AAAA,OAAO,kBAAkB,CAAC;AAE1B,MAAM,CAAC,OAAO,UAAU,YAAY,4CAEnC"}
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/* src/pdf/controls.css */
|
|
2
|
+
.hj-controls {
|
|
3
|
+
position: absolute;
|
|
4
|
+
bottom: 12px;
|
|
5
|
+
left: 12px;
|
|
6
|
+
right: 12px;
|
|
7
|
+
display: flex;
|
|
8
|
+
justify-content: center;
|
|
9
|
+
align-items: center;
|
|
10
|
+
z-index: 10;
|
|
11
|
+
}
|
|
12
|
+
.hj-controls-bar {
|
|
13
|
+
display: flex;
|
|
14
|
+
align-items: center;
|
|
15
|
+
gap: 12px;
|
|
16
|
+
padding: 6px 12px;
|
|
17
|
+
background: #fff;
|
|
18
|
+
border: 1px solid #dee2e6;
|
|
19
|
+
border-radius: 8px;
|
|
20
|
+
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1), 0 1px 2px rgba(0, 0, 0, 0.06);
|
|
21
|
+
}
|
|
22
|
+
.hj-controls-group {
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
gap: 6px;
|
|
26
|
+
}
|
|
27
|
+
.hj-divider {
|
|
28
|
+
width: 1px;
|
|
29
|
+
height: 24px;
|
|
30
|
+
background: #dee2e6;
|
|
31
|
+
}
|
|
32
|
+
.hj-btn {
|
|
33
|
+
display: inline-flex;
|
|
34
|
+
align-items: center;
|
|
35
|
+
justify-content: center;
|
|
36
|
+
padding: 4px 12px;
|
|
37
|
+
font-size: 13px;
|
|
38
|
+
font-family: inherit;
|
|
39
|
+
line-height: 1.4;
|
|
40
|
+
border: 1px solid #dee2e6;
|
|
41
|
+
border-radius: 4px;
|
|
42
|
+
background: #fff;
|
|
43
|
+
color: #212529;
|
|
44
|
+
cursor: pointer;
|
|
45
|
+
user-select: none;
|
|
46
|
+
white-space: nowrap;
|
|
47
|
+
}
|
|
48
|
+
.hj-btn:hover:not(:disabled) {
|
|
49
|
+
background: #f8f9fa;
|
|
50
|
+
}
|
|
51
|
+
.hj-btn:disabled {
|
|
52
|
+
opacity: 0.5;
|
|
53
|
+
cursor: not-allowed;
|
|
54
|
+
}
|
|
55
|
+
.hj-icon-btn {
|
|
56
|
+
display: inline-flex;
|
|
57
|
+
align-items: center;
|
|
58
|
+
justify-content: center;
|
|
59
|
+
width: 28px;
|
|
60
|
+
height: 28px;
|
|
61
|
+
padding: 0;
|
|
62
|
+
border: 1px solid #dee2e6;
|
|
63
|
+
border-radius: 4px;
|
|
64
|
+
background: #fff;
|
|
65
|
+
color: #212529;
|
|
66
|
+
cursor: pointer;
|
|
67
|
+
}
|
|
68
|
+
.hj-icon-btn:hover:not(:disabled) {
|
|
69
|
+
background: #f8f9fa;
|
|
70
|
+
}
|
|
71
|
+
.hj-icon-btn:disabled {
|
|
72
|
+
opacity: 0.5;
|
|
73
|
+
cursor: not-allowed;
|
|
74
|
+
}
|
|
75
|
+
.hj-page-indicator {
|
|
76
|
+
font-size: 13px;
|
|
77
|
+
min-width: 50px;
|
|
78
|
+
text-align: center;
|
|
79
|
+
color: #212529;
|
|
80
|
+
user-select: none;
|
|
81
|
+
}
|
|
82
|
+
.hj-select {
|
|
83
|
+
font-size: 13px;
|
|
84
|
+
font-family: inherit;
|
|
85
|
+
padding: 4px 8px;
|
|
86
|
+
border: 1px solid #dee2e6;
|
|
87
|
+
border-radius: 4px;
|
|
88
|
+
background: #fff;
|
|
89
|
+
color: #212529;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
min-width: 120px;
|
|
92
|
+
}
|
|
93
|
+
.hj-select:focus {
|
|
94
|
+
outline: 2px solid #228be6;
|
|
95
|
+
outline-offset: -1px;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* src/pdf/error-page.css */
|
|
99
|
+
.hj-error {
|
|
100
|
+
display: flex;
|
|
101
|
+
align-items: center;
|
|
102
|
+
justify-content: center;
|
|
103
|
+
width: 100%;
|
|
104
|
+
height: 100%;
|
|
105
|
+
font-size: 14px;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/* src/pdf/loading-page.css */
|
|
109
|
+
.hj-loading {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
width: 100%;
|
|
114
|
+
height: 100%;
|
|
115
|
+
}
|
|
116
|
+
.hj-spinner {
|
|
117
|
+
width: 32px;
|
|
118
|
+
height: 32px;
|
|
119
|
+
border: 3px solid #e9ecef;
|
|
120
|
+
border-top-color: #228be6;
|
|
121
|
+
border-radius: 50%;
|
|
122
|
+
animation: hj-spin 0.6s linear infinite;
|
|
123
|
+
}
|
|
124
|
+
@keyframes hj-spin {
|
|
125
|
+
to {
|
|
126
|
+
transform: rotate(360deg);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* src/pdf/pdf-viewer.css */
|
|
131
|
+
.hj-viewer .react-pdf__Document {
|
|
132
|
+
height: 100%;
|
|
133
|
+
width: 100%;
|
|
134
|
+
}
|
|
135
|
+
.hj-viewer .react-pdf__message {
|
|
136
|
+
height: 100%;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* src/pdf/renderer.css */
|
|
140
|
+
.hj-page {
|
|
141
|
+
display: flex;
|
|
142
|
+
align-items: center;
|
|
143
|
+
justify-content: center;
|
|
144
|
+
}
|
|
145
|
+
.hj-page .react-pdf__Page {
|
|
146
|
+
height: 100%;
|
|
147
|
+
}
|
|
148
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/pdf/controls.css","../../src/pdf/error-page.css","../../src/pdf/loading-page.css","../../src/pdf/pdf-viewer.css","../../src/pdf/renderer.css"],"sourcesContent":["/* Controls */\n\n.hj-controls {\n\tposition: absolute;\n\tbottom: 12px;\n\tleft: 12px;\n\tright: 12px;\n\tdisplay: flex;\n\tjustify-content: center;\n\talign-items: center;\n\tz-index: 10;\n}\n\n.hj-controls-bar {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 6px 12px;\n\tbackground: #fff;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 8px;\n\tbox-shadow:\n\t\t0 1px 3px rgba(0, 0, 0, 0.1),\n\t\t0 1px 2px rgba(0, 0, 0, 0.06);\n}\n\n.hj-controls-group {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 6px;\n}\n\n.hj-divider {\n\twidth: 1px;\n\theight: 24px;\n\tbackground: #dee2e6;\n}\n\n.hj-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\tpadding: 4px 12px;\n\tfont-size: 13px;\n\tfont-family: inherit;\n\tline-height: 1.4;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n\tuser-select: none;\n\twhite-space: nowrap;\n}\n\n.hj-btn:hover:not(:disabled) {\n\tbackground: #f8f9fa;\n}\n\n.hj-btn:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.hj-icon-btn {\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 28px;\n\theight: 28px;\n\tpadding: 0;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n}\n\n.hj-icon-btn:hover:not(:disabled) {\n\tbackground: #f8f9fa;\n}\n\n.hj-icon-btn:disabled {\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.hj-page-indicator {\n\tfont-size: 13px;\n\tmin-width: 50px;\n\ttext-align: center;\n\tcolor: #212529;\n\tuser-select: none;\n}\n\n.hj-select {\n\tfont-size: 13px;\n\tfont-family: inherit;\n\tpadding: 4px 8px;\n\tborder: 1px solid #dee2e6;\n\tborder-radius: 4px;\n\tbackground: #fff;\n\tcolor: #212529;\n\tcursor: pointer;\n\tmin-width: 120px;\n}\n\n.hj-select:focus {\n\toutline: 2px solid #228be6;\n\toutline-offset: -1px;\n}\n","/* Error page */\n\n.hj-error {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 100%;\n\theight: 100%;\n\tfont-size: 14px;\n}\n","/* Loading page */\n\n.hj-loading {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 100%;\n\theight: 100%;\n}\n\n.hj-spinner {\n\twidth: 32px;\n\theight: 32px;\n\tborder: 3px solid #e9ecef;\n\tborder-top-color: #228be6;\n\tborder-radius: 50%;\n\tanimation: hj-spin 0.6s linear infinite;\n}\n\n@keyframes hj-spin {\n\tto {\n\t\ttransform: rotate(360deg);\n\t}\n}\n","/* PDF Viewer — react-pdf integration styles */\n\n.hj-viewer .react-pdf__Document {\n\theight: 100%;\n\twidth: 100%;\n}\n\n.hj-viewer .react-pdf__message {\n\theight: 100%;\n}\n","/* Page renderer */\n\n.hj-page {\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n\n.hj-page .react-pdf__Page {\n\theight: 100%;\n}\n"],"mappings":";AAEA,CAAC;AACA,YAAU;AACV,UAAQ;AACR,QAAM;AACN,SAAO;AACP,WAAS;AACT,mBAAiB;AACjB,eAAa;AACb,WAAS;AACV;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,OAAK;AACL,WAAS,IAAI;AACb,cAAY;AACZ,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cACC,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,EAC5B,EAAE,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE;AAC1B;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,OAAK;AACN;AAEA,CAAC;AACA,SAAO;AACP,UAAQ;AACR,cAAY;AACb;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,WAAS,IAAI;AACb,aAAW;AACX,eAAa;AACb,eAAa;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACR,eAAa;AACb,eAAa;AACd;AAEA,CAjBC,MAiBM,MAAM,KAAK;AACjB,cAAY;AACb;AAEA,CArBC,MAqBM;AACN,WAAS;AACT,UAAQ;AACT;AAEA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACR,WAAS;AACT,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACT;AAEA,CAdC,WAcW,MAAM,KAAK;AACtB,cAAY;AACb;AAEA,CAlBC,WAkBW;AACX,WAAS;AACT,UAAQ;AACT;AAEA,CAAC;AACA,aAAW;AACX,aAAW;AACX,cAAY;AACZ,SAAO;AACP,eAAa;AACd;AAEA,CAAC;AACA,aAAW;AACX,eAAa;AACb,WAAS,IAAI;AACb,UAAQ,IAAI,MAAM;AAClB,iBAAe;AACf,cAAY;AACZ,SAAO;AACP,UAAQ;AACR,aAAW;AACZ;AAEA,CAZC,SAYS;AACT,WAAS,IAAI,MAAM;AACnB,kBAAgB;AACjB;;;AC5GA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACR,aAAW;AACZ;;;ACPA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AACjB,SAAO;AACP,UAAQ;AACT;AAEA,CAAC;AACA,SAAO;AACP,UAAQ;AACR,UAAQ,IAAI,MAAM;AAClB,oBAAkB;AAClB,iBAAe;AACf,aAAW,QAAQ,KAAK,OAAO;AAChC;AAEA,WAHY;AAIX;AACC,eAAW,OAAO;AACnB;AACD;;;ACrBA,CAAC,UAAU,CAAC;AACX,UAAQ;AACR,SAAO;AACR;AAEA,CALC,UAKU,CAAC;AACX,UAAQ;AACT;;;ACPA,CAAC;AACA,WAAS;AACT,eAAa;AACb,mBAAiB;AAClB;AAEA,CANC,QAMQ,CAAC;AACT,UAAQ;AACT;","names":[]}
|