@file-viewer/core 3.3.0 → 3.3.3

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.en.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [English](https://github.com/flyfish-dev/file-viewer/blob/main/packages/core/README.md) · [简体中文](https://github.com/flyfish-dev/file-viewer/blob/main/packages/core/README.zh-CN.md)
4
4
 
5
+ Framework-neutral TypeScript APIs for browser-side file preview. Build a viewer in Vanilla JavaScript, or use the Vue, React, Svelte and jQuery components with the same loading, search, zoom, page navigation, print and export controls. Files are processed locally, without server-side conversion.
6
+
5
7
  <!-- FILE_VIEWER_PACKAGE_HEADER -->
6
8
  <p>
7
9
  <a href="https://www.npmjs.com/package/@file-viewer/core"><img src="https://img.shields.io/npm/v/@file-viewer%2Fcore?logo=npm" alt="npm version"></a>
@@ -20,20 +22,22 @@
20
22
 
21
23
  > ⭐ If File Viewer helps you, please [star the repo on GitHub](https://github.com/flyfish-dev/file-viewer).
22
24
 
23
- Framework-neutral TypeScript foundation for Flyfish File Viewer.
24
-
25
- This package is the migration base for the next architecture: one pure TypeScript core package with internal `headless`, `browser`, and `renderers` layers, plus multiple native standard component packages for Vue, React, pure JavaScript, jQuery, and Svelte. Core owns the shared format matrix, source detection, renderer protocol, capability calculation, lifecycle context, operation guards, operation/event/search/location/zoom/print/export contracts, heavy renderer asset manifests, option normalization, pure state models, and framework-neutral browser rendering engine.
25
+ File Viewer has a catalog of 275 file extensions through optional renderers. **This package is the lightweight foundation, not an all-format viewer.** Add only the engines your application needs; stable and experimental support are listed separately in the [format matrix](https://doc.file-viewer.app/guide/formats).
26
26
 
27
- Browser execution belongs inside core only when it remains framework-neutral TypeScript. DOM mounting, the standard browser shell and toolbar, `HTMLElement` traversal, search highlights, zoom provider discovery, print windows, download triggers, Canvas, Worker, and WASM renderers must not depend on Vue, React, Svelte, or any component package. Framework component packages keep their own component lifecycle, public type surface, compatibility defaults, and ecosystem interaction layer while depending on `@file-viewer/core` as the only shared base.
27
+ ## Start here
28
28
 
29
- `@file-viewer/core` is the only shared foundation package. It owns the headless contracts plus browser/renderers layers for the direct `createViewer(container, options)` engine, renderer registry, DOM provider registry, print layout helpers, browser asset resolution, and framework-neutral DOM/Canvas/Worker/WASM rendering contracts. Core source is public; the private Gitea aggregate remains available for the complete workspace, unified release automation, sponsorship, and priority support.
30
-
31
- Current framework-neutral browser renderers still inside core are limited to the low-cost image path. Spreadsheet rendering has moved to `@file-viewer/renderer-spreadsheet`; CAD rendering has moved to `@file-viewer/renderer-cad`; Typst rendering has moved to `@file-viewer/renderer-typst`; OFD rendering has moved to `@file-viewer/renderer-ofd`; PDF rendering has moved to `@file-viewer/renderer-pdf`; archive rendering has moved to `@file-viewer/renderer-archive`; email rendering has moved to `@file-viewer/renderer-email`; EPUB and UMD ebook rendering has moved to `@file-viewer/renderer-epub`; 3D model rendering has moved to `@file-viewer/renderer-3d`; Draw.io, Excalidraw, Mermaid, and PlantUML rendering has moved to `@file-viewer/renderer-drawing`; audio, video, HLS, and MIDI rendering has moved to `@file-viewer/renderer-media`; code, text, Markdown, patch, and git bundle rendering has moved to `@file-viewer/renderer-text`; Word DOCX/DOC/RTF/ODT rendering has moved to `@file-viewer/renderer-word`; PowerPoint rendering has moved to `@file-viewer/renderer-presentation`; XMind rendering has moved to `@file-viewer/renderer-mindmap`; geospatial rendering has moved to `@file-viewer/renderer-geo`; data asset rendering has moved to `@file-viewer/renderer-data`; EDA rendering and parsing has moved to `@file-viewer/renderer-eda`. Core-only installs now avoid direct OFD, PDF, Word, Spreadsheet, PPTX, CAD, Typst, XMind, Geo, media, 3D, drawing, archive, email, EPUB, UMD, data asset, EDA, `ofd-xml-parser`, `jszip`, `pdfjs-dist`, `styled-exceljs`, `e-virt-table`, `tinycolor2`, `@flyfish-dev/cad-viewer`, `@myriaddreamin/*`, `highlight.js`, `marked`, `diff2html`, `pako`, `mermaid`, `plantuml-encoder`, `@panzoom/panzoom`, `hls.js`, `@tonejs/midi`, `three`, `@excalidraw/excalidraw`, `roughjs`, `libarchive.js`, `postal-mime`, `@kenjiuno/msgreader`, `epubjs`, `ag-psd`, `sql.js`, `hyparquet`, `avsc`, and `cfb` engine dependencies.
29
+ - [Create a configured application](https://doc.file-viewer.app/guide/cli): `npm create file-viewer@latest my-viewer`.
30
+ - [Use a Web Component](https://doc.file-viewer.app/guide/quickstart-web), or choose a [framework integration](https://github.com/flyfish-dev/file-viewer#readme).
31
+ - For a custom integration, use `core/headless` for metadata and contracts, or `core/browser` for DOM rendering. PDF and Office require an explicit renderer or preset and local runtime assets.
32
32
 
33
33
  ```bash
34
34
  npm install @file-viewer/core
35
35
  ```
36
36
 
37
+ ## Browser source feedback (unreleased)
38
+
39
+ The browser `mountViewer` shell shows localized download feedback while buffering a URL, then reading feedback until the renderer takes over. File and buffer inputs use reading feedback. The status follows the configured locale/theme, reports acquisition failures, and is cleared when a source is replaced or the viewer is destroyed.
40
+
37
41
  ## Preflight Before Rendering
38
42
 
39
43
  `precheckFileViewerSource()` does not create a viewer or load a heavy renderer. It checks whether the extension is available and validates known PDF, OpenXML / OpenDocument, legacy OLE Office, and RTF signatures or package parts. `valid: null` explicitly means capability-only detection, not a full parse; the real renderer remains the final authority for malformed content.
@@ -71,10 +75,7 @@ const pdfAssets = resolveFileViewerRendererAssets('pdf', {
71
75
  Use `@file-viewer/core/browser` when a native component package or pure browser integration needs the shared browser shell and toolbar, direct DOM engine, renderer registry, search/zoom providers, print/export adapters, and framework-neutral Canvas/Worker/WASM renderers.
72
76
 
73
77
  ```ts
74
- import {
75
- createViewer,
76
- coreBrowserRendererHandlers
77
- } from '@file-viewer/core/browser'
78
+ import { createViewer } from '@file-viewer/core/browser'
78
79
 
79
80
  const viewer = createViewer(document.querySelector('#viewer')!, {
80
81
  options: {
@@ -83,7 +84,8 @@ const viewer = createViewer(document.querySelector('#viewer')!, {
83
84
  }
84
85
  })
85
86
 
86
- await viewer.load({ url: '/files/report.pdf' })
87
+ // Images use the built-in renderer; document formats need an optional preset.
88
+ await viewer.load({ url: '/files/photo.png' })
87
89
  ```
88
90
 
89
91
  Zoom buttons keep their positions and become disabled at their limits. Configure the existing `toolbar.items` map to hide reset controls while retaining the `resetZoom()` API. Set `pdf.zoomToolbar` to `false` to hide the PDF renderer's zoom group while keeping its page navigation and rotation controls:
@@ -149,8 +151,6 @@ Public source repositories:
149
151
  - GitHub: https://github.com/flyfish-dev/file-viewer-core
150
152
  - Gitee: https://gitee.com/flyfish-dev/file-viewer-core
151
153
 
152
- The GitHub/Gitee repositories are distributed public source packages. The private Gitea aggregate remains useful for the complete workspace, release automation, integration history, sponsorship, and priority support.
153
-
154
154
  License: Apache-2.0. For second development or commercial use, keep clear Flyfish Viewer attribution and contribute shared compatibility improvements where possible.
155
155
 
156
156
  ## Formats and related packages
package/README.md CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  [English](https://github.com/flyfish-dev/file-viewer/blob/main/packages/core/README.md) · [简体中文](https://github.com/flyfish-dev/file-viewer/blob/main/packages/core/README.zh-CN.md)
4
4
 
5
+ Framework-neutral TypeScript APIs for browser-side file preview. Build a viewer in Vanilla JavaScript, or use the Vue, React, Svelte and jQuery components with the same loading, search, zoom, page navigation, print and export controls. Files are processed locally, without server-side conversion.
6
+
5
7
  <!-- FILE_VIEWER_PACKAGE_HEADER -->
6
8
  <p>
7
9
  <a href="https://www.npmjs.com/package/@file-viewer/core"><img src="https://img.shields.io/npm/v/@file-viewer%2Fcore?logo=npm" alt="npm version"></a>
@@ -20,20 +22,22 @@
20
22
 
21
23
  > ⭐ If File Viewer helps you, please [star the repo on GitHub](https://github.com/flyfish-dev/file-viewer).
22
24
 
23
- Framework-neutral TypeScript foundation for Flyfish File Viewer.
24
-
25
- This package is the migration base for the next architecture: one pure TypeScript core package with internal `headless`, `browser`, and `renderers` layers, plus multiple native standard component packages for Vue, React, pure JavaScript, jQuery, and Svelte. Core owns the shared format matrix, source detection, renderer protocol, capability calculation, lifecycle context, operation guards, operation/event/search/location/zoom/print/export contracts, heavy renderer asset manifests, option normalization, pure state models, and framework-neutral browser rendering engine.
25
+ File Viewer has a catalog of 275 file extensions through optional renderers. **This package is the lightweight foundation, not an all-format viewer.** Add only the engines your application needs; stable and experimental support are listed separately in the [format matrix](https://doc.file-viewer.app/guide/formats).
26
26
 
27
- Browser execution belongs inside core only when it remains framework-neutral TypeScript. DOM mounting, the standard browser shell and toolbar, `HTMLElement` traversal, search highlights, zoom provider discovery, print windows, download triggers, Canvas, Worker, and WASM renderers must not depend on Vue, React, Svelte, or any component package. Framework component packages keep their own component lifecycle, public type surface, compatibility defaults, and ecosystem interaction layer while depending on `@file-viewer/core` as the only shared base.
27
+ ## Start here
28
28
 
29
- `@file-viewer/core` is the only shared foundation package. It owns the headless contracts plus browser/renderers layers for the direct `createViewer(container, options)` engine, renderer registry, DOM provider registry, print layout helpers, browser asset resolution, and framework-neutral DOM/Canvas/Worker/WASM rendering contracts. Core source is public; the private Gitea aggregate remains available for the complete workspace, unified release automation, sponsorship, and priority support.
30
-
31
- Current framework-neutral browser renderers still inside core are limited to the low-cost image path. Spreadsheet rendering has moved to `@file-viewer/renderer-spreadsheet`; CAD rendering has moved to `@file-viewer/renderer-cad`; Typst rendering has moved to `@file-viewer/renderer-typst`; OFD rendering has moved to `@file-viewer/renderer-ofd`; PDF rendering has moved to `@file-viewer/renderer-pdf`; archive rendering has moved to `@file-viewer/renderer-archive`; email rendering has moved to `@file-viewer/renderer-email`; EPUB and UMD ebook rendering has moved to `@file-viewer/renderer-epub`; 3D model rendering has moved to `@file-viewer/renderer-3d`; Draw.io, Excalidraw, Mermaid, and PlantUML rendering has moved to `@file-viewer/renderer-drawing`; audio, video, HLS, and MIDI rendering has moved to `@file-viewer/renderer-media`; code, text, Markdown, patch, and git bundle rendering has moved to `@file-viewer/renderer-text`; Word DOCX/DOC/RTF/ODT rendering has moved to `@file-viewer/renderer-word`; PowerPoint rendering has moved to `@file-viewer/renderer-presentation`; XMind rendering has moved to `@file-viewer/renderer-mindmap`; geospatial rendering has moved to `@file-viewer/renderer-geo`; data asset rendering has moved to `@file-viewer/renderer-data`; EDA rendering and parsing has moved to `@file-viewer/renderer-eda`. Core-only installs now avoid direct OFD, PDF, Word, Spreadsheet, PPTX, CAD, Typst, XMind, Geo, media, 3D, drawing, archive, email, EPUB, UMD, data asset, EDA, `ofd-xml-parser`, `jszip`, `pdfjs-dist`, `styled-exceljs`, `e-virt-table`, `tinycolor2`, `@flyfish-dev/cad-viewer`, `@myriaddreamin/*`, `highlight.js`, `marked`, `diff2html`, `pako`, `mermaid`, `plantuml-encoder`, `@panzoom/panzoom`, `hls.js`, `@tonejs/midi`, `three`, `@excalidraw/excalidraw`, `roughjs`, `libarchive.js`, `postal-mime`, `@kenjiuno/msgreader`, `epubjs`, `ag-psd`, `sql.js`, `hyparquet`, `avsc`, and `cfb` engine dependencies.
29
+ - [Create a configured application](https://doc.file-viewer.app/guide/cli): `npm create file-viewer@latest my-viewer`.
30
+ - [Use a Web Component](https://doc.file-viewer.app/guide/quickstart-web), or choose a [framework integration](https://github.com/flyfish-dev/file-viewer#readme).
31
+ - For a custom integration, use `core/headless` for metadata and contracts, or `core/browser` for DOM rendering. PDF and Office require an explicit renderer or preset and local runtime assets.
32
32
 
33
33
  ```bash
34
34
  npm install @file-viewer/core
35
35
  ```
36
36
 
37
+ ## Browser source feedback (unreleased)
38
+
39
+ The browser `mountViewer` shell shows localized download feedback while buffering a URL, then reading feedback until the renderer takes over. File and buffer inputs use reading feedback. The status follows the configured locale/theme, reports acquisition failures, and is cleared when a source is replaced or the viewer is destroyed.
40
+
37
41
  ## Preflight Before Rendering
38
42
 
39
43
  `precheckFileViewerSource()` does not create a viewer or load a heavy renderer. It checks whether the extension is available and validates known PDF, OpenXML / OpenDocument, legacy OLE Office, and RTF signatures or package parts. `valid: null` explicitly means capability-only detection, not a full parse; the real renderer remains the final authority for malformed content.
@@ -71,10 +75,7 @@ const pdfAssets = resolveFileViewerRendererAssets('pdf', {
71
75
  Use `@file-viewer/core/browser` when a native component package or pure browser integration needs the shared browser shell and toolbar, direct DOM engine, renderer registry, search/zoom providers, print/export adapters, and framework-neutral Canvas/Worker/WASM renderers.
72
76
 
73
77
  ```ts
74
- import {
75
- createViewer,
76
- coreBrowserRendererHandlers
77
- } from '@file-viewer/core/browser'
78
+ import { createViewer } from '@file-viewer/core/browser'
78
79
 
79
80
  const viewer = createViewer(document.querySelector('#viewer')!, {
80
81
  options: {
@@ -83,7 +84,8 @@ const viewer = createViewer(document.querySelector('#viewer')!, {
83
84
  }
84
85
  })
85
86
 
86
- await viewer.load({ url: '/files/report.pdf' })
87
+ // Images use the built-in renderer; document formats need an optional preset.
88
+ await viewer.load({ url: '/files/photo.png' })
87
89
  ```
88
90
 
89
91
  Zoom buttons keep their positions and become disabled at their limits. Configure the existing `toolbar.items` map to hide reset controls while retaining the `resetZoom()` API. Set `pdf.zoomToolbar` to `false` to hide the PDF renderer's zoom group while keeping its page navigation and rotation controls:
@@ -149,8 +151,6 @@ Public source repositories:
149
151
  - GitHub: https://github.com/flyfish-dev/file-viewer-core
150
152
  - Gitee: https://gitee.com/flyfish-dev/file-viewer-core
151
153
 
152
- The GitHub/Gitee repositories are distributed public source packages. The private Gitea aggregate remains useful for the complete workspace, release automation, integration history, sponsorship, and priority support.
153
-
154
154
  License: Apache-2.0. For second development or commercial use, keep clear Flyfish Viewer attribution and contribute shared compatibility improvements where possible.
155
155
 
156
156
  ## Formats and related packages
package/README.zh-CN.md CHANGED
@@ -34,6 +34,10 @@ Current framework-neutral browser renderers still inside core are limited to the
34
34
  npm install @file-viewer/core
35
35
  ```
36
36
 
37
+ ## 浏览器源加载反馈(未发布)
38
+
39
+ 浏览器 `mountViewer` 在缓冲 URL 时显示本地化的下载提示,随后显示读取提示,直至渲染器接管。File 和 buffer 输入显示读取提示。状态遵循配置的语言和主题,展示获取失败,并在切源或销毁时清理。
40
+
37
41
  ## 渲染前预检
38
42
 
39
43
  `precheckFileViewerSource()` 不会创建 viewer,也不会加载重型 renderer。它先检查当前扩展名是否在能力范围内,并对 PDF、OpenXML / OpenDocument、旧版 OLE Office、RTF 等格式执行签名或包结构检查。`valid: null` 明确表示该格式只有能力检查、没有做完整解析;真实 renderer 仍是畸形文件的最终判断者。
@@ -2,6 +2,8 @@ import { appendFileViewerStyle, cloneFileViewerViewState, applyFileViewerZoomAva
2
2
  import { DEFAULT_FILE_VIEWER_SOURCE_FILENAME, createFileViewerTranslator, getExtension, normalizeFileViewerSourceUrl, hasVisibleFileViewerToolbarActions, isFileViewerZoomButtonDisabled, normalizeFileViewerToolbar, normalizeFilename, readFileViewerBuffer, resolveFileViewerSourceFilename, resolveFileViewerRemoteSourcePlan, resolveFileViewerColorScheme, resolveFileViewerToolbarOrder, resolveFileViewerToolbarPosition, resolveVisibleFileViewerToolbar, toggleFileViewerColorScheme, wrapFileViewerFileRef, } from "../index.js";
3
3
  import { resolveFileViewerToolbarZoomButtons } from "../lifecycle/operations.js";
4
4
  import { createToolbarFocusRestorer } from "./toolbar-focus.js";
5
+ import { bindToolbarKeyboardActivation } from "./toolbar-keyboard.js";
6
+ import { createViewerSourceFeedback } from "./source-feedback.js";
5
7
  const isBrowser = () => typeof window !== 'undefined' && typeof document !== 'undefined';
6
8
  const hasSource = (options = {}) => {
7
9
  return !!(options.url || options.file || options.buffer);
@@ -116,26 +118,28 @@ const resolveViewerSourceFilename = (source) => {
116
118
  }), source.type ? `preview.${source.type}` : DEFAULT_FILE_VIEWER_SOURCE_FILENAME);
117
119
  };
118
120
  const resolveViewerLoadSource = async (source, options = {}) => {
119
- var _a, _b, _c;
121
+ var _a, _b, _c, _d, _e, _f, _g, _h;
120
122
  const filename = resolveViewerSourceFilename(source);
121
123
  const type = source.type || getExtension(filename);
122
124
  if (source.buffer) {
125
+ (_a = options.onPhase) === null || _a === void 0 ? void 0 : _a.call(options, 'reading');
123
126
  return {
124
127
  buffer: source.buffer,
125
128
  filename,
126
129
  type,
127
- size: (_a = source.size) !== null && _a !== void 0 ? _a : source.buffer.byteLength,
130
+ size: (_b = source.size) !== null && _b !== void 0 ? _b : source.buffer.byteLength,
128
131
  url: source.url,
129
132
  };
130
133
  }
131
134
  if (source.file) {
135
+ (_c = options.onPhase) === null || _c === void 0 ? void 0 : _c.call(options, 'reading');
132
136
  const file = wrapFileViewerFileRef(source.file, filename);
133
137
  return {
134
138
  file,
135
139
  buffer: await readFileViewerBuffer(file),
136
140
  filename: file.name || filename,
137
141
  type: type || getExtension(file.name),
138
- size: (_b = source.size) !== null && _b !== void 0 ? _b : file.size,
142
+ size: (_d = source.size) !== null && _d !== void 0 ? _d : file.size,
139
143
  url: source.url,
140
144
  };
141
145
  }
@@ -145,8 +149,10 @@ const resolveViewerLoadSource = async (source, options = {}) => {
145
149
  pageHref: options.pageHref, streaming: options.streaming,
146
150
  });
147
151
  if (!options.fetchFile && options.acceptsPdfUrl && plan.streamPdf) {
152
+ (_e = options.onPhase) === null || _e === void 0 ? void 0 : _e.call(options, 'streamingPdf');
148
153
  return { url: plan.url, filename: plan.filename, type: plan.extension, size: source.size };
149
154
  }
155
+ (_f = options.onPhase) === null || _f === void 0 ? void 0 : _f.call(options, 'downloading');
150
156
  const fileRef = await (options.fetchFile || defaultFetchFile)({
151
157
  url: source.url,
152
158
  signal: options.signal,
@@ -156,12 +162,13 @@ const resolveViewerLoadSource = async (source, options = {}) => {
156
162
  throw new Error('Downloaded file is empty.');
157
163
  }
158
164
  const file = wrapFileViewerFileRef(fileRef, filename);
165
+ (_g = options.onPhase) === null || _g === void 0 ? void 0 : _g.call(options, 'reading');
159
166
  return {
160
167
  file,
161
168
  buffer: await readFileViewerBuffer(file),
162
169
  filename: file.name || filename,
163
170
  type: type || getExtension(file.name),
164
- size: (_c = source.size) !== null && _c !== void 0 ? _c : file.size,
171
+ size: (_h = source.size) !== null && _h !== void 0 ? _h : file.size,
165
172
  url: source.url,
166
173
  };
167
174
  }
@@ -314,6 +321,9 @@ const WEB_VIEWER_STYLE = `
314
321
  .file-viewer-web-shell{position:relative;width:100%;height:100%;min-height:0;display:flex;flex-direction:column;overflow:hidden;background:var(--file-viewer-render-surface-background,var(--file-viewer-bg));color:var(--file-viewer-text);font:var(--file-viewer-font);letter-spacing:0;box-sizing:border-box;contain:content}
315
322
  .file-viewer-web-shell[data-viewer-density="compact"]{--file-viewer-toolbar-gap:3px;--file-viewer-toolbar-min-height:34px;--file-viewer-toolbar-padding:3px 5px;--file-viewer-toolbar-floating-min-height:32px;--file-viewer-toolbar-floating-padding:3px;--file-viewer-toolbar-floating-offset:10px;--file-viewer-group-gap:2px;--file-viewer-group-padding:2px;--file-viewer-button-radius:6px;--file-viewer-button-min-width:34px;--file-viewer-button-height:26px;--file-viewer-button-padding:0 6px;--file-viewer-icon-button-size:26px;--file-viewer-zoom-meter-min-width:42px;--file-viewer-zoom-meter-padding:0 5px;--file-viewer-floating-button-min-width:38px;--file-viewer-floating-button-height:28px;--file-viewer-floating-icon-button-size:28px;--file-viewer-floating-zoom-meter-min-width:46px;--file-viewer-search-input-height:26px;--file-viewer-search-input-padding:0 8px;--file-viewer-search-button-min-width:28px;--file-viewer-search-button-padding:0 6px;--file-viewer-search-count-min-width:36px;--file-viewer-floating-search-input-height:28px}
316
323
  .file-viewer-web-content{position:relative;flex:1 1 auto;min-height:0;min-width:0;overflow:auto;overscroll-behavior:contain;background:var(--file-viewer-render-surface-background,var(--file-viewer-content-bg))}
324
+ .file-viewer-web-source-status{position:absolute;inset:0;z-index:10;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:12px;padding:24px;background:var(--file-viewer-toolbar-bg);color:var(--file-viewer-text);text-align:center;overflow:auto}
325
+ .file-viewer-web-source-status p{margin:0;max-width:560px;white-space:pre-wrap;overflow-wrap:anywhere}
326
+ .file-viewer-web-source-status strong{font-size:18px}
317
327
  .file-viewer-web-toolbar{flex:0 0 auto;min-height:var(--file-viewer-toolbar-min-height);display:inline-flex;align-items:center;justify-content:flex-end;gap:var(--file-viewer-toolbar-gap);padding:var(--file-viewer-toolbar-padding);border-bottom:1px solid var(--file-viewer-toolbar-border);background:var(--file-viewer-toolbar-bg);box-sizing:border-box;z-index:var(--file-viewer-z-toolbar)}
318
328
  .file-viewer-web-toolbar[hidden]{display:none!important}
319
329
  .file-viewer-web-toolbar[data-toolbar-position="top-center"]{justify-content:center}
@@ -462,7 +472,10 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
462
472
  let currentSource = hasSource(currentOptions)
463
473
  ? toViewerSourceInput(currentOptions)
464
474
  : null;
465
- let abortController = null;
475
+ let sourceRequest = null;
476
+ let renderingRequest = null;
477
+ let lifecycleVersion = -1;
478
+ const updateSourceFeedback = createViewerSourceFeedback(shell, contentEl);
466
479
  const listeners = new Set();
467
480
  const state = {
468
481
  loading: false,
@@ -502,6 +515,7 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
502
515
  syncFileViewerRenderSurfaceBackground(shell, currentOptions.options);
503
516
  };
504
517
  const captureToolbarFocus = createToolbarFocusRestorer(toolbarEl, contentEl);
518
+ const disposeToolbarKeyboard = bindToolbarKeyboardActivation(toolbarEl);
505
519
  let controller = null;
506
520
  let searchDraft = '';
507
521
  const isSearchToolbarVisible = (toolbar, options) => {
@@ -804,11 +818,20 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
804
818
  var _a;
805
819
  const snapshot = snapshotState();
806
820
  renderToolbar();
821
+ updateSourceFeedback((sourceRequest === null || sourceRequest === void 0 ? void 0 : sourceRequest.pending) ? sourceRequest.phase : null, state.error, currentSource ? currentSource.type || getExtension(resolveViewerSourceFilename(currentSource)) : '', currentOptions.options, Boolean((sourceRequest === null || sourceRequest === void 0 ? void 0 : sourceRequest.rendering) && contentEl.querySelector('.file-viewer-render-error')));
807
822
  (_a = currentOptions.onStateChange) === null || _a === void 0 ? void 0 : _a.call(currentOptions, snapshot, event);
808
823
  listeners.forEach(listener => listener(snapshot, event));
809
824
  };
810
825
  const applyViewerEvent = (event) => {
811
826
  var _a;
827
+ if (disposed || sourceRequest !== renderingRequest)
828
+ return;
829
+ if (event.type === 'load-start' || event.type === 'load-complete' ||
830
+ event.type === 'unload-start' || event.type === 'unload-complete') {
831
+ if (event.payload.version < lifecycleVersion)
832
+ return;
833
+ lifecycleVersion = event.payload.version;
834
+ }
812
835
  state.lastEvent = event;
813
836
  if (event.type === 'load-start') {
814
837
  state.loading = true;
@@ -819,6 +842,8 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
819
842
  searchDraft = '';
820
843
  }
821
844
  else if (event.type === 'load-complete') {
845
+ if (sourceRequest)
846
+ sourceRequest.pending = false;
822
847
  state.loading = false;
823
848
  state.ready = true;
824
849
  state.lifecycle = event.payload;
@@ -829,7 +854,7 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
829
854
  state.lifecycle = event.payload;
830
855
  }
831
856
  else if (event.type === 'unload-complete') {
832
- state.loading = false;
857
+ state.loading = Boolean(sourceRequest === null || sourceRequest === void 0 ? void 0 : sourceRequest.pending);
833
858
  state.ready = false;
834
859
  state.lifecycle = event.payload;
835
860
  }
@@ -860,21 +885,27 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
860
885
  (_e = viewerColorSchemeQuery === null || viewerColorSchemeQuery === void 0 ? void 0 : viewerColorSchemeQuery.addEventListener) === null || _e === void 0 ? void 0 : _e.call(viewerColorSchemeQuery, 'change', handleViewerColorSchemeChange);
861
886
  renderToolbar();
862
887
  const cancel = () => {
863
- abortController === null || abortController === void 0 ? void 0 : abortController.abort();
864
- abortController = null;
888
+ var _a;
889
+ const previous = sourceRequest;
890
+ sourceRequest = null;
891
+ (_a = previous === null || previous === void 0 ? void 0 : previous.abort) === null || _a === void 0 ? void 0 : _a.abort();
865
892
  };
866
893
  const loadSource = async (nextSource) => {
867
- var _a, _b, _c, _d, _e, _f;
894
+ var _a, _b, _c, _d, _e, _f, _g, _h;
868
895
  cancel();
869
896
  currentSource = nextSource;
870
- abortController = typeof AbortController !== 'undefined' ? new AbortController() : null;
871
- const controller = abortController;
897
+ const request = {
898
+ abort: typeof AbortController !== 'undefined' ? new AbortController() : null,
899
+ phase: 'reading', pending: true, rendering: false,
900
+ };
901
+ sourceRequest = request;
902
+ const isCurrent = () => { var _a; return !disposed && sourceRequest === request && !((_a = request.abort) === null || _a === void 0 ? void 0 : _a.signal.aborted); };
872
903
  try {
873
904
  state.loading = true;
874
905
  state.error = null;
875
906
  notifyState();
876
907
  await ((_a = instance.prepare) === null || _a === void 0 ? void 0 : _a.call(instance));
877
- if (disposed || (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) || abortController !== controller) {
908
+ if (!isCurrent()) {
878
909
  return null;
879
910
  }
880
911
  const extension = nextSource.type || getExtension(resolveViewerSourceFilename(nextSource));
@@ -882,29 +913,43 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
882
913
  const resolvedSource = await resolveViewerLoadSource(nextSource, {
883
914
  acceptsPdfUrl: (renderer === null || renderer === void 0 ? void 0 : renderer.sourceAccess) === 'stream-preferred' && Boolean(renderer.load),
884
915
  fetchFile: coreOptions.fetchFile,
885
- signal: controller === null || controller === void 0 ? void 0 : controller.signal,
886
- streaming: (_c = (_b = currentOptions.options) === null || _b === void 0 ? void 0 : _b.pdf) === null || _c === void 0 ? void 0 : _c.streaming,
887
- pageHref: (_e = (_d = documentRef.defaultView) === null || _d === void 0 ? void 0 : _d.location) === null || _e === void 0 ? void 0 : _e.href,
916
+ signal: (_b = request.abort) === null || _b === void 0 ? void 0 : _b.signal,
917
+ streaming: (_d = (_c = currentOptions.options) === null || _c === void 0 ? void 0 : _c.pdf) === null || _d === void 0 ? void 0 : _d.streaming,
918
+ pageHref: (_f = (_e = documentRef.defaultView) === null || _e === void 0 ? void 0 : _e.location) === null || _f === void 0 ? void 0 : _f.href,
919
+ onPhase(phase) {
920
+ if (!isCurrent())
921
+ return;
922
+ request.phase = phase;
923
+ updateSourceFeedback(phase, null, extension, currentOptions.options);
924
+ },
888
925
  });
889
- if (disposed || (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) || abortController !== controller) {
926
+ if (!isCurrent()) {
890
927
  return null;
891
928
  }
892
- return await instance.load(resolvedSource);
929
+ if (resolvedSource.buffer || resolvedSource.file)
930
+ request.phase = 'reading';
931
+ request.rendering = true;
932
+ renderingRequest = request;
933
+ notifyState();
934
+ return await instance.load(resolvedSource, { signal: (_g = request.abort) === null || _g === void 0 ? void 0 : _g.signal });
893
935
  }
894
936
  catch (error) {
895
- if (disposed || (controller === null || controller === void 0 ? void 0 : controller.signal.aborted) || abortController !== controller) {
937
+ if (!isCurrent()) {
896
938
  return null;
897
939
  }
898
940
  state.loading = false;
899
941
  state.ready = false;
900
- state.error = error;
942
+ state.error = error !== null && error !== void 0 ? error : new Error(createFileViewerTranslator(currentOptions.options)('error.unknown'));
943
+ request.pending = false;
901
944
  notifyState();
902
- (_f = coreOptions.onError) === null || _f === void 0 ? void 0 : _f.call(coreOptions, error, nextSource);
945
+ (_h = coreOptions.onError) === null || _h === void 0 ? void 0 : _h.call(coreOptions, error, nextSource);
903
946
  throw error;
904
947
  }
905
948
  finally {
906
- if (abortController === controller) {
907
- abortController = null;
949
+ if (isCurrent() && request.pending) {
950
+ request.pending = false;
951
+ state.loading = false;
952
+ notifyState();
908
953
  }
909
954
  }
910
955
  };
@@ -969,7 +1014,13 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
969
1014
  }
970
1015
  }
971
1016
  else {
1017
+ cancel();
1018
+ renderingRequest = null;
972
1019
  currentSource = null;
1020
+ state.loading = false;
1021
+ state.ready = false;
1022
+ state.error = null;
1023
+ notifyState();
973
1024
  await instance.load({ filename: DEFAULT_FILE_VIEWER_SOURCE_FILENAME });
974
1025
  }
975
1026
  },
@@ -985,6 +1036,7 @@ export const mountViewer = (container, initialOptions = {}, coreOptions = {}) =>
985
1036
  if (disposed)
986
1037
  return;
987
1038
  disposed = true;
1039
+ disposeToolbarKeyboard();
988
1040
  cancel();
989
1041
  (_a = viewerColorSchemeQuery === null || viewerColorSchemeQuery === void 0 ? void 0 : viewerColorSchemeQuery.removeEventListener) === null || _a === void 0 ? void 0 : _a.call(viewerColorSchemeQuery, 'change', handleViewerColorSchemeChange);
990
1042
  void instance.destroy('component-unmount');
@@ -0,0 +1,3 @@
1
+ import { type FileViewerI18nInput } from "../i18n/messages.js";
2
+ export type ViewerSourcePhase = 'downloading' | 'reading' | 'streamingPdf';
3
+ export declare const createViewerSourceFeedback: (shell: HTMLElement, content: HTMLElement) => (phase: ViewerSourcePhase | null, error: unknown, extension: string, options?: FileViewerI18nInput, rendererHasError?: boolean) => void;
@@ -0,0 +1,39 @@
1
+ import { createFileViewerTranslator } from "../i18n/messages.js";
2
+ import { createFileViewerErrorState } from "../viewer/state.js";
3
+ export const createViewerSourceFeedback = (shell, content) => {
4
+ let surface = null;
5
+ let title = null;
6
+ let message = null;
7
+ return (phase, error, extension, options, rendererHasError = false) => {
8
+ content.setAttribute('aria-busy', String(Boolean(phase)));
9
+ content.toggleAttribute('inert', Boolean(phase));
10
+ if (!phase && (error == null || rendererHasError)) {
11
+ surface === null || surface === void 0 ? void 0 : surface.remove();
12
+ surface = title = message = null;
13
+ return;
14
+ }
15
+ if (!surface) {
16
+ surface = shell.ownerDocument.createElement('div');
17
+ surface.className = 'file-viewer-web-source-status';
18
+ surface.setAttribute('part', 'source-status');
19
+ title = shell.ownerDocument.createElement('strong');
20
+ message = shell.ownerDocument.createElement('p');
21
+ surface.append(title, message);
22
+ shell.append(surface);
23
+ }
24
+ surface.dataset.fileViewerSourceState = phase ? 'loading' : 'error';
25
+ surface.setAttribute('role', phase ? 'status' : 'alert');
26
+ surface.setAttribute('aria-live', phase ? 'polite' : 'assertive');
27
+ surface.setAttribute('aria-atomic', 'true');
28
+ const failure = phase ? null : createFileViewerErrorState(extension, error, undefined, options);
29
+ const nextTitle = (failure === null || failure === void 0 ? void 0 : failure.title) || '';
30
+ const nextMessage = phase
31
+ ? createFileViewerTranslator(options)(`preview.${phase}`)
32
+ : failure.message;
33
+ title.hidden = Boolean(phase);
34
+ if (title.textContent !== nextTitle)
35
+ title.textContent = nextTitle;
36
+ if (message.textContent !== nextMessage)
37
+ message.textContent = nextMessage;
38
+ };
39
+ };
@@ -0,0 +1 @@
1
+ export declare function bindToolbarKeyboardActivation(toolbar: HTMLElement): () => void;
@@ -0,0 +1,63 @@
1
+ const isSpace = (event) => event.code === 'Space' || event.key === ' ' || event.key === 'Spacebar';
2
+ export function bindToolbarKeyboardActivation(toolbar) {
3
+ var _a;
4
+ const documentRef = toolbar.ownerDocument;
5
+ let pending = null;
6
+ let releaseTimer;
7
+ const clear = () => { pending = null; };
8
+ const clearOnSpaceDown = (event) => {
9
+ if (isSpace(event) || event.key === 'Tab' || event.key === 'Escape')
10
+ clear();
11
+ };
12
+ const clearAfterSpaceUp = (event) => {
13
+ if (!isSpace(event))
14
+ return;
15
+ const released = pending;
16
+ clearTimeout(releaseTimer);
17
+ releaseTimer = setTimeout(() => { if (pending === released)
18
+ clear(); }, 0);
19
+ };
20
+ const buttonFor = (event) => {
21
+ const target = event.target;
22
+ return (target === null || target === void 0 ? void 0 : target.tagName) === 'BUTTON' && toolbar.contains(target) ? target : null;
23
+ };
24
+ const onKeyDown = (event) => {
25
+ if (!isSpace(event) || event.defaultPrevented || event.isComposing || event.altKey || event.ctrlKey || event.metaKey)
26
+ return;
27
+ const button = buttonFor(event);
28
+ if (!(button === null || button === void 0 ? void 0 : button.dataset.viewerToolbarKey) || button.disabled)
29
+ return;
30
+ event.preventDefault();
31
+ pending = { key: button.dataset.viewerToolbarKey };
32
+ };
33
+ const onKeyUp = (event) => {
34
+ if (!isSpace(event))
35
+ return;
36
+ const activation = pending;
37
+ clear();
38
+ if (!activation || event.defaultPrevented || event.isComposing || event.altKey || event.ctrlKey || event.metaKey)
39
+ return;
40
+ const button = buttonFor(event);
41
+ if (!button || button.disabled || button.dataset.viewerToolbarKey !== activation.key)
42
+ return;
43
+ event.preventDefault();
44
+ button.click();
45
+ };
46
+ documentRef.addEventListener('keydown', clearOnSpaceDown, true);
47
+ documentRef.addEventListener('keyup', clearAfterSpaceUp, true);
48
+ documentRef.addEventListener('pointerdown', clear, true);
49
+ (_a = documentRef.defaultView) === null || _a === void 0 ? void 0 : _a.addEventListener('blur', clear);
50
+ toolbar.addEventListener('keydown', onKeyDown);
51
+ toolbar.addEventListener('keyup', onKeyUp);
52
+ return () => {
53
+ var _a;
54
+ clear();
55
+ clearTimeout(releaseTimer);
56
+ documentRef.removeEventListener('keydown', clearOnSpaceDown, true);
57
+ documentRef.removeEventListener('keyup', clearAfterSpaceUp, true);
58
+ documentRef.removeEventListener('pointerdown', clear, true);
59
+ (_a = documentRef.defaultView) === null || _a === void 0 ? void 0 : _a.removeEventListener('blur', clear);
60
+ toolbar.removeEventListener('keydown', onKeyDown);
61
+ toolbar.removeEventListener('keyup', onKeyUp);
62
+ };
63
+ }
@@ -134,7 +134,7 @@ export const DE_DE_MESSAGES = {
134
134
  "presentation.ppt.state.loading": "Parsen von PowerPoint 97–2003...",
135
135
  "presentation.ppt.error.title": "PPT-Vorschau fehlgeschlagen",
136
136
  "presentation.ppt.error.parseFailed": "Diese PPT-Datei konnte nicht analysiert werden.",
137
- "presentation.ppt.error.assetHint": "Überprüfen Sie die Einstellungen für Modul @file-viewer/ppt, pptWasmUrl, application/wasm MIME, Web Crypto und CSP.",
137
+ "presentation.ppt.error.assetHint": "Überprüfen Sie das Modul @file-viewer/ppt, den JavaScript-MIME-Typ des Parsing-Workers und die CSP-Einstellungen.",
138
138
  "presentation.slideshow.start": "Diashow starten",
139
139
  "presentation.slideshow.exit": "Diashow beenden",
140
140
  "presentation.slideshow.hint": "← → navigieren · Esc beenden",
@@ -134,7 +134,7 @@ export const JA_JP_MESSAGES = {
134
134
  'presentation.ppt.state.loading': 'PowerPoint 97–2003 を解析しています...',
135
135
  'presentation.ppt.error.title': 'PPT プレビューに失敗しました',
136
136
  'presentation.ppt.error.parseFailed': 'この PPT ファイルを解析できませんでした。',
137
- 'presentation.ppt.error.assetHint': '@file-viewer/ppt モジュール、pptWasmUrl、application/wasm MIME タイプ、Web Crypto、CSP 設定を確認してください。',
137
+ 'presentation.ppt.error.assetHint': '@file-viewer/ppt モジュール、解析 Worker の JavaScript MIME タイプ、CSP 設定を確認してください。',
138
138
  'presentation.slideshow.start': 'スライドショーを開始',
139
139
  'presentation.slideshow.exit': 'スライドショーを終了',
140
140
  'presentation.slideshow.hint': '← → 移動 · Esc 終了',
@@ -139,7 +139,7 @@ const ZH_CN_MESSAGES = {
139
139
  'presentation.ppt.state.loading': '正在解析 PowerPoint 97–2003...',
140
140
  'presentation.ppt.error.title': 'PPT 预览失败',
141
141
  'presentation.ppt.error.parseFailed': '无法解析这个 PPT 文件。',
142
- 'presentation.ppt.error.assetHint': '请检查 @file-viewer/ppt 模块、pptWasmUrl、application/wasm MIME 类型、Web Crypto 和 CSP 配置。',
142
+ 'presentation.ppt.error.assetHint': '请检查 @file-viewer/ppt 模块、解析 Worker 的 JavaScript MIME 类型和 CSP 配置。',
143
143
  'presentation.slideshow.start': '开始放映',
144
144
  'presentation.slideshow.exit': '退出放映',
145
145
  'presentation.slideshow.hint': '← → 翻页 · Esc 退出',
@@ -602,7 +602,7 @@ const EN_US_MESSAGES = {
602
602
  'presentation.ppt.state.loading': 'Parsing PowerPoint 97–2003...',
603
603
  'presentation.ppt.error.title': 'PPT preview failed',
604
604
  'presentation.ppt.error.parseFailed': 'This PPT file could not be parsed.',
605
- 'presentation.ppt.error.assetHint': 'Check the @file-viewer/ppt module, pptWasmUrl, application/wasm MIME type, Web Crypto, and CSP settings.',
605
+ 'presentation.ppt.error.assetHint': 'Check the @file-viewer/ppt module, parsing Worker JavaScript MIME type, and CSP settings.',
606
606
  'presentation.slideshow.start': 'Start slideshow',
607
607
  'presentation.slideshow.exit': 'Exit slideshow',
608
608
  'presentation.slideshow.hint': '← → navigate · Esc exit',
@@ -12,9 +12,9 @@ export declare const DEFAULT_FILE_VIEWER_DOCX_WORKER_JSZIP_PATH = "vendor/docx/j
12
12
  export declare const DEFAULT_FILE_VIEWER_DOCX_RUNTIME_VERSION = "0.3.39";
13
13
  export declare const DEFAULT_FILE_VIEWER_PRESENTATION_WORKER_PATH = "vendor/pptx/pptx.worker.js";
14
14
  export declare const DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH = "vendor/ppt";
15
- export declare const DEFAULT_FILE_VIEWER_PPT_RUNTIME_VERSION = "0.3.6";
16
- export declare const DEFAULT_FILE_VIEWER_PPT_MODULE_PATH = "vendor/ppt/index.mjs";
17
- export declare const DEFAULT_FILE_VIEWER_PPT_WORKER_PATH = "vendor/ppt/worker.mjs";
15
+ export declare const DEFAULT_FILE_VIEWER_PPT_RUNTIME_VERSION = "1.0.2";
16
+ export declare const DEFAULT_FILE_VIEWER_PPT_MODULE_PATH = "vendor/ppt/dist/pptjs.mjs";
17
+ export declare const DEFAULT_FILE_VIEWER_PPT_WORKER_PATH = "vendor/ppt/dist/pptjs.worker.js";
18
18
  export declare const DEFAULT_FILE_VIEWER_PPT_FRAME_CACHE_PATH = "vendor/ppt/frame-cache.mjs";
19
19
  export declare const DEFAULT_FILE_VIEWER_PPT_WASM_PATH = "vendor/ppt/ppt-native.wasm";
20
20
  export declare const DEFAULT_FILE_VIEWER_PPT_FONT_PATH = "vendor/ppt/ppt-font-cjk.otf";
@@ -11,9 +11,9 @@ export const DEFAULT_FILE_VIEWER_DOCX_WORKER_JSZIP_PATH = 'vendor/docx/jszip.min
11
11
  export const DEFAULT_FILE_VIEWER_DOCX_RUNTIME_VERSION = '0.3.39';
12
12
  export const DEFAULT_FILE_VIEWER_PRESENTATION_WORKER_PATH = 'vendor/pptx/pptx.worker.js';
13
13
  export const DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH = 'vendor/ppt';
14
- export const DEFAULT_FILE_VIEWER_PPT_RUNTIME_VERSION = '0.3.6';
15
- export const DEFAULT_FILE_VIEWER_PPT_MODULE_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/index.mjs`;
16
- export const DEFAULT_FILE_VIEWER_PPT_WORKER_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/worker.mjs`;
14
+ export const DEFAULT_FILE_VIEWER_PPT_RUNTIME_VERSION = '1.0.2';
15
+ export const DEFAULT_FILE_VIEWER_PPT_MODULE_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/dist/pptjs.mjs`;
16
+ export const DEFAULT_FILE_VIEWER_PPT_WORKER_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/dist/pptjs.worker.js`;
17
17
  export const DEFAULT_FILE_VIEWER_PPT_FRAME_CACHE_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/frame-cache.mjs`;
18
18
  export const DEFAULT_FILE_VIEWER_PPT_WASM_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/ppt-native.wasm`;
19
19
  export const DEFAULT_FILE_VIEWER_PPT_FONT_PATH = `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/ppt-font-cjk.otf`;
@@ -733,7 +733,7 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
733
733
  required: true,
734
734
  defaultPath: DEFAULT_FILE_VIEWER_PPT_MODULE_PATH,
735
735
  optionPath: 'presentation.pptModuleUrl',
736
- description: 'Official @file-viewer/ppt 0.3 browser entry for PowerPoint 97–2003 preview.',
736
+ description: 'Self-hosted TypeScript PPT standalone module for PowerPoint 97–2003 preview.',
737
737
  },
738
738
  {
739
739
  id: 'ppt-worker',
@@ -743,36 +743,16 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
743
743
  required: true,
744
744
  defaultPath: DEFAULT_FILE_VIEWER_PPT_WORKER_PATH,
745
745
  optionPath: 'presentation.pptWorkerUrl',
746
- description: 'Official @file-viewer/ppt 0.3 module Worker.',
746
+ description: 'TypeScript PPT parsing Worker; layout and Canvas rendering use the main thread.',
747
747
  },
748
748
  {
749
- id: 'ppt-frame-cache',
749
+ id: 'ppt-runtime-dist',
750
750
  rendererId: 'office-presentation-binary',
751
- kind: 'script',
752
- target: 'public',
753
- required: true,
754
- defaultPath: DEFAULT_FILE_VIEWER_PPT_FRAME_CACHE_PATH,
755
- description: 'Bounded IndexedDB frame cache imported by the binary-PPT Worker.',
756
- },
757
- {
758
- id: 'ppt-wasm',
759
- rendererId: 'office-presentation-binary',
760
- kind: 'wasm',
761
- target: 'public',
762
- required: true,
763
- defaultPath: DEFAULT_FILE_VIEWER_PPT_WASM_PATH,
764
- optionPath: 'presentation.pptWasmUrl',
765
- description: 'Official @file-viewer/ppt 0.3 native WebAssembly parser and renderer.',
766
- },
767
- {
768
- id: 'ppt-cjk-font',
769
- rendererId: 'office-presentation-binary',
770
- kind: 'font',
751
+ kind: 'directory',
771
752
  target: 'public',
772
753
  required: true,
773
- defaultPath: DEFAULT_FILE_VIEWER_PPT_FONT_PATH,
774
- optionPath: 'presentation.pptFontUrl',
775
- description: 'CJK font pack verified and loaded by the binary-PPT runtime.',
754
+ defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/dist`,
755
+ description: 'Unmodified compiled JavaScript and declarations from the installed PPT package.',
776
756
  },
777
757
  {
778
758
  id: 'ppt-runtime-manifest',
@@ -780,7 +760,7 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
780
760
  kind: 'metadata',
781
761
  target: 'public',
782
762
  required: true,
783
- defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/manifest.json`,
763
+ defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/dist/manifest.json`,
784
764
  description: 'Integrity and edition metadata for the official binary-PPT runtime.',
785
765
  },
786
766
  {
@@ -792,6 +772,15 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
792
772
  defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/package.json`,
793
773
  description: 'Package identity metadata for the official binary-PPT runtime.',
794
774
  },
775
+ {
776
+ id: 'ppt-runtime-readme',
777
+ rendererId: 'office-presentation-binary',
778
+ kind: 'metadata',
779
+ target: 'public',
780
+ required: true,
781
+ defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/README.md`,
782
+ description: 'Usage and supported-format limits shipped with the PPT runtime.',
783
+ },
795
784
  {
796
785
  id: 'ppt-runtime-license',
797
786
  rendererId: 'office-presentation-binary',
@@ -807,7 +796,7 @@ export const DEFAULT_FILE_VIEWER_RENDERER_ASSET_MANIFESTS = [
807
796
  kind: 'license',
808
797
  target: 'public',
809
798
  required: true,
810
- defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/NOTICE`,
799
+ defaultPath: `${DEFAULT_FILE_VIEWER_PPT_RUNTIME_PATH}/NOTICE.md`,
811
800
  description: 'Notices shipped by the independently versioned @file-viewer/ppt package.',
812
801
  },
813
802
  ],
@@ -47,7 +47,7 @@ export declare const DEFAULT_RENDERER_DEFINITIONS: readonly [{
47
47
  readonly packageName: "@file-viewer/renderer-ppt";
48
48
  readonly presets: readonly ["office", "all"];
49
49
  readonly containerVersions: readonly ["PowerPoint 97-2003 Binary"];
50
- readonly knownLimits: readonly ["Embedded engine watermark is retained", "Macros are never executed"];
50
+ readonly knownLimits: readonly ["Host fonts and complex effects can differ from PowerPoint", "Macros are never executed"];
51
51
  readonly capabilities: {
52
52
  readonly download: true;
53
53
  readonly print: "adapter";
@@ -715,7 +715,7 @@ export declare const DEFAULT_RENDERER_DEFINITIONS: readonly [{
715
715
  readonly status: "experimental";
716
716
  readonly packageName: "@file-viewer/renderer-design";
717
717
  readonly presets: readonly [];
718
- readonly containerVersions: readonly ["IDML package", "@paged-media/introspect-wasm 0.70.2"];
718
+ readonly containerVersions: readonly ["IDML package", "@paged-media/introspect-wasm 0.73.4"];
719
719
  readonly knownLimits: readonly ["Pages are rendered locally by the CPU WASM engine in a module Worker; the browser never uploads the IDML package", "ZIP64, encrypted, multi-disk, overlapping, unsafe-path, unsupported-compression, and configured expansion-limit packages are rejected before the WASM engine opens them", "The current engine page tree lists TextFrame and Rectangle objects only even though other supported objects may still appear in rendered page pixels", "Each page render rebuilds the upstream document internally; interactive requests are latest-wins, preview is lazy, and print-all is bounded by the configured total RGBA working-set limit"];
720
720
  readonly capabilities: {
721
721
  readonly download: true;
@@ -84,7 +84,7 @@ export const DEFAULT_RENDERER_DEFINITIONS = [
84
84
  "PowerPoint 97-2003 Binary"
85
85
  ],
86
86
  "knownLimits": [
87
- "Embedded engine watermark is retained",
87
+ "Host fonts and complex effects can differ from PowerPoint",
88
88
  "Macros are never executed"
89
89
  ],
90
90
  "capabilities": {
@@ -1327,7 +1327,7 @@ export const DEFAULT_RENDERER_DEFINITIONS = [
1327
1327
  "presets": [],
1328
1328
  "containerVersions": [
1329
1329
  "IDML package",
1330
- "@paged-media/introspect-wasm 0.70.2"
1330
+ "@paged-media/introspect-wasm 0.73.4"
1331
1331
  ],
1332
1332
  "knownLimits": [
1333
1333
  "Pages are rendered locally by the CPU WASM engine in a module Worker; the browser never uploads the IDML package",
@@ -56,7 +56,7 @@ export declare const coreLiteRendererDefinitions: ({
56
56
  readonly packageName: "@file-viewer/renderer-ppt";
57
57
  readonly presets: readonly ["office", "all"];
58
58
  readonly containerVersions: readonly ["PowerPoint 97-2003 Binary"];
59
- readonly knownLimits: readonly ["Embedded engine watermark is retained", "Macros are never executed"];
59
+ readonly knownLimits: readonly ["Host fonts and complex effects can differ from PowerPoint", "Macros are never executed"];
60
60
  readonly capabilities: {
61
61
  readonly download: true;
62
62
  readonly print: "adapter";
@@ -724,7 +724,7 @@ export declare const coreLiteRendererDefinitions: ({
724
724
  readonly status: "experimental";
725
725
  readonly packageName: "@file-viewer/renderer-design";
726
726
  readonly presets: readonly [];
727
- readonly containerVersions: readonly ["IDML package", "@paged-media/introspect-wasm 0.70.2"];
727
+ readonly containerVersions: readonly ["IDML package", "@paged-media/introspect-wasm 0.73.4"];
728
728
  readonly knownLimits: readonly ["Pages are rendered locally by the CPU WASM engine in a module Worker; the browser never uploads the IDML package", "ZIP64, encrypted, multi-disk, overlapping, unsafe-path, unsupported-compression, and configured expansion-limit packages are rejected before the WASM engine opens them", "The current engine page tree lists TextFrame and Rectangle objects only even though other supported objects may still appear in rendered page pixels", "Each page render rebuilds the upstream document internally; interactive requests are latest-wins, preview is lazy, and print-all is bounded by the configured total RGBA working-set limit"];
729
729
  readonly capabilities: {
730
730
  readonly download: true;
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "name": "@file-viewer/core",
3
- "version": "3.3.0",
3
+ "version": "3.3.3",
4
4
  "private": false,
5
5
  "type": "module",
6
- "description": "Framework-neutral modular TypeScript core for File Viewer renderer orchestration, lifecycle APIs, search, zoom, print, and export",
6
+ "description": "Framework-neutral TypeScript APIs for browser-side file preview, renderer presets, search, zoom, page navigation, print and export.",
7
7
  "keywords": [
8
8
  "file-viewer",
9
9
  "document-preview",
@@ -36,7 +36,7 @@
36
36
  "type": "individual",
37
37
  "url": "https://dev.flyfish.group/donate?source=npm"
38
38
  },
39
- "homepage": "https://doc.file-viewer.app/",
39
+ "homepage": "https://github.com/flyfish-dev/file-viewer#readme",
40
40
  "main": "./dist/index.js",
41
41
  "module": "./dist/index.js",
42
42
  "types": "./dist/index.d.ts",
@@ -84,8 +84,12 @@
84
84
  "dist/browser.js",
85
85
  "dist/browser/controller.d.ts",
86
86
  "dist/browser/controller.js",
87
+ "dist/browser/source-feedback.d.ts",
88
+ "dist/browser/source-feedback.js",
87
89
  "dist/browser/toolbar-focus.d.ts",
88
90
  "dist/browser/toolbar-focus.js",
91
+ "dist/browser/toolbar-keyboard.d.ts",
92
+ "dist/browser/toolbar-keyboard.js",
89
93
  "dist/config/options.d.ts",
90
94
  "dist/config/options.js",
91
95
  "dist/contracts/types.d.ts",