@silurus/ooxml 0.24.2 → 0.25.0

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
@@ -48,13 +48,14 @@ await docx.load('/document.docx');
48
48
  docx.nextPage();
49
49
 
50
50
  // XLSX — viewer manages its own <canvas> + tab bar
51
- const xlsx = new XlsxViewer(document.getElementById('xlsx-container')!);
51
+ const container = document.getElementById('xlsx-container') as HTMLElement;
52
+ const xlsx = new XlsxViewer(container);
52
53
  await xlsx.load('/workbook.xlsx');
53
54
 
54
- // PPTX — viewer manages its own <canvas>
55
- const pptx = new PptxViewer(document.getElementById('pptx-container')!);
56
- const buf = await fetch('/deck.pptx').then(r => r.arrayBuffer());
57
- await pptx.load(buf);
55
+ // PPTX — caller provides the <canvas>
56
+ const canvas = document.getElementById('pptx-canvas') as HTMLCanvasElement;
57
+ const pptx = new PptxViewer(canvas);
58
+ await pptx.load('/deck.pptx');
58
59
  pptx.nextSlide();
59
60
  ```
60
61
 
@@ -138,30 +139,24 @@ import { useEffect, useRef, useState } from 'react';
138
139
  import { PptxViewer } from '@silurus/ooxml/pptx';
139
140
 
140
141
  export function PptxViewerComponent({ src }: { src: string }) {
141
- const containerRef = useRef<HTMLDivElement>(null);
142
- const viewerRef = useRef<PptxViewer | null>(null);
142
+ const canvasRef = useRef<HTMLCanvasElement>(null);
143
+ const viewerRef = useRef<PptxViewer | null>(null);
143
144
  const [slide, setSlide] = useState({ current: 0, total: 0 });
144
145
 
145
146
  useEffect(() => {
146
- const container = containerRef.current;
147
- if (!container) return;
147
+ const canvas = canvasRef.current;
148
+ if (!canvas) return;
148
149
 
149
- const viewer = new PptxViewer(container, {
150
+ const viewer = new PptxViewer(canvas, {
150
151
  onSlideChange: (i, total) => setSlide({ current: i, total }),
151
152
  });
152
153
  viewerRef.current = viewer;
153
-
154
- let cancelled = false;
155
- fetch(src)
156
- .then(r => r.arrayBuffer())
157
- .then(buf => { if (!cancelled) viewer.load(buf); });
158
-
159
- return () => { cancelled = true; };
154
+ viewer.load(src);
160
155
  }, [src]);
161
156
 
162
157
  return (
163
158
  <div>
164
- <div ref={containerRef} style={{ width: 800 }} />
159
+ <canvas ref={canvasRef} style={{ width: 800 }} />
165
160
  <button onClick={() => viewerRef.current?.prevSlide()}>‹ Prev</button>
166
161
  <span> {slide.current + 1} / {slide.total} </span>
167
162
  <button onClick={() => viewerRef.current?.nextSlide()}>Next ›</button>
@@ -183,23 +178,22 @@ import { PptxViewer } from '@silurus/ooxml/pptx';
183
178
 
184
179
  const props = defineProps<{ src: string }>();
185
180
 
186
- const container = useTemplateRef<HTMLDivElement>('container');
181
+ const canvas = useTemplateRef<HTMLCanvasElement>('canvas');
187
182
  let viewer: PptxViewer | null = null;
188
183
  const current = ref(0);
189
184
  const total = ref(0);
190
185
 
191
186
  onMounted(async () => {
192
- viewer = new PptxViewer(container.value!, {
187
+ viewer = new PptxViewer(canvas.value!, {
193
188
  onSlideChange: (i, t) => { current.value = i; total.value = t; },
194
189
  });
195
- const buf = await fetch(props.src).then(r => r.arrayBuffer());
196
- await viewer.load(buf);
190
+ await viewer.load(props.src);
197
191
  });
198
192
  </script>
199
193
 
200
194
  <template>
201
195
  <div>
202
- <div ref="container" style="width: 800px" />
196
+ <canvas ref="canvas" style="width: 800px" />
203
197
  <button @click="viewer?.prevSlide()">‹ Prev</button>
204
198
  <span> {{ current + 1 }} / {{ total }} </span>
205
199
  <button @click="viewer?.nextSlide()">Next ›</button>
@@ -225,7 +219,7 @@ import { PptxViewer } from '@silurus/ooxml/pptx';
225
219
  standalone: true,
226
220
  template: `
