@extend-ai/react-pptx 0.1.1 → 0.2.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/CHANGELOG.md +6 -0
- package/README.md +43 -0
- package/dist/index.d.ts +64 -1
- package/dist/index.js +746 -107
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -9247,8 +9247,71 @@ var EMU_PER_CSS_PIXEL = 9525;
|
|
|
9247
9247
|
var DEFAULT_TEXT_HORIZONTAL_INSET_EMU = 91440;
|
|
9248
9248
|
var DEFAULT_TEXT_VERTICAL_INSET_EMU = 45720;
|
|
9249
9249
|
var POWERPOINT_SINGLE_LINE_HEIGHT = 1.15;
|
|
9250
|
+
var PresentationAssetCache = class {
|
|
9251
|
+
references = 0;
|
|
9252
|
+
objectUrls = /* @__PURE__ */ new Set();
|
|
9253
|
+
assetUrls = /* @__PURE__ */ new Map();
|
|
9254
|
+
metafileUrls = /* @__PURE__ */ new Map();
|
|
9255
|
+
acquire() {
|
|
9256
|
+
this.references += 1;
|
|
9257
|
+
return this;
|
|
9258
|
+
}
|
|
9259
|
+
metafileUrl(assetId, contentType, data) {
|
|
9260
|
+
const cached = this.metafileUrls.get(assetId);
|
|
9261
|
+
if (cached) return cached;
|
|
9262
|
+
const convert = contentType.includes("wmf") ? renderWmfToDataUrl : renderEmfToDataUrl;
|
|
9263
|
+
const ownedBytes = data.slice();
|
|
9264
|
+
const pending = convert(ownedBytes.buffer, 2048, 2048, {
|
|
9265
|
+
dpiScale: 2,
|
|
9266
|
+
maxCanvasDimension: 4096,
|
|
9267
|
+
maxRecords: 2e5,
|
|
9268
|
+
fontFamilyMap: METAFILE_FONT_MAP
|
|
9269
|
+
}).then((url) => url || void 0);
|
|
9270
|
+
this.metafileUrls.set(assetId, pending);
|
|
9271
|
+
return pending;
|
|
9272
|
+
}
|
|
9273
|
+
assetUrl(asset) {
|
|
9274
|
+
if (asset.url) return Promise.resolve(asset.url);
|
|
9275
|
+
if (!asset.data) return Promise.resolve(void 0);
|
|
9276
|
+
const contentType = asset.contentType.toLowerCase();
|
|
9277
|
+
if (contentType.includes("emf") || contentType.includes("wmf")) {
|
|
9278
|
+
return this.metafileUrl(asset.id, contentType, asset.data);
|
|
9279
|
+
}
|
|
9280
|
+
const cached = this.assetUrls.get(asset.id);
|
|
9281
|
+
if (cached) return Promise.resolve(cached);
|
|
9282
|
+
const ownedBytes = asset.data.slice();
|
|
9283
|
+
const url = URL.createObjectURL(
|
|
9284
|
+
new Blob([ownedBytes.buffer], { type: asset.contentType })
|
|
9285
|
+
);
|
|
9286
|
+
this.objectUrls.add(url);
|
|
9287
|
+
this.assetUrls.set(asset.id, url);
|
|
9288
|
+
return Promise.resolve(url);
|
|
9289
|
+
}
|
|
9290
|
+
release() {
|
|
9291
|
+
this.references = Math.max(0, this.references - 1);
|
|
9292
|
+
if (this.references > 0) return;
|
|
9293
|
+
for (const url of this.objectUrls) URL.revokeObjectURL(url);
|
|
9294
|
+
this.objectUrls.clear();
|
|
9295
|
+
this.assetUrls.clear();
|
|
9296
|
+
this.metafileUrls.clear();
|
|
9297
|
+
}
|
|
9298
|
+
};
|
|
9299
|
+
var presentationAssetCaches = /* @__PURE__ */ new WeakMap();
|
|
9300
|
+
function acquirePresentationAssetCache(presentation) {
|
|
9301
|
+
let cache = presentationAssetCaches.get(presentation);
|
|
9302
|
+
if (!cache) {
|
|
9303
|
+
cache = new PresentationAssetCache();
|
|
9304
|
+
presentationAssetCaches.set(presentation, cache);
|
|
9305
|
+
}
|
|
9306
|
+
return cache.acquire();
|
|
9307
|
+
}
|
|
9250
9308
|
var LIST_ITEM_GAP = 24;
|
|
9251
9309
|
var FALLBACK_VIEWPORT_RECT = { width: 800, height: 600 };
|
|
9310
|
+
function scaleListAnchorOffset(offset, previousSlideHeight, nextSlideHeight) {
|
|
9311
|
+
if (previousSlideHeight <= 0) return offset;
|
|
9312
|
+
if (offset <= previousSlideHeight) return offset * (nextSlideHeight / previousSlideHeight);
|
|
9313
|
+
return nextSlideHeight + (offset - previousSlideHeight);
|
|
9314
|
+
}
|
|
9252
9315
|
var METAFILE_FONT_MAP = Object.fromEntries(
|
|
9253
9316
|
Object.entries(OFFICE_FONT_FALLBACKS).map(([family, fallbacks]) => [
|
|
9254
9317
|
family,
|
|
@@ -9783,6 +9846,7 @@ var NormalizedPresentationViewer = class {
|
|
|
9783
9846
|
this.container = container;
|
|
9784
9847
|
this.presentation = presentation;
|
|
9785
9848
|
this.callbacks = callbacks;
|
|
9849
|
+
this.assetCache = acquirePresentationAssetCache(presentation);
|
|
9786
9850
|
}
|
|
9787
9851
|
container;
|
|
9788
9852
|
presentation;
|
|
@@ -9790,12 +9854,10 @@ var NormalizedPresentationViewer = class {
|
|
|
9790
9854
|
current = 0;
|
|
9791
9855
|
zoom = 100;
|
|
9792
9856
|
fit = "contain";
|
|
9793
|
-
|
|
9794
|
-
assetUrls = /* @__PURE__ */ new Map();
|
|
9795
|
-
metafileUrls = /* @__PURE__ */ new Map();
|
|
9857
|
+
assetCache;
|
|
9796
9858
|
listCleanup;
|
|
9797
9859
|
highlight;
|
|
9798
|
-
|
|
9860
|
+
activeMountResources;
|
|
9799
9861
|
mountedHandles = /* @__PURE__ */ new Set();
|
|
9800
9862
|
handlesByTarget = /* @__PURE__ */ new Map();
|
|
9801
9863
|
destroyed = false;
|
|
@@ -9826,6 +9888,10 @@ var NormalizedPresentationViewer = class {
|
|
|
9826
9888
|
const height = this.presentation.size.heightEmu / EMU_PER_CSS_PIXEL;
|
|
9827
9889
|
return Number.isFinite(height) && height > 0 ? height : 1;
|
|
9828
9890
|
}
|
|
9891
|
+
scaleForViewport(viewportWidth) {
|
|
9892
|
+
const fitScale = this.fit === "contain" ? Math.min(1, (viewportWidth || this.naturalSlideWidth) / this.naturalSlideWidth) : 1;
|
|
9893
|
+
return fitScale * (this.zoom / 100);
|
|
9894
|
+
}
|
|
9829
9895
|
isRenderActive(generation) {
|
|
9830
9896
|
return !this.destroyed && generation === this.renderGeneration;
|
|
9831
9897
|
}
|
|
@@ -9844,46 +9910,19 @@ var NormalizedPresentationViewer = class {
|
|
|
9844
9910
|
this.lastNotifiedSlide = index;
|
|
9845
9911
|
this.callbacks.onSlideChange?.(index);
|
|
9846
9912
|
}
|
|
9847
|
-
metafileUrl(assetId, contentType, data) {
|
|
9848
|
-
const cached = this.metafileUrls.get(assetId);
|
|
9849
|
-
if (cached) return cached;
|
|
9850
|
-
const convert = contentType.includes("wmf") ? renderWmfToDataUrl : renderEmfToDataUrl;
|
|
9851
|
-
const ownedBytes = data.slice();
|
|
9852
|
-
const pending = convert(ownedBytes.buffer, 2048, 2048, {
|
|
9853
|
-
dpiScale: 2,
|
|
9854
|
-
maxCanvasDimension: 4096,
|
|
9855
|
-
maxRecords: 2e5,
|
|
9856
|
-
fontFamilyMap: METAFILE_FONT_MAP
|
|
9857
|
-
}).then((url) => url || void 0);
|
|
9858
|
-
this.metafileUrls.set(assetId, pending);
|
|
9859
|
-
return pending;
|
|
9860
|
-
}
|
|
9861
9913
|
assetUrl(asset) {
|
|
9862
|
-
|
|
9863
|
-
if (!asset.data) return Promise.resolve(void 0);
|
|
9864
|
-
const contentType = asset.contentType.toLowerCase();
|
|
9865
|
-
if (contentType.includes("emf") || contentType.includes("wmf")) {
|
|
9866
|
-
return this.metafileUrl(asset.id, contentType, asset.data);
|
|
9867
|
-
}
|
|
9868
|
-
const cached = this.assetUrls.get(asset.id);
|
|
9869
|
-
if (cached) return Promise.resolve(cached);
|
|
9870
|
-
const ownedBytes = asset.data.slice();
|
|
9871
|
-
const url = URL.createObjectURL(
|
|
9872
|
-
new Blob([ownedBytes.buffer], { type: asset.contentType })
|
|
9873
|
-
);
|
|
9874
|
-
this.objectUrls.add(url);
|
|
9875
|
-
this.assetUrls.set(asset.id, url);
|
|
9876
|
-
return Promise.resolve(url);
|
|
9914
|
+
return this.assetCache.assetUrl(asset);
|
|
9877
9915
|
}
|
|
9878
9916
|
applyAsset(assetId, apply, nodeId) {
|
|
9879
9917
|
const asset = this.presentation.assets[assetId];
|
|
9880
9918
|
if (!asset) return;
|
|
9919
|
+
const resources = this.activeMountResources;
|
|
9881
9920
|
const pending = this.assetUrl(asset).then((url) => {
|
|
9882
9921
|
if (url && !this.destroyed) apply(url);
|
|
9883
9922
|
}).catch((error) => {
|
|
9884
9923
|
if (!this.destroyed) this.callbacks.onNodeError?.(nodeId, error);
|
|
9885
|
-
})
|
|
9886
|
-
|
|
9924
|
+
});
|
|
9925
|
+
resources?.add(pending);
|
|
9887
9926
|
}
|
|
9888
9927
|
/**
|
|
9889
9928
|
* Applies DrawingML picture recolor effects (`a:biLevel`, `a:grayscl`,
|
|
@@ -10039,11 +10078,7 @@ var NormalizedPresentationViewer = class {
|
|
|
10039
10078
|
image.setAttribute("preserveAspectRatio", "none");
|
|
10040
10079
|
image.setAttribute("clip-path", `url(#${clipId})`);
|
|
10041
10080
|
image.style.opacity = String(Math.max(0, Math.min(1, fillStyle.opacity ?? 1)));
|
|
10042
|
-
this.applyAsset(
|
|
10043
|
-
fillStyle.assetId,
|
|
10044
|
-
(url) => image.setAttribute("href", url),
|
|
10045
|
-
node.id
|
|
10046
|
-
);
|
|
10081
|
+
this.applyAsset(fillStyle.assetId, (url) => image.setAttribute("href", url), node.id);
|
|
10047
10082
|
svg.append(image);
|
|
10048
10083
|
}
|
|
10049
10084
|
if (node.line) {
|
|
@@ -10406,23 +10441,35 @@ var NormalizedPresentationViewer = class {
|
|
|
10406
10441
|
element,
|
|
10407
10442
|
target,
|
|
10408
10443
|
ready: Promise.resolve(),
|
|
10444
|
+
setScale: () => {
|
|
10445
|
+
},
|
|
10409
10446
|
dispose: () => element.remove()
|
|
10410
10447
|
};
|
|
10411
10448
|
}
|
|
10412
10449
|
mount(index, target, scale) {
|
|
10413
10450
|
if (this.destroyed) return this.emptyHandle(target);
|
|
10414
10451
|
this.handlesByTarget.get(target)?.dispose();
|
|
10415
|
-
const
|
|
10416
|
-
const
|
|
10417
|
-
|
|
10452
|
+
const resources = /* @__PURE__ */ new Set();
|
|
10453
|
+
const previousResources = this.activeMountResources;
|
|
10454
|
+
this.activeMountResources = resources;
|
|
10455
|
+
let slide;
|
|
10456
|
+
try {
|
|
10457
|
+
slide = this.createSlide(index);
|
|
10458
|
+
} finally {
|
|
10459
|
+
this.activeMountResources = previousResources;
|
|
10460
|
+
}
|
|
10461
|
+
const effectiveScale = scale ?? this.scaleForViewport(target.clientWidth);
|
|
10418
10462
|
const wrapper = document.createElement("div");
|
|
10419
10463
|
wrapper.dataset.rpvSlideWrapper = String(index);
|
|
10420
10464
|
wrapper.style.position = "relative";
|
|
10421
|
-
wrapper.style.width = `${this.naturalSlideWidth * effectiveScale}px`;
|
|
10422
|
-
wrapper.style.height = `${this.naturalSlideHeight * effectiveScale}px`;
|
|
10423
10465
|
wrapper.style.margin = "0 auto";
|
|
10424
10466
|
slide.style.transformOrigin = "top left";
|
|
10425
|
-
|
|
10467
|
+
const setScale = (nextScale) => {
|
|
10468
|
+
wrapper.style.width = `${this.naturalSlideWidth * nextScale}px`;
|
|
10469
|
+
wrapper.style.height = `${this.naturalSlideHeight * nextScale}px`;
|
|
10470
|
+
slide.style.transform = `scale(${nextScale})`;
|
|
10471
|
+
};
|
|
10472
|
+
setScale(effectiveScale);
|
|
10426
10473
|
wrapper.append(slide);
|
|
10427
10474
|
target.replaceChildren(wrapper);
|
|
10428
10475
|
this.callbacks.onSlideRendered?.(index, slide);
|
|
@@ -10430,7 +10477,8 @@ var NormalizedPresentationViewer = class {
|
|
|
10430
10477
|
const handle = {
|
|
10431
10478
|
element: slide,
|
|
10432
10479
|
target,
|
|
10433
|
-
ready: Promise.all([...
|
|
10480
|
+
ready: Promise.all([...resources]).then(() => void 0),
|
|
10481
|
+
setScale,
|
|
10434
10482
|
dispose: () => {
|
|
10435
10483
|
if (disposed) return;
|
|
10436
10484
|
disposed = true;
|
|
@@ -10458,6 +10506,32 @@ var NormalizedPresentationViewer = class {
|
|
|
10458
10506
|
await Promise.resolve();
|
|
10459
10507
|
}
|
|
10460
10508
|
}
|
|
10509
|
+
async yieldNavigationPaint() {
|
|
10510
|
+
if (typeof requestAnimationFrame !== "undefined") {
|
|
10511
|
+
await new Promise((resolve) => {
|
|
10512
|
+
let settled = false;
|
|
10513
|
+
let firstFrame;
|
|
10514
|
+
let secondFrame;
|
|
10515
|
+
const complete = () => {
|
|
10516
|
+
if (settled) return;
|
|
10517
|
+
settled = true;
|
|
10518
|
+
clearTimeout(timeout2);
|
|
10519
|
+
if (typeof cancelAnimationFrame !== "undefined") {
|
|
10520
|
+
if (firstFrame !== void 0) cancelAnimationFrame(firstFrame);
|
|
10521
|
+
if (secondFrame !== void 0) cancelAnimationFrame(secondFrame);
|
|
10522
|
+
}
|
|
10523
|
+
resolve();
|
|
10524
|
+
};
|
|
10525
|
+
const timeout2 = setTimeout(complete, 100);
|
|
10526
|
+
firstFrame = requestAnimationFrame(() => {
|
|
10527
|
+
if (settled) return;
|
|
10528
|
+
secondFrame = requestAnimationFrame(complete);
|
|
10529
|
+
});
|
|
10530
|
+
});
|
|
10531
|
+
} else {
|
|
10532
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
10533
|
+
}
|
|
10534
|
+
}
|
|
10461
10535
|
async mountInBatches(placeholders, indices, batchSize, generation) {
|
|
10462
10536
|
const uniqueIndices = [...new Set(indices)].filter(
|
|
10463
10537
|
(index) => index >= 0 && index < placeholders.length
|
|
@@ -10490,12 +10564,13 @@ var NormalizedPresentationViewer = class {
|
|
|
10490
10564
|
createListPlaceholder(index, item, generation, scale) {
|
|
10491
10565
|
let handle;
|
|
10492
10566
|
let mountPromise;
|
|
10567
|
+
let effectiveScale = scale;
|
|
10493
10568
|
const isActive = () => this.isRenderActive(generation) && this.listState?.generation === generation;
|
|
10494
10569
|
const mount = () => {
|
|
10495
10570
|
if (!isActive()) return Promise.resolve();
|
|
10496
10571
|
if (handle) return handle.ready;
|
|
10497
10572
|
if (mountPromise) return mountPromise;
|
|
10498
|
-
const nextHandle = this.mount(index, item,
|
|
10573
|
+
const nextHandle = this.mount(index, item, effectiveScale);
|
|
10499
10574
|
handle = nextHandle;
|
|
10500
10575
|
const pending = nextHandle.ready.then(() => {
|
|
10501
10576
|
if (!isActive() || handle !== nextHandle) {
|
|
@@ -10511,11 +10586,16 @@ var NormalizedPresentationViewer = class {
|
|
|
10511
10586
|
const unmount = () => {
|
|
10512
10587
|
const mounted = handle;
|
|
10513
10588
|
handle = void 0;
|
|
10589
|
+
mountPromise = void 0;
|
|
10514
10590
|
if (mounted) {
|
|
10515
10591
|
mounted.dispose();
|
|
10516
10592
|
}
|
|
10517
10593
|
};
|
|
10518
|
-
|
|
10594
|
+
const setScale = (nextScale) => {
|
|
10595
|
+
effectiveScale = nextScale;
|
|
10596
|
+
handle?.setScale(nextScale);
|
|
10597
|
+
};
|
|
10598
|
+
return { item, mount, unmount, isMounted: () => Boolean(handle), setScale };
|
|
10519
10599
|
}
|
|
10520
10600
|
async renderList(options = {}) {
|
|
10521
10601
|
const windowingEnabled = options.enabled !== false;
|
|
@@ -10539,11 +10619,9 @@ var NormalizedPresentationViewer = class {
|
|
|
10539
10619
|
Math.min(this.slideCount - 1, options.initialSlideIndex ?? this.current)
|
|
10540
10620
|
);
|
|
10541
10621
|
const scroller = options.scrollElement ?? this.container;
|
|
10542
|
-
|
|
10543
|
-
|
|
10544
|
-
|
|
10545
|
-
const slideHeight = this.naturalSlideHeight * effectiveScale;
|
|
10546
|
-
const itemStride = slideHeight + LIST_ITEM_GAP;
|
|
10622
|
+
let effectiveScale = this.scaleForViewport(scroller.clientWidth);
|
|
10623
|
+
let slideHeight = this.naturalSlideHeight * effectiveScale;
|
|
10624
|
+
let itemStride = slideHeight + LIST_ITEM_GAP;
|
|
10547
10625
|
if (!windowingEnabled) {
|
|
10548
10626
|
const placeholders2 = this.presentation.slides.map((_, index) => {
|
|
10549
10627
|
const item = document.createElement("div");
|
|
@@ -10551,9 +10629,35 @@ var NormalizedPresentationViewer = class {
|
|
|
10551
10629
|
item.style.minHeight = `${slideHeight}px`;
|
|
10552
10630
|
item.style.margin = `0 auto ${LIST_ITEM_GAP}px`;
|
|
10553
10631
|
this.container.append(item);
|
|
10554
|
-
return this.createListPlaceholder(index, item, generation);
|
|
10632
|
+
return this.createListPlaceholder(index, item, generation, effectiveScale);
|
|
10555
10633
|
});
|
|
10556
10634
|
const state2 = { generation, options: normalizedOptions, placeholders: placeholders2 };
|
|
10635
|
+
state2.updateScale = () => {
|
|
10636
|
+
if (!this.isRenderActive(generation) || this.listState !== state2) return;
|
|
10637
|
+
const previousStride = itemStride;
|
|
10638
|
+
const previousSlideHeight = slideHeight;
|
|
10639
|
+
const listStart = scroller === this.container ? 0 : this.container.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
|
|
10640
|
+
const listOffset = scroller.scrollTop - listStart;
|
|
10641
|
+
const anchorIndex = Math.max(
|
|
10642
|
+
0,
|
|
10643
|
+
Math.min(this.slideCount - 1, Math.floor(listOffset / previousStride))
|
|
10644
|
+
);
|
|
10645
|
+
const anchorOffset = listOffset - anchorIndex * previousStride;
|
|
10646
|
+
effectiveScale = this.scaleForViewport(scroller.clientWidth);
|
|
10647
|
+
slideHeight = this.naturalSlideHeight * effectiveScale;
|
|
10648
|
+
itemStride = slideHeight + LIST_ITEM_GAP;
|
|
10649
|
+
placeholders2.forEach((placeholder) => {
|
|
10650
|
+
placeholder.item.style.minHeight = `${slideHeight}px`;
|
|
10651
|
+
placeholder.setScale(effectiveScale);
|
|
10652
|
+
});
|
|
10653
|
+
if (listOffset < 0) return;
|
|
10654
|
+
const nextAnchorOffset = scaleListAnchorOffset(
|
|
10655
|
+
anchorOffset,
|
|
10656
|
+
previousSlideHeight,
|
|
10657
|
+
slideHeight
|
|
10658
|
+
);
|
|
10659
|
+
scroller.scrollTop = Math.max(0, listStart + anchorIndex * itemStride + nextAnchorOffset);
|
|
10660
|
+
};
|
|
10557
10661
|
this.listState = state2;
|
|
10558
10662
|
await this.mountInBatches(
|
|
10559
10663
|
placeholders2,
|
|
@@ -10595,6 +10699,20 @@ var NormalizedPresentationViewer = class {
|
|
|
10595
10699
|
const state = { generation, options: normalizedOptions, placeholders };
|
|
10596
10700
|
this.listState = state;
|
|
10597
10701
|
const isActive = () => this.isRenderActive(generation) && this.listState === state;
|
|
10702
|
+
const deferredMounts = /* @__PURE__ */ new Map();
|
|
10703
|
+
let virtualWindow = /* @__PURE__ */ new Set();
|
|
10704
|
+
state.deferMount = (index) => {
|
|
10705
|
+
deferredMounts.set(index, (deferredMounts.get(index) ?? 0) + 1);
|
|
10706
|
+
};
|
|
10707
|
+
state.resumeMount = (index) => {
|
|
10708
|
+
const remaining = (deferredMounts.get(index) ?? 0) - 1;
|
|
10709
|
+
if (remaining > 0) {
|
|
10710
|
+
deferredMounts.set(index, remaining);
|
|
10711
|
+
return;
|
|
10712
|
+
}
|
|
10713
|
+
deferredMounts.delete(index);
|
|
10714
|
+
if (virtualWindow.has(index)) void placeholders[index]?.mount();
|
|
10715
|
+
};
|
|
10598
10716
|
const measureViewportRect = () => {
|
|
10599
10717
|
const rect = scroller.getBoundingClientRect();
|
|
10600
10718
|
if (rect.width > 0 && rect.height > 0) return { width: rect.width, height: rect.height };
|
|
@@ -10606,16 +10724,25 @@ var NormalizedPresentationViewer = class {
|
|
|
10606
10724
|
const initialRect = measureViewportRect();
|
|
10607
10725
|
const requestedOverscan = options.overscanViewport ?? 1.5;
|
|
10608
10726
|
const overscanViewports = Number.isFinite(requestedOverscan) && requestedOverscan >= 0 ? requestedOverscan : 1.5;
|
|
10609
|
-
|
|
10727
|
+
let overscan = Math.max(1, Math.ceil(overscanViewports * initialRect.height / itemStride));
|
|
10610
10728
|
const measureScrollMargin = () => sizer.getBoundingClientRect().top - scroller.getBoundingClientRect().top + scroller.scrollTop;
|
|
10611
10729
|
let scrollMargin = measureScrollMargin();
|
|
10612
10730
|
let needsSettleAlignment = initialIndex > 0;
|
|
10613
10731
|
let lastProgrammaticTop;
|
|
10732
|
+
const writeScrollTop = (top, behavior) => {
|
|
10733
|
+
lastProgrammaticTop = top;
|
|
10734
|
+
if (typeof scroller.scrollTo === "function") {
|
|
10735
|
+
scroller.scrollTo(behavior ? { top, behavior } : { top });
|
|
10736
|
+
} else {
|
|
10737
|
+
scroller.scrollTop = top;
|
|
10738
|
+
}
|
|
10739
|
+
};
|
|
10614
10740
|
const reconcile = (instance) => {
|
|
10615
10741
|
if (!isActive()) return;
|
|
10616
10742
|
const windowed = new Set(instance.getVirtualItems().map((item) => item.index));
|
|
10743
|
+
virtualWindow = windowed;
|
|
10617
10744
|
placeholders.forEach((placeholder, index) => {
|
|
10618
|
-
if (windowed.has(index)) void placeholder.mount();
|
|
10745
|
+
if (windowed.has(index) && !deferredMounts.has(index)) void placeholder.mount();
|
|
10619
10746
|
else placeholder.unmount();
|
|
10620
10747
|
});
|
|
10621
10748
|
const offset = (instance.scrollOffset ?? 0) - scrollMargin;
|
|
@@ -10678,12 +10805,7 @@ var NormalizedPresentationViewer = class {
|
|
|
10678
10805
|
},
|
|
10679
10806
|
scrollToFn: (offset, { adjustments, behavior }) => {
|
|
10680
10807
|
const top = offset + (adjustments ?? 0);
|
|
10681
|
-
|
|
10682
|
-
if (typeof scroller.scrollTo === "function") {
|
|
10683
|
-
scroller.scrollTo(behavior ? { top, behavior } : { top });
|
|
10684
|
-
} else {
|
|
10685
|
-
scroller.scrollTop = top;
|
|
10686
|
-
}
|
|
10808
|
+
writeScrollTop(top, behavior);
|
|
10687
10809
|
},
|
|
10688
10810
|
onChange: (instance) => reconcile(instance)
|
|
10689
10811
|
});
|
|
@@ -10694,6 +10816,39 @@ var NormalizedPresentationViewer = class {
|
|
|
10694
10816
|
behavior: scrollOptions?.behavior === "smooth" ? "smooth" : "auto"
|
|
10695
10817
|
});
|
|
10696
10818
|
};
|
|
10819
|
+
state.updateScale = () => {
|
|
10820
|
+
if (!isActive()) return;
|
|
10821
|
+
const previousStride = itemStride;
|
|
10822
|
+
const previousSlideHeight = slideHeight;
|
|
10823
|
+
const anchorIndex = this.current;
|
|
10824
|
+
const observedScrollTop = virtualizer.scrollOffset ?? scroller.scrollTop;
|
|
10825
|
+
const observedIndex = Math.floor((observedScrollTop - scrollMargin) / previousStride);
|
|
10826
|
+
const intendedIndex = lastProgrammaticTop === void 0 ? void 0 : Math.floor((lastProgrammaticTop - scrollMargin) / previousStride);
|
|
10827
|
+
const previousScrollTop = Math.abs(observedIndex - anchorIndex) > 1 && intendedIndex !== void 0 && Math.abs(intendedIndex - anchorIndex) <= 1 ? lastProgrammaticTop : observedScrollTop;
|
|
10828
|
+
const previousOffset = previousScrollTop - scrollMargin;
|
|
10829
|
+
const anchorOffset = previousOffset - anchorIndex * previousStride;
|
|
10830
|
+
effectiveScale = this.scaleForViewport(scroller.clientWidth);
|
|
10831
|
+
slideHeight = this.naturalSlideHeight * effectiveScale;
|
|
10832
|
+
itemStride = slideHeight + LIST_ITEM_GAP;
|
|
10833
|
+
sizer.style.height = `${this.slideCount * itemStride - LIST_ITEM_GAP}px`;
|
|
10834
|
+
placeholders.forEach((placeholder, index) => {
|
|
10835
|
+
placeholder.item.style.height = `${slideHeight}px`;
|
|
10836
|
+
placeholder.item.style.transform = `translateY(${index * itemStride}px)`;
|
|
10837
|
+
placeholder.setScale(effectiveScale);
|
|
10838
|
+
});
|
|
10839
|
+
const nextAnchorOffset = scaleListAnchorOffset(
|
|
10840
|
+
anchorOffset,
|
|
10841
|
+
previousSlideHeight,
|
|
10842
|
+
slideHeight
|
|
10843
|
+
);
|
|
10844
|
+
const nextScrollTop = previousOffset < 0 ? previousScrollTop : Math.max(0, scrollMargin + anchorIndex * itemStride + nextAnchorOffset);
|
|
10845
|
+
const viewportRect = measureViewportRect();
|
|
10846
|
+
overscan = Math.max(1, Math.ceil(overscanViewports * viewportRect.height / itemStride));
|
|
10847
|
+
virtualizer.scrollOffset = nextScrollTop;
|
|
10848
|
+
writeScrollTop(nextScrollTop);
|
|
10849
|
+
virtualizer.setOptions({ ...virtualizer.options, overscan });
|
|
10850
|
+
virtualizer.measure();
|
|
10851
|
+
};
|
|
10697
10852
|
const teardown = virtualizer._didMount();
|
|
10698
10853
|
this.listCleanup = teardown;
|
|
10699
10854
|
virtualizer._willUpdate();
|
|
@@ -10721,16 +10876,27 @@ var NormalizedPresentationViewer = class {
|
|
|
10721
10876
|
if (state && this.isRenderActive(state.generation)) {
|
|
10722
10877
|
const navigation = ++this.navigationGeneration;
|
|
10723
10878
|
const placeholder = state.placeholders[next];
|
|
10724
|
-
|
|
10725
|
-
if (
|
|
10726
|
-
|
|
10727
|
-
|
|
10728
|
-
|
|
10729
|
-
|
|
10730
|
-
|
|
10879
|
+
let mountDeferred = Boolean(state.deferMount && placeholder && !placeholder.isMounted());
|
|
10880
|
+
if (mountDeferred) state.deferMount?.(next);
|
|
10881
|
+
try {
|
|
10882
|
+
if (changed) {
|
|
10883
|
+
if (state.scrollToIndex) state.scrollToIndex(next, scrollOptions);
|
|
10884
|
+
else placeholder?.item.scrollIntoView?.(scrollOptions);
|
|
10885
|
+
this.current = next;
|
|
10886
|
+
this.notifySlideChange(next);
|
|
10887
|
+
}
|
|
10888
|
+
if (mountDeferred) await this.yieldNavigationPaint();
|
|
10889
|
+
if (this.destroyed || navigation !== this.navigationGeneration || !this.isRenderActive(state.generation) || this.listState !== state) {
|
|
10890
|
+
return;
|
|
10891
|
+
}
|
|
10892
|
+
if (mountDeferred) {
|
|
10893
|
+
state.resumeMount?.(next);
|
|
10894
|
+
mountDeferred = false;
|
|
10895
|
+
}
|
|
10896
|
+
await placeholder?.mount();
|
|
10897
|
+
} finally {
|
|
10898
|
+
if (mountDeferred) state.resumeMount?.(next);
|
|
10731
10899
|
}
|
|
10732
|
-
this.current = next;
|
|
10733
|
-
if (changed) this.notifySlideChange(next);
|
|
10734
10900
|
return;
|
|
10735
10901
|
}
|
|
10736
10902
|
if (!changed && this.container.querySelector(`[data-rpv-slide-index="${next}"]`)) return;
|
|
@@ -10741,15 +10907,33 @@ var NormalizedPresentationViewer = class {
|
|
|
10741
10907
|
if (this.zoom === next) return;
|
|
10742
10908
|
this.zoom = next;
|
|
10743
10909
|
if (this.renderState?.mode === "continuous") {
|
|
10744
|
-
|
|
10745
|
-
|
|
10910
|
+
const state = this.listState;
|
|
10911
|
+
if (state && this.isRenderActive(state.generation) && state.updateScale) {
|
|
10912
|
+
state.updateScale();
|
|
10913
|
+
} else {
|
|
10914
|
+
await this.renderList({ ...this.renderState.options, initialSlideIndex: this.current });
|
|
10915
|
+
}
|
|
10916
|
+
} else if (this.renderState) {
|
|
10917
|
+
const handle = this.handlesByTarget.get(this.container);
|
|
10918
|
+
if (handle) handle.setScale(this.scaleForViewport(this.container.clientWidth));
|
|
10919
|
+
else await this.renderSlide(this.current);
|
|
10920
|
+
}
|
|
10746
10921
|
}
|
|
10747
10922
|
async setFitMode(mode) {
|
|
10748
10923
|
if (this.fit === mode) return;
|
|
10749
10924
|
this.fit = mode;
|
|
10750
10925
|
if (this.renderState?.mode === "continuous") {
|
|
10751
|
-
|
|
10752
|
-
|
|
10926
|
+
const state = this.listState;
|
|
10927
|
+
if (state && this.isRenderActive(state.generation) && state.updateScale) {
|
|
10928
|
+
state.updateScale();
|
|
10929
|
+
} else {
|
|
10930
|
+
await this.renderList({ ...this.renderState.options, initialSlideIndex: this.current });
|
|
10931
|
+
}
|
|
10932
|
+
} else if (this.renderState) {
|
|
10933
|
+
const handle = this.handlesByTarget.get(this.container);
|
|
10934
|
+
if (handle) handle.setScale(this.scaleForViewport(this.container.clientWidth));
|
|
10935
|
+
else await this.renderSlide(this.current);
|
|
10936
|
+
}
|
|
10753
10937
|
}
|
|
10754
10938
|
searchText(query, options) {
|
|
10755
10939
|
return searchDocument(this.presentation, query, options);
|
|
@@ -10827,11 +11011,8 @@ var NormalizedPresentationViewer = class {
|
|
|
10827
11011
|
this.listCleanup = void 0;
|
|
10828
11012
|
this.listState = void 0;
|
|
10829
11013
|
this.clearSearchHighlights();
|
|
10830
|
-
|
|
10831
|
-
this.
|
|
10832
|
-
this.assetUrls.clear();
|
|
10833
|
-
this.metafileUrls.clear();
|
|
10834
|
-
this.pendingResources.clear();
|
|
11014
|
+
this.assetCache.release();
|
|
11015
|
+
this.activeMountResources = void 0;
|
|
10835
11016
|
for (const handle of [...this.mountedHandles]) handle.dispose();
|
|
10836
11017
|
this.handlesByTarget.clear();
|
|
10837
11018
|
this.renderState = void 0;
|
|
@@ -10990,6 +11171,18 @@ async function parseInWorker(bytes, signal, wasmSource) {
|
|
|
10990
11171
|
});
|
|
10991
11172
|
}
|
|
10992
11173
|
|
|
11174
|
+
// src/performance.ts
|
|
11175
|
+
function performanceNow() {
|
|
11176
|
+
return globalThis.performance?.now?.() ?? Date.now();
|
|
11177
|
+
}
|
|
11178
|
+
function performanceMeasurement(phase, startedAt, slideIndex) {
|
|
11179
|
+
return {
|
|
11180
|
+
durationMs: Math.max(0, performanceNow() - startedAt),
|
|
11181
|
+
phase,
|
|
11182
|
+
...slideIndex === void 0 ? {} : { slideIndex }
|
|
11183
|
+
};
|
|
11184
|
+
}
|
|
11185
|
+
|
|
10993
11186
|
// src/parse.ts
|
|
10994
11187
|
var DEFAULT_MAX_INPUT_BYTES = 100 * 1024 * 1024;
|
|
10995
11188
|
function isParsedPresentation(source) {
|
|
@@ -11074,14 +11267,20 @@ async function parsePresentation(source, options = {}) {
|
|
|
11074
11267
|
warnings: source.warnings
|
|
11075
11268
|
};
|
|
11076
11269
|
}
|
|
11270
|
+
const downloadStartedAt = performanceNow();
|
|
11077
11271
|
const buffer = await readSource(source, options);
|
|
11272
|
+
if (typeof source === "string" || source instanceof URL) {
|
|
11273
|
+
options.onPerformanceMeasurement?.(performanceMeasurement("download", downloadStartedAt));
|
|
11274
|
+
}
|
|
11078
11275
|
const format = detectFormat(buffer, options.formatHint);
|
|
11079
11276
|
const bytes = new Uint8Array(buffer);
|
|
11080
11277
|
throwIfAborted(options.signal);
|
|
11278
|
+
const parsingStartedAt = performanceNow();
|
|
11081
11279
|
const nativeDocument = await parseWithWasm(bytes, {
|
|
11082
11280
|
formatHint: format,
|
|
11083
11281
|
...options.signal ? { signal: options.signal } : {}
|
|
11084
11282
|
});
|
|
11283
|
+
options.onPerformanceMeasurement?.(performanceMeasurement("wasm-parsing", parsingStartedAt));
|
|
11085
11284
|
throwIfAborted(options.signal);
|
|
11086
11285
|
if (!nativeDocument) {
|
|
11087
11286
|
throw new PptxViewerError(
|
|
@@ -11099,7 +11298,7 @@ var presentationParsingDefaults = Object.freeze({
|
|
|
11099
11298
|
maxInputBytes: DEFAULT_MAX_INPUT_BYTES
|
|
11100
11299
|
});
|
|
11101
11300
|
var THUMBNAIL_ROW_ESTIMATE = 123;
|
|
11102
|
-
var THUMBNAIL_OVERSCAN =
|
|
11301
|
+
var THUMBNAIL_OVERSCAN = 1;
|
|
11103
11302
|
var THUMBNAIL_INITIAL_RECT = { height: 780, width: 184 };
|
|
11104
11303
|
var observeThumbnailFilmstripRect = (instance, callback) => {
|
|
11105
11304
|
const element = instance.scrollElement;
|
|
@@ -11158,7 +11357,11 @@ async function createAdapter(target, parsed, props, getCurrentProps, onCurrentSl
|
|
|
11158
11357
|
const fontManager = new PptxFontManager(props.fonts, (warning) => {
|
|
11159
11358
|
if (isCurrent()) reportWarning(warning);
|
|
11160
11359
|
});
|
|
11360
|
+
const fontStartedAt = performanceNow();
|
|
11161
11361
|
await fontManager.prepare(parsed.document);
|
|
11362
|
+
getCurrentProps().onPerformanceMeasurement?.(
|
|
11363
|
+
performanceMeasurement("embedded-font-preparation", fontStartedAt)
|
|
11364
|
+
);
|
|
11162
11365
|
if (!isCurrent()) {
|
|
11163
11366
|
fontManager.destroy();
|
|
11164
11367
|
throw new Error("Viewer adapter creation was superseded.");
|
|
@@ -11191,6 +11394,7 @@ async function createAdapter(target, parsed, props, getCurrentProps, onCurrentSl
|
|
|
11191
11394
|
const normalized = new NormalizedPresentationViewer(target, parsed.document, callbacks);
|
|
11192
11395
|
return {
|
|
11193
11396
|
async render(mode, slideIndex) {
|
|
11397
|
+
const startedAt = performanceNow();
|
|
11194
11398
|
if (mode === "continuous") {
|
|
11195
11399
|
const virtualization = typeof props.virtualization === "object" ? props.virtualization : {};
|
|
11196
11400
|
await normalized.renderList({
|
|
@@ -11204,6 +11408,9 @@ async function createAdapter(target, parsed, props, getCurrentProps, onCurrentSl
|
|
|
11204
11408
|
} else {
|
|
11205
11409
|
await normalized.renderSlide(slideIndex);
|
|
11206
11410
|
}
|
|
11411
|
+
getCurrentProps().onPerformanceMeasurement?.(
|
|
11412
|
+
performanceMeasurement("slide-dom-svg-rendering", startedAt, slideIndex)
|
|
11413
|
+
);
|
|
11207
11414
|
},
|
|
11208
11415
|
goToSlide: (index, options) => normalized.goToSlide(index, options),
|
|
11209
11416
|
setZoom: (percent) => normalized.setZoom(percent),
|
|
@@ -11436,7 +11643,8 @@ var ReactPptxViewer = forwardRef(
|
|
|
11436
11643
|
signal: abort.signal,
|
|
11437
11644
|
...parseFormatHint ? { formatHint: parseFormatHint } : {},
|
|
11438
11645
|
...parseMaxInputBytes !== void 0 ? { maxInputBytes: parseMaxInputBytes } : {},
|
|
11439
|
-
...parseFetchInit ? { fetchInit: parseFetchInit } : {}
|
|
11646
|
+
...parseFetchInit ? { fetchInit: parseFetchInit } : {},
|
|
11647
|
+
onPerformanceMeasurement: (measurement) => latestPropsRef.current.onPerformanceMeasurement?.(measurement)
|
|
11440
11648
|
}).then((next) => {
|
|
11441
11649
|
if (abort.signal.aborted) return;
|
|
11442
11650
|
setParsed(next);
|
|
@@ -11820,9 +12028,12 @@ function usePptxViewer() {
|
|
|
11820
12028
|
}
|
|
11821
12029
|
var EMU_PER_CSS_PIXEL2 = 9525;
|
|
11822
12030
|
var DEFAULT_MAX_DIMENSION2 = 160;
|
|
11823
|
-
function normalizeSlideIndexes(indexes, slideCount) {
|
|
12031
|
+
function normalizeSlideIndexes(indexes, slideCount, sort = true) {
|
|
11824
12032
|
if (!indexes?.length || slideCount <= 0) return [];
|
|
11825
|
-
|
|
12033
|
+
const normalized = [...new Set(indexes)].filter(
|
|
12034
|
+
(index) => Number.isInteger(index) && index >= 0 && index < slideCount
|
|
12035
|
+
);
|
|
12036
|
+
return sort ? normalized.sort((left, right) => left - right) : normalized;
|
|
11826
12037
|
}
|
|
11827
12038
|
function finitePositive2(value) {
|
|
11828
12039
|
return value !== void 0 && Number.isFinite(value) && value > 0 ? value : void 0;
|
|
@@ -11860,6 +12071,7 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
11860
12071
|
const attachedElementsRef = useRef(/* @__PURE__ */ new Map());
|
|
11861
12072
|
const cleanupsRef = useRef(/* @__PURE__ */ new Map());
|
|
11862
12073
|
const prefetchedRef = useRef(/* @__PURE__ */ new Map());
|
|
12074
|
+
const prefetchInFlightRef = useRef(/* @__PURE__ */ new Map());
|
|
11863
12075
|
const renderGenerationRef = useRef(/* @__PURE__ */ new Map());
|
|
11864
12076
|
const refCallbacksRef = useRef(/* @__PURE__ */ new Map());
|
|
11865
12077
|
const attachRef = useRef(() => {
|
|
@@ -11872,7 +12084,7 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
11872
12084
|
[options.renderWindow?.visibleSlideIndexes, slideCount]
|
|
11873
12085
|
);
|
|
11874
12086
|
const prefetchSlideIndexes = useMemo(
|
|
11875
|
-
() => normalizeSlideIndexes(options.renderWindow?.prefetchSlideIndexes, slideCount),
|
|
12087
|
+
() => normalizeSlideIndexes(options.renderWindow?.prefetchSlideIndexes, slideCount, false),
|
|
11876
12088
|
[options.renderWindow?.prefetchSlideIndexes, slideCount]
|
|
11877
12089
|
);
|
|
11878
12090
|
const visibleSlideIndexesKey = visibleSlideIndexes.join(",");
|
|
@@ -11987,28 +12199,46 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
11987
12199
|
}, [renderThumbnail]);
|
|
11988
12200
|
const prefetchThumbnail = useCallback(
|
|
11989
12201
|
async (slideIndex) => {
|
|
11990
|
-
|
|
11991
|
-
|
|
11992
|
-
|
|
11993
|
-
|
|
11994
|
-
|
|
11995
|
-
const element = globalThis.document.createElement("div");
|
|
11996
|
-
setThumbnailState(slideIndex, { status: "rendering" });
|
|
11997
|
-
try {
|
|
11998
|
-
const cleanup = await controller.renderThumbnail(slideIndex, element, {
|
|
11999
|
-
width: size.width
|
|
12000
|
-
});
|
|
12001
|
-
if (!mountedRef.current || renderGenerationRef.current.get(slideIndex) !== generation || attachedElementsRef.current.has(slideIndex) || !requestedPrefetchSlideIndexSetRef.current.has(slideIndex)) {
|
|
12002
|
-
cleanup();
|
|
12003
|
-
return;
|
|
12202
|
+
while (true) {
|
|
12203
|
+
const existing = prefetchInFlightRef.current.get(slideIndex);
|
|
12204
|
+
if (existing) {
|
|
12205
|
+
await existing;
|
|
12206
|
+
continue;
|
|
12004
12207
|
}
|
|
12005
|
-
|
|
12006
|
-
setThumbnailState(slideIndex, { status: "ready" });
|
|
12007
|
-
} catch (reason) {
|
|
12008
|
-
if (!mountedRef.current || renderGenerationRef.current.get(slideIndex) !== generation) {
|
|
12208
|
+
if (disabled || !controller?.isReady() || attachedElementsRef.current.has(slideIndex) || prefetchedRef.current.has(slideIndex) || !requestedPrefetchSlideIndexSetRef.current.has(slideIndex)) {
|
|
12009
12209
|
return;
|
|
12010
12210
|
}
|
|
12011
|
-
|
|
12211
|
+
const generation = (renderGenerationRef.current.get(slideIndex) ?? 0) + 1;
|
|
12212
|
+
renderGenerationRef.current.set(slideIndex, generation);
|
|
12213
|
+
const element = globalThis.document.createElement("div");
|
|
12214
|
+
setThumbnailState(slideIndex, { status: "rendering" });
|
|
12215
|
+
const pending = (async () => {
|
|
12216
|
+
try {
|
|
12217
|
+
const cleanup = await controller.renderThumbnail(slideIndex, element, {
|
|
12218
|
+
width: size.width
|
|
12219
|
+
});
|
|
12220
|
+
if (!mountedRef.current || renderGenerationRef.current.get(slideIndex) !== generation || attachedElementsRef.current.has(slideIndex) || !requestedPrefetchSlideIndexSetRef.current.has(slideIndex)) {
|
|
12221
|
+
cleanup();
|
|
12222
|
+
return;
|
|
12223
|
+
}
|
|
12224
|
+
prefetchedRef.current.set(slideIndex, { cleanup, element, width: size.width });
|
|
12225
|
+
setThumbnailState(slideIndex, { status: "ready" });
|
|
12226
|
+
} catch (reason) {
|
|
12227
|
+
if (!mountedRef.current || renderGenerationRef.current.get(slideIndex) !== generation) {
|
|
12228
|
+
return;
|
|
12229
|
+
}
|
|
12230
|
+
setThumbnailState(slideIndex, { error: asError(reason), status: "error" });
|
|
12231
|
+
}
|
|
12232
|
+
})();
|
|
12233
|
+
prefetchInFlightRef.current.set(slideIndex, pending);
|
|
12234
|
+
try {
|
|
12235
|
+
await pending;
|
|
12236
|
+
} finally {
|
|
12237
|
+
if (prefetchInFlightRef.current.get(slideIndex) === pending) {
|
|
12238
|
+
prefetchInFlightRef.current.delete(slideIndex);
|
|
12239
|
+
}
|
|
12240
|
+
}
|
|
12241
|
+
return;
|
|
12012
12242
|
}
|
|
12013
12243
|
},
|
|
12014
12244
|
[controller, disabled, setThumbnailState, size.width]
|
|
@@ -12024,14 +12254,17 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
12024
12254
|
cleanupsRef.current.clear();
|
|
12025
12255
|
for (const prefetched of prefetchedRef.current.values()) prefetched.cleanup();
|
|
12026
12256
|
prefetchedRef.current.clear();
|
|
12257
|
+
prefetchInFlightRef.current.clear();
|
|
12027
12258
|
};
|
|
12028
12259
|
}, []);
|
|
12029
12260
|
useEffect(
|
|
12030
12261
|
() => () => {
|
|
12262
|
+
for (const index of prefetchInFlightRef.current.keys()) invalidateThumbnail(index);
|
|
12263
|
+
prefetchInFlightRef.current.clear();
|
|
12031
12264
|
for (const prefetched of prefetchedRef.current.values()) prefetched.cleanup();
|
|
12032
12265
|
prefetchedRef.current.clear();
|
|
12033
12266
|
},
|
|
12034
|
-
[controller, size.width]
|
|
12267
|
+
[controller, invalidateThumbnail, size.width]
|
|
12035
12268
|
);
|
|
12036
12269
|
useEffect(() => {
|
|
12037
12270
|
void rerenderAttachedThumbnails();
|
|
@@ -12043,6 +12276,13 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
12043
12276
|
if (!attachedElementsRef.current.has(index)) setThumbnailState(index, { status: "idle" });
|
|
12044
12277
|
}
|
|
12045
12278
|
}
|
|
12279
|
+
for (const index of prefetchInFlightRef.current.keys()) {
|
|
12280
|
+
if (disabled || attachedElementsRef.current.has(index) || !requestedPrefetchSlideIndexSetRef.current.has(index)) {
|
|
12281
|
+
invalidateThumbnail(index);
|
|
12282
|
+
prefetchInFlightRef.current.delete(index);
|
|
12283
|
+
if (!attachedElementsRef.current.has(index)) setThumbnailState(index, { status: "idle" });
|
|
12284
|
+
}
|
|
12285
|
+
}
|
|
12046
12286
|
if (disabled) return;
|
|
12047
12287
|
let cancelled = false;
|
|
12048
12288
|
void (async () => {
|
|
@@ -12057,6 +12297,7 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
12057
12297
|
}, [
|
|
12058
12298
|
disabled,
|
|
12059
12299
|
disposePrefetchedThumbnail,
|
|
12300
|
+
invalidateThumbnail,
|
|
12060
12301
|
prefetchSlideIndexesKey,
|
|
12061
12302
|
prefetchThumbnail,
|
|
12062
12303
|
setThumbnailState
|
|
@@ -12096,6 +12337,404 @@ function usePptxViewerThumbnails(controller, options = {}) {
|
|
|
12096
12337
|
);
|
|
12097
12338
|
}
|
|
12098
12339
|
|
|
12099
|
-
|
|
12340
|
+
// src/thumbnail-renderer.ts
|
|
12341
|
+
var EMU_PER_CSS_PIXEL3 = 9525;
|
|
12342
|
+
var DEFAULT_MAX_DIMENSION3 = 160;
|
|
12343
|
+
var RenderQueue = class {
|
|
12344
|
+
constructor(limit) {
|
|
12345
|
+
this.limit = limit;
|
|
12346
|
+
}
|
|
12347
|
+
limit;
|
|
12348
|
+
active = 0;
|
|
12349
|
+
destroyed = false;
|
|
12350
|
+
waiters = [];
|
|
12351
|
+
acquire(signal) {
|
|
12352
|
+
throwIfAborted(signal);
|
|
12353
|
+
if (this.destroyed) return Promise.reject(abortedError());
|
|
12354
|
+
return new Promise((resolve, reject) => {
|
|
12355
|
+
const waiter = { resolve, reject, ...signal ? { signal } : {} };
|
|
12356
|
+
if (signal) {
|
|
12357
|
+
waiter.abort = () => {
|
|
12358
|
+
const index = this.waiters.indexOf(waiter);
|
|
12359
|
+
if (index >= 0) this.waiters.splice(index, 1);
|
|
12360
|
+
reject(abortedError(signal.reason));
|
|
12361
|
+
};
|
|
12362
|
+
signal.addEventListener("abort", waiter.abort, { once: true });
|
|
12363
|
+
}
|
|
12364
|
+
this.waiters.push(waiter);
|
|
12365
|
+
this.drain();
|
|
12366
|
+
});
|
|
12367
|
+
}
|
|
12368
|
+
destroy() {
|
|
12369
|
+
this.destroyed = true;
|
|
12370
|
+
for (const waiter of this.waiters.splice(0)) {
|
|
12371
|
+
if (waiter.abort && waiter.signal) {
|
|
12372
|
+
waiter.signal.removeEventListener("abort", waiter.abort);
|
|
12373
|
+
}
|
|
12374
|
+
waiter.reject(abortedError());
|
|
12375
|
+
}
|
|
12376
|
+
}
|
|
12377
|
+
drain() {
|
|
12378
|
+
while (!this.destroyed && this.active < this.limit && this.waiters.length) {
|
|
12379
|
+
const waiter = this.waiters.shift();
|
|
12380
|
+
if (waiter.abort && waiter.signal) {
|
|
12381
|
+
waiter.signal.removeEventListener("abort", waiter.abort);
|
|
12382
|
+
}
|
|
12383
|
+
if (waiter.signal?.aborted) {
|
|
12384
|
+
waiter.reject(abortedError(waiter.signal.reason));
|
|
12385
|
+
continue;
|
|
12386
|
+
}
|
|
12387
|
+
this.active += 1;
|
|
12388
|
+
let released = false;
|
|
12389
|
+
waiter.resolve(() => {
|
|
12390
|
+
if (released) return;
|
|
12391
|
+
released = true;
|
|
12392
|
+
this.active -= 1;
|
|
12393
|
+
this.drain();
|
|
12394
|
+
});
|
|
12395
|
+
}
|
|
12396
|
+
}
|
|
12397
|
+
};
|
|
12398
|
+
function abortedError(reason) {
|
|
12399
|
+
return new PptxViewerError("aborted", "Thumbnail rendering was cancelled.", { cause: reason });
|
|
12400
|
+
}
|
|
12401
|
+
function finitePositive3(value, fallback) {
|
|
12402
|
+
return value !== void 0 && Number.isFinite(value) && value > 0 ? value : fallback;
|
|
12403
|
+
}
|
|
12404
|
+
function outputSize(presentation, options) {
|
|
12405
|
+
const naturalWidth = Math.max(1, presentation.document.size.widthEmu / EMU_PER_CSS_PIXEL3);
|
|
12406
|
+
const naturalHeight = Math.max(1, presentation.document.size.heightEmu / EMU_PER_CSS_PIXEL3);
|
|
12407
|
+
const hasWidth = options.maxWidth !== void 0 && Number.isFinite(options.maxWidth) && options.maxWidth > 0;
|
|
12408
|
+
const hasHeight = options.maxHeight !== void 0 && Number.isFinite(options.maxHeight) && options.maxHeight > 0;
|
|
12409
|
+
const maxWidth = hasWidth ? options.maxWidth : hasHeight ? Number.POSITIVE_INFINITY : DEFAULT_MAX_DIMENSION3;
|
|
12410
|
+
const maxHeight = hasHeight ? options.maxHeight : hasWidth ? Number.POSITIVE_INFINITY : DEFAULT_MAX_DIMENSION3;
|
|
12411
|
+
const scale = Math.min(maxWidth / naturalWidth, maxHeight / naturalHeight);
|
|
12412
|
+
return {
|
|
12413
|
+
height: Math.max(1, Math.round(naturalHeight * scale)),
|
|
12414
|
+
naturalHeight,
|
|
12415
|
+
naturalWidth,
|
|
12416
|
+
width: Math.max(1, Math.round(naturalWidth * scale))
|
|
12417
|
+
};
|
|
12418
|
+
}
|
|
12419
|
+
function blobToDataUrl(blob, signal) {
|
|
12420
|
+
return abortable(
|
|
12421
|
+
new Promise((resolve, reject) => {
|
|
12422
|
+
const reader = new FileReader();
|
|
12423
|
+
reader.onload = () => resolve(String(reader.result));
|
|
12424
|
+
reader.onerror = () => reject(reader.error ?? new Error("Could not read a slide asset."));
|
|
12425
|
+
reader.readAsDataURL(blob);
|
|
12426
|
+
}),
|
|
12427
|
+
signal
|
|
12428
|
+
);
|
|
12429
|
+
}
|
|
12430
|
+
async function inlineResourceUrl(url, signal) {
|
|
12431
|
+
if (!/^(?:blob:|https?:)/i.test(url)) return url;
|
|
12432
|
+
try {
|
|
12433
|
+
const response = await fetch(url, signal ? { signal } : void 0);
|
|
12434
|
+
if (!response.ok) return url;
|
|
12435
|
+
return await blobToDataUrl(await response.blob(), signal);
|
|
12436
|
+
} catch {
|
|
12437
|
+
throwIfAborted(signal);
|
|
12438
|
+
return url;
|
|
12439
|
+
}
|
|
12440
|
+
}
|
|
12441
|
+
async function inlineResources(root, signal) {
|
|
12442
|
+
const cache = /* @__PURE__ */ new Map();
|
|
12443
|
+
const inline = (url) => {
|
|
12444
|
+
let pending = cache.get(url);
|
|
12445
|
+
if (!pending) {
|
|
12446
|
+
pending = inlineResourceUrl(url, signal);
|
|
12447
|
+
cache.set(url, pending);
|
|
12448
|
+
}
|
|
12449
|
+
return pending;
|
|
12450
|
+
};
|
|
12451
|
+
const elements = [root, ...root.querySelectorAll("*")];
|
|
12452
|
+
await Promise.all(
|
|
12453
|
+
elements.flatMap((element) => {
|
|
12454
|
+
const attributeNames = ["src", "poster", ...element.localName === "image" ? ["href"] : []];
|
|
12455
|
+
const attributes = attributeNames.map((name) => ({ name, value: element.getAttribute(name) })).filter((entry) => Boolean(entry.value));
|
|
12456
|
+
const attributeTasks = attributes.map(async ({ name, value }) => {
|
|
12457
|
+
element.setAttribute(name, await inline(value));
|
|
12458
|
+
});
|
|
12459
|
+
const styleTasks = Array.from(
|
|
12460
|
+
{ length: element.style.length },
|
|
12461
|
+
(_, index) => element.style.item(index)
|
|
12462
|
+
).map((property) => ({ property, value: element.style.getPropertyValue(property) })).filter(({ value }) => value.includes("url(")).map(async ({ property, value }) => {
|
|
12463
|
+
const urls = [...value.matchAll(/url\(["']?([^"')]+)["']?\)/g)].map((match) => match[1]);
|
|
12464
|
+
let next = value;
|
|
12465
|
+
for (const url of urls) next = next.replace(url, await inline(url));
|
|
12466
|
+
element.style.setProperty(property, next);
|
|
12467
|
+
});
|
|
12468
|
+
return [...attributeTasks, ...styleTasks];
|
|
12469
|
+
})
|
|
12470
|
+
);
|
|
12471
|
+
}
|
|
12472
|
+
async function serializeSlide(slide, naturalWidth, naturalHeight, width, height, signal) {
|
|
12473
|
+
const clone = slide.cloneNode(true);
|
|
12474
|
+
clone.style.transform = "none";
|
|
12475
|
+
clone.style.transformOrigin = "top left";
|
|
12476
|
+
clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
|
|
12477
|
+
const sourceCanvases = slide.querySelectorAll("canvas");
|
|
12478
|
+
const clonedCanvases = clone.querySelectorAll("canvas");
|
|
12479
|
+
sourceCanvases.forEach((canvas, index) => {
|
|
12480
|
+
const cloned = clonedCanvases[index];
|
|
12481
|
+
if (!cloned) return;
|
|
12482
|
+
try {
|
|
12483
|
+
const image = document.createElement("img");
|
|
12484
|
+
image.src = canvas.toDataURL("image/png");
|
|
12485
|
+
image.setAttribute("style", cloned.getAttribute("style") ?? "");
|
|
12486
|
+
cloned.replaceWith(image);
|
|
12487
|
+
} catch {
|
|
12488
|
+
cloned.remove();
|
|
12489
|
+
}
|
|
12490
|
+
});
|
|
12491
|
+
await inlineResources(clone, signal);
|
|
12492
|
+
const content = new XMLSerializer().serializeToString(clone);
|
|
12493
|
+
return `<svg xmlns="http://www.w3.org/2000/svg" width="${width}" height="${height}" viewBox="0 0 ${naturalWidth} ${naturalHeight}"><foreignObject width="${naturalWidth}" height="${naturalHeight}">${content}</foreignObject></svg>`;
|
|
12494
|
+
}
|
|
12495
|
+
async function abortable(promise, signal) {
|
|
12496
|
+
throwIfAborted(signal);
|
|
12497
|
+
if (!signal) return promise;
|
|
12498
|
+
return new Promise((resolve, reject) => {
|
|
12499
|
+
const abort = () => reject(abortedError(signal.reason));
|
|
12500
|
+
signal.addEventListener("abort", abort, { once: true });
|
|
12501
|
+
void promise.then(
|
|
12502
|
+
(value) => {
|
|
12503
|
+
signal.removeEventListener("abort", abort);
|
|
12504
|
+
resolve(value);
|
|
12505
|
+
},
|
|
12506
|
+
(error) => {
|
|
12507
|
+
signal.removeEventListener("abort", abort);
|
|
12508
|
+
reject(error);
|
|
12509
|
+
}
|
|
12510
|
+
);
|
|
12511
|
+
});
|
|
12512
|
+
}
|
|
12513
|
+
async function decodeElementImages(root, signal) {
|
|
12514
|
+
const images = [...root.querySelectorAll("img")];
|
|
12515
|
+
const svgImages = [...root.querySelectorAll("image")].map((image) => image.href.baseVal || image.getAttribute("href") || "").filter(Boolean);
|
|
12516
|
+
await abortable(
|
|
12517
|
+
Promise.all([
|
|
12518
|
+
...images.map(async (image) => {
|
|
12519
|
+
if (typeof image.decode === "function") await image.decode().catch(() => void 0);
|
|
12520
|
+
}),
|
|
12521
|
+
...svgImages.map(
|
|
12522
|
+
(source) => new Promise((resolve) => {
|
|
12523
|
+
const image = new Image();
|
|
12524
|
+
image.onload = () => resolve();
|
|
12525
|
+
image.onerror = () => resolve();
|
|
12526
|
+
image.src = source;
|
|
12527
|
+
})
|
|
12528
|
+
)
|
|
12529
|
+
]).then(() => void 0),
|
|
12530
|
+
signal
|
|
12531
|
+
);
|
|
12532
|
+
}
|
|
12533
|
+
async function decodeSvg(svg, signal) {
|
|
12534
|
+
return abortable(
|
|
12535
|
+
new Promise((resolve, reject) => {
|
|
12536
|
+
const image = new Image();
|
|
12537
|
+
image.onload = () => resolve(image);
|
|
12538
|
+
image.onerror = () => reject(new Error("The rendered slide SVG could not be decoded."));
|
|
12539
|
+
image.src = `data:image/svg+xml;charset=utf-8,${encodeURIComponent(svg)}`;
|
|
12540
|
+
}),
|
|
12541
|
+
signal
|
|
12542
|
+
);
|
|
12543
|
+
}
|
|
12544
|
+
function canvasToBlob(canvas, quality) {
|
|
12545
|
+
return new Promise((resolve, reject) => {
|
|
12546
|
+
canvas.toBlob(
|
|
12547
|
+
(blob) => {
|
|
12548
|
+
if (blob) resolve(blob);
|
|
12549
|
+
else reject(new Error("The browser could not encode the thumbnail."));
|
|
12550
|
+
},
|
|
12551
|
+
"image/png",
|
|
12552
|
+
quality
|
|
12553
|
+
);
|
|
12554
|
+
});
|
|
12555
|
+
}
|
|
12556
|
+
var ThumbnailRenderer = class {
|
|
12557
|
+
constructor(presentation, options) {
|
|
12558
|
+
this.presentation = presentation;
|
|
12559
|
+
this.options = options;
|
|
12560
|
+
if (typeof document === "undefined") {
|
|
12561
|
+
throw new PptxViewerError(
|
|
12562
|
+
"unsupported-environment",
|
|
12563
|
+
"Thumbnail rendering requires a browser DOM."
|
|
12564
|
+
);
|
|
12565
|
+
}
|
|
12566
|
+
const concurrency = Math.max(1, Math.floor(finitePositive3(options.concurrency, 2)));
|
|
12567
|
+
this.queue = new RenderQueue(concurrency);
|
|
12568
|
+
this.root = document.createElement("div");
|
|
12569
|
+
this.root.setAttribute("aria-hidden", "true");
|
|
12570
|
+
this.root.style.position = "fixed";
|
|
12571
|
+
this.root.style.left = "-100000px";
|
|
12572
|
+
this.root.style.top = "0";
|
|
12573
|
+
this.root.style.pointerEvents = "none";
|
|
12574
|
+
this.root.style.opacity = "0";
|
|
12575
|
+
document.body.append(this.root);
|
|
12576
|
+
this.fontManager = new PptxFontManager(
|
|
12577
|
+
{
|
|
12578
|
+
loadEmbeddedFonts: false,
|
|
12579
|
+
reportMissingFonts: false,
|
|
12580
|
+
waitForFonts: false,
|
|
12581
|
+
...options.fonts
|
|
12582
|
+
},
|
|
12583
|
+
(warning) => options.onWarning?.(warning)
|
|
12584
|
+
);
|
|
12585
|
+
this.viewer = new NormalizedPresentationViewer(this.root, presentation.document, {
|
|
12586
|
+
onNodeError: (nodeId, error) => options.onWarning?.({
|
|
12587
|
+
code: "degraded-rendering",
|
|
12588
|
+
severity: "warning",
|
|
12589
|
+
nodeId,
|
|
12590
|
+
feature: "thumbnail-renderer",
|
|
12591
|
+
message: `A slide element could not be rendered: ${error instanceof Error ? error.message : String(error)}`
|
|
12592
|
+
})
|
|
12593
|
+
});
|
|
12594
|
+
const startedAt = performanceNow();
|
|
12595
|
+
this.ready = this.fontManager.prepare(presentation.document).then(() => {
|
|
12596
|
+
this.report(performanceMeasurement("embedded-font-preparation", startedAt));
|
|
12597
|
+
});
|
|
12598
|
+
}
|
|
12599
|
+
presentation;
|
|
12600
|
+
options;
|
|
12601
|
+
ready;
|
|
12602
|
+
fontManager;
|
|
12603
|
+
queue;
|
|
12604
|
+
root;
|
|
12605
|
+
viewer;
|
|
12606
|
+
destroyed = false;
|
|
12607
|
+
async renderSlide(slideIndex, options = {}) {
|
|
12608
|
+
const release = await this.queue.acquire(options.signal);
|
|
12609
|
+
try {
|
|
12610
|
+
this.assertAvailable(options.signal);
|
|
12611
|
+
await abortable(this.ready, options.signal);
|
|
12612
|
+
this.assertAvailable(options.signal);
|
|
12613
|
+
if (!Number.isInteger(slideIndex) || slideIndex < 0 || slideIndex >= this.presentation.document.slides.length) {
|
|
12614
|
+
throw new RangeError(`Slide ${slideIndex} does not exist.`);
|
|
12615
|
+
}
|
|
12616
|
+
const measurements = [];
|
|
12617
|
+
const size = outputSize(this.presentation, options);
|
|
12618
|
+
const target = document.createElement("div");
|
|
12619
|
+
this.root.append(target);
|
|
12620
|
+
const domStartedAt = performanceNow();
|
|
12621
|
+
const handle = this.viewer.renderThumbnailToContainer(slideIndex, target, {
|
|
12622
|
+
width: size.naturalWidth
|
|
12623
|
+
});
|
|
12624
|
+
try {
|
|
12625
|
+
await abortable(handle.ready, options.signal);
|
|
12626
|
+
this.fontManager.applyTo(handle.element, slideIndex);
|
|
12627
|
+
const domDurationMs = performanceNow() - domStartedAt;
|
|
12628
|
+
const decodeStartedAt = performanceNow();
|
|
12629
|
+
await decodeElementImages(handle.element, options.signal);
|
|
12630
|
+
let decodeDurationMs = performanceNow() - decodeStartedAt;
|
|
12631
|
+
const serializationStartedAt = performanceNow();
|
|
12632
|
+
const svg = await serializeSlide(
|
|
12633
|
+
handle.element,
|
|
12634
|
+
size.naturalWidth,
|
|
12635
|
+
size.naturalHeight,
|
|
12636
|
+
size.width,
|
|
12637
|
+
size.height,
|
|
12638
|
+
options.signal
|
|
12639
|
+
);
|
|
12640
|
+
this.record(
|
|
12641
|
+
{
|
|
12642
|
+
durationMs: Math.max(0, domDurationMs + performanceNow() - serializationStartedAt),
|
|
12643
|
+
phase: "slide-dom-svg-rendering",
|
|
12644
|
+
slideIndex
|
|
12645
|
+
},
|
|
12646
|
+
measurements
|
|
12647
|
+
);
|
|
12648
|
+
const output = options.output ?? "blob";
|
|
12649
|
+
if (output === "svg") {
|
|
12650
|
+
this.record(
|
|
12651
|
+
{ durationMs: Math.max(0, decodeDurationMs), phase: "image-decoding", slideIndex },
|
|
12652
|
+
measurements
|
|
12653
|
+
);
|
|
12654
|
+
return this.result(svg, output, slideIndex, size, measurements);
|
|
12655
|
+
}
|
|
12656
|
+
const svgDecodeStartedAt = performanceNow();
|
|
12657
|
+
const image = await decodeSvg(svg, options.signal);
|
|
12658
|
+
decodeDurationMs += performanceNow() - svgDecodeStartedAt;
|
|
12659
|
+
this.record(
|
|
12660
|
+
{ durationMs: Math.max(0, decodeDurationMs), phase: "image-decoding", slideIndex },
|
|
12661
|
+
measurements
|
|
12662
|
+
);
|
|
12663
|
+
this.assertAvailable(options.signal);
|
|
12664
|
+
const encodeStartedAt = performanceNow();
|
|
12665
|
+
const pixelRatio = finitePositive3(options.pixelRatio, 1);
|
|
12666
|
+
const canvas = document.createElement("canvas");
|
|
12667
|
+
canvas.width = Math.max(1, Math.round(size.width * pixelRatio));
|
|
12668
|
+
canvas.height = Math.max(1, Math.round(size.height * pixelRatio));
|
|
12669
|
+
canvas.style.width = `${size.width}px`;
|
|
12670
|
+
canvas.style.height = `${size.height}px`;
|
|
12671
|
+
const context = canvas.getContext("2d");
|
|
12672
|
+
if (!context) throw new Error("The browser does not provide a 2D canvas renderer.");
|
|
12673
|
+
context.drawImage(image, 0, 0, canvas.width, canvas.height);
|
|
12674
|
+
let data;
|
|
12675
|
+
if (output === "canvas") data = canvas;
|
|
12676
|
+
else if (output === "imageBitmap") {
|
|
12677
|
+
if (typeof createImageBitmap !== "function") {
|
|
12678
|
+
throw new PptxViewerError(
|
|
12679
|
+
"unsupported-environment",
|
|
12680
|
+
"ImageBitmap output is not supported by this browser."
|
|
12681
|
+
);
|
|
12682
|
+
}
|
|
12683
|
+
data = await abortable(createImageBitmap(canvas), options.signal);
|
|
12684
|
+
} else data = await abortable(canvasToBlob(canvas, options.quality), options.signal);
|
|
12685
|
+
this.measure("raster-encoding", encodeStartedAt, slideIndex, measurements);
|
|
12686
|
+
return this.result(data, output, slideIndex, size, measurements);
|
|
12687
|
+
} finally {
|
|
12688
|
+
handle.dispose();
|
|
12689
|
+
target.remove();
|
|
12690
|
+
}
|
|
12691
|
+
} finally {
|
|
12692
|
+
release();
|
|
12693
|
+
}
|
|
12694
|
+
}
|
|
12695
|
+
renderSlides(slideIndexes, options = {}) {
|
|
12696
|
+
return Promise.all(slideIndexes.map((slideIndex) => this.renderDynamic(slideIndex, options)));
|
|
12697
|
+
}
|
|
12698
|
+
destroy() {
|
|
12699
|
+
if (this.destroyed) return;
|
|
12700
|
+
this.destroyed = true;
|
|
12701
|
+
this.queue.destroy();
|
|
12702
|
+
this.viewer.destroy();
|
|
12703
|
+
this.fontManager.destroy();
|
|
12704
|
+
this.root.remove();
|
|
12705
|
+
}
|
|
12706
|
+
renderDynamic(slideIndex, options) {
|
|
12707
|
+
return this.renderSlide(slideIndex, options);
|
|
12708
|
+
}
|
|
12709
|
+
assertAvailable(signal) {
|
|
12710
|
+
throwIfAborted(signal);
|
|
12711
|
+
if (this.destroyed) throw abortedError();
|
|
12712
|
+
}
|
|
12713
|
+
measure(phase, startedAt, slideIndex, measurements) {
|
|
12714
|
+
this.record(performanceMeasurement(phase, startedAt, slideIndex), measurements);
|
|
12715
|
+
}
|
|
12716
|
+
record(measurement, measurements) {
|
|
12717
|
+
measurements.push(measurement);
|
|
12718
|
+
this.report(measurement);
|
|
12719
|
+
}
|
|
12720
|
+
report(measurement) {
|
|
12721
|
+
this.options.onPerformanceMeasurement?.(measurement);
|
|
12722
|
+
}
|
|
12723
|
+
result(data, output, slideIndex, size, measurements) {
|
|
12724
|
+
return {
|
|
12725
|
+
data,
|
|
12726
|
+
height: size.height,
|
|
12727
|
+
measurements,
|
|
12728
|
+
output,
|
|
12729
|
+
slideIndex,
|
|
12730
|
+
width: size.width
|
|
12731
|
+
};
|
|
12732
|
+
}
|
|
12733
|
+
};
|
|
12734
|
+
function createPptxThumbnailRenderer(presentation, options = {}) {
|
|
12735
|
+
return new ThumbnailRenderer(presentation, options);
|
|
12736
|
+
}
|
|
12737
|
+
|
|
12738
|
+
export { OFFICE_FONT_FALLBACKS, PptxViewerError, ReactPptxViewer, createPptxThumbnailRenderer, initWasm, parsePresentation, presentationParsingDefaults, resolvePptxFontFamily, setWasmSource, usePptxModel, usePptxPresentation, usePptxViewer, usePptxViewerThumbnails };
|
|
12100
12739
|
//# sourceMappingURL=index.js.map
|
|
12101
12740
|
//# sourceMappingURL=index.js.map
|