viewdoc 0.2.1 → 0.3.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/README.md +7 -2
- package/dist/DocxViewer-F3MW62BA.js +10 -0
- package/dist/PdfViewer-6YF7AER3.js +9 -0
- package/dist/XlsxViewer-7X25BBRT.js +10 -0
- package/dist/{chunk-LE4YTMPN.js → chunk-3EUNNQXJ.js} +36 -9
- package/dist/chunk-3EUNNQXJ.js.map +1 -0
- package/dist/{chunk-EQCFZMLL.js → chunk-4BFQ7U2R.js} +10 -4
- package/dist/chunk-4BFQ7U2R.js.map +1 -0
- package/dist/{chunk-US2KTONG.js → chunk-AIDVQYXH.js} +6 -3
- package/dist/chunk-AIDVQYXH.js.map +1 -0
- package/dist/chunk-DKFD7M4R.js +12 -0
- package/dist/chunk-DKFD7M4R.js.map +1 -0
- package/dist/{chunk-OA35SYM6.js → chunk-HOF2XEU5.js} +43 -6
- package/dist/chunk-HOF2XEU5.js.map +1 -0
- package/dist/docx.cjs +53 -7
- package/dist/docx.cjs.map +1 -1
- package/dist/docx.d.cts +3 -1
- package/dist/docx.d.ts +3 -1
- package/dist/docx.js +4 -2
- package/dist/index.cjs +94 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -1
- package/dist/index.d.ts +5 -1
- package/dist/index.js +7 -5
- package/dist/index.js.map +1 -1
- package/dist/pdf.cjs +44 -6
- package/dist/pdf.cjs.map +1 -1
- package/dist/pdf.d.cts +3 -1
- package/dist/pdf.d.ts +3 -1
- package/dist/pdf.js +3 -2
- package/dist/styles.css +10 -0
- package/dist/styles.css.map +1 -1
- package/dist/xlsx.cjs +77 -12
- package/dist/xlsx.cjs.map +1 -1
- package/dist/xlsx.d.cts +9 -1
- package/dist/xlsx.d.ts +9 -1
- package/dist/xlsx.js +4 -2
- package/package.json +5 -1
- package/dist/DocxViewer-HQFSWXQW.js +0 -8
- package/dist/PdfViewer-YJOHTAPL.js +0 -8
- package/dist/XlsxViewer-SQMAF5UA.js +0 -8
- package/dist/chunk-EQCFZMLL.js.map +0 -1
- package/dist/chunk-LE4YTMPN.js.map +0 -1
- package/dist/chunk-OA35SYM6.js.map +0 -1
- package/dist/chunk-US2KTONG.js.map +0 -1
- /package/dist/{DocxViewer-HQFSWXQW.js.map → DocxViewer-F3MW62BA.js.map} +0 -0
- /package/dist/{PdfViewer-YJOHTAPL.js.map → PdfViewer-6YF7AER3.js.map} +0 -0
- /package/dist/{XlsxViewer-SQMAF5UA.js.map → XlsxViewer-7X25BBRT.js.map} +0 -0
package/dist/pdf.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -280,9 +281,10 @@ function ViewerShell({
|
|
|
280
281
|
document.addEventListener("fullscreenchange", onChange);
|
|
281
282
|
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
282
283
|
}, []);
|
|
284
|
+
const fullscreenSupported = typeof document !== "undefined" && typeof document.fullscreenEnabled === "boolean" ? document.fullscreenEnabled : false;
|
|
283
285
|
const onFullscreen = (0, import_react2.useCallback)(() => {
|
|
284
286
|
const el = rootRef.current;
|
|
285
|
-
if (!el) return;
|
|
287
|
+
if (!el || typeof el.requestFullscreen !== "function") return;
|
|
286
288
|
if (document.fullscreenElement) {
|
|
287
289
|
document.exitFullscreen();
|
|
288
290
|
} else {
|
|
@@ -308,7 +310,7 @@ function ViewerShell({
|
|
|
308
310
|
onZoomIn: zoomPan.zoomIn,
|
|
309
311
|
onZoomOut: zoomPan.zoomOut,
|
|
310
312
|
onReset: zoomPan.resetZoom,
|
|
311
|
-
onFullscreen: enableFullscreen ? onFullscreen : void 0,
|
|
313
|
+
onFullscreen: enableFullscreen && fullscreenSupported ? onFullscreen : void 0,
|
|
312
314
|
onDownload,
|
|
313
315
|
isFullscreen,
|
|
314
316
|
showZoomControls: enableZoomControls,
|
|
@@ -349,6 +351,9 @@ var import_react3 = require("react");
|
|
|
349
351
|
var DEFAULT_MIN = 0.1;
|
|
350
352
|
var DEFAULT_MAX = 8;
|
|
351
353
|
var DEFAULT_STEP = 0.25;
|
|
354
|
+
function pointerDistance(a, b) {
|
|
355
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
356
|
+
}
|
|
352
357
|
function useZoomPan(options = {}) {
|
|
353
358
|
const {
|
|
354
359
|
minScale = DEFAULT_MIN,
|
|
@@ -356,7 +361,8 @@ function useZoomPan(options = {}) {
|
|
|
356
361
|
zoomStep = DEFAULT_STEP,
|
|
357
362
|
enablePan = true,
|
|
358
363
|
enableWheelZoom = true,
|
|
359
|
-
enableDragScroll = false
|
|
364
|
+
enableDragScroll = false,
|
|
365
|
+
enablePinchZoom = true
|
|
360
366
|
} = options;
|
|
361
367
|
const [state, setState] = (0, import_react3.useState)({ scale: 1, translateX: 0, translateY: 0 });
|
|
362
368
|
const containerRef = (0, import_react3.useRef)(null);
|
|
@@ -370,6 +376,12 @@ function useZoomPan(options = {}) {
|
|
|
370
376
|
const scrollDragState = (0, import_react3.useRef)(
|
|
371
377
|
{ dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }
|
|
372
378
|
);
|
|
379
|
+
const activePointers = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
380
|
+
const pinchState = (0, import_react3.useRef)({
|
|
381
|
+
pinching: false,
|
|
382
|
+
startDistance: 0,
|
|
383
|
+
startScale: 1
|
|
384
|
+
});
|
|
373
385
|
const clamp = (0, import_react3.useCallback)(
|
|
374
386
|
(value) => Math.min(maxScale, Math.max(minScale, value)),
|
|
375
387
|
[minScale, maxScale]
|
|
@@ -393,6 +405,16 @@ function useZoomPan(options = {}) {
|
|
|
393
405
|
);
|
|
394
406
|
const onPointerDown = (0, import_react3.useCallback)(
|
|
395
407
|
(e) => {
|
|
408
|
+
if (enablePinchZoom) {
|
|
409
|
+
activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
410
|
+
if (activePointers.current.size === 2) {
|
|
411
|
+
const [a, b] = Array.from(activePointers.current.values());
|
|
412
|
+
pinchState.current = { pinching: true, startDistance: pointerDistance(a, b), startScale: state.scale };
|
|
413
|
+
dragState.current.dragging = false;
|
|
414
|
+
scrollDragState.current.dragging = false;
|
|
415
|
+
return;
|
|
416
|
+
}
|
|
417
|
+
}
|
|
396
418
|
if (enablePan) {
|
|
397
419
|
dragState.current = {
|
|
398
420
|
dragging: true,
|
|
@@ -413,10 +435,20 @@ function useZoomPan(options = {}) {
|
|
|
413
435
|
e.target.setPointerCapture(e.pointerId);
|
|
414
436
|
}
|
|
415
437
|
},
|
|
416
|
-
[enablePan, enableDragScroll, state.translateX, state.translateY]
|
|
438
|
+
[enablePan, enableDragScroll, enablePinchZoom, state.translateX, state.translateY, state.scale]
|
|
417
439
|
);
|
|
418
440
|
const onPointerMove = (0, import_react3.useCallback)(
|
|
419
441
|
(e) => {
|
|
442
|
+
if (enablePinchZoom && activePointers.current.has(e.pointerId)) {
|
|
443
|
+
activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
444
|
+
}
|
|
445
|
+
if (pinchState.current.pinching && activePointers.current.size === 2) {
|
|
446
|
+
const [a, b] = Array.from(activePointers.current.values());
|
|
447
|
+
const distance = pointerDistance(a, b);
|
|
448
|
+
const ratio = distance / (pinchState.current.startDistance || distance);
|
|
449
|
+
setScale(pinchState.current.startScale * ratio);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
420
452
|
if (enablePan) {
|
|
421
453
|
if (!dragState.current.dragging) return;
|
|
422
454
|
const dx = e.clientX - dragState.current.startX;
|
|
@@ -434,10 +466,14 @@ function useZoomPan(options = {}) {
|
|
|
434
466
|
containerRef.current.scrollTop = scrollDragState.current.originTop - dy;
|
|
435
467
|
}
|
|
436
468
|
},
|
|
437
|
-
[enablePan, enableDragScroll]
|
|
469
|
+
[enablePan, enableDragScroll, enablePinchZoom, setScale]
|
|
438
470
|
);
|
|
439
471
|
const onPointerUp = (0, import_react3.useCallback)(
|
|
440
472
|
(e) => {
|
|
473
|
+
activePointers.current.delete(e.pointerId);
|
|
474
|
+
if (activePointers.current.size < 2) {
|
|
475
|
+
pinchState.current.pinching = false;
|
|
476
|
+
}
|
|
441
477
|
if (enablePan) {
|
|
442
478
|
dragState.current.dragging = false;
|
|
443
479
|
e.target.releasePointerCapture(e.pointerId);
|
|
@@ -572,6 +608,7 @@ function PdfViewer({
|
|
|
572
608
|
renderScale,
|
|
573
609
|
enableZoomControls = true,
|
|
574
610
|
enableWheelZoom = true,
|
|
611
|
+
enablePinchZoom = true,
|
|
575
612
|
enableFullscreen = true,
|
|
576
613
|
enableDownload = true,
|
|
577
614
|
onDownload,
|
|
@@ -586,7 +623,8 @@ function PdfViewer({
|
|
|
586
623
|
zoomStep,
|
|
587
624
|
enablePan: false,
|
|
588
625
|
enableDragScroll: true,
|
|
589
|
-
enableWheelZoom
|
|
626
|
+
enableWheelZoom,
|
|
627
|
+
enablePinchZoom
|
|
590
628
|
});
|
|
591
629
|
const { doc, numPages, error, loading } = usePdfDocument(uri);
|
|
592
630
|
const currentPage = useVisiblePage(zoomPan.containerRef, numPages);
|
package/dist/pdf.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/entry-pdf.ts","../src/core/ViewerShell.tsx","../src/core/useDraggable.ts","../src/core/icons.tsx","../src/core/Toolbar.tsx","../src/core/theme.ts","../src/core/useZoomPan.ts","../src/viewers/PdfPage.tsx","../src/viewers/usePdfDocument.ts","../src/viewers/useVisiblePage.ts","../src/viewers/PdfViewer.tsx"],"sourcesContent":["export { PdfViewer } from './viewers/PdfViewer'\nexport type { PdfViewerProps } from './viewers/PdfViewer'\n","import { useCallback, useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { useDraggable, type Position } from './useDraggable'\nimport { GripIcon } from './icons'\nimport { Toolbar } from './Toolbar'\nimport { themeToStyle, type ViewerTheme } from './theme'\nimport type { ZoomPanControls } from './useZoomPan'\n\nexport interface ViewerShellProps {\n zoomPan: ZoomPanControls\n onDownload?: () => void\n toolbarExtra?: ReactNode\n children: ReactNode\n /** Show the zoom in/out/reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Allow click-drag-release panning of the content. Default: true. */\n enablePan?: boolean\n /** Colors/radii to override the default look. Any field left out keeps the default. */\n theme?: ViewerTheme\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent container. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n draggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n /** CSS transform-origin for the zoomed content. Default: 'center center'. */\n transformOrigin?: string\n}\n\nexport function ViewerShell({\n zoomPan,\n onDownload,\n toolbarExtra,\n children,\n enableZoomControls = true,\n enableFullscreen = true,\n enablePan = true,\n theme,\n width,\n height,\n floating = true,\n draggable = true,\n defaultPosition,\n transformOrigin,\n}: ViewerShellProps) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [isFullscreen, setIsFullscreen] = useState(false)\n\n const effectiveWidth = typeof width === 'number' ? width : 1200\n const effectiveHeight = typeof height === 'number' ? height : 700\n const resolvedDefaultPosition =\n defaultPosition ??\n (typeof window !== 'undefined'\n ? {\n x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),\n y: Math.max(0, (window.innerHeight - effectiveHeight) / 2),\n }\n : { x: 80, y: 80 })\n\n const { position, onDragHandlePointerDown } = useDraggable({\n defaultPosition: resolvedDefaultPosition,\n draggable,\n })\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current)\n document.addEventListener('fullscreenchange', onChange)\n return () => document.removeEventListener('fullscreenchange', onChange)\n }, [])\n\n const onFullscreen = useCallback(() => {\n const el = rootRef.current\n if (!el) return\n if (document.fullscreenElement) {\n document.exitFullscreen()\n } else {\n el.requestFullscreen()\n }\n }, [])\n\n const sizeStyle: CSSProperties = {\n width: width ?? 1200,\n height: height ?? 700,\n }\n const floatingStyle: CSSProperties | undefined = floating\n ? { position: 'fixed', left: position.x, top: position.y }\n : undefined\n\n return (\n <div\n className={`vd-shell${floating ? ' vd-shell--floating' : ''}`}\n ref={rootRef}\n style={{ ...themeToStyle(theme), ...sizeStyle, ...floatingStyle }}\n >\n <Toolbar\n scale={zoomPan.scale}\n onZoomIn={zoomPan.zoomIn}\n onZoomOut={zoomPan.zoomOut}\n onReset={zoomPan.resetZoom}\n onFullscreen={enableFullscreen ? onFullscreen : undefined}\n onDownload={onDownload}\n isFullscreen={isFullscreen}\n showZoomControls={enableZoomControls}\n dragHandle={floating && draggable ? <GripIcon /> : undefined}\n onDragHandlePointerDown={floating && draggable ? onDragHandlePointerDown : undefined}\n extra={toolbarExtra}\n />\n <div\n className={`vd-canvas${enablePan ? '' : ' vd-canvas--no-pan'}`}\n ref={zoomPan.containerRef}\n onWheel={zoomPan.handlers.onWheel}\n onPointerDown={zoomPan.handlers.onPointerDown}\n onPointerMove={zoomPan.handlers.onPointerMove}\n onPointerUp={zoomPan.handlers.onPointerUp}\n >\n <div\n className=\"vd-canvas-content\"\n style={{\n transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,\n transformOrigin,\n }}\n >\n {children}\n </div>\n </div>\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\n\nexport interface Position {\n x: number\n y: number\n}\n\nexport interface UseDraggableOptions {\n defaultPosition?: Position\n /** Allow dragging via the returned handle props. Default: true. */\n draggable?: boolean\n}\n\nexport interface DraggableControls {\n position: Position\n onDragHandlePointerDown: (e: React.PointerEvent) => void\n}\n\nexport function useDraggable(options: UseDraggableOptions = {}): DraggableControls {\n const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options\n const [position, setPosition] = useState<Position>(defaultPosition)\n\n const onDragHandlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (!draggable) return\n e.preventDefault()\n const startX = e.clientX\n const startY = e.clientY\n\n setPosition((current) => {\n const originX = current.x\n const originY = current.y\n\n const onMove = (ev: PointerEvent) => {\n setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) })\n }\n const onUp = () => {\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', onUp)\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', onUp)\n\n return current\n })\n },\n [draggable]\n )\n\n return { position, onDragHandlePointerDown }\n}\n","import type { SVGProps } from 'react'\n\nfunction Svg(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n />\n )\n}\n\nexport function ZoomOutIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function ZoomInIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function DownloadIcon() {\n return (\n <Svg>\n <path d=\"M12 3v12\" />\n <path d=\"M7 10l5 5 5-5\" />\n <path d=\"M5 21h14\" />\n </Svg>\n )\n}\n\nexport function FullscreenEnterIcon() {\n return (\n <Svg>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </Svg>\n )\n}\n\nexport function ResetIcon() {\n return (\n <Svg>\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <polyline points=\"3 3 3 8 8 8\" />\n </Svg>\n )\n}\n\nexport function GripIcon() {\n return (\n <Svg>\n <polyline points=\"5 9 2 12 5 15\" />\n <polyline points=\"9 5 12 2 15 5\" />\n <polyline points=\"15 19 12 22 9 19\" />\n <polyline points=\"19 9 22 12 19 15\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"22\" />\n </Svg>\n )\n}\n\nexport function FullscreenExitIcon() {\n return (\n <Svg>\n <polyline points=\"9 3 9 9 3 9\" />\n <polyline points=\"15 21 15 15 21 15\" />\n <line x1=\"9\" y1=\"9\" x2=\"3\" y2=\"3\" />\n <line x1=\"15\" y1=\"15\" x2=\"21\" y2=\"21\" />\n </Svg>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DownloadIcon, FullscreenEnterIcon, FullscreenExitIcon, ResetIcon, ZoomInIcon, ZoomOutIcon } from './icons'\n\nexport interface ToolbarProps {\n scale: number\n onZoomIn: () => void\n onZoomOut: () => void\n onReset: () => void\n onFullscreen?: () => void\n onDownload?: () => void\n /** Whether the viewer is currently in fullscreen mode (controls which icon is shown). */\n isFullscreen?: boolean\n /** Show zoom in/out/reset controls. Default: true. */\n showZoomControls?: boolean\n /** Icon shown at the start of the toolbar; pointer-down on it starts dragging. */\n dragHandle?: ReactNode\n /** Pointer-down handler attached to the drag handle icon. */\n onDragHandlePointerDown?: (e: React.PointerEvent) => void\n extra?: ReactNode\n}\n\nexport function Toolbar({\n scale,\n onZoomIn,\n onZoomOut,\n onReset,\n onFullscreen,\n onDownload,\n isFullscreen = false,\n showZoomControls = true,\n dragHandle,\n onDragHandlePointerDown,\n extra,\n}: ToolbarProps) {\n return (\n <div className=\"vd-toolbar\" role=\"toolbar\" aria-label=\"Document viewer controls\">\n {dragHandle && (\n <span\n className=\"vd-toolbar-drag-handle\"\n onPointerDown={onDragHandlePointerDown}\n title=\"Drag to move\"\n aria-label=\"Drag to move\"\n >\n {dragHandle}\n </span>\n )}\n {showZoomControls && (\n <>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onZoomOut}\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n >\n <ZoomOutIcon />\n </button>\n <span className=\"vd-toolbar-scale\" aria-live=\"polite\">\n {Math.round(scale * 100)}%\n </span>\n <button type=\"button\" className=\"vd-toolbar-btn\" onClick={onZoomIn} aria-label=\"Zoom in\" title=\"Zoom in\">\n <ZoomInIcon />\n </button>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onReset}\n aria-label=\"Reset zoom to 100%\"\n title=\"Reset zoom to 100%\"\n >\n <ResetIcon />\n </button>\n </>\n )}\n {extra}\n <span className=\"vd-toolbar-spacer\" />\n {onDownload && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onDownload}\n aria-label=\"Download file\"\n title=\"Download file\"\n >\n <DownloadIcon />\n </button>\n )}\n {onFullscreen && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onFullscreen}\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n >\n {isFullscreen ? <FullscreenExitIcon /> : <FullscreenEnterIcon />}\n </button>\n )}\n </div>\n )\n}\n","import type { CSSProperties } from 'react'\n\nexport interface ViewerTheme {\n /** Background color of the viewer canvas area. */\n background?: string\n /** Background color of the toolbar strip. */\n toolbarBackground?: string\n /** Border color under the toolbar. */\n toolbarBorderColor?: string\n /** Hover background for toolbar buttons. */\n toolbarButtonHoverBackground?: string\n /** Text/icon color used across the toolbar. */\n textColor?: string\n /** Corner radius of the outer viewer container. */\n borderRadius?: string\n /** Corner radius of individual toolbar buttons. */\n toolbarButtonRadius?: string\n}\n\nconst THEME_VAR_MAP: Record<keyof ViewerTheme, string> = {\n background: '--vd-bg',\n toolbarBackground: '--vd-toolbar-bg',\n toolbarBorderColor: '--vd-toolbar-border-color',\n toolbarButtonHoverBackground: '--vd-toolbar-btn-hover-bg',\n textColor: '--vd-text-color',\n borderRadius: '--vd-border-radius',\n toolbarButtonRadius: '--vd-toolbar-btn-radius',\n}\n\n/** Converts a ViewerTheme into inline CSS custom properties overriding the defaults in styles.css. */\nexport function themeToStyle(theme?: ViewerTheme): CSSProperties | undefined {\n if (!theme) return undefined\n const style: Record<string, string> = {}\n for (const key of Object.keys(theme) as (keyof ViewerTheme)[]) {\n const value = theme[key]\n if (value) style[THEME_VAR_MAP[key]] = value\n }\n return style as CSSProperties\n}\n","import { useCallback, useRef, useState } from 'react'\n\nexport interface ZoomPanState {\n scale: number\n translateX: number\n translateY: number\n}\n\nexport interface ZoomPanOptions {\n minScale?: number\n maxScale?: number\n zoomStep?: number\n /** Allow click-drag-release panning by transforming the content. Default: true. */\n enablePan?: boolean\n /** Allow Ctrl/Cmd + scroll wheel zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Allow click-drag-release scrolling of a natively-scrollable container (used instead of enablePan for scrollable content like PDF pages). Default: false. */\n enableDragScroll?: boolean\n}\n\nexport interface ZoomPanControls extends ZoomPanState {\n containerRef: React.RefObject<HTMLDivElement>\n zoomIn: () => void\n zoomOut: () => void\n resetZoom: () => void\n setScale: (scale: number) => void\n handlers: {\n onWheel: (e: React.WheelEvent) => void\n onPointerDown: (e: React.PointerEvent) => void\n onPointerMove: (e: React.PointerEvent) => void\n onPointerUp: (e: React.PointerEvent) => void\n }\n}\n\nconst DEFAULT_MIN = 0.1\nconst DEFAULT_MAX = 8\nconst DEFAULT_STEP = 0.25\n\nexport function useZoomPan(options: ZoomPanOptions = {}): ZoomPanControls {\n const {\n minScale = DEFAULT_MIN,\n maxScale = DEFAULT_MAX,\n zoomStep = DEFAULT_STEP,\n enablePan = true,\n enableWheelZoom = true,\n enableDragScroll = false,\n } = options\n\n const [state, setState] = useState<ZoomPanState>({ scale: 1, translateX: 0, translateY: 0 })\n const containerRef = useRef<HTMLDivElement>(null)\n const dragState = useRef<{ dragging: boolean; startX: number; startY: number; originX: number; originY: number }>({\n dragging: false,\n startX: 0,\n startY: 0,\n originX: 0,\n originY: 0,\n })\n const scrollDragState = useRef<{ dragging: boolean; startX: number; startY: number; originLeft: number; originTop: number }>(\n { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }\n )\n\n const clamp = useCallback(\n (value: number) => Math.min(maxScale, Math.max(minScale, value)),\n [minScale, maxScale]\n )\n\n const setScale = useCallback(\n (scale: number) => setState((prev) => ({ ...prev, scale: clamp(scale) })),\n [clamp]\n )\n\n const zoomIn = useCallback(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep])\n const zoomOut = useCallback(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep])\n const resetZoom = useCallback(() => setState({ scale: 1, translateX: 0, translateY: 0 }), [])\n\n const onWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!enableWheelZoom) return\n if (!e.ctrlKey && !e.metaKey) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -zoomStep : zoomStep\n setScale(state.scale + delta)\n },\n [enableWheelZoom, setScale, state.scale, zoomStep]\n )\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originX: state.translateX,\n originY: state.translateY,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n } else if (enableDragScroll && containerRef.current) {\n scrollDragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originLeft: containerRef.current.scrollLeft,\n originTop: containerRef.current.scrollTop,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll, state.translateX, state.translateY]\n )\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n if (!dragState.current.dragging) return\n const dx = e.clientX - dragState.current.startX\n const dy = e.clientY - dragState.current.startY\n setState((prev) => ({\n ...prev,\n translateX: dragState.current.originX + dx,\n translateY: dragState.current.originY + dy,\n }))\n } else if (enableDragScroll) {\n if (!scrollDragState.current.dragging || !containerRef.current) return\n const dx = e.clientX - scrollDragState.current.startX\n const dy = e.clientY - scrollDragState.current.startY\n containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx\n containerRef.current.scrollTop = scrollDragState.current.originTop - dy\n }\n },\n [enablePan, enableDragScroll]\n )\n\n const onPointerUp = useCallback(\n (e: React.PointerEvent) => {\n if (enablePan) {\n dragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n } else if (enableDragScroll) {\n scrollDragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll]\n )\n\n return {\n ...state,\n containerRef,\n zoomIn,\n zoomOut,\n resetZoom,\n setScale,\n handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp },\n }\n}\n","import { useEffect, useRef } from 'react'\nimport type { PDFDocumentProxy } from 'pdfjs-dist'\n\nexport interface PdfPageProps {\n doc: PDFDocumentProxy\n pageNumber: number\n /** Render resolution multiplier. Higher = crisper at deep zoom, more memory. Default: 1.5 */\n renderScale?: number\n}\n\nexport function PdfPage({ doc, pageNumber, renderScale = 1.5 }: PdfPageProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const renderTaskRef = useRef<{ cancel: () => void } | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n doc.getPage(pageNumber).then((page) => {\n if (cancelled) return\n const viewport = page.getViewport({ scale: renderScale })\n const canvas = canvasRef.current\n if (!canvas) return\n const context = canvas.getContext('2d')\n if (!context) return\n\n canvas.width = viewport.width\n canvas.height = viewport.height\n canvas.style.width = `${viewport.width / renderScale}px`\n canvas.style.height = `${viewport.height / renderScale}px`\n\n const renderTask = page.render({ canvasContext: context, viewport, canvas })\n renderTaskRef.current = renderTask\n renderTask.promise.catch(() => {\n // ignore cancellation errors from rapid re-renders\n })\n })\n\n return () => {\n cancelled = true\n renderTaskRef.current?.cancel()\n }\n }, [doc, pageNumber, renderScale])\n\n return <canvas ref={canvasRef} className=\"vd-pdf-page\" data-page-number={pageNumber} />\n}\n","import { useEffect, useState } from 'react'\nimport * as pdfjsLib from 'pdfjs-dist'\nimport type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist'\n\npdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString()\n\nexport interface UsePdfDocumentResult {\n doc: PDFDocumentProxy | null\n numPages: number\n error: Error | null\n loading: boolean\n}\n\nexport function usePdfDocument(uri: string): UsePdfDocumentResult {\n const [doc, setDoc] = useState<PDFDocumentProxy | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setDoc(null)\n\n const loadingTask: PDFDocumentLoadingTask = pdfjsLib.getDocument({ url: uri })\n loadingTask.promise\n .then((pdf) => {\n if (cancelled) return\n setDoc(pdf)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n loadingTask.destroy()\n }\n }, [uri])\n\n return { doc, numPages: doc?.numPages ?? 0, error, loading }\n}\n","import { useEffect, useState } from 'react'\n\n/** Tracks which page (by data-page-number) is most visible inside the given scroll container. */\nexport function useVisiblePage(containerRef: React.RefObject<HTMLElement>, numPages: number): number {\n const [currentPage, setCurrentPage] = useState(1)\n\n useEffect(() => {\n const root = containerRef.current\n if (!root || numPages === 0) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const mostVisible = entries\n .filter((e) => e.isIntersecting)\n .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]\n if (mostVisible) {\n const page = Number((mostVisible.target as HTMLElement).dataset.pageNumber)\n if (page) setCurrentPage(page)\n }\n },\n { root, threshold: [0.25, 0.5, 0.75] }\n )\n\n const pages = root.querySelectorAll('[data-page-number]')\n pages.forEach((el) => observer.observe(el))\n\n return () => observer.disconnect()\n }, [containerRef, numPages])\n\n return currentPage\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { PdfPage } from './PdfPage'\nimport { usePdfDocument } from './usePdfDocument'\nimport { useVisiblePage } from './useVisiblePage'\n\nexport interface PdfViewerProps {\n /** URL or data URI of the PDF to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.25 */\n minScale?: number\n /** Maximum zoom scale. Default: 5 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n /** Canvas render resolution multiplier (crispness at high zoom). Default: 1.5 */\n renderScale?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function PdfViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.25,\n maxScale = 5,\n zoomStep,\n renderScale,\n enableZoomControls = true,\n enableWheelZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: PdfViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n })\n const { doc, numPages, error, loading } = usePdfDocument(uri)\n const currentPage = useVisiblePage(zoomPan.containerRef, numPages)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n toolbarExtra={\n numPages > 0 ? (\n <span className=\"vd-pdf-page-indicator\">\n Page {currentPage} / {numPages}\n </span>\n ) : undefined\n }\n >\n {loading && <span className=\"vd-doc-status\">Loading PDF…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load PDF: {error.message}</span>}\n {doc && (\n <div className=\"vd-pdf-pages\">\n {Array.from({ length: numPages }, (_, i) => (\n <PdfPage key={i + 1} doc={doc} pageNumber={i + 1} renderScale={renderScale} />\n ))}\n </div>\n )}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":"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","names":["import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime"]}
|
|
1
|
+
{"version":3,"sources":["../src/entry-pdf.ts","../src/core/ViewerShell.tsx","../src/core/useDraggable.ts","../src/core/icons.tsx","../src/core/Toolbar.tsx","../src/core/theme.ts","../src/core/useZoomPan.ts","../src/viewers/PdfPage.tsx","../src/viewers/usePdfDocument.ts","../src/viewers/useVisiblePage.ts","../src/viewers/PdfViewer.tsx"],"sourcesContent":["export { PdfViewer } from './viewers/PdfViewer'\nexport type { PdfViewerProps } from './viewers/PdfViewer'\n","import { useCallback, useEffect, useRef, useState, type CSSProperties, type ReactNode } from 'react'\nimport { useDraggable, type Position } from './useDraggable'\nimport { GripIcon } from './icons'\nimport { Toolbar } from './Toolbar'\nimport { themeToStyle, type ViewerTheme } from './theme'\nimport type { ZoomPanControls } from './useZoomPan'\n\nexport interface ViewerShellProps {\n zoomPan: ZoomPanControls\n onDownload?: () => void\n toolbarExtra?: ReactNode\n children: ReactNode\n /** Show the zoom in/out/reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Allow click-drag-release panning of the content. Default: true. */\n enablePan?: boolean\n /** Colors/radii to override the default look. Any field left out keeps the default. */\n theme?: ViewerTheme\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent container. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n draggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n /** CSS transform-origin for the zoomed content. Default: 'center center'. */\n transformOrigin?: string\n}\n\nexport function ViewerShell({\n zoomPan,\n onDownload,\n toolbarExtra,\n children,\n enableZoomControls = true,\n enableFullscreen = true,\n enablePan = true,\n theme,\n width,\n height,\n floating = true,\n draggable = true,\n defaultPosition,\n transformOrigin,\n}: ViewerShellProps) {\n const rootRef = useRef<HTMLDivElement>(null)\n const [isFullscreen, setIsFullscreen] = useState(false)\n\n const effectiveWidth = typeof width === 'number' ? width : 1200\n const effectiveHeight = typeof height === 'number' ? height : 700\n const resolvedDefaultPosition =\n defaultPosition ??\n (typeof window !== 'undefined'\n ? {\n x: Math.max(0, (window.innerWidth - effectiveWidth) / 2),\n y: Math.max(0, (window.innerHeight - effectiveHeight) / 2),\n }\n : { x: 80, y: 80 })\n\n const { position, onDragHandlePointerDown } = useDraggable({\n defaultPosition: resolvedDefaultPosition,\n draggable,\n })\n\n useEffect(() => {\n const onChange = () => setIsFullscreen(document.fullscreenElement === rootRef.current)\n document.addEventListener('fullscreenchange', onChange)\n return () => document.removeEventListener('fullscreenchange', onChange)\n }, [])\n\n const fullscreenSupported =\n typeof document !== 'undefined' && typeof document.fullscreenEnabled === 'boolean'\n ? document.fullscreenEnabled\n : false\n\n const onFullscreen = useCallback(() => {\n const el = rootRef.current\n if (!el || typeof el.requestFullscreen !== 'function') return\n if (document.fullscreenElement) {\n document.exitFullscreen()\n } else {\n el.requestFullscreen()\n }\n }, [])\n\n const sizeStyle: CSSProperties = {\n width: width ?? 1200,\n height: height ?? 700,\n }\n const floatingStyle: CSSProperties | undefined = floating\n ? { position: 'fixed', left: position.x, top: position.y }\n : undefined\n\n return (\n <div\n className={`vd-shell${floating ? ' vd-shell--floating' : ''}`}\n ref={rootRef}\n style={{ ...themeToStyle(theme), ...sizeStyle, ...floatingStyle }}\n >\n <Toolbar\n scale={zoomPan.scale}\n onZoomIn={zoomPan.zoomIn}\n onZoomOut={zoomPan.zoomOut}\n onReset={zoomPan.resetZoom}\n onFullscreen={enableFullscreen && fullscreenSupported ? onFullscreen : undefined}\n onDownload={onDownload}\n isFullscreen={isFullscreen}\n showZoomControls={enableZoomControls}\n dragHandle={floating && draggable ? <GripIcon /> : undefined}\n onDragHandlePointerDown={floating && draggable ? onDragHandlePointerDown : undefined}\n extra={toolbarExtra}\n />\n <div\n className={`vd-canvas${enablePan ? '' : ' vd-canvas--no-pan'}`}\n ref={zoomPan.containerRef}\n onWheel={zoomPan.handlers.onWheel}\n onPointerDown={zoomPan.handlers.onPointerDown}\n onPointerMove={zoomPan.handlers.onPointerMove}\n onPointerUp={zoomPan.handlers.onPointerUp}\n >\n <div\n className=\"vd-canvas-content\"\n style={{\n transform: `translate(${zoomPan.translateX}px, ${zoomPan.translateY}px) scale(${zoomPan.scale})`,\n transformOrigin,\n }}\n >\n {children}\n </div>\n </div>\n </div>\n )\n}\n","import { useCallback, useState } from 'react'\n\nexport interface Position {\n x: number\n y: number\n}\n\nexport interface UseDraggableOptions {\n defaultPosition?: Position\n /** Allow dragging via the returned handle props. Default: true. */\n draggable?: boolean\n}\n\nexport interface DraggableControls {\n position: Position\n onDragHandlePointerDown: (e: React.PointerEvent) => void\n}\n\nexport function useDraggable(options: UseDraggableOptions = {}): DraggableControls {\n const { defaultPosition = { x: 80, y: 80 }, draggable = true } = options\n const [position, setPosition] = useState<Position>(defaultPosition)\n\n const onDragHandlePointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (!draggable) return\n e.preventDefault()\n const startX = e.clientX\n const startY = e.clientY\n\n setPosition((current) => {\n const originX = current.x\n const originY = current.y\n\n const onMove = (ev: PointerEvent) => {\n setPosition({ x: originX + (ev.clientX - startX), y: originY + (ev.clientY - startY) })\n }\n const onUp = () => {\n window.removeEventListener('pointermove', onMove)\n window.removeEventListener('pointerup', onUp)\n }\n window.addEventListener('pointermove', onMove)\n window.addEventListener('pointerup', onUp)\n\n return current\n })\n },\n [draggable]\n )\n\n return { position, onDragHandlePointerDown }\n}\n","import type { SVGProps } from 'react'\n\nfunction Svg(props: SVGProps<SVGSVGElement>) {\n return (\n <svg\n width=\"16\"\n height=\"16\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n focusable=\"false\"\n {...props}\n />\n )\n}\n\nexport function ZoomOutIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function ZoomInIcon() {\n return (\n <Svg>\n <circle cx=\"11\" cy=\"11\" r=\"7\" />\n <line x1=\"21\" y1=\"21\" x2=\"16.65\" y2=\"16.65\" />\n <line x1=\"11\" y1=\"8\" x2=\"11\" y2=\"14\" />\n <line x1=\"8\" y1=\"11\" x2=\"14\" y2=\"11\" />\n </Svg>\n )\n}\n\nexport function DownloadIcon() {\n return (\n <Svg>\n <path d=\"M12 3v12\" />\n <path d=\"M7 10l5 5 5-5\" />\n <path d=\"M5 21h14\" />\n </Svg>\n )\n}\n\nexport function FullscreenEnterIcon() {\n return (\n <Svg>\n <polyline points=\"15 3 21 3 21 9\" />\n <polyline points=\"9 21 3 21 3 15\" />\n <line x1=\"21\" y1=\"3\" x2=\"14\" y2=\"10\" />\n <line x1=\"3\" y1=\"21\" x2=\"10\" y2=\"14\" />\n </Svg>\n )\n}\n\nexport function ResetIcon() {\n return (\n <Svg>\n <path d=\"M3 12a9 9 0 1 0 3-6.7\" />\n <polyline points=\"3 3 3 8 8 8\" />\n </Svg>\n )\n}\n\nexport function GripIcon() {\n return (\n <Svg>\n <polyline points=\"5 9 2 12 5 15\" />\n <polyline points=\"9 5 12 2 15 5\" />\n <polyline points=\"15 19 12 22 9 19\" />\n <polyline points=\"19 9 22 12 19 15\" />\n <line x1=\"2\" y1=\"12\" x2=\"22\" y2=\"12\" />\n <line x1=\"12\" y1=\"2\" x2=\"12\" y2=\"22\" />\n </Svg>\n )\n}\n\nexport function FullscreenExitIcon() {\n return (\n <Svg>\n <polyline points=\"9 3 9 9 3 9\" />\n <polyline points=\"15 21 15 15 21 15\" />\n <line x1=\"9\" y1=\"9\" x2=\"3\" y2=\"3\" />\n <line x1=\"15\" y1=\"15\" x2=\"21\" y2=\"21\" />\n </Svg>\n )\n}\n","import type { ReactNode } from 'react'\nimport { DownloadIcon, FullscreenEnterIcon, FullscreenExitIcon, ResetIcon, ZoomInIcon, ZoomOutIcon } from './icons'\n\nexport interface ToolbarProps {\n scale: number\n onZoomIn: () => void\n onZoomOut: () => void\n onReset: () => void\n onFullscreen?: () => void\n onDownload?: () => void\n /** Whether the viewer is currently in fullscreen mode (controls which icon is shown). */\n isFullscreen?: boolean\n /** Show zoom in/out/reset controls. Default: true. */\n showZoomControls?: boolean\n /** Icon shown at the start of the toolbar; pointer-down on it starts dragging. */\n dragHandle?: ReactNode\n /** Pointer-down handler attached to the drag handle icon. */\n onDragHandlePointerDown?: (e: React.PointerEvent) => void\n extra?: ReactNode\n}\n\nexport function Toolbar({\n scale,\n onZoomIn,\n onZoomOut,\n onReset,\n onFullscreen,\n onDownload,\n isFullscreen = false,\n showZoomControls = true,\n dragHandle,\n onDragHandlePointerDown,\n extra,\n}: ToolbarProps) {\n return (\n <div className=\"vd-toolbar\" role=\"toolbar\" aria-label=\"Document viewer controls\">\n {dragHandle && (\n <span\n className=\"vd-toolbar-drag-handle\"\n onPointerDown={onDragHandlePointerDown}\n title=\"Drag to move\"\n aria-label=\"Drag to move\"\n >\n {dragHandle}\n </span>\n )}\n {showZoomControls && (\n <>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onZoomOut}\n aria-label=\"Zoom out\"\n title=\"Zoom out\"\n >\n <ZoomOutIcon />\n </button>\n <span className=\"vd-toolbar-scale\" aria-live=\"polite\">\n {Math.round(scale * 100)}%\n </span>\n <button type=\"button\" className=\"vd-toolbar-btn\" onClick={onZoomIn} aria-label=\"Zoom in\" title=\"Zoom in\">\n <ZoomInIcon />\n </button>\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onReset}\n aria-label=\"Reset zoom to 100%\"\n title=\"Reset zoom to 100%\"\n >\n <ResetIcon />\n </button>\n </>\n )}\n {extra}\n <span className=\"vd-toolbar-spacer\" />\n {onDownload && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onDownload}\n aria-label=\"Download file\"\n title=\"Download file\"\n >\n <DownloadIcon />\n </button>\n )}\n {onFullscreen && (\n <button\n type=\"button\"\n className=\"vd-toolbar-btn\"\n onClick={onFullscreen}\n aria-label={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n title={isFullscreen ? 'Exit fullscreen' : 'Enter fullscreen'}\n >\n {isFullscreen ? <FullscreenExitIcon /> : <FullscreenEnterIcon />}\n </button>\n )}\n </div>\n )\n}\n","import type { CSSProperties } from 'react'\n\nexport interface ViewerTheme {\n /** Background color of the viewer canvas area. */\n background?: string\n /** Background color of the toolbar strip. */\n toolbarBackground?: string\n /** Border color under the toolbar. */\n toolbarBorderColor?: string\n /** Hover background for toolbar buttons. */\n toolbarButtonHoverBackground?: string\n /** Text/icon color used across the toolbar. */\n textColor?: string\n /** Corner radius of the outer viewer container. */\n borderRadius?: string\n /** Corner radius of individual toolbar buttons. */\n toolbarButtonRadius?: string\n}\n\nconst THEME_VAR_MAP: Record<keyof ViewerTheme, string> = {\n background: '--vd-bg',\n toolbarBackground: '--vd-toolbar-bg',\n toolbarBorderColor: '--vd-toolbar-border-color',\n toolbarButtonHoverBackground: '--vd-toolbar-btn-hover-bg',\n textColor: '--vd-text-color',\n borderRadius: '--vd-border-radius',\n toolbarButtonRadius: '--vd-toolbar-btn-radius',\n}\n\n/** Converts a ViewerTheme into inline CSS custom properties overriding the defaults in styles.css. */\nexport function themeToStyle(theme?: ViewerTheme): CSSProperties | undefined {\n if (!theme) return undefined\n const style: Record<string, string> = {}\n for (const key of Object.keys(theme) as (keyof ViewerTheme)[]) {\n const value = theme[key]\n if (value) style[THEME_VAR_MAP[key]] = value\n }\n return style as CSSProperties\n}\n","import { useCallback, useRef, useState } from 'react'\n\nexport interface ZoomPanState {\n scale: number\n translateX: number\n translateY: number\n}\n\nexport interface ZoomPanOptions {\n minScale?: number\n maxScale?: number\n zoomStep?: number\n /** Allow click-drag-release panning by transforming the content. Default: true. */\n enablePan?: boolean\n /** Allow Ctrl/Cmd + scroll wheel zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Allow click-drag-release scrolling of a natively-scrollable container (used instead of enablePan for scrollable content like PDF pages). Default: false. */\n enableDragScroll?: boolean\n /** Allow two-finger pinch to zoom on touch devices. Default: true. */\n enablePinchZoom?: boolean\n}\n\nexport interface ZoomPanControls extends ZoomPanState {\n containerRef: React.RefObject<HTMLDivElement>\n zoomIn: () => void\n zoomOut: () => void\n resetZoom: () => void\n setScale: (scale: number) => void\n handlers: {\n onWheel: (e: React.WheelEvent) => void\n onPointerDown: (e: React.PointerEvent) => void\n onPointerMove: (e: React.PointerEvent) => void\n onPointerUp: (e: React.PointerEvent) => void\n }\n}\n\nconst DEFAULT_MIN = 0.1\nconst DEFAULT_MAX = 8\nconst DEFAULT_STEP = 0.25\n\nfunction pointerDistance(a: PointerData, b: PointerData) {\n return Math.hypot(a.x - b.x, a.y - b.y)\n}\n\ninterface PointerData {\n x: number\n y: number\n}\n\nexport function useZoomPan(options: ZoomPanOptions = {}): ZoomPanControls {\n const {\n minScale = DEFAULT_MIN,\n maxScale = DEFAULT_MAX,\n zoomStep = DEFAULT_STEP,\n enablePan = true,\n enableWheelZoom = true,\n enableDragScroll = false,\n enablePinchZoom = true,\n } = options\n\n const [state, setState] = useState<ZoomPanState>({ scale: 1, translateX: 0, translateY: 0 })\n const containerRef = useRef<HTMLDivElement>(null)\n const dragState = useRef<{ dragging: boolean; startX: number; startY: number; originX: number; originY: number }>({\n dragging: false,\n startX: 0,\n startY: 0,\n originX: 0,\n originY: 0,\n })\n const scrollDragState = useRef<{ dragging: boolean; startX: number; startY: number; originLeft: number; originTop: number }>(\n { dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }\n )\n const activePointers = useRef<Map<number, PointerData>>(new Map())\n const pinchState = useRef<{ pinching: boolean; startDistance: number; startScale: number }>({\n pinching: false,\n startDistance: 0,\n startScale: 1,\n })\n\n const clamp = useCallback(\n (value: number) => Math.min(maxScale, Math.max(minScale, value)),\n [minScale, maxScale]\n )\n\n const setScale = useCallback(\n (scale: number) => setState((prev) => ({ ...prev, scale: clamp(scale) })),\n [clamp]\n )\n\n const zoomIn = useCallback(() => setScale(state.scale + zoomStep), [setScale, state.scale, zoomStep])\n const zoomOut = useCallback(() => setScale(state.scale - zoomStep), [setScale, state.scale, zoomStep])\n const resetZoom = useCallback(() => setState({ scale: 1, translateX: 0, translateY: 0 }), [])\n\n const onWheel = useCallback(\n (e: React.WheelEvent) => {\n if (!enableWheelZoom) return\n if (!e.ctrlKey && !e.metaKey) return\n e.preventDefault()\n const delta = e.deltaY > 0 ? -zoomStep : zoomStep\n setScale(state.scale + delta)\n },\n [enableWheelZoom, setScale, state.scale, zoomStep]\n )\n\n const onPointerDown = useCallback(\n (e: React.PointerEvent) => {\n if (enablePinchZoom) {\n activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY })\n if (activePointers.current.size === 2) {\n const [a, b] = Array.from(activePointers.current.values())\n pinchState.current = { pinching: true, startDistance: pointerDistance(a, b), startScale: state.scale }\n dragState.current.dragging = false\n scrollDragState.current.dragging = false\n return\n }\n }\n\n if (enablePan) {\n dragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originX: state.translateX,\n originY: state.translateY,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n } else if (enableDragScroll && containerRef.current) {\n scrollDragState.current = {\n dragging: true,\n startX: e.clientX,\n startY: e.clientY,\n originLeft: containerRef.current.scrollLeft,\n originTop: containerRef.current.scrollTop,\n }\n ;(e.target as HTMLElement).setPointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll, enablePinchZoom, state.translateX, state.translateY, state.scale]\n )\n\n const onPointerMove = useCallback(\n (e: React.PointerEvent) => {\n if (enablePinchZoom && activePointers.current.has(e.pointerId)) {\n activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY })\n }\n\n if (pinchState.current.pinching && activePointers.current.size === 2) {\n const [a, b] = Array.from(activePointers.current.values())\n const distance = pointerDistance(a, b)\n const ratio = distance / (pinchState.current.startDistance || distance)\n setScale(pinchState.current.startScale * ratio)\n return\n }\n\n if (enablePan) {\n if (!dragState.current.dragging) return\n const dx = e.clientX - dragState.current.startX\n const dy = e.clientY - dragState.current.startY\n setState((prev) => ({\n ...prev,\n translateX: dragState.current.originX + dx,\n translateY: dragState.current.originY + dy,\n }))\n } else if (enableDragScroll) {\n if (!scrollDragState.current.dragging || !containerRef.current) return\n const dx = e.clientX - scrollDragState.current.startX\n const dy = e.clientY - scrollDragState.current.startY\n containerRef.current.scrollLeft = scrollDragState.current.originLeft - dx\n containerRef.current.scrollTop = scrollDragState.current.originTop - dy\n }\n },\n [enablePan, enableDragScroll, enablePinchZoom, setScale]\n )\n\n const onPointerUp = useCallback(\n (e: React.PointerEvent) => {\n activePointers.current.delete(e.pointerId)\n if (activePointers.current.size < 2) {\n pinchState.current.pinching = false\n }\n\n if (enablePan) {\n dragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n } else if (enableDragScroll) {\n scrollDragState.current.dragging = false\n ;(e.target as HTMLElement).releasePointerCapture(e.pointerId)\n }\n },\n [enablePan, enableDragScroll]\n )\n\n return {\n ...state,\n containerRef,\n zoomIn,\n zoomOut,\n resetZoom,\n setScale,\n handlers: { onWheel, onPointerDown, onPointerMove, onPointerUp },\n }\n}\n","import { useEffect, useRef } from 'react'\nimport type { PDFDocumentProxy } from 'pdfjs-dist'\n\nexport interface PdfPageProps {\n doc: PDFDocumentProxy\n pageNumber: number\n /** Render resolution multiplier. Higher = crisper at deep zoom, more memory. Default: 1.5 */\n renderScale?: number\n}\n\nexport function PdfPage({ doc, pageNumber, renderScale = 1.5 }: PdfPageProps) {\n const canvasRef = useRef<HTMLCanvasElement>(null)\n const renderTaskRef = useRef<{ cancel: () => void } | null>(null)\n\n useEffect(() => {\n let cancelled = false\n\n doc.getPage(pageNumber).then((page) => {\n if (cancelled) return\n const viewport = page.getViewport({ scale: renderScale })\n const canvas = canvasRef.current\n if (!canvas) return\n const context = canvas.getContext('2d')\n if (!context) return\n\n canvas.width = viewport.width\n canvas.height = viewport.height\n canvas.style.width = `${viewport.width / renderScale}px`\n canvas.style.height = `${viewport.height / renderScale}px`\n\n const renderTask = page.render({ canvasContext: context, viewport, canvas })\n renderTaskRef.current = renderTask\n renderTask.promise.catch(() => {\n // ignore cancellation errors from rapid re-renders\n })\n })\n\n return () => {\n cancelled = true\n renderTaskRef.current?.cancel()\n }\n }, [doc, pageNumber, renderScale])\n\n return <canvas ref={canvasRef} className=\"vd-pdf-page\" data-page-number={pageNumber} />\n}\n","import { useEffect, useState } from 'react'\nimport * as pdfjsLib from 'pdfjs-dist'\nimport type { PDFDocumentLoadingTask, PDFDocumentProxy } from 'pdfjs-dist'\n\npdfjsLib.GlobalWorkerOptions.workerSrc = new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url).toString()\n\nexport interface UsePdfDocumentResult {\n doc: PDFDocumentProxy | null\n numPages: number\n error: Error | null\n loading: boolean\n}\n\nexport function usePdfDocument(uri: string): UsePdfDocumentResult {\n const [doc, setDoc] = useState<PDFDocumentProxy | null>(null)\n const [error, setError] = useState<Error | null>(null)\n const [loading, setLoading] = useState(true)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(null)\n setDoc(null)\n\n const loadingTask: PDFDocumentLoadingTask = pdfjsLib.getDocument({ url: uri })\n loadingTask.promise\n .then((pdf) => {\n if (cancelled) return\n setDoc(pdf)\n setLoading(false)\n })\n .catch((err: Error) => {\n if (!cancelled) {\n setError(err)\n setLoading(false)\n }\n })\n\n return () => {\n cancelled = true\n loadingTask.destroy()\n }\n }, [uri])\n\n return { doc, numPages: doc?.numPages ?? 0, error, loading }\n}\n","import { useEffect, useState } from 'react'\n\n/** Tracks which page (by data-page-number) is most visible inside the given scroll container. */\nexport function useVisiblePage(containerRef: React.RefObject<HTMLElement>, numPages: number): number {\n const [currentPage, setCurrentPage] = useState(1)\n\n useEffect(() => {\n const root = containerRef.current\n if (!root || numPages === 0) return\n\n const observer = new IntersectionObserver(\n (entries) => {\n const mostVisible = entries\n .filter((e) => e.isIntersecting)\n .sort((a, b) => b.intersectionRatio - a.intersectionRatio)[0]\n if (mostVisible) {\n const page = Number((mostVisible.target as HTMLElement).dataset.pageNumber)\n if (page) setCurrentPage(page)\n }\n },\n { root, threshold: [0.25, 0.5, 0.75] }\n )\n\n const pages = root.querySelectorAll('[data-page-number]')\n pages.forEach((el) => observer.observe(el))\n\n return () => observer.disconnect()\n }, [containerRef, numPages])\n\n return currentPage\n}\n","import type { CSSProperties } from 'react'\nimport { ViewerShell } from '../core/ViewerShell'\nimport type { ViewerTheme } from '../core/theme'\nimport type { Position } from '../core/useDraggable'\nimport { useZoomPan } from '../core/useZoomPan'\nimport { PdfPage } from './PdfPage'\nimport { usePdfDocument } from './usePdfDocument'\nimport { useVisiblePage } from './useVisiblePage'\n\nexport interface PdfViewerProps {\n /** URL or data URI of the PDF to display. */\n uri: string\n /** Used as the suggested filename on download. */\n fileName?: string\n className?: string\n style?: CSSProperties\n\n /** Width of the viewer. Accepts any CSS size (e.g. 1200, '1200px', '100%'). Default: 1200. */\n width?: number | string\n /** Height of the viewer. Accepts any CSS size (e.g. 700, '700px', '100vh'). Default: 700. */\n height?: number | string\n\n /** Minimum zoom scale. Default: 0.25 */\n minScale?: number\n /** Maximum zoom scale. Default: 5 */\n maxScale?: number\n /** Zoom increment per step (buttons / Ctrl+scroll). Default: 0.25 */\n zoomStep?: number\n /** Canvas render resolution multiplier (crispness at high zoom). Default: 1.5 */\n renderScale?: number\n\n /** Show zoom in/out and reset-to-100% controls. Default: true. */\n enableZoomControls?: boolean\n /** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */\n enableWheelZoom?: boolean\n /** Allow two-finger pinch to zoom on touch devices. Default: true. */\n enablePinchZoom?: boolean\n /** Show the fullscreen toggle button. Default: true. */\n enableFullscreen?: boolean\n /** Show the download button. Default: true. */\n enableDownload?: boolean\n /** Called when the download button is clicked. If omitted, downloads `uri` directly. */\n onDownload?: () => void\n /** Colors/radii to override the default look (toolbar background, text color, etc). */\n theme?: ViewerTheme\n\n /** Render as a floating window (position: fixed) that can be dragged, instead of filling the parent. Default: true. */\n floating?: boolean\n /** When floating, allow dragging the window by its toolbar. Default: true. */\n windowDraggable?: boolean\n /** Initial position when floating. Default: centered in the viewport. */\n defaultPosition?: Position\n}\n\nfunction defaultDownload(uri: string, fileName?: string) {\n const link = document.createElement('a')\n link.href = uri\n link.download = fileName ?? ''\n link.rel = 'noopener'\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n}\n\nexport function PdfViewer({\n uri,\n fileName,\n className,\n style,\n width,\n height,\n minScale = 0.25,\n maxScale = 5,\n zoomStep,\n renderScale,\n enableZoomControls = true,\n enableWheelZoom = true,\n enablePinchZoom = true,\n enableFullscreen = true,\n enableDownload = true,\n onDownload,\n theme,\n floating = true,\n windowDraggable = true,\n defaultPosition,\n}: PdfViewerProps) {\n const zoomPan = useZoomPan({\n minScale,\n maxScale,\n zoomStep,\n enablePan: false,\n enableDragScroll: true,\n enableWheelZoom,\n enablePinchZoom,\n })\n const { doc, numPages, error, loading } = usePdfDocument(uri)\n const currentPage = useVisiblePage(zoomPan.containerRef, numPages)\n\n const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : undefined\n\n const wrapperStyle: CSSProperties = floating\n ? { ...style }\n : { display: 'flex', alignItems: 'center', justifyContent: 'center', width: '100%', height: '100%', ...style }\n\n return (\n <div className={className} style={wrapperStyle}>\n <ViewerShell\n zoomPan={zoomPan}\n onDownload={handleDownload}\n enableZoomControls={enableZoomControls}\n enableFullscreen={enableFullscreen}\n enablePan={false}\n theme={theme}\n width={width}\n height={height}\n floating={floating}\n draggable={windowDraggable}\n defaultPosition={defaultPosition}\n transformOrigin=\"top center\"\n toolbarExtra={\n numPages > 0 ? (\n <span className=\"vd-pdf-page-indicator\">\n Page {currentPage} / {numPages}\n </span>\n ) : undefined\n }\n >\n {loading && <span className=\"vd-doc-status\">Loading PDF…</span>}\n {error && <span className=\"vd-doc-status\">Failed to load PDF: {error.message}</span>}\n {doc && (\n <div className=\"vd-pdf-pages\">\n {Array.from({ length: numPages }, (_, i) => (\n <PdfPage key={i + 1} doc={doc} pageNumber={i + 1} renderScale={renderScale} />\n ))}\n </div>\n )}\n </ViewerShell>\n </div>\n )\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,IAAAA,gBAA6F;;;ACA7F,mBAAsC;AAkB/B,SAAS,aAAa,UAA+B,CAAC,GAAsB;AACjF,QAAM,EAAE,kBAAkB,EAAE,GAAG,IAAI,GAAG,GAAG,GAAG,YAAY,KAAK,IAAI;AACjE,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAmB,eAAe;AAElE,QAAM,8BAA0B;AAAA,IAC9B,CAAC,MAA0B;AACzB,UAAI,CAAC,UAAW;AAChB,QAAE,eAAe;AACjB,YAAM,SAAS,EAAE;AACjB,YAAM,SAAS,EAAE;AAEjB,kBAAY,CAAC,YAAY;AACvB,cAAM,UAAU,QAAQ;AACxB,cAAM,UAAU,QAAQ;AAExB,cAAM,SAAS,CAAC,OAAqB;AACnC,sBAAY,EAAE,GAAG,WAAW,GAAG,UAAU,SAAS,GAAG,WAAW,GAAG,UAAU,QAAQ,CAAC;AAAA,QACxF;AACA,cAAM,OAAO,MAAM;AACjB,iBAAO,oBAAoB,eAAe,MAAM;AAChD,iBAAO,oBAAoB,aAAa,IAAI;AAAA,QAC9C;AACA,eAAO,iBAAiB,eAAe,MAAM;AAC7C,eAAO,iBAAiB,aAAa,IAAI;AAEzC,eAAO;AAAA,MACT,CAAC;AAAA,IACH;AAAA,IACA,CAAC,SAAS;AAAA,EACZ;AAEA,SAAO,EAAE,UAAU,wBAAwB;AAC7C;;;AC9CI;AAFJ,SAAS,IAAI,OAAgC;AAC3C,SACE;AAAA,IAAC;AAAA;AAAA,MACC,OAAM;AAAA,MACN,QAAO;AAAA,MACP,SAAQ;AAAA,MACR,MAAK;AAAA,MACL,QAAO;AAAA,MACP,aAAY;AAAA,MACZ,eAAc;AAAA,MACd,gBAAe;AAAA,MACf,eAAY;AAAA,MACZ,WAAU;AAAA,MACT,GAAG;AAAA;AAAA,EACN;AAEJ;AAEO,SAAS,cAAc;AAC5B,SACE,6CAAC,OACC;AAAA,gDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,4CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,IAC5C,4CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEO,SAAS,aAAa;AAC3B,SACE,6CAAC,OACC;AAAA,gDAAC,YAAO,IAAG,MAAK,IAAG,MAAK,GAAE,KAAI;AAAA,IAC9B,4CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,SAAQ,IAAG,SAAQ;AAAA,IAC5C,4CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,4CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEO,SAAS,eAAe;AAC7B,SACE,6CAAC,OACC;AAAA,gDAAC,UAAK,GAAE,YAAW;AAAA,IACnB,4CAAC,UAAK,GAAE,iBAAgB;AAAA,IACxB,4CAAC,UAAK,GAAE,YAAW;AAAA,KACrB;AAEJ;AAEO,SAAS,sBAAsB;AACpC,SACE,6CAAC,OACC;AAAA,gDAAC,cAAS,QAAO,kBAAiB;AAAA,IAClC,4CAAC,cAAS,QAAO,kBAAiB;AAAA,IAClC,4CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,4CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEO,SAAS,YAAY;AAC1B,SACE,6CAAC,OACC;AAAA,gDAAC,UAAK,GAAE,yBAAwB;AAAA,IAChC,4CAAC,cAAS,QAAO,eAAc;AAAA,KACjC;AAEJ;AAEO,SAAS,WAAW;AACzB,SACE,6CAAC,OACC;AAAA,gDAAC,cAAS,QAAO,iBAAgB;AAAA,IACjC,4CAAC,cAAS,QAAO,iBAAgB;AAAA,IACjC,4CAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,4CAAC,cAAS,QAAO,oBAAmB;AAAA,IACpC,4CAAC,UAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,IACrC,4CAAC,UAAK,IAAG,MAAK,IAAG,KAAI,IAAG,MAAK,IAAG,MAAK;AAAA,KACvC;AAEJ;AAEO,SAAS,qBAAqB;AACnC,SACE,6CAAC,OACC;AAAA,gDAAC,cAAS,QAAO,eAAc;AAAA,IAC/B,4CAAC,cAAS,QAAO,qBAAoB;AAAA,IACrC,4CAAC,UAAK,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI,IAAG,KAAI;AAAA,IAClC,4CAAC,UAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK,IAAG,MAAK;AAAA,KACxC;AAEJ;;;ACxDQ,IAAAC,sBAAA;AAhBD,SAAS,QAAQ;AAAA,EACtB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,mBAAmB;AAAA,EACnB;AAAA,EACA;AAAA,EACA;AACF,GAAiB;AACf,SACE,8CAAC,SAAI,WAAU,cAAa,MAAK,WAAU,cAAW,4BACnD;AAAA,kBACC;AAAA,MAAC;AAAA;AAAA,QACC,WAAU;AAAA,QACV,eAAe;AAAA,QACf,OAAM;AAAA,QACN,cAAW;AAAA,QAEV;AAAA;AAAA,IACH;AAAA,IAED,oBACC,8EACE;AAAA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,cAAW;AAAA,UACX,OAAM;AAAA,UAEN,uDAAC,eAAY;AAAA;AAAA,MACf;AAAA,MACA,8CAAC,UAAK,WAAU,oBAAmB,aAAU,UAC1C;AAAA,aAAK,MAAM,QAAQ,GAAG;AAAA,QAAE;AAAA,SAC3B;AAAA,MACA,6CAAC,YAAO,MAAK,UAAS,WAAU,kBAAiB,SAAS,UAAU,cAAW,WAAU,OAAM,WAC7F,uDAAC,cAAW,GACd;AAAA,MACA;AAAA,QAAC;AAAA;AAAA,UACC,MAAK;AAAA,UACL,WAAU;AAAA,UACV,SAAS;AAAA,UACT,cAAW;AAAA,UACX,OAAM;AAAA,UAEN,uDAAC,aAAU;AAAA;AAAA,MACb;AAAA,OACF;AAAA,IAED;AAAA,IACD,6CAAC,UAAK,WAAU,qBAAoB;AAAA,IACnC,cACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAW;AAAA,QACX,OAAM;AAAA,QAEN,uDAAC,gBAAa;AAAA;AAAA,IAChB;AAAA,IAED,gBACC;AAAA,MAAC;AAAA;AAAA,QACC,MAAK;AAAA,QACL,WAAU;AAAA,QACV,SAAS;AAAA,QACT,cAAY,eAAe,oBAAoB;AAAA,QAC/C,OAAO,eAAe,oBAAoB;AAAA,QAEzC,yBAAe,6CAAC,sBAAmB,IAAK,6CAAC,uBAAoB;AAAA;AAAA,IAChE;AAAA,KAEJ;AAEJ;;;ACjFA,IAAM,gBAAmD;AAAA,EACvD,YAAY;AAAA,EACZ,mBAAmB;AAAA,EACnB,oBAAoB;AAAA,EACpB,8BAA8B;AAAA,EAC9B,WAAW;AAAA,EACX,cAAc;AAAA,EACd,qBAAqB;AACvB;AAGO,SAAS,aAAa,OAAgD;AAC3E,MAAI,CAAC,MAAO,QAAO;AACnB,QAAM,QAAgC,CAAC;AACvC,aAAW,OAAO,OAAO,KAAK,KAAK,GAA4B;AAC7D,UAAM,QAAQ,MAAM,GAAG;AACvB,QAAI,MAAO,OAAM,cAAc,GAAG,CAAC,IAAI;AAAA,EACzC;AACA,SAAO;AACT;;;AJ8DI,IAAAC,sBAAA;AAjEG,SAAS,YAAY;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,mBAAmB;AAAA,EACnB,YAAY;AAAA,EACZ;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,YAAY;AAAA,EACZ;AAAA,EACA;AACF,GAAqB;AACnB,QAAM,cAAU,sBAAuB,IAAI;AAC3C,QAAM,CAAC,cAAc,eAAe,QAAI,wBAAS,KAAK;AAEtD,QAAM,iBAAiB,OAAO,UAAU,WAAW,QAAQ;AAC3D,QAAM,kBAAkB,OAAO,WAAW,WAAW,SAAS;AAC9D,QAAM,0BACJ,oBACC,OAAO,WAAW,cACf;AAAA,IACE,GAAG,KAAK,IAAI,IAAI,OAAO,aAAa,kBAAkB,CAAC;AAAA,IACvD,GAAG,KAAK,IAAI,IAAI,OAAO,cAAc,mBAAmB,CAAC;AAAA,EAC3D,IACA,EAAE,GAAG,IAAI,GAAG,GAAG;AAErB,QAAM,EAAE,UAAU,wBAAwB,IAAI,aAAa;AAAA,IACzD,iBAAiB;AAAA,IACjB;AAAA,EACF,CAAC;AAED,+BAAU,MAAM;AACd,UAAM,WAAW,MAAM,gBAAgB,SAAS,sBAAsB,QAAQ,OAAO;AACrF,aAAS,iBAAiB,oBAAoB,QAAQ;AACtD,WAAO,MAAM,SAAS,oBAAoB,oBAAoB,QAAQ;AAAA,EACxE,GAAG,CAAC,CAAC;AAEL,QAAM,sBACJ,OAAO,aAAa,eAAe,OAAO,SAAS,sBAAsB,YACrE,SAAS,oBACT;AAEN,QAAM,mBAAe,2BAAY,MAAM;AACrC,UAAM,KAAK,QAAQ;AACnB,QAAI,CAAC,MAAM,OAAO,GAAG,sBAAsB,WAAY;AACvD,QAAI,SAAS,mBAAmB;AAC9B,eAAS,eAAe;AAAA,IAC1B,OAAO;AACL,SAAG,kBAAkB;AAAA,IACvB;AAAA,EACF,GAAG,CAAC,CAAC;AAEL,QAAM,YAA2B;AAAA,IAC/B,OAAO,SAAS;AAAA,IAChB,QAAQ,UAAU;AAAA,EACpB;AACA,QAAM,gBAA2C,WAC7C,EAAE,UAAU,SAAS,MAAM,SAAS,GAAG,KAAK,SAAS,EAAE,IACvD;AAEJ,SACE;AAAA,IAAC;AAAA;AAAA,MACC,WAAW,WAAW,WAAW,wBAAwB,EAAE;AAAA,MAC3D,KAAK;AAAA,MACL,OAAO,EAAE,GAAG,aAAa,KAAK,GAAG,GAAG,WAAW,GAAG,cAAc;AAAA,MAEhE;AAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO,QAAQ;AAAA,YACf,UAAU,QAAQ;AAAA,YAClB,WAAW,QAAQ;AAAA,YACnB,SAAS,QAAQ;AAAA,YACjB,cAAc,oBAAoB,sBAAsB,eAAe;AAAA,YACvE;AAAA,YACA;AAAA,YACA,kBAAkB;AAAA,YAClB,YAAY,YAAY,YAAY,6CAAC,YAAS,IAAK;AAAA,YACnD,yBAAyB,YAAY,YAAY,0BAA0B;AAAA,YAC3E,OAAO;AAAA;AAAA,QACT;AAAA,QACA;AAAA,UAAC;AAAA;AAAA,YACC,WAAW,YAAY,YAAY,KAAK,oBAAoB;AAAA,YAC5D,KAAK,QAAQ;AAAA,YACb,SAAS,QAAQ,SAAS;AAAA,YAC1B,eAAe,QAAQ,SAAS;AAAA,YAChC,eAAe,QAAQ,SAAS;AAAA,YAChC,aAAa,QAAQ,SAAS;AAAA,YAE9B;AAAA,cAAC;AAAA;AAAA,gBACC,WAAU;AAAA,gBACV,OAAO;AAAA,kBACL,WAAW,aAAa,QAAQ,UAAU,OAAO,QAAQ,UAAU,aAAa,QAAQ,KAAK;AAAA,kBAC7F;AAAA,gBACF;AAAA,gBAEC;AAAA;AAAA,YACH;AAAA;AAAA,QACF;AAAA;AAAA;AAAA,EACF;AAEJ;;;AK1IA,IAAAC,gBAA8C;AAoC9C,IAAM,cAAc;AACpB,IAAM,cAAc;AACpB,IAAM,eAAe;AAErB,SAAS,gBAAgB,GAAgB,GAAgB;AACvD,SAAO,KAAK,MAAM,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,CAAC;AACxC;AAOO,SAAS,WAAW,UAA0B,CAAC,GAAoB;AACxE,QAAM;AAAA,IACJ,WAAW;AAAA,IACX,WAAW;AAAA,IACX,WAAW;AAAA,IACX,YAAY;AAAA,IACZ,kBAAkB;AAAA,IAClB,mBAAmB;AAAA,IACnB,kBAAkB;AAAA,EACpB,IAAI;AAEJ,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,EAAE,OAAO,GAAG,YAAY,GAAG,YAAY,EAAE,CAAC;AAC3F,QAAM,mBAAe,sBAAuB,IAAI;AAChD,QAAM,gBAAY,sBAAgG;AAAA,IAChH,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,SAAS;AAAA,EACX,CAAC;AACD,QAAM,sBAAkB;AAAA,IACtB,EAAE,UAAU,OAAO,QAAQ,GAAG,QAAQ,GAAG,YAAY,GAAG,WAAW,EAAE;AAAA,EACvE;AACA,QAAM,qBAAiB,sBAAiC,oBAAI,IAAI,CAAC;AACjE,QAAM,iBAAa,sBAAyE;AAAA,IAC1F,UAAU;AAAA,IACV,eAAe;AAAA,IACf,YAAY;AAAA,EACd,CAAC;AAED,QAAM,YAAQ;AAAA,IACZ,CAAC,UAAkB,KAAK,IAAI,UAAU,KAAK,IAAI,UAAU,KAAK,CAAC;AAAA,IAC/D,CAAC,UAAU,QAAQ;AAAA,EACrB;AAEA,QAAM,eAAW;AAAA,IACf,CAAC,UAAkB,SAAS,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,MAAM,KAAK,EAAE,EAAE;AAAA,IACxE,CAAC,KAAK;AAAA,EACR;AAEA,QAAM,aAAS,2BAAY,MAAM,SAAS,MAAM,QAAQ,QAAQ,GAAG,CAAC,UAAU,MAAM,OAAO,QAAQ,CAAC;AACpG,QAAM,cAAU,2BAAY,MAAM,SAAS,MAAM,QAAQ,QAAQ,GAAG,CAAC,UAAU,MAAM,OAAO,QAAQ,CAAC;AACrG,QAAM,gBAAY,2BAAY,MAAM,SAAS,EAAE,OAAO,GAAG,YAAY,GAAG,YAAY,EAAE,CAAC,GAAG,CAAC,CAAC;AAE5F,QAAM,cAAU;AAAA,IACd,CAAC,MAAwB;AACvB,UAAI,CAAC,gBAAiB;AACtB,UAAI,CAAC,EAAE,WAAW,CAAC,EAAE,QAAS;AAC9B,QAAE,eAAe;AACjB,YAAM,QAAQ,EAAE,SAAS,IAAI,CAAC,WAAW;AACzC,eAAS,MAAM,QAAQ,KAAK;AAAA,IAC9B;AAAA,IACA,CAAC,iBAAiB,UAAU,MAAM,OAAO,QAAQ;AAAA,EACnD;AAEA,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAA0B;AACzB,UAAI,iBAAiB;AACnB,uBAAe,QAAQ,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AACtE,YAAI,eAAe,QAAQ,SAAS,GAAG;AACrC,gBAAM,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,eAAe,QAAQ,OAAO,CAAC;AACzD,qBAAW,UAAU,EAAE,UAAU,MAAM,eAAe,gBAAgB,GAAG,CAAC,GAAG,YAAY,MAAM,MAAM;AACrG,oBAAU,QAAQ,WAAW;AAC7B,0BAAgB,QAAQ,WAAW;AACnC;AAAA,QACF;AAAA,MACF;AAEA,UAAI,WAAW;AACb,kBAAU,UAAU;AAAA,UAClB,UAAU;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,SAAS,MAAM;AAAA,UACf,SAAS,MAAM;AAAA,QACjB;AACC,QAAC,EAAE,OAAuB,kBAAkB,EAAE,SAAS;AAAA,MAC1D,WAAW,oBAAoB,aAAa,SAAS;AACnD,wBAAgB,UAAU;AAAA,UACxB,UAAU;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,QAAQ,EAAE;AAAA,UACV,YAAY,aAAa,QAAQ;AAAA,UACjC,WAAW,aAAa,QAAQ;AAAA,QAClC;AACC,QAAC,EAAE,OAAuB,kBAAkB,EAAE,SAAS;AAAA,MAC1D;AAAA,IACF;AAAA,IACA,CAAC,WAAW,kBAAkB,iBAAiB,MAAM,YAAY,MAAM,YAAY,MAAM,KAAK;AAAA,EAChG;AAEA,QAAM,oBAAgB;AAAA,IACpB,CAAC,MAA0B;AACzB,UAAI,mBAAmB,eAAe,QAAQ,IAAI,EAAE,SAAS,GAAG;AAC9D,uBAAe,QAAQ,IAAI,EAAE,WAAW,EAAE,GAAG,EAAE,SAAS,GAAG,EAAE,QAAQ,CAAC;AAAA,MACxE;AAEA,UAAI,WAAW,QAAQ,YAAY,eAAe,QAAQ,SAAS,GAAG;AACpE,cAAM,CAAC,GAAG,CAAC,IAAI,MAAM,KAAK,eAAe,QAAQ,OAAO,CAAC;AACzD,cAAM,WAAW,gBAAgB,GAAG,CAAC;AACrC,cAAM,QAAQ,YAAY,WAAW,QAAQ,iBAAiB;AAC9D,iBAAS,WAAW,QAAQ,aAAa,KAAK;AAC9C;AAAA,MACF;AAEA,UAAI,WAAW;AACb,YAAI,CAAC,UAAU,QAAQ,SAAU;AACjC,cAAM,KAAK,EAAE,UAAU,UAAU,QAAQ;AACzC,cAAM,KAAK,EAAE,UAAU,UAAU,QAAQ;AACzC,iBAAS,CAAC,UAAU;AAAA,UAClB,GAAG;AAAA,UACH,YAAY,UAAU,QAAQ,UAAU;AAAA,UACxC,YAAY,UAAU,QAAQ,UAAU;AAAA,QAC1C,EAAE;AAAA,MACJ,WAAW,kBAAkB;AAC3B,YAAI,CAAC,gBAAgB,QAAQ,YAAY,CAAC,aAAa,QAAS;AAChE,cAAM,KAAK,EAAE,UAAU,gBAAgB,QAAQ;AAC/C,cAAM,KAAK,EAAE,UAAU,gBAAgB,QAAQ;AAC/C,qBAAa,QAAQ,aAAa,gBAAgB,QAAQ,aAAa;AACvE,qBAAa,QAAQ,YAAY,gBAAgB,QAAQ,YAAY;AAAA,MACvE;AAAA,IACF;AAAA,IACA,CAAC,WAAW,kBAAkB,iBAAiB,QAAQ;AAAA,EACzD;AAEA,QAAM,kBAAc;AAAA,IAClB,CAAC,MAA0B;AACzB,qBAAe,QAAQ,OAAO,EAAE,SAAS;AACzC,UAAI,eAAe,QAAQ,OAAO,GAAG;AACnC,mBAAW,QAAQ,WAAW;AAAA,MAChC;AAEA,UAAI,WAAW;AACb,kBAAU,QAAQ,WAAW;AAC5B,QAAC,EAAE,OAAuB,sBAAsB,EAAE,SAAS;AAAA,MAC9D,WAAW,kBAAkB;AAC3B,wBAAgB,QAAQ,WAAW;AAClC,QAAC,EAAE,OAAuB,sBAAsB,EAAE,SAAS;AAAA,MAC9D;AAAA,IACF;AAAA,IACA,CAAC,WAAW,gBAAgB;AAAA,EAC9B;AAEA,SAAO;AAAA,IACL,GAAG;AAAA,IACH;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,UAAU,EAAE,SAAS,eAAe,eAAe,YAAY;AAAA,EACjE;AACF;;;ACzMA,IAAAC,gBAAkC;AA2CzB,IAAAC,sBAAA;AAjCF,SAAS,QAAQ,EAAE,KAAK,YAAY,cAAc,IAAI,GAAiB;AAC5E,QAAM,gBAAY,sBAA0B,IAAI;AAChD,QAAM,oBAAgB,sBAAsC,IAAI;AAEhE,+BAAU,MAAM;AACd,QAAI,YAAY;AAEhB,QAAI,QAAQ,UAAU,EAAE,KAAK,CAAC,SAAS;AACrC,UAAI,UAAW;AACf,YAAM,WAAW,KAAK,YAAY,EAAE,OAAO,YAAY,CAAC;AACxD,YAAM,SAAS,UAAU;AACzB,UAAI,CAAC,OAAQ;AACb,YAAM,UAAU,OAAO,WAAW,IAAI;AACtC,UAAI,CAAC,QAAS;AAEd,aAAO,QAAQ,SAAS;AACxB,aAAO,SAAS,SAAS;AACzB,aAAO,MAAM,QAAQ,GAAG,SAAS,QAAQ,WAAW;AACpD,aAAO,MAAM,SAAS,GAAG,SAAS,SAAS,WAAW;AAEtD,YAAM,aAAa,KAAK,OAAO,EAAE,eAAe,SAAS,UAAU,OAAO,CAAC;AAC3E,oBAAc,UAAU;AACxB,iBAAW,QAAQ,MAAM,MAAM;AAAA,MAE/B,CAAC;AAAA,IACH,CAAC;AAED,WAAO,MAAM;AACX,kBAAY;AACZ,oBAAc,SAAS,OAAO;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,KAAK,YAAY,WAAW,CAAC;AAEjC,SAAO,6CAAC,YAAO,KAAK,WAAW,WAAU,eAAc,oBAAkB,YAAY;AACvF;;;AC5CA,IAAAC,gBAAoC;AACpC,eAA0B;AAD1B;AAIS,6BAAoB,YAAY,IAAI,IAAI,uCAAuC,YAAY,GAAG,EAAE,SAAS;AAS3G,SAAS,eAAe,KAAmC;AAChE,QAAM,CAAC,KAAK,MAAM,QAAI,wBAAkC,IAAI;AAC5D,QAAM,CAAC,OAAO,QAAQ,QAAI,wBAAuB,IAAI;AACrD,QAAM,CAAC,SAAS,UAAU,QAAI,wBAAS,IAAI;AAE3C,+BAAU,MAAM;AACd,QAAI,YAAY;AAChB,eAAW,IAAI;AACf,aAAS,IAAI;AACb,WAAO,IAAI;AAEX,UAAM,cAA+C,qBAAY,EAAE,KAAK,IAAI,CAAC;AAC7E,gBAAY,QACT,KAAK,CAAC,QAAQ;AACb,UAAI,UAAW;AACf,aAAO,GAAG;AACV,iBAAW,KAAK;AAAA,IAClB,CAAC,EACA,MAAM,CAAC,QAAe;AACrB,UAAI,CAAC,WAAW;AACd,iBAAS,GAAG;AACZ,mBAAW,KAAK;AAAA,MAClB;AAAA,IACF,CAAC;AAEH,WAAO,MAAM;AACX,kBAAY;AACZ,kBAAY,QAAQ;AAAA,IACtB;AAAA,EACF,GAAG,CAAC,GAAG,CAAC;AAER,SAAO,EAAE,KAAK,UAAU,KAAK,YAAY,GAAG,OAAO,QAAQ;AAC7D;;;AC7CA,IAAAC,gBAAoC;AAG7B,SAAS,eAAe,cAA4C,UAA0B;AACnG,QAAM,CAAC,aAAa,cAAc,QAAI,wBAAS,CAAC;AAEhD,+BAAU,MAAM;AACd,UAAM,OAAO,aAAa;AAC1B,QAAI,CAAC,QAAQ,aAAa,EAAG;AAE7B,UAAM,WAAW,IAAI;AAAA,MACnB,CAAC,YAAY;AACX,cAAM,cAAc,QACjB,OAAO,CAAC,MAAM,EAAE,cAAc,EAC9B,KAAK,CAAC,GAAG,MAAM,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,CAAC;AAC9D,YAAI,aAAa;AACf,gBAAM,OAAO,OAAQ,YAAY,OAAuB,QAAQ,UAAU;AAC1E,cAAI,KAAM,gBAAe,IAAI;AAAA,QAC/B;AAAA,MACF;AAAA,MACA,EAAE,MAAM,WAAW,CAAC,MAAM,KAAK,IAAI,EAAE;AAAA,IACvC;AAEA,UAAM,QAAQ,KAAK,iBAAiB,oBAAoB;AACxD,UAAM,QAAQ,CAAC,OAAO,SAAS,QAAQ,EAAE,CAAC;AAE1C,WAAO,MAAM,SAAS,WAAW;AAAA,EACnC,GAAG,CAAC,cAAc,QAAQ,CAAC;AAE3B,SAAO;AACT;;;AC2FY,IAAAC,sBAAA;AAnEZ,SAAS,gBAAgB,KAAa,UAAmB;AACvD,QAAM,OAAO,SAAS,cAAc,GAAG;AACvC,OAAK,OAAO;AACZ,OAAK,WAAW,YAAY;AAC5B,OAAK,MAAM;AACX,WAAS,KAAK,YAAY,IAAI;AAC9B,OAAK,MAAM;AACX,WAAS,KAAK,YAAY,IAAI;AAChC;AAEO,SAAS,UAAU;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA,qBAAqB;AAAA,EACrB,kBAAkB;AAAA,EAClB,kBAAkB;AAAA,EAClB,mBAAmB;AAAA,EACnB,iBAAiB;AAAA,EACjB;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX,kBAAkB;AAAA,EAClB;AACF,GAAmB;AACjB,QAAM,UAAU,WAAW;AAAA,IACzB;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB;AAAA,IACA;AAAA,EACF,CAAC;AACD,QAAM,EAAE,KAAK,UAAU,OAAO,QAAQ,IAAI,eAAe,GAAG;AAC5D,QAAM,cAAc,eAAe,QAAQ,cAAc,QAAQ;AAEjE,QAAM,iBAAiB,iBAAiB,eAAe,MAAM,gBAAgB,KAAK,QAAQ,KAAK;AAE/F,QAAM,eAA8B,WAChC,EAAE,GAAG,MAAM,IACX,EAAE,SAAS,QAAQ,YAAY,UAAU,gBAAgB,UAAU,OAAO,QAAQ,QAAQ,QAAQ,GAAG,MAAM;AAE/G,SACE,6CAAC,SAAI,WAAsB,OAAO,cAChC;AAAA,IAAC;AAAA;AAAA,MACC;AAAA,MACA,YAAY;AAAA,MACZ;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA,WAAW;AAAA,MACX;AAAA,MACA,iBAAgB;AAAA,MAChB,cACE,WAAW,IACT,8CAAC,UAAK,WAAU,yBAAwB;AAAA;AAAA,QAChC;AAAA,QAAY;AAAA,QAAI;AAAA,SACxB,IACE;AAAA,MAGL;AAAA,mBAAW,6CAAC,UAAK,WAAU,iBAAgB,+BAAY;AAAA,QACvD,SAAS,8CAAC,UAAK,WAAU,iBAAgB;AAAA;AAAA,UAAqB,MAAM;AAAA,WAAQ;AAAA,QAC5E,OACC,6CAAC,SAAI,WAAU,gBACZ,gBAAM,KAAK,EAAE,QAAQ,SAAS,GAAG,CAAC,GAAG,MACpC,6CAAC,WAAoB,KAAU,YAAY,IAAI,GAAG,eAApC,IAAI,CAA0D,CAC7E,GACH;AAAA;AAAA;AAAA,EAEJ,GACF;AAEJ;","names":["import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","import_react","import_react","import_jsx_runtime"]}
|
package/dist/pdf.d.cts
CHANGED
|
@@ -25,6 +25,8 @@ interface PdfViewerProps {
|
|
|
25
25
|
enableZoomControls?: boolean;
|
|
26
26
|
/** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */
|
|
27
27
|
enableWheelZoom?: boolean;
|
|
28
|
+
/** Allow two-finger pinch to zoom on touch devices. Default: true. */
|
|
29
|
+
enablePinchZoom?: boolean;
|
|
28
30
|
/** Show the fullscreen toggle button. Default: true. */
|
|
29
31
|
enableFullscreen?: boolean;
|
|
30
32
|
/** Show the download button. Default: true. */
|
|
@@ -40,6 +42,6 @@ interface PdfViewerProps {
|
|
|
40
42
|
/** Initial position when floating. Default: centered in the viewport. */
|
|
41
43
|
defaultPosition?: Position;
|
|
42
44
|
}
|
|
43
|
-
declare function PdfViewer({ uri, fileName, className, style, width, height, minScale, maxScale, zoomStep, renderScale, enableZoomControls, enableWheelZoom, enableFullscreen, enableDownload, onDownload, theme, floating, windowDraggable, defaultPosition, }: PdfViewerProps): react.JSX.Element;
|
|
45
|
+
declare function PdfViewer({ uri, fileName, className, style, width, height, minScale, maxScale, zoomStep, renderScale, enableZoomControls, enableWheelZoom, enablePinchZoom, enableFullscreen, enableDownload, onDownload, theme, floating, windowDraggable, defaultPosition, }: PdfViewerProps): react.JSX.Element;
|
|
44
46
|
|
|
45
47
|
export { PdfViewer, type PdfViewerProps };
|
package/dist/pdf.d.ts
CHANGED
|
@@ -25,6 +25,8 @@ interface PdfViewerProps {
|
|
|
25
25
|
enableZoomControls?: boolean;
|
|
26
26
|
/** Allow Ctrl/Cmd + scroll wheel to zoom. Default: true. */
|
|
27
27
|
enableWheelZoom?: boolean;
|
|
28
|
+
/** Allow two-finger pinch to zoom on touch devices. Default: true. */
|
|
29
|
+
enablePinchZoom?: boolean;
|
|
28
30
|
/** Show the fullscreen toggle button. Default: true. */
|
|
29
31
|
enableFullscreen?: boolean;
|
|
30
32
|
/** Show the download button. Default: true. */
|
|
@@ -40,6 +42,6 @@ interface PdfViewerProps {
|
|
|
40
42
|
/** Initial position when floating. Default: centered in the viewport. */
|
|
41
43
|
defaultPosition?: Position;
|
|
42
44
|
}
|
|
43
|
-
declare function PdfViewer({ uri, fileName, className, style, width, height, minScale, maxScale, zoomStep, renderScale, enableZoomControls, enableWheelZoom, enableFullscreen, enableDownload, onDownload, theme, floating, windowDraggable, defaultPosition, }: PdfViewerProps): react.JSX.Element;
|
|
45
|
+
declare function PdfViewer({ uri, fileName, className, style, width, height, minScale, maxScale, zoomStep, renderScale, enableZoomControls, enableWheelZoom, enablePinchZoom, enableFullscreen, enableDownload, onDownload, theme, floating, windowDraggable, defaultPosition, }: PdfViewerProps): react.JSX.Element;
|
|
44
46
|
|
|
45
47
|
export { PdfViewer, type PdfViewerProps };
|
package/dist/pdf.js
CHANGED
package/dist/styles.css
CHANGED
|
@@ -180,6 +180,16 @@
|
|
|
180
180
|
.vd-xlsx-tab:hover {
|
|
181
181
|
background: var(--vd-toolbar-btn-hover-bg);
|
|
182
182
|
}
|
|
183
|
+
.vd-xlsx-truncated-notice {
|
|
184
|
+
margin-bottom: 8px;
|
|
185
|
+
padding: 8px 12px;
|
|
186
|
+
background: var(--vd-toolbar-bg);
|
|
187
|
+
border: 1px solid var(--vd-toolbar-border-color);
|
|
188
|
+
border-radius: var(--vd-toolbar-btn-radius);
|
|
189
|
+
color: var(--vd-text-color);
|
|
190
|
+
font-size: 12px;
|
|
191
|
+
max-width: 100%;
|
|
192
|
+
}
|
|
183
193
|
.vd-xlsx-tab--active {
|
|
184
194
|
background: var(--vd-toolbar-btn-hover-bg);
|
|
185
195
|
border-color: var(--vd-text-color);
|
package/dist/styles.css.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/styles.css"],"sourcesContent":[".vd-shell {\n --vd-bg: #262626;\n --vd-toolbar-bg: #1f1f1f;\n --vd-toolbar-border-color: #3a3a3a;\n --vd-toolbar-btn-hover-bg: #3a3a3a;\n --vd-text-color: #e5e5e5;\n --vd-border-radius: 8px;\n --vd-toolbar-btn-radius: 6px;\n\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--vd-bg);\n border-radius: var(--vd-border-radius);\n overflow: hidden;\n}\n\n.vd-shell--floating {\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);\n z-index: 1000;\n}\n\n.vd-toolbar {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 10px;\n background: var(--vd-toolbar-bg);\n border-bottom: 1px solid var(--vd-toolbar-border-color);\n}\n\n.vd-toolbar-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n background: transparent;\n border: none;\n border-radius: var(--vd-toolbar-btn-radius);\n color: var(--vd-text-color);\n font-size: 16px;\n cursor: pointer;\n}\n\n.vd-toolbar-btn svg {\n display: block;\n}\n\n.vd-toolbar-drag-handle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 32px;\n color: var(--vd-text-color);\n opacity: 0.6;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n\n.vd-toolbar-drag-handle:active {\n cursor: grabbing;\n}\n\n.vd-toolbar-btn:hover {\n background: var(--vd-toolbar-btn-hover-bg);\n}\n\n.vd-toolbar-scale {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 48px;\n height: 32px;\n color: var(--vd-text-color);\n font-size: 13px;\n}\n\n.vd-toolbar-spacer {\n flex: 1;\n}\n\n.vd-canvas {\n position: relative;\n flex: 1;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n touch-action: none;\n}\n\n.vd-canvas.vd-canvas--no-pan {\n overflow: auto;\n align-items: flex-start;\n}\n\n.vd-canvas:active {\n cursor: grabbing;\n}\n\n.vd-canvas-content {\n transform-origin: center center;\n transition: transform 0.05s ease-out;\n}\n\n.vd-image {\n max-width: none;\n max-height: 80vh;\n user-select: none;\n pointer-events: none;\n}\n\n.vd-pdf-pages {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 12px 0;\n}\n\n.vd-pdf-page {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n.vd-pdf-page-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n height: 32px;\n color: var(--vd-text-color);\n font-size: 13px;\n white-space: nowrap;\n}\n\n.vd-doc-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n max-width: 100%;\n padding: 24px;\n color: var(--vd-text-color);\n font-size: 14px;\n text-align: center;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.vd-docx-page {\n background: #ffffff;\n color: #1a1a1a;\n width: 816px;\n max-width: 90vw;\n margin: 24px auto;\n padding: 64px 72px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n font-family: 'Calibri', 'Segoe UI', sans-serif;\n line-height: 1.5;\n}\n\n.vd-docx-page img {\n max-width: 100%;\n}\n\n.vd-docx-page table {\n border-collapse: collapse;\n}\n\n.vd-docx-page table td,\n.vd-docx-page table th {\n border: 1px solid #ccc;\n padding: 4px 8px;\n}\n\n.vd-xlsx {\n padding: 12px;\n}\n\n.vd-xlsx-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n flex-wrap: wrap;\n}\n\n.vd-xlsx-tab {\n padding: 6px 12px;\n background: var(--vd-toolbar-bg);\n border: 1px solid var(--vd-toolbar-border-color);\n border-radius: var(--vd-toolbar-btn-radius);\n color: var(--vd-text-color);\n font-size: 13px;\n cursor: pointer;\n}\n\n.vd-xlsx-tab:hover {\n background: var(--vd-toolbar-btn-hover-bg);\n}\n\n.vd-xlsx-tab--active {\n background: var(--vd-toolbar-btn-hover-bg);\n border-color: var(--vd-text-color);\n}\n\n.vd-xlsx-table {\n background: #ffffff;\n display: inline-block;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n.vd-xlsx-table table {\n border-collapse: collapse;\n color: #1a1a1a;\n font-size: 13px;\n}\n\n.vd-xlsx-table table td,\n.vd-xlsx-table table th {\n border: 1px solid #d0d0d0;\n padding: 4px 8px;\n white-space: nowrap;\n}\n\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/styles.css"],"sourcesContent":[".vd-shell {\n --vd-bg: #262626;\n --vd-toolbar-bg: #1f1f1f;\n --vd-toolbar-border-color: #3a3a3a;\n --vd-toolbar-btn-hover-bg: #3a3a3a;\n --vd-text-color: #e5e5e5;\n --vd-border-radius: 8px;\n --vd-toolbar-btn-radius: 6px;\n\n display: flex;\n flex-direction: column;\n width: 100%;\n height: 100%;\n background: var(--vd-bg);\n border-radius: var(--vd-border-radius);\n overflow: hidden;\n}\n\n.vd-shell--floating {\n box-shadow: 0 12px 32px rgba(0, 0, 0, 0.4);\n z-index: 1000;\n}\n\n.vd-toolbar {\n display: flex;\n align-items: center;\n gap: 4px;\n padding: 6px 10px;\n background: var(--vd-toolbar-bg);\n border-bottom: 1px solid var(--vd-toolbar-border-color);\n}\n\n.vd-toolbar-btn {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 32px;\n height: 32px;\n padding: 0 8px;\n background: transparent;\n border: none;\n border-radius: var(--vd-toolbar-btn-radius);\n color: var(--vd-text-color);\n font-size: 16px;\n cursor: pointer;\n}\n\n.vd-toolbar-btn svg {\n display: block;\n}\n\n.vd-toolbar-drag-handle {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 24px;\n height: 32px;\n color: var(--vd-text-color);\n opacity: 0.6;\n cursor: grab;\n touch-action: none;\n user-select: none;\n}\n\n.vd-toolbar-drag-handle:active {\n cursor: grabbing;\n}\n\n.vd-toolbar-btn:hover {\n background: var(--vd-toolbar-btn-hover-bg);\n}\n\n.vd-toolbar-scale {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n min-width: 48px;\n height: 32px;\n color: var(--vd-text-color);\n font-size: 13px;\n}\n\n.vd-toolbar-spacer {\n flex: 1;\n}\n\n.vd-canvas {\n position: relative;\n flex: 1;\n overflow: hidden;\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: grab;\n touch-action: none;\n}\n\n.vd-canvas.vd-canvas--no-pan {\n overflow: auto;\n align-items: flex-start;\n}\n\n.vd-canvas:active {\n cursor: grabbing;\n}\n\n.vd-canvas-content {\n transform-origin: center center;\n transition: transform 0.05s ease-out;\n}\n\n.vd-image {\n max-width: none;\n max-height: 80vh;\n user-select: none;\n pointer-events: none;\n}\n\n.vd-pdf-pages {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 12px;\n padding: 12px 0;\n}\n\n.vd-pdf-page {\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n.vd-pdf-page-indicator {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n padding: 0 8px;\n height: 32px;\n color: var(--vd-text-color);\n font-size: 13px;\n white-space: nowrap;\n}\n\n.vd-doc-status {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n max-width: 100%;\n padding: 24px;\n color: var(--vd-text-color);\n font-size: 14px;\n text-align: center;\n white-space: normal;\n overflow-wrap: break-word;\n word-break: break-word;\n}\n\n.vd-docx-page {\n background: #ffffff;\n color: #1a1a1a;\n width: 816px;\n max-width: 90vw;\n margin: 24px auto;\n padding: 64px 72px;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n font-family: 'Calibri', 'Segoe UI', sans-serif;\n line-height: 1.5;\n}\n\n.vd-docx-page img {\n max-width: 100%;\n}\n\n.vd-docx-page table {\n border-collapse: collapse;\n}\n\n.vd-docx-page table td,\n.vd-docx-page table th {\n border: 1px solid #ccc;\n padding: 4px 8px;\n}\n\n.vd-xlsx {\n padding: 12px;\n}\n\n.vd-xlsx-tabs {\n display: flex;\n gap: 4px;\n margin-bottom: 8px;\n flex-wrap: wrap;\n}\n\n.vd-xlsx-tab {\n padding: 6px 12px;\n background: var(--vd-toolbar-bg);\n border: 1px solid var(--vd-toolbar-border-color);\n border-radius: var(--vd-toolbar-btn-radius);\n color: var(--vd-text-color);\n font-size: 13px;\n cursor: pointer;\n}\n\n.vd-xlsx-tab:hover {\n background: var(--vd-toolbar-btn-hover-bg);\n}\n\n.vd-xlsx-truncated-notice {\n margin-bottom: 8px;\n padding: 8px 12px;\n background: var(--vd-toolbar-bg);\n border: 1px solid var(--vd-toolbar-border-color);\n border-radius: var(--vd-toolbar-btn-radius);\n color: var(--vd-text-color);\n font-size: 12px;\n max-width: 100%;\n}\n\n.vd-xlsx-tab--active {\n background: var(--vd-toolbar-btn-hover-bg);\n border-color: var(--vd-text-color);\n}\n\n.vd-xlsx-table {\n background: #ffffff;\n display: inline-block;\n box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);\n}\n\n.vd-xlsx-table table {\n border-collapse: collapse;\n color: #1a1a1a;\n font-size: 13px;\n}\n\n.vd-xlsx-table table td,\n.vd-xlsx-table table th {\n border: 1px solid #d0d0d0;\n padding: 4px 8px;\n white-space: nowrap;\n}\n\n"],"mappings":"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","names":[]}
|
package/dist/xlsx.cjs
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
'use client'
|
|
1
2
|
"use strict";
|
|
2
3
|
var __create = Object.create;
|
|
3
4
|
var __defProp = Object.defineProperty;
|
|
@@ -284,9 +285,10 @@ function ViewerShell({
|
|
|
284
285
|
document.addEventListener("fullscreenchange", onChange);
|
|
285
286
|
return () => document.removeEventListener("fullscreenchange", onChange);
|
|
286
287
|
}, []);
|
|
288
|
+
const fullscreenSupported = typeof document !== "undefined" && typeof document.fullscreenEnabled === "boolean" ? document.fullscreenEnabled : false;
|
|
287
289
|
const onFullscreen = (0, import_react2.useCallback)(() => {
|
|
288
290
|
const el = rootRef.current;
|
|
289
|
-
if (!el) return;
|
|
291
|
+
if (!el || typeof el.requestFullscreen !== "function") return;
|
|
290
292
|
if (document.fullscreenElement) {
|
|
291
293
|
document.exitFullscreen();
|
|
292
294
|
} else {
|
|
@@ -312,7 +314,7 @@ function ViewerShell({
|
|
|
312
314
|
onZoomIn: zoomPan.zoomIn,
|
|
313
315
|
onZoomOut: zoomPan.zoomOut,
|
|
314
316
|
onReset: zoomPan.resetZoom,
|
|
315
|
-
onFullscreen: enableFullscreen ? onFullscreen : void 0,
|
|
317
|
+
onFullscreen: enableFullscreen && fullscreenSupported ? onFullscreen : void 0,
|
|
316
318
|
onDownload,
|
|
317
319
|
isFullscreen,
|
|
318
320
|
showZoomControls: enableZoomControls,
|
|
@@ -348,11 +350,20 @@ function ViewerShell({
|
|
|
348
350
|
);
|
|
349
351
|
}
|
|
350
352
|
|
|
353
|
+
// src/core/sanitizeHtml.ts
|
|
354
|
+
var import_dompurify = __toESM(require("dompurify"), 1);
|
|
355
|
+
function sanitizeUntrustedHtml(html) {
|
|
356
|
+
return import_dompurify.default.sanitize(html);
|
|
357
|
+
}
|
|
358
|
+
|
|
351
359
|
// src/core/useZoomPan.ts
|
|
352
360
|
var import_react3 = require("react");
|
|
353
361
|
var DEFAULT_MIN = 0.1;
|
|
354
362
|
var DEFAULT_MAX = 8;
|
|
355
363
|
var DEFAULT_STEP = 0.25;
|
|
364
|
+
function pointerDistance(a, b) {
|
|
365
|
+
return Math.hypot(a.x - b.x, a.y - b.y);
|
|
366
|
+
}
|
|
356
367
|
function useZoomPan(options = {}) {
|
|
357
368
|
const {
|
|
358
369
|
minScale = DEFAULT_MIN,
|
|
@@ -360,7 +371,8 @@ function useZoomPan(options = {}) {
|
|
|
360
371
|
zoomStep = DEFAULT_STEP,
|
|
361
372
|
enablePan = true,
|
|
362
373
|
enableWheelZoom = true,
|
|
363
|
-
enableDragScroll = false
|
|
374
|
+
enableDragScroll = false,
|
|
375
|
+
enablePinchZoom = true
|
|
364
376
|
} = options;
|
|
365
377
|
const [state, setState] = (0, import_react3.useState)({ scale: 1, translateX: 0, translateY: 0 });
|
|
366
378
|
const containerRef = (0, import_react3.useRef)(null);
|
|
@@ -374,6 +386,12 @@ function useZoomPan(options = {}) {
|
|
|
374
386
|
const scrollDragState = (0, import_react3.useRef)(
|
|
375
387
|
{ dragging: false, startX: 0, startY: 0, originLeft: 0, originTop: 0 }
|
|
376
388
|
);
|
|
389
|
+
const activePointers = (0, import_react3.useRef)(/* @__PURE__ */ new Map());
|
|
390
|
+
const pinchState = (0, import_react3.useRef)({
|
|
391
|
+
pinching: false,
|
|
392
|
+
startDistance: 0,
|
|
393
|
+
startScale: 1
|
|
394
|
+
});
|
|
377
395
|
const clamp = (0, import_react3.useCallback)(
|
|
378
396
|
(value) => Math.min(maxScale, Math.max(minScale, value)),
|
|
379
397
|
[minScale, maxScale]
|
|
@@ -397,6 +415,16 @@ function useZoomPan(options = {}) {
|
|
|
397
415
|
);
|
|
398
416
|
const onPointerDown = (0, import_react3.useCallback)(
|
|
399
417
|
(e) => {
|
|
418
|
+
if (enablePinchZoom) {
|
|
419
|
+
activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
420
|
+
if (activePointers.current.size === 2) {
|
|
421
|
+
const [a, b] = Array.from(activePointers.current.values());
|
|
422
|
+
pinchState.current = { pinching: true, startDistance: pointerDistance(a, b), startScale: state.scale };
|
|
423
|
+
dragState.current.dragging = false;
|
|
424
|
+
scrollDragState.current.dragging = false;
|
|
425
|
+
return;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
400
428
|
if (enablePan) {
|
|
401
429
|
dragState.current = {
|
|
402
430
|
dragging: true,
|
|
@@ -417,10 +445,20 @@ function useZoomPan(options = {}) {
|
|
|
417
445
|
e.target.setPointerCapture(e.pointerId);
|
|
418
446
|
}
|
|
419
447
|
},
|
|
420
|
-
[enablePan, enableDragScroll, state.translateX, state.translateY]
|
|
448
|
+
[enablePan, enableDragScroll, enablePinchZoom, state.translateX, state.translateY, state.scale]
|
|
421
449
|
);
|
|
422
450
|
const onPointerMove = (0, import_react3.useCallback)(
|
|
423
451
|
(e) => {
|
|
452
|
+
if (enablePinchZoom && activePointers.current.has(e.pointerId)) {
|
|
453
|
+
activePointers.current.set(e.pointerId, { x: e.clientX, y: e.clientY });
|
|
454
|
+
}
|
|
455
|
+
if (pinchState.current.pinching && activePointers.current.size === 2) {
|
|
456
|
+
const [a, b] = Array.from(activePointers.current.values());
|
|
457
|
+
const distance = pointerDistance(a, b);
|
|
458
|
+
const ratio = distance / (pinchState.current.startDistance || distance);
|
|
459
|
+
setScale(pinchState.current.startScale * ratio);
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
424
462
|
if (enablePan) {
|
|
425
463
|
if (!dragState.current.dragging) return;
|
|
426
464
|
const dx = e.clientX - dragState.current.startX;
|
|
@@ -438,10 +476,14 @@ function useZoomPan(options = {}) {
|
|
|
438
476
|
containerRef.current.scrollTop = scrollDragState.current.originTop - dy;
|
|
439
477
|
}
|
|
440
478
|
},
|
|
441
|
-
[enablePan, enableDragScroll]
|
|
479
|
+
[enablePan, enableDragScroll, enablePinchZoom, setScale]
|
|
442
480
|
);
|
|
443
481
|
const onPointerUp = (0, import_react3.useCallback)(
|
|
444
482
|
(e) => {
|
|
483
|
+
activePointers.current.delete(e.pointerId);
|
|
484
|
+
if (activePointers.current.size < 2) {
|
|
485
|
+
pinchState.current.pinching = false;
|
|
486
|
+
}
|
|
445
487
|
if (enablePan) {
|
|
446
488
|
dragState.current.dragging = false;
|
|
447
489
|
e.target.releasePointerCapture(e.pointerId);
|
|
@@ -519,13 +561,15 @@ function XlsxViewer({
|
|
|
519
561
|
zoomStep,
|
|
520
562
|
enableZoomControls = true,
|
|
521
563
|
enableWheelZoom = true,
|
|
564
|
+
enablePinchZoom = true,
|
|
522
565
|
enableFullscreen = true,
|
|
523
566
|
enableDownload = true,
|
|
524
567
|
onDownload,
|
|
525
568
|
theme,
|
|
526
569
|
floating = true,
|
|
527
570
|
windowDraggable = true,
|
|
528
|
-
defaultPosition
|
|
571
|
+
defaultPosition,
|
|
572
|
+
maxRows = 2e3
|
|
529
573
|
}) {
|
|
530
574
|
const zoomPan = useZoomPan({
|
|
531
575
|
minScale,
|
|
@@ -533,18 +577,32 @@ function XlsxViewer({
|
|
|
533
577
|
zoomStep,
|
|
534
578
|
enablePan: false,
|
|
535
579
|
enableDragScroll: true,
|
|
536
|
-
enableWheelZoom
|
|
580
|
+
enableWheelZoom,
|
|
581
|
+
enablePinchZoom
|
|
537
582
|
});
|
|
538
583
|
const { workbook, error, loading } = useXlsxWorkbook(uri);
|
|
539
584
|
const [activeSheet, setActiveSheet] = (0, import_react5.useState)(0);
|
|
540
585
|
const handleDownload = enableDownload ? onDownload ?? (() => defaultDownload(uri, fileName)) : void 0;
|
|
541
|
-
const tableHtml = (0, import_react5.useMemo)(() => {
|
|
542
|
-
if (!workbook) return null;
|
|
586
|
+
const { tableHtml, truncatedRowCount, totalRowCount } = (0, import_react5.useMemo)(() => {
|
|
587
|
+
if (!workbook) return { tableHtml: null, truncatedRowCount: null, totalRowCount: 0 };
|
|
543
588
|
const sheetName = workbook.SheetNames[activeSheet];
|
|
544
589
|
const sheet = workbook.Sheets[sheetName];
|
|
545
|
-
if (!sheet) return null;
|
|
546
|
-
|
|
547
|
-
|
|
590
|
+
if (!sheet || !sheet["!ref"]) return { tableHtml: null, truncatedRowCount: null, totalRowCount: 0 };
|
|
591
|
+
const range = XLSX2.utils.decode_range(sheet["!ref"]);
|
|
592
|
+
const totalRows = range.e.r - range.s.r + 1;
|
|
593
|
+
let sheetToRender = sheet;
|
|
594
|
+
let truncated = null;
|
|
595
|
+
if (totalRows > maxRows) {
|
|
596
|
+
truncated = maxRows;
|
|
597
|
+
const clampedRange = { s: range.s, e: { r: range.s.r + maxRows - 1, c: range.e.c } };
|
|
598
|
+
sheetToRender = { ...sheet, "!ref": XLSX2.utils.encode_range(clampedRange) };
|
|
599
|
+
}
|
|
600
|
+
return {
|
|
601
|
+
tableHtml: sanitizeUntrustedHtml(XLSX2.utils.sheet_to_html(sheetToRender, { editable: false })),
|
|
602
|
+
truncatedRowCount: truncated,
|
|
603
|
+
totalRowCount: totalRows
|
|
604
|
+
};
|
|
605
|
+
}, [workbook, activeSheet, maxRows]);
|
|
548
606
|
const wrapperStyle = floating ? { ...style } : { display: "flex", alignItems: "center", justifyContent: "center", width: "100%", height: "100%", ...style };
|
|
549
607
|
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className, style: wrapperStyle, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
550
608
|
ViewerShell,
|
|
@@ -578,6 +636,13 @@ function XlsxViewer({
|
|
|
578
636
|
},
|
|
579
637
|
name
|
|
580
638
|
)) }),
|
|
639
|
+
truncatedRowCount != null && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "vd-xlsx-truncated-notice", children: [
|
|
640
|
+
"Showing the first ",
|
|
641
|
+
truncatedRowCount.toLocaleString(),
|
|
642
|
+
" of ",
|
|
643
|
+
totalRowCount.toLocaleString(),
|
|
644
|
+
" rows. Download the file to see the rest."
|
|
645
|
+
] }),
|
|
581
646
|
tableHtml && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "vd-xlsx-table", dangerouslySetInnerHTML: { __html: tableHtml } })
|
|
582
647
|
] })
|
|
583
648
|
]
|