@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 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 all 13 desktop
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-Cif3MLQd.js";
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: () => setStatus("ready"),
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
- if (container.clientWidth > 0 && viewer.currentScaleValue === DEFAULT_PDF_SCALE) viewer.currentScaleValue = DEFAULT_PDF_SCALE;
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 (cancelled || failed) return;
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) setZoom(nextScale);
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 (pdfViewerRef.current !== pdfViewer) return;
29603
- pdfViewer.currentScaleValue = DEFAULT_PDF_SCALE;
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 (pdfViewerRef.current !== pdfViewer) return;
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 text-muted-foreground",
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 (cancelled) return;
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 (!cancelled) setCurrentPage(index + 1);
57897
+ if (isCurrent()) setCurrentPage(index + 1);
57881
57898
  },
57882
57899
  onRenderStart: () => {
57883
- if (!cancelled) setPreviewControlsBusy(true);
57900
+ if (isCurrent()) setPreviewControlsBusy(true);
57884
57901
  },
57885
57902
  onRenderComplete: () => {
57886
- if (cancelled) return;
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 (cancelled) return;
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 (cancelled) return;
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 (cancelled) return;
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 (!cancelled) setLoading(false);
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 [&[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 [&[data-picker=true]_[data-slide-index]]:cursor-pointer [&_[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",
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 text-muted-foreground",
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({ status: "loading" });
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 (cancelled || requestId !== requestIdRef.current) return;
1003
+ if (!isCurrent()) return;
1000
1004
  bytes = raw.slice().buffer;
1001
1005
  } catch (error) {
1002
- if (cancelled || requestId !== requestIdRef.current) return;
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 (cancelled || requestId !== requestIdRef.current) return;
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 (cancelled || requestId !== requestIdRef.current) {
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 (cancelled || requestId !== requestIdRef.current) return;
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-foreground text-sm",
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-foreground text-sm shadow-md outline outline-primary",
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-border border-dashed text-center text-muted-foreground text-xs",
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-border border-r text-muted-foreground text-xs",
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-border border-b text-muted-foreground text-xs",
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 = state.status === "ready" ? state.model : null;
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
- } : null), [activeSheet]);
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.revision
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-muted-foreground text-sm",
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-muted-foreground text-xs",
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 truncate",
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 [normalizeSymbolBullets] = useState(() => options?.docx?.normalizeSymbolBullets === true);
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(nextPageCount > 0 ? 1 : 0);
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
- normalizeSymbolBullets
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 [&[data-picker=true]_p[data-docx-part=body]:not([data-docx-picked=true]):hover]:bg-primary/10 [&[data-picker=true]_p[data-docx-part=body]]:cursor-pointer [&_.docx-preview-wrapper]:mx-auto [&_.docx-preview]:box-border [&_.docx-preview]:max-w-full [&_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"
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 text-muted-foreground",
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-Cbw6HzIR.js")
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-Cif3MLQd.js";
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-DqnRzmwY.js"),
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-CO_N6c1I.js"),
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-GKeQwJL3.js"),
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-IfWcWbwn.js"),
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 failDocument = useCallback((error) => {
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 reportSelection = useCallback((selection) => callbacks.current.onSelection?.(selection), []);
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
- refreshKey,
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
- failDocument(error);
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
- failDocument
3167
+ reportFailure
3112
3168
  ]);
3113
- const ready = session?.source === source && session.refreshKey === refreshKey ? session : null;
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
- }, `${source.id}:${refreshKey}:${ready.document.revision}`)
3183
+ })
3128
3184
  })
3129
- }, `${source.id}:${refreshKey}:${ready.document.revision}`);
3185
+ }, `${source.id}:${plugin?.id}`);
3130
3186
  return /* @__PURE__ */ jsx("div", {
3131
3187
  ref: setRoot,
3132
3188
  "data-file-preview-root": "",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cherrystudio/file-preview",
3
- "version": "0.2.0",
3
+ "version": "0.2.2",
4
4
  "description": "Portable read-only document preview for Cherry Studio",
5
5
  "license": "AGPL-3.0-only",
6
6
  "repository": {