@algenium/blocks 1.7.0-rc.2 → 1.7.0-rc.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +742 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +82 -2
- package/dist/index.d.ts +82 -2
- package/dist/index.js +742 -2
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
package/dist/index.cjs
CHANGED
|
@@ -8131,6 +8131,746 @@ function USAddressInput({
|
|
|
8131
8131
|
] })
|
|
8132
8132
|
] });
|
|
8133
8133
|
}
|
|
8134
|
+
function defaultPageOf(page, total) {
|
|
8135
|
+
return `${page} / ${total}`;
|
|
8136
|
+
}
|
|
8137
|
+
var DEFAULT_WORKER_MSG = "PdfViewer requires a non-empty workerSrc pointing at pdf.worker matching your project's pdfjs-dist version. Example: `new URL('pdfjs-dist/build/pdf.worker.min.mjs', import.meta.url)`.";
|
|
8138
|
+
function buildGetDocumentArgs(src, documentOptions) {
|
|
8139
|
+
const rest = documentOptions ?? {};
|
|
8140
|
+
if (typeof src === "string") {
|
|
8141
|
+
return { url: src, ...rest };
|
|
8142
|
+
}
|
|
8143
|
+
return { data: src, ...rest };
|
|
8144
|
+
}
|
|
8145
|
+
function PdfPageCanvas({
|
|
8146
|
+
page,
|
|
8147
|
+
layout,
|
|
8148
|
+
scale,
|
|
8149
|
+
visible,
|
|
8150
|
+
pageClassName
|
|
8151
|
+
}) {
|
|
8152
|
+
const canvasRef = React2.useRef(null);
|
|
8153
|
+
const taskRef = React2.useRef(null);
|
|
8154
|
+
React2.useEffect(() => {
|
|
8155
|
+
if (!visible || !canvasRef.current) {
|
|
8156
|
+
taskRef.current?.cancel();
|
|
8157
|
+
taskRef.current = null;
|
|
8158
|
+
const c = canvasRef.current;
|
|
8159
|
+
if (c) {
|
|
8160
|
+
const ctx2 = c.getContext("2d");
|
|
8161
|
+
if (ctx2) {
|
|
8162
|
+
ctx2.setTransform(1, 0, 0, 1, 0, 0);
|
|
8163
|
+
ctx2.clearRect(0, 0, c.width, c.height);
|
|
8164
|
+
}
|
|
8165
|
+
}
|
|
8166
|
+
return;
|
|
8167
|
+
}
|
|
8168
|
+
const canvas = canvasRef.current;
|
|
8169
|
+
const ctx = canvas.getContext("2d");
|
|
8170
|
+
if (!ctx) return;
|
|
8171
|
+
const viewport = page.getViewport({ scale });
|
|
8172
|
+
canvas.width = viewport.width;
|
|
8173
|
+
canvas.height = viewport.height;
|
|
8174
|
+
const task = page.render({
|
|
8175
|
+
canvasContext: ctx,
|
|
8176
|
+
viewport,
|
|
8177
|
+
canvas
|
|
8178
|
+
});
|
|
8179
|
+
taskRef.current = task;
|
|
8180
|
+
task.promise.catch(() => {
|
|
8181
|
+
});
|
|
8182
|
+
return () => {
|
|
8183
|
+
task.cancel();
|
|
8184
|
+
if (taskRef.current === task) {
|
|
8185
|
+
taskRef.current = null;
|
|
8186
|
+
}
|
|
8187
|
+
};
|
|
8188
|
+
}, [page, visible, scale]);
|
|
8189
|
+
const w = layout.widthPt * scale;
|
|
8190
|
+
const h = layout.heightPt * scale;
|
|
8191
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8192
|
+
"div",
|
|
8193
|
+
{
|
|
8194
|
+
className: cn("relative flex justify-center bg-muted/40", pageClassName),
|
|
8195
|
+
style: { width: w, height: h },
|
|
8196
|
+
"data-page": layout.pageNumber,
|
|
8197
|
+
children: visible ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8198
|
+
"canvas",
|
|
8199
|
+
{
|
|
8200
|
+
ref: canvasRef,
|
|
8201
|
+
className: "block max-h-full shadow-sm",
|
|
8202
|
+
"aria-hidden": "true"
|
|
8203
|
+
}
|
|
8204
|
+
) : null
|
|
8205
|
+
}
|
|
8206
|
+
);
|
|
8207
|
+
}
|
|
8208
|
+
var PAGE_INPUT_CLASS = "h-8 w-14 rounded-md border px-2 text-sm tabular-nums shadow-sm border-neutral-300 bg-white text-neutral-950 caret-neutral-950 selection:bg-neutral-200 selection:text-neutral-950 dark:border-neutral-600 dark:bg-neutral-950 dark:text-neutral-50 dark:caret-neutral-50 dark:selection:bg-neutral-700 dark:selection:text-neutral-50";
|
|
8209
|
+
function touchPairDistance(touches) {
|
|
8210
|
+
if (touches.length < 2) return 0;
|
|
8211
|
+
const a = touches.item(0);
|
|
8212
|
+
const b = touches.item(1);
|
|
8213
|
+
return Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY);
|
|
8214
|
+
}
|
|
8215
|
+
function PdfThumbnailStrip({
|
|
8216
|
+
page,
|
|
8217
|
+
pageNumber,
|
|
8218
|
+
active,
|
|
8219
|
+
onPick,
|
|
8220
|
+
label
|
|
8221
|
+
}) {
|
|
8222
|
+
const canvasRef = React2.useRef(null);
|
|
8223
|
+
React2.useEffect(() => {
|
|
8224
|
+
const canvas = canvasRef.current;
|
|
8225
|
+
if (!canvas) return;
|
|
8226
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
8227
|
+
const thumbMax = 112;
|
|
8228
|
+
const s = thumbMax / Math.max(viewport.width, viewport.height);
|
|
8229
|
+
const vp = page.getViewport({ scale: s });
|
|
8230
|
+
const ctx = canvas.getContext("2d");
|
|
8231
|
+
if (!ctx) return;
|
|
8232
|
+
canvas.width = vp.width;
|
|
8233
|
+
canvas.height = vp.height;
|
|
8234
|
+
const task = page.render({
|
|
8235
|
+
canvasContext: ctx,
|
|
8236
|
+
viewport: vp,
|
|
8237
|
+
canvas
|
|
8238
|
+
});
|
|
8239
|
+
task.promise.catch(() => {
|
|
8240
|
+
});
|
|
8241
|
+
return () => {
|
|
8242
|
+
task.cancel();
|
|
8243
|
+
};
|
|
8244
|
+
}, [page]);
|
|
8245
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8246
|
+
"button",
|
|
8247
|
+
{
|
|
8248
|
+
type: "button",
|
|
8249
|
+
onClick: () => onPick(pageNumber),
|
|
8250
|
+
className: cn(
|
|
8251
|
+
"flex w-full flex-col items-center gap-1 rounded-md p-1 transition-colors hover:bg-muted/80",
|
|
8252
|
+
active ? "bg-muted ring-2 ring-ring" : ""
|
|
8253
|
+
),
|
|
8254
|
+
"aria-label": label,
|
|
8255
|
+
"aria-current": active ? "page" : void 0,
|
|
8256
|
+
children: [
|
|
8257
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8258
|
+
"canvas",
|
|
8259
|
+
{
|
|
8260
|
+
ref: canvasRef,
|
|
8261
|
+
className: "block max-w-full rounded-sm shadow-sm",
|
|
8262
|
+
"aria-hidden": true
|
|
8263
|
+
}
|
|
8264
|
+
),
|
|
8265
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-[10px] tabular-nums", children: pageNumber })
|
|
8266
|
+
]
|
|
8267
|
+
}
|
|
8268
|
+
);
|
|
8269
|
+
}
|
|
8270
|
+
function PdfViewer({
|
|
8271
|
+
src,
|
|
8272
|
+
workerSrc,
|
|
8273
|
+
documentOptions,
|
|
8274
|
+
initialPage = 1,
|
|
8275
|
+
initialScale = 1,
|
|
8276
|
+
minScale = 0.5,
|
|
8277
|
+
maxScale = 4,
|
|
8278
|
+
scaleStep = 0.2,
|
|
8279
|
+
enableKeyboardShortcuts = true,
|
|
8280
|
+
enablePinchZoom = true,
|
|
8281
|
+
enableThumbnailSidebar = true,
|
|
8282
|
+
thumbnailSidebarDefaultOpen = true,
|
|
8283
|
+
labels,
|
|
8284
|
+
onLoad,
|
|
8285
|
+
onError,
|
|
8286
|
+
onPageChange,
|
|
8287
|
+
onScaleChange,
|
|
8288
|
+
className,
|
|
8289
|
+
toolbarClassName,
|
|
8290
|
+
pageClassName,
|
|
8291
|
+
toolbarEndSlot
|
|
8292
|
+
}) {
|
|
8293
|
+
const mergedLabels = labels ?? {};
|
|
8294
|
+
const toolbarLabel = mergedLabels.toolbar ?? "PDF controls";
|
|
8295
|
+
const loadingLabel = mergedLabels.loading ?? "Loading PDF\u2026";
|
|
8296
|
+
const workerErrorMessage = mergedLabels.workerMissing ?? DEFAULT_WORKER_MSG;
|
|
8297
|
+
const errorLabelFallback = mergedLabels.error ?? "Failed to load PDF";
|
|
8298
|
+
const toolbarId = React2.useId();
|
|
8299
|
+
const pageInputId = `${toolbarId}-page`;
|
|
8300
|
+
const scrollRef = React2.useRef(null);
|
|
8301
|
+
const observerRef = React2.useRef(null);
|
|
8302
|
+
const lastReportedPage = React2.useRef(0);
|
|
8303
|
+
const loadedPdfRef = React2.useRef(null);
|
|
8304
|
+
const [loadError, setLoadError] = React2.useState(null);
|
|
8305
|
+
const [busy, setBusy] = React2.useState(false);
|
|
8306
|
+
const [layouts, setLayouts] = React2.useState([]);
|
|
8307
|
+
const [pagesMap, setPagesMap] = React2.useState(
|
|
8308
|
+
null
|
|
8309
|
+
);
|
|
8310
|
+
const [scale, setScale] = React2.useState(initialScale);
|
|
8311
|
+
const [ratios, setRatios] = React2.useState({});
|
|
8312
|
+
const [pageInput, setPageInput] = React2.useState(String(initialPage));
|
|
8313
|
+
const [thumbnailSidebarOpen, setThumbnailSidebarOpen] = React2.useState(
|
|
8314
|
+
thumbnailSidebarDefaultOpen
|
|
8315
|
+
);
|
|
8316
|
+
const baselineScaleRef = React2.useRef(initialScale);
|
|
8317
|
+
React2.useEffect(() => {
|
|
8318
|
+
baselineScaleRef.current = initialScale;
|
|
8319
|
+
}, [initialScale]);
|
|
8320
|
+
const pageOfFormatter = mergedLabels.pageOf ?? defaultPageOf;
|
|
8321
|
+
const resolvedGoToLabel = mergedLabels.goToPage ?? "Go to page";
|
|
8322
|
+
const zoomInLabel = mergedLabels.zoomIn ?? "Zoom in";
|
|
8323
|
+
const zoomOutLabel = mergedLabels.zoomOut ?? "Zoom out";
|
|
8324
|
+
const resetZoomLabel = mergedLabels.resetZoom ?? "Reset zoom";
|
|
8325
|
+
const fitWidthLabel = mergedLabels.fitToWidth ?? "Fit to width";
|
|
8326
|
+
const thumbnailSidebarLabel = mergedLabels.thumbnailSidebar ?? "Page thumbnails";
|
|
8327
|
+
const toggleThumbLabel = mergedLabels.toggleThumbnailSidebar ?? "Toggle page thumbnails";
|
|
8328
|
+
const pageThumbLabel = mergedLabels.pageThumbnail ?? ((n) => `Page ${n}, show in document`);
|
|
8329
|
+
const pageCount = layouts.length;
|
|
8330
|
+
const currentVisiblePage = React2.useMemo(() => {
|
|
8331
|
+
let bestPage = 1;
|
|
8332
|
+
let bestRatio = -1;
|
|
8333
|
+
for (const layout of layouts) {
|
|
8334
|
+
const r2 = ratios[layout.pageNumber] ?? 0;
|
|
8335
|
+
if (r2 > bestRatio) {
|
|
8336
|
+
bestRatio = r2;
|
|
8337
|
+
bestPage = layout.pageNumber;
|
|
8338
|
+
}
|
|
8339
|
+
}
|
|
8340
|
+
return bestRatio >= 0.01 ? bestPage : 1;
|
|
8341
|
+
}, [layouts, ratios]);
|
|
8342
|
+
const clampScaleValue = React2.useCallback(
|
|
8343
|
+
(v) => Math.min(maxScale, Math.max(minScale, v)),
|
|
8344
|
+
[minScale, maxScale]
|
|
8345
|
+
);
|
|
8346
|
+
const zoomInAct = React2.useCallback(() => {
|
|
8347
|
+
setScale((prev) => {
|
|
8348
|
+
const c = clampScaleValue(prev + scaleStep);
|
|
8349
|
+
onScaleChange?.(c);
|
|
8350
|
+
return c;
|
|
8351
|
+
});
|
|
8352
|
+
}, [clampScaleValue, onScaleChange, scaleStep]);
|
|
8353
|
+
const zoomOutAct = React2.useCallback(() => {
|
|
8354
|
+
setScale((prev) => {
|
|
8355
|
+
const c = clampScaleValue(prev - scaleStep);
|
|
8356
|
+
onScaleChange?.(c);
|
|
8357
|
+
return c;
|
|
8358
|
+
});
|
|
8359
|
+
}, [clampScaleValue, onScaleChange, scaleStep]);
|
|
8360
|
+
const resetZoomAct = React2.useCallback(() => {
|
|
8361
|
+
const c = clampScaleValue(baselineScaleRef.current);
|
|
8362
|
+
setScale(c);
|
|
8363
|
+
onScaleChange?.(c);
|
|
8364
|
+
}, [clampScaleValue, onScaleChange]);
|
|
8365
|
+
const fitToWidthAct = React2.useCallback(() => {
|
|
8366
|
+
const root = scrollRef.current;
|
|
8367
|
+
if (!root || layouts.length === 0) return;
|
|
8368
|
+
const avail = Math.max(root.clientWidth - 32, 120);
|
|
8369
|
+
const maxW = Math.max(...layouts.map((l) => l.widthPt), 1);
|
|
8370
|
+
const next = clampScaleValue(avail / maxW);
|
|
8371
|
+
setScale(next);
|
|
8372
|
+
onScaleChange?.(next);
|
|
8373
|
+
}, [clampScaleValue, layouts, onScaleChange]);
|
|
8374
|
+
React2.useEffect(() => {
|
|
8375
|
+
setPageInput(String(currentVisiblePage));
|
|
8376
|
+
if (lastReportedPage.current !== currentVisiblePage) {
|
|
8377
|
+
lastReportedPage.current = currentVisiblePage;
|
|
8378
|
+
onPageChange?.(currentVisiblePage);
|
|
8379
|
+
}
|
|
8380
|
+
}, [currentVisiblePage, onPageChange]);
|
|
8381
|
+
const scrollToPage = React2.useCallback((pageNum) => {
|
|
8382
|
+
const root = scrollRef.current;
|
|
8383
|
+
if (!root || pageNum < 1) return;
|
|
8384
|
+
const el = root.querySelector(`[data-page="${pageNum}"]`);
|
|
8385
|
+
if (el instanceof HTMLElement) {
|
|
8386
|
+
el.scrollIntoView({ behavior: "smooth", block: "start" });
|
|
8387
|
+
}
|
|
8388
|
+
}, []);
|
|
8389
|
+
React2.useEffect(() => {
|
|
8390
|
+
if (!busy && pagesMap && pageCount > 0) {
|
|
8391
|
+
const p = Math.min(Math.max(1, initialPage), pageCount);
|
|
8392
|
+
requestAnimationFrame(() => scrollToPage(p));
|
|
8393
|
+
}
|
|
8394
|
+
}, [busy, pagesMap, pageCount, initialPage, scrollToPage]);
|
|
8395
|
+
const loadKey = React2.useMemo(() => {
|
|
8396
|
+
if (typeof src === "string") return src;
|
|
8397
|
+
if (src instanceof ArrayBuffer) return `ab:${src.byteLength}`;
|
|
8398
|
+
return `ua:${src.byteLength}:${src.byteOffset}:${src.buffer.byteLength}`;
|
|
8399
|
+
}, [src]);
|
|
8400
|
+
React2.useEffect(() => {
|
|
8401
|
+
let cancelled = false;
|
|
8402
|
+
let activeDoc = null;
|
|
8403
|
+
setLoadError(null);
|
|
8404
|
+
if (loadedPdfRef.current) {
|
|
8405
|
+
void loadedPdfRef.current.destroy();
|
|
8406
|
+
loadedPdfRef.current = null;
|
|
8407
|
+
}
|
|
8408
|
+
setLayouts([]);
|
|
8409
|
+
setPagesMap(null);
|
|
8410
|
+
setRatios({});
|
|
8411
|
+
const trimmedWorker = workerSrc?.trim?.() ?? "";
|
|
8412
|
+
if (!trimmedWorker) {
|
|
8413
|
+
setLoadError(workerErrorMessage);
|
|
8414
|
+
onError?.(new Error(workerErrorMessage));
|
|
8415
|
+
return () => {
|
|
8416
|
+
cancelled = true;
|
|
8417
|
+
};
|
|
8418
|
+
}
|
|
8419
|
+
void (async () => {
|
|
8420
|
+
try {
|
|
8421
|
+
setBusy(true);
|
|
8422
|
+
const pdfjs = await import('pdfjs-dist');
|
|
8423
|
+
if (cancelled) return;
|
|
8424
|
+
pdfjs.GlobalWorkerOptions.workerSrc = trimmedWorker;
|
|
8425
|
+
const loadingTask = pdfjs.getDocument(
|
|
8426
|
+
buildGetDocumentArgs(src, documentOptions)
|
|
8427
|
+
);
|
|
8428
|
+
activeDoc = await loadingTask.promise;
|
|
8429
|
+
if (cancelled) {
|
|
8430
|
+
void activeDoc.destroy();
|
|
8431
|
+
activeDoc = null;
|
|
8432
|
+
return;
|
|
8433
|
+
}
|
|
8434
|
+
const layoutsLocal = [];
|
|
8435
|
+
const mapLocal = /* @__PURE__ */ new Map();
|
|
8436
|
+
for (let p = 1; p <= activeDoc.numPages; p++) {
|
|
8437
|
+
const page = await activeDoc.getPage(p);
|
|
8438
|
+
mapLocal.set(p, page);
|
|
8439
|
+
const viewport = page.getViewport({ scale: 1 });
|
|
8440
|
+
layoutsLocal.push({
|
|
8441
|
+
pageNumber: p,
|
|
8442
|
+
widthPt: viewport.width,
|
|
8443
|
+
heightPt: viewport.height
|
|
8444
|
+
});
|
|
8445
|
+
}
|
|
8446
|
+
if (cancelled) {
|
|
8447
|
+
void activeDoc.destroy();
|
|
8448
|
+
activeDoc = null;
|
|
8449
|
+
return;
|
|
8450
|
+
}
|
|
8451
|
+
onLoad?.(activeDoc);
|
|
8452
|
+
loadedPdfRef.current = activeDoc;
|
|
8453
|
+
setLayouts(layoutsLocal);
|
|
8454
|
+
setPagesMap(mapLocal);
|
|
8455
|
+
activeDoc = null;
|
|
8456
|
+
} catch (e) {
|
|
8457
|
+
const err = e instanceof Error ? e : new Error(String(e));
|
|
8458
|
+
if (!cancelled) {
|
|
8459
|
+
setLoadError(errorLabelFallback);
|
|
8460
|
+
onError?.(err);
|
|
8461
|
+
}
|
|
8462
|
+
if (activeDoc) {
|
|
8463
|
+
void activeDoc.destroy();
|
|
8464
|
+
activeDoc = null;
|
|
8465
|
+
}
|
|
8466
|
+
} finally {
|
|
8467
|
+
if (!cancelled) setBusy(false);
|
|
8468
|
+
}
|
|
8469
|
+
})();
|
|
8470
|
+
return () => {
|
|
8471
|
+
cancelled = true;
|
|
8472
|
+
if (observerRef.current) {
|
|
8473
|
+
observerRef.current.disconnect();
|
|
8474
|
+
observerRef.current = null;
|
|
8475
|
+
}
|
|
8476
|
+
if (activeDoc) {
|
|
8477
|
+
void activeDoc.destroy();
|
|
8478
|
+
}
|
|
8479
|
+
if (loadedPdfRef.current) {
|
|
8480
|
+
void loadedPdfRef.current.destroy();
|
|
8481
|
+
loadedPdfRef.current = null;
|
|
8482
|
+
}
|
|
8483
|
+
};
|
|
8484
|
+
}, [workerSrc, loadKey, documentOptions]);
|
|
8485
|
+
React2.useEffect(() => {
|
|
8486
|
+
setScale(clampScaleValue(initialScale));
|
|
8487
|
+
}, [initialScale, clampScaleValue]);
|
|
8488
|
+
React2.useEffect(() => {
|
|
8489
|
+
const el = scrollRef.current;
|
|
8490
|
+
if (!el || !enablePinchZoom) return;
|
|
8491
|
+
let pinchDist = 0;
|
|
8492
|
+
const onWheel = (e) => {
|
|
8493
|
+
if (!e.ctrlKey) return;
|
|
8494
|
+
e.preventDefault();
|
|
8495
|
+
const delta = -e.deltaY;
|
|
8496
|
+
const factor = Math.exp(delta * 2e-3);
|
|
8497
|
+
setScale((prev) => {
|
|
8498
|
+
const c = clampScaleValue(prev * factor);
|
|
8499
|
+
onScaleChange?.(c);
|
|
8500
|
+
return c;
|
|
8501
|
+
});
|
|
8502
|
+
};
|
|
8503
|
+
const onTouchStart = (e) => {
|
|
8504
|
+
if (e.touches.length === 2) {
|
|
8505
|
+
pinchDist = touchPairDistance(e.touches);
|
|
8506
|
+
}
|
|
8507
|
+
};
|
|
8508
|
+
const onTouchMove = (e) => {
|
|
8509
|
+
if (e.touches.length !== 2 || pinchDist <= 0) return;
|
|
8510
|
+
e.preventDefault();
|
|
8511
|
+
const d = touchPairDistance(e.touches);
|
|
8512
|
+
const ratio = d / pinchDist;
|
|
8513
|
+
pinchDist = d;
|
|
8514
|
+
setScale((prev) => {
|
|
8515
|
+
const c = clampScaleValue(prev * ratio);
|
|
8516
|
+
onScaleChange?.(c);
|
|
8517
|
+
return c;
|
|
8518
|
+
});
|
|
8519
|
+
};
|
|
8520
|
+
const endPinch = (e) => {
|
|
8521
|
+
if (e.touches.length < 2) pinchDist = 0;
|
|
8522
|
+
};
|
|
8523
|
+
el.addEventListener("wheel", onWheel, { passive: false });
|
|
8524
|
+
el.addEventListener("touchstart", onTouchStart, { passive: true });
|
|
8525
|
+
el.addEventListener("touchmove", onTouchMove, { passive: false });
|
|
8526
|
+
el.addEventListener("touchend", endPinch);
|
|
8527
|
+
el.addEventListener("touchcancel", endPinch);
|
|
8528
|
+
return () => {
|
|
8529
|
+
el.removeEventListener("wheel", onWheel);
|
|
8530
|
+
el.removeEventListener("touchstart", onTouchStart);
|
|
8531
|
+
el.removeEventListener("touchmove", onTouchMove);
|
|
8532
|
+
el.removeEventListener("touchend", endPinch);
|
|
8533
|
+
el.removeEventListener("touchcancel", endPinch);
|
|
8534
|
+
};
|
|
8535
|
+
}, [enablePinchZoom, clampScaleValue, onScaleChange]);
|
|
8536
|
+
React2.useEffect(() => {
|
|
8537
|
+
if (layouts.length === 0) return;
|
|
8538
|
+
const frame = requestAnimationFrame(() => {
|
|
8539
|
+
const root = scrollRef.current;
|
|
8540
|
+
if (!root) return;
|
|
8541
|
+
if (observerRef.current) {
|
|
8542
|
+
observerRef.current.disconnect();
|
|
8543
|
+
}
|
|
8544
|
+
const io = new IntersectionObserver(
|
|
8545
|
+
(entries) => {
|
|
8546
|
+
setRatios((prev) => {
|
|
8547
|
+
const next = { ...prev };
|
|
8548
|
+
for (const e of entries) {
|
|
8549
|
+
const tgt = e.target;
|
|
8550
|
+
const p = Number(tgt.dataset.page);
|
|
8551
|
+
if (Number.isFinite(p)) next[p] = e.intersectionRatio;
|
|
8552
|
+
}
|
|
8553
|
+
return next;
|
|
8554
|
+
});
|
|
8555
|
+
},
|
|
8556
|
+
{
|
|
8557
|
+
root,
|
|
8558
|
+
rootMargin: "200px 0px",
|
|
8559
|
+
threshold: [0, 0.05, 0.25, 0.5, 0.75, 1]
|
|
8560
|
+
}
|
|
8561
|
+
);
|
|
8562
|
+
observerRef.current = io;
|
|
8563
|
+
root.querySelectorAll("[data-page]").forEach((el) => io.observe(el));
|
|
8564
|
+
});
|
|
8565
|
+
return () => {
|
|
8566
|
+
cancelAnimationFrame(frame);
|
|
8567
|
+
if (observerRef.current) {
|
|
8568
|
+
observerRef.current.disconnect();
|
|
8569
|
+
observerRef.current = null;
|
|
8570
|
+
}
|
|
8571
|
+
};
|
|
8572
|
+
}, [layouts]);
|
|
8573
|
+
const handleSubmitPage = React2.useCallback(() => {
|
|
8574
|
+
const n = Number.parseInt(pageInput, 10);
|
|
8575
|
+
if (!Number.isFinite(n) || pageCount === 0) return;
|
|
8576
|
+
const clamped = Math.min(Math.max(1, n), pageCount);
|
|
8577
|
+
scrollToPage(clamped);
|
|
8578
|
+
setPageInput(String(clamped));
|
|
8579
|
+
}, [pageInput, pageCount, scrollToPage]);
|
|
8580
|
+
const handleKeyDown = React2.useCallback(
|
|
8581
|
+
(e) => {
|
|
8582
|
+
if (!enableKeyboardShortcuts) return;
|
|
8583
|
+
if (e.target !== e.currentTarget && e.target instanceof HTMLInputElement) {
|
|
8584
|
+
return;
|
|
8585
|
+
}
|
|
8586
|
+
let handled = false;
|
|
8587
|
+
switch (e.key) {
|
|
8588
|
+
case "PageDown": {
|
|
8589
|
+
scrollToPage(Math.min(pageCount || 1, currentVisiblePage + 1));
|
|
8590
|
+
handled = true;
|
|
8591
|
+
break;
|
|
8592
|
+
}
|
|
8593
|
+
case "PageUp": {
|
|
8594
|
+
scrollToPage(Math.max(1, currentVisiblePage - 1));
|
|
8595
|
+
handled = true;
|
|
8596
|
+
break;
|
|
8597
|
+
}
|
|
8598
|
+
case "Home": {
|
|
8599
|
+
scrollToPage(1);
|
|
8600
|
+
handled = true;
|
|
8601
|
+
break;
|
|
8602
|
+
}
|
|
8603
|
+
case "End": {
|
|
8604
|
+
if (pageCount) scrollToPage(pageCount);
|
|
8605
|
+
handled = true;
|
|
8606
|
+
break;
|
|
8607
|
+
}
|
|
8608
|
+
case "+":
|
|
8609
|
+
case "=": {
|
|
8610
|
+
zoomInAct();
|
|
8611
|
+
handled = true;
|
|
8612
|
+
break;
|
|
8613
|
+
}
|
|
8614
|
+
case "-":
|
|
8615
|
+
case "_": {
|
|
8616
|
+
zoomOutAct();
|
|
8617
|
+
handled = true;
|
|
8618
|
+
break;
|
|
8619
|
+
}
|
|
8620
|
+
case "0": {
|
|
8621
|
+
resetZoomAct();
|
|
8622
|
+
handled = true;
|
|
8623
|
+
break;
|
|
8624
|
+
}
|
|
8625
|
+
}
|
|
8626
|
+
if (handled) {
|
|
8627
|
+
e.preventDefault();
|
|
8628
|
+
e.stopPropagation();
|
|
8629
|
+
}
|
|
8630
|
+
},
|
|
8631
|
+
[
|
|
8632
|
+
enableKeyboardShortcuts,
|
|
8633
|
+
pageCount,
|
|
8634
|
+
currentVisiblePage,
|
|
8635
|
+
scrollToPage,
|
|
8636
|
+
zoomInAct,
|
|
8637
|
+
zoomOutAct,
|
|
8638
|
+
resetZoomAct
|
|
8639
|
+
]
|
|
8640
|
+
);
|
|
8641
|
+
if (loadError) {
|
|
8642
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
8643
|
+
"div",
|
|
8644
|
+
{
|
|
8645
|
+
className: cn("rounded-md border border-destructive/50 p-4", className),
|
|
8646
|
+
role: "alert",
|
|
8647
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-destructive text-sm", children: loadError })
|
|
8648
|
+
}
|
|
8649
|
+
);
|
|
8650
|
+
}
|
|
8651
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
8652
|
+
"div",
|
|
8653
|
+
{
|
|
8654
|
+
className: cn(
|
|
8655
|
+
"flex min-h-0 flex-col overflow-hidden rounded-md border",
|
|
8656
|
+
className
|
|
8657
|
+
),
|
|
8658
|
+
children: [
|
|
8659
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8660
|
+
"div",
|
|
8661
|
+
{
|
|
8662
|
+
id: toolbarId,
|
|
8663
|
+
role: "toolbar",
|
|
8664
|
+
"aria-label": toolbarLabel,
|
|
8665
|
+
className: cn(
|
|
8666
|
+
"sticky top-0 z-10 flex shrink-0 flex-wrap items-center gap-2 border-b bg-background/95 px-2 py-2 backdrop-blur supports-[backdrop-filter]:bg-background/80",
|
|
8667
|
+
toolbarClassName
|
|
8668
|
+
),
|
|
8669
|
+
children: [
|
|
8670
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-muted-foreground text-xs tabular-nums sm:text-sm", children: busy || pagesMap === null ? "\u2014" : pageOfFormatter(currentVisiblePage, pageCount) }),
|
|
8671
|
+
/* @__PURE__ */ jsxRuntime.jsx("label", { htmlFor: pageInputId, className: "sr-only", children: resolvedGoToLabel }),
|
|
8672
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8673
|
+
"input",
|
|
8674
|
+
{
|
|
8675
|
+
id: pageInputId,
|
|
8676
|
+
type: "number",
|
|
8677
|
+
min: 1,
|
|
8678
|
+
max: Math.max(pageCount, 1),
|
|
8679
|
+
disabled: busy || pageCount === 0,
|
|
8680
|
+
className: PAGE_INPUT_CLASS,
|
|
8681
|
+
"aria-label": resolvedGoToLabel,
|
|
8682
|
+
value: pageInput,
|
|
8683
|
+
onChange: (ev) => setPageInput(ev.target.value),
|
|
8684
|
+
onKeyDown: (ev) => {
|
|
8685
|
+
if (ev.key === "Enter") {
|
|
8686
|
+
ev.preventDefault();
|
|
8687
|
+
handleSubmitPage();
|
|
8688
|
+
}
|
|
8689
|
+
}
|
|
8690
|
+
}
|
|
8691
|
+
),
|
|
8692
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8693
|
+
Button,
|
|
8694
|
+
{
|
|
8695
|
+
type: "button",
|
|
8696
|
+
variant: "outline",
|
|
8697
|
+
size: "icon-sm",
|
|
8698
|
+
onClick: zoomOutAct,
|
|
8699
|
+
disabled: busy || scale <= minScale,
|
|
8700
|
+
"aria-label": zoomOutLabel,
|
|
8701
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomOut, { "aria-hidden": true })
|
|
8702
|
+
}
|
|
8703
|
+
),
|
|
8704
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8705
|
+
Button,
|
|
8706
|
+
{
|
|
8707
|
+
type: "button",
|
|
8708
|
+
variant: "outline",
|
|
8709
|
+
size: "icon-sm",
|
|
8710
|
+
onClick: zoomInAct,
|
|
8711
|
+
disabled: busy || scale >= maxScale,
|
|
8712
|
+
"aria-label": zoomInLabel,
|
|
8713
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { "aria-hidden": true })
|
|
8714
|
+
}
|
|
8715
|
+
),
|
|
8716
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8717
|
+
Button,
|
|
8718
|
+
{
|
|
8719
|
+
type: "button",
|
|
8720
|
+
variant: "outline",
|
|
8721
|
+
size: "icon-sm",
|
|
8722
|
+
onClick: resetZoomAct,
|
|
8723
|
+
disabled: busy,
|
|
8724
|
+
"aria-label": resetZoomLabel,
|
|
8725
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RotateCcw, { "aria-hidden": true })
|
|
8726
|
+
}
|
|
8727
|
+
),
|
|
8728
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8729
|
+
Button,
|
|
8730
|
+
{
|
|
8731
|
+
type: "button",
|
|
8732
|
+
variant: "outline",
|
|
8733
|
+
size: "icon-sm",
|
|
8734
|
+
onClick: fitToWidthAct,
|
|
8735
|
+
disabled: busy || pageCount === 0,
|
|
8736
|
+
"aria-label": fitWidthLabel,
|
|
8737
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { "aria-hidden": true })
|
|
8738
|
+
}
|
|
8739
|
+
),
|
|
8740
|
+
toolbarEndSlot
|
|
8741
|
+
]
|
|
8742
|
+
}
|
|
8743
|
+
),
|
|
8744
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 flex-1 overflow-hidden", children: [
|
|
8745
|
+
enableThumbnailSidebar && !busy && pagesMap !== null && pageCount > 0 && thumbnailSidebarOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8746
|
+
"nav",
|
|
8747
|
+
{
|
|
8748
|
+
className: "bg-muted/30 flex w-[132px] shrink-0 flex-col overflow-y-auto border-r py-2 pl-2 pr-1",
|
|
8749
|
+
"aria-label": thumbnailSidebarLabel,
|
|
8750
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-1", children: layouts.map((layout) => {
|
|
8751
|
+
const pg = pagesMap.get(layout.pageNumber);
|
|
8752
|
+
return pg ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8753
|
+
PdfThumbnailStrip,
|
|
8754
|
+
{
|
|
8755
|
+
page: pg,
|
|
8756
|
+
pageNumber: layout.pageNumber,
|
|
8757
|
+
active: layout.pageNumber === currentVisiblePage,
|
|
8758
|
+
onPick: scrollToPage,
|
|
8759
|
+
label: pageThumbLabel(layout.pageNumber)
|
|
8760
|
+
},
|
|
8761
|
+
`thumb-${layout.pageNumber}`
|
|
8762
|
+
) : null;
|
|
8763
|
+
}) })
|
|
8764
|
+
}
|
|
8765
|
+
) : null,
|
|
8766
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex min-h-0 min-w-0 flex-1", children: [
|
|
8767
|
+
enableThumbnailSidebar && !busy && pagesMap !== null && pageCount > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8768
|
+
"button",
|
|
8769
|
+
{
|
|
8770
|
+
type: "button",
|
|
8771
|
+
className: "text-muted-foreground hover:bg-muted/60 flex w-9 shrink-0 flex-col items-center justify-center border-r bg-transparent transition-colors",
|
|
8772
|
+
onClick: () => setThumbnailSidebarOpen((v) => !v),
|
|
8773
|
+
"aria-label": toggleThumbLabel,
|
|
8774
|
+
"aria-expanded": thumbnailSidebarOpen,
|
|
8775
|
+
children: thumbnailSidebarOpen ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4", "aria-hidden": true }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4", "aria-hidden": true })
|
|
8776
|
+
}
|
|
8777
|
+
) : null,
|
|
8778
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8779
|
+
"div",
|
|
8780
|
+
{
|
|
8781
|
+
ref: scrollRef,
|
|
8782
|
+
tabIndex: 0,
|
|
8783
|
+
onKeyDown: handleKeyDown,
|
|
8784
|
+
className: "relative min-h-[240px] min-w-0 flex-1 overflow-auto outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
8785
|
+
"aria-busy": busy,
|
|
8786
|
+
"aria-label": busy ? loadingLabel : "PDF pages",
|
|
8787
|
+
children: busy || pagesMap === null ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-muted-foreground p-6 text-sm", children: loadingLabel }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col items-center gap-4 pb-8 pt-2", children: layouts.map((layout) => {
|
|
8788
|
+
const pg = pagesMap.get(layout.pageNumber);
|
|
8789
|
+
const visible = (ratios[layout.pageNumber] ?? 0) >= 1e-3;
|
|
8790
|
+
return pg ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
8791
|
+
PdfPageCanvas,
|
|
8792
|
+
{
|
|
8793
|
+
page: pg,
|
|
8794
|
+
layout,
|
|
8795
|
+
scale,
|
|
8796
|
+
visible,
|
|
8797
|
+
pageClassName
|
|
8798
|
+
},
|
|
8799
|
+
layout.pageNumber
|
|
8800
|
+
) : null;
|
|
8801
|
+
}) })
|
|
8802
|
+
}
|
|
8803
|
+
)
|
|
8804
|
+
] })
|
|
8805
|
+
] })
|
|
8806
|
+
]
|
|
8807
|
+
}
|
|
8808
|
+
);
|
|
8809
|
+
}
|
|
8810
|
+
var fullscreenDialogContentClass = "!max-w-none !w-screen !h-screen !p-0 !border-0 !bg-black/95 !rounded-none !top-0 !left-0 !translate-x-0 !translate-y-0 !gap-0 !shadow-none !flex !flex-col data-[state=open]:!zoom-in-100 data-[state=closed]:!zoom-out-100";
|
|
8811
|
+
function PdfViewerDialog({
|
|
8812
|
+
open,
|
|
8813
|
+
onOpenChange,
|
|
8814
|
+
src,
|
|
8815
|
+
workerSrc,
|
|
8816
|
+
documentOptions,
|
|
8817
|
+
trigger,
|
|
8818
|
+
title,
|
|
8819
|
+
labels,
|
|
8820
|
+
forwardedProps
|
|
8821
|
+
}) {
|
|
8822
|
+
const closeLabel = labels?.close ?? "Close";
|
|
8823
|
+
const dialogTitle = labels?.dialogTitle ?? title ?? "PDF document";
|
|
8824
|
+
const dialogDescription = labels?.dialogDescription ?? "Document viewer with zoom and page navigation.";
|
|
8825
|
+
const {
|
|
8826
|
+
className: forwardedClassName,
|
|
8827
|
+
toolbarClassName: forwardedToolbarClassName,
|
|
8828
|
+
...restForwarded
|
|
8829
|
+
} = forwardedProps ?? {};
|
|
8830
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(Dialog, { open, onOpenChange, children: [
|
|
8831
|
+
trigger ? /* @__PURE__ */ jsxRuntime.jsx(DialogTrigger, { asChild: true, children: trigger }) : null,
|
|
8832
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
8833
|
+
DialogContent,
|
|
8834
|
+
{
|
|
8835
|
+
className: fullscreenDialogContentClass,
|
|
8836
|
+
showCloseButton: false,
|
|
8837
|
+
children: [
|
|
8838
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogTitle, { className: "sr-only", children: dialogTitle }),
|
|
8839
|
+
/* @__PURE__ */ jsxRuntime.jsx(DialogDescription, { className: "sr-only", children: dialogDescription }),
|
|
8840
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
8841
|
+
PdfViewer,
|
|
8842
|
+
{
|
|
8843
|
+
...restForwarded,
|
|
8844
|
+
src,
|
|
8845
|
+
workerSrc,
|
|
8846
|
+
documentOptions,
|
|
8847
|
+
className: cn(
|
|
8848
|
+
"min-h-0 flex-1 rounded-none border-0 bg-transparent text-white",
|
|
8849
|
+
forwardedClassName
|
|
8850
|
+
),
|
|
8851
|
+
toolbarClassName: cn(
|
|
8852
|
+
"border-white/10 bg-black/80 text-white backdrop-blur",
|
|
8853
|
+
forwardedToolbarClassName
|
|
8854
|
+
),
|
|
8855
|
+
toolbarEndSlot: /* @__PURE__ */ jsxRuntime.jsx(
|
|
8856
|
+
Button,
|
|
8857
|
+
{
|
|
8858
|
+
type: "button",
|
|
8859
|
+
variant: "ghost",
|
|
8860
|
+
size: "icon-sm",
|
|
8861
|
+
className: "ml-auto text-white hover:bg-white/10 hover:text-white",
|
|
8862
|
+
onClick: () => onOpenChange(false),
|
|
8863
|
+
"aria-label": closeLabel,
|
|
8864
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-5", "aria-hidden": true })
|
|
8865
|
+
}
|
|
8866
|
+
)
|
|
8867
|
+
}
|
|
8868
|
+
)
|
|
8869
|
+
]
|
|
8870
|
+
}
|
|
8871
|
+
)
|
|
8872
|
+
] });
|
|
8873
|
+
}
|
|
8134
8874
|
|
|
8135
8875
|
exports.AvatarEditor = AvatarEditor;
|
|
8136
8876
|
exports.AvatarEditorDialog = AvatarEditorDialog;
|
|
@@ -8192,6 +8932,8 @@ exports.LanguageSwitcher = LanguageSwitcher;
|
|
|
8192
8932
|
exports.MiniCalendar = MiniCalendar;
|
|
8193
8933
|
exports.NotificationsContext = NotificationsContext;
|
|
8194
8934
|
exports.NotificationsWidget = NotificationsWidget;
|
|
8935
|
+
exports.PdfViewer = PdfViewer;
|
|
8936
|
+
exports.PdfViewerDialog = PdfViewerDialog;
|
|
8195
8937
|
exports.Popover = Popover;
|
|
8196
8938
|
exports.PopoverAnchor = PopoverAnchor;
|
|
8197
8939
|
exports.PopoverContent = PopoverContent;
|