@cherrystudio/file-preview 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +26 -2
- package/dist/{ImageFilePreview-Cbw6HzIR.js → ImageFilePreview-C_P1iIEi.js} +22 -7
- package/dist/{PdfFilePreview-DqnRzmwY.js → PdfFilePreview-CbrMcPzo.js} +125 -20
- package/dist/{PowerPointFilePreview-CO_N6c1I.js → PowerPointFilePreview-9E6kUy_A.js} +48 -16
- package/dist/{SpreadsheetFilePreview-GKeQwJL3.js → SpreadsheetFilePreview-PWFG3UY3.js} +55 -28
- package/dist/{WordFilePreview-IfWcWbwn.js → WordFilePreview-hfALJk2N.js} +19 -18
- package/dist/{imageFilePreviewPlugin-Cif3MLQd.js → imageFilePreviewPlugin-D6hV1Hm1.js} +1 -1
- package/dist/react.js +79 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -44,6 +44,15 @@ and file-identity content for the fixed top row; the format toolbar shares that
|
|
|
44
44
|
Without a header, format controls render above the document. Give `source` and
|
|
45
45
|
`resources` stable references so layout, locale and theme updates retain the session.
|
|
46
46
|
|
|
47
|
+
Refreshing the same source ID and format retains the mounted format and its valid
|
|
48
|
+
reading state while opening a fresh document. Formats preserve zoom, page, scroll,
|
|
49
|
+
worksheet and image transforms as applicable, and clamp positions to shorter content.
|
|
50
|
+
A different source ID or format starts a new preview. The previous document still
|
|
51
|
+
closes on refresh; obsolete reads and parsing results cannot overwrite retained
|
|
52
|
+
content or publish selections or terminal errors for the replacement session.
|
|
53
|
+
Closing and reopening a preview does not persist reading
|
|
54
|
+
history. Hosts must clear any held selection when requesting a refresh.
|
|
55
|
+
|
|
47
56
|
`onSelection` reports `{ sourceId, revision, anchor, excerpt }`, or `null` when a
|
|
48
57
|
pick is cleared. Anchors use worksheet A1 ranges, body paragraph ordinals, PDF pages
|
|
49
58
|
and PPTX slides. The host owns held selections across refreshes and file switches.
|
|
@@ -92,8 +101,7 @@ PDF workers belong to individual previews and never change pdf.js global options
|
|
|
92
101
|
Cleanup awaits the pdf.js loading task's destruction before terminating its worker,
|
|
93
102
|
allowing document fonts to be released. There is no forced teardown timeout: an
|
|
94
103
|
already-unresponsive worker can leave that destruction promise pending.
|
|
95
|
-
Translations use an independent i18next instance with resources for
|
|
96
|
-
languages; other locales fall back to English.
|
|
104
|
+
Translations use an independent i18next instance with resources for 14 languages; other locales fall back to English.
|
|
97
105
|
|
|
98
106
|
`FilePreviewLayout.Shell` owns the shared header and toolbar placement.
|
|
99
107
|
`FilePreviewLayout`, `FilePreviewToolbar` and its portal provider/host are also used
|
|
@@ -246,6 +254,22 @@ is bundled, including UI components and the patched docx-preview and pptx-render
|
|
|
246
254
|
dependencies; consumers install only `zod` and the React peers. CSS excludes Tailwind preflight
|
|
247
255
|
and scopes selectors to `.file-preview-root`.
|
|
248
256
|
|
|
257
|
+
## Browser regression tests
|
|
258
|
+
|
|
259
|
+
From the workspace root, install Playwright's Chromium once, then run the package tests:
|
|
260
|
+
|
|
261
|
+
```sh
|
|
262
|
+
pnpm exec playwright install chromium
|
|
263
|
+
pnpm exec playwright test --config packages/file-preview/playwright.config.ts
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
The test configuration builds the package and starts its own Vite server, then stops
|
|
267
|
+
the server after the run. No running Electron instance or renderer development server
|
|
268
|
+
is required. The PDF cases exercise the built public package and actual worker/layout
|
|
269
|
+
for mixed/changed page geometry, reading offsets, refresh, zoom, Activity and shorter documents.
|
|
270
|
+
The PowerPoint case uses the real renderer to retain a slide-relative reading offset
|
|
271
|
+
when the same deck changes its slide proportions, including Activity restoration.
|
|
272
|
+
|
|
249
273
|
## Publishing
|
|
250
274
|
|
|
251
275
|
Versioning and npm publishing use the repository's [Changesets workflow](../../.changeset/README.md).
|
|
@@ -3,10 +3,10 @@ import { _ as cva, a as usePreviewHost, b as useComposedRefs, d as EmptyState, g
|
|
|
3
3
|
import { n as ZoomIn, t as ZoomOut } from "./zoom-out-B2XJ64Kx.js";
|
|
4
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
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-
|
|
6
|
+
import { t as imageFilePreviewPlugin } from "./imageFilePreviewPlugin-D6hV1Hm1.js";
|
|
7
7
|
import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DC7vPyMI.js";
|
|
8
8
|
import * as React$1 from "react";
|
|
9
|
-
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
9
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
10
10
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
11
11
|
/**
|
|
12
12
|
* @license lucide-react v0.545.0 - ISC
|
|
@@ -2078,11 +2078,20 @@ var IMAGE_MEDIA_TYPE_BY_EXTENSION = {
|
|
|
2078
2078
|
};
|
|
2079
2079
|
function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
2080
2080
|
const { t } = useTranslation();
|
|
2081
|
-
const { failDocument } = usePreviewHost();
|
|
2081
|
+
const { failDocument, isCurrentDocument } = usePreviewHost();
|
|
2082
2082
|
const [url, setUrl] = useState(null);
|
|
2083
2083
|
const objectUrlRef = useRef(null);
|
|
2084
2084
|
const [status, setStatus] = useState("loading");
|
|
2085
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]);
|
|
2086
2095
|
const releaseImageUrl = useCallback(() => {
|
|
2087
2096
|
if (objectUrlRef.current) URL.revokeObjectURL(objectUrlRef.current);
|
|
2088
2097
|
objectUrlRef.current = null;
|
|
@@ -2103,14 +2112,14 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2103
2112
|
setStatus("loading");
|
|
2104
2113
|
setUrl(null);
|
|
2105
2114
|
readPreviewDocument(document, IMAGE_PREVIEW_MAX_SIZE_BYTES, controller.signal).then((bytes) => {
|
|
2106
|
-
if (controller.signal.aborted) return;
|
|
2115
|
+
if (controller.signal.aborted || isCurrentDocument?.() === false) return;
|
|
2107
2116
|
const extension = fileName.split(".").at(-1)?.toLowerCase();
|
|
2108
2117
|
const normalizedMediaType = mediaType?.split(";", 1)[0].trim().toLowerCase();
|
|
2109
2118
|
const mime = normalizedMediaType && imageFilePreviewPlugin.mediaTypes.includes(normalizedMediaType) ? normalizedMediaType : IMAGE_MEDIA_TYPE_BY_EXTENSION[extension ?? ""] ?? `image/${extension}`;
|
|
2110
2119
|
objectUrlRef.current = URL.createObjectURL(new Blob([bytes], { type: mime }));
|
|
2111
2120
|
setUrl(objectUrlRef.current);
|
|
2112
2121
|
}).catch((error) => {
|
|
2113
|
-
if (controller.signal.aborted) return;
|
|
2122
|
+
if (controller.signal.aborted || isCurrentDocument?.() === false) return;
|
|
2114
2123
|
failDocument?.(error);
|
|
2115
2124
|
setStatus(error instanceof PreviewError && error.code === "too_large" ? "too_large" : "error");
|
|
2116
2125
|
});
|
|
@@ -2123,7 +2132,8 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2123
2132
|
fileName,
|
|
2124
2133
|
mediaType,
|
|
2125
2134
|
failDocument,
|
|
2126
|
-
releaseImageUrl
|
|
2135
|
+
releaseImageUrl,
|
|
2136
|
+
isCurrentDocument
|
|
2127
2137
|
]);
|
|
2128
2138
|
if (status === "too_large") return /* @__PURE__ */ jsx(FilePreviewLayout.Frame, { children: /* @__PURE__ */ jsx(FilePreviewLayout.Content, { children: /* @__PURE__ */ jsx(FilePreviewTooLarge, {
|
|
2129
2139
|
sizeBytes: document.size,
|
|
@@ -2156,8 +2166,13 @@ function ImageFilePreview({ sourceId, fileName, document, mediaType }) {
|
|
|
2156
2166
|
imageClassName: status === "loading" ? "opacity-0" : void 0,
|
|
2157
2167
|
item,
|
|
2158
2168
|
transformControls,
|
|
2159
|
-
onLoad: () =>
|
|
2169
|
+
onLoad: () => {
|
|
2170
|
+
if (isCurrentDocument?.() === false) return;
|
|
2171
|
+
transformControls.update(pendingTransform);
|
|
2172
|
+
setStatus("ready");
|
|
2173
|
+
},
|
|
2160
2174
|
onError: () => {
|
|
2175
|
+
if (isCurrentDocument?.() === false) return;
|
|
2161
2176
|
const error = /* @__PURE__ */ new Error(`Failed to load image preview: ${sourceId}`);
|
|
2162
2177
|
failDocument?.(error);
|
|
2163
2178
|
releaseImageUrl();
|
|
@@ -8,7 +8,7 @@ import { i as useFocusGuards, n as hideOthers, r as FocusScope, t as ReactRemove
|
|
|
8
8
|
import { t as createPreviewSelection } from "./selection-B0INvh6t.js";
|
|
9
9
|
import { t as attachTouchPinch } from "./touchPinch-C4fl-9fg.js";
|
|
10
10
|
import * as React$1 from "react";
|
|
11
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
12
12
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
13
13
|
/**
|
|
14
14
|
* @license lucide-react v0.545.0 - ISC
|
|
@@ -29148,13 +29148,26 @@ function PdfPreviewTooLarge() {
|
|
|
29148
29148
|
*/
|
|
29149
29149
|
function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelection }) {
|
|
29150
29150
|
const logger = usePreviewLogger("PdfFilePreview");
|
|
29151
|
-
const { root: previewRoot, resources, options, failDocument } = usePreviewHost();
|
|
29151
|
+
const { root: previewRoot, resources, options, failDocument, isCurrentDocument } = usePreviewHost();
|
|
29152
29152
|
const { t } = useTranslation();
|
|
29153
29153
|
const rootRef = useRef(null);
|
|
29154
29154
|
const containerRef = useRef(null);
|
|
29155
29155
|
const viewerRef = useRef(null);
|
|
29156
29156
|
const pdfViewerRef = useRef(null);
|
|
29157
|
+
const restoredViewerRef = useRef(null);
|
|
29157
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]);
|
|
29158
29171
|
const [background, setBackground] = useState(() => resolveThemeBackground(null));
|
|
29159
29172
|
const backgroundRef = useRef(background);
|
|
29160
29173
|
backgroundRef.current = background;
|
|
@@ -29263,7 +29276,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29263
29276
|
useEffect(() => {
|
|
29264
29277
|
pickTokenRef.current += 1;
|
|
29265
29278
|
setPickedPage(null);
|
|
29266
|
-
}, [sourceId]);
|
|
29279
|
+
}, [sourceId, previewDocument]);
|
|
29267
29280
|
useEffect(() => () => {
|
|
29268
29281
|
pickTokenRef.current += 1;
|
|
29269
29282
|
}, []);
|
|
@@ -29304,7 +29317,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29304
29317
|
const viewer = pdfViewerRef.current;
|
|
29305
29318
|
if (!responsiveLayout || status !== "ready" || !container || !viewer) return;
|
|
29306
29319
|
const observer = new ResizeObserver(() => {
|
|
29307
|
-
|
|
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;
|
|
29308
29324
|
});
|
|
29309
29325
|
observer.observe(container);
|
|
29310
29326
|
return () => observer.disconnect();
|
|
@@ -29344,9 +29360,11 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29344
29360
|
let workerPort = null;
|
|
29345
29361
|
let worker = null;
|
|
29346
29362
|
let disposing = false;
|
|
29363
|
+
const isCurrent = () => !cancelled && isCurrentDocument?.() !== false;
|
|
29347
29364
|
const dispose = () => {
|
|
29348
29365
|
if (disposing) return;
|
|
29349
29366
|
disposing = true;
|
|
29367
|
+
captureReadingPosition();
|
|
29350
29368
|
rangeTransport?.abort();
|
|
29351
29369
|
const task = loadingTask;
|
|
29352
29370
|
loadingTask = null;
|
|
@@ -29363,6 +29381,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29363
29381
|
};
|
|
29364
29382
|
const failLoad = (error) => {
|
|
29365
29383
|
if (cancelled || failed) return;
|
|
29384
|
+
if (!isCurrent()) {
|
|
29385
|
+
dispose();
|
|
29386
|
+
return;
|
|
29387
|
+
}
|
|
29366
29388
|
failed = true;
|
|
29367
29389
|
dispose();
|
|
29368
29390
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
@@ -29379,8 +29401,6 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29379
29401
|
setStatus("loading");
|
|
29380
29402
|
setCurrentPage(0);
|
|
29381
29403
|
setPageCount(0);
|
|
29382
|
-
setZoom(DEFAULT_ZOOM);
|
|
29383
|
-
setIsOutlineOpen(false);
|
|
29384
29404
|
setOutlineItems([]);
|
|
29385
29405
|
setOutlineStatus("loading");
|
|
29386
29406
|
(async () => {
|
|
@@ -29409,7 +29429,10 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29409
29429
|
...resources?.readPdfResource ? createPdfResourceFactories(resources.readPdfResource) : {}
|
|
29410
29430
|
});
|
|
29411
29431
|
const nextDocument = await loadingTask.promise;
|
|
29412
|
-
if (
|
|
29432
|
+
if (!isCurrent() || failed) {
|
|
29433
|
+
dispose();
|
|
29434
|
+
return;
|
|
29435
|
+
}
|
|
29413
29436
|
setDocumentProxy(nextDocument);
|
|
29414
29437
|
} catch (error) {
|
|
29415
29438
|
failLoad(error);
|
|
@@ -29424,19 +29447,21 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29424
29447
|
previewDocument,
|
|
29425
29448
|
resources,
|
|
29426
29449
|
failDocument,
|
|
29427
|
-
logger
|
|
29450
|
+
logger,
|
|
29451
|
+
captureReadingPosition,
|
|
29452
|
+
isCurrentDocument
|
|
29428
29453
|
]);
|
|
29429
29454
|
useEffect(() => {
|
|
29430
|
-
if (!documentProxy) return;
|
|
29455
|
+
if (!documentProxy || documentProxy.loadingTask.destroyed) return;
|
|
29431
29456
|
let cancelled = false;
|
|
29432
29457
|
setOutlineItems([]);
|
|
29433
29458
|
setOutlineStatus("loading");
|
|
29434
29459
|
documentProxy.getOutline().then((items) => {
|
|
29435
|
-
if (cancelled) return;
|
|
29460
|
+
if (cancelled || isCurrentDocument?.() === false) return;
|
|
29436
29461
|
setOutlineItems(items ?? []);
|
|
29437
29462
|
setOutlineStatus("ready");
|
|
29438
29463
|
}).catch((error) => {
|
|
29439
|
-
if (cancelled) return;
|
|
29464
|
+
if (cancelled || isCurrentDocument?.() === false) return;
|
|
29440
29465
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
29441
29466
|
logger.error(`Failed to load PDF outline: ${sourceId}`, normalized);
|
|
29442
29467
|
setOutlineStatus("error");
|
|
@@ -29447,16 +29472,18 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29447
29472
|
}, [
|
|
29448
29473
|
documentProxy,
|
|
29449
29474
|
sourceId,
|
|
29450
|
-
logger
|
|
29475
|
+
logger,
|
|
29476
|
+
isCurrentDocument
|
|
29451
29477
|
]);
|
|
29452
29478
|
useEffect(() => {
|
|
29453
29479
|
const container = containerRef.current;
|
|
29454
29480
|
const viewerElement = viewerRef.current;
|
|
29455
|
-
if (!documentProxy || !container || !viewerElement) return;
|
|
29481
|
+
if (!documentProxy || documentProxy.loadingTask.destroyed || !container || !viewerElement) return;
|
|
29456
29482
|
const eventBus = new EventBus();
|
|
29457
29483
|
const linkService = new PDFLinkService({ eventBus });
|
|
29458
29484
|
const viewerAbortController = new AbortController();
|
|
29459
29485
|
let pdfViewer;
|
|
29486
|
+
const isCurrent = () => pdfViewerRef.current === pdfViewer && isCurrentDocument?.() !== false;
|
|
29460
29487
|
try {
|
|
29461
29488
|
pdfViewer = new PDFViewer({
|
|
29462
29489
|
container,
|
|
@@ -29494,7 +29521,26 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29494
29521
|
};
|
|
29495
29522
|
const handleScaleChanging = (event) => {
|
|
29496
29523
|
const nextScale = event?.scale ?? pdfViewer.currentScale;
|
|
29497
|
-
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
|
+
};
|
|
29498
29544
|
};
|
|
29499
29545
|
const zoomOptions = { drawingDelay: ZOOM_DRAWING_DELAY };
|
|
29500
29546
|
let pinchWheelDelta = 0;
|
|
@@ -29598,14 +29644,69 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29598
29644
|
pdfViewer.setDocument(documentProxy);
|
|
29599
29645
|
linkService.setDocument(documentProxy);
|
|
29600
29646
|
syncPreviewControls();
|
|
29601
|
-
pdfViewer.firstPagePromise.then(() => {
|
|
29602
|
-
if (
|
|
29603
|
-
|
|
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
|
+
}
|
|
29604
29704
|
syncBackground();
|
|
29605
29705
|
syncPreviewControls();
|
|
29706
|
+
restoredViewerRef.current = pdfViewer;
|
|
29606
29707
|
setStatus("ready");
|
|
29607
29708
|
}).catch((error) => {
|
|
29608
|
-
if (
|
|
29709
|
+
if (!isCurrent()) return;
|
|
29609
29710
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
29610
29711
|
failDocument?.(normalized);
|
|
29611
29712
|
setStatus("error");
|
|
@@ -29615,6 +29716,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29615
29716
|
eventBus.on("pagerendered", syncBackground);
|
|
29616
29717
|
eventBus.on("pagechanging", handlePageChanging);
|
|
29617
29718
|
eventBus.on("scalechanging", handleScaleChanging);
|
|
29719
|
+
eventBus.on("updateviewarea", handleViewArea);
|
|
29618
29720
|
container.addEventListener("wheel", handleWheelZoom, { passive: false });
|
|
29619
29721
|
container.addEventListener("keydown", handleKeyboardZoom);
|
|
29620
29722
|
container.addEventListener("pointerdown", focusContainer);
|
|
@@ -29630,6 +29732,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29630
29732
|
eventBus.off("pagerendered", syncBackground);
|
|
29631
29733
|
eventBus.off("pagechanging", handlePageChanging);
|
|
29632
29734
|
eventBus.off("scalechanging", handleScaleChanging);
|
|
29735
|
+
eventBus.off("updateviewarea", handleViewArea);
|
|
29633
29736
|
container.removeEventListener("wheel", handleWheelZoom);
|
|
29634
29737
|
container.removeEventListener("keydown", handleKeyboardZoom);
|
|
29635
29738
|
container.removeEventListener("pointerdown", focusContainer);
|
|
@@ -29639,6 +29742,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29639
29742
|
detachDocument(pdfViewer);
|
|
29640
29743
|
pdfViewer.cleanup();
|
|
29641
29744
|
if (pdfViewerRef.current === pdfViewer) pdfViewerRef.current = null;
|
|
29745
|
+
if (restoredViewerRef.current === pdfViewer) restoredViewerRef.current = null;
|
|
29642
29746
|
if (linkServiceRef.current === linkService) linkServiceRef.current = null;
|
|
29643
29747
|
};
|
|
29644
29748
|
}, [
|
|
@@ -29647,7 +29751,8 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29647
29751
|
sourceId,
|
|
29648
29752
|
focusContainer,
|
|
29649
29753
|
logger,
|
|
29650
|
-
failDocument
|
|
29754
|
+
failDocument,
|
|
29755
|
+
isCurrentDocument
|
|
29651
29756
|
]);
|
|
29652
29757
|
const hasPages = status === "ready" && pageCount > 0;
|
|
29653
29758
|
return /* @__PURE__ */ jsxs(FilePreviewLayout.Frame, { children: [
|
|
@@ -29710,7 +29815,7 @@ function PdfFilePreview({ sourceId, fileName, document: previewDocument, onSelec
|
|
|
29710
29815
|
})]
|
|
29711
29816
|
}), status === "loading" ? /* @__PURE__ */ jsxs("div", {
|
|
29712
29817
|
role: "status",
|
|
29713
|
-
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",
|
|
29714
29819
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
29715
29820
|
className: "size-4 animate-spin",
|
|
29716
29821
|
"aria-hidden": true
|
|
@@ -8,7 +8,7 @@ import { t as FilePreviewToolbarButton } from "./FilePreviewToolbarButton-ptqwCT
|
|
|
8
8
|
import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DC7vPyMI.js";
|
|
9
9
|
import { t as createPreviewSelection } from "./selection-B0INvh6t.js";
|
|
10
10
|
import { t as require_jszip_min } from "./jszip.min-uwqlc4KL.js";
|
|
11
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
11
|
+
import { useCallback, useEffect, useLayoutEffect, useRef, useState } from "react";
|
|
12
12
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
13
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
|
|
14
14
|
var import_jszip_min = /* @__PURE__ */ __toESM(require_jszip_min(), 1);
|
|
@@ -57774,10 +57774,26 @@ function stripExternalMediaRelationships(presentation) {
|
|
|
57774
57774
|
*/
|
|
57775
57775
|
function PowerPointFilePreview({ sourceId, fileName, document: previewDocument, onSelection }) {
|
|
57776
57776
|
const logger = usePreviewLogger("PowerPointFilePreview");
|
|
57777
|
-
const { options, failDocument } = usePreviewHost();
|
|
57777
|
+
const { options, failDocument, isCurrentDocument } = usePreviewHost();
|
|
57778
57778
|
const { t } = useTranslation();
|
|
57779
57779
|
const containerRef = useRef(null);
|
|
57780
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]);
|
|
57781
57797
|
const presentationRef = useRef(null);
|
|
57782
57798
|
const controlsBusyRef = useRef(false);
|
|
57783
57799
|
const [error, setError] = useState(null);
|
|
@@ -57849,20 +57865,21 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57849
57865
|
const controller = new AbortController();
|
|
57850
57866
|
let cancelled = false;
|
|
57851
57867
|
let viewer = null;
|
|
57868
|
+
const isCurrent = () => !cancelled && isCurrentDocument?.() !== false;
|
|
57852
57869
|
setError(null);
|
|
57853
57870
|
setLoading(true);
|
|
57854
57871
|
setCurrentPage(0);
|
|
57855
57872
|
setPageCount(0);
|
|
57856
|
-
setZoom(PPTX_PREVIEW_DEFAULT_ZOOM);
|
|
57857
57873
|
setPreviewControlsBusy(false);
|
|
57858
57874
|
container.innerHTML = "";
|
|
57859
57875
|
(async () => {
|
|
57860
57876
|
try {
|
|
57861
57877
|
const pptxData = await readPreviewDocument(previewDocument, PPTX_PREVIEW_MAX_SOURCE_BYTES, controller.signal);
|
|
57862
|
-
if (
|
|
57878
|
+
if (!isCurrent()) return;
|
|
57863
57879
|
throwIfAborted(controller.signal);
|
|
57864
57880
|
const pptxFiles = await ZE(toArrayBuffer(pptxData), $ut);
|
|
57865
57881
|
throwIfAborted(controller.signal);
|
|
57882
|
+
if (!isCurrent()) return;
|
|
57866
57883
|
const presentation = pv(pptxFiles, { lazySlides: true });
|
|
57867
57884
|
if (presentation.slides.length === 0) throw new PreviewError("load_error", "PPTX contains no slides to preview");
|
|
57868
57885
|
stripExternalMediaRelationships(presentation);
|
|
@@ -57870,26 +57887,26 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57870
57887
|
throwIfAborted(controller.signal);
|
|
57871
57888
|
viewer = new Q_(container, {
|
|
57872
57889
|
fitMode: "contain",
|
|
57873
|
-
zoomPercent: PPTX_PREVIEW_DEFAULT_ZOOM,
|
|
57890
|
+
zoomPercent: readingPositionRef.current?.zoom ?? PPTX_PREVIEW_DEFAULT_ZOOM,
|
|
57874
57891
|
scrollContainer: container,
|
|
57875
57892
|
zipLimits: $ut,
|
|
57876
57893
|
lazyMedia: true,
|
|
57877
57894
|
lazySlides: true,
|
|
57878
57895
|
pdfjs: false,
|
|
57879
57896
|
onSlideChange: (index) => {
|
|
57880
|
-
if (
|
|
57897
|
+
if (isCurrent()) setCurrentPage(index + 1);
|
|
57881
57898
|
},
|
|
57882
57899
|
onRenderStart: () => {
|
|
57883
|
-
if (
|
|
57900
|
+
if (isCurrent()) setPreviewControlsBusy(true);
|
|
57884
57901
|
},
|
|
57885
57902
|
onRenderComplete: () => {
|
|
57886
|
-
if (
|
|
57903
|
+
if (!isCurrent()) return;
|
|
57887
57904
|
const activeViewer = viewerRef.current;
|
|
57888
57905
|
if (activeViewer) setZoom(activeViewer.zoomPercent);
|
|
57889
57906
|
setPreviewControlsBusy(false);
|
|
57890
57907
|
},
|
|
57891
57908
|
onSlideError: (index, slideError) => {
|
|
57892
|
-
if (
|
|
57909
|
+
if (!isCurrent()) return;
|
|
57893
57910
|
const normalized = slideError instanceof Error ? slideError : new Error(String(slideError));
|
|
57894
57911
|
logger.error(`Failed to render PPTX preview slide ${index + 1}: ${sourceId}`, normalized);
|
|
57895
57912
|
},
|
|
@@ -57910,13 +57927,24 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57910
57927
|
overscanViewport: 2
|
|
57911
57928
|
});
|
|
57912
57929
|
throwIfAborted(controller.signal);
|
|
57913
|
-
if (
|
|
57930
|
+
if (!isCurrent()) return;
|
|
57914
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;
|
|
57915
57943
|
setPageCount(nextPageCount);
|
|
57916
57944
|
setCurrentPage(nextPageCount > 0 ? viewer.currentSlideIndex + 1 : 0);
|
|
57917
57945
|
focusContainer();
|
|
57918
57946
|
} catch (loadError) {
|
|
57919
|
-
if (
|
|
57947
|
+
if (!isCurrent()) return;
|
|
57920
57948
|
if (viewerRef.current === viewer) viewerRef.current = null;
|
|
57921
57949
|
viewer?.destroy();
|
|
57922
57950
|
container.innerHTML = "";
|
|
@@ -57925,25 +57953,29 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57925
57953
|
failDocument?.(reported);
|
|
57926
57954
|
setError(reported);
|
|
57927
57955
|
} finally {
|
|
57928
|
-
if (
|
|
57956
|
+
if (isCurrent()) setLoading(false);
|
|
57929
57957
|
}
|
|
57930
57958
|
})();
|
|
57931
57959
|
return () => {
|
|
57960
|
+
captureReadingPosition();
|
|
57932
57961
|
cancelled = true;
|
|
57933
57962
|
controller.abort();
|
|
57934
57963
|
controlsBusyRef.current = false;
|
|
57935
57964
|
presentationRef.current = null;
|
|
57936
57965
|
if (viewerRef.current === viewer) viewerRef.current = null;
|
|
57966
|
+
if (restoredViewerRef.current === viewer) restoredViewerRef.current = null;
|
|
57937
57967
|
viewer?.destroy();
|
|
57938
57968
|
container.innerHTML = "";
|
|
57939
57969
|
};
|
|
57940
57970
|
}, [
|
|
57971
|
+
captureReadingPosition,
|
|
57941
57972
|
sourceId,
|
|
57942
57973
|
focusContainer,
|
|
57943
57974
|
previewDocument,
|
|
57944
57975
|
logger,
|
|
57945
57976
|
failDocument,
|
|
57946
|
-
setPreviewControlsBusy
|
|
57977
|
+
setPreviewControlsBusy,
|
|
57978
|
+
isCurrentDocument
|
|
57947
57979
|
]);
|
|
57948
57980
|
const handlePick = useCallback((event) => {
|
|
57949
57981
|
if (!onSelection || !(event.target instanceof Element)) return;
|
|
@@ -57989,7 +58021,7 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
57989
58021
|
}, [onSelection]);
|
|
57990
58022
|
useEffect(() => {
|
|
57991
58023
|
setPickedSlide(null);
|
|
57992
|
-
}, [sourceId]);
|
|
58024
|
+
}, [sourceId, previewDocument]);
|
|
57993
58025
|
const hasPages = !error && pageCount > 0;
|
|
57994
58026
|
return /* @__PURE__ */ jsxs(FilePreviewLayout.Frame, { children: [/* @__PURE__ */ jsx(PowerPointFilePreviewToolbar, {
|
|
57995
58027
|
currentPage: hasPages ? currentPage : 0,
|
|
@@ -58018,13 +58050,13 @@ function PowerPointFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
58018
58050
|
"data-picker": onSelection ? "true" : void 0,
|
|
58019
58051
|
role: "region",
|
|
58020
58052
|
"aria-label": fileName,
|
|
58021
|
-
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",
|
|
58022
58054
|
tabIndex: 0,
|
|
58023
58055
|
onClick: handlePick
|
|
58024
58056
|
}),
|
|
58025
58057
|
loading ? /* @__PURE__ */ jsxs("div", {
|
|
58026
58058
|
role: "status",
|
|
58027
|
-
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",
|
|
58028
58060
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
58029
58061
|
className: "size-4 animate-spin",
|
|
58030
58062
|
"aria-hidden": true
|
|
@@ -7,7 +7,7 @@ import { t as FilePreviewToolbarButton } from "./FilePreviewToolbarButton-ptqwCT
|
|
|
7
7
|
import { t as FilePreviewTooLarge } from "./FilePreviewTooLarge-DC7vPyMI.js";
|
|
8
8
|
import { n as normalizeSelectionText, t as createPreviewSelection } from "./selection-B0INvh6t.js";
|
|
9
9
|
import * as React$1 from "react";
|
|
10
|
-
import React, { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
10
|
+
import React, { memo, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
11
11
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
12
12
|
import { flushSync } from "react-dom";
|
|
13
13
|
typeof window !== "undefined" && window.document && window.document.createElement;
|
|
@@ -973,7 +973,7 @@ function SpreadsheetFilePreviewToolbar({ canZoomIn, canZoomOut, onZoomIn, onZoom
|
|
|
973
973
|
var XLSX_PREVIEW_MAX_SIZE_BYTES = 20971520;
|
|
974
974
|
function useXlsxWorkbook(document, fileName) {
|
|
975
975
|
const logger = usePreviewLogger("useXlsxWorkbook");
|
|
976
|
-
const { failDocument, resources } = usePreviewHost();
|
|
976
|
+
const { failDocument, resources, isCurrentDocument } = usePreviewHost();
|
|
977
977
|
const { baseUrl, createWorker } = resources ?? {};
|
|
978
978
|
const [state, setState] = useState({ status: "idle" });
|
|
979
979
|
const workerRef = useRef(null);
|
|
@@ -983,6 +983,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
983
983
|
let cancelled = false;
|
|
984
984
|
const controller = new AbortController();
|
|
985
985
|
const requestId = ++requestIdRef.current;
|
|
986
|
+
const isCurrent = () => !cancelled && requestId === requestIdRef.current && isCurrentDocument?.() !== false;
|
|
986
987
|
if (document.size > 20971520) {
|
|
987
988
|
failDocument?.(new PreviewError("too_large", "Workbook exceeds the preview size limit"));
|
|
988
989
|
setState({
|
|
@@ -991,15 +992,18 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
991
992
|
});
|
|
992
993
|
return;
|
|
993
994
|
}
|
|
994
|
-
setState(
|
|
995
|
+
setState((current) => ({
|
|
996
|
+
status: "loading",
|
|
997
|
+
model: "model" in current ? current.model : void 0
|
|
998
|
+
}));
|
|
995
999
|
(async () => {
|
|
996
1000
|
let bytes;
|
|
997
1001
|
try {
|
|
998
1002
|
const raw = await readPreviewDocument(document, XLSX_PREVIEW_MAX_SIZE_BYTES, controller.signal);
|
|
999
|
-
if (
|
|
1003
|
+
if (!isCurrent()) return;
|
|
1000
1004
|
bytes = raw.slice().buffer;
|
|
1001
1005
|
} catch (error) {
|
|
1002
|
-
if (
|
|
1006
|
+
if (!isCurrent()) return;
|
|
1003
1007
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
1004
1008
|
failDocument?.(normalized);
|
|
1005
1009
|
setState({
|
|
@@ -1012,7 +1016,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1012
1016
|
try {
|
|
1013
1017
|
worker = createXlsxWorker(baseUrl, createWorker);
|
|
1014
1018
|
} catch (error) {
|
|
1015
|
-
if (
|
|
1019
|
+
if (!isCurrent()) return;
|
|
1016
1020
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
1017
1021
|
failDocument?.(normalized);
|
|
1018
1022
|
setState({
|
|
@@ -1021,7 +1025,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1021
1025
|
});
|
|
1022
1026
|
return;
|
|
1023
1027
|
}
|
|
1024
|
-
if (
|
|
1028
|
+
if (!isCurrent()) {
|
|
1025
1029
|
worker.terminate();
|
|
1026
1030
|
return;
|
|
1027
1031
|
}
|
|
@@ -1030,6 +1034,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1030
1034
|
if (cancelled || event.data.id !== requestIdRef.current) return;
|
|
1031
1035
|
worker.terminate();
|
|
1032
1036
|
if (workerRef.current === worker) workerRef.current = null;
|
|
1037
|
+
if (!isCurrent()) return;
|
|
1033
1038
|
if (event.data.ok) {
|
|
1034
1039
|
for (const warning of event.data.model.warnings) {
|
|
1035
1040
|
if (loggedWarningsRef.current.has(warning)) continue;
|
|
@@ -1052,6 +1057,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1052
1057
|
if (cancelled || requestId !== requestIdRef.current) return;
|
|
1053
1058
|
worker.terminate();
|
|
1054
1059
|
if (workerRef.current === worker) workerRef.current = null;
|
|
1060
|
+
if (!isCurrent()) return;
|
|
1055
1061
|
failDocument?.(event.error instanceof Error ? event.error : new Error(event.message));
|
|
1056
1062
|
setState({
|
|
1057
1063
|
status: "error",
|
|
@@ -1068,7 +1074,7 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1068
1074
|
} catch (error) {
|
|
1069
1075
|
worker.terminate();
|
|
1070
1076
|
if (workerRef.current === worker) workerRef.current = null;
|
|
1071
|
-
if (
|
|
1077
|
+
if (!isCurrent()) return;
|
|
1072
1078
|
const normalized = error instanceof Error ? error : new Error(String(error));
|
|
1073
1079
|
failDocument?.(normalized);
|
|
1074
1080
|
setState({
|
|
@@ -1089,7 +1095,8 @@ function useXlsxWorkbook(document, fileName) {
|
|
|
1089
1095
|
logger,
|
|
1090
1096
|
failDocument,
|
|
1091
1097
|
baseUrl,
|
|
1092
|
-
createWorker
|
|
1098
|
+
createWorker,
|
|
1099
|
+
isCurrentDocument
|
|
1093
1100
|
]);
|
|
1094
1101
|
return state;
|
|
1095
1102
|
}
|
|
@@ -2174,7 +2181,7 @@ var CellView = memo(function CellView({ cell, style, covered = false, isFirstRow
|
|
|
2174
2181
|
borderLeft: covered ? void 0 : isFirstCol ? css.borderLeft ?? DEFAULT_GRID_LINE : css.borderLeft
|
|
2175
2182
|
};
|
|
2176
2183
|
return /* @__PURE__ */ jsx("div", {
|
|
2177
|
-
className: "absolute px-1 text-
|
|
2184
|
+
className: "absolute px-1 text-sm text-foreground",
|
|
2178
2185
|
style: finalCss,
|
|
2179
2186
|
children: cell && /* @__PURE__ */ jsx("span", {
|
|
2180
2187
|
className: cn(cell.formulaState === "unevaluated" && "text-muted-foreground italic"),
|
|
@@ -2208,7 +2215,7 @@ var SelectedCellOverlay = ({ cell, style, rect }) => {
|
|
|
2208
2215
|
};
|
|
2209
2216
|
return /* @__PURE__ */ jsx("div", {
|
|
2210
2217
|
"data-testid": "xlsx-grid-selected-overlay",
|
|
2211
|
-
className: "z-10 px-1 text-
|
|
2218
|
+
className: "z-10 px-1 text-sm text-foreground shadow-md outline outline-primary",
|
|
2212
2219
|
style: finalCss,
|
|
2213
2220
|
children: cell && /* @__PURE__ */ jsx("span", {
|
|
2214
2221
|
className: cn(cell.formulaState === "unevaluated" && "text-muted-foreground italic"),
|
|
@@ -2221,7 +2228,7 @@ var SelectedCellOverlay = ({ cell, style, rect }) => {
|
|
|
2221
2228
|
var UnsupportedChartPlaceholder = ({ chart }) => {
|
|
2222
2229
|
const { t } = useTranslation();
|
|
2223
2230
|
return /* @__PURE__ */ jsxs("div", {
|
|
2224
|
-
className: "flex h-full w-full flex-col items-center justify-center gap-1 rounded-md border border-
|
|
2231
|
+
className: "text-muted-foreground flex h-full w-full flex-col items-center justify-center gap-1 rounded-md border border-dashed border-border text-center text-xs",
|
|
2225
2232
|
children: [/* @__PURE__ */ jsx("span", { children: t("xlsx_preview.chart_unsupported") }), chart.rawTypeName && /* @__PURE__ */ jsx("span", { children: chart.rawTypeName })]
|
|
2226
2233
|
});
|
|
2227
2234
|
};
|
|
@@ -2294,6 +2301,20 @@ var XlsxGrid = ({ sheet, styles, imageUrls, zoom, onSelectCell, pickerActive, re
|
|
|
2294
2301
|
estimateSize: (index) => colLayout.sizes[index] * zoom,
|
|
2295
2302
|
overscan: OVERSCAN
|
|
2296
2303
|
});
|
|
2304
|
+
useLayoutEffect(() => {
|
|
2305
|
+
rowVirtualizer.measure();
|
|
2306
|
+
}, [
|
|
2307
|
+
rowVirtualizer,
|
|
2308
|
+
rowLayout,
|
|
2309
|
+
zoom
|
|
2310
|
+
]);
|
|
2311
|
+
useLayoutEffect(() => {
|
|
2312
|
+
colVirtualizer.measure();
|
|
2313
|
+
}, [
|
|
2314
|
+
colVirtualizer,
|
|
2315
|
+
colLayout,
|
|
2316
|
+
zoom
|
|
2317
|
+
]);
|
|
2297
2318
|
const virtualRows = rowVirtualizer.getVirtualItems();
|
|
2298
2319
|
const virtualCols = colVirtualizer.getVirtualItems();
|
|
2299
2320
|
const readViewport = useCallback((el) => ({
|
|
@@ -2408,6 +2429,12 @@ var XlsxGrid = ({ sheet, styles, imageUrls, zoom, onSelectCell, pickerActive, re
|
|
|
2408
2429
|
commitSelection(null);
|
|
2409
2430
|
}, [applySelection, commitSelection]);
|
|
2410
2431
|
const pickerWasActiveRef = useRef(false);
|
|
2432
|
+
const previousSheetRef = useRef(sheet);
|
|
2433
|
+
useEffect(() => {
|
|
2434
|
+
if (previousSheetRef.current === sheet) return;
|
|
2435
|
+
previousSheetRef.current = sheet;
|
|
2436
|
+
clearSelection();
|
|
2437
|
+
}, [sheet, clearSelection]);
|
|
2411
2438
|
useEffect(() => {
|
|
2412
2439
|
const isActive = Boolean(pickerActive);
|
|
2413
2440
|
if (pickerWasActiveRef.current === isActive) return;
|
|
@@ -2778,7 +2805,7 @@ var XlsxGrid = ({ sheet, styles, imageUrls, zoom, onSelectCell, pickerActive, re
|
|
|
2778
2805
|
className: "absolute",
|
|
2779
2806
|
style: zoomTransform,
|
|
2780
2807
|
children: virtualCols.map((vc) => /* @__PURE__ */ jsx("div", {
|
|
2781
|
-
className: "absolute flex items-center justify-center border-
|
|
2808
|
+
className: "text-muted-foreground absolute flex items-center justify-center border-r border-border text-xs",
|
|
2782
2809
|
style: {
|
|
2783
2810
|
left: axisOffset(colLayout, vc.index),
|
|
2784
2811
|
width: colLayout.sizes[vc.index],
|
|
@@ -2800,7 +2827,7 @@ var XlsxGrid = ({ sheet, styles, imageUrls, zoom, onSelectCell, pickerActive, re
|
|
|
2800
2827
|
className: "absolute",
|
|
2801
2828
|
style: zoomTransform,
|
|
2802
2829
|
children: virtualRows.map((vr) => /* @__PURE__ */ jsx("div", {
|
|
2803
|
-
className: "absolute flex items-center justify-center border-
|
|
2830
|
+
className: "text-muted-foreground absolute flex items-center justify-center border-b border-border text-xs",
|
|
2804
2831
|
style: {
|
|
2805
2832
|
top: axisOffset(rowLayout, vr.index),
|
|
2806
2833
|
height: rowLayout.sizes[vr.index],
|
|
@@ -3039,23 +3066,21 @@ function SpreadsheetFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
3039
3066
|
const [selectedCell, setSelectedCell] = useState(null);
|
|
3040
3067
|
const [chartRenderer, setChartRenderer] = useState(null);
|
|
3041
3068
|
const [imageUrls, setImageUrls] = useState({});
|
|
3042
|
-
const model =
|
|
3069
|
+
const model = "model" in state ? state.model : null;
|
|
3043
3070
|
const sheets = useMemo(() => model ? visibleSheets(model) : [], [model]);
|
|
3044
3071
|
const activeSheet = sheets.find((sheet) => sheet.name === activeSheetName) ?? sheets[0] ?? null;
|
|
3045
3072
|
useEffect(() => {
|
|
3046
3073
|
setSelectedCell(null);
|
|
3047
|
-
if (sheets.length === 0)
|
|
3048
|
-
setActiveSheetName(null);
|
|
3049
|
-
return;
|
|
3050
|
-
}
|
|
3074
|
+
if (sheets.length === 0) return;
|
|
3051
3075
|
if (!sheets.some((sheet) => sheet.name === activeSheetName)) setActiveSheetName(sheets[0].name);
|
|
3052
3076
|
}, [sheets, activeSheetName]);
|
|
3053
3077
|
const handleSelectCell = useCallback((info) => setSelectedCell(info && activeSheet ? {
|
|
3054
3078
|
...info,
|
|
3055
|
-
sheet: activeSheet
|
|
3056
|
-
|
|
3079
|
+
sheet: activeSheet,
|
|
3080
|
+
document: previewDocument
|
|
3081
|
+
} : null), [activeSheet, previewDocument]);
|
|
3057
3082
|
const selectionReference = useMemo(() => {
|
|
3058
|
-
if (!selectedCell || !activeSheet || selectedCell.sheet !== activeSheet) return null;
|
|
3083
|
+
if (state.status !== "ready" || !selectedCell || !activeSheet || selectedCell.sheet !== activeSheet || selectedCell.document !== previewDocument) return null;
|
|
3059
3084
|
return createPreviewSelection({
|
|
3060
3085
|
sourceId,
|
|
3061
3086
|
anchor: {
|
|
@@ -3070,7 +3095,8 @@ function SpreadsheetFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
3070
3095
|
selectedCell,
|
|
3071
3096
|
activeSheet,
|
|
3072
3097
|
sourceId,
|
|
3073
|
-
previewDocument
|
|
3098
|
+
previewDocument,
|
|
3099
|
+
state.status
|
|
3074
3100
|
]);
|
|
3075
3101
|
const captureArmedRef = useRef(false);
|
|
3076
3102
|
useEffect(() => {
|
|
@@ -3129,9 +3155,9 @@ function SpreadsheetFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
3129
3155
|
});
|
|
3130
3156
|
}, []);
|
|
3131
3157
|
let content;
|
|
3132
|
-
if (state.status === "loading" || state.status === "idle") content = /* @__PURE__ */ jsxs("div", {
|
|
3158
|
+
if (state.status === "loading" && !model || state.status === "idle") content = /* @__PURE__ */ jsxs("div", {
|
|
3133
3159
|
role: "status",
|
|
3134
|
-
className: "flex h-full w-full items-center justify-center gap-2 bg-background text-
|
|
3160
|
+
className: "text-muted-foreground flex h-full w-full items-center justify-center gap-2 bg-background text-sm",
|
|
3135
3161
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
3136
3162
|
className: "size-4 animate-spin",
|
|
3137
3163
|
"aria-hidden": true
|
|
@@ -3159,13 +3185,14 @@ function SpreadsheetFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
3159
3185
|
className: "relative flex h-full w-full flex-col overflow-hidden bg-background",
|
|
3160
3186
|
children: [/* @__PURE__ */ jsx("div", {
|
|
3161
3187
|
className: "min-h-0 flex-1",
|
|
3188
|
+
inert: state.status !== "ready",
|
|
3162
3189
|
children: /* @__PURE__ */ jsx(XlsxGrid_default, {
|
|
3163
3190
|
sheet: activeSheet,
|
|
3164
3191
|
styles: model.styles,
|
|
3165
3192
|
imageUrls,
|
|
3166
3193
|
zoom,
|
|
3167
3194
|
onSelectCell: handleSelectCell,
|
|
3168
|
-
pickerActive: onSelection !== void 0,
|
|
3195
|
+
pickerActive: state.status === "ready" && onSelection !== void 0,
|
|
3169
3196
|
renderChart
|
|
3170
3197
|
}, activeSheet.name)
|
|
3171
3198
|
}), /* @__PURE__ */ jsxs("div", {
|
|
@@ -3189,9 +3216,9 @@ function SpreadsheetFilePreview({ sourceId, fileName, document: previewDocument,
|
|
|
3189
3216
|
})
|
|
3190
3217
|
}),
|
|
3191
3218
|
/* @__PURE__ */ jsxs("div", {
|
|
3192
|
-
className: "flex min-w-0 flex-1 items-center justify-end gap-2 text-
|
|
3219
|
+
className: "text-muted-foreground flex min-w-0 flex-1 items-center justify-end gap-2 text-xs",
|
|
3193
3220
|
children: [statusBarText ? /* @__PURE__ */ jsx("span", {
|
|
3194
|
-
className: "selectable cursor-text select-text
|
|
3221
|
+
className: "selectable cursor-text truncate select-text",
|
|
3195
3222
|
"data-testid": "xlsx-preview-status-bar",
|
|
3196
3223
|
children: statusBarText
|
|
3197
3224
|
}) : null, cellOnActiveSheet?.cell?.formulaState === "unevaluated" ? /* @__PURE__ */ jsx("span", {
|
|
@@ -3836,7 +3836,7 @@ function sanitizeHyperlinks(body) {
|
|
|
3836
3836
|
});
|
|
3837
3837
|
}
|
|
3838
3838
|
function WordFilePreview({ sourceId, fileName, document: previewDocument, onSelection }) {
|
|
3839
|
-
const { options, failDocument } = usePreviewHost();
|
|
3839
|
+
const { options, failDocument, isCurrentDocument } = usePreviewHost();
|
|
3840
3840
|
const { t } = useTranslation();
|
|
3841
3841
|
const docxClassName = `docx-preview-${useId().replace(/[^a-zA-Z0-9_-]/g, "")}`;
|
|
3842
3842
|
const containerRef = useRef(null);
|
|
@@ -3853,7 +3853,10 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
3853
3853
|
const [zoom, setZoom] = useState(DOCX_PREVIEW_DEFAULT_ZOOM);
|
|
3854
3854
|
const [fitZoom, setFitZoom] = useState(DOCX_PREVIEW_DEFAULT_ZOOM);
|
|
3855
3855
|
const [manualZoom, setManualZoom] = useState(false);
|
|
3856
|
-
const
|
|
3856
|
+
const normalizeSymbolBulletsRef = useRef(options?.docx?.normalizeSymbolBullets === true);
|
|
3857
|
+
useLayoutEffect(() => {
|
|
3858
|
+
normalizeSymbolBulletsRef.current = options?.docx?.normalizeSymbolBullets === true;
|
|
3859
|
+
}, [options?.docx?.normalizeSymbolBullets]);
|
|
3857
3860
|
const fitWidth = options?.docx?.initialZoom === "fit-width";
|
|
3858
3861
|
const minZoom = fitWidth ? Math.min(DOCX_PREVIEW_MIN_ZOOM, fitZoom) : DOCX_PREVIEW_MIN_ZOOM;
|
|
3859
3862
|
useLayoutEffect(() => {
|
|
@@ -3923,16 +3926,10 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
3923
3926
|
if (!bodyContainer || !styleContainer) return;
|
|
3924
3927
|
const controller = new AbortController();
|
|
3925
3928
|
const token = ++renderTokenRef.current;
|
|
3926
|
-
const isCurrent = () => renderTokenRef.current === token;
|
|
3929
|
+
const isCurrent = () => renderTokenRef.current === token && isCurrentDocument?.() !== false;
|
|
3930
|
+
const normalizeSymbolBullets = normalizeSymbolBulletsRef.current;
|
|
3927
3931
|
setError(null);
|
|
3928
3932
|
setLoading(true);
|
|
3929
|
-
setCurrentPage(0);
|
|
3930
|
-
setPageCount(0);
|
|
3931
|
-
setZoom(DOCX_PREVIEW_DEFAULT_ZOOM);
|
|
3932
|
-
setFitZoom(DOCX_PREVIEW_DEFAULT_ZOOM);
|
|
3933
|
-
setManualZoom(false);
|
|
3934
|
-
fitScrollTopRef.current = null;
|
|
3935
|
-
pinchAnchorRef.current = null;
|
|
3936
3933
|
const stagingHost = document.createElement("div");
|
|
3937
3934
|
const stagingBody = document.createElement("div");
|
|
3938
3935
|
const stagingStyle = document.createElement("div");
|
|
@@ -3967,11 +3964,17 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
3967
3964
|
page.classList.add("docx-preview-page", "docx-preview");
|
|
3968
3965
|
});
|
|
3969
3966
|
sanitizeHyperlinks(stagingBody);
|
|
3967
|
+
const scrollTop = containerRef.current?.scrollTop ?? 0;
|
|
3968
|
+
const scrollLeft = containerRef.current?.scrollLeft ?? 0;
|
|
3970
3969
|
bodyContainer.replaceChildren(...stagingBody.childNodes);
|
|
3971
3970
|
styleContainer.replaceChildren(...stagingStyle.childNodes);
|
|
3971
|
+
if (containerRef.current) {
|
|
3972
|
+
containerRef.current.scrollTop = scrollTop;
|
|
3973
|
+
containerRef.current.scrollLeft = scrollLeft;
|
|
3974
|
+
}
|
|
3972
3975
|
const nextPageCount = Math.max(pages.length, 1);
|
|
3973
3976
|
setPageCount(nextPageCount);
|
|
3974
|
-
setCurrentPage(
|
|
3977
|
+
setCurrentPage((page) => clamp(page, 1, nextPageCount));
|
|
3975
3978
|
focusContainer();
|
|
3976
3979
|
} catch (loadError) {
|
|
3977
3980
|
if (!isCurrent()) return;
|
|
@@ -3986,8 +3989,6 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
3986
3989
|
return () => {
|
|
3987
3990
|
controller.abort();
|
|
3988
3991
|
renderTokenRef.current += 1;
|
|
3989
|
-
bodyContainer.innerHTML = "";
|
|
3990
|
-
styleContainer.innerHTML = "";
|
|
3991
3992
|
stagingHost.remove();
|
|
3992
3993
|
};
|
|
3993
3994
|
}, [
|
|
@@ -3996,12 +3997,12 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
3996
3997
|
previewDocument,
|
|
3997
3998
|
failDocument,
|
|
3998
3999
|
docxClassName,
|
|
3999
|
-
|
|
4000
|
+
isCurrentDocument
|
|
4000
4001
|
]);
|
|
4001
4002
|
useEffect(() => {
|
|
4002
4003
|
const scrollRoot = containerRef.current;
|
|
4003
4004
|
const bodyContainer = bodyRef.current;
|
|
4004
|
-
if (!scrollRoot || !bodyContainer || pageCount <= 0) return;
|
|
4005
|
+
if (!scrollRoot || !bodyContainer || pageCount <= 0 || loading) return;
|
|
4005
4006
|
const pages = Array.from(bodyContainer.querySelectorAll(".docx-preview-page"));
|
|
4006
4007
|
if (pages.length === 0) return;
|
|
4007
4008
|
const visiblePages = /* @__PURE__ */ new Set();
|
|
@@ -4024,7 +4025,7 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
4024
4025
|
});
|
|
4025
4026
|
pages.forEach((page) => observer.observe(page));
|
|
4026
4027
|
return () => observer.disconnect();
|
|
4027
|
-
}, [pageCount]);
|
|
4028
|
+
}, [pageCount, loading]);
|
|
4028
4029
|
const handlePick = useCallback((event) => {
|
|
4029
4030
|
if (!onSelection || !(event.target instanceof Element)) return;
|
|
4030
4031
|
if (event.target.closest("a[href]")) event.preventDefault();
|
|
@@ -4107,12 +4108,12 @@ function WordFilePreview({ sourceId, fileName, document: previewDocument, onSele
|
|
|
4107
4108
|
"data-picker": onSelection ? "true" : void 0,
|
|
4108
4109
|
onClick: handlePick,
|
|
4109
4110
|
style: contentStyle,
|
|
4110
|
-
className: "mx-auto w-fit min-w-0 [&
|
|
4111
|
+
className: "mx-auto w-fit min-w-0 [&_.docx-preview]:box-border [&_.docx-preview]:max-w-full [&_.docx-preview-wrapper]:mx-auto [&_p[data-docx-picked=true]]:bg-primary/15 [&_p[data-docx-picked=true]]:outline [&_p[data-docx-picked=true]]:outline-1 [&_p[data-docx-picked=true]]:outline-primary/60 [&_section]:overflow-hidden [&_section]:rounded-sm [&_section]:shadow-md [&[data-picker=true]_p[data-docx-part=body]]:cursor-pointer [&[data-picker=true]_p[data-docx-part=body]:not([data-docx-picked=true]):hover]:bg-primary/10"
|
|
4111
4112
|
})]
|
|
4112
4113
|
}),
|
|
4113
4114
|
loading ? /* @__PURE__ */ jsxs("div", {
|
|
4114
4115
|
role: "status",
|
|
4115
|
-
className: "absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm
|
|
4116
|
+
className: "text-muted-foreground absolute inset-0 flex items-center justify-center gap-2 bg-background text-sm",
|
|
4116
4117
|
children: [/* @__PURE__ */ jsx(LoaderCircle, {
|
|
4117
4118
|
className: "size-4 animate-spin",
|
|
4118
4119
|
"aria-hidden": true
|
|
@@ -23,7 +23,7 @@ var imageFilePreviewPlugin = {
|
|
|
23
23
|
"image/vnd.microsoft.icon",
|
|
24
24
|
"image/svg+xml"
|
|
25
25
|
],
|
|
26
|
-
load: () => import("./ImageFilePreview-
|
|
26
|
+
load: () => import("./ImageFilePreview-C_P1iIEi.js")
|
|
27
27
|
};
|
|
28
28
|
//#endregion
|
|
29
29
|
export { imageFilePreviewPlugin as t };
|
package/dist/react.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { n as assertPreviewRange, t as PreviewError } from "./source-Rx3etU3y.js";
|
|
2
2
|
import { a as usePreviewHost, c as FilePreviewToolbarPortalHost, d as EmptyState, g as createLucideIcon, h as FileWarning, i as PreviewHostContext, l as FilePreviewToolbarPortalProvider, m as LoaderCircle, n as I18nContext, p as cn, r as FilePreviewLayout, s as FilePreviewToolbar, t as useTranslation } from "./useTranslation-BJY4EKsz.js";
|
|
3
3
|
import { n as DialogPortalContainerProvider, r as PortalContainerProvider, t as FilePreviewToolbarButton } from "./FilePreviewToolbarButton-ptqwCTnz.js";
|
|
4
|
-
import { t as imageFilePreviewPlugin } from "./imageFilePreviewPlugin-
|
|
5
|
-
import { Component, Suspense, createContext, createElement, lazy, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
4
|
+
import { t as imageFilePreviewPlugin } from "./imageFilePreviewPlugin-D6hV1Hm1.js";
|
|
5
|
+
import { Component, Suspense, createContext, createElement, lazy, useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState } from "react";
|
|
6
6
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
7
|
/**
|
|
8
8
|
* @license lucide-react v0.545.0 - ISC
|
|
@@ -32,14 +32,14 @@ var plugins = [
|
|
|
32
32
|
id: "pdf",
|
|
33
33
|
extensions: ["pdf"],
|
|
34
34
|
mediaTypes: ["application/pdf"],
|
|
35
|
-
load: () => import("./PdfFilePreview-
|
|
35
|
+
load: () => import("./PdfFilePreview-CbrMcPzo.js"),
|
|
36
36
|
supportsSelectionReference: true
|
|
37
37
|
},
|
|
38
38
|
{
|
|
39
39
|
id: "powerpoint",
|
|
40
40
|
extensions: ["pptx"],
|
|
41
41
|
mediaTypes: ["application/vnd.openxmlformats-officedocument.presentationml.presentation"],
|
|
42
|
-
load: () => import("./PowerPointFilePreview-
|
|
42
|
+
load: () => import("./PowerPointFilePreview-9E6kUy_A.js"),
|
|
43
43
|
supportsSelectionReference: true
|
|
44
44
|
},
|
|
45
45
|
{
|
|
@@ -56,14 +56,14 @@ var plugins = [
|
|
|
56
56
|
id: "spreadsheet",
|
|
57
57
|
extensions: ["xlsx"],
|
|
58
58
|
mediaTypes: ["application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"],
|
|
59
|
-
load: () => import("./SpreadsheetFilePreview-
|
|
59
|
+
load: () => import("./SpreadsheetFilePreview-PWFG3UY3.js"),
|
|
60
60
|
supportsSelectionReference: true
|
|
61
61
|
},
|
|
62
62
|
{
|
|
63
63
|
id: "word",
|
|
64
64
|
extensions: ["docx"],
|
|
65
65
|
mediaTypes: ["application/vnd.openxmlformats-officedocument.wordprocessingml.document"],
|
|
66
|
-
load: () => import("./WordFilePreview-
|
|
66
|
+
load: () => import("./WordFilePreview-hfALJk2N.js"),
|
|
67
67
|
supportsSelectionReference: true
|
|
68
68
|
}
|
|
69
69
|
];
|
|
@@ -2670,6 +2670,42 @@ var catalogs = {
|
|
|
2670
2670
|
"xlsx_preview.formula_not_evaluated": "Impossible d’évaluer la formule",
|
|
2671
2671
|
"xlsx_preview.sheet_tabs_label": "Feuilles"
|
|
2672
2672
|
},
|
|
2673
|
+
"it-it": {
|
|
2674
|
+
"common.close": "Chiudi",
|
|
2675
|
+
"common.loading": "Caricamento...",
|
|
2676
|
+
"common.next": "Avanti",
|
|
2677
|
+
"common.previous": "Indietro",
|
|
2678
|
+
"file_preview.load_error.description": "Impossibile caricare il contenuto dell'anteprima.",
|
|
2679
|
+
"file_preview.load_error.title": "Anteprima non riuscita",
|
|
2680
|
+
"file_preview.loading": "Caricamento dell'anteprima...",
|
|
2681
|
+
"file_preview.pdf.outline.empty": "Questo PDF non contiene un indice.",
|
|
2682
|
+
"file_preview.pdf.outline.load_error": "Impossibile caricare l'indice.",
|
|
2683
|
+
"file_preview.pdf.outline.title": "Indice",
|
|
2684
|
+
"file_preview.pdf.page_number": "Numero di pagina",
|
|
2685
|
+
"file_preview.pdf.too_large.description": "Una parte di questo PDF è troppo grande per visualizzarne l'anteprima in modo sicuro nell'app.",
|
|
2686
|
+
"file_preview.pdf.too_large.title": "Impossibile visualizzare l'anteprima di questo PDF",
|
|
2687
|
+
"file_preview.powerpoint.zip_limit.description": "Questo file PowerPoint supera i limiti di sicurezza dell'app per l'anteprima.",
|
|
2688
|
+
"file_preview.powerpoint.zip_limit.title": "Impossibile visualizzare l'anteprima di questo file PowerPoint",
|
|
2689
|
+
"file_preview.too_large.action": "Apri con l'app predefinita",
|
|
2690
|
+
"file_preview.too_large.description": "La dimensione del file {{size}} supera il limite di {{limit}} per l'anteprima.",
|
|
2691
|
+
"file_preview.too_large.title": "File troppo grande per l'anteprima",
|
|
2692
|
+
"file_preview.unsupported.action": "Apri con l'app predefinita",
|
|
2693
|
+
"file_preview.unsupported.description": "L'anteprima di questo tipo di file non è ancora supportata.",
|
|
2694
|
+
"file_preview.unsupported.title": "Anteprima non disponibile",
|
|
2695
|
+
"preview.flip_horizontal": "Rifletti orizzontalmente",
|
|
2696
|
+
"preview.flip_vertical": "Rifletti verticalmente",
|
|
2697
|
+
"preview.label": "Anteprima",
|
|
2698
|
+
"preview.reset": "Reimposta",
|
|
2699
|
+
"preview.rotate_left": "Ruota a sinistra",
|
|
2700
|
+
"preview.rotate_right": "Ruota a destra",
|
|
2701
|
+
"preview.zoom_in": "Ingrandisci",
|
|
2702
|
+
"preview.zoom_out": "Riduci",
|
|
2703
|
+
"xlsx_preview.chart": "Grafico",
|
|
2704
|
+
"xlsx_preview.chart_unsupported": "Questo tipo di grafico non è ancora supportato",
|
|
2705
|
+
"xlsx_preview.error.description": "Impossibile visualizzare l'anteprima di questo foglio di calcolo.",
|
|
2706
|
+
"xlsx_preview.formula_not_evaluated": "Impossibile valutare la formula",
|
|
2707
|
+
"xlsx_preview.sheet_tabs_label": "Fogli"
|
|
2708
|
+
},
|
|
2673
2709
|
"ja-jp": {
|
|
2674
2710
|
"common.close": "閉じる",
|
|
2675
2711
|
"common.loading": "読み込み中...",
|
|
@@ -3008,6 +3044,8 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3008
3044
|
const [session, setSession] = useState(null);
|
|
3009
3045
|
const [failure, setFailure] = useState(null);
|
|
3010
3046
|
const closeRef = useRef(void 0);
|
|
3047
|
+
const plugin = useMemo(() => resolvePreviewPlugin(source.name, source.mediaType), [source.name, source.mediaType]);
|
|
3048
|
+
const Plugin = useMemo(() => plugin ? lazy(plugin.load) : null, [plugin]);
|
|
3011
3049
|
const hasFailedRef = useRef(false);
|
|
3012
3050
|
const callbacks = useRef({
|
|
3013
3051
|
onSelection,
|
|
@@ -3021,7 +3059,7 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3021
3059
|
onError,
|
|
3022
3060
|
onRequestOpen
|
|
3023
3061
|
};
|
|
3024
|
-
const
|
|
3062
|
+
const reportFailure = useCallback((error) => {
|
|
3025
3063
|
if (hasFailedRef.current) return;
|
|
3026
3064
|
hasFailedRef.current = true;
|
|
3027
3065
|
closeRef.current?.();
|
|
@@ -3035,7 +3073,24 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3035
3073
|
});
|
|
3036
3074
|
callbacks.current.onError?.(normalized);
|
|
3037
3075
|
}, []);
|
|
3038
|
-
const
|
|
3076
|
+
const requestIdRef = useRef(0);
|
|
3077
|
+
useLayoutEffect(() => {
|
|
3078
|
+
requestIdRef.current += 1;
|
|
3079
|
+
return () => {
|
|
3080
|
+
requestIdRef.current += 1;
|
|
3081
|
+
};
|
|
3082
|
+
}, [
|
|
3083
|
+
source,
|
|
3084
|
+
refreshKey,
|
|
3085
|
+
plugin
|
|
3086
|
+
]);
|
|
3087
|
+
const isCurrentSession = useCallback(() => session?.requestId === requestIdRef.current, [session]);
|
|
3088
|
+
const failDocument = useCallback((error) => {
|
|
3089
|
+
if (isCurrentSession()) reportFailure(error);
|
|
3090
|
+
}, [isCurrentSession, reportFailure]);
|
|
3091
|
+
const reportSelection = useCallback((selection) => {
|
|
3092
|
+
if (isCurrentSession()) callbacks.current.onSelection?.(selection);
|
|
3093
|
+
}, [isCurrentSession]);
|
|
3039
3094
|
const reportDiagnostic = useCallback((diagnostic) => callbacks.current.onDiagnostic?.(diagnostic), []);
|
|
3040
3095
|
const requestOpen = useCallback((reason) => callbacks.current.onRequestOpen?.(reason), []);
|
|
3041
3096
|
const hasOpenAction = onRequestOpen !== void 0;
|
|
@@ -3045,7 +3100,8 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3045
3100
|
options,
|
|
3046
3101
|
onDiagnostic: reportDiagnostic,
|
|
3047
3102
|
onRequestOpen: hasOpenAction ? requestOpen : void 0,
|
|
3048
|
-
failDocument
|
|
3103
|
+
failDocument,
|
|
3104
|
+
isCurrentDocument: isCurrentSession
|
|
3049
3105
|
}), [
|
|
3050
3106
|
root,
|
|
3051
3107
|
resources,
|
|
@@ -3053,15 +3109,14 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3053
3109
|
reportDiagnostic,
|
|
3054
3110
|
requestOpen,
|
|
3055
3111
|
hasOpenAction,
|
|
3056
|
-
failDocument
|
|
3112
|
+
failDocument,
|
|
3113
|
+
isCurrentSession
|
|
3057
3114
|
]);
|
|
3058
|
-
const plugin = useMemo(() => resolvePreviewPlugin(source.name, source.mediaType), [source.name, source.mediaType]);
|
|
3059
|
-
const Plugin = useMemo(() => plugin ? lazy(plugin.load) : null, [plugin]);
|
|
3060
3115
|
useEffect(() => {
|
|
3061
|
-
setSession(null);
|
|
3062
3116
|
setFailure(null);
|
|
3063
3117
|
hasFailedRef.current = false;
|
|
3064
3118
|
if (!plugin) return;
|
|
3119
|
+
const requestId = requestIdRef.current;
|
|
3065
3120
|
const controller = new AbortController();
|
|
3066
3121
|
let opened = null;
|
|
3067
3122
|
let closed = false;
|
|
@@ -3086,8 +3141,9 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3086
3141
|
assertPreviewRange(opened.size, 0, opened.size);
|
|
3087
3142
|
setSession({
|
|
3088
3143
|
source,
|
|
3089
|
-
|
|
3090
|
-
document: opened
|
|
3144
|
+
requestId,
|
|
3145
|
+
document: opened,
|
|
3146
|
+
plugin
|
|
3091
3147
|
});
|
|
3092
3148
|
} catch (error) {
|
|
3093
3149
|
close();
|
|
@@ -3096,7 +3152,7 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3096
3152
|
source,
|
|
3097
3153
|
refreshKey
|
|
3098
3154
|
});
|
|
3099
|
-
|
|
3155
|
+
reportFailure(error);
|
|
3100
3156
|
}
|
|
3101
3157
|
})();
|
|
3102
3158
|
return () => {
|
|
@@ -3108,9 +3164,9 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3108
3164
|
source,
|
|
3109
3165
|
refreshKey,
|
|
3110
3166
|
plugin,
|
|
3111
|
-
|
|
3167
|
+
reportFailure
|
|
3112
3168
|
]);
|
|
3113
|
-
const ready = session?.source === source && session.
|
|
3169
|
+
const ready = session?.source.id === source.id && session.plugin === plugin ? session : null;
|
|
3114
3170
|
const failed = failure?.source === source && failure.refreshKey === refreshKey;
|
|
3115
3171
|
const content = !Plugin ? /* @__PURE__ */ jsx(PreviewState, { kind: "unsupported" }) : failed ? /* @__PURE__ */ jsx(PreviewState, { kind: "error" }) : !ready ? /* @__PURE__ */ jsx(PreviewState, { kind: "loading" }) : /* @__PURE__ */ jsx(m, {
|
|
3116
3172
|
resetKeys: [ready.document],
|
|
@@ -3119,14 +3175,14 @@ function PreviewSession({ source, header, className, style, refreshKey = 0, reso
|
|
|
3119
3175
|
children: /* @__PURE__ */ jsx(Suspense, {
|
|
3120
3176
|
fallback: /* @__PURE__ */ jsx(PreviewState, { kind: "loading" }),
|
|
3121
3177
|
children: /* @__PURE__ */ jsx(Plugin, {
|
|
3122
|
-
sourceId: source.id,
|
|
3123
|
-
fileName: source.name,
|
|
3124
|
-
mediaType: source.mediaType,
|
|
3178
|
+
sourceId: ready.source.id,
|
|
3179
|
+
fileName: ready.source.name,
|
|
3180
|
+
mediaType: ready.source.mediaType,
|
|
3125
3181
|
document: ready.document,
|
|
3126
3182
|
onSelection: onSelection ? reportSelection : void 0
|
|
3127
|
-
}
|
|
3183
|
+
})
|
|
3128
3184
|
})
|
|
3129
|
-
}, `${source.id}:${
|
|
3185
|
+
}, `${source.id}:${plugin?.id}`);
|
|
3130
3186
|
return /* @__PURE__ */ jsx("div", {
|
|
3131
3187
|
ref: setRoot,
|
|
3132
3188
|
"data-file-preview-root": "",
|