@file-viewer/pptx 2.1.16 → 2.1.17

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/dist/styles.d.ts CHANGED
@@ -1,2 +1,2 @@
1
- export declare const pptxViewerCss = "\n.flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}\n.flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}\n.flyfish-pptx-content[data-render-state=\"loading\"]{opacity:.82}\n.flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}\n.flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}\n\n.slide{position:relative;border:0;border-radius:0;overflow:hidden;margin-bottom:50px;margin-left:auto;margin-right:auto;z-index:100}\n.slide div.block{position:absolute;top:0;left:0;width:100%;line-height:1}\n.slide div.content{display:flex;flex-direction:column}\n.slide div.diagram-content{display:flex;flex-direction:column}\n.slide div.content-rtl{display:flex;flex-direction:column;direction:rtl}\n.slide .pregraph-rtl{direction:rtl}\n.slide .pregraph-ltr{direction:ltr}\n.slide .pregraph-inherit{direction:inherit}\n.slide .slide-prgrph{width:100%}\n.slide .line-break-br::before{content:\"\\A\";white-space:pre}\n.slide div.v-up{justify-content:flex-start}\n.slide div.v-mid{justify-content:center}\n.slide div.v-down{justify-content:flex-end}\n.slide div.h-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.h-left-rtl{justify-content:flex-end;align-items:flex-end;text-align:left}\n.slide div.h-mid{justify-content:center;align-items:center;text-align:center}\n.slide div.h-right{justify-content:flex-end;align-items:flex-end;text-align:right}\n.slide div.h-right-rtl{justify-content:flex-start;align-items:flex-start;text-align:right}\n.slide div.h-just,.slide div.h-dist{text-align:justify}\n.slide div.up-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.up-center{justify-content:flex-start;align-items:center}\n.slide div.up-right{justify-content:flex-start;align-items:flex-end}\n.slide div.center-left{justify-content:center;align-items:flex-start;text-align:left}\n.slide div.center-center{justify-content:center;align-items:center}\n.slide div.center-right{justify-content:center;align-items:flex-end}\n.slide div.down-left{justify-content:flex-end;align-items:flex-start;text-align:left}\n.slide div.down-center{justify-content:flex-end;align-items:center}\n.slide div.down-right{justify-content:flex-end;align-items:flex-end}\n.slide li.slide{margin:10px 0;font-size:18px}\n.slide table{position:absolute}\n.slide svg.drawing{position:absolute;overflow:visible}\n\n.flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}\n";
1
+ export declare const pptxViewerCss = "\n.flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}\n.flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}\n.flyfish-pptx-content[data-render-state=\"loading\"]{opacity:.82}\n.flyfish-pptx-slide-slot{display:flow-root;box-sizing:border-box;width:100%;min-width:0}\n.flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}\n.flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}\n\n.slide{position:relative;border:0;border-radius:0;overflow:hidden;margin-bottom:50px;margin-left:auto;margin-right:auto;z-index:100}\n.slide div.block{position:absolute;top:0;left:0;width:100%;line-height:1}\n.slide div.content{display:flex;flex-direction:column}\n.slide div.diagram-content{display:flex;flex-direction:column}\n.slide div.content-rtl{display:flex;flex-direction:column;direction:rtl}\n.slide .pregraph-rtl{direction:rtl}\n.slide .pregraph-ltr{direction:ltr}\n.slide .pregraph-inherit{direction:inherit}\n.slide .slide-prgrph{width:100%}\n.slide .line-break-br::before{content:\"\\A\";white-space:pre}\n.slide div.v-up{justify-content:flex-start}\n.slide div.v-mid{justify-content:center}\n.slide div.v-down{justify-content:flex-end}\n.slide div.h-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.h-left-rtl{justify-content:flex-end;align-items:flex-end;text-align:left}\n.slide div.h-mid{justify-content:center;align-items:center;text-align:center}\n.slide div.h-right{justify-content:flex-end;align-items:flex-end;text-align:right}\n.slide div.h-right-rtl{justify-content:flex-start;align-items:flex-start;text-align:right}\n.slide div.h-just,.slide div.h-dist{text-align:justify}\n.slide div.up-left{justify-content:flex-start;align-items:flex-start;text-align:left}\n.slide div.up-center{justify-content:flex-start;align-items:center}\n.slide div.up-right{justify-content:flex-start;align-items:flex-end}\n.slide div.center-left{justify-content:center;align-items:flex-start;text-align:left}\n.slide div.center-center{justify-content:center;align-items:center}\n.slide div.center-right{justify-content:center;align-items:flex-end}\n.slide div.down-left{justify-content:flex-end;align-items:flex-start;text-align:left}\n.slide div.down-center{justify-content:flex-end;align-items:center}\n.slide div.down-right{justify-content:flex-end;align-items:flex-end}\n.slide li.slide{margin:10px 0;font-size:18px}\n.slide table{position:absolute}\n.slide svg.drawing{position:absolute;overflow:visible}\n\n.flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}\n.flyfish-pptx-slide-slot:last-of-type > .slide{margin-bottom:0}\n";
2
2
  export declare const ensurePptxViewerStyles: (documentRef: Document) => void;
