@cherrystudio/file-preview 0.1.3 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +48 -5
- package/dist/{Combination-BLg27FvF.js → Combination-i8Z9CJHc.js} +2 -1
- package/dist/{FilePreviewTooLarge-DkHa6toZ.js → FilePreviewTooLarge-DC7vPyMI.js} +1 -1
- package/dist/{useTranslation-DMhY277o.js → FilePreviewToolbarButton-ptqwCTnz.js} +11 -3634
- package/dist/{ImageFilePreview-Be0jdBJ-.js → ImageFilePreview-C_P1iIEi.js} +27 -11
- package/dist/{PdfFilePreview-D3Ie0_mm.js → PdfFilePreview-CbrMcPzo.js} +132 -25
- package/dist/{PowerPointFilePreview-CyQHTp4B.js → PowerPointFilePreview-9E6kUy_A.js} +55 -21
- package/dist/RtfFilePreview-Bgl6lmWy.js +21434 -0
- package/dist/{SpreadsheetFilePreview-DJdoyeis.js → SpreadsheetFilePreview-PWFG3UY3.js} +61 -32
- package/dist/{WordFilePreview-Tvm-vK91.js → WordFilePreview-hfALJk2N.js} +26 -23
- package/dist/circle-alert-sByhBDN4.js +31 -0
- package/dist/{imageFilePreviewPlugin-CYLM2bwR.js → imageFilePreviewPlugin-D6hV1Hm1.js} +1 -1
- package/dist/react.js +55 -24
- package/dist/{rotate-ccw-YWx7RzY9.js → rotate-ccw-Bx-jjhVm.js} +1 -1
- package/dist/{selection-CQPD5a6C.js → selection-B0INvh6t.js} +1 -31
- package/dist/styles.css +44 -1
- package/dist/useTranslation-BJY4EKsz.js +3631 -0
- package/dist/{zoom-out-DLOQGt1e.js → zoom-out-B2XJ64Kx.js} +1 -1
- package/package.json +2 -1
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { r as readPreviewDocument, t as PreviewError } from "./source-Rx3etU3y.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-
|
|
4
|
-
import {
|
|
5
|
-
import { t as
|
|
6
|
-
import { t as
|
|
2
|
+
import { _ as cva, a as usePreviewHost, b as useComposedRefs, d as EmptyState, g as createLucideIcon, m as LoaderCircle, p as cn, r as FilePreviewLayout, s as FilePreviewToolbar, t as useTranslation, v as createSlot } from "./useTranslation-BJY4EKsz.js";
|
|
3
|
+
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-B2XJ64Kx.js";
|
|
4
|
+
import { S as composeEventHandlers, a as usePortalContainer, b as dispatchDiscreteCustomEvent, c as Portal$1, d as Content, f as Root2$1, g as DismissableLayer, h as useLayoutEffect2, l as Anchor, m as useId$1, o as useControllableState, p as createPopperScope, s as Presence, t as FilePreviewToolbarButton, u as Arrow, v as useCallbackRef, x as createContextScope, y as Primitive } from "./FilePreviewToolbarButton-ptqwCTnz.js";
|
|
5
|
+
import { i as useFocusGuards, n as hideOthers, r as FocusScope, t as ReactRemoveScroll } from "./Combination-i8Z9CJHc.js";
|
|
6
|
+
import { t as imageFilePreviewPlugin } from "./imageFilePreviewPlugin-D6hV1Hm1.js";
|
|
7
|
+
import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DC7vPyMI.js";
|
|
7
8
|
import * as React$1 from "react";
|
|
8
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
9
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
/**
|
|
11
12
|
* @license lucide-react v0.545.0 - ISC
|
|
@@ -2077,11 +2078,20 @@ var IMAGE_MEDIA_TYPE_BY_EXTENSION = {
|
|
|
2077
2078
|
};
|
|
2078
2079
|
function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
2079
2080
|
const { t } = useTranslation();
|
|
2080
|
-
const { failDocument } = usePreviewHost();
|
|
2081
|
+
const { failDocument, isCurrentDocument } = usePreviewHost();
|
|
2081
2082
|
const [url, setUrl] = useState(null);
|
|
2082
2083
|
const objectUrlRef = useRef(null);
|
|
2083
2084
|
const [status, setStatus] = useState("loading");
|
|
2084
2085
|
const transformControls = useImagePreviewTransform();
|
|
2086
|
+
const [loadedDocument, setLoadedDocument] = useState(document);
|
|
2087
|
+
const [pendingTransform, setPendingTransform] = useState(transformControls.transform);
|
|
2088
|
+
if (loadedDocument !== document) {
|
|
2089
|
+
setLoadedDocument(document);
|
|
2090
|
+
setStatus("loading");
|
|
2091
|
+
}
|
|
2092
|
+
useLayoutEffect(() => {
|
|
2093
|
+
if (status === "ready") setPendingTransform(transformControls.transform);
|
|
2094
|
+
}, [status, transformControls.transform]);
|
|
2085
2095
|
const releaseImageUrl = useCallback(() => {
|
|
2086
2096
|
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
2087
2097
|
objectUrlRef.current = null;
|
|
@@ -2102,14 +2112,14 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2102
2112
|
setStatus("loading");
|
|
2103
2113
|
setUrl(null);
|
|
2104
2114
|
readPreviewDocument(document, IMAGE_PREVIEW_MAX_SIZE_BYTES, controller.signal).then((bytes) => {
|
|
2105
|
-
if (controller.signal.aborted) return;
|
|
2115
|
+
if (controller.signal.aborted || isCurrentDocument?.() === false) return;
|
|
2106
2116
|
const extension = fileName.split(".").at(-1)?.toLowerCase();
|
|
2107
2117
|
const normalizedMediaType = mediaType?.split(";", 1)[0].trim().toLowerCase();
|
|
2108
2118
|
const mime = normalizedMediaType && imageFilePreviewPlugin.mediaTypes.includes(normalizedMediaType) ? normalizedMediaType : IMAGE_MEDIA_TYPE_BY_EXTENSION[extension ?? ""] ?? `image/${extension}`;
|
|
2109
2119
|
objectUrlRef.current = URL.createObjectURL(new Blob([bytes], { type: mime }));
|
|
2110
2120
|
setUrl(objectUrlRef.current);
|
|
2111
2121
|
}).catch((error) => {
|
|
2112
|
-
if (controller.signal.aborted) return;
|
|
2122
|
+
if (controller.signal.aborted || isCurrentDocument?.() === false) return;
|
|
2113
2123
|
failDocument?.(error);
|
|
2114
2124
|
setStatus(error instanceof PreviewError && error.code === "too_large" ? "too_large" : "error");
|
|
2115
2125
|
});
|
|
@@ -2122,7 +2132,8 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2122
2132
|
fileName,
|
|
2123
2133
|
mediaType,
|
|
2124
2134
|
failDocument,
|
|
2125
|
-
releaseImageUrl
|
|
2135
|
+
releaseImageUrl,
|
|
2136
|
+
isCurrentDocument
|
|
2126
2137
|
]);
|
|
2127
2138
|
if (status === "too_large") return /* @__PURE__ */ jsx(FilePreviewLayout.Frame, { children: /* @__PURE__ */ jsx(FilePreviewLayout.Content, { children: /* @__PURE__ */ jsx(FilePreviewTooLarge, {
|
|
2128
2139
|
sizeBytes: document.size,
|
|
@@ -2155,8 +2166,13 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2155
2166
|
imageClassName: status === "loading" ? "opacity-0" : void 0,
|
|
2156
2167
|
item,
|
|
2157
2168
|
transformControls,
|
|
2158
|
-
onLoad: () =>
|
|
2169
|
+
onLoad: () => {
|
|
2170
|
+
if (isCurrentDocument?.() === false) return;
|
|
2171
|
+
transformControls.update(pendingTransform);
|
|
2172
|
+
setStatus("ready");
|
|
2173
|
+
},
|
|
2159
2174
|
onError: () => {
|
|
2175
|
+
if (isCurrentDocument?.() === false) return;
|
|
2160
2176
|
const error = /* @__PURE__ */ new Error(`Failed to load image preview: ${sourceId}`);
|
|
2161
2177
|
failDocument?.(error);
|
|
2162
2178
|
releaseImageUrl();
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { i as readPreviewRange, n as assertPreviewRange, t as PreviewError } from "./source-Rx3etU3y.js";
|
|
2
|
-
import {
|
|
3
|
-
import { n as ChevronRight, r as ChevronLeft, t as RotateCcw } from "./rotate-ccw-
|
|
4
|
-
import {
|
|
5
|
-
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-
|
|
6
|
-
import { i as
|
|
2
|
+
import { a as usePreviewHost, b as useComposedRefs, d as EmptyState, f as Button, g as createLucideIcon, h as FileWarning, m as LoaderCircle, o as usePreviewLogger, p as cn, r as FilePreviewLayout, s as FilePreviewToolbar, t as useTranslation, u as Scrollbar, v as createSlot } from "./useTranslation-BJY4EKsz.js";
|
|
3
|
+
import { n as ChevronRight, r as ChevronLeft, t as RotateCcw } from "./rotate-ccw-Bx-jjhVm.js";
|
|
4
|
+
import { t as CircleAlert } from "./circle-alert-sByhBDN4.js";
|
|
5
|
+
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-B2XJ64Kx.js";
|
|
6
|
+
import { S as composeEventHandlers, _ as useDismissableLayerSurface, c as Portal, g as DismissableLayer, i as useDialogPortalContainer, m as useId$1, o as useControllableState, r as PortalContainerProvider, s as Presence, t as FilePreviewToolbarButton, x as createContextScope, y as Primitive } from "./FilePreviewToolbarButton-ptqwCTnz.js";
|
|
7
|
+
import { i as useFocusGuards, n as hideOthers, r as FocusScope, t as ReactRemoveScroll } from "./Combination-i8Z9CJHc.js";
|
|
8
|
+
import { t as createPreviewSelection } from "./selection-B0INvh6t.js";
|
|
7
9
|
import { t as attachTouchPinch } from "./touchPinch-C4fl-9fg.js";
|
|
8
10
|
import * as React$1 from "react";
|
|
9
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
10
12
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
/**
|
|
12
14
|
* @license lucide-react v0.545.0 - ISC
|
|
@@ -29146,13 +29148,26 @@ function PdfPreviewTooLarge() {
|
|
|
29146
29148
|
*/
|
|
29147
29149
|
function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelection }) {
|
|
29148
29150
|
const logger = usePreviewLogger("PdfFilePreview");
|
|
29149
|
-
const { root: previewRoot, resources, options, failDocument } = usePreviewHost();
|
|
29151
|
+
const { root: previewRoot, resources, options, failDocument, isCurrentDocument } = usePreviewHost();
|
|
29150
29152
|
const { t } = useTranslation();
|
|
29151
29153
|
const rootRef = useRef(null);
|
|
29152
29154
|
const containerRef = useRef(null);
|
|
29153
29155
|
const viewerRef = useRef(null);
|
|
29154
29156
|
const pdfViewerRef = useRef(null);
|
|
29157
|
+
const restoredViewerRef = useRef(null);
|
|
29155
29158
|
const linkServiceRef = useRef(null);
|
|
29159
|
+
const zoomIntentRef = useRef({
|
|
29160
|
+
value: DEFAULT_PDF_SCALE,
|
|
29161
|
+
width: 0
|
|
29162
|
+
});
|
|
29163
|
+
const readingPositionRef = useRef(null);
|
|
29164
|
+
const captureReadingPosition = useCallback(() => {
|
|
29165
|
+
const viewer = pdfViewerRef.current;
|
|
29166
|
+
const container = containerRef.current;
|
|
29167
|
+
if (!viewer || restoredViewerRef.current !== viewer || !container || container.clientHeight === 0) return;
|
|
29168
|
+
viewer.update();
|
|
29169
|
+
}, []);
|
|
29170
|
+
useLayoutEffect(() => captureReadingPosition, [captureReadingPosition]);
|
|
29156
29171
|
const [background, setBackground] = useState(() => resolveThemeBackground(null));
|
|
29157
29172
|
const backgroundRef = useRef(background);
|
|
29158
29173
|
backgroundRef.current = background;
|
|
@@ -29261,7 +29276,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29261
29276
|
useEffect(() => {
|
|
29262
29277
|
pickTokenRef.current += 1;
|
|
29263
29278
|
setPickedPage(null);
|
|
29264
|
-
}, [sourceId]);
|
|
29279
|
+
}, [sourceId, previewDocument]);
|
|
29265
29280
|
useEffect(() => () => {
|
|
29266
29281
|
pickTokenRef.current += 1;
|
|
29267
29282
|
}, []);
|
|
@@ -29302,7 +29317,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29302
29317
|
const viewer = pdfViewerRef.current;
|
|
29303
29318
|
if (!responsiveLayout || status !== "ready" || !container || !viewer) return;
|
|
29304
29319
|
const observer = new ResizeObserver(() => {
|
|
29305
|
-
|
|
29320
|
+
const nextWidth = container.clientWidth;
|
|
29321
|
+
if (nextWidth <= 0 || nextWidth === zoomIntentRef.current.width) return;
|
|
29322
|
+
zoomIntentRef.current.width = nextWidth;
|
|
29323
|
+
if (zoomIntentRef.current.value === DEFAULT_PDF_SCALE) viewer.currentScaleValue = DEFAULT_PDF_SCALE;
|
|
29306
29324
|
});
|
|
29307
29325
|
observer.observe(container);
|
|
29308
29326
|
return () => observer.disconnect();
|
|
@@ -29342,9 +29360,11 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29342
29360
|
let workerPort = null;
|
|
29343
29361
|
let worker = null;
|
|
29344
29362
|
let disposing = false;
|
|
29363
|
+
const isCurrent = () => !cancelled && isCurrentDocument?.() !== false;
|
|
29345
29364
|
const dispose = () => {
|
|
29346
29365
|
if (disposing) return;
|
|
29347
29366
|
disposing = true;
|
|
29367
|
+
captureReadingPosition();
|
|
29348
29368
|
rangeTransport?.abort();
|
|
29349
29369
|
const task = loadingTask;
|
|
29350
29370
|
loadingTask = null;
|
|
@@ -29361,6 +29381,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29361
29381
|
};
|
|
29362
29382
|
const failLoad = (error) => {
|
|
29363
29383
|
if (cancelled || failed) return;
|
|
29384
|
+
if (!isCurrent()) {
|
|
29385
|
+
dispose();
|
|
29386
|
+
return;
|
|
29387
|
+
}
|
|
29364
29388
|
failed = true;
|
|
29365
29389
|
dispose();
|
|
29366
29390
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
@@ -29377,8 +29401,6 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29377
29401
|
setStatus("loading");
|
|
29378
29402
|
setCurrentPage(0);
|
|
29379
29403
|
setPageCount(0);
|
|
29380
|
-
setZoom(DEFAULT_ZOOM);
|
|
29381
|
-
setIsOutlineOpen(false);
|
|
29382
29404
|
setOutlineItems([]);
|
|
29383
29405
|
setOutlineStatus("loading");
|
|
29384
29406
|
(async () => {
|
|
@@ -29407,7 +29429,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29407
29429
|
...resources?.readPdfResource ? createPdfResourceFactories(resources.readPdfResource) : {}
|
|
29408
29430
|
});
|
|
29409
29431
|
const nextDocument = await loadingTask.promise;
|
|
29410
|
-
if (
|
|
29432
|
+
if (!isCurrent() || failed) {
|
|
29433
|
+
dispose();
|
|
29434
|
+
return;
|
|
29435
|
+
}
|
|
29411
29436
|
setDocumentProxy(nextDocument);
|
|
29412
29437
|
} catch (error) {
|
|
29413
29438
|
failLoad(error);
|
|
@@ -29422,19 +29447,21 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29422
29447
|
previewDocument,
|
|
29423
29448
|
resources,
|
|
29424
29449
|
failDocument,
|
|
29425
|
-
logger
|
|
29450
|
+
logger,
|
|
29451
|
+
captureReadingPosition,
|
|
29452
|
+
isCurrentDocument
|
|
29426
29453
|
]);
|
|
29427
29454
|
useEffect(() => {
|
|
29428
|
-
if (!documentProxy) return;
|
|
29455
|
+
if (!documentProxy || documentProxy.loadingTask.destroyed) return;
|
|
29429
29456
|
let cancelled = false;
|
|
29430
29457
|
setOutlineItems([]);
|
|
29431
29458
|
setOutlineStatus("loading");
|
|
29432
29459
|
documentProxy.getOutline().then((items) => {
|
|
29433
|
-
if (cancelled) return;
|
|
29460
|
+
if (cancelled || isCurrentDocument?.() === false) return;
|
|
29434
29461
|
setOutlineItems(items ?? []);
|
|
29435
29462
|
setOutlineStatus("ready");
|
|
29436
29463
|
}).catch((error) => {
|
|
29437
|
-
if (cancelled) return;
|
|
29464
|
+
if (cancelled || isCurrentDocument?.() === false) return;
|
|
29438
29465
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
29439
29466
|
logger.error(`Failed to load PDF outline: ${sourceId}`, normalized);
|
|
29440
29467
|
setOutlineStatus("error");
|
|
@@ -29445,16 +29472,18 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29445
29472
|
}, [
|
|
29446
29473
|
documentProxy,
|
|
29447
29474
|
sourceId,
|
|
29448
|
-
logger
|
|
29475
|
+
logger,
|
|
29476
|
+
isCurrentDocument
|
|
29449
29477
|
]);
|
|
29450
29478
|
useEffect(() => {
|
|
29451
29479
|
const container = containerRef.current;
|
|
29452
29480
|
const viewerElement = viewerRef.current;
|
|
29453
|
-
if (!documentProxy || !container || !viewerElement) return;
|
|
29481
|
+
if (!documentProxy || documentProxy.loadingTask.destroyed || !container || !viewerElement) return;
|
|
29454
29482
|
const eventBus = new EventBus();
|
|
29455
29483
|
const linkService = new PDFLinkService({ eventBus });
|
|
29456
29484
|
const viewerAbortController = new AbortController();
|
|
29457
29485
|
let pdfViewer;
|
|
29486
|
+
const isCurrent = () => pdfViewerRef.current === pdfViewer && isCurrentDocument?.() !== false;
|
|
29458
29487
|
try {
|
|
29459
29488
|
pdfViewer = new PDFViewer({
|
|
29460
29489
|
container,
|
|
@@ -29492,7 +29521,26 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29492
29521
|
};
|
|
29493
29522
|
const handleScaleChanging = (event) => {
|
|
29494
29523
|
const nextScale = event?.scale ?? pdfViewer.currentScale;
|
|
29495
|
-
if (typeof nextScale === "number" && Number.isFinite(nextScale) && nextScale > 0)
|
|
29524
|
+
if (typeof nextScale === "number" && Number.isFinite(nextScale) && nextScale > 0) {
|
|
29525
|
+
if (restoredViewerRef.current === pdfViewer) zoomIntentRef.current = {
|
|
29526
|
+
value: pdfViewer.currentScaleValue,
|
|
29527
|
+
width: container.clientWidth
|
|
29528
|
+
};
|
|
29529
|
+
setZoom(nextScale);
|
|
29530
|
+
}
|
|
29531
|
+
};
|
|
29532
|
+
const handleViewArea = (event) => {
|
|
29533
|
+
if (restoredViewerRef.current !== pdfViewer || container.clientHeight === 0) return;
|
|
29534
|
+
const { pageNumber, left, top } = event.location;
|
|
29535
|
+
const pageView = pdfViewer.getPageView(pageNumber - 1);
|
|
29536
|
+
if (!pageView?.pdfPage) return;
|
|
29537
|
+
readingPositionRef.current = {
|
|
29538
|
+
scale: pdfViewer.currentScale,
|
|
29539
|
+
page: pageNumber,
|
|
29540
|
+
left,
|
|
29541
|
+
top,
|
|
29542
|
+
viewBox: [...pageView.viewport.viewBox]
|
|
29543
|
+
};
|
|
29496
29544
|
};
|
|
29497
29545
|
const zoomOptions = { drawingDelay: ZOOM_DRAWING_DELAY };
|
|
29498
29546
|
let pinchWheelDelta = 0;
|
|
@@ -29596,14 +29644,69 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29596
29644
|
pdfViewer.setDocument(documentProxy);
|
|
29597
29645
|
linkService.setDocument(documentProxy);
|
|
29598
29646
|
syncPreviewControls();
|
|
29599
|
-
pdfViewer.firstPagePromise.then(() => {
|
|
29600
|
-
if (
|
|
29601
|
-
|
|
29647
|
+
pdfViewer.firstPagePromise.then(async () => {
|
|
29648
|
+
if (!isCurrent()) return;
|
|
29649
|
+
const position = readingPositionRef.current;
|
|
29650
|
+
if (position) {
|
|
29651
|
+
const pageNumber = clamp(position.page, 1, documentProxy.numPages);
|
|
29652
|
+
const ensurePageGeometry = async (number) => {
|
|
29653
|
+
const view = pdfViewer.getPageView(number - 1);
|
|
29654
|
+
if (!view.pdfPage) {
|
|
29655
|
+
const page = await documentProxy.getPage(number);
|
|
29656
|
+
if (!isCurrent()) return null;
|
|
29657
|
+
if (!view.pdfPage) view.setPdfPage(page);
|
|
29658
|
+
}
|
|
29659
|
+
return view;
|
|
29660
|
+
};
|
|
29661
|
+
const pageView = await ensurePageGeometry(pageNumber);
|
|
29662
|
+
if (!pageView || !isCurrent()) return;
|
|
29663
|
+
pdfViewer.currentPageNumber = pageNumber;
|
|
29664
|
+
pdfViewer.currentScaleValue = String(position.scale);
|
|
29665
|
+
const point = pageNumber === position.page ? [position.left, position.top].map((value, axis) => {
|
|
29666
|
+
const min = pageView.viewport.viewBox[axis];
|
|
29667
|
+
const max = pageView.viewport.viewBox[axis + 2];
|
|
29668
|
+
if (value < position.viewBox[axis]) return min + value - position.viewBox[axis];
|
|
29669
|
+
if (value > position.viewBox[axis + 2]) return max + value - position.viewBox[axis + 2];
|
|
29670
|
+
return clamp(value, min, max);
|
|
29671
|
+
}) : null;
|
|
29672
|
+
const offsetTop = point ? pageView.viewport.convertToViewportPoint(point[0], point[1])[1] : 0;
|
|
29673
|
+
let remainingHeight = container.clientHeight + offsetTop - pageView.height;
|
|
29674
|
+
for (let number = pageNumber + 1; remainingHeight > 0 && number <= documentProxy.numPages; number++) {
|
|
29675
|
+
const nextPage = await ensurePageGeometry(number);
|
|
29676
|
+
if (!nextPage || !isCurrent()) return;
|
|
29677
|
+
remainingHeight -= nextPage.height;
|
|
29678
|
+
}
|
|
29679
|
+
remainingHeight -= Math.max(0, offsetTop);
|
|
29680
|
+
for (let number = pageNumber - 1; remainingHeight > 0 && number >= 1; number--) {
|
|
29681
|
+
const previousPage = await ensurePageGeometry(number);
|
|
29682
|
+
if (!previousPage || !isCurrent()) return;
|
|
29683
|
+
remainingHeight -= previousPage.height;
|
|
29684
|
+
}
|
|
29685
|
+
pdfViewer.scrollPageIntoView({
|
|
29686
|
+
pageNumber,
|
|
29687
|
+
destArray: [
|
|
29688
|
+
null,
|
|
29689
|
+
{ name: "XYZ" },
|
|
29690
|
+
point?.[0] ?? null,
|
|
29691
|
+
point?.[1] ?? null,
|
|
29692
|
+
null
|
|
29693
|
+
],
|
|
29694
|
+
allowNegativeOffset: true,
|
|
29695
|
+
ignoreDestinationZoom: true
|
|
29696
|
+
});
|
|
29697
|
+
} else {
|
|
29698
|
+
zoomIntentRef.current = {
|
|
29699
|
+
value: DEFAULT_PDF_SCALE,
|
|
29700
|
+
width: container.clientWidth
|
|
29701
|
+
};
|
|
29702
|
+
pdfViewer.currentScaleValue = DEFAULT_PDF_SCALE;
|
|
29703
|
+
}
|
|
29602
29704
|
syncBackground();
|
|
29603
29705
|
syncPreviewControls();
|
|
29706
|
+
restoredViewerRef.current = pdfViewer;
|
|
29604
29707
|
setStatus("ready");
|
|
29605
29708
|
}).catch((error) => {
|
|
29606
|
-
if (
|
|
29709
|
+
if (!isCurrent()) return;
|
|
29607
29710
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
29608
29711
|
failDocument?.(normalized);
|
|
29609
29712
|
setStatus("error");
|
|
@@ -29613,6 +29716,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29613
29716
|
eventBus.on("pagerendered", syncBackground);
|
|
29614
29717
|
eventBus.on("pagechanging", handlePageChanging);
|
|
29615
29718
|
eventBus.on("scalechanging", handleScaleChanging);
|
|
29719
|
+
eventBus.on("updateviewarea", handleViewArea);
|
|
29616
29720
|
container.addEventListener("wheel", handleWheelZoom, { passive: false });
|
|
29617
29721
|
container.addEventListener("keydown", handleKeyboardZoom);
|
|
29618
29722
|
container.addEventListener("pointerdown", focusContainer);
|
|
@@ -29628,6 +29732,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29628
29732
|
eventBus.off("pagerendered", syncBackground);
|
|
29629
29733
|
eventBus.off("pagechanging", handlePageChanging);
|
|
29630
29734
|
eventBus.off("scalechanging", handleScaleChanging);
|
|
29735
|
+
eventBus.off("updateviewarea", handleViewArea);
|
|
29631
29736
|
container.removeEventListener("wheel", handleWheelZoom);
|
|
29632
29737
|
container.removeEventListener("keydown", handleKeyboardZoom);
|
|
29633
29738
|
container.removeEventListener("pointerdown", focusContainer);
|
|
@@ -29637,6 +29742,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29637
29742
|
detachDocument(pdfViewer);
|
|
29638
29743
|
pdfViewer.cleanup();
|
|
29639
29744
|
if (pdfViewerRef.current === pdfViewer) pdfViewerRef.current = null;
|
|
29745
|
+
if (restoredViewerRef.current === pdfViewer) restoredViewerRef.current = null;
|
|
29640
29746
|
if (linkServiceRef.current === linkService) linkServiceRef.current = null;
|
|
29641
29747
|
};
|
|
29642
29748
|
}, [
|
|
@@ -29645,7 +29751,8 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29645
29751
|
sourceId,
|
|
29646
29752
|
focusContainer,
|
|
29647
29753
|
logger,
|
|
29648
|
-
failDocument
|
|
29754
|
+
failDocument,
|
|
29755
|
+
isCurrentDocument
|
|
29649
29756
|
]);
|
|
29650
29757
|
const hasPages = status === "ready" && pageCount > 0;
|
|
29651
29758
|
return /* @__PURE__ */ jsxs(FilePreviewLayout.Frame, { children: [
|
|
@@ -29708,7 +29815,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29708
29815
|
})]
|
|
29709
29816
|
}), status === "loading" ? /* @__PURE__ */ jsxs("div", {
|
|
29710
29817
|
role: "status",
|
|
29711
|
-
className: "absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm
|
|
29818
|
+
className: "text-muted-foreground absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm",
|
|
29712
29819
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
29713
29820
|
className: "size-4 animate-spin",
|
|
29714
29821
|
"aria-hidden": true
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { i as __toESM } from "./rolldown-runtime-B-lAHAz2.js";
|
|
2
2
|
import { r as readPreviewDocument, t as PreviewError } from "./source-Rx3etU3y.js";
|
|
3
|
-
import {
|
|
4
|
-
import { n as ChevronRight, r as ChevronLeft, t as RotateCcw } from "./rotate-ccw-
|
|
5
|
-
import {
|
|
6
|
-
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-
|
|
7
|
-
import { t as
|
|
3
|
+
import { a as usePreviewHost, d as EmptyState, h as FileWarning, m as LoaderCircle, o as usePreviewLogger, r as FilePreviewLayout, s as FilePreviewToolbar, t as useTranslation } from "./useTranslation-BJY4EKsz.js";
|
|
4
|
+
import { n as ChevronRight, r as ChevronLeft, t as RotateCcw } from "./rotate-ccw-Bx-jjhVm.js";
|
|
5
|
+
import { t as CircleAlert } from "./circle-alert-sByhBDN4.js";
|
|
6
|
+
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-B2XJ64Kx.js";
|
|
7
|
+
import { t as FilePreviewToolbarButton } from "./FilePreviewToolbarButton-ptqwCTnz.js";
|
|
8
|
+
import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DC7vPyMI.js";
|
|
9
|
+
import { t as createPreviewSelection } from "./selection-B0INvh6t.js";
|
|
8
10
|
import { t as require_jszip_min } from "./jszip.min-uwqlc4KL.js";
|
|
9
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
10
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
11
13
|
//#region ../../node_modules/.pnpm/@aiden0z+pptx-renderer@1.2.2_patch_hash=cef8fdac29413f0b6e59df97fe5c874f536c1bc064d77aa_88cebeb44ab3d763fe0846cd3c392c59/node_modules/@aiden0z/pptx-renderer/dist/aiden0z-pptx-renderer.es.js
|
|
12
14
|
var import_jszip_min = /* @__PURE__ */ __toESM(require_jszip_min(), 1);
|
|
@@ -57772,10 +57774,26 @@ function stripExternalMediaRelationships(presentation) {
|
|
|
57772
57774
|
*/
|
|
57773
57775
|
function PowerPointFilePreview({ sourceId, fileName, document: previewDocument, onSelection }) {
|
|
57774
57776
|
const logger = usePreviewLogger("PowerPointFilePreview");
|
|
57775
|
-
const { options, failDocument } = usePreviewHost();
|
|
57777
|
+
const { options, failDocument, isCurrentDocument } = usePreviewHost();
|
|
57776
57778
|
const { t } = useTranslation();
|
|
57777
57779
|
const containerRef = useRef(null);
|
|
57778
57780
|
const viewerRef = useRef(null);
|
|
57781
|
+
const restoredViewerRef = useRef(null);
|
|
57782
|
+
const readingPositionRef = useRef(null);
|
|
57783
|
+
const captureReadingPosition = useCallback(() => {
|
|
57784
|
+
const viewer = viewerRef.current;
|
|
57785
|
+
const container = containerRef.current;
|
|
57786
|
+
if (!viewer || restoredViewerRef.current !== viewer || !container || container.clientHeight === 0) return;
|
|
57787
|
+
const slide = container.querySelector(`[data-slide-index="${viewer.currentSlideIndex}"]`);
|
|
57788
|
+
if (!slide) return;
|
|
57789
|
+
readingPositionRef.current = {
|
|
57790
|
+
zoom: viewer.zoomPercent,
|
|
57791
|
+
page: viewer.currentSlideIndex + 1,
|
|
57792
|
+
top: container.scrollTop - slide.offsetTop,
|
|
57793
|
+
left: container.scrollLeft - slide.offsetLeft
|
|
57794
|
+
};
|
|
57795
|
+
}, []);
|
|
57796
|
+
useLayoutEffect(() => captureReadingPosition, [captureReadingPosition]);
|
|
57779
57797
|
const presentationRef = useRef(null);
|
|
57780
57798
|
const controlsBusyRef = useRef(false);
|
|
57781
57799
|
const [error, setError] = useState(null);
|
|
@@ -57847,20 +57865,21 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57847
57865
|
const controller = new AbortController();
|
|
57848
57866
|
let cancelled = false;
|
|
57849
57867
|
let viewer = null;
|
|
57868
|
+
const isCurrent = () => !cancelled && isCurrentDocument?.() !== false;
|
|
57850
57869
|
setError(null);
|
|
57851
57870
|
setLoading(true);
|
|
57852
57871
|
setCurrentPage(0);
|
|
57853
57872
|
setPageCount(0);
|
|
57854
|
-
setZoom(PPTX_PREVIEW_DEFAULT_ZOOM);
|
|
57855
57873
|
setPreviewControlsBusy(false);
|
|
57856
57874
|
container.innerHTML = "";
|
|
57857
57875
|
(async () => {
|
|
57858
57876
|
try {
|
|
57859
57877
|
const pptxData = await readPreviewDocument(previewDocument, PPTX_PREVIEW_MAX_SOURCE_BYTES, controller.signal);
|
|
57860
|
-
if (
|
|
57878
|
+
if (!isCurrent()) return;
|
|
57861
57879
|
throwIfAborted(controller.signal);
|
|
57862
57880
|
const pptxFiles = await ZE(toArrayBuffer(pptxData), $ut);
|
|
57863
57881
|
throwIfAborted(controller.signal);
|
|
57882
|
+
if (!isCurrent()) return;
|
|
57864
57883
|
const presentation = pv(pptxFiles, { lazySlides: true });
|
|
57865
57884
|
if (presentation.slides.length === 0) throw new PreviewError("load_error", "PPTX contains no slides to preview");
|
|
57866
57885
|
stripExternalMediaRelationships(presentation);
|
|
@@ -57868,26 +57887,26 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57868
57887
|
throwIfAborted(controller.signal);
|
|
57869
57888
|
viewer = new Q_(container, {
|
|
57870
57889
|
fitMode: "contain",
|
|
57871
|
-
zoomPercent: PPTX_PREVIEW_DEFAULT_ZOOM,
|
|
57890
|
+
zoomPercent: readingPositionRef.current?.zoom ?? PPTX_PREVIEW_DEFAULT_ZOOM,
|
|
57872
57891
|
scrollContainer: container,
|
|
57873
57892
|
zipLimits: $ut,
|
|
57874
57893
|
lazyMedia: true,
|
|
57875
57894
|
lazySlides: true,
|
|
57876
57895
|
pdfjs: false,
|
|
57877
57896
|
onSlideChange: (index) => {
|
|
57878
|
-
if (
|
|
57897
|
+
if (isCurrent()) setCurrentPage(index + 1);
|
|
57879
57898
|
},
|
|
57880
57899
|
onRenderStart: () => {
|
|
57881
|
-
if (
|
|
57900
|
+
if (isCurrent()) setPreviewControlsBusy(true);
|
|
57882
57901
|
},
|
|
57883
57902
|
onRenderComplete: () => {
|
|
57884
|
-
if (
|
|
57903
|
+
if (!isCurrent()) return;
|
|
57885
57904
|
const activeViewer = viewerRef.current;
|
|
57886
57905
|
if (activeViewer) setZoom(activeViewer.zoomPercent);
|
|
57887
57906
|
setPreviewControlsBusy(false);
|
|
57888
57907
|
},
|
|
57889
57908
|
onSlideError: (index, slideError) => {
|
|
57890
|
-
if (
|
|
57909
|
+
if (!isCurrent()) return;
|
|
57891
57910
|
const normalized = slideError instanceof Error ? slideError : new Error(String(slideError));
|
|
57892
57911
|
logger.error(`Failed to render PPTX preview slide ${index + 1}: ${sourceId}`, normalized);
|
|
57893
57912
|
},
|
|
@@ -57908,13 +57927,24 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57908
57927
|
overscanViewport: 2
|
|
57909
57928
|
});
|
|
57910
57929
|
throwIfAborted(controller.signal);
|
|
57911
|
-
if (
|
|
57930
|
+
if (!isCurrent()) return;
|
|
57912
57931
|
const nextPageCount = viewer.slideCount;
|
|
57932
|
+
const position = readingPositionRef.current;
|
|
57933
|
+
if (position && nextPageCount > 0) {
|
|
57934
|
+
await viewer.goToSlide(clamp(position.page, 1, nextPageCount) - 1, { block: "start" });
|
|
57935
|
+
if (!isCurrent()) return;
|
|
57936
|
+
const slide = container.querySelector(`[data-slide-index="${viewer.currentSlideIndex}"]`);
|
|
57937
|
+
if (slide) {
|
|
57938
|
+
container.scrollTop = slide.offsetTop + clamp(position.top, 1 - container.clientHeight, Math.max(0, slide.offsetHeight - 1));
|
|
57939
|
+
container.scrollLeft = slide.offsetLeft + clamp(position.left, 1 - container.clientWidth, Math.max(0, slide.offsetWidth - 1));
|
|
57940
|
+
}
|
|
57941
|
+
}
|
|
57942
|
+
restoredViewerRef.current = viewer;
|
|
57913
57943
|
setPageCount(nextPageCount);
|
|
57914
57944
|
setCurrentPage(nextPageCount > 0 ? viewer.currentSlideIndex + 1 : 0);
|
|
57915
57945
|
focusContainer();
|
|
57916
57946
|
} catch (loadError) {
|
|
57917
|
-
if (
|
|
57947
|
+
if (!isCurrent()) return;
|
|
57918
57948
|
if (viewerRef.current === viewer) viewerRef.current = null;
|
|
57919
57949
|
viewer?.destroy();
|
|
57920
57950
|
container.innerHTML = "";
|
|
@@ -57923,25 +57953,29 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57923
57953
|
failDocument?.(reported);
|
|
57924
57954
|
setError(reported);
|
|
57925
57955
|
} finally {
|
|
57926
|
-
if (
|
|
57956
|
+
if (isCurrent()) setLoading(false);
|
|
57927
57957
|
}
|
|
57928
57958
|
})();
|
|
57929
57959
|
return () => {
|
|
57960
|
+
captureReadingPosition();
|
|
57930
57961
|
cancelled = true;
|
|
57931
57962
|
controller.abort();
|
|
57932
57963
|
controlsBusyRef.current = false;
|
|
57933
57964
|
presentationRef.current = null;
|
|
57934
57965
|
if (viewerRef.current === viewer) viewerRef.current = null;
|
|
57966
|
+
if (restoredViewerRef.current === viewer) restoredViewerRef.current = null;
|
|
57935
57967
|
viewer?.destroy();
|
|
57936
57968
|
container.innerHTML = "";
|
|
57937
57969
|
};
|
|
57938
57970
|
}, [
|
|
57971
|
+
captureReadingPosition,
|
|
57939
57972
|
sourceId,
|
|
57940
57973
|
focusContainer,
|
|
57941
57974
|
previewDocument,
|
|
57942
57975
|
logger,
|
|
57943
57976
|
failDocument,
|
|
57944
|
-
setPreviewControlsBusy
|
|
57977
|
+
setPreviewControlsBusy,
|
|
57978
|
+
isCurrentDocument
|
|
57945
57979
|
]);
|
|
57946
57980
|
const handlePick = useCallback((event) => {
|
|
57947
57981
|
if (!onSelection || !(event.target instanceof Element)) return;
|
|
@@ -57987,7 +58021,7 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57987
58021
|
}, [onSelection]);
|
|
57988
58022
|
useEffect(() => {
|
|
57989
58023
|
setPickedSlide(null);
|
|
57990
|
-
}, [sourceId]);
|
|
58024
|
+
}, [sourceId, previewDocument]);
|
|
57991
58025
|
const hasPages = !error && pageCount > 0;
|
|
57992
58026
|
return /* @__PURE__ */ jsxs(FilePreviewLayout.Frame, { children: [/* @__PURE__ */ jsx(PowerPointFilePreviewToolbar, {
|
|
57993
58027
|
currentPage: hasPages ? currentPage : 0,
|
|
@@ -58016,13 +58050,13 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
58016
58050
|
"data-picker": onSelection ? "true" : void 0,
|
|
58017
58051
|
role: "region",
|
|
58018
58052
|
"aria-label": fileName,
|
|
58019
|
-
className: "h-full w-full overflow-auto bg-background outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset [&
|
|
58053
|
+
className: "h-full w-full overflow-auto bg-background outline-none focus-visible:ring-2 focus-visible:ring-ring/50 focus-visible:ring-inset [&_[data-slide-index][data-pptx-picked=true]]:outline [&_[data-slide-index][data-pptx-picked=true]]:outline-2 [&_[data-slide-index][data-pptx-picked=true]]:outline-primary [&[data-picker=true]_[data-slide-index]]:cursor-pointer [&[data-picker=true]_[data-slide-index]:not([data-pptx-picked=true]):hover]:outline [&[data-picker=true]_[data-slide-index]:not([data-pptx-picked=true]):hover]:outline-2 [&[data-picker=true]_[data-slide-index]:not([data-pptx-picked=true]):hover]:outline-primary/40",
|
|
58020
58054
|
tabIndex: 0,
|
|
58021
58055
|
onClick: handlePick
|
|
58022
58056
|
}),
|
|
58023
58057
|
loading ? /* @__PURE__ */ jsxs("div", {
|
|
58024
58058
|
role: "status",
|
|
58025
|
-
className: "absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm
|
|
58059
|
+
className: "text-muted-foreground absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm",
|
|
58026
58060
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
58027
58061
|
className: "size-4 animate-spin",
|
|
58028
58062
|
"aria-hidden": true
|