227
221
  <div>
228
- <div #container style="width: 800px"></div>
222
+ <canvas #canvas style="width: 800px"></canvas>
229
223
  <button (click)="prev()">‹ Prev</button>
230
224
  <span> {{ current() + 1 }} / {{ total() }} </span>
231
225
  <button (click)="next()">Next ›</button>
@@ -233,18 +227,16 @@ import { PptxViewer } from '@silurus/ooxml/pptx';
233
227
  `,
234
228
  })
235
229
  export class PptxViewerComponent implements AfterViewInit {
236
- containerEl = viewChild.required<ElementRef<HTMLDivElement>>('container');
230
+ canvasEl = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');
237
231
  current = signal(0);
238
232
  total = signal(0);
239
233
  private viewer?: PptxViewer;
240
234
 
241
235
  ngAfterViewInit(): void {
242
- this.viewer = new PptxViewer(this.containerEl().nativeElement, {
236
+ this.viewer = new PptxViewer(this.canvasEl().nativeElement, {
243
237
  onSlideChange: (i, t) => { this.current.set(i); this.total.set(t); },
244
238
  });
245
- fetch('/deck.pptx')
246
- .then(r => r.arrayBuffer())
247
- .then(buf => this.viewer!.load(buf));
239
+ this.viewer.load('/deck.pptx');
248
240
  }
249
241
 
250
242
  prev(): void { this.viewer?.prevSlide(); }
@@ -267,22 +259,21 @@ export class PptxViewerComponent implements AfterViewInit {
267
259
 
268
260
  let { src }: { src: string } = $props();
269
261
 
270
- let container: HTMLDivElement;
262
+ let canvas: HTMLCanvasElement;
271
263
  let viewer: PptxViewer;
272
264
  let current = $state(0);
273
265
  let total = $state(0);
274
266
 
275
267
  onMount(async () => {
276
- viewer = new PptxViewer(container, {
268
+ viewer = new PptxViewer(canvas, {
277
269
  onSlideChange: (i, t) => { current = i; total = t; },
278
270
  });
279
- const buf = await fetch(src).then(r => r.arrayBuffer());
280
- await viewer.load(buf);
271
+ await viewer.load(src);
281
272
  });
282
273
  </script>
283
274
 
284
275
  <div>
285
- <div bind:this={container} style="width: 800px"></div>
276
+ <canvas bind:this={canvas} style="width: 800px"></canvas>
286
277
  <button onclick={() => viewer?.prevSlide()}>‹ Prev</button>
287
278
  <span> {current + 1} / {total} </span>
288
279
  <button onclick={() => viewer?.nextSlide()}>Next ›</button>
@@ -300,24 +291,23 @@ import { createSignal, onMount, onCleanup } from 'solid-js';
300
291
  import { PptxViewer } from '@silurus/ooxml/pptx';
301
292
 
302
293
  export function PptxViewerComponent(props: { src: string }) {
303
- let containerEl!: HTMLDivElement;
294
+ let canvasEl!: HTMLCanvasElement;
304
295
  let viewer: PptxViewer | undefined;
305
296
  const [current, setCurrent] = createSignal(0);
306
297
  const [total, setTotal ] = createSignal(0);
307
298
 
308
299
  onMount(async () => {
309
- viewer = new PptxViewer(containerEl, {
300
+ viewer = new PptxViewer(canvasEl, {
310
301
  onSlideChange: (i, t) => { setCurrent(i); setTotal(t); },
311
302
  });
312
- const buf = await fetch(props.src).then(r => r.arrayBuffer());
313
- await viewer.load(buf);
303
+ await viewer.load(props.src);
314
304
  });
315
305
 
316
306
  onCleanup(() => { /* viewer?.destroy?.() */ });
317
307
 
318
308
  return (
319
309
  <div>
320
- <div ref={containerEl} style={{ width: '800px' }} />
310
+ <canvas ref={canvasEl} style={{ width: '800px' }} />
321
311
  <button onClick={() => viewer?.prevSlide()}>‹ Prev</button>
322
312
  <span> {current() + 1} / {total()} </span>
323
313
  <button onClick={() => viewer?.nextSlide()}>Next ›</button>
@@ -337,25 +327,24 @@ import { component$, useSignal, useVisibleTask$ } from '@builder.io/qwik';
337
327
  import type { PptxViewer as PptxViewerType } from '@silurus/ooxml/pptx';
338
328
 
339
329
  export const PptxViewerComponent = component$<{ src: string }>(({ src }) => {
340
- const containerRef = useSignal<HTMLDivElement>();
330
+ const canvasRef = useSignal<HTMLCanvasElement>();
341
331
  const current = useSignal(0);
342
332
  const total = useSignal(0);
343
333
  let viewer: PptxViewerType | undefined;
344
334
 
345
335
  // useVisibleTask$ runs only in the browser, never during SSR
346
336
  useVisibleTask$(async () => {
347
- if (!containerRef.value) return;
337
+ if (!canvasRef.value) return;
348
338
  const { PptxViewer } = await import('@silurus/ooxml/pptx');
349
- viewer = new PptxViewer(containerRef.value, {
339
+ viewer = new PptxViewer(canvasRef.value, {
350
340
  onSlideChange: (i, t) => { current.value = i; total.value = t; },
351
341
  });
352
- const buf = await fetch(src).then(r => r.arrayBuffer());
353
- await viewer.load(buf);
342
+ await viewer.load(src);
354
343
  });
355
344
 
356
345
  return (
357
346
  <div>
358
- <div ref={containerRef} style={{ width: '800px' }} />
347
+ <canvas ref={canvasRef} style={{ width: '800px' }} />
359
348
  <button onClick$={() => viewer?.prevSlide()}>‹ Prev</button>
360
349
  <span> {current.value + 1} / {total.value} </span>
361
350
  <button onClick$={() => viewer?.nextSlide()}>Next ›</button>
@@ -554,7 +543,7 @@ cd packages/pptx/parser && wasm-pack build --target web && cp pkg/pptx_parser_bg
554
543
 
555
544
  - **Canvas-only rendering.** Documents are decoded and drawn to an `HTMLCanvasElement`. No script, link, form, or other active content from the source file is executed or injected into the DOM.
556
545
  - **ZIP decompression cap.** Each entry in the source archive is limited to 512 MiB of uncompressed output to block zip-bomb DoS.
557
- - **No network by default.** The library does not send telemetry or analytics, and does not contact third-party services unless you ask it to. In particular, PPTX theme webfonts are **not** loaded from Google Fonts unless you pass `useGoogleFonts: true` to `PptxPresentation.load()` / `new PptxViewer(...)`. Enabling that option causes the end-user's browser to send an HTTP request (IP and User-Agent) to `fonts.googleapis.com`, which may have GDPR implications for your application — consider self-hosting the required fonts via `@font-face` instead.
546
+ - **No network by default.** The library does not send telemetry or analytics, and does not contact third-party services unless you ask it to. In particular, theme webfonts (and Office font metric substitutes for XLSX) are **not** loaded from Google Fonts unless you pass `useGoogleFonts: true` to the relevant `Viewer` / `load(...)` options — supported uniformly by `DocxViewer`, `PptxViewer`, and `XlsxViewer`. Enabling that option causes the end-user's browser to send an HTTP request (IP and User-Agent) to `fonts.googleapis.com`, which may have GDPR implications for your application — consider self-hosting the required fonts via `@font-face` instead.
558
547
  - **XML parsing.** Uses `roxmltree`, which does not resolve external entities (XXE-safe by default).
559
548
 
560
549
  ## License
@@ -0,0 +1 @@
1
+ var e=Object.defineProperty,t=(t,n)=>{let r={};for(var i in t)e(r,i,{get:t[i],enumerable:!0});return n||e(r,Symbol.toStringTag,{value:`Module`}),r},n=3e3,r=20,i=25;async function a(e,t){if(typeof document>`u`)return;let a=new Set,o=new Set;for(let n of e){if(!n)continue;let e=n.toLowerCase();if(a.has(e))continue;a.add(e);let r=t[e];if(r){if(!document.querySelector(`link[href="${r.url}"]`))try{let e=document.createElement(`link`);e.rel=`stylesheet`,e.href=r.url,document.head.appendChild(e)}catch{}o.add((r.loadFamily??n).toLowerCase())}}if(o.size===0)return;let s=[];for(let e=0;e<i&&(s=[...document.fonts].filter(e=>o.has(e.family.toLowerCase())),!(s.length>0));e++)await new Promise(e=>setTimeout(e,r));await Promise.race([Promise.allSettled(s.map(e=>e.load())).then(()=>document.fonts.ready),new Promise(e=>setTimeout(e,n))])}function o(e,t,n={}){let r=n.pauseWhenHidden??!0,i=null,a=0,o=0,s=null,c=!1,l=!1,u=()=>{if(!l&&!(r&&typeof document<`u`&&document.hidden)){if(s){c=!0;return}i===null&&(i=requestAnimationFrame(d))}},d=async()=>{if(i=null,l)return;let t=a,n=o;try{let r=e(t,n);s=r instanceof Promise?r:Promise.resolve(),await s}catch(e){console.error(`[autoResize] render failed:`,e)}finally{s=null,c&&!l&&(c=!1,u())}},f=new ResizeObserver(e=>{for(let t of e){let e=t.contentRect;a=e.width,o=e.height}u()});f.observe(t);let p=()=>{typeof document<`u`&&!document.hidden&&u()};return r&&typeof document<`u`&&document.addEventListener(`visibilitychange`,p),()=>{l=!0,f.disconnect(),i!==null&&(cancelAnimationFrame(i),i=null),r&&typeof document<`u`&&document.removeEventListener(`visibilitychange`,p)}}Object.defineProperty(exports,`n`,{enumerable:!0,get:function(){return a}}),Object.defineProperty(exports,`r`,{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,`t`,{enumerable:!0,get:function(){return o}});
@@ -6,10 +6,32 @@ var e = Object.defineProperty, t = (t, n) => {
6
6
  enumerable: !0
7
7
  });
8
8
  return n || e(r, Symbol.toStringTag, { value: "Module" }), r;
9
- };
9
+ }, n = 3e3, r = 20, i = 25;
10
+ async function a(e, t) {
11
+ if (typeof document > "u") return;
12
+ let a = /* @__PURE__ */ new Set(), o = /* @__PURE__ */ new Set();
13
+ for (let n of e) {
14
+ if (!n) continue;
15
+ let e = n.toLowerCase();
16
+ if (a.has(e)) continue;
17
+ a.add(e);
18
+ let r = t[e];
19
+ if (r) {
20
+ if (!document.querySelector(`link[href="${r.url}"]`)) try {
21
+ let e = document.createElement("link");
22
+ e.rel = "stylesheet", e.href = r.url, document.head.appendChild(e);
23
+ } catch {}
24
+ o.add((r.loadFamily ?? n).toLowerCase());
25
+ }
26
+ }
27
+ if (o.size === 0) return;
28
+ let s = [];
29
+ for (let e = 0; e < i && (s = [...document.fonts].filter((e) => o.has(e.family.toLowerCase())), !(s.length > 0)); e++) await new Promise((e) => setTimeout(e, r));
30
+ await Promise.race([Promise.allSettled(s.map((e) => e.load())).then(() => document.fonts.ready), new Promise((e) => setTimeout(e, n))]);
31
+ }
10
32
  //#endregion
11
33
  //#region packages/core/src/autoResize.ts
12
- function n(e, t, n = {}) {
34
+ function o(e, t, n = {}) {
13
35
  let r = n.pauseWhenHidden ?? !0, i = null, a = 0, o = 0, s = null, c = !1, l = !1, u = () => {
14
36
  if (!l && !(r && typeof document < "u" && document.hidden)) {
15
37
  if (s) {
@@ -45,4 +67,4 @@ function n(e, t, n = {}) {
45
67
  };
46
68
  }
47
69
  //#endregion
48
- export { t as n, n as t };
70
+ export { a as n, t as r, o as t };