@aixa-transformation/pptx-viewer 2.0.2 → 2.0.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,16 +1,16 @@
1
1
  # pptx-react-viewer
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/pptx-react-viewer.svg)](https://www.npmjs.com/package/pptx-react-viewer)
4
- [![license](https://img.shields.io/npm/l/@aixa-transformation/pptx-viewer.svg)](https://github.com/Aixa-Transformation/Aixa-PptxViewer/blob/main/LICENSE)
4
+ [![license](https://img.shields.io/npm/l/@aixa-transformation/pptx-viewer.svg)](https://github.com/Aixa-Transformation/Aixa-PptxViewer/blob/main/LICENSE)
5
5
  [![types](https://img.shields.io/npm/types/pptx-react-viewer.svg)](https://www.npmjs.com/package/pptx-react-viewer)
6
6
 
7
7
  > A drop-in **React** component that turns a `.pptx` file into a fully interactive PowerPoint: **view, edit, present, collaborate, and export**, entirely in the browser.
8
8
 
9
- ![Selecting, dragging, and resizing a slide element in the React demo](https://raw.githubusercontent.com/Aixa-Transformation/Aixa-PptxViewer/main/.github/assets/packages/react-demo.gif)
9
+ ![Selecting, dragging, and resizing a slide element in the React demo](https://raw.githubusercontent.com/Aixa-Transformation/Aixa-PptxViewer/main/.github/assets/packages/react-demo.gif)
10
10
 
11
11
  Slides render with real **HTML/CSS** (not `<canvas>`), so text stays crisp at any zoom, is selectable and screen-reader accessible, and every element is directly editable. The parsing/editing engine ([`pptx-viewer-core`](https://www.npmjs.com/package/pptx-viewer-core)) is **bundled in**, so you install just one package.
12
12
 
13
- <samp>**[📦 npm](https://www.npmjs.com/package/@aixa-transformation/pptx-viewer)** · **[Source](https://github.com/Aixa-Transformation/Aixa-PptxViewer)** · **[🧩 Core SDK](https://www.npmjs.com/package/pptx-viewer-core)**</samp>
13
+ <samp>**[📦 npm](https://www.npmjs.com/package/@aixa-transformation/pptx-viewer)** · **[Source](https://github.com/Aixa-Transformation/Aixa-PptxViewer)** · **[🧩 Core SDK](https://www.npmjs.com/package/pptx-viewer-core)**</samp>
14
14
 
15
15
  ---
16
16
 
@@ -218,9 +218,9 @@ Override specific values with the `theme` prop:
218
218
  />
219
219
  ```
220
220
 
221
- All `ViewerTheme.colors` keys are optional; override only what you need. Helpers `defaultThemeColors`, `defaultRadius`, `themeToCssVars`, `defaultCssVars`, `ViewerThemeProvider`, and `useViewerTheme` are exported for advanced use.
221
+ All `ViewerTheme.colors` keys are optional; override only what you need. Helpers `defaultThemeColors`, `defaultRadius`, `themeToCssVars`, `defaultCssVars`, `ViewerThemeProvider`, and `useViewerTheme` are exported for advanced use.
222
222
 
223
- Two ready-made presets ship with the package: `vermilionLightTheme` (warm paper canvas) and `vermilionDarkTheme` (dimmed presenter room):
223
+ Two ready-made presets ship with the package: `vermilionLightTheme` (warm paper canvas) and `vermilionDarkTheme` (dimmed presenter room):
224
224
 
225
225
  ```tsx
226
226
  import { PowerPointViewer, vermilionLightTheme } from 'pptx-react-viewer';
@@ -232,17 +232,17 @@ The underlying palettes (`vermilionLightColors`, `vermilionDarkColors`) and radi
232
232
 
233
233
  ## Localization (i18n)
234
234
 
235
- UI labels go through [i18next](https://www.i18next.com/) / [react-i18next](https://react.i18next.com/) with dotted keys such as `pptx.statusBar.allSaved`. Initialise an i18next instance and wrap your app in `I18nextProvider` (the demo's `demo/i18n.ts` shows a minimal config, including a `parseMissingKeyHandler` that derives Title Case labels for any key you don't explicitly translate). `@aixa-transformation/pptx-viewer/i18n` exports `translationsEn` (the English dictionary), `keyToLabel` (the fallback), and a `TranslationKey` type you can use to type-check a new locale dictionary (`Record<TranslationKey, string>`) at compile time. Add a new language by supplying a resource bundle under its language code.
235
+ UI labels go through [i18next](https://www.i18next.com/) / [react-i18next](https://react.i18next.com/) with dotted keys such as `pptx.statusBar.allSaved`. Initialise an i18next instance and wrap your app in `I18nextProvider` (the demo's `demo/i18n.ts` shows a minimal config, including a `parseMissingKeyHandler` that derives Title Case labels for any key you don't explicitly translate). `@aixa-transformation/pptx-viewer/i18n` exports `translationsEn` (the English dictionary), `keyToLabel` (the fallback), and a `TranslationKey` type you can use to type-check a new locale dictionary (`Record<TranslationKey, string>`) at compile time. Add a new language by supplying a resource bundle under its language code.
236
236
 
237
237
  ## How it's built
238
238
 
239
- You only need the `<PowerPointViewer>` component; everything else is internal. Behind it, the logic lives in many small, focused React hooks, and the components themselves just draw what those hooks produce. Slides are rendered as ordinary HTML and CSS (charts as inline SVG, tables as real `<table>` elements), which is why text stays sharp, selectable, and accessible.
239
+ You only need the `<PowerPointViewer>` component; everything else is internal. Behind it, the logic lives in many small, focused React hooks, and the components themselves just draw what those hooks produce. Slides are rendered as ordinary HTML and CSS (charts as inline SVG, tables as real `<table>` elements), which is why text stays sharp, selectable, and accessible.
240
240
 
241
- A small curated set of those hooks is exported from `@aixa-transformation/pptx-viewer/viewer` with a stable API; the complete set (67+) is also importable from `@aixa-transformation/pptx-viewer/internals` for advanced integrations. The `internals` subpath is **not covered by semver**: prefer the stable root exports.
241
+ A small curated set of those hooks is exported from `@aixa-transformation/pptx-viewer/viewer` with a stable API; the complete set (67+) is also importable from `@aixa-transformation/pptx-viewer/internals` for advanced integrations. The `internals` subpath is **not covered by semver**: prefer the stable root exports.
242
242
 
243
243
  ## Limitations
244
244
 
245
- CSS-based rendering trades a few visual effects for crisp text, accessibility, and DOM interactivity: `backdrop-filter` becomes semi-transparent backgrounds and path gradients approximate as elliptical radials, while `mix-blend-mode` and CSS 3D transforms render natively on screen but flatten in raster export. Text uses fonts available in the browser (embedded fonts are injected when present). Media playback depends on browser codec support. SmartArt is decomposed into editable shapes with a live reflow engine for structural edits, and charts edit via the inspector data grid rather than the chart surface. 3D models need the optional Three.js peer.
245
+ CSS-based rendering trades a few visual effects for crisp text, accessibility, and DOM interactivity: `backdrop-filter` becomes semi-transparent backgrounds and path gradients approximate as elliptical radials, while `mix-blend-mode` and CSS 3D transforms render natively on screen but flatten in raster export. Text uses fonts available in the browser (embedded fonts are injected when present). Media playback depends on browser codec support. SmartArt is decomposed into editable shapes with a live reflow engine for structural edits, and charts edit via the inspector data grid rather than the chart surface. 3D models need the optional Three.js peer.
246
246
 
247
247
  ## License
248
248
 
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunk2TOLRBFU_js = require('./chunk-2TOLRBFU.js');
4
- require('./chunk-AD2CLKY6.js');
3
+ var chunkIVCWQLQK_js = require('./chunk-IVCWQLQK.js');
4
+ require('./chunk-KAP5TS7O.js');
5
5
  require('./chunk-QGM4M3NI.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -15,7 +15,7 @@ function Model3DScene({ modelUrl, interactive, width, height }) {
15
15
  return;
16
16
  }
17
17
  let disposed = false;
18
- void chunk2TOLRBFU_js.mountModel3D(container, modelUrl, { width, height, interactive }).then((handle) => {
18
+ void chunkIVCWQLQK_js.mountModel3D(container, modelUrl, { width, height, interactive }).then((handle) => {
19
19
  if (disposed) {
20
20
  handle.dispose();
21
21
  } else {
@@ -1,5 +1,5 @@
1
- import { mountModel3D } from './chunk-XAVVR6OX.mjs';
2
- import './chunk-KVM4DBEU.mjs';
1
+ import { mountModel3D } from './chunk-4ZF7B5WU.mjs';
2
+ import './chunk-C36MFNDN.mjs';
3
3
  import './chunk-6DZX6EAA.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsx } from 'react/jsx-runtime';
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunk2TOLRBFU_js = require('./chunk-2TOLRBFU.js');
4
- require('./chunk-AD2CLKY6.js');
3
+ var chunkIVCWQLQK_js = require('./chunk-IVCWQLQK.js');
4
+ require('./chunk-KAP5TS7O.js');
5
5
  require('./chunk-QGM4M3NI.js');
6
6
  var react = require('react');
7
7
  var jsxRuntime = require('react/jsx-runtime');
@@ -26,7 +26,7 @@ function SurfaceChart3DScene({
26
26
  return;
27
27
  }
28
28
  let disposed = false;
29
- void chunk2TOLRBFU_js.mountSurfaceChart3D(container, {
29
+ void chunkIVCWQLQK_js.mountSurfaceChart3D(container, {
30
30
  cols,
31
31
  rows,
32
32
  heightMap,
@@ -1,5 +1,5 @@
1
- import { mountSurfaceChart3D } from './chunk-XAVVR6OX.mjs';
2
- import './chunk-KVM4DBEU.mjs';
1
+ import { mountSurfaceChart3D } from './chunk-4ZF7B5WU.mjs';
2
+ import './chunk-C36MFNDN.mjs';
3
3
  import './chunk-6DZX6EAA.mjs';
4
4
  import { useRef, useEffect } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -1,4 +1,4 @@
1
- import { THEME_PRESETS, MIN_ELEMENT_SIZE, guideEmuToPx, hasShapeProperties, THEME_COLOR_SCHEME_KEYS, hasTextProperties, createChartElement, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hslToRgb, PRESET_COLOR_MAP, isImageLikeElement, stripXmlOrderSuffix, orderedXmlKey, createBuiltinVariables, resolveCoordinate, applyDrawingColorTransforms } from './chunk-KVM4DBEU.mjs';
1
+ import { THEME_PRESETS, MIN_ELEMENT_SIZE, guideEmuToPx, hasShapeProperties, THEME_COLOR_SCHEME_KEYS, hasTextProperties, createChartElement, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hslToRgb, PRESET_COLOR_MAP, isImageLikeElement, stripXmlOrderSuffix, orderedXmlKey, createBuiltinVariables, resolveCoordinate, applyDrawingColorTransforms } from './chunk-C36MFNDN.mjs';
2
2
  import DOMPurify from 'dompurify';
3
3
 
4
4
  var defaultThemeColors = {
@@ -24440,6 +24440,12 @@ var BACKSTAGE_TEMPLATES = [
24440
24440
  name: "Future Forward",
24441
24441
  description: "Clean technology storytelling",
24442
24442
  preview: "repeating-radial-gradient(ellipse at bottom, #111 0 3px, #fff 4px 13px)"
24443
+ },
24444
+ {
24445
+ id: "oasis",
24446
+ name: "Oasis",
24447
+ description: "56 editorial layouts with marble imagery",
24448
+ preview: "linear-gradient(90deg, #111111 0 48%, transparent 48%), radial-gradient(ellipse at 78% 38%, #e8c7b4 0 18%, #91b9b4 42%, #c8a38f 67%, #eee6df 100%)"
24443
24449
  }
24444
24450
  ];
24445
24451
  var TEMPLATE_BACKGROUNDS = {
@@ -42208,6 +42208,11 @@ function getSectionSlideRange(zoomElement, slides) {
42208
42208
  }
42209
42209
  var FONT_SUBSTITUTION_MAP = {
42210
42210
  // Microsoft Office default fonts
42211
+ // Aptos replaced Calibri as Office's default and is intentionally close in
42212
+ // metrics. Calibri/Calibri Light are better fidelity fallbacks than Segoe UI
42213
+ // (which is wider and makes authored one-line titles wrap).
42214
+ Aptos: ["Calibri", "Arial", "sans-serif"],
42215
+ "Aptos Display": ["Calibri Light", "Calibri", "Arial", "sans-serif"],
42211
42216
  Calibri: ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42212
42217
  "Calibri Light": ["Carlito", "Liberation Sans", "Arial", "sans-serif"],
42213
42218
  Cambria: ["Caladea", "Liberation Serif", "Times New Roman", "serif"],
@@ -55218,6 +55223,28 @@ var PptxHandlerRuntime9 = class _PptxHandlerRuntime extends PptxHandlerRuntime8
55218
55223
  if (!this.layoutXmlMap.has(layoutPath)) {
55219
55224
  this.layoutXmlMap.set(layoutPath, data);
55220
55225
  }
55226
+ if (!this.slideRelsMap.has(layoutPath)) {
55227
+ const layoutRelsPath = `${layoutPath.replace(
55228
+ "slideLayouts/",
55229
+ "slideLayouts/_rels/"
55230
+ )}.rels`;
55231
+ const layoutRelsXml2 = await this.zip.file(layoutRelsPath)?.async("string");
55232
+ if (layoutRelsXml2) {
55233
+ const layoutRelsData = this.parser.parse(layoutRelsXml2);
55234
+ const relationships = this.ensureArray(
55235
+ xmlChild(layoutRelsData, "Relationships")?.["Relationship"]
55236
+ );
55237
+ const relationshipMap = /* @__PURE__ */ new Map();
55238
+ for (const relationship of relationships) {
55239
+ const id = String(relationship["@_Id"] || "").trim();
55240
+ const target = String(relationship["@_Target"] || "").trim();
55241
+ if (id && target) {
55242
+ relationshipMap.set(id, target);
55243
+ }
55244
+ }
55245
+ this.slideRelsMap.set(layoutPath, relationshipMap);
55246
+ }
55247
+ }
55221
55248
  const layout = { path: layoutPath };
55222
55249
  const cSldName = (xmlAttr(xmlChild(sldLayout, "p:cSld"), "name") ?? "").trim();
55223
55250
  if (cSldName) {
@@ -58124,6 +58151,16 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
58124
58151
  }
58125
58152
  return type;
58126
58153
  }
58154
+ placeholderRole(phInfo) {
58155
+ const type = phInfo.type || "body";
58156
+ if (type === "title" || type === "ctrtitle") {
58157
+ return "title";
58158
+ }
58159
+ if (type === "body" || type === "obj" || type === "subtitle") {
58160
+ return "content";
58161
+ }
58162
+ return type;
58163
+ }
58127
58164
  // ── Core layout switching logic ─────────────────────────────────────
58128
58165
  /**
58129
58166
  * Re-map slide elements to a new layout's placeholders.
@@ -58162,6 +58199,15 @@ var PptxHandlerRuntime21 = class extends PptxHandlerRuntime20 {
58162
58199
  }
58163
58200
  }
58164
58201
  }
58202
+ if (!resolvedLayoutPh) {
58203
+ const sourceRole = this.placeholderRole(phInfo);
58204
+ for (const [, lp] of layoutPhMap.entries()) {
58205
+ if (!lp.matched && this.placeholderRole(lp.phInfo) === sourceRole) {
58206
+ resolvedLayoutPh = lp;
58207
+ break;
58208
+ }
58209
+ }
58210
+ }
58165
58211
  if (resolvedLayoutPh) {
58166
58212
  resolvedLayoutPh.matched = true;
58167
58213
  const updatedElement = { ...element };
@@ -67551,12 +67597,20 @@ var PptxHandlerRuntime56 = class extends PptxHandlerRuntime55 {
67551
67597
  }
67552
67598
  const phKey = this.buildPlaceholderDefaultsKey(phInfo);
67553
67599
  const layoutMap = this.layoutPlaceholderDefaultsCache.get(layoutPath);
67554
- const layoutDefaults = layoutMap?.get(phKey);
67600
+ const lookupDefaults = (map) => {
67601
+ const exact = map?.get(phKey);
67602
+ if (exact || phInfo.type !== void 0 || phInfo.idx === void 0) {
67603
+ return exact;
67604
+ }
67605
+ return map?.get(`obj_${phInfo.idx}`) ?? map?.get(`body_${phInfo.idx}`);
67606
+ };
67607
+ const layoutDefaults = lookupDefaults(layoutMap);
67555
67608
  const masterPath = this.resolveMasterPathForLayout(layoutPath);
67556
67609
  const masterMap = masterPath ? this.masterPlaceholderDefaultsCache.get(masterPath) : void 0;
67557
- const masterDefaults = masterMap?.get(phKey);
67610
+ const masterDefaults = lookupDefaults(masterMap);
67558
67611
  const normalizedType = this.buildPlaceholderDefaultsKey(phInfo).split("_")[0];
67559
- const masterTextStyleType = phInfo.type === "title" || phInfo.type === "ctrtitle" ? "title" : phInfo.type === "body" || phInfo.type === "obj" || phInfo.type === "subtitle" ? "body" : "other";
67612
+ const effectivePlaceholderType = phInfo.type ?? "obj";
67613
+ const masterTextStyleType = effectivePlaceholderType === "title" || effectivePlaceholderType === "ctrtitle" ? "title" : effectivePlaceholderType === "body" || effectivePlaceholderType === "obj" || effectivePlaceholderType === "subtitle" ? "body" : "other";
67560
67614
  const masterTextStyles = masterPath ? this.masterTxStylesCache.get(masterPath) : void 0;
67561
67615
  const masterTextLevels = masterTextStyleType === "title" ? masterTextStyles?.titleStyle : masterTextStyleType === "body" ? masterTextStyles?.bodyStyle : masterTextStyles?.otherStyle;
67562
67616
  const resolvedMasterDefaults = masterTextLevels ? {
@@ -68240,6 +68294,17 @@ var PptxHandlerRuntime58 = class _PptxHandlerRuntime24 extends PptxHandlerRuntim
68240
68294
  return void 0;
68241
68295
  }
68242
68296
  };
68297
+ function parseOoxmlPercentage(value) {
68298
+ const raw = String(value ?? "").trim();
68299
+ if (!raw) {
68300
+ return void 0;
68301
+ }
68302
+ const numeric = Number.parseFloat(raw.endsWith("%") ? raw.slice(0, -1) : raw);
68303
+ if (!Number.isFinite(numeric)) {
68304
+ return void 0;
68305
+ }
68306
+ return raw.endsWith("%") ? numeric / 100 : numeric / 1e5;
68307
+ }
68243
68308
  var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
68244
68309
  /**
68245
68310
  * Apply {@link PlaceholderDefaults} body-level properties to a
@@ -68286,12 +68351,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
68286
68351
  if (Number.isFinite(spacingPointsRaw)) {
68287
68352
  return this.pointsToPixels(spacingPointsRaw / 100);
68288
68353
  }
68289
- const spacingPercentRaw = Number.parseInt(
68290
- String(spacingNode["a:spcPct"]?.["@_val"] || ""),
68291
- 10
68354
+ const spacingPercent = parseOoxmlPercentage(
68355
+ spacingNode["a:spcPct"]?.["@_val"]
68292
68356
  );
68293
- if (Number.isFinite(spacingPercentRaw) && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
68294
- return spacingPercentRaw / 1e5 * basisFontSizePx;
68357
+ if (spacingPercent !== void 0 && typeof basisFontSizePx === "number" && basisFontSizePx > 0) {
68358
+ return spacingPercent * basisFontSizePx;
68295
68359
  }
68296
68360
  return void 0;
68297
68361
  }
@@ -68299,12 +68363,11 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
68299
68363
  if (!lineSpacingNode) {
68300
68364
  return void 0;
68301
68365
  }
68302
- const spacingPercentRaw = Number.parseInt(
68303
- String(lineSpacingNode["a:spcPct"]?.["@_val"] || ""),
68304
- 10
68366
+ const spacingPercent = parseOoxmlPercentage(
68367
+ lineSpacingNode["a:spcPct"]?.["@_val"]
68305
68368
  );
68306
- if (Number.isFinite(spacingPercentRaw)) {
68307
- return Math.max(0.1, Math.min(5, spacingPercentRaw / 1e5));
68369
+ if (spacingPercent !== void 0) {
68370
+ return Math.max(0.1, Math.min(5, spacingPercent));
68308
68371
  }
68309
68372
  return void 0;
68310
68373
  }
@@ -68342,8 +68405,13 @@ var PptxHandlerRuntime59 = class extends PptxHandlerRuntime58 {
68342
68405
  if (textStyle.italic === void 0 && levelStyle.italic !== void 0) {
68343
68406
  textStyle.italic = levelStyle.italic;
68344
68407
  }
68345
- if (textStyle.color === void 0 && levelStyle.color !== void 0) {
68346
- textStyle.color = levelStyle.color;
68408
+ if (textStyle.color === void 0) {
68409
+ const currentSlideColor = levelStyle.colorXml ? this.parseColor(levelStyle.colorXml) : void 0;
68410
+ if (currentSlideColor !== void 0) {
68411
+ textStyle.color = currentSlideColor;
68412
+ } else if (levelStyle.color !== void 0) {
68413
+ textStyle.color = levelStyle.color;
68414
+ }
68347
68415
  }
68348
68416
  if (textStyle.paragraphMarginLeft === void 0 && levelStyle.marginLeft !== void 0) {
68349
68417
  textStyle.paragraphMarginLeft = levelStyle.marginLeft;
@@ -69157,7 +69225,30 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
69157
69225
  bulletText = `${paragraphBulletInfo.char} `;
69158
69226
  } else if (paragraphBulletInfo.autoNumType) {
69159
69227
  const startAt = paragraphBulletInfo.autoNumStartAt ?? 1;
69160
- bulletText = this.formatAutoNumber(paragraphBulletInfo.autoNumType, startAt + pIdx);
69228
+ const paragraphs = this.ensureArray(
69229
+ ctx.txBody?.["a:p"]
69230
+ );
69231
+ let sequenceOffset = 0;
69232
+ for (let priorIndex = pIdx - 1; priorIndex >= 0; priorIndex--) {
69233
+ const priorBullet = this.resolveParagraphBulletInfo(
69234
+ paragraphs[priorIndex],
69235
+ priorIndex,
69236
+ ctx.txBody,
69237
+ ctx.inheritedTxBody,
69238
+ isBodyPlaceholder,
69239
+ ctx.slidePath,
69240
+ ctx.effectiveLevelStyles
69241
+ );
69242
+ if (priorBullet?.none || priorBullet?.autoNumType !== paragraphBulletInfo.autoNumType) {
69243
+ break;
69244
+ }
69245
+ sequenceOffset++;
69246
+ }
69247
+ bulletText = this.formatAutoNumber(
69248
+ paragraphBulletInfo.autoNumType,
69249
+ startAt + sequenceOffset
69250
+ );
69251
+ paragraphBulletInfo.paragraphIndex = sequenceOffset;
69161
69252
  } else if (paragraphBulletInfo.imageRelId) {
69162
69253
  bulletText = "\u{1F4CE} ";
69163
69254
  } else {
@@ -69285,25 +69376,31 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
69285
69376
  "mc:AlternateContent",
69286
69377
  "a:br"
69287
69378
  ]);
69379
+ const paragraphRuns = this.ensureArray(p["a:r"]);
69380
+ const paragraphBreaks = this.ensureArray(p["a:br"]);
69381
+ const hasCollapsedRunBreakOrder = paragraphRuns.length > 1 && paragraphBreaks.length > 0;
69288
69382
  for (const key of Object.keys(p)) {
69289
69383
  if (!contentTagSet.has(key)) {
69290
69384
  continue;
69291
69385
  }
69292
69386
  const items = this.ensureArray(p[key]);
69293
- const rawBreaks = p["a:br"];
69294
- const breakCount = Array.isArray(rawBreaks) ? rawBreaks.length : rawBreaks === void 0 ? 0 : 1;
69295
- const insertCollapsedBreaks = key === "a:r" && items.length > 1 && breakCount > 0;
69387
+ const breakCount = paragraphBreaks.length;
69388
+ const insertCollapsedBreaks = key === "a:r" && hasCollapsedRunBreakOrder;
69296
69389
  for (const [itemIndex, item] of items.entries()) {
69297
69390
  switch (key) {
69298
69391
  case "a:r": {
69299
69392
  processRun(item);
69300
- if (insertCollapsedBreaks && itemIndex < Math.min(items.length - 1, breakCount)) {
69301
- parts.push("\n");
69302
- segments.push({
69303
- text: "\n",
69304
- style: { ...mergedDefaultRunStyle },
69305
- isLineBreak: true
69306
- });
69393
+ if (insertCollapsedBreaks && itemIndex < items.length - 1) {
69394
+ const gapCount = items.length - 1;
69395
+ const breaksHere = Math.floor(breakCount / gapCount) + (itemIndex < breakCount % gapCount ? 1 : 0);
69396
+ for (let breakIndex = 0; breakIndex < breaksHere; breakIndex++) {
69397
+ parts.push("\n");
69398
+ segments.push({
69399
+ text: "\n",
69400
+ style: { ...mergedDefaultRunStyle },
69401
+ isLineBreak: true
69402
+ });
69403
+ }
69307
69404
  }
69308
69405
  break;
69309
69406
  }
@@ -69324,7 +69421,7 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
69324
69421
  processAlternateContent(item);
69325
69422
  break;
69326
69423
  case "a:br": {
69327
- if (insertCollapsedBreaks) {
69424
+ if (hasCollapsedRunBreakOrder) {
69328
69425
  break;
69329
69426
  }
69330
69427
  const brNode = item ?? {};
@@ -69348,6 +69445,14 @@ var PptxHandlerRuntime63 = class extends PptxHandlerRuntime62 {
69348
69445
  }
69349
69446
  }
69350
69447
  }
69448
+ const markerSegment = segments.find((segment) => segment.bulletInfo);
69449
+ const firstVisibleRun = segments.find(
69450
+ (segment) => !segment.bulletInfo && segment.text !== "\n" && segment.text.length > 0
69451
+ );
69452
+ if (markerSegment && firstVisibleRun) {
69453
+ markerSegment.style = { ...firstVisibleRun.style };
69454
+ seedStyle = { ...firstVisibleRun.style };
69455
+ }
69351
69456
  if (pIdx < paraCount - 1) {
69352
69457
  parts.push("\n");
69353
69458
  segments.push({ text: "\n", style: { ...mergedDefaultRunStyle } });
@@ -71647,10 +71752,14 @@ var PptxHandlerRuntime72 = class _PptxHandlerRuntime31 extends PptxHandlerRuntim
71647
71752
  if (defRPr["@_i"] !== void 0) {
71648
71753
  style.italic = defRPr["@_i"] === "1";
71649
71754
  }
71650
- const color2 = this.parseColor(defRPr["a:solidFill"]);
71755
+ const colorXml2 = defRPr["a:solidFill"];
71756
+ const color2 = this.parseColor(colorXml2);
71651
71757
  if (color2) {
71652
71758
  style.color = color2;
71653
71759
  }
71760
+ if (colorXml2) {
71761
+ style.colorXml = colorXml2;
71762
+ }
71654
71763
  const latin = defRPr["a:latin"];
71655
71764
  if (latin?.["@_typeface"]) {
71656
71765
  const typeface = String(latin["@_typeface"]);
@@ -74105,6 +74214,11 @@ var PptxHandlerRuntime83 = class extends PptxHandlerRuntime82 {
74105
74214
  };
74106
74215
  function extractDrawingShapeFill(spPr, deps) {
74107
74216
  const result = {};
74217
+ if (Object.keys(spPr).some(
74218
+ (key) => !key.startsWith("@_") && (key.split(":").at(-1) ?? key) === "noFill"
74219
+ )) {
74220
+ result.fillNone = true;
74221
+ }
74108
74222
  const solidFill2 = deps.getChild(spPr, "solidFill");
74109
74223
  if (solidFill2) {
74110
74224
  result.fillColor = deps.parseColor(solidFill2) ?? void 0;