@silurus/ooxml 0.69.0 → 0.70.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +146 -10
- package/dist/docx-BGWUAYkh.js +3895 -0
- package/dist/docx.mjs +3 -3
- package/dist/docx_parser_bg.wasm +0 -0
- package/dist/index.mjs +3 -3
- package/dist/{src-dTwJJJoi.js → line-metrics-DG9p1RvA.js} +3592 -6462
- package/dist/math.mjs +18 -18
- package/dist/mathjax-stix2.js +15 -0
- package/dist/pptx-ECIKr-R_.js +3325 -0
- package/dist/pptx.mjs +3 -3
- package/dist/pptx_parser_bg.wasm +0 -0
- package/dist/render-worker-host-2V2UCnvB.js +27 -0
- package/dist/render-worker-host-BcmXt3yA.js +27 -0
- package/dist/render-worker-host-UUYE6Oqt.js +27 -0
- package/dist/segments-BTivjRMw.js +7 -0
- package/dist/types/docx.d.ts +586 -2
- package/dist/types/index.d.ts +1370 -351
- package/dist/types/pptx.d.ts +616 -108
- package/dist/types/xlsx.d.ts +596 -206
- package/dist/virtual-scroll-CsikPntn.js +873 -0
- package/dist/visible-index-B4ljB_dg.js +1266 -0
- package/dist/xlsx-CCmtIDr_.js +4274 -0
- package/dist/xlsx.mjs +2 -2
- package/dist/xlsx_parser_bg.wasm +0 -0
- package/package.json +14 -6
- package/dist/docx-DVGEDCWy.js +0 -3218
- package/dist/pptx-Bkjpmiqt.js +0 -2080
- package/dist/render-worker-host-D1d4uOqW.js +0 -27
- package/dist/render-worker-host-DAh6fO6-.js +0 -27
- package/dist/render-worker-host-fgjf6Hlu.js +0 -27
- package/dist/xlsx-DLv5RYrM.js +0 -4237
- /package/dist/{mathjax-Q1s8_eMq.js → mathjax-BRfWlbSJ.js} +0 -0
package/README.md
CHANGED
|
@@ -27,9 +27,23 @@ npm install @silurus/ooxml
|
|
|
27
27
|
pnpm add @silurus/ooxml
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
> **Bundler note**:
|
|
31
|
-
|
|
32
|
-
>
|
|
30
|
+
> **Bundler note**: the Rust parsers ship as real `.wasm` asset files next to the
|
|
31
|
+
> JavaScript, referenced with the standard `new URL('…', import.meta.url)` form
|
|
32
|
+
> and fetched (streaming-compiled) at load time. Vite, webpack 5, Rollup and
|
|
33
|
+
> Parcel detect that reference and copy the asset automatically — no extra
|
|
34
|
+
> WebAssembly plugin is required. esbuild and the Angular CLI (whose application
|
|
35
|
+
> builder is esbuild-based) do **not** process that reference
|
|
36
|
+
> ([esbuild#795](https://github.com/evanw/esbuild/issues/795)): copy the `.wasm`
|
|
37
|
+
> into your served output yourself and point the viewer at it with the `wasmUrl`
|
|
38
|
+
> load option — see the [Angular example](#framework-examples) for the two-step
|
|
39
|
+
> setup. `wasmUrl` also serves the parser WASM from a CDN or any path you
|
|
40
|
+
> control:
|
|
41
|
+
>
|
|
42
|
+
> ```typescript
|
|
43
|
+
> new DocxViewer(canvas, { wasmUrl: 'https://cdn.example.com/docx_parser_bg.wasm' });
|
|
44
|
+
> ```
|
|
45
|
+
|
|
46
|
+
> **Bundle size note**: the package is ESM-only (`.mjs`). npm's *Unpacked Size* sums every entry bundle **and** the standalone MathJax + STIX Two Math asset (`mathjax-stix2.js`, ~3 MB) that ships in the tarball, so the reported figure is much larger than any single app build. What actually lands in your app is smaller on two counts: import only the format you need (e.g. `@silurus/ooxml/pptx`), and the math engine is a **separate entry** (`@silurus/ooxml/math`). Its main-thread chunk is a ~1 KB loader that references the ~3 MB engine asset as a **sibling file** (not an inline data URL): the engine is fetched **lazily, only when a document actually contains equations** — and only if you imported `@silurus/ooxml/math` and passed it to a viewer in the first place (see [Rendering equations](#rendering-equations)). Never import the `math` entry and the loader chunk never enters your graph at all.
|
|
33
47
|
|
|
34
48
|
---
|
|
35
49
|
|
|
@@ -62,11 +76,14 @@ pptx.nextSlide();
|
|
|
62
76
|
|
|
63
77
|
OMML equations (`m:oMath` / `m:oMathPara`) in `.docx`, `.pptx` and `.xlsx` are rendered with
|
|
64
78
|
[MathJax](https://www.mathjax.org/) + [STIX Two Math](https://github.com/stipub/stixfonts).
|
|
65
|
-
That engine is ~
|
|
79
|
+
That engine is ~3 MB, so it is **opt-in**: import the `math` engine from the separate
|
|
66
80
|
`@silurus/ooxml/math` entry and pass it to the viewer. Pass it and equations render;
|
|
67
|
-
omit it and the engine is referenced nowhere, so a bundler
|
|
68
|
-
|
|
69
|
-
|
|
81
|
+
omit it and the engine is referenced nowhere, so a bundler leaves it out of your build
|
|
82
|
+
entirely (equations are simply skipped). When you *do* pass it, the ~3 MB engine ships
|
|
83
|
+
as a **standalone asset file** next to the bundle rather than an inline data URL, and is
|
|
84
|
+
fetched **on demand — only the first time a document actually contains an equation**, so
|
|
85
|
+
equation-free documents never pay for it. It is fully self-contained: served from your own
|
|
86
|
+
origin, no cross-origin requests.
|
|
70
87
|
|
|
71
88
|
```typescript
|
|
72
89
|
import { DocxViewer } from '@silurus/ooxml/docx';
|
|
@@ -125,6 +142,97 @@ Notes:
|
|
|
125
142
|
transferred back as an `ImageBitmap`, so a single render can be marginally
|
|
126
143
|
slower than `mode: 'main'`. Choose it for non-blocking UI, not raw speed.
|
|
127
144
|
|
|
145
|
+
### Continuous scroll viewers
|
|
146
|
+
|
|
147
|
+
`DocxScrollViewer` and `PptxScrollViewer` render the whole document as one
|
|
148
|
+
vertically-scrolling, PDF-reader-style surface instead of a single page/slide at
|
|
149
|
+
a time. Unlike `DocxViewer` / `PptxViewer` (which take a `<canvas>`), the scroll
|
|
150
|
+
viewers take a **container** `<div>` — they own the scroll host, virtualize the
|
|
151
|
+
page/slide list (only the visible window plus a small overscan is mounted), and
|
|
152
|
+
recycle canvases as you scroll.
|
|
153
|
+
|
|
154
|
+
```typescript
|
|
155
|
+
import { DocxScrollViewer } from '@silurus/ooxml/docx';
|
|
156
|
+
|
|
157
|
+
const container = document.getElementById('docx-scroll') as HTMLElement;
|
|
158
|
+
const viewer = new DocxScrollViewer(container);
|
|
159
|
+
await viewer.load('/document.docx');
|
|
160
|
+
// viewer.scrollToPage(3);
|
|
161
|
+
// viewer.pageCount, viewer.topVisiblePage
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
import { PptxScrollViewer } from '@silurus/ooxml/pptx';
|
|
166
|
+
|
|
167
|
+
const container = document.getElementById('pptx-scroll') as HTMLElement;
|
|
168
|
+
const viewer = new PptxScrollViewer(container);
|
|
169
|
+
await viewer.load('/deck.pptx');
|
|
170
|
+
// viewer.scrollToSlide(2);
|
|
171
|
+
// viewer.slideCount, viewer.topVisibleSlide
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The container must have a bounded height (e.g. `height: 100vh` or a flex child)
|
|
175
|
+
so the viewer can size its scroll host to it. Base zoom fits the first page/slide
|
|
176
|
+
width to the container width and re-fits on resize; a `0`-width container defers
|
|
177
|
+
layout until it has width. Call `destroy()` to tear down (a self-loaded engine is
|
|
178
|
+
destroyed with it; an injected one is not — see below).
|
|
179
|
+
|
|
180
|
+
**Desk appearance.** The viewer paints each page/slide on its own white canvas
|
|
181
|
+
with a soft drop shadow, over a transparent "desk". Style the desk and the sheet
|
|
182
|
+
gaps without any wrapper CSS:
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
const viewer = new DocxScrollViewer(container, {
|
|
186
|
+
background: '#f3f4f6', // the desk behind / between pages
|
|
187
|
+
gap: 24, // vertical gap between pages
|
|
188
|
+
paddingTop: 32, // desk padding above the first page
|
|
189
|
+
pageShadow: '0 0 0 1px #c8ccd0', // crisp 1px "border" look (box-shadow never shifts layout)
|
|
190
|
+
// pageShadow: false, // flat pages, no shadow
|
|
191
|
+
});
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
`paddingBottom`, `paddingLeft` and `paddingRight` each default to `gap`, so the
|
|
195
|
+
sheet sits inside a uniform desk margin; pass `0` for a flush edge.
|
|
196
|
+
|
|
197
|
+
**Zoom.** `Ctrl`/`⌘` + mouse-wheel (and trackpad pinch) zooms the surface;
|
|
198
|
+
bare-wheel still scrolls natively. Zoom is flicker-free — a rapid gesture shows a
|
|
199
|
+
CSS preview and settles into a crisp re-render when it pauses. Bounds are the
|
|
200
|
+
absolute scale factors `zoomMin` / `zoomMax` (default `0.1` / `4`), and
|
|
201
|
+
`setScale(scale)` sets it programmatically. Pass `enableZoom: false` to disable.
|
|
202
|
+
|
|
203
|
+
**Text selection** (main mode only). Pass `enableTextSelection: true` to overlay
|
|
204
|
+
a transparent, selectable text layer per page/slide for native copy. In
|
|
205
|
+
`mode: 'worker'` the overlay stays empty (the per-run geometry cannot cross the
|
|
206
|
+
worker boundary) and the viewer logs one warning — use the default `mode: 'main'`
|
|
207
|
+
for selectable text.
|
|
208
|
+
|
|
209
|
+
**Master–detail / shared engine.** Inject an already-loaded headless engine so a
|
|
210
|
+
paged viewer and a scroll viewer (or several panes) share **one** parse. When you
|
|
211
|
+
inject, `load()` is unsupported (the engine is already loaded), the engine's own
|
|
212
|
+
`mode` wins, and `destroy()` leaves the injected engine intact — the caller owns
|
|
213
|
+
its lifecycle:
|
|
214
|
+
|
|
215
|
+
```typescript
|
|
216
|
+
import { DocxDocument, DocxScrollViewer } from '@silurus/ooxml/docx';
|
|
217
|
+
|
|
218
|
+
const doc = await DocxDocument.load('/document.docx'); // parse once
|
|
219
|
+
const scroll = new DocxScrollViewer(container, { document: doc });
|
|
220
|
+
// ...also drive a thumbnail grid, a paged view, etc. from the same `doc`.
|
|
221
|
+
scroll.destroy(); // the injected `doc` is NOT destroyed — you own it
|
|
222
|
+
doc.destroy(); // release it yourself when every pane is gone
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
`PptxScrollViewer` takes the same shape with `{ presentation: pres }`
|
|
226
|
+
(`await PptxPresentation.load(...)`).
|
|
227
|
+
|
|
228
|
+
Both viewers also expose `relayout()` (force a re-fit when the container resizes
|
|
229
|
+
in a way a `ResizeObserver` cannot see — e.g. a late web-font load),
|
|
230
|
+
`onVisiblePageChange` / `onVisibleSlideChange` (fires when the top-most visible
|
|
231
|
+
page/slide changes), and `onError` (async per-page render failures are routed
|
|
232
|
+
here instead of crashing the scroll loop). The parse/render knobs from the
|
|
233
|
+
headless engines (`mode`, `useGoogleFonts`, `maxZipEntryBytes`, `math`, `dpr`)
|
|
234
|
+
are accepted too.
|
|
235
|
+
|
|
128
236
|
---
|
|
129
237
|
|
|
130
238
|
<details>
|
|
@@ -200,7 +308,7 @@ All three formats follow the same shape: the worker parses the `.docx` / `.xlsx`
|
|
|
200
308
|
<summary><strong>React 19</strong></summary>
|
|
201
309
|
|
|
202
310
|
```tsx
|
|
203
|
-
// React 19.1 —
|
|
311
|
+
// React 19.1 — Vite copies the parser .wasm asset automatically; no extra plugin needed.
|
|
204
312
|
import { useEffect, useRef, useState } from 'react';
|
|
205
313
|
import { PptxViewer } from '@silurus/ooxml/pptx';
|
|
206
314
|
|
|
@@ -272,6 +380,28 @@ onMounted(async () => {
|
|
|
272
380
|
<details>
|
|
273
381
|
<summary><strong>Angular 19</strong></summary>
|
|
274
382
|
|
|
383
|
+
The Angular CLI's esbuild-based builder does not process the `new URL('…', import.meta.url)`
|
|
384
|
+
asset reference the parsers use ([angular-cli#22388](https://github.com/angular/angular-cli/issues/22388)),
|
|
385
|
+
so the `.wasm` never reaches the build output — and under `ng serve` the dependency
|
|
386
|
+
optimizer additionally rewrites the reference into its own cache path. **Both steps
|
|
387
|
+
below are required** (the asset copy alone fixes only production builds; `ng serve`
|
|
388
|
+
still 404s without `wasmUrl`):
|
|
389
|
+
|
|
390
|
+
```jsonc
|
|
391
|
+
// angular.json — copy the parser WASM into the served root
|
|
392
|
+
// (restart `ng serve` after editing this file)
|
|
393
|
+
"architect": {
|
|
394
|
+
"build": {
|
|
395
|
+
"options": {
|
|
396
|
+
"assets": [
|
|
397
|
+
{ "glob": "*_parser_bg.wasm", "input": "node_modules/@silurus/ooxml/dist", "output": "/" },
|
|
398
|
+
{ "glob": "**/*", "input": "public" }
|
|
399
|
+
]
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
```
|
|
404
|
+
|
|
275
405
|
```typescript
|
|
276
406
|
// Angular 19 — standalone component with signal-based state
|
|
277
407
|
import {
|
|
@@ -300,6 +430,7 @@ export class PptxViewerComponent implements AfterViewInit {
|
|
|
300
430
|
|
|
301
431
|
ngAfterViewInit(): void {
|
|
302
432
|
this.viewer = new PptxViewer(this.canvasEl().nativeElement, {
|
|
433
|
+
wasmUrl: '/pptx_parser_bg.wasm',
|
|
303
434
|
onSlideChange: (i, t) => { this.current.set(i); this.total.set(t); },
|
|
304
435
|
});
|
|
305
436
|
this.viewer.load('/deck.pptx');
|
|
@@ -310,7 +441,10 @@ export class PptxViewerComponent implements AfterViewInit {
|
|
|
310
441
|
}
|
|
311
442
|
```
|
|
312
443
|
|
|
313
|
-
>
|
|
444
|
+
> The `*_parser_bg.wasm` glob copies all three parsers; narrow it to
|
|
445
|
+
> `pptx_parser_bg.wasm` if you only use one format. If you deploy under a
|
|
446
|
+
> non-root `base href`, adjust `wasmUrl` so it resolves under your base (a
|
|
447
|
+
> relative `wasmUrl` is resolved against the document URL).
|
|
314
448
|
|
|
315
449
|
</details>
|
|
316
450
|
|
|
@@ -459,7 +593,7 @@ export const PptxViewerComponent = component$<{ src: string }>(({ src }) => {
|
|
|
459
593
|
| | Math equations (OMML `m:oMath` / `m:oMathPara`, rendered via MathJax — opt-in `@silurus/ooxml/math`) | ✅ |
|
|
460
594
|
| | Images (inline and anchored, with text wrap) | ✅ |
|
|
461
595
|
| | SVG images (`asvg:svgBlip` MS-2016 extension — vector drawn from the embedded `.svg`, raster fallback) | ✅ |
|
|
462
|
-
| | Text boxes / drawing shapes (`wps:txbx`, `a:prstGeom` — 186 preset geometries via the shared engine; connector arrow heads `headEnd` / `tailEnd` (§20.1.8.3) and `prstDash` dash patterns (§20.1.8.48)) | ✅ |
|
|
596
|
+
| | Text boxes / drawing shapes (`wps:txbx`, `a:prstGeom` — 186 preset geometries via the shared engine; connector arrow heads `headEnd` / `tailEnd` (§20.1.8.3) and `prstDash` dash patterns (§20.1.8.48)). Text-box paragraphs run through the **same line-layout engine as body text**, so kinsoku 行頭/行末禁則 (§17.15.1.58–60), UAX#9 bidi (`w:bidi`, §17.3.1.6), justification (§17.18.44) and tab stops (§17.3.1.37) all apply inside a box | ✅ |
|
|
463
597
|
| | WMF metafile images (legacy vector, incl. inside text boxes) — rasterized via a built-in player (window mapping, pens/brushes, poly/rect); true EMF detected but not yet rendered | ✅ |
|
|
464
598
|
| **Advanced** | Footnotes — reference markers + bottom-of-page bodies with separator rule, numbered (`w:footnoteReference` / `w:footnoteRef`, §17.11) | ✅ |
|
|
465
599
|
| | Endnotes — reference markers + bodies at document end (`w:endnoteReference`, §17.11) | ✅ |
|
|
@@ -468,6 +602,7 @@ export const PptxViewerComponent = component$<{ src: string }>(({ src }) => {
|
|
|
468
602
|
| | Comments — author / date / text via the document model (`doc.comments`, §17.13.4; not drawn on the page) | ✅ |
|
|
469
603
|
| | Mail merge fields | ❌ Not planned |
|
|
470
604
|
| **Interaction** | Text selection (transparent overlay, native copy) | ✅ |
|
|
605
|
+
| | Continuous scroll viewer (`DocxScrollViewer` — virtualized page list, desk background / shadow, Ctrl/⌘+wheel zoom, engine injection) | ✅ |
|
|
471
606
|
|
|
472
607
|
---
|
|
473
608
|
|
|
@@ -612,6 +747,7 @@ export const PptxViewerComponent = component$<{ src: string }>(({ src }) => {
|
|
|
612
747
|
| | Font scheme (`+mj-lt`, `+mn-lt`) | ✅ |
|
|
613
748
|
| | lumMod / lumOff / alpha transforms | ✅ |
|
|
614
749
|
| **Interaction** | Text selection (transparent overlay, native copy) | ✅ |
|
|
750
|
+
| | Continuous scroll viewer (`PptxScrollViewer` — virtualized slide list, desk background / shadow, Ctrl/⌘+wheel zoom, engine injection) | ✅ |
|
|
615
751
|
|
|
616
752
|
---
|
|
617
753
|
|