package/dist/styles.js CHANGED
@@ -35,10 +35,12 @@ export const pptxViewerCss = `
35
35
  .flyfish-pptx-scale-box{position:relative;box-sizing:border-box;max-width:100%;margin:0 auto;min-width:0}
36
36
  .flyfish-pptx-content{position:absolute;top:0;left:0;box-sizing:border-box;max-width:none;min-width:0;transform-origin:top left;will-change:transform}
37
37
  .flyfish-pptx-content[data-render-state="loading"]{opacity:.82}
38
+ .flyfish-pptx-slide-slot{display:flow-root;box-sizing:border-box;width:100%;min-width:0}
38
39
  .flyfish-pptx-content .slide{background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.12)}
39
40
  .flyfish-pptx-thumbnail{display:block;box-sizing:border-box;width:min(960px,100%);height:auto;margin:0 auto 28px;border-radius:12px;background:#fff;box-shadow:0 18px 36px rgba(18,35,52,.14)}
40
41
  ${legacyPptxCss}
41
42
  .flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}
43
+ .flyfish-pptx-slide-slot:last-of-type > .slide{margin-bottom:0}
42
44
  `;
43
45
  const PPTX_STYLE_ID = 'flyfish-pptx-native-style';
44
46
  export const ensurePptxViewerStyles = (documentRef) => {
package/dist/viewer.d.ts CHANGED
@@ -13,8 +13,15 @@ export declare class PptxViewer {
13
13
  private userZoomPercent;
14
14
  private currentZoomPercent;
15
15
  private thumbnailElement;
16
+ private slideSize;
17
+ private slideRecords;
18
+ private slideWindowTarget;
19
+ private slideWindowListeners;
20
+ private slideWindowFrame;
21
+ private charts;
16
22
  private disposed;
17
23
  private completed;
24
+ private readonly handleSlideWindowChange;
18
25
  private constructor();
19
26
  get zoomPercent(): number;
20
27
  open(): Promise<void>;
@@ -25,9 +32,31 @@ export declare class PptxViewer {
25
32
  private appendGlobalCss;
26
33
  private showThumbnail;
27
34
  private clearThumbnail;
35
+ private shouldWindowSlides;
36
+ private getSlideWindowOptions;
37
+ private getEstimatedSlideHeight;
38
+ private appendWindowedSlide;
39
+ private createWindowedSlideRecord;
40
+ private renderSlideRecord;
41
+ private unmountSlideRecord;
42
+ private updateMeasuredSlideHeight;
43
+ private syncWindowedPlaceholderHeights;
44
+ private scheduleSlideWindowUpdate;
45
+ private updateSlideWindow;
46
+ private getWindowedSlideIndexes;
47
+ private getDistanceFromViewport;
48
+ private getSlideViewport;
49
+ private attachSlideWindowListeners;
50
+ private addSlideWindowListener;
51
+ private detachSlideWindowListeners;
52
+ private findSlideWindowTarget;
53
+ private postProcessRenderedContent;
54
+ private postProcessSlideRecord;
28
55
  private complete;
29
56
  private fail;
30
57
  private attachResizeObserver;
31
58
  private scheduleResize;
32
59
  private resize;
60
+ private getMountedSlideElements;
61
+ private isSlideElement;
33
62
  }
package/dist/viewer.js CHANGED
@@ -25,6 +25,21 @@ const appendHtml = (container, html) => {
25
25
  container.append(template.content);
26
26
  return nodes[0] || null;
27
27
  };
28
+ const DEFAULT_INITIAL_SLIDES = 3;
29
+ const DEFAULT_BATCH_SIZE = 4;
30
+ const DEFAULT_OVERSCAN_VIEWPORTS = 1.5;
31
+ const DEFAULT_SLIDE_HEIGHT = 540;
32
+ const DEFAULT_SLIDE_GAP = 50;
33
+ const toPositiveInteger = (value, fallback, min = 1, max = Number.MAX_SAFE_INTEGER) => {
34
+ const numeric = typeof value === 'number' && Number.isFinite(value)
35
+ ? Math.floor(value)
36
+ : fallback;
37
+ return clamp(numeric, min, max);
38
+ };
39
+ const toPositiveNumber = (value, fallback, min = 0, max = Number.MAX_SAFE_INTEGER) => {
40
+ const numeric = typeof value === 'number' && Number.isFinite(value) ? value : fallback;
41
+ return clamp(numeric, min, max);
42
+ };
28
43
  export class PptxViewer {
29
44
  static async open(buffer, target, options = {}) {
30
45
  const viewer = new PptxViewer(buffer, target, options);
@@ -39,8 +54,15 @@ export class PptxViewer {
39
54
  this.userZoomPercent = 100;
40
55
  this.currentZoomPercent = 100;
41
56
  this.thumbnailElement = null;
57
+ this.slideSize = null;
58
+ this.slideRecords = [];
59
+ this.slideWindowTarget = null;
60
+ this.slideWindowListeners = [];
61
+ this.slideWindowFrame = 0;
62
+ this.charts = null;
42
63
  this.disposed = false;
43
64
  this.completed = false;
65
+ this.handleSlideWindowChange = () => this.scheduleSlideWindowUpdate();
44
66
  this.buffer = buffer;
45
67
  this.target = target;
46
68
  this.options = options;
@@ -62,6 +84,7 @@ export class PptxViewer {
62
84
  ensurePptxViewerStyles(this.target.ownerDocument || document);
63
85
  this.target.replaceChildren(this.scaleBox);
64
86
  this.attachResizeObserver();
87
+ this.attachSlideWindowListeners();
65
88
  this.startWorker();
66
89
  }
67
90
  async setZoom(percent) {
@@ -70,7 +93,7 @@ export class PptxViewer {
70
93
  this.scheduleResize();
71
94
  }
72
95
  destroy() {
73
- var _a, _b, _c;
96
+ var _a, _b, _c, _d;
74
97
  this.disposed = true;
75
98
  (_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
76
99
  this.worker = null;
@@ -79,12 +102,20 @@ export class PptxViewer {
79
102
  if (this.resizeFrame) {
80
103
  (_c = this.target.ownerDocument.defaultView) === null || _c === void 0 ? void 0 : _c.cancelAnimationFrame(this.resizeFrame);
81
104
  }
105
+ if (this.slideWindowFrame) {
106
+ (_d = this.target.ownerDocument.defaultView) === null || _d === void 0 ? void 0 : _d.cancelAnimationFrame(this.slideWindowFrame);
107
+ }
108
+ this.detachSlideWindowListeners();
82
109
  this.target.replaceChildren();
83
110
  }
84
111
  startWorker() {
85
112
  var _a;
86
113
  (_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
87
114
  this.completed = false;
115
+ this.charts = null;
116
+ this.slideSize = null;
117
+ this.slideRecords = [];
118
+ this.content.replaceChildren();
88
119
  this.content.dataset.renderState = 'loading';
89
120
  this.worker = createPptxWorker(this.options);
90
121
  this.worker.addEventListener('message', event => this.processMessage(event.data));
@@ -104,9 +135,14 @@ export class PptxViewer {
104
135
  switch (message.type) {
105
136
  case 'slide': {
106
137
  this.clearThumbnail();
107
- const element = appendHtml(this.content, String(message.data || ''));
108
- this.scheduleResize();
109
- (_b = (_a = this.options).onSlideRendered) === null || _b === void 0 ? void 0 : _b.call(_a, Number(message.slide_num || 0), element);
138
+ if (this.shouldWindowSlides()) {
139
+ this.appendWindowedSlide(String(message.data || ''), Number(message.slide_num || 0));
140
+ }
141
+ else {
142
+ const element = appendHtml(this.content, String(message.data || ''));
143
+ this.scheduleResize();
144
+ (_b = (_a = this.options).onSlideRendered) === null || _b === void 0 ? void 0 : _b.call(_a, Number(message.slide_num || 0), element);
145
+ }
110
146
  break;
111
147
  }
112
148
  case 'pptx-thumb':
@@ -114,6 +150,8 @@ export class PptxViewer {
114
150
  (_d = (_c = this.options).onThumbnail) === null || _d === void 0 ? void 0 : _d.call(_c, String(message.data || ''));
115
151
  break;
116
152
  case 'slideSize':
153
+ this.slideSize = (message.data || {});
154
+ this.syncWindowedPlaceholderHeights();
117
155
  (_f = (_e = this.options).onSlideSize) === null || _f === void 0 ? void 0 : _f.call(_e, (message.data || {}));
118
156
  break;
119
157
  case 'globalCSS':
@@ -160,17 +198,283 @@ export class PptxViewer {
160
198
  (_a = this.thumbnailElement) === null || _a === void 0 ? void 0 : _a.remove();
161
199
  this.thumbnailElement = null;
162
200
  }
201
+ shouldWindowSlides() {
202
+ var _a;
203
+ return Boolean(this.options.lazySlides || ((_a = this.options.listOptions) === null || _a === void 0 ? void 0 : _a.windowed));
204
+ }
205
+ getSlideWindowOptions() {
206
+ const listOptions = this.options.listOptions || {};
207
+ return {
208
+ initialSlides: toPositiveInteger(listOptions.initialSlides, DEFAULT_INITIAL_SLIDES, 1, 20),
209
+ batchSize: toPositiveInteger(listOptions.batchSize, DEFAULT_BATCH_SIZE, 1, 20),
210
+ overscanViewport: toPositiveNumber(listOptions.overscanViewport, DEFAULT_OVERSCAN_VIEWPORTS, 0.25, 6),
211
+ };
212
+ }
213
+ getEstimatedSlideHeight() {
214
+ var _a, _b;
215
+ const sizeHeight = Number((_a = this.slideSize) === null || _a === void 0 ? void 0 : _a.height);
216
+ const measuredHeight = (_b = this.slideRecords.find(record => record.estimatedHeight > 0)) === null || _b === void 0 ? void 0 : _b.estimatedHeight;
217
+ return Math.ceil((Number.isFinite(sizeHeight) && sizeHeight > 0
218
+ ? sizeHeight + DEFAULT_SLIDE_GAP
219
+ : measuredHeight || DEFAULT_SLIDE_HEIGHT + DEFAULT_SLIDE_GAP));
220
+ }
221
+ appendWindowedSlide(html, slideNumber) {
222
+ const record = this.createWindowedSlideRecord(html, slideNumber || this.slideRecords.length + 1);
223
+ this.slideRecords.push(record);
224
+ this.content.append(record.slot);
225
+ if (this.slideRecords.length <= this.getSlideWindowOptions().initialSlides) {
226
+ this.renderSlideRecord(record);
227
+ }
228
+ this.scheduleResize();
229
+ this.scheduleSlideWindowUpdate();
230
+ }
231
+ createWindowedSlideRecord(html, slideNumber) {
232
+ const slot = this.target.ownerDocument.createElement('div');
233
+ const estimatedHeight = this.getEstimatedSlideHeight();
234
+ slot.className = 'flyfish-pptx-slide-slot';
235
+ slot.dataset.slideNumber = String(slideNumber);
236
+ slot.style.minHeight = `${estimatedHeight}px`;
237
+ return {
238
+ slideNumber,
239
+ html,
240
+ slot,
241
+ element: null,
242
+ estimatedHeight,
243
+ rendered: false,
244
+ notified: false,
245
+ postProcessed: false,
246
+ };
247
+ }
248
+ renderSlideRecord(record) {
249
+ var _a, _b;
250
+ if (record.rendered || this.disposed) {
251
+ return;
252
+ }
253
+ record.slot.replaceChildren();
254
+ record.element = appendHtml(record.slot, record.html);
255
+ record.rendered = true;
256
+ record.postProcessed = false;
257
+ this.updateMeasuredSlideHeight(record);
258
+ if (!record.notified) {
259
+ record.notified = true;
260
+ (_b = (_a = this.options).onSlideRendered) === null || _b === void 0 ? void 0 : _b.call(_a, record.slideNumber, record.element);
261
+ }
262
+ if (this.completed) {
263
+ void this.postProcessSlideRecord(record).finally(() => this.scheduleResize());
264
+ }
265
+ this.scheduleResize();
266
+ }
267
+ unmountSlideRecord(record) {
268
+ if (!record.rendered) {
269
+ return;
270
+ }
271
+ this.updateMeasuredSlideHeight(record);
272
+ record.slot.replaceChildren();
273
+ record.element = null;
274
+ record.rendered = false;
275
+ record.postProcessed = false;
276
+ }
277
+ updateMeasuredSlideHeight(record) {
278
+ var _a;
279
+ const HTMLElementCtor = ((_a = this.target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.HTMLElement) || HTMLElement;
280
+ if (!(record.element instanceof HTMLElementCtor)) {
281
+ return;
282
+ }
283
+ const view = this.target.ownerDocument.defaultView || window;
284
+ const computed = view.getComputedStyle(record.element);
285
+ const marginTop = parseFloat(computed.marginTop) || 0;
286
+ const marginBottom = parseFloat(computed.marginBottom) || 0;
287
+ const measuredHeight = Math.ceil(record.element.offsetHeight + marginTop + marginBottom);
288
+ const nextHeight = Math.max(measuredHeight, record.estimatedHeight, 1);
289
+ record.estimatedHeight = nextHeight;
290
+ record.slot.style.minHeight = `${nextHeight}px`;
291
+ }
292
+ syncWindowedPlaceholderHeights() {
293
+ if (!this.shouldWindowSlides() || !this.slideRecords.length) {
294
+ return;
295
+ }
296
+ const estimatedHeight = this.getEstimatedSlideHeight();
297
+ for (const record of this.slideRecords) {
298
+ if (!record.rendered && record.estimatedHeight < estimatedHeight) {
299
+ record.estimatedHeight = estimatedHeight;
300
+ record.slot.style.minHeight = `${estimatedHeight}px`;
301
+ }
302
+ }
303
+ this.scheduleResize();
304
+ }
305
+ scheduleSlideWindowUpdate() {
306
+ if (!this.shouldWindowSlides() || this.disposed) {
307
+ return;
308
+ }
309
+ const view = this.target.ownerDocument.defaultView || window;
310
+ if (this.slideWindowFrame) {
311
+ view.cancelAnimationFrame(this.slideWindowFrame);
312
+ }
313
+ this.slideWindowFrame = view.requestAnimationFrame(() => this.updateSlideWindow());
314
+ }
315
+ updateSlideWindow() {
316
+ this.slideWindowFrame = 0;
317
+ if (!this.shouldWindowSlides() || !this.slideRecords.length || this.disposed) {
318
+ return;
319
+ }
320
+ const windowOptions = this.getSlideWindowOptions();
321
+ const indexesToRender = this.getWindowedSlideIndexes(windowOptions);
322
+ let changed = false;
323
+ this.slideRecords.forEach((record, index) => {
324
+ if (indexesToRender.has(index)) {
325
+ const wasRendered = record.rendered;
326
+ this.renderSlideRecord(record);
327
+ changed || (changed = !wasRendered);
328
+ }
329
+ else if (record.rendered) {
330
+ this.unmountSlideRecord(record);
331
+ changed = true;
332
+ }
333
+ });
334
+ if (changed) {
335
+ this.scheduleResize();
336
+ }
337
+ }
338
+ getWindowedSlideIndexes(windowOptions) {
339
+ const viewport = this.getSlideViewport();
340
+ const maxMountedSlides = Math.max(windowOptions.initialSlides, windowOptions.initialSlides + windowOptions.batchSize * 4, 12);
341
+ const selected = new Set();
342
+ for (let index = 0; index < Math.min(windowOptions.initialSlides, this.slideRecords.length); index += 1) {
343
+ selected.add(index);
344
+ }
345
+ const candidates = this.slideRecords
346
+ .map((record, index) => ({
347
+ index,
348
+ distance: this.getDistanceFromViewport(record, viewport, windowOptions.overscanViewport),
349
+ }))
350
+ .filter(candidate => candidate.distance !== Number.POSITIVE_INFINITY)
351
+ .sort((a, b) => a.distance - b.distance || a.index - b.index);
352
+ const closestFallback = candidates[0];
353
+ for (const candidate of candidates) {
354
+ if (candidate.distance > 0 && selected.size >= windowOptions.initialSlides) {
355
+ continue;
356
+ }
357
+ selected.add(candidate.index);
358
+ }
359
+ if (closestFallback) {
360
+ selected.add(closestFallback.index);
361
+ }
362
+ if (selected.size <= maxMountedSlides) {
363
+ return selected;
364
+ }
365
+ const capped = new Set();
366
+ for (let index = 0; index < Math.min(windowOptions.initialSlides, this.slideRecords.length); index += 1) {
367
+ capped.add(index);
368
+ }
369
+ for (const candidate of candidates) {
370
+ if (capped.size >= maxMountedSlides) {
371
+ break;
372
+ }
373
+ capped.add(candidate.index);
374
+ }
375
+ return capped;
376
+ }
377
+ getDistanceFromViewport(record, viewport, overscanViewport) {
378
+ const rect = record.slot.getBoundingClientRect();
379
+ const overscan = viewport.height * overscanViewport;
380
+ const top = viewport.top - overscan;
381
+ const bottom = viewport.bottom + overscan;
382
+ if (rect.bottom >= top && rect.top <= bottom) {
383
+ return 0;
384
+ }
385
+ if (rect.bottom < top) {
386
+ return top - rect.bottom;
387
+ }
388
+ if (rect.top > bottom) {
389
+ return rect.top - bottom;
390
+ }
391
+ return Number.POSITIVE_INFINITY;
392
+ }
393
+ getSlideViewport() {
394
+ const view = this.target.ownerDocument.defaultView || window;
395
+ const HTMLElementCtor = view.HTMLElement;
396
+ if (this.slideWindowTarget instanceof HTMLElementCtor) {
397
+ const rect = this.slideWindowTarget.getBoundingClientRect();
398
+ const height = Math.max(1, rect.height || this.slideWindowTarget.clientHeight || view.innerHeight || 1);
399
+ return {
400
+ top: rect.top,
401
+ bottom: rect.top + height,
402
+ height,
403
+ };
404
+ }
405
+ const height = Math.max(1, view.innerHeight || this.target.ownerDocument.documentElement.clientHeight || DEFAULT_SLIDE_HEIGHT);
406
+ return {
407
+ top: 0,
408
+ bottom: height,
409
+ height,
410
+ };
411
+ }
412
+ attachSlideWindowListeners() {
413
+ if (!this.shouldWindowSlides()) {
414
+ return;
415
+ }
416
+ this.detachSlideWindowListeners();
417
+ const view = this.target.ownerDocument.defaultView || window;
418
+ this.slideWindowTarget = this.findSlideWindowTarget();
419
+ this.addSlideWindowListener(view, 'scroll');
420
+ this.addSlideWindowListener(view, 'resize');
421
+ if (this.slideWindowTarget && this.slideWindowTarget !== view) {
422
+ this.addSlideWindowListener(this.slideWindowTarget, 'scroll');
423
+ }
424
+ }
425
+ addSlideWindowListener(target, type) {
426
+ target.addEventListener(type, this.handleSlideWindowChange, { passive: true });
427
+ this.slideWindowListeners.push({ target, type, listener: this.handleSlideWindowChange });
428
+ }
429
+ detachSlideWindowListeners() {
430
+ for (const { target, type, listener } of this.slideWindowListeners) {
431
+ target.removeEventListener(type, listener);
432
+ }
433
+ this.slideWindowListeners = [];
434
+ this.slideWindowTarget = null;
435
+ }
436
+ findSlideWindowTarget() {
437
+ const view = this.target.ownerDocument.defaultView || window;
438
+ let element = this.target.parentElement;
439
+ while (element && element !== this.target.ownerDocument.body && element !== this.target.ownerDocument.documentElement) {
440
+ const style = view.getComputedStyle(element);
441
+ if (/(auto|scroll|overlay)/.test(`${style.overflowY} ${style.overflow}`)) {
442
+ return element;
443
+ }
444
+ element = element.parentElement;
445
+ }
446
+ return view;
447
+ }
448
+ async postProcessRenderedContent(charts) {
449
+ if (!this.shouldWindowSlides()) {
450
+ await renderPptxPostProcessing(charts, this.content);
451
+ return;
452
+ }
453
+ await Promise.all(this.slideRecords
454
+ .filter(record => record.rendered)
455
+ .map(record => this.postProcessSlideRecord(record)));
456
+ }
457
+ async postProcessSlideRecord(record) {
458
+ if (!record.rendered || record.postProcessed || this.disposed) {
459
+ return;
460
+ }
461
+ await renderPptxPostProcessing(this.charts, record.slot);
462
+ record.postProcessed = true;
463
+ this.updateMeasuredSlideHeight(record);
464
+ }
163
465
  async complete(charts) {
164
466
  var _a, _b, _c;
165
467
  if (this.disposed || this.completed) {
166
468
  return;
167
469
  }
168
470
  this.completed = true;
471
+ this.charts = charts;
169
472
  this.content.dataset.renderState = 'ready';
170
473
  (_a = this.worker) === null || _a === void 0 ? void 0 : _a.terminate();
171
474
  this.worker = null;
475
+ this.scheduleSlideWindowUpdate();
172
476
  this.scheduleResize();
173
- await renderPptxPostProcessing(charts, this.content);
477
+ await this.postProcessRenderedContent(charts);
174
478
  this.scheduleResize();
175
479
  (_c = (_b = this.options).onRenderComplete) === null || _c === void 0 ? void 0 : _c.call(_b);
176
480
  }
@@ -189,7 +493,10 @@ export class PptxViewer {
189
493
  if (typeof ResizeObserver === 'undefined') {
190
494
  return;
191
495
  }
192
- this.resizeObserver = new ResizeObserver(() => this.scheduleResize());
496
+ this.resizeObserver = new ResizeObserver(() => {
497
+ this.scheduleResize();
498
+ this.scheduleSlideWindowUpdate();
499
+ });
193
500
  this.resizeObserver.observe(this.target);
194
501
  if (this.target.parentElement) {
195
502
  this.resizeObserver.observe(this.target.parentElement);
@@ -204,14 +511,10 @@ export class PptxViewer {
204
511
  }
205
512
  resize() {
206
513
  var _a, _b;
207
- const HTMLElementCtor = ((_a = this.target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.HTMLElement) || HTMLElement;
208
- const slides = Array.from(this.content.children).filter((child) => {
209
- return child instanceof HTMLElementCtor && (child.classList.contains('slide') || child.tagName === 'SECTION');
210
- });
211
- if (!slides.length) {
212
- return;
213
- }
214
- const slideWidth = Math.max(...slides.map(slide => slide.offsetWidth), 0);
514
+ const slides = this.getMountedSlideElements();
515
+ const sizeWidth = Number((_a = this.slideSize) === null || _a === void 0 ? void 0 : _a.width);
516
+ const fallbackWidth = Number.isFinite(sizeWidth) && sizeWidth > 0 ? sizeWidth : 0;
517
+ const slideWidth = Math.max(...slides.map(slide => slide.offsetWidth), fallbackWidth);
215
518
  if (!slideWidth) {
216
519
  return;
217
520
  }
@@ -227,4 +530,29 @@ export class PptxViewer {
227
530
  this.scaleBox.style.height = `${Math.ceil(this.content.scrollHeight * effectiveScale)}px`;
228
531
  this.scaleBox.style.minHeight = '';
229
532
  }
533
+ getMountedSlideElements() {
534
+ var _a;
535
+ const HTMLElementCtor = ((_a = this.target.ownerDocument.defaultView) === null || _a === void 0 ? void 0 : _a.HTMLElement) || HTMLElement;
536
+ const slides = [];
537
+ for (const child of Array.from(this.content.children)) {
538
+ if (!(child instanceof HTMLElementCtor)) {
539
+ continue;
540
+ }
541
+ if (this.isSlideElement(child)) {
542
+ slides.push(child);
543
+ continue;
544
+ }
545
+ if (!child.classList.contains('flyfish-pptx-slide-slot')) {
546
+ continue;
547
+ }
548
+ const firstChild = child.firstElementChild;
549
+ if (firstChild instanceof HTMLElementCtor && this.isSlideElement(firstChild)) {
550
+ slides.push(firstChild);
551
+ }
552
+ }
553
+ return slides;
554
+ }
555
+ isSlideElement(element) {
556
+ return element.classList.contains('slide') || element.tagName === 'SECTION';
557
+ }
230
558
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/pptx",
3
- "version": "2.1.16",
3
+ "version": "2.1.17",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Native PPTX renderer extracted from Flyfish File Viewer",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "funding": {
35
35
  "type": "individual",
36
- "url": "https://dev.flyfish.group/shop"
36
+ "url": "https://dev.flyfish.group/donate?source=npm"
37
37
  },
38
38
  "main": "./dist/index.js",
39
39
  "module": "./dist/index.js",