@file-viewer/pptx 3.3.1 → 3.3.3

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.
@@ -1,12 +1,10 @@
1
- import type { PptxChartAxis, PptxChartModel } from './chart-types.js';
2
- /** Common authored numeric formats; unsupported Excel formats remain in the model. */
1
+ import type { PptxChartAxis, PptxChartModel } from "./chart-types.js";
3
2
  export declare const formatPptxChartNumber: (value: number, format?: string) => string;
4
3
  export declare const resolvePptxChartAxes: (model: PptxChartModel) => {
5
4
  category: PptxChartAxis | undefined;
6
5
  primary: PptxChartAxis | undefined;
7
6
  secondary: PptxChartAxis | undefined;
8
7
  };
9
- /** One category coordinate system, with every authored bar/line/area group. */
10
8
  export declare const createPptxCartesianChart: (model: PptxChartModel, library: Record<string, any>) => {
11
9
  interaction: {
12
10
  enabled: boolean;
@@ -1,4 +1,3 @@
1
- /** Common authored numeric formats; unsupported Excel formats remain in the model. */
2
1
  export const formatPptxChartNumber = (value, format = 'General') => {
3
2
  if (!Number.isFinite(value))
4
3
  return '';
@@ -37,7 +36,6 @@ export const resolvePptxChartAxes = (model) => {
37
36
  const category = (_b = axesFor(model.groups[0]).find(axis => axis.kind === 'category' || axis.kind === 'date')) !== null && _b !== void 0 ? _b : model.axes.find(axis => axis.kind === 'category' || axis.kind === 'date');
38
37
  return { category, primary, secondary };
39
38
  };
40
- /** One category coordinate system, with every authored bar/line/area group. */
41
39
  export const createPptxCartesianChart = (model, library) => {
42
40
  var _a, _b, _c, _d;
43
41
  if (!model.groups.length || model.groups.some(group => !['lineChart', 'barChart', 'areaChart'].includes(group.chartType)))
@@ -73,7 +71,6 @@ export const createPptxCartesianChart = (model, library) => {
73
71
  const groups = model.groups.flatMap((group, groupIndex) => group.options.grouping === 'stacked' || group.options.grouping === 'percentStacked'
74
72
  ? [rows.filter(row => row.groupIndex === groupIndex).map(row => row.id)] : []);
75
73
  const normalizeAll = model.groups.length === 1 && model.groups[0].options.grouping === 'percentStacked';
76
- // Normalize only this stacked group, preserving an unrelated line/secondary axis.
77
74
  const totals = new Map();
78
75
  rows.forEach((row, rowIndex) => {
79
76
  if (normalizeAll || row.group.options.grouping !== 'percentStacked')
@@ -1,6 +1,4 @@
1
- import type { PptxChartFont, PptxChartOptions } from './chart-types.js';
2
- /** Billboard only provides outside bottom/right legends. Preserve the other
3
- * DrawingML placements without changing the authored outer chart frame. */
1
+ import type { PptxChartFont, PptxChartOptions } from "./chart-types.js";
4
2
  export declare const createPptxChartLegend: (surface: HTMLElement, chart: any, legend?: PptxChartOptions["legend"], font?: PptxChartFont) => {
5
3
  size(): {
6
4
  width: number;
@@ -1,6 +1,4 @@
1
- import { applyPptxChartFont } from './chart-text.js';
2
- /** Billboard only provides outside bottom/right legends. Preserve the other
3
- * DrawingML placements without changing the authored outer chart frame. */
1
+ import { applyPptxChartFont } from "./chart-text.js";
4
2
  export const createPptxChartLegend = (surface, chart, legend, font) => {
5
3
  var _a, _b;
6
4
  const document = surface.ownerDocument;
@@ -28,8 +26,6 @@ export const createPptxChartLegend = (surface, chart, legend, font) => {
28
26
  else
29
27
  list.style.width = '100%';
30
28
  }
31
- // Prevent the surface's 100% basis from pushing a non-overlay legend outside
32
- // the frame. Flex assigns only the remaining logical area to the plot.
33
29
  surface.style.width = left ? '0' : '100%';
34
30
  surface.style.height = left ? '100%' : '0';
35
31
  surface.style.alignSelf = 'stretch';
@@ -1,14 +1,7 @@
1
- import type { PptxChartFont, PptxChartModel } from './chart-types.js';
1
+ import type { PptxChartFont, PptxChartModel } from "./chart-types.js";
2
2
  export declare const mergePptxChartFonts: (...fonts: Array<PptxChartFont | undefined>) => PptxChartFont;
3
- /** CSSOM property assignment keeps document font names out of stylesheet source. */
4
3
  export declare const applyPptxChartFont: (style: CSSStyleDeclaration, font?: PptxChartFont) => void;
5
- /** Apply authored fonts before Billboard measures labels, including Shadow DOM. */
6
4
  export declare const stylePptxChartText: (surface: HTMLElement, model?: PptxChartModel, chart?: any, legendFont?: PptxChartFont) => HTMLStyleElement | undefined;
7
- /**
8
- * Billboard's plugin hooks are per-chart. Its screen-space text rectangles and
9
- * punctuation-normalized cache keys cannot represent DrawingML coordinates or
10
- * distinct CJK labels. Measure fresh SVG glyph geometry in local coordinates.
11
- */
12
5
  export declare const createPptxChartTextPlugin: (surface: HTMLElement) => {
13
6
  $$: any;
14
7
  $beforeInit(): void;
@@ -1,6 +1,5 @@
1
- import { resolvePptxChartAxes } from './chart-config.js';
1
+ import { resolvePptxChartAxes } from "./chart-config.js";
2
2
  export const mergePptxChartFonts = (...fonts) => Object.assign({}, ...fonts.map(font => Object.fromEntries(Object.entries(font || {}).filter(([, value]) => value !== undefined))));
3
- /** CSSOM property assignment keeps document font names out of stylesheet source. */
4
3
  export const applyPptxChartFont = (style, font) => {
5
4
  if (!font)
6
5
  return;
@@ -23,7 +22,6 @@ export const applyPptxChartFont = (style, font) => {
23
22
  style.fill = font.color;
24
23
  }
25
24
  };
26
- /** Apply authored fonts before Billboard measures labels, including Shadow DOM. */
27
25
  export const stylePptxChartText = (surface, model, chart, legendFont) => {
28
26
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
29
27
  const view = (_a = surface.ownerDocument) === null || _a === void 0 ? void 0 : _a.defaultView;
@@ -35,8 +33,6 @@ export const stylePptxChartText = (surface, model, chart, legendFont) => {
35
33
  const selector = `.pptx-chart-surface.pptx-chart-typed[data-pptx-chart-text="${scope}"]`;
36
34
  const element = surface.ownerDocument.createElement('style');
37
35
  element.dataset.pptxChartFonts = '';
38
- // Billboard replaces the bind target's children during initialization.
39
- // Keep scoped rules beside that target so they also apply during measurement.
40
36
  (_b = surface.parentNode) === null || _b === void 0 ? void 0 : _b.appendChild(element);
41
37
  const sheet = element.sheet;
42
38
  if (!sheet)
@@ -77,11 +73,6 @@ export const stylePptxChartText = (surface, model, chart, legendFont) => {
77
73
  }
78
74
  return element;
79
75
  };
80
- /**
81
- * Billboard's plugin hooks are per-chart. Its screen-space text rectangles and
82
- * punctuation-normalized cache keys cannot represent DrawingML coordinates or
83
- * distinct CJK labels. Measure fresh SVG glyph geometry in local coordinates.
84
- */
85
76
  export const createPptxChartTextPlugin = (surface) => {
86
77
  const document = surface.ownerDocument;
87
78
  const view = document === null || document === void 0 ? void 0 : document.defaultView;
@@ -126,7 +117,6 @@ export const createPptxChartTextPlugin = (surface) => {
126
117
  return { x: box.x, y: box.y, left: box.x, top: box.y, right: box.x + box.width,
127
118
  bottom: box.y + box.height, width: box.width, height: box.height };
128
119
  }
129
- // Hidden slides still need logical font metrics before they become visible.
130
120
  const style = view.getComputedStyle(node);
131
121
  context !== null && context !== void 0 ? context : (context = document.createElement('canvas').getContext('2d'));
132
122
  const size = Number.parseFloat(style.fontSize) || 10;
@@ -1,4 +1,3 @@
1
- /** Serializable DrawingML metadata carried by the actual PPTX Worker. */
2
1
  export type PptxChartType = 'lineChart' | 'barChart' | 'areaChart' | 'scatterChart' | 'pieChart' | 'pie3DChart' | 'doughnutChart';
3
2
  export interface PptxChartFont {
4
3
  family?: string;
@@ -47,7 +46,6 @@ export interface PptxChartSeries {
47
46
  y: number | null;
48
47
  }>;
49
48
  xlabels: Record<string, string | number>;
50
- /** Original indexed hierarchy, from innermost to outermost category level. */
51
49
  categoryLevels?: Array<Record<string, string>>;
52
50
  }
53
51
  export interface PptxChartAxis {
package/dist/chart.d.ts CHANGED
@@ -1,16 +1,14 @@
1
- import type { PptxChartRenderer } from './chart-types.js';
1
+ import type { PptxChartRenderer } from "./chart-types.js";
2
2
  export type PptxChartLibraries = {
3
3
  billboard: any;
4
4
  d3Format: typeof import('d3-format');
5
5
  };
6
6
  export type PptxChartLibraryLoader = () => Promise<PptxChartLibraries>;
7
- /** Register a renderer receiving the preserved Worker model, without reopening the ZIP. */
8
7
  export declare const registerPptxChartRenderer: (renderer: PptxChartRenderer | null) => void;
9
8
  export declare const registerPptxChartLibraryLoader: (loader: PptxChartLibraryLoader | null) => void;
10
9
  export type PptxPostProcessingHandle = {
11
10
  destroy: () => void;
12
11
  };
13
12
  export declare const findPptxChartTarget: (root: ParentNode, chartID: string) => HTMLElement | null;
14
- /** DrawingML numbering, including the authored suffix punctuation. */
15
13
  export declare const getNumericBulletText: (type: string, index: number) => string;
16
14
  export declare const renderPptxPostProcessing: (charts: unknown, root: ParentNode) => Promise<PptxPostProcessingHandle>;
package/dist/chart.js CHANGED
@@ -1,9 +1,8 @@
1
- import { createPptxCartesianChart } from './chart-config.js';
2
- import { createPptxChartTextPlugin, mergePptxChartFonts, stylePptxChartText } from './chart-text.js';
3
- import { createPptxChartLegend } from './chart-legend.js';
1
+ import { createPptxCartesianChart } from "./chart-config.js";
2
+ import { createPptxChartTextPlugin, mergePptxChartFonts, stylePptxChartText } from "./chart-text.js";
3
+ import { createPptxChartLegend } from "./chart-legend.js";
4
4
  let chartLibraryLoader = null;
5
5
  let chartRenderer = null;
6
- /** Register a renderer receiving the preserved Worker model, without reopening the ZIP. */
7
6
  export const registerPptxChartRenderer = (renderer) => {
8
7
  chartRenderer = renderer;
9
8
  };
@@ -47,7 +46,6 @@ const formatEastAsianNumber = (index) => {
47
46
  return digits[Math.floor(index / 10000)] + '万' +
48
47
  (remainder ? (remainder < 1000 ? digits[0] : '') + group(remainder, false) : '');
49
48
  };
50
- /** DrawingML numbering, including the authored suffix punctuation. */
51
49
  export const getNumericBulletText = (type, index) => {
52
50
  if (!Number.isInteger(index) || index < 1 || index > 32767) {
53
51
  return String(index);
@@ -179,8 +177,6 @@ const applyTextFitScale = (block, scale) => {
179
177
  const hasTextOverflow = (block, fitWidth = true) => block.scrollHeight > block.clientHeight + TEXT_FIT_TOLERANCE ||
180
178
  (fitWidth && block.scrollWidth > block.clientWidth + TEXT_FIT_TOLERANCE);
181
179
  const fitOverflowingTextBlock = (block, fitWidth = true) => {
182
- // noAutofit/spAutoFit preserve authored typography. Only normal AutoFit may
183
- // shrink text; unmarked legacy/table content retains its existing policy.
184
180
  const mode = block.dataset.pptxAutofit;
185
181
  if (mode && mode !== 'normal')
186
182
  return;
@@ -244,14 +240,10 @@ const renderChart = async (message, root) => {
244
240
  const { billboard, d3Format } = await chartLibraryLoader();
245
241
  const bb = billboard.default || billboard;
246
242
  const { area, bar, line, pie, donut, scatter } = billboard;
247
- // Billboard 4 exposes grid focus as a separately registered ESM module.
248
- // Bundled or custom loaders may already provide it without this export.
249
243
  if (typeof billboard.grid === 'function') {
250
244
  billboard.grid();
251
245
  }
252
246
  const chart = {
253
- // A selector makes Billboard query the main document. That misses chart
254
- // placeholders inside the viewer Shadow DOM and makes it fall back to body.
255
247
  bindto: chartTarget,
256
248
  };
257
249
  const chartData = payload.chartData;
@@ -276,8 +268,6 @@ const renderChart = async (message, root) => {
276
268
  const names = {};
277
269
  const colors = {};
278
270
  for (const [index, point] of ((series === null || series === void 0 ? void 0 : series.values) || []).entries()) {
279
- // Keep one library id per indexed point, not per label. Duplicate/empty
280
- // labels are valid and must never merge sectors. Null is not zero.
281
271
  if (typeof point.y !== 'number' || !Number.isFinite(point.y) || point.y === 0)
282
272
  continue;
283
273
  const id = `point-${index}`;
@@ -300,11 +290,6 @@ const renderChart = async (message, root) => {
300
290
  },
301
291
  transition: { duration: 0 },
302
292
  onrendered() {
303
- // Billboard accepts an absolute ring width, while DrawingML specifies
304
- // a ratio. Read its finished SVG geometry and update through the public
305
- // config API. This also tracks library resize without private state or
306
- // assumptions about legend/font layout. The re-entrancy guard bounds
307
- // the corrective redraw to one pass per changed radius.
308
293
  if (adjustingWidth || typeof this.config !== 'function')
309
294
  return;
310
295
  let radius = 0;
@@ -418,15 +403,10 @@ const renderChart = async (message, root) => {
418
403
  chart.legend = {
419
404
  show: options.legend.show !== false,
420
405
  position: options.legend.position === 'b' ? 'bottom' : 'right',
421
- // The chart library cannot measure an empty SVG text node. Use an
422
- // invisible measuring character only in legend presentation; names and
423
- // tooltip data still retain the document's actual empty string.
424
406
  format: (label) => label === '' ? '\u200b' : label,
425
407
  };
426
408
  }
427
409
  if (!cartesian && ['barChart', 'areaChart', 'lineChart'].includes(payload.chartType)) {
428
- // Distinct series can legitimately share a display name. Billboard groups
429
- // by id, so disambiguate only duplicate ids and preserve authored labels.
430
410
  const used = new Set();
431
411
  const reserved = new Set(chart.data.columns.map((column) => String(column[0])));
432
412
  const names = {};
@@ -459,8 +439,6 @@ const renderChart = async (message, root) => {
459
439
  if (Object.keys(colors).length)
460
440
  chart.data.colors = colors;
461
441
  }
462
- // Billboard resets the bind target's position to relative. Keep DrawingML
463
- // placement on the outer frame; only let the library own its inner surface.
464
442
  const surface = chartTarget.ownerDocument.createElement('div');
465
443
  surface.className = 'pptx-chart-surface';
466
444
  surface.style.cssText = 'width:100%;height:100%;min-width:0;min-height:0;flex:1 1 auto';
@@ -471,10 +449,6 @@ const renderChart = async (message, root) => {
471
449
  const textPlugin = createPptxChartTextPlugin(surface);
472
450
  if (textPlugin)
473
451
  chart.plugins = [...(chart.plugins || []), textPlugin];
474
- // DrawingML fixes the chart's size in slide coordinates. Billboard's
475
- // automatic measurement uses transformed screen rectangles (or a visible
476
- // ancestor for hidden slides), which applies presentation scaling twice.
477
- // Keep fractional authored dimensions; the viewer scales the whole slide.
478
452
  const logicalSize = [((_u = chartTarget.style) === null || _u === void 0 ? void 0 : _u.width) || '', ((_v = chartTarget.style) === null || _v === void 0 ? void 0 : _v.height) || '']
479
453
  .map(value => /^\d+(?:\.\d+)?px$/.test(value) ? Number.parseFloat(value) : NaN);
480
454
  if (logicalSize.every(value => Number.isFinite(value) && value > 0)) {
@@ -538,7 +512,6 @@ export const renderPptxPostProcessing = async (charts, root) => {
538
512
  (_a = chart.destroy) === null || _a === void 0 ? void 0 : _a.call(chart);
539
513
  }
540
514
  catch {
541
- // The DOM may already be detached during framework unmount.
542
515
  }
543
516
  }
544
517
  chartInstances.length = 0;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
- export { PptxViewer } from './viewer.js';
2
- export { PptxPresentation } from './presentation.js';
3
- export type { PptxPresentationLabels, PptxPresentationState } from './presentation.js';
4
- export { createPptxWorker, resolvePptxPackageWorkerUrl } from './worker.js';
5
- export { registerPptxChartLibraryLoader, registerPptxChartRenderer } from './chart.js';
6
- export type { PptxChartLibraries, PptxChartLibraryLoader } from './chart.js';
7
- export type { PptxChartType, PptxChartFont, PptxChartLabels, PptxChartOptions, PptxChartSeries, PptxChartAxis, PptxChartGroup, PptxChartModel, PptxChartMessage, PptxChartCollection, PptxChartRenderer, } from './chart-types.js';
8
- export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from './options.js';
9
- export type { NativePptxEngineOptions, PptxDiagnosticError, PptxDiagnosticErrorCode, PptxFitMode, PptxListOptions, PptxSlideSize, PptxViewerOptions, PptxWorkerFactoryOptions, PptxWorkerMessage, PptxZipLimits, } from './types.js';
1
+ export { PptxViewer } from "./viewer.js";
2
+ export { PptxPresentation } from "./presentation.js";
3
+ export type { PptxPresentationLabels, PptxPresentationState } from "./presentation.js";
4
+ export { createPptxWorker, resolvePptxPackageWorkerUrl } from "./worker.js";
5
+ export { registerPptxChartLibraryLoader, registerPptxChartRenderer } from "./chart.js";
6
+ export type { PptxChartLibraries, PptxChartLibraryLoader } from "./chart.js";
7
+ export type { PptxChartType, PptxChartFont, PptxChartLabels, PptxChartOptions, PptxChartSeries, PptxChartAxis, PptxChartGroup, PptxChartModel, PptxChartMessage, PptxChartCollection, PptxChartRenderer, } from "./chart-types.js";
8
+ export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from "./options.js";
9
+ export type { NativePptxEngineOptions, PptxDiagnosticError, PptxDiagnosticErrorCode, PptxFitMode, PptxListOptions, PptxSlideSize, PptxViewerOptions, PptxWorkerFactoryOptions, PptxWorkerMessage, PptxZipLimits, } from "./types.js";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
- export { PptxViewer } from './viewer.js';
2
- export { PptxPresentation } from './presentation.js';
3
- export { createPptxWorker, resolvePptxPackageWorkerUrl } from './worker.js';
4
- export { registerPptxChartLibraryLoader, registerPptxChartRenderer } from './chart.js';
5
- export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from './options.js';
1
+ export { PptxViewer } from "./viewer.js";
2
+ export { PptxPresentation } from "./presentation.js";
3
+ export { createPptxWorker, resolvePptxPackageWorkerUrl } from "./worker.js";
4
+ export { registerPptxChartLibraryLoader, registerPptxChartRenderer } from "./chart.js";
5
+ export { RECOMMENDED_ZIP_LIMITS, createDefaultPptxOptions, resolvePptxEngineOptions, } from "./options.js";
package/dist/options.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { NativePptxEngineOptions, PptxZipLimits } from './types.js';
1
+ import type { NativePptxEngineOptions, PptxZipLimits } from "./types.js";
2
2
  export declare const RECOMMENDED_ZIP_LIMITS: Required<PptxZipLimits>;
3
3
  export declare const createDefaultPptxOptions: () => NativePptxEngineOptions;
4
4
  export declare const resolvePptxEngineOptions: (options?: Partial<NativePptxEngineOptions>) => NativePptxEngineOptions;
@@ -1,4 +1,4 @@
1
- import type { PptxViewer } from './viewer.js';
1
+ import type { PptxViewer } from "./viewer.js";
2
2
  export interface PptxPresentationState {
3
3
  active: boolean;
4
4
  slideNumber: number;
@@ -10,14 +10,6 @@ export interface PptxPresentationLabels {
10
10
  next?: string;
11
11
  previous?: string;
12
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
13
  export declare class PptxPresentation {
22
14
  private readonly viewer;
23
15
  private readonly labels;
@@ -40,21 +32,10 @@ export declare class PptxPresentation {
40
32
  goTo(slideNumber: number): void;
41
33
  next(): void;
42
34
  previous(): void;
43
- /** Scale the active slide to fit the overlay, letterboxing whichever axis has slack. */
44
35
  layout(): void;
45
36
  destroy(): void;
46
37
  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
38
  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
39
  private isFullscreenElement;
59
40
  private scheduleLayout;
60
41
  private notify;
@@ -1,12 +1,4 @@
1
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
2
  export class PptxPresentation {
11
3
  constructor(viewer, labels = {}, fullscreen = true) {
12
4
  this.overlay = null;
@@ -62,11 +54,8 @@ export class PptxPresentation {
62
54
  this.overlay = overlay;
63
55
  this.stage = stage;
64
56
  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
57
  const styleRoot = this.viewer.presentationRoot;
68
58
  styleRoot.appendChild(overlay);
69
- // Park a comment where the scale box lived so exit() can restore the exact position.
70
59
  this.placeholder = documentRef.createComment('flyfish-pptx-presentation');
71
60
  this.viewer.saveScrollPosition();
72
61
  this.viewer.scaleBox.replaceWith(this.placeholder);
@@ -80,13 +69,9 @@ export class PptxPresentation {
80
69
  this.ownsFullscreen = this.isFullscreenElement(overlay);
81
70
  }
82
71
  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
72
  this.ownsFullscreen = false;
86
73
  }
87
74
  }
88
- // exit() may have run while fullscreen was being requested. Leave the
89
- // browser out of fullscreen rather than stranded with no overlay.
90
75
  if (this.overlay !== overlay) {
91
76
  if (this.ownsFullscreen) {
92
77
  void ((_b = documentRef.exitFullscreen) === null || _b === void 0 ? void 0 : _b.call(documentRef).catch(() => undefined));
@@ -105,8 +90,6 @@ export class PptxPresentation {
105
90
  return;
106
91
  }
107
92
  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
93
  const shouldExitFullscreen = this.ownsFullscreen && this.isFullscreenElement(overlay);
111
94
  this.detach();
112
95
  if (this.layoutFrame) {
@@ -149,11 +132,8 @@ export class PptxPresentation {
149
132
  }
150
133
  this.current = clamp(Math.round(slideNumber) || 1, 1, total);
151
134
  this.viewer.ensureSlideRendered(this.current);
152
- // Rendering the neighbour keeps the next step instant without defeating virtualization.
153
135
  this.viewer.ensureSlideRendered(this.current + 1);
154
136
  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
137
  const byNumber = containers.some(container => Boolean(container.dataset.slideNumber));
158
138
  containers.forEach((container, index) => {
159
139
  const isActive = byNumber
@@ -179,7 +159,6 @@ export class PptxPresentation {
179
159
  this.goTo(this.current - 1);
180
160
  }
181
161
  }
182
- /** Scale the active slide to fit the overlay, letterboxing whichever axis has slack. */
183
162
  layout() {
184
163
  const overlay = this.overlay;
185
164
  if (!overlay) {
@@ -191,7 +170,6 @@ export class PptxPresentation {
191
170
  }
192
171
  return index === this.current - 1;
193
172
  });
194
- // Windowed decks wrap the slide in a slot; non-windowed decks are the slide.
195
173
  const slide = container && container.classList.contains('flyfish-pptx-slide-slot')
196
174
  ? container.firstElementChild
197
175
  : container;
@@ -220,11 +198,6 @@ export class PptxPresentation {
220
198
  slots() {
221
199
  return Array.from(this.viewer.content.querySelectorAll(':scope > .flyfish-pptx-slide-slot'));
222
200
  }
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
201
  slideContainers() {
229
202
  const slots = this.slots();
230
203
  if (slots.length > 0) {
@@ -232,11 +205,6 @@ export class PptxPresentation {
232
205
  }
233
206
  return Array.from(this.viewer.content.querySelectorAll(':scope > .slide'));
234
207
  }
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
208
  isFullscreenElement(overlay) {
241
209
  const documentRef = this.viewer.target.ownerDocument || document;
242
210
  if (documentRef.fullscreenElement === overlay) {
@@ -275,8 +243,6 @@ export class PptxPresentation {
275
243
  });
276
244
  this.on(view, 'resize', () => this.scheduleLayout());
277
245
  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
246
  if (this.ownsFullscreen && !this.isFullscreenElement(overlay)) {
281
247
  this.ownsFullscreen = false;
282
248
  this.exit();
@@ -295,7 +261,6 @@ export class PptxPresentation {
295
261
  if (!overlay || ((_a = event.target) === null || _a === void 0 ? void 0 : _a.closest('.flyfish-pptx-presentation-exit'))) {
296
262
  return;
297
263
  }
298
- // PowerPoint advances on click; the left edge is the only place that goes back.
299
264
  const bounds = overlay.getBoundingClientRect();
300
265
  const ratio = (event.clientX - bounds.left) / (bounds.width || 1);
301
266
  if (ratio < 0.2) {
@@ -309,16 +274,12 @@ export class PptxPresentation {
309
274
  if (!this.active || event.altKey || event.metaKey || event.ctrlKey) {
310
275
  return;
311
276
  }
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
277
  const target = event.target;
315
278
  if (target &&
316
279
  typeof target.closest === 'function' &&
317
280
  target.closest('button, a, input, textarea, select, [contenteditable="true"], [contenteditable=""]')) {
318
281
  return;
319
282
  }
320
- // With two slideshows open, a key pressed inside the other overlay belongs
321
- // to that overlay; only the focused one advances.
322
283
  if (target && typeof target.closest === 'function') {
323
284
  const otherOverlay = target.closest('.flyfish-pptx-presentation');
324
285
  if (otherOverlay && otherOverlay !== this.overlay) {
package/dist/styles.d.ts CHANGED
@@ -1,8 +1,3 @@
1
- /**
2
- * The legacy engine emits class-only selector lists. Prefix each top-level
3
- * class rule so light-DOM consumers do not inherit generic `.slide` or
4
- * generated `._css_*` rules from a renderer-local style element.
5
- */
6
1
  export declare const scopePptxContentStyleText: (cssText: string) => string;
7
2
  export declare const pptxViewerCss: string;
8
3
  export declare const ensurePptxViewerStyles: (documentRef: Document, root?: Document | ShadowRoot) => void;
package/dist/styles.js CHANGED
@@ -51,11 +51,6 @@ const legacyPptxCss = `
51
51
 
52
52
  `;
53
53
  const PPTX_CONTENT_STYLE_SCOPE = '.flyfish-pptx-content';
54
- /**
55
- * The legacy engine emits class-only selector lists. Prefix each top-level
56
- * class rule so light-DOM consumers do not inherit generic `.slide` or
57
- * generated `._css_*` rules from a renderer-local style element.
58
- */
59
54
  export const scopePptxContentStyleText = (cssText) => cssText.replace(/(^|})\s*(\.[^{}]+)\{/g, (_match, boundary, selectorList) => {
60
55
  const scopedSelectors = selectorList
61
56
  .split(',')
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { PptxPresentationLabels, PptxPresentationState } from './presentation.js';
2
- import type { PptxChartCollection } from './chart-types.js';
1
+ import type { PptxPresentationLabels, PptxPresentationState } from "./presentation.js";
2
+ import type { PptxChartCollection } from "./chart-types.js";
3
3
  export type PptxFitMode = 'contain' | 'none';
4
4
  export interface PptxZipLimits {
5
5
  maxFileBytes?: number;
package/dist/viewer.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { PptxPresentationState } from './presentation.js';
2
- import type { PptxViewerOptions } from './types.js';
1
+ import type { PptxPresentationState } from "./presentation.js";
2
+ import type { PptxViewerOptions } from "./types.js";
3
3
  export declare class PptxViewer {
4
4
  static open(buffer: ArrayBuffer, target: HTMLElement, options?: PptxViewerOptions): Promise<PptxViewer>;
5
5
  readonly target: HTMLElement;
@@ -41,19 +41,9 @@ export declare class PptxViewer {
41
41
  get presenting(): boolean;
42
42
  get presentationSlideNumber(): number;
43
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
44
  get presentationRoot(): ShadowRoot | HTMLElement;
49
- /** Force a slide out of the virtualized window so the slideshow can show it immediately. */
50
45
  ensureSlideRendered(slideNumber: number): Element | null;
51
46
  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
47
  saveScrollPosition(): void;
58
48
  restoreScrollPosition(): void;
59
49
  emitPresentationChange(state: PptxPresentationState): void;
@@ -89,7 +79,6 @@ export declare class PptxViewer {
89
79
  private findSlideWindowTarget;
90
80
  private postProcessRenderedContent;
91
81
  private postProcessSlideRecord;
92
- /** Materializes every lazy slide only for the duration of an export snapshot. */
93
82
  cloneForExport(): Promise<HTMLElement>;
94
83
  private complete;
95
84
  private fail;
package/dist/viewer.js CHANGED
@@ -1,9 +1,9 @@
1
- import { renderPptxPostProcessing } from './chart.js';
2
- import { resolvePptxEngineOptions, RECOMMENDED_ZIP_LIMITS } from './options.js';
3
- import { PptxPresentation } from './presentation.js';
4
- import { sanitizePptxCss, sanitizePptxMarkup } from './sanitize.js';
5
- import { ensurePptxViewerStyles } from './styles.js';
6
- import { createPptxWorker } from './worker.js';
1
+ import { renderPptxPostProcessing } from "./chart.js";
2
+ import { resolvePptxEngineOptions, RECOMMENDED_ZIP_LIMITS } from "./options.js";
3
+ import { PptxPresentation } from "./presentation.js";
4
+ import { sanitizePptxCss, sanitizePptxMarkup } from "./sanitize.js";
5
+ import { ensurePptxViewerStyles } from "./styles.js";
6
+ import { createPptxWorker } from "./worker.js";
7
7
  const clamp = (value, min, max) => {
8
8
  return Math.min(max, Math.max(min, value));
9
9
  };
@@ -97,10 +97,6 @@ export class PptxViewer {
97
97
  this.previewThumbnailDataUrl = null;
98
98
  this.slideSize = null;
99
99
  this.slideRecords = [];
100
- // Total slides received from the worker. The windowed path mirrors this in
101
- // slideRecords, but the default (non-windowed) path appends slides straight
102
- // into the content node without creating records, so the deck size has to be
103
- // counted independently of the virtualization bookkeeping.
104
100
  this.totalSlides = 0;
105
101
  this.savedScroll = null;
106
102
  this.pendingScrollRestore = null;
@@ -164,10 +160,6 @@ export class PptxViewer {
164
160
  ? root
165
161
  : documentRef;
166
162
  }
167
- /**
168
- * Where the slideshow overlay is mounted. It has to share a root with the injected slide styles,
169
- * or the engine's scoped CSS stops applying once the slides move into the overlay.
170
- */
171
163
  get presentationRoot() {
172
164
  const documentRef = this.target.ownerDocument || document;
173
165
  const styleRoot = this.styleRoot;
@@ -176,7 +168,6 @@ export class PptxViewer {
176
168
  }
177
169
  return documentRef.body || documentRef.documentElement;
178
170
  }
179
- /** Force a slide out of the virtualized window so the slideshow can show it immediately. */
180
171
  ensureSlideRendered(slideNumber) {
181
172
  const record = this.slideRecords.find(item => item.slideNumber === slideNumber);
182
173
  if (!record) {
@@ -190,11 +181,6 @@ export class PptxViewer {
190
181
  refreshLayout() {
191
182
  this.scheduleResize();
192
183
  }
193
- /**
194
- * Remember where the deck was scrolled before the slideshow moves the scale
195
- * box into the overlay. Moving it collapses the scroller and clamps scrollTop
196
- * to zero, so the position has to be captured up front and restored on exit.
197
- */
198
184
  saveScrollPosition() {
199
185
  const view = this.target.ownerDocument.defaultView || window;
200
186
  const HTMLElementCtor = view.HTMLElement;
@@ -536,9 +522,6 @@ export class PptxViewer {
536
522
  }
537
523
  const windowOptions = this.getSlideWindowOptions();
538
524
  const indexesToRender = this.getWindowedSlideIndexes(windowOptions);
539
- // While presenting, the active slide and its neighbour live inside the fixed
540
- // overlay, outside the scroll-view geometry the windowing code measures. Keep
541
- // them mounted so a resize cannot unmount the slide that is on screen.
542
525
  const presentation = this.presentation;
543
526
  if (presentation === null || presentation === void 0 ? void 0 : presentation.active) {
544
527
  const activeIndex = this.slideRecords.findIndex(record => record.slideNumber === presentation.slideNumber);
@@ -711,7 +694,6 @@ export class PptxViewer {
711
694
  }
712
695
  await record.postProcessPromise;
713
696
  }
714
- /** Materializes every lazy slide only for the duration of an export snapshot. */
715
697
  async cloneForExport() {
716
698
  if (!this.shouldWindowSlides()) {
717
699
  return this.target.cloneNode(true);
@@ -878,7 +860,6 @@ export class PptxViewer {
878
860
  }
879
861
  resize() {
880
862
  var _a, _b, _c;
881
- // While presenting, the slideshow owns the transform of the same nodes.
882
863
  if ((_a = this.presentation) === null || _a === void 0 ? void 0 : _a.active) {
883
864
  this.presentation.layout();
884
865
  return;
@@ -901,8 +882,6 @@ export class PptxViewer {
901
882
  this.scaleBox.style.width = `${Math.ceil(slideWidth * effectiveScale)}px`;
902
883
  this.scaleBox.style.height = `${Math.ceil(this.content.scrollHeight * effectiveScale)}px`;
903
884
  this.scaleBox.style.minHeight = '';
904
- // The scale box height is recomputed above; only now can the saved scroll
905
- // position be applied without the scroller clamping it back to zero.
906
885
  if (this.pendingScrollRestore) {
907
886
  const { top, left } = this.pendingScrollRestore;
908
887
  this.pendingScrollRestore = null;
@@ -1,2 +1 @@
1
- /** Distinguish an emitted asset from an untouched dependency-relative URL. */
2
1
  export declare const isResolvedPptxWorkerLocation: (moduleUrl: URL, assetUrl: URL) => boolean;
@@ -1,7 +1,4 @@
1
- /** Distinguish an emitted asset from an untouched dependency-relative URL. */
2
1
  export const isResolvedPptxWorkerLocation = (moduleUrl, assetUrl) => {
3
- // Keep the comparison URL dynamic: a bundler must only rewrite the static
4
- // new URL reference in worker.ts, not both sides of this comparison.
5
2
  const relativePath = ['worker', 'pptx.worker.js'].join('/');
6
3
  const dependencyRelativeUrl = new URL(relativePath, moduleUrl);
7
4
  return assetUrl.href !== dependencyRelativeUrl.href || /\/dist\/worker\.[cm]?js$/.test(moduleUrl.pathname);
package/dist/worker.d.ts CHANGED
@@ -1,4 +1,3 @@
1
- import type { PptxWorkerFactoryOptions } from './types.js';
2
- /** Returns only a Worker URL that the active bundler has emitted or serves directly. */
1
+ import type { PptxWorkerFactoryOptions } from "./types.js";
3
2
  export declare const resolvePptxPackageWorkerUrl: () => string | undefined;
4
3
  export declare const createPptxWorker: (options?: PptxWorkerFactoryOptions) => Worker;
package/dist/worker.js CHANGED
@@ -1,14 +1,10 @@
1
- import { isResolvedPptxWorkerLocation } from './worker-location.js';
1
+ import { isResolvedPptxWorkerLocation } from "./worker-location.js";
2
2
  const viteOptimizedWorkerPathPattern = /\/\.?vite\/deps\/worker\/pptx\.worker\.js$/;
3
3
  const viteSourceWorkerModulePattern = /\/src\/worker\.[cm]?[jt]s$/;
4
4
  const angularCachePath = '/.angular/cache/';
5
5
  const viteOptimizedPptxSourcePattern = /\/\/\s+(node_modules\/(?:\.pnpm\/[^\n]+?\/node_modules\/)?@file-viewer\/pptx\/dist\/worker\.js)\b/;
6
6
  const resolveBundledPptxWorkerUrl = () => {
7
7
  const moduleUrl = new URL(import.meta.url);
8
- // Workspace demos and source-linked consumer projects let Vite serve this
9
- // TypeScript module directly from /@fs/.../src/worker.ts. The built Worker
10
- // remains under dist/worker, so resolving ./worker from the source module
11
- // points at a directory that does not exist.
12
8
  if (viteSourceWorkerModulePattern.test(moduleUrl.pathname)) {
13
9
  return new URL('../dist/worker/pptx.worker.js', moduleUrl);
14
10
  }
@@ -31,8 +27,6 @@ const resolveViteOptimizedPptxWorkerUrl = (defaultPptxWorkerUrl) => {
31
27
  }
32
28
  try {
33
29
  const request = new XMLHttpRequest();
34
- // Vite dev-only fallback: inspect the optimized module to recover the real
35
- // package path when @file-viewer/pptx is only a transitive pnpm dependency.
36
30
  request.open('GET', import.meta.url, false);
37
31
  request.send(null);
38
32
  if ((request.status > 0 && request.status < 200) || request.status >= 400) {
@@ -66,17 +60,12 @@ const resolvePptxWorkerUrl = (allowDependencyRelativeUrl) => {
66
60
  const optimizedUrl = resolveViteOptimizedPptxWorkerUrl(workerUrl);
67
61
  return optimizedUrl ? String(optimizedUrl) : undefined;
68
62
  }
69
- // An untouched dependency-relative URL points below the application bundle,
70
- // not this package. Renderers with copied-asset discovery must not select it.
71
63
  return allowDependencyRelativeUrl ? workerUrl.href : undefined;
72
64
  }
73
65
  catch {
74
- // An inlined module without a resolvable package base can still use the
75
- // host's standard copied assets or an explicitly configured Worker URL.
76
66
  }
77
67
  return undefined;
78
68
  };
79
- /** Returns only a Worker URL that the active bundler has emitted or serves directly. */
80
69
  export const resolvePptxPackageWorkerUrl = () => {
81
70
  return resolvePptxWorkerUrl(false);
82
71
  };
@@ -90,7 +79,6 @@ export const createPptxWorker = (options = {}) => {
90
79
  type: (_a = options.workerType) !== null && _a !== void 0 ? _a : 'module',
91
80
  });
92
81
  }
93
- // Direct PptxViewer users have no renderer-level copied-asset discovery.
94
82
  const workerUrl = resolvePptxWorkerUrl(true);
95
83
  if (!workerUrl) {
96
84
  throw new Error('PPTX Worker URL is unavailable. Run file-viewer-copy-assets or provide workerUrl.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@file-viewer/pptx",
3
- "version": "3.3.1",
3
+ "version": "3.3.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Native PPTX renderer extracted from File Viewer",