@file-viewer/pptx 2.2.9 → 2.3.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/dist/index.d.ts CHANGED
@@ -1,4 +1,6 @@
1
1
  export { PptxViewer } from './viewer';
2
+ export { PptxPresentation } from './presentation';
3
+ export type { PptxPresentationLabels, PptxPresentationState } from './presentation';
2
4
  export { createPptxWorker } from './worker';
3
5
  export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from './options';
4
6
  export type { NativePptxEngineOptions, PptxDiagnosticError, PptxDiagnosticErrorCode, PptxFitMode, PptxListOptions, PptxSlideSize, PptxViewerOptions, PptxWorkerFactoryOptions, PptxWorkerMessage, PptxZipLimits, } from './types';
package/dist/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { PptxViewer } from './viewer.js';
2
+ export { PptxPresentation } from './presentation.js';
2
3
  export { createPptxWorker } from './worker.js';
3
4
  export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from './options.js';
@@ -0,0 +1,66 @@
1
+ import type { PptxViewer } from './viewer';
2
+ export interface PptxPresentationState {
3
+ active: boolean;
4
+ slideNumber: number;
5
+ total: number;
6
+ }
7
+ export interface PptxPresentationLabels {
8
+ exit?: string;
9
+ hint?: string;
10
+ next?: string;
11
+ previous?: string;
12
+ }
13
+ /**
14
+ * Full-screen slideshow for a rendered PPTX deck.
15
+ *
16
+ * The slides stay where the viewer put them: the whole scale box is moved into an overlay and the
17
+ * inactive slots are hidden with CSS, so the engine's scoped `.flyfish-pptx-content .slide` rules
18
+ * keep applying and no node is cloned. A placeholder marks the original position so exiting puts
19
+ * everything back exactly where it was.
20
+ */
21
+ export declare class PptxPresentation {
22
+ private readonly viewer;
23
+ private readonly labels;
24
+ private readonly fullscreen;
25
+ private overlay;
26
+ private stage;
27
+ private counter;
28
+ private placeholder;
29
+ private listeners;
30
+ private layoutFrame;
31
+ private ownsFullscreen;
32
+ private current;
33
+ constructor(viewer: PptxViewer, labels?: PptxPresentationLabels, fullscreen?: boolean);
34
+ get active(): boolean;
35
+ get slideNumber(): number;
36
+ get state(): PptxPresentationState;
37
+ enter(slideNumber?: number): Promise<void>;
38
+ exit(): void;
39
+ toggle(slideNumber?: number): Promise<void>;
40
+ goTo(slideNumber: number): void;
41
+ next(): void;
42
+ previous(): void;
43
+ /** Scale the active slide to fit the overlay, letterboxing whichever axis has slack. */
44
+ layout(): void;
45
+ destroy(): void;
46
+ private slots;
47
+ /**
48
+ * The nodes the slideshow toggles between. Windowed decks wrap each slide in a
49
+ * slot; the default (non-windowed) deck appends slides directly to the content
50
+ * node, so those are the containers there.
51
+ */
52
+ private slideContainers;
53
+ /**
54
+ * Chromium reports the fullscreen element of a shadow root on the shadow root
55
+ * itself while document.fullscreenElement stays on the host, so both have to
56
+ * be checked before deciding who owns fullscreen.
57
+ */
58
+ private isFullscreenElement;
59
+ private scheduleLayout;
60
+ private notify;
61
+ private on;
62
+ private attach;
63
+ private detach;
64
+ private handleClick;
65
+ private handleKey;
66
+ }
@@ -0,0 +1,360 @@
1
+ const clamp = (value, min, max) => Math.min(Math.max(value, min), max);
2
+ /**
3
+ * Full-screen slideshow for a rendered PPTX deck.
4
+ *
5
+ * The slides stay where the viewer put them: the whole scale box is moved into an overlay and the
6
+ * inactive slots are hidden with CSS, so the engine's scoped `.flyfish-pptx-content .slide` rules
7
+ * keep applying and no node is cloned. A placeholder marks the original position so exiting puts
8
+ * everything back exactly where it was.
9
+ */
10
+ export class PptxPresentation {
11
+ constructor(viewer, labels = {}, fullscreen = true) {
12
+ this.overlay = null;
13
+ this.stage = null;
14
+ this.counter = null;
15
+ this.placeholder = null;
16
+ this.listeners = [];
17
+ this.layoutFrame = 0;
18
+ this.ownsFullscreen = false;
19
+ this.current = 1;
20
+ this.viewer = viewer;
21
+ this.labels = labels;
22
+ this.fullscreen = fullscreen;
23
+ }
24
+ get active() {
25
+ return Boolean(this.overlay);
26
+ }
27
+ get slideNumber() {
28
+ return this.current;
29
+ }
30
+ get state() {
31
+ return { active: this.active, slideNumber: this.current, total: this.viewer.slideCount };
32
+ }
33
+ async enter(slideNumber = this.current) {
34
+ var _a, _b;
35
+ if (this.active || this.viewer.slideCount === 0) {
36
+ return;
37
+ }
38
+ const documentRef = this.viewer.target.ownerDocument || document;
39
+ const overlay = documentRef.createElement('div');
40
+ overlay.className = 'flyfish-pptx-presentation';
41
+ overlay.tabIndex = -1;
42
+ overlay.setAttribute('role', 'region');
43
+ overlay.setAttribute('aria-label', this.labels.hint || 'Slideshow');
44
+ const stage = documentRef.createElement('div');
45
+ stage.className = 'flyfish-pptx-presentation-stage';
46
+ const counter = documentRef.createElement('div');
47
+ counter.className = 'flyfish-pptx-presentation-counter';
48
+ const hint = documentRef.createElement('div');
49
+ hint.className = 'flyfish-pptx-presentation-hint';
50
+ hint.textContent = this.labels.hint || '';
51
+ hint.hidden = !this.labels.hint;
52
+ const exit = documentRef.createElement('button');
53
+ exit.type = 'button';
54
+ exit.className = 'flyfish-pptx-presentation-exit';
55
+ exit.textContent = '✕';
56
+ exit.setAttribute('aria-label', this.labels.exit || 'Exit slideshow');
57
+ exit.addEventListener('click', event => {
58
+ event.stopPropagation();
59
+ this.exit();
60
+ });
61
+ overlay.append(stage, counter, hint, exit);
62
+ this.overlay = overlay;
63
+ this.stage = stage;
64
+ this.counter = counter;
65
+ // Keep the overlay inside whichever root holds the slide styles, or the engine's scoped CSS
66
+ // would not reach the slides once they move.
67
+ const styleRoot = this.viewer.presentationRoot;
68
+ styleRoot.appendChild(overlay);
69
+ // Park a comment where the scale box lived so exit() can restore the exact position.
70
+ this.placeholder = documentRef.createComment('flyfish-pptx-presentation');
71
+ this.viewer.saveScrollPosition();
72
+ this.viewer.scaleBox.replaceWith(this.placeholder);
73
+ stage.appendChild(this.viewer.scaleBox);
74
+ this.viewer.content.classList.add('is-presenting');
75
+ this.attach(documentRef, overlay);
76
+ this.goTo(slideNumber);
77
+ if (this.fullscreen) {
78
+ try {
79
+ await ((_a = overlay.requestFullscreen) === null || _a === void 0 ? void 0 : _a.call(overlay));
80
+ this.ownsFullscreen = this.isFullscreenElement(overlay);
81
+ }
82
+ catch {
83
+ // Fullscreen needs a user gesture and can be blocked by permissions policy. The overlay is
84
+ // position:fixed, so the slideshow still fills the viewport without it.
85
+ this.ownsFullscreen = false;
86
+ }
87
+ }
88
+ // exit() may have run while fullscreen was being requested. Leave the
89
+ // browser out of fullscreen rather than stranded with no overlay.
90
+ if (this.overlay !== overlay) {
91
+ if (this.ownsFullscreen) {
92
+ void ((_b = documentRef.exitFullscreen) === null || _b === void 0 ? void 0 : _b.call(documentRef).catch(() => undefined));
93
+ }
94
+ this.ownsFullscreen = false;
95
+ return;
96
+ }
97
+ overlay.focus({ preventScroll: true });
98
+ this.scheduleLayout();
99
+ this.notify();
100
+ }
101
+ exit() {
102
+ var _a, _b;
103
+ const overlay = this.overlay;
104
+ if (!overlay) {
105
+ return;
106
+ }
107
+ const documentRef = this.viewer.target.ownerDocument || document;
108
+ // Capture before the overlay leaves the DOM: a detached node's getRootNode()
109
+ // is the document, so the fullscreen check would fail after removal.
110
+ const shouldExitFullscreen = this.ownsFullscreen && this.isFullscreenElement(overlay);
111
+ this.detach();
112
+ if (this.layoutFrame) {
113
+ (documentRef.defaultView || window).cancelAnimationFrame(this.layoutFrame);
114
+ this.layoutFrame = 0;
115
+ }
116
+ this.viewer.content.classList.remove('is-presenting');
117
+ for (const container of this.slideContainers()) {
118
+ container.classList.remove('is-active-slide');
119
+ }
120
+ if ((_a = this.placeholder) === null || _a === void 0 ? void 0 : _a.parentNode) {
121
+ this.placeholder.replaceWith(this.viewer.scaleBox);
122
+ }
123
+ else {
124
+ this.viewer.target.appendChild(this.viewer.scaleBox);
125
+ }
126
+ this.placeholder = null;
127
+ overlay.remove();
128
+ this.overlay = null;
129
+ this.stage = null;
130
+ this.counter = null;
131
+ if (shouldExitFullscreen) {
132
+ void ((_b = documentRef.exitFullscreen) === null || _b === void 0 ? void 0 : _b.call(documentRef).catch(() => undefined));
133
+ }
134
+ this.ownsFullscreen = false;
135
+ this.viewer.restoreScrollPosition();
136
+ this.notify();
137
+ }
138
+ async toggle(slideNumber) {
139
+ if (this.active) {
140
+ this.exit();
141
+ return;
142
+ }
143
+ await this.enter(slideNumber);
144
+ }
145
+ goTo(slideNumber) {
146
+ const total = this.viewer.slideCount;
147
+ if (total === 0) {
148
+ return;
149
+ }
150
+ this.current = clamp(Math.round(slideNumber) || 1, 1, total);
151
+ this.viewer.ensureSlideRendered(this.current);
152
+ // Rendering the neighbour keeps the next step instant without defeating virtualization.
153
+ this.viewer.ensureSlideRendered(this.current + 1);
154
+ const containers = this.slideContainers();
155
+ // Windowed decks tag each slot with its slide number; non-windowed decks
156
+ // append slides in order, so the active one is found by index.
157
+ const byNumber = containers.some(container => Boolean(container.dataset.slideNumber));
158
+ containers.forEach((container, index) => {
159
+ const isActive = byNumber
160
+ ? Number(container.dataset.slideNumber) === this.current
161
+ : index === this.current - 1;
162
+ container.classList.toggle('is-active-slide', isActive);
163
+ });
164
+ if (this.counter) {
165
+ this.counter.textContent = `${this.current} / ${total}`;
166
+ }
167
+ if (this.active) {
168
+ this.scheduleLayout();
169
+ this.notify();
170
+ }
171
+ }
172
+ next() {
173
+ if (this.current < this.viewer.slideCount) {
174
+ this.goTo(this.current + 1);
175
+ }
176
+ }
177
+ previous() {
178
+ if (this.current > 1) {
179
+ this.goTo(this.current - 1);
180
+ }
181
+ }
182
+ /** Scale the active slide to fit the overlay, letterboxing whichever axis has slack. */
183
+ layout() {
184
+ const overlay = this.overlay;
185
+ if (!overlay) {
186
+ return;
187
+ }
188
+ const container = this.slideContainers().find((item, index) => {
189
+ if (item.dataset.slideNumber) {
190
+ return Number(item.dataset.slideNumber) === this.current;
191
+ }
192
+ return index === this.current - 1;
193
+ });
194
+ // Windowed decks wrap the slide in a slot; non-windowed decks are the slide.
195
+ const slide = container && container.classList.contains('flyfish-pptx-slide-slot')
196
+ ? container.firstElementChild
197
+ : container;
198
+ const size = this.viewer.slideDimensions;
199
+ const slideWidth = (slide === null || slide === void 0 ? void 0 : slide.offsetWidth) || (size === null || size === void 0 ? void 0 : size.width) || 0;
200
+ const slideHeight = (slide === null || slide === void 0 ? void 0 : slide.offsetHeight) || (size === null || size === void 0 ? void 0 : size.height) || 0;
201
+ if (!slideWidth || !slideHeight) {
202
+ return;
203
+ }
204
+ const viewWidth = overlay.clientWidth;
205
+ const viewHeight = overlay.clientHeight;
206
+ const scale = Math.min(viewWidth / slideWidth, viewHeight / slideHeight);
207
+ const offsetX = Math.max(0, (viewWidth - slideWidth * scale) / 2);
208
+ const offsetY = Math.max(0, (viewHeight - slideHeight * scale) / 2);
209
+ const content = this.viewer.content;
210
+ content.style.width = `${slideWidth}px`;
211
+ content.style.transform = `translate(${offsetX}px, ${offsetY}px) scale(${scale})`;
212
+ const scaleBox = this.viewer.scaleBox;
213
+ scaleBox.style.width = '100%';
214
+ scaleBox.style.height = '100%';
215
+ scaleBox.style.minHeight = '';
216
+ }
217
+ destroy() {
218
+ this.exit();
219
+ }
220
+ slots() {
221
+ return Array.from(this.viewer.content.querySelectorAll(':scope > .flyfish-pptx-slide-slot'));
222
+ }
223
+ /**
224
+ * The nodes the slideshow toggles between. Windowed decks wrap each slide in a
225
+ * slot; the default (non-windowed) deck appends slides directly to the content
226
+ * node, so those are the containers there.
227
+ */
228
+ slideContainers() {
229
+ const slots = this.slots();
230
+ if (slots.length > 0) {
231
+ return slots;
232
+ }
233
+ return Array.from(this.viewer.content.querySelectorAll(':scope > .slide'));
234
+ }
235
+ /**
236
+ * Chromium reports the fullscreen element of a shadow root on the shadow root
237
+ * itself while document.fullscreenElement stays on the host, so both have to
238
+ * be checked before deciding who owns fullscreen.
239
+ */
240
+ isFullscreenElement(overlay) {
241
+ const documentRef = this.viewer.target.ownerDocument || document;
242
+ if (documentRef.fullscreenElement === overlay) {
243
+ return true;
244
+ }
245
+ const root = overlay.getRootNode();
246
+ if (root !== documentRef && 'fullscreenElement' in root) {
247
+ return root.fullscreenElement === overlay;
248
+ }
249
+ return false;
250
+ }
251
+ scheduleLayout() {
252
+ const view = this.viewer.target.ownerDocument.defaultView || window;
253
+ if (this.layoutFrame) {
254
+ view.cancelAnimationFrame(this.layoutFrame);
255
+ }
256
+ this.layoutFrame = view.requestAnimationFrame(() => {
257
+ this.layoutFrame = 0;
258
+ this.layout();
259
+ });
260
+ }
261
+ notify() {
262
+ this.viewer.emitPresentationChange(this.state);
263
+ }
264
+ on(target, type, listener) {
265
+ target.addEventListener(type, listener);
266
+ this.listeners.push({ target, type, listener });
267
+ }
268
+ attach(documentRef, overlay) {
269
+ const view = documentRef.defaultView || window;
270
+ this.on(documentRef, 'keydown', (event) => this.handleKey(event));
271
+ this.on(overlay, 'click', (event) => this.handleClick(event));
272
+ this.on(overlay, 'contextmenu', (event) => {
273
+ event.preventDefault();
274
+ this.previous();
275
+ });
276
+ this.on(view, 'resize', () => this.scheduleLayout());
277
+ this.on(documentRef, 'fullscreenchange', () => {
278
+ // Leaving fullscreen with the browser's own Esc must close the slideshow too, otherwise the
279
+ // overlay would stay up as a plain fixed layer.
280
+ if (this.ownsFullscreen && !this.isFullscreenElement(overlay)) {
281
+ this.ownsFullscreen = false;
282
+ this.exit();
283
+ }
284
+ });
285
+ }
286
+ detach() {
287
+ for (const { target, type, listener } of this.listeners) {
288
+ target.removeEventListener(type, listener);
289
+ }
290
+ this.listeners = [];
291
+ }
292
+ handleClick(event) {
293
+ var _a;
294
+ const overlay = this.overlay;
295
+ if (!overlay || ((_a = event.target) === null || _a === void 0 ? void 0 : _a.closest('.flyfish-pptx-presentation-exit'))) {
296
+ return;
297
+ }
298
+ // PowerPoint advances on click; the left edge is the only place that goes back.
299
+ const bounds = overlay.getBoundingClientRect();
300
+ const ratio = (event.clientX - bounds.left) / (bounds.width || 1);
301
+ if (ratio < 0.2) {
302
+ this.previous();
303
+ }
304
+ else {
305
+ this.next();
306
+ }
307
+ }
308
+ handleKey(event) {
309
+ if (!this.active || event.altKey || event.metaKey || event.ctrlKey) {
310
+ return;
311
+ }
312
+ // Enter/Space on a focused control (the exit button) must activate that
313
+ // control, not advance the slide. Let the browser's default run instead.
314
+ const target = event.target;
315
+ if (target &&
316
+ typeof target.closest === 'function' &&
317
+ target.closest('button, a, input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
318
+ return;
319
+ }
320
+ // With two slideshows open, a key pressed inside the other overlay belongs
321
+ // to that overlay; only the focused one advances.
322
+ if (target && typeof target.closest === 'function') {
323
+ const otherOverlay = target.closest('.flyfish-pptx-presentation');
324
+ if (otherOverlay && otherOverlay !== this.overlay) {
325
+ return;
326
+ }
327
+ }
328
+ switch (event.key) {
329
+ case 'ArrowRight':
330
+ case 'ArrowDown':
331
+ case 'PageDown':
332
+ case ' ':
333
+ case 'Enter':
334
+ event.preventDefault();
335
+ this.next();
336
+ break;
337
+ case 'ArrowLeft':
338
+ case 'ArrowUp':
339
+ case 'PageUp':
340
+ case 'Backspace':
341
+ event.preventDefault();
342
+ this.previous();
343
+ break;
344
+ case 'Home':
345
+ event.preventDefault();
346
+ this.goTo(1);
347
+ break;
348
+ case 'End':
349
+ event.preventDefault();
350
+ this.goTo(this.viewer.slideCount);
351
+ break;
352
+ case 'Escape':
353
+ event.preventDefault();
354
+ this.exit();
355
+ break;
356
+ default:
357
+ break;
358
+ }
359
+ }
360
+ }
package/dist/styles.js CHANGED
@@ -57,6 +57,24 @@ export const pptxViewerCss = `
57
57
  ${scopePptxContentStyleText(legacyPptxCss)}
58
58
  .flyfish-pptx-content > .slide:last-of-type{margin-bottom:0}
59
59
  .flyfish-pptx-slide-slot:last-of-type > .slide{margin-bottom:0}
60
+ .flyfish-pptx-presentation{position:fixed;inset:0;z-index:2147483000;display:block;overflow:hidden;background:#000;cursor:default;user-select:none;-webkit-user-select:none}
61
+ .flyfish-pptx-presentation:focus{outline:none}
62
+ .flyfish-pptx-presentation-stage{position:absolute;inset:0;overflow:hidden}
63
+ .flyfish-pptx-presentation .flyfish-pptx-scale-box{position:absolute;inset:0;width:100%;height:100%;margin:0}
64
+ .flyfish-pptx-presentation .flyfish-pptx-thumbnail{display:none}
65
+ .flyfish-pptx-content.is-presenting > .flyfish-pptx-slide-slot{display:none;min-height:0}
66
+ .flyfish-pptx-content.is-presenting > .flyfish-pptx-slide-slot.is-active-slide{display:flow-root}
67
+ .flyfish-pptx-content.is-presenting > .slide{display:none}
68
+ .flyfish-pptx-content.is-presenting > .slide.is-active-slide{display:block}
69
+ .flyfish-pptx-content.is-presenting .slide{margin:0!important;box-shadow:none}
70
+ .flyfish-pptx-presentation-counter{position:absolute;right:18px;bottom:14px;padding:5px 12px;border-radius:999px;background:rgba(255,255,255,.14);color:#fff;font:13px/1.4 system-ui,sans-serif;letter-spacing:.02em;pointer-events:none}
71
+ .flyfish-pptx-presentation-hint{position:absolute;left:18px;bottom:14px;color:rgba(255,255,255,.55);font:12px/1.4 system-ui,sans-serif;pointer-events:none}
72
+ .flyfish-pptx-presentation-hint[hidden]{display:none}
73
+ .flyfish-pptx-presentation-exit{position:absolute;top:14px;right:14px;width:34px;height:34px;padding:0;border:0;border-radius:999px;background:rgba(255,255,255,.14);color:#fff;font-size:15px;line-height:1;cursor:pointer}
74
+ .flyfish-pptx-presentation-exit:hover{background:rgba(255,255,255,.26)}
75
+ .flyfish-pptx-presentation-exit:focus-visible{outline:2px solid #fff;outline-offset:2px}
76
+ @media (prefers-reduced-motion:no-preference){.flyfish-pptx-content.is-presenting > .flyfish-pptx-slide-slot.is-active-slide,.flyfish-pptx-content.is-presenting > .slide.is-active-slide{animation:flyfish-pptx-slide-in 140ms ease-out}}
77
+ @keyframes flyfish-pptx-slide-in{from{opacity:.35}to{opacity:1}}
60
78
  `;
61
79
  const PPTX_STYLE_ID = 'flyfish-pptx-native-style';
62
80
  export const ensurePptxViewerStyles = (documentRef, root = documentRef) => {
package/dist/types.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { PptxPresentationLabels, PptxPresentationState } from './presentation';
1
2
  export type PptxFitMode = 'contain' | 'none';
2
3
  export interface PptxZipLimits {
3
4
  maxFileBytes?: number;
@@ -60,6 +61,9 @@ export interface PptxViewerOptions extends PptxWorkerFactoryOptions {
60
61
  onRenderComplete?: () => void;
61
62
  onWarning?: (warning: unknown) => void;
62
63
  onError?: (error: unknown) => void;
64
+ presentationLabels?: PptxPresentationLabels;
65
+ presentationFullscreen?: boolean;
66
+ onPresentationChange?: (state: PptxPresentationState) => void;
63
67
  }
64
68
  export interface PptxWorkerMessage {
65
69
  type: string;
package/dist/viewer.d.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import type { PptxPresentationState } from './presentation';
1
2
  import type { PptxViewerOptions } from './types';
2
3
  export declare class PptxViewer {
3
4
  static open(buffer: ArrayBuffer, target: HTMLElement, options?: PptxViewerOptions): Promise<PptxViewer>;
@@ -16,6 +17,9 @@ export declare class PptxViewer {
16
17
  private previewThumbnailDataUrl;
17
18
  private slideSize;
18
19
  private slideRecords;
20
+ private totalSlides;
21
+ private savedScroll;
22
+ private pendingScrollRestore;
19
23
  private slideWindowTarget;
20
24
  private slideWindowListeners;
21
25
  private slideWindowFrame;
@@ -24,10 +28,38 @@ export declare class PptxViewer {
24
28
  private readonly mediaRecords;
25
29
  private disposed;
26
30
  private completed;
31
+ private presentation;
27
32
  private readonly handleSlideWindowChange;
28
33
  private constructor();
29
34
  get zoomPercent(): number;
30
35
  get thumbnailDataUrl(): string | null;
36
+ get slideCount(): number;
37
+ get slideDimensions(): {
38
+ width: number;
39
+ height: number;
40
+ } | null;
41
+ get presenting(): boolean;
42
+ get presentationSlideNumber(): number;
43
+ private get styleRoot();
44
+ /**
45
+ * Where the slideshow overlay is mounted. It has to share a root with the injected slide styles,
46
+ * or the engine's scoped CSS stops applying once the slides move into the overlay.
47
+ */
48
+ get presentationRoot(): ShadowRoot | HTMLElement;
49
+ /** Force a slide out of the virtualized window so the slideshow can show it immediately. */
50
+ ensureSlideRendered(slideNumber: number): Element | null;
51
+ refreshLayout(): void;
52
+ /**
53
+ * Remember where the deck was scrolled before the slideshow moves the scale
54
+ * box into the overlay. Moving it collapses the scroller and clamps scrollTop
55
+ * to zero, so the position has to be captured up front and restored on exit.
56
+ */
57
+ saveScrollPosition(): void;
58
+ restoreScrollPosition(): void;
59
+ emitPresentationChange(state: PptxPresentationState): void;
60
+ enterPresentation(slideNumber?: number): Promise<void>;
61
+ exitPresentation(): void;
62
+ togglePresentation(slideNumber?: number): Promise<void>;
31
63
  open(): Promise<void>;
32
64
  setZoom(percent: number): Promise<void>;
33
65
  destroy(): void;