pptx-angular-viewer 1.31.4 → 1.31.5

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.
@@ -2,7 +2,7 @@ import { NgStyle, NgTemplateOutlet, NgClass } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, input, output, computed, ChangeDetectionStrategy, Component, signal, Injectable, inject, Injector, DestroyRef, effect, viewChild, ElementRef, HostListener, afterNextRender, forwardRef, untracked } from '@angular/core';
4
4
  import { TranslatePipe, TranslateService, translate } from '@ngx-translate/core';
5
- import { guideEmuToPx, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hasShapeProperties, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, isImageLikeElement, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$2, THEME_COLOR_SCHEME_KEYS, getLinkedTextBoxSegments, svgPathToPolygons, deobfuscateFont, detectFontFormat, getSubstituteFontFamily, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, formatCommentTimestamp as formatCommentTimestamp$1, PptxHandler, EncryptedFileError, parseSignatureXml, cloneSlide as cloneSlide$1, cloneTemplateElementsBySlideId as cloneTemplateElementsBySlideId$1, cloneElement as cloneElement$1, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, parseDataUrlToBytes, isZoomElement, SvgExporter, applyThemeToData, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, chartDataChangeType, getOleObjectTypeLabel, addSmartArtNodeAsChild, removeSmartArtNode, promoteSmartArtNode, demoteSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, THEME_PRESETS, getAnimationPresetInfo } from 'pptx-viewer-core';
5
+ import { guideEmuToPx, getShapeClipPath, getAdjustmentAwareShapeClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, hasShapeProperties, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, isImageLikeElement, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$2, THEME_COLOR_SCHEME_KEYS, getLinkedTextBoxSegments, createBuiltinVariables, resolveCoordinate, svgPathToPolygons, deobfuscateFont, detectFontFormat, getSubstituteFontFamily, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, formatCommentTimestamp as formatCommentTimestamp$1, PptxHandler, EncryptedFileError, parseSignatureXml, cloneSlide as cloneSlide$1, cloneTemplateElementsBySlideId as cloneTemplateElementsBySlideId$1, cloneElement as cloneElement$1, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, parseDataUrlToBytes, isZoomElement, SvgExporter, applyThemeToData, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointExplosion, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, chartDataChangeType, getOleObjectTypeLabel, addSmartArtNodeAsChild, removeSmartArtNode, promoteSmartArtNode, demoteSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, THEME_PRESETS, getAnimationPresetInfo } from 'pptx-viewer-core';
6
6
  export { SWITCHABLE_LAYOUT_TYPES, addSmartArtNode, addSmartArtNodeAsChild, chartDataAddCategory, chartDataAddSeries, chartDataChangeType, chartDataRemoveCategory, chartDataRemoveSeries, chartDataUpdatePoint, demoteSmartArtNode, promoteSmartArtNode, removeSmartArtNode, reorderSmartArtNode, switchSmartArtLayout, updateSmartArtNodeText } from 'pptx-viewer-core';
7
7
  import DOMPurify from 'dompurify';
8
8
  import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideChevronRight, LucidePenTool, LucideHighlighter, LucideEraser, LucideMousePointer2, LucideChevronLeft, LucidePlay, LucideSparkles, LucidePanelRight, LucideMoveRight, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideDownload, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucidePrinter, LucideSave, LucideSettings, LucideShare2, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucidePlus, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucidePaintbrush, LucideRotateCcw, LucideScissors, LucideImage, LucideVideo, LucideDatabase, LucideLayers, LucidePanelLeft, LucideMessageSquare, LucideEllipsis, LucideEye, LucideEyeOff, LucideSettings2, LucideStickyNote, LucideMonitor, LucideColumns2, LucidePresentation, LucideCheck, LucideUndo, LucideRedo, LucideSearch } from '@lucide/angular';
@@ -770,6 +770,36 @@ function getGradientTileFlipCss(mode) {
770
770
  return undefined;
771
771
  }
772
772
  }
773
+ /**
774
+ * Builds the `background-size` / `background-position` / `background-repeat`
775
+ * that confine a gradient to the rectangle described by `a:gradFill/a:tileRect`.
776
+ *
777
+ * `tileRect` LTRB values are 0..1 insets from each edge, so the tile covers
778
+ * `(1 - l - r)` x `(1 - t - b)` of the shape, offset by `l`/`t`. Returns
779
+ * `undefined` when the rect is missing, degenerate, or effectively full-bleed
780
+ * (no meaningful inset), so callers fall through to the plain gradient.
781
+ */
782
+ function getGradientTileRectCss(tileRect) {
783
+ if (!tileRect) {
784
+ return undefined;
785
+ }
786
+ const { l, t, r, b } = tileRect;
787
+ const sizeW = 1 - l - r;
788
+ const sizeH = 1 - t - b;
789
+ if (sizeW <= 0 || sizeH <= 0) {
790
+ return undefined;
791
+ }
792
+ if (Math.abs(sizeW - 1) < 0.001 && Math.abs(sizeH - 1) < 0.001) {
793
+ return undefined;
794
+ }
795
+ const posX = 1 - sizeW > 0.001 ? (l / (1 - sizeW)) * 100 : 0;
796
+ const posY = 1 - sizeH > 0.001 ? (t / (1 - sizeH)) * 100 : 0;
797
+ return {
798
+ backgroundSize: `${Math.round(sizeW * 100)}% ${Math.round(sizeH * 100)}%`,
799
+ backgroundPosition: `${Math.round(posX)}% ${Math.round(posY)}%`,
800
+ backgroundRepeat: 'no-repeat',
801
+ };
802
+ }
773
803
  /**
774
804
  * Creates a reflected (mirrored) copy of gradient stops for tile-flip
775
805
  * rendering. The original stops run 0->100; the result packs one full
@@ -796,6 +826,36 @@ function buildReflectedGradientStops(stops) {
796
826
  }));
797
827
  return [...forward, ...reversed];
798
828
  }
829
+ /** Normalise a degree value into the [0, 360) range. */
830
+ function normalizeDegrees(deg) {
831
+ return ((deg % 360) + 360) % 360;
832
+ }
833
+ /**
834
+ * Apply `a:lin/@scaled` (aspect-ratio) and `a:gradFill/@rotWithShape`
835
+ * corrections to a linear-gradient angle. A no-op when no geometry context is
836
+ * supplied or neither attribute is in force, so callers that pass only a style
837
+ * keep the raw authored angle.
838
+ */
839
+ function adjustLinearGradientAngle(angle, gradient, context) {
840
+ if (!context) {
841
+ return angle;
842
+ }
843
+ let result = angle;
844
+ const { width, height, rotation } = context;
845
+ if (gradient.fillGradientScaled !== false &&
846
+ typeof width === 'number' &&
847
+ typeof height === 'number' &&
848
+ width > 0 &&
849
+ height > 0 &&
850
+ width !== height) {
851
+ const rad = (result * Math.PI) / 180;
852
+ result = normalizeDegrees((Math.atan2(height * Math.sin(rad), width * Math.cos(rad)) * 180) / Math.PI);
853
+ }
854
+ if (gradient.fillGradientRotWithShape === false && typeof rotation === 'number') {
855
+ result = normalizeDegrees(result - rotation);
856
+ }
857
+ return result;
858
+ }
799
859
  /**
800
860
  * Converts a structured OOXML gradient on a `ShapeStyle` to a CSS
801
861
  * `linear-gradient(...)` / `radial-gradient(...)` string.
@@ -810,9 +870,11 @@ function buildReflectedGradientStops(stops) {
810
870
  * a radial), matching the React port.
811
871
  *
812
872
  * @param gradient - The shape style carrying gradient configuration.
873
+ * @param context - Optional element geometry enabling `@scaled` /
874
+ * `@rotWithShape` angle corrections (linear only).
813
875
  * @returns A CSS gradient string, or `undefined`.
814
876
  */
815
- function buildGradientCss(gradient) {
877
+ function buildGradientCss(gradient, context) {
816
878
  if (!gradient || gradient.fillMode !== 'gradient') {
817
879
  return undefined;
818
880
  }
@@ -836,12 +898,13 @@ function buildGradientCss(gradient) {
836
898
  const normalizedAngle = typeof gradient.fillGradientAngle === 'number' && Number.isFinite(gradient.fillGradientAngle)
837
899
  ? gradient.fillGradientAngle
838
900
  : 90;
901
+ const effectiveAngle = adjustLinearGradientAngle(normalizedAngle, gradient, context);
839
902
  // Tile-flip: reflect the stops so a single tile contains one mirrored
840
903
  // forward-backward cycle. The repeating/halved tiling is applied by the
841
904
  // caller via getGradientTileFlipCss (wired into getComputedFillStyle).
842
905
  const flip = gradient.fillGradientFlip;
843
906
  const linearStops = flip && flip !== 'none' ? buildReflectedGradientStops(stops) : stops;
844
- return `linear-gradient(${Math.round(normalizedAngle)}deg, ${linearStops
907
+ return `linear-gradient(${Math.round(effectiveAngle)}deg, ${linearStops
845
908
  .map(toCssGradientStop)
846
909
  .join(', ')})`;
847
910
  }
@@ -1251,9 +1314,16 @@ const OOXML_PATTERN_PRESETS = [
1251
1314
  * empty-ish object when no fill applies (so callers can spread the result
1252
1315
  * safely).
1253
1316
  *
1254
- * @param element - The PPTX element to resolve a fill for.
1317
+ * A child of a group whose fill is `a:grpFill` (`fillMode === "group"`)
1318
+ * inherits the group's resolved fill: pass the parent group's `ShapeStyle`
1319
+ * (`GroupPptxElement.groupFill`) as {@link parentGroupFill} and it is resolved
1320
+ * in the child's own box.
1321
+ *
1322
+ * @param element - The PPTX element to resolve a fill for.
1323
+ * @param parentGroupFill - The enclosing group's fill style, used only when the
1324
+ * element's own fill is `a:grpFill`.
1255
1325
  */
1256
- function getComputedFillStyle(element) {
1326
+ function getComputedFillStyle(element, parentGroupFill) {
1257
1327
  if (!hasShapeProperties(element)) {
1258
1328
  return undefined;
1259
1329
  }
@@ -1261,6 +1331,20 @@ function getComputedFillStyle(element) {
1261
1331
  if (!ss) {
1262
1332
  return {};
1263
1333
  }
1334
+ // grpFill inheritance: paint the parent group's resolved fill in this
1335
+ // child's box. Without a parent fill there is nothing to inherit.
1336
+ if (ss.fillMode === 'group') {
1337
+ return parentGroupFill ? resolveComputedFill(parentGroupFill, element) : {};
1338
+ }
1339
+ return resolveComputedFill(ss, element);
1340
+ }
1341
+ /**
1342
+ * Resolves a concrete {@link ComputedFillStyle} from a {@link ShapeStyle} in the
1343
+ * context of `element` (id namespaces pattern filters; geometry drives gradient
1344
+ * `@scaled`/`@rotWithShape` corrections). Split out so grpFill children can
1345
+ * resolve the parent group's style through the identical pipeline.
1346
+ */
1347
+ function resolveComputedFill(ss, element) {
1264
1348
  // 1. Image fill — highest priority.
1265
1349
  const imageFillUrl = ss.fillMode === 'image' && ss.fillImageUrl ? ss.fillImageUrl : undefined;
1266
1350
  if (imageFillUrl) {
@@ -1273,7 +1357,12 @@ function getComputedFillStyle(element) {
1273
1357
  };
1274
1358
  }
1275
1359
  // 2. Gradient (structured, with prebuilt-string fallback).
1276
- const gradient = buildGradientCss(ss) ?? (ss.fillMode === 'gradient' ? ss.fillGradient : undefined);
1360
+ const geometry = {
1361
+ rotation: element.rotation,
1362
+ width: element.width,
1363
+ height: element.height,
1364
+ };
1365
+ const gradient = buildGradientCss(ss, geometry) ?? (ss.fillMode === 'gradient' ? ss.fillGradient : undefined);
1277
1366
  if (gradient) {
1278
1367
  // Tile-flip applies only to structured linear gradients: buildGradientCss
1279
1368
  // reflects the stops, and the matching halved/repeating background-size +
@@ -1290,6 +1379,16 @@ function getComputedFillStyle(element) {
1290
1379
  backgroundRepeat: tileFlip.backgroundRepeat,
1291
1380
  };
1292
1381
  }
1382
+ // tileRect confines the gradient to a sub-rectangle of the shape.
1383
+ const tileRect = ss.fillMode === 'gradient' ? getGradientTileRectCss(ss.fillGradientTileRect) : undefined;
1384
+ if (tileRect) {
1385
+ return {
1386
+ backgroundImage: gradient,
1387
+ backgroundSize: tileRect.backgroundSize,
1388
+ backgroundPosition: tileRect.backgroundPosition,
1389
+ backgroundRepeat: tileRect.backgroundRepeat,
1390
+ };
1391
+ }
1293
1392
  return { backgroundImage: gradient };
1294
1393
  }
1295
1394
  // 3. Pattern fill.
@@ -7008,6 +7107,38 @@ function buildCartesianAxes(chartData, layout, primaryRange, secondaryRange, cat
7008
7107
  function categoryTotals(series, catCount) {
7009
7108
  return Array.from({ length: catCount }, (_, ci) => series.reduce((sum, s) => sum + Math.abs(s.values[ci] ?? 0), 0));
7010
7109
  }
7110
+ /**
7111
+ * Blend a `#RRGGBB` colour halfway toward white. Returns the input unchanged
7112
+ * when it is not a parseable 6-digit hex (e.g. a named colour or gradient ref).
7113
+ */
7114
+ function blendToWhite(color) {
7115
+ const match = /^#?([0-9a-f]{6})$/iu.exec(color.trim());
7116
+ if (!match) {
7117
+ return color;
7118
+ }
7119
+ const value = Number.parseInt(match[1], 16);
7120
+ const mix = (channel) => Math.round(channel + (255 - channel) * 0.5);
7121
+ const r = mix((value >> 16) & 0xff);
7122
+ const g = mix((value >> 8) & 0xff);
7123
+ const b = mix(value & 0xff);
7124
+ return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, '0').toUpperCase()}`;
7125
+ }
7126
+ /**
7127
+ * Apply PowerPoint's `c:invertIfNegative` treatment to a bar fill: when the
7128
+ * point value is negative and invert-if-negative is set (a per-point `c:dPt`
7129
+ * override wins over the series-level flag), the bar is drawn in a lightened
7130
+ * fill. Convention: a 50% blend of the base fill toward white. PowerPoint has no
7131
+ * single canonical inverted colour; a lightened same-hue fill echoes its default
7132
+ * "hollow" appearance and is deterministic across bindings.
7133
+ */
7134
+ function invertNegativeFill(series, pointIndex, value, baseFill) {
7135
+ if (value >= 0) {
7136
+ return baseFill;
7137
+ }
7138
+ const point = series.dataPoints?.find((p) => p.idx === pointIndex);
7139
+ const invert = point?.invertIfNegative ?? series.invertIfNegative ?? false;
7140
+ return invert ? blendToWhite(baseFill) : baseFill;
7141
+ }
7011
7142
  /**
7012
7143
  * Bar primitives for clustered / stacked / percentStacked, honouring a secondary
7013
7144
  * value range for secondary-mapped series (clustered only). Returns rects + data
@@ -7019,29 +7150,45 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
7019
7150
  const series = chartData.series;
7020
7151
  const palette = chartData.colorPalette;
7021
7152
  const showLabels = chartData.style?.hasDataLabels;
7153
+ // Single-series bar/column with c:varyColors=1 gives every category a distinct
7154
+ // palette colour (a per-point c:dPt fill still wins). Multi-series charts keep
7155
+ // their per-series colours (varyColors has no cross-series meaning there).
7156
+ const varyColorsSingle = chartData.varyColors === true && series.length === 1;
7022
7157
  if (grouping === 'clustered') {
7023
7158
  const seriesCount = Math.max(series.length, 1);
7024
7159
  const barGroupWidth = layout.plotWidth / Math.max(catCount, 1);
7025
- const singleBarWidth = (barGroupWidth * 0.7) / seriesCount;
7026
- const groupOffset = (barGroupWidth - singleBarWidth * seriesCount) / 2;
7160
+ // Honour c:gapWidth (gap between clusters, % of a bar width) when parsed;
7161
+ // otherwise keep the legacy 0.7-of-group heuristic byte-for-byte.
7162
+ const singleBarWidth = chartData.barGapWidth !== undefined
7163
+ ? barGroupWidth / (seriesCount + Math.max(chartData.barGapWidth, 0) / 100)
7164
+ : (barGroupWidth * 0.7) / seriesCount;
7165
+ // Honour c:overlap (% overlap between adjacent series). overlap=0 reproduces
7166
+ // the original side-by-side layout exactly.
7167
+ const overlap = chartData.barOverlap ?? 0;
7168
+ const step = singleBarWidth * (1 - overlap / 100);
7169
+ const clusterWidth = singleBarWidth + step * (seriesCount - 1);
7170
+ const groupOffset = (barGroupWidth - clusterWidth) / 2;
7027
7171
  for (let displayIndex = 0; displayIndex < catCount; displayIndex++) {
7028
7172
  const sourceIndex = sourceIndices[displayIndex] ?? displayIndex;
7029
7173
  for (let si = 0; si < series.length; si++) {
7030
7174
  const val = series[si].values[sourceIndex] ?? 0;
7031
- const x = layout.plotLeft + barGroupWidth * displayIndex + groupOffset + singleBarWidth * si;
7175
+ const x = layout.plotLeft + barGroupWidth * displayIndex + groupOffset + step * si;
7032
7176
  const activeRange = secondaryIdx.has(si) && secondaryRange ? secondaryRange : primaryRange;
7033
7177
  const zeroY = valueToY(0, activeRange, layout.plotTop, layout.plotBottom);
7034
7178
  const valY = valueToY(val, activeRange, layout.plotTop, layout.plotBottom);
7035
7179
  const y = Math.min(zeroY, valY);
7036
7180
  const h = Math.max(Math.abs(zeroY - valY), 1);
7181
+ const baseFill = varyColorsSingle
7182
+ ? resolveVaryColorFill(series[si], sourceIndex, paletteColor(sourceIndex, palette))
7183
+ : (resolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??
7184
+ seriesColor(series[si], si, palette));
7037
7185
  primitives.push({
7038
7186
  kind: 'rect',
7039
7187
  x,
7040
7188
  y,
7041
7189
  w: singleBarWidth,
7042
7190
  h,
7043
- fill: resolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??
7044
- seriesColor(series[si], si, palette),
7191
+ fill: invertNegativeFill(series[si], sourceIndex, val, baseFill),
7045
7192
  rx: 1,
7046
7193
  part: { role: 'dataPoint', seriesIndex: si, pointIndex: sourceIndex },
7047
7194
  });
@@ -7076,6 +7223,8 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
7076
7223
  if (r.seriesIndex !== undefined && r.pointIndex !== undefined) {
7077
7224
  const sourcePointIndex = sourceIndices[r.pointIndex] ?? r.pointIndex;
7078
7225
  fill = resolveDataPointFill(series[r.seriesIndex], sourcePointIndex, r.fill) ?? r.fill;
7226
+ const value = series[r.seriesIndex].values[sourcePointIndex] ?? 0;
7227
+ fill = invertNegativeFill(series[r.seriesIndex], sourcePointIndex, value, fill);
7079
7228
  part = { role: 'dataPoint', seriesIndex: r.seriesIndex, pointIndex: sourcePointIndex };
7080
7229
  }
7081
7230
  primitives.push({ kind: 'rect', x: r.x, y: r.y, w: r.w, h: r.h, fill, rx: 1, part });
@@ -7110,14 +7259,15 @@ function buildBars(chartData, catCount, layout, primaryRange, secondaryRange, se
7110
7259
  const topY = valueToY(top, primaryRange, layout.plotTop, layout.plotBottom);
7111
7260
  const y = Math.min(baseY, topY);
7112
7261
  const h = Math.max(Math.abs(baseY - topY), 0.5);
7262
+ const pctBaseFill = resolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??
7263
+ seriesColor(series[si], si, palette);
7113
7264
  primitives.push({
7114
7265
  kind: 'rect',
7115
7266
  x,
7116
7267
  y,
7117
7268
  w: barW,
7118
7269
  h,
7119
- fill: resolveDataPointFill(series[si], sourceIndex, paletteColor(si, palette)) ??
7120
- seriesColor(series[si], si, palette),
7270
+ fill: invertNegativeFill(series[si], sourceIndex, rawVal, pctBaseFill),
7121
7271
  part: { role: 'dataPoint', seriesIndex: si, pointIndex: sourceIndex },
7122
7272
  });
7123
7273
  if (showLabels && Math.abs(val) > 0) {
@@ -7178,6 +7328,181 @@ function pushClusteredStackedLabels(series, sourceIndices, catCount, layout, ran
7178
7328
  }
7179
7329
  }
7180
7330
 
7331
+ /**
7332
+ * chart-line-path.ts: bezier smoothing for line-series paths.
7333
+ *
7334
+ * OOXML line/scatter series may set `c:smooth`, which PowerPoint renders as a
7335
+ * smoothed curve through the data points rather than straight segments. This
7336
+ * helper converts a point list into an SVG path `d` string using a Catmull-Rom
7337
+ * spline expressed as cubic beziers, so every binding can render the smoothed
7338
+ * line identically.
7339
+ *
7340
+ * @module chart-line-path
7341
+ */
7342
+ /**
7343
+ * Build a smoothed cubic-bezier path `d` through `points` (Catmull-Rom spline).
7344
+ * Returns a straight `M…L…` fallback for fewer than three points.
7345
+ */
7346
+ function smoothLinePath(points) {
7347
+ if (points.length === 0) {
7348
+ return '';
7349
+ }
7350
+ if (points.length === 1) {
7351
+ return `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
7352
+ }
7353
+ if (points.length === 2) {
7354
+ return `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)} L${points[1].x.toFixed(2)},${points[1].y.toFixed(2)}`;
7355
+ }
7356
+ let d = `M${points[0].x.toFixed(2)},${points[0].y.toFixed(2)}`;
7357
+ for (let i = 0; i < points.length - 1; i++) {
7358
+ const p0 = points[i - 1] ?? points[i];
7359
+ const p1 = points[i];
7360
+ const p2 = points[i + 1];
7361
+ const p3 = points[i + 2] ?? p2;
7362
+ const cp1x = p1.x + (p2.x - p0.x) / 6;
7363
+ const cp1y = p1.y + (p2.y - p0.y) / 6;
7364
+ const cp2x = p2.x - (p3.x - p1.x) / 6;
7365
+ const cp2y = p2.y - (p3.y - p1.y) / 6;
7366
+ d += ` C${cp1x.toFixed(2)},${cp1y.toFixed(2)} ${cp2x.toFixed(2)},${cp2y.toFixed(2)} ${p2.x.toFixed(2)},${p2.y.toFixed(2)}`;
7367
+ }
7368
+ return d;
7369
+ }
7370
+
7371
+ /**
7372
+ * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for
7373
+ * line / scatter / area chart data points.
7374
+ *
7375
+ * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,
7376
+ * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an
7377
+ * optional `c:size` (2-72 points). The base view-model historically drew every
7378
+ * data point as a fixed-radius circle, ignoring both. This helper resolves the
7379
+ * parsed marker into the correct `SvgPrimitive` at the requested size, and
7380
+ * returns `null` for `symbol === 'none'` so no dot is drawn.
7381
+ *
7382
+ * @module chart-marker-shape
7383
+ */
7384
+ /** Resolve the drawn radius (px) from the parsed point size or the default. */
7385
+ function markerRadius(size, defaultRadius) {
7386
+ if (size === undefined || !Number.isFinite(size) || size <= 0) {
7387
+ return defaultRadius;
7388
+ }
7389
+ // OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.
7390
+ return size / 2;
7391
+ }
7392
+ /** Build the SVG points string for a regular/irregular polygon vertex list. */
7393
+ function polygonPoints(vertices) {
7394
+ return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');
7395
+ }
7396
+ function starVertices(cx, cy, r) {
7397
+ const inner = r * 0.5;
7398
+ const out = [];
7399
+ for (let i = 0; i < 10; i++) {
7400
+ const radius = i % 2 === 0 ? r : inner;
7401
+ const angle = -Math.PI / 2 + (Math.PI * i) / 5;
7402
+ out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
7403
+ }
7404
+ return out;
7405
+ }
7406
+ /**
7407
+ * Build the marker primitive for one data point, honouring `symbol` and `size`.
7408
+ * Returns `null` when `symbol === 'none'` (draw nothing).
7409
+ */
7410
+ function buildMarkerPrimitive(input) {
7411
+ const { symbol, cx, cy, fill, part } = input;
7412
+ if (symbol === 'none') {
7413
+ return null;
7414
+ }
7415
+ const r = markerRadius(input.size, input.defaultRadius);
7416
+ const stroke = fill;
7417
+ switch (symbol) {
7418
+ case 'square':
7419
+ return { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };
7420
+ case 'dash':
7421
+ return { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };
7422
+ case 'diamond':
7423
+ return {
7424
+ kind: 'polygon',
7425
+ points: polygonPoints([
7426
+ [cx, cy - r],
7427
+ [cx + r, cy],
7428
+ [cx, cy + r],
7429
+ [cx - r, cy],
7430
+ ]),
7431
+ fill,
7432
+ stroke,
7433
+ strokeWidth: 0,
7434
+ part,
7435
+ };
7436
+ case 'triangle':
7437
+ return {
7438
+ kind: 'polygon',
7439
+ points: polygonPoints([
7440
+ [cx, cy - r],
7441
+ [cx + r * 0.9, cy + r * 0.75],
7442
+ [cx - r * 0.9, cy + r * 0.75],
7443
+ ]),
7444
+ fill,
7445
+ stroke,
7446
+ strokeWidth: 0,
7447
+ part,
7448
+ };
7449
+ case 'star':
7450
+ return {
7451
+ kind: 'polygon',
7452
+ points: polygonPoints(starVertices(cx, cy, r)),
7453
+ fill,
7454
+ stroke,
7455
+ strokeWidth: 0,
7456
+ part,
7457
+ };
7458
+ case 'plus':
7459
+ return {
7460
+ kind: 'path',
7461
+ d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
7462
+ fill: 'none',
7463
+ stroke,
7464
+ strokeWidth: Math.max(1, r * 0.4),
7465
+ part,
7466
+ };
7467
+ case 'x':
7468
+ return {
7469
+ kind: 'path',
7470
+ d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
7471
+ fill: 'none',
7472
+ stroke,
7473
+ strokeWidth: Math.max(1, r * 0.4),
7474
+ part,
7475
+ };
7476
+ case 'dot':
7477
+ return { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };
7478
+ default:
7479
+ // circle / auto / picture / undefined -> filled circle.
7480
+ return { kind: 'circle', cx, cy, r, fill, part };
7481
+ }
7482
+ }
7483
+
7484
+ /**
7485
+ * Build the marker for a data point (honouring `marker.symbol`/`size`) and push
7486
+ * it, unless the symbol is `none`. Shared by the line / area / scatter builders.
7487
+ */
7488
+ function pushMarker(out, series, cx, cy, fill, defaultRadius, part, opacity) {
7489
+ const m = buildMarkerPrimitive({
7490
+ symbol: series.marker?.symbol,
7491
+ size: series.marker?.size,
7492
+ cx,
7493
+ cy,
7494
+ fill,
7495
+ defaultRadius,
7496
+ part,
7497
+ });
7498
+ if (!m) {
7499
+ return;
7500
+ }
7501
+ if (opacity !== undefined) {
7502
+ m.opacity = opacity;
7503
+ }
7504
+ out.push(m);
7505
+ }
7181
7506
  /** Build line-chart primitives, honouring a secondary value range per series. */
7182
7507
  function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, secondaryIdx, sourceIndices, xPositions) {
7183
7508
  const primitives = [];
@@ -7195,24 +7520,29 @@ function buildLines(chartData, catCount, layout, primaryRange, secondaryRange, s
7195
7520
  x: xPositions?.[index] ?? point.x,
7196
7521
  }));
7197
7522
  const c = seriesColor(series, si, chartData.colorPalette);
7198
- primitives.push({
7199
- kind: 'polyline',
7200
- points: linePointsToSvgString(pts),
7201
- stroke: c,
7202
- strokeWidth: 2.4,
7203
- fill: 'none',
7204
- part: { role: 'series', seriesIndex: si },
7205
- });
7206
- pts.forEach((pt, displayIndex) => {
7207
- const sourceIndex = sourceIndices[displayIndex] ?? displayIndex;
7208
- primitives.push({
7209
- kind: 'circle',
7210
- cx: pt.x,
7211
- cy: pt.y,
7212
- r: 2.5,
7213
- fill: resolveDataPointFill(series, sourceIndex, c) ?? c,
7214
- part: { role: 'dataPoint', seriesIndex: si, pointIndex: sourceIndex },
7523
+ // c:smooth draws a bezier path through the points; otherwise a polyline.
7524
+ const seriesPart = { role: 'series', seriesIndex: si };
7525
+ primitives.push(series.smooth
7526
+ ? {
7527
+ kind: 'path',
7528
+ d: smoothLinePath(pts),
7529
+ stroke: c,
7530
+ strokeWidth: 2.4,
7531
+ fill: 'none',
7532
+ part: seriesPart,
7533
+ }
7534
+ : {
7535
+ kind: 'polyline',
7536
+ points: linePointsToSvgString(pts),
7537
+ stroke: c,
7538
+ strokeWidth: 2.4,
7539
+ fill: 'none',
7540
+ part: seriesPart,
7215
7541
  });
7542
+ pts.forEach((pt, displayIndex) => {
7543
+ const idx = sourceIndices[displayIndex] ?? displayIndex;
7544
+ const part = { role: 'dataPoint', seriesIndex: si, pointIndex: idx };
7545
+ pushMarker(primitives, series, pt.x, pt.y, resolveDataPointFill(series, idx, c) ?? c, 2.5, part);
7216
7546
  });
7217
7547
  if (showLabels) {
7218
7548
  displayValues.forEach((val, displayIndex) => {
@@ -7274,19 +7604,9 @@ function buildAreas(chartData, catCount, layout, range, sourceIndices, xPosition
7274
7604
  part: { role: 'series', seriesIndex: si },
7275
7605
  });
7276
7606
  pts.forEach((pt, displayIndex) => {
7277
- const sourceIndex = sourceIndices[displayIndex] ?? displayIndex;
7278
- primitives.push({
7279
- kind: 'circle',
7280
- cx: pt.x,
7281
- cy: pt.y,
7282
- r: 2,
7283
- fill: resolveDataPointFill(series, sourceIndex, c) ?? c,
7284
- part: {
7285
- role: 'dataPoint',
7286
- seriesIndex: si,
7287
- pointIndex: sourceIndex,
7288
- },
7289
- });
7607
+ const idx = sourceIndices[displayIndex] ?? displayIndex;
7608
+ const part = { role: 'dataPoint', seriesIndex: si, pointIndex: idx };
7609
+ pushMarker(primitives, series, pt.x, pt.y, resolveDataPointFill(series, idx, c) ?? c, 2, part);
7290
7610
  });
7291
7611
  if (showLabels) {
7292
7612
  displayValues.forEach((val, displayIndex) => {
@@ -7321,15 +7641,8 @@ function buildScatter(chartData, layout, range) {
7321
7641
  const c = seriesColor(series, si, chartData.colorPalette);
7322
7642
  const dots = computeScatterDots(series.values, maxXIndex, layout, range, xValues);
7323
7643
  dots.forEach((dot, vi) => {
7324
- primitives.push({
7325
- kind: 'circle',
7326
- cx: dot.cx,
7327
- cy: dot.cy,
7328
- r: 4,
7329
- fill: resolveDataPointFill(series, vi, c) ?? c,
7330
- opacity: 0.85,
7331
- part: { role: 'dataPoint', seriesIndex: si, pointIndex: vi },
7332
- });
7644
+ const part = { role: 'dataPoint', seriesIndex: si, pointIndex: vi };
7645
+ pushMarker(primitives, series, dot.cx, dot.cy, resolveDataPointFill(series, vi, c) ?? c, 4, part, 0.85);
7333
7646
  });
7334
7647
  if (showLabels) {
7335
7648
  series.values.forEach((val, vi) => {
@@ -7400,6 +7713,163 @@ function buildBubbles(chartData, layout, range) {
7400
7713
  return { primitives, dataLabels };
7401
7714
  }
7402
7715
 
7716
+ /**
7717
+ * chart-helper-lines.ts: shared drop-line / hi-low-line / up-down-bar primitives.
7718
+ *
7719
+ * OOXML line and stock charts may declare `c:dropLines`, `c:hiLowLines`, and
7720
+ * `c:upDownBars` on the chart-type container. Historically these rendered only
7721
+ * in the React chart chrome (drop/hi-low), and up-down bars nowhere, so the
7722
+ * framework-agnostic view-model (Vue / Angular / Vanilla / Svelte) never drew
7723
+ * them. These pure builders project each into `SvgPrimitive[]` so every binding
7724
+ * renders them from a single source.
7725
+ *
7726
+ * dropLines - a vertical line from each data point down to the axis baseline.
7727
+ * hiLowLines - a vertical line spanning the highest and lowest series value
7728
+ * in each category (requires >= 2 series).
7729
+ * upDownBars - a bar between the first and last series value in each category,
7730
+ * coloured by whether the last value rose or fell (>= 2 series).
7731
+ *
7732
+ * @module chart-helper-lines
7733
+ */
7734
+ /** X pixel for a category index, preferring an explicit x-position. */
7735
+ function categoryX$2(index, catCount, layout, options) {
7736
+ const explicit = options.xPositions?.[index];
7737
+ if (explicit !== undefined) {
7738
+ return explicit;
7739
+ }
7740
+ if (options.mode === 'bar') {
7741
+ const slot = layout.plotWidth / Math.max(catCount, 1);
7742
+ return layout.plotLeft + slot * index + slot / 2;
7743
+ }
7744
+ const maxIdx = Math.max(catCount - 1, 1);
7745
+ return layout.plotLeft + (index / maxIdx) * layout.plotWidth;
7746
+ }
7747
+ /** SVG dash pattern for a helper-line dash style, if any. */
7748
+ function dashFor(dashStyle) {
7749
+ if (!dashStyle || dashStyle === 'solid') {
7750
+ return undefined;
7751
+ }
7752
+ return dashStyle === 'dot' || dashStyle === 'sysDot' ? '1 2' : '4 3';
7753
+ }
7754
+ /**
7755
+ * Drop lines: a vertical line from every data point down to the value-axis
7756
+ * baseline (`range.min`). Returns `[]` when `c:dropLines` is absent.
7757
+ */
7758
+ function computeDropLinePrimitives(chartData, layout, range, catCount, options) {
7759
+ const style = chartData.dropLines;
7760
+ if (!style) {
7761
+ return [];
7762
+ }
7763
+ const baselineY = valueToY(range.min, range, layout.plotTop, layout.plotBottom);
7764
+ const dashArray = dashFor(style.dashStyle);
7765
+ const out = [];
7766
+ for (const series of chartData.series) {
7767
+ series.values.forEach((val, vi) => {
7768
+ const x = categoryX$2(vi, catCount, layout, options);
7769
+ out.push({
7770
+ kind: 'line',
7771
+ x1: x,
7772
+ y1: valueToY(val, range, layout.plotTop, layout.plotBottom),
7773
+ x2: x,
7774
+ y2: baselineY,
7775
+ stroke: style.color ?? '#94a3b8',
7776
+ strokeWidth: style.width ?? 0.8,
7777
+ dashArray,
7778
+ });
7779
+ });
7780
+ }
7781
+ return out;
7782
+ }
7783
+ /**
7784
+ * Hi-low lines: a vertical line joining the highest and lowest series value in
7785
+ * each category. Returns `[]` when `c:hiLowLines` is absent or fewer than two
7786
+ * series are present.
7787
+ */
7788
+ function computeHiLowLinePrimitives(chartData, layout, range, catCount, options) {
7789
+ const style = chartData.hiLowLines;
7790
+ if (!style || chartData.series.length < 2) {
7791
+ return [];
7792
+ }
7793
+ const dashArray = dashFor(style.dashStyle);
7794
+ const out = [];
7795
+ for (let vi = 0; vi < catCount; vi++) {
7796
+ let high = Number.NEGATIVE_INFINITY;
7797
+ let low = Number.POSITIVE_INFINITY;
7798
+ for (const series of chartData.series) {
7799
+ const v = series.values[vi];
7800
+ if (v !== undefined) {
7801
+ high = Math.max(high, v);
7802
+ low = Math.min(low, v);
7803
+ }
7804
+ }
7805
+ if (!Number.isFinite(high) || !Number.isFinite(low)) {
7806
+ continue;
7807
+ }
7808
+ const x = categoryX$2(vi, catCount, layout, options);
7809
+ out.push({
7810
+ kind: 'line',
7811
+ x1: x,
7812
+ y1: valueToY(high, range, layout.plotTop, layout.plotBottom),
7813
+ x2: x,
7814
+ y2: valueToY(low, range, layout.plotTop, layout.plotBottom),
7815
+ stroke: style.color ?? '#334155',
7816
+ strokeWidth: style.width ?? 1,
7817
+ dashArray,
7818
+ });
7819
+ }
7820
+ return out;
7821
+ }
7822
+ /**
7823
+ * Up-down bars: a bar between the first and last series value in each category.
7824
+ * Rising categories (last >= first) use the `upBars` fill, falling ones the
7825
+ * `downBars` fill. Returns `[]` when `c:upDownBars` is absent or fewer than two
7826
+ * series are present.
7827
+ */
7828
+ function computeUpDownBarPrimitives(chartData, layout, range, catCount, options) {
7829
+ const bars = chartData.upDownBars;
7830
+ if (!bars || chartData.series.length < 2) {
7831
+ return [];
7832
+ }
7833
+ const first = chartData.series[0];
7834
+ const last = chartData.series[chartData.series.length - 1];
7835
+ const slot = layout.plotWidth / Math.max(catCount, 1);
7836
+ const gapWidth = bars.gapWidth ?? 150;
7837
+ const barW = Math.max(slot / (1 + Math.max(gapWidth, 0) / 100), 1);
7838
+ const upFill = bars.upBars?.fillColor ?? '#e2e8f0';
7839
+ const downFill = bars.downBars?.fillColor ?? '#334155';
7840
+ const out = [];
7841
+ for (let vi = 0; vi < catCount; vi++) {
7842
+ const firstVal = first.values[vi];
7843
+ const lastVal = last.values[vi];
7844
+ if (firstVal === undefined || lastVal === undefined) {
7845
+ continue;
7846
+ }
7847
+ const firstY = valueToY(firstVal, range, layout.plotTop, layout.plotBottom);
7848
+ const lastY = valueToY(lastVal, range, layout.plotTop, layout.plotBottom);
7849
+ const x = categoryX$2(vi, catCount, layout, options) - barW / 2;
7850
+ out.push({
7851
+ kind: 'rect',
7852
+ x,
7853
+ y: Math.min(firstY, lastY),
7854
+ w: barW,
7855
+ h: Math.max(Math.abs(firstY - lastY), 1),
7856
+ fill: lastVal >= firstVal ? upFill : downFill,
7857
+ });
7858
+ }
7859
+ return out;
7860
+ }
7861
+ /**
7862
+ * Convenience: all three helper-line families for a chart, concatenated.
7863
+ * Drawn under the series marks by the caller (they push the data marks first).
7864
+ */
7865
+ function computeHelperLinePrimitives(chartData, layout, range, catCount, options) {
7866
+ return [
7867
+ ...computeUpDownBarPrimitives(chartData, layout, range, catCount, options),
7868
+ ...computeDropLinePrimitives(chartData, layout, range, catCount, options),
7869
+ ...computeHiLowLinePrimitives(chartData, layout, range, catCount, options),
7870
+ ];
7871
+ }
7872
+
7403
7873
  function categoryX$1(displayIndex, count, layout, spacing) {
7404
7874
  if (spacing === 'bar') {
7405
7875
  return layout.plotLeft + (layout.plotWidth / Math.max(count, 1)) * (displayIndex + 0.5);
@@ -8573,7 +9043,19 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
8573
9043
  else {
8574
9044
  plot = buildBubbles(chartData, layout, primaryRange);
8575
9045
  }
8576
- const primitives = [...plot.primitives, ...horizontalAxis.tickMarks];
9046
+ // Drop lines / hi-low lines / up-down bars (line + area kinds). Drawn behind
9047
+ // the series marks so the data stays legible on top.
9048
+ const helperLines = kind === 'line' || kind === 'area'
9049
+ ? computeHelperLinePrimitives(chartData, layout, primaryRange, catCount, {
9050
+ mode: 'line',
9051
+ xPositions: horizontalAxis.xPositions,
9052
+ })
9053
+ : [];
9054
+ const primitives = [
9055
+ ...helperLines,
9056
+ ...plot.primitives,
9057
+ ...horizontalAxis.tickMarks,
9058
+ ];
8577
9059
  // Overlays (depth): regression trendlines, error bars, axis titles, data table.
8578
9060
  const overlays = [
8579
9061
  ...computeTrendlinePrimitives(displayChartData, catCount, layout, primaryRange, catAxisStyle, chartData.colorPalette),
@@ -8656,6 +9138,9 @@ function buildComboViewModel(element, chartData, categoryLabels) {
8656
9138
  const { legend, legendX, legendY, legendAnchor } = buildLegend(chartData.series, chartData.colorPalette, layout.svgWidth, legendPos, layout.svgHeight, layout.plotTop);
8657
9139
  const primitives = [];
8658
9140
  const dataLabels = [];
9141
+ // Drop / hi-low / up-down helper lines, drawn behind the combo marks.
9142
+ const helperOpts = { mode: 'line', xPositions: horizontalAxis.xPositions };
9143
+ primitives.push(...computeHelperLinePrimitives(chartData, layout, primaryRange, catCount, helperOpts));
8659
9144
  const barSeries = chartData.series.slice(0, 1);
8660
9145
  if (barSeries[0]) {
8661
9146
  const barRange = rangeForSeries$1(0, primaryRange, secondaryRange, secondaryIndexes);
@@ -11320,16 +11805,28 @@ function computePieLayout(elementWidth, elementHeight, chartData, isDoughnut) {
11320
11805
  const cx = size / 2;
11321
11806
  const cy = titleOffset + (size - titleOffset - legendOffset) / 2;
11322
11807
  const outerR = Math.max((size - titleOffset - legendOffset) * 0.42, 0);
11323
- const innerR = isDoughnut ? outerR * 0.55 : 0;
11808
+ // Honour c:holeSize (10-90% of the outer diameter) when parsed; otherwise
11809
+ // keep the legacy 0.55 ratio byte-for-byte.
11810
+ const holeRatio = isDoughnut && chartData.doughnutHoleSize !== undefined
11811
+ ? Math.min(Math.max(chartData.doughnutHoleSize, 10), 90) / 100
11812
+ : 0.55;
11813
+ const innerR = isDoughnut ? outerR * holeRatio : 0;
11324
11814
  return { cx, cy, outerR, innerR, size };
11325
11815
  }
11326
- function computePieSlices(values, cx, cy, outerR, innerR) {
11816
+ function computePieSlices(values, cx, cy, outerR, innerR, options) {
11327
11817
  const total = values.reduce((s, v) => s + Math.abs(v), 0) || 1;
11328
- let cumAngle = -Math.PI / 2;
11329
- return values.map((val) => {
11818
+ let cumAngle = options?.startAngle ?? -Math.PI / 2;
11819
+ return values.map((val, i) => {
11330
11820
  const sliceAngle = (Math.abs(val) / total) * Math.PI * 2;
11331
11821
  const startAngle = cumAngle;
11332
11822
  cumAngle += sliceAngle;
11823
+ // A c:explosion pulls the slice outward along its bisector.
11824
+ const explosion = options?.explosions?.[i] ?? 0;
11825
+ if (explosion > 0) {
11826
+ const mid = (startAngle + cumAngle) / 2;
11827
+ const offset = outerR * (explosion / 100);
11828
+ return computePieSlicePath(cx + Math.cos(mid) * offset, cy + Math.sin(mid) * offset, outerR, innerR, startAngle, cumAngle);
11829
+ }
11333
11830
  return computePieSlicePath(cx, cy, outerR, innerR, startAngle, cumAngle);
11334
11831
  });
11335
11832
  }
@@ -11541,7 +12038,13 @@ function buildPieViewModel(element, chartData, categoryLabels, isDoughnut) {
11541
12038
  const svgHeight = Math.max(size, 60);
11542
12039
  const pieSeries = chartData.series[0];
11543
12040
  const values = pieSeries?.values ?? [];
11544
- const slices = computePieSlices(values, cx, cy, outerR, innerR);
12041
+ // c:firstSliceAng rotates the pie clockwise from 12 o'clock; c:explosion (per
12042
+ // series or per c:dPt) pulls slices outward.
12043
+ const startAngle = -Math.PI / 2 + ((chartData.firstSliceAngle ?? 0) * Math.PI) / 180;
12044
+ const explosions = pieSeries
12045
+ ? values.map((_v, i) => resolveDataPointExplosion(pieSeries, i))
12046
+ : undefined;
12047
+ const slices = computePieSlices(values, cx, cy, outerR, innerR, { startAngle, explosions });
11545
12048
  const primitives = slices.map(({ d }, i) => ({
11546
12049
  kind: 'path',
11547
12050
  d,
@@ -14222,6 +14725,51 @@ class AnimationSequencer {
14222
14725
  * @module render/animation-timeline-builder
14223
14726
  */
14224
14727
  // ==========================================================================
14728
+ // Unmapped-preset safety net
14729
+ // ==========================================================================
14730
+ /**
14731
+ * Resolve a fallback {@link EffectName} for an animation whose preset we do
14732
+ * not model (no static effect and no dynamic keyframe).
14733
+ *
14734
+ * Without this, an unmapped animation was silently dropped, which broke slide
14735
+ * visibility semantics: an unmapped **entrance** was never registered as
14736
+ * hidden-until-its-start, so it stayed visible from the very first frame; an
14737
+ * unmapped **exit** never hid its element. We substitute a neutral fade so the
14738
+ * element still transitions in (entrance) or out (exit) at the correct time.
14739
+ *
14740
+ * Emphasis / motion-path presets carry no show/hide semantics, so a missing
14741
+ * one is safe to skip and returns `undefined`.
14742
+ */
14743
+ /**
14744
+ * Map an animation's parsed `accel`/`decel` fractions to a CSS timing function.
14745
+ * PowerPoint's acceleration eases the effect in, deceleration eases it out, and
14746
+ * both together ease in-and-out. With neither set we keep the neutral `ease`
14747
+ * default so existing decks are unchanged.
14748
+ */
14749
+ function cssEasingForAnimation(anim) {
14750
+ const hasAccel = anim.accel !== undefined && anim.accel > 0;
14751
+ const hasDecel = anim.decel !== undefined && anim.decel > 0;
14752
+ if (hasAccel && hasDecel) {
14753
+ return 'ease-in-out';
14754
+ }
14755
+ if (hasAccel) {
14756
+ return 'ease-in';
14757
+ }
14758
+ if (hasDecel) {
14759
+ return 'ease-out';
14760
+ }
14761
+ return 'ease';
14762
+ }
14763
+ function fallbackEffectForClass(presetClass) {
14764
+ if (presetClass === 'entr') {
14765
+ return 'fadeIn';
14766
+ }
14767
+ if (presetClass === 'exit') {
14768
+ return 'fadeOut';
14769
+ }
14770
+ return undefined;
14771
+ }
14772
+ // ==========================================================================
14225
14773
  // Timeline builder
14226
14774
  // ==========================================================================
14227
14775
  /**
@@ -14284,10 +14832,15 @@ function buildTimeline(nativeAnimations) {
14284
14832
  for (const anim of regularAnims) {
14285
14833
  const expandedSteps = expandIterateAnimation(anim);
14286
14834
  for (const singleAnim of expandedSteps) {
14287
- const effect = resolveEffect(singleAnim);
14835
+ let effect = resolveEffect(singleAnim);
14288
14836
  const dynamic = effect ? undefined : buildDynamicKeyframe(singleAnim, dynamicUid++);
14289
14837
  if (!effect && !dynamic) {
14290
- continue;
14838
+ // Unmapped preset: fall back so an entrance is still hidden until
14839
+ // its start and an exit still hides, rather than being dropped.
14840
+ effect = fallbackEffectForClass(singleAnim.presetClass);
14841
+ if (!effect) {
14842
+ continue;
14843
+ }
14291
14844
  }
14292
14845
  const keyframe = effect ? cssKeyframeName(effect) : dynamic.keyframeName;
14293
14846
  if (effect) {
@@ -14351,7 +14904,8 @@ function buildTimeline(nativeAnimations) {
14351
14904
  delayMs = animDelay + triggerDelay;
14352
14905
  }
14353
14906
  const iterStr = iterCount === Infinity ? 'infinite' : String(iterCount);
14354
- const cssAnimation = `${keyframe} ${duration}ms ease ${delayMs}ms ${iterStr} ${direction} ${fill}`;
14907
+ const easing = cssEasingForAnimation(singleAnim);
14908
+ const cssAnimation = `${keyframe} ${duration}ms ${easing} ${delayMs}ms ${iterStr} ${direction} ${fill}`;
14355
14909
  currentGroup.push({
14356
14910
  elementId,
14357
14911
  cssAnimation,
@@ -14452,10 +15006,14 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
14452
15006
  const seqGroups = [];
14453
15007
  let seqGroup = [];
14454
15008
  for (const anim of anims) {
14455
- const effect = resolveEffect(anim);
15009
+ let effect = resolveEffect(anim);
14456
15010
  const dynamic = effect ? undefined : buildDynamicKeyframe(anim, dynamicUid++);
14457
15011
  if (!effect && !dynamic) {
14458
- continue;
15012
+ // Same unmapped-preset safety net as the main timeline loop.
15013
+ effect = fallbackEffectForClass(anim.presetClass);
15014
+ if (!effect) {
15015
+ continue;
15016
+ }
14459
15017
  }
14460
15018
  const keyframe = effect ? cssKeyframeName(effect) : dynamic.keyframeName;
14461
15019
  if (effect) {
@@ -14495,7 +15053,8 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
14495
15053
  delayMs = animDelay + triggerDelay;
14496
15054
  }
14497
15055
  const iterStr = iterCount === Infinity ? 'infinite' : String(iterCount);
14498
- const cssAnimation = `${keyframe} ${duration}ms ease ${delayMs}ms ${iterStr} ${direction} ${fill}`;
15056
+ const easing = cssEasingForAnimation(anim);
15057
+ const cssAnimation = `${keyframe} ${duration}ms ${easing} ${delayMs}ms ${iterStr} ${direction} ${fill}`;
14499
15058
  seqGroup.push({
14500
15059
  elementId,
14501
15060
  cssAnimation,
@@ -16264,6 +16823,174 @@ function resolveCellBorderCss(entry, tableData, pos, resolve) {
16264
16823
  return applied ? css : undefined;
16265
16824
  }
16266
16825
 
16826
+ // ---------------------------------------------------------------------------
16827
+ // Theme colour helpers (tint / shade) — mirrors React viewer/utils/theme.ts
16828
+ // ---------------------------------------------------------------------------
16829
+ /** Parse a 6-digit hex colour (`#RRGGBB` or `RRGGBB`) into RGB components. */
16830
+ function hexToRgb$2(hex) {
16831
+ const clean = hex.replace(/^#/u, '');
16832
+ return {
16833
+ r: parseInt(clean.substring(0, 2), 16),
16834
+ g: parseInt(clean.substring(2, 4), 16),
16835
+ b: parseInt(clean.substring(4, 6), 16),
16836
+ };
16837
+ }
16838
+ /** Convert RGB components back to a `#RRGGBB` string. */
16839
+ function rgbToHex$1(r, g, b) {
16840
+ const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
16841
+ return `#${clamp(r).toString(16).padStart(2, '0').toUpperCase()}${clamp(g).toString(16).padStart(2, '0').toUpperCase()}${clamp(b).toString(16).padStart(2, '0').toUpperCase()}`;
16842
+ }
16843
+ /** Compute a tinted (lighter) colour. `tintFactor` in 0-1 (1 = white). */
16844
+ function tintColor$1(hex, tintFactor) {
16845
+ const { r, g, b } = hexToRgb$2(hex);
16846
+ return rgbToHex$1(r + (255 - r) * tintFactor, g + (255 - g) * tintFactor, b + (255 - b) * tintFactor);
16847
+ }
16848
+ /** Compute a shaded (darker) colour. `shadeFactor` in 0-1 (1 = black). */
16849
+ function shadeColor$1(hex, shadeFactor) {
16850
+ const { r, g, b } = hexToRgb$2(hex);
16851
+ return rgbToHex$1(r * (1 - shadeFactor), g * (1 - shadeFactor), b * (1 - shadeFactor));
16852
+ }
16853
+ /** Apply a fill's tint/shade to a resolved base hex colour. */
16854
+ function applyTintShade(base, fill) {
16855
+ let color = base;
16856
+ if (fill.tint !== undefined && fill.tint > 0) {
16857
+ color = tintColor$1(color, fill.tint / 100_000);
16858
+ }
16859
+ if (fill.shade !== undefined && fill.shade > 0) {
16860
+ color = shadeColor$1(color, 1 - fill.shade / 100_000);
16861
+ }
16862
+ return color;
16863
+ }
16864
+ /**
16865
+ * Resolve a {@link ParsedTableStyleFill} to a concrete CSS hex colour using the
16866
+ * supplied colour scheme. Honours a scheme colour first, then an explicit sRGB
16867
+ * `color`. Returns `undefined` when neither resolves (e.g. gradient/pattern/no
16868
+ * fill, or a scheme key absent from the theme).
16869
+ */
16870
+ function resolveStyleFillColor(fill, colorScheme) {
16871
+ if (!fill) {
16872
+ return undefined;
16873
+ }
16874
+ let base;
16875
+ if (fill.schemeColor && colorScheme) {
16876
+ base = colorScheme[fill.schemeColor];
16877
+ }
16878
+ if (!base && fill.color) {
16879
+ base = fill.color;
16880
+ }
16881
+ if (!base) {
16882
+ return undefined;
16883
+ }
16884
+ return applyTintShade(base, fill);
16885
+ }
16886
+ /** Clear every background-related key so a higher layer replaces cleanly. */
16887
+ function clearBackground(css) {
16888
+ delete css.background;
16889
+ delete css.backgroundColor;
16890
+ delete css.backgroundImage;
16891
+ }
16892
+ /** Build a CSS gradient string from a parsed table-style gradient fill. */
16893
+ function gradientCssFromFill(fill, colorScheme) {
16894
+ const gradient = fill.gradient;
16895
+ if (!gradient || gradient.stops.length === 0) {
16896
+ return undefined;
16897
+ }
16898
+ const shapeLike = {
16899
+ fillMode: 'gradient',
16900
+ fillGradientType: gradient.type,
16901
+ fillGradientAngle: gradient.angle ?? 90,
16902
+ fillGradientStops: gradient.stops.map((stop) => ({
16903
+ color: resolveStyleFillColor(stop.fill, colorScheme) ?? stop.fill.color ?? '#000000',
16904
+ position: stop.position,
16905
+ })),
16906
+ };
16907
+ return buildGradientCss(shapeLike);
16908
+ }
16909
+ /**
16910
+ * Apply a {@link ParsedTableStyleFill} onto a {@link TableCellCss} background.
16911
+ * Handles no-fill (transparent), gradient, preset pattern, and solid (scheme or
16912
+ * sRGB) fills. When the fill is absent or unresolvable, falls back to
16913
+ * `fallback` as a solid background colour. Returns `true` when anything was set.
16914
+ */
16915
+ function applyStyleFill(fill, colorScheme, css, fallback) {
16916
+ if (fill?.noFill) {
16917
+ clearBackground(css);
16918
+ css.backgroundColor = 'transparent';
16919
+ return true;
16920
+ }
16921
+ if (fill?.gradient) {
16922
+ const gradientCss = gradientCssFromFill(fill, colorScheme);
16923
+ if (gradientCss) {
16924
+ clearBackground(css);
16925
+ css.background = gradientCss;
16926
+ return true;
16927
+ }
16928
+ }
16929
+ if (fill?.pattern) {
16930
+ const fg = normalizeHexColor$1(resolveStyleFillColor(fill.pattern.foreground, colorScheme), '#000000');
16931
+ const bg = normalizeHexColor$1(resolveStyleFillColor(fill.pattern.background, colorScheme), '#ffffff');
16932
+ const svg = getPatternSvg$1(fill.pattern.preset, fg, bg);
16933
+ clearBackground(css);
16934
+ if (svg) {
16935
+ css.backgroundImage = `url("data:image/svg+xml,${encodeURIComponent(svg)}")`;
16936
+ }
16937
+ css.backgroundColor = bg;
16938
+ return true;
16939
+ }
16940
+ const color = resolveStyleFillColor(fill, colorScheme) ?? fallback;
16941
+ if (color) {
16942
+ clearBackground(css);
16943
+ css.backgroundColor = color;
16944
+ return true;
16945
+ }
16946
+ return false;
16947
+ }
16948
+ /**
16949
+ * Apply text properties from a {@link ParsedTableStyleText} entry into a
16950
+ * {@link TableCellCss} object. Returns `true` when any property was set.
16951
+ */
16952
+ function applyStyleText(text, colorScheme, css) {
16953
+ if (!text) {
16954
+ return false;
16955
+ }
16956
+ let applied = false;
16957
+ if (text.bold) {
16958
+ css.fontWeight = 700;
16959
+ applied = true;
16960
+ }
16961
+ if (text.italic) {
16962
+ css.fontStyle = 'italic';
16963
+ applied = true;
16964
+ }
16965
+ if (text.underline) {
16966
+ css.textDecorationLine = 'underline';
16967
+ applied = true;
16968
+ }
16969
+ if (text.fontFace) {
16970
+ css.fontFamily = text.fontFace;
16971
+ applied = true;
16972
+ }
16973
+ if (text.fontSchemeColor && colorScheme) {
16974
+ const base = colorScheme[text.fontSchemeColor];
16975
+ if (base) {
16976
+ let color = base;
16977
+ if (text.fontTint !== undefined && text.fontTint > 0) {
16978
+ color = tintColor$1(color, text.fontTint / 100_000);
16979
+ }
16980
+ if (text.fontShade !== undefined && text.fontShade > 0) {
16981
+ color = shadeColor$1(color, 1 - text.fontShade / 100_000);
16982
+ }
16983
+ css.color = color;
16984
+ applied = true;
16985
+ }
16986
+ }
16987
+ else if (text.fontColor) {
16988
+ css.color = text.fontColor;
16989
+ applied = true;
16990
+ }
16991
+ return applied;
16992
+ }
16993
+
16267
16994
  /**
16268
16995
  * Convert a {@link CellTextRun}'s per-run formatting to an inline CSS style
16269
16996
  * object suitable for a `<span>` element.
@@ -16323,97 +17050,6 @@ function cellPatternFillCss(style) {
16323
17050
  const fallback = style.patternFillBackground ?? style.backgroundColor;
16324
17051
  return fallback ? { backgroundColor: fallback } : null;
16325
17052
  }
16326
- // ---------------------------------------------------------------------------
16327
- // Theme colour helpers (tint / shade) — mirrors React viewer/utils/theme.ts
16328
- // ---------------------------------------------------------------------------
16329
- /** Parse a 6-digit hex colour (`#RRGGBB` or `RRGGBB`) into RGB components. */
16330
- function hexToRgb$2(hex) {
16331
- const clean = hex.replace(/^#/u, '');
16332
- return {
16333
- r: parseInt(clean.substring(0, 2), 16),
16334
- g: parseInt(clean.substring(2, 4), 16),
16335
- b: parseInt(clean.substring(4, 6), 16),
16336
- };
16337
- }
16338
- /** Convert RGB components back to a `#RRGGBB` string. */
16339
- function rgbToHex$1(r, g, b) {
16340
- const clamp = (v) => Math.max(0, Math.min(255, Math.round(v)));
16341
- return `#${clamp(r).toString(16).padStart(2, '0').toUpperCase()}${clamp(g).toString(16).padStart(2, '0').toUpperCase()}${clamp(b).toString(16).padStart(2, '0').toUpperCase()}`;
16342
- }
16343
- /**
16344
- * Compute a tinted (lighter) version of a colour.
16345
- * `tintFactor` is 0–1 where 1 = white and 0 = original.
16346
- */
16347
- function tintColor$1(hex, tintFactor) {
16348
- const { r, g, b } = hexToRgb$2(hex);
16349
- return rgbToHex$1(r + (255 - r) * tintFactor, g + (255 - g) * tintFactor, b + (255 - b) * tintFactor);
16350
- }
16351
- /**
16352
- * Compute a shaded (darker) version of a colour.
16353
- * `shadeFactor` is 0–1 where 1 = black and 0 = original.
16354
- */
16355
- function shadeColor$1(hex, shadeFactor) {
16356
- const { r, g, b } = hexToRgb$2(hex);
16357
- return rgbToHex$1(r * (1 - shadeFactor), g * (1 - shadeFactor), b * (1 - shadeFactor));
16358
- }
16359
- /**
16360
- * Resolve a {@link ParsedTableStyleFill} to a CSS hex colour using the
16361
- * supplied colour scheme. Returns `undefined` when the scheme colour key
16362
- * cannot be found.
16363
- */
16364
- function resolveStyleFillColor(fill, colorScheme) {
16365
- if (!fill) {
16366
- return undefined;
16367
- }
16368
- if (!colorScheme) {
16369
- return undefined;
16370
- }
16371
- const base = colorScheme[fill.schemeColor];
16372
- if (!base) {
16373
- return undefined;
16374
- }
16375
- let color = base;
16376
- if (fill.tint !== undefined && fill.tint > 0) {
16377
- color = tintColor$1(color, fill.tint / 100_000);
16378
- }
16379
- if (fill.shade !== undefined && fill.shade > 0) {
16380
- color = shadeColor$1(color, 1 - fill.shade / 100_000);
16381
- }
16382
- return color;
16383
- }
16384
- /**
16385
- * Apply text properties from a {@link ParsedTableStyleText} entry into a
16386
- * {@link TableCellCss} object. Returns `true` when any property was set.
16387
- */
16388
- function applyStyleText(text, colorScheme, css) {
16389
- if (!text) {
16390
- return false;
16391
- }
16392
- let applied = false;
16393
- if (text.bold) {
16394
- css.fontWeight = 700;
16395
- applied = true;
16396
- }
16397
- if (text.italic) {
16398
- css.fontStyle = 'italic';
16399
- applied = true;
16400
- }
16401
- if (text.fontSchemeColor && colorScheme) {
16402
- const base = colorScheme[text.fontSchemeColor];
16403
- if (base) {
16404
- let color = base;
16405
- if (text.fontTint !== undefined && text.fontTint > 0) {
16406
- color = tintColor$1(color, text.fontTint / 100_000);
16407
- }
16408
- if (text.fontShade !== undefined && text.fontShade > 0) {
16409
- color = shadeColor$1(color, 1 - text.fontShade / 100_000);
16410
- }
16411
- css.color = color;
16412
- applied = true;
16413
- }
16414
- }
16415
- return applied;
16416
- }
16417
17053
  /**
16418
17054
  * Look up the table style entry for a style GUID, trying both the raw value
16419
17055
  * and the braced-upper-case normalisation that OOXML uses.
@@ -16642,9 +17278,7 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16642
17278
  let applied = false;
16643
17279
  // ── Whole-table fill (lowest priority layer). ──
16644
17280
  if (styleEntry?.wholeTblFill) {
16645
- const wholeBg = resolveFill(styleEntry.wholeTblFill, '');
16646
- if (wholeBg) {
16647
- style.backgroundColor = wholeBg;
17281
+ if (applyStyleFill(styleEntry.wholeTblFill, colorScheme, style, '')) {
16648
17282
  applied = true;
16649
17283
  }
16650
17284
  }
@@ -16659,16 +17293,12 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16659
17293
  const rowCycle = Math.max(tableData.bandRowCycle ?? 1, 1);
16660
17294
  const bandGroup = Math.floor(bandIndex / rowCycle) % 2;
16661
17295
  if (bandGroup === 0) {
16662
- style.backgroundColor = resolveFill(styleEntry?.band1HFill, 'rgba(217, 226, 243, 0.5)');
16663
- if (applyStyleText(styleEntry?.band1HText, colorScheme, style)) {
16664
- applied = true;
16665
- }
17296
+ applyStyleFill(styleEntry?.band1HFill, colorScheme, style, 'rgba(217, 226, 243, 0.5)');
17297
+ applyStyleText(styleEntry?.band1HText, colorScheme, style);
16666
17298
  applied = true;
16667
17299
  }
16668
17300
  else if (styleEntry?.band2HFill) {
16669
- const band2Bg = resolveFill(styleEntry.band2HFill, '');
16670
- if (band2Bg) {
16671
- style.backgroundColor = band2Bg;
17301
+ if (applyStyleFill(styleEntry.band2HFill, colorScheme, style, '')) {
16672
17302
  applyStyleText(styleEntry.band2HText, colorScheme, style);
16673
17303
  applied = true;
16674
17304
  }
@@ -16683,21 +17313,19 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16683
17313
  if (!skipCol) {
16684
17314
  const colCycle = Math.max(tableData.bandColCycle ?? 1, 1);
16685
17315
  const colBandGroup = Math.floor(colBandIndex / colCycle) % 2;
17316
+ // Column banding yields to row banding when both apply to this cell.
17317
+ const canOverride = !style.backgroundColor || !tableData.bandedRows;
16686
17318
  if (colBandGroup === 0) {
16687
- if (!style.backgroundColor || !tableData.bandedRows) {
16688
- style.backgroundColor = resolveFill(styleEntry?.band1VFill, 'rgba(217, 226, 243, 0.35)');
17319
+ if (canOverride) {
17320
+ applyStyleFill(styleEntry?.band1VFill, colorScheme, style, 'rgba(217, 226, 243, 0.35)');
16689
17321
  applyStyleText(styleEntry?.band1VText, colorScheme, style);
16690
17322
  applied = true;
16691
17323
  }
16692
17324
  }
16693
- else if (styleEntry?.band2VFill) {
16694
- if (!style.backgroundColor || !tableData.bandedRows) {
16695
- const band2Bg = resolveFill(styleEntry.band2VFill, '');
16696
- if (band2Bg) {
16697
- style.backgroundColor = band2Bg;
16698
- applyStyleText(styleEntry.band2VText, colorScheme, style);
16699
- applied = true;
16700
- }
17325
+ else if (styleEntry?.band2VFill && canOverride) {
17326
+ if (applyStyleFill(styleEntry.band2VFill, colorScheme, style, '')) {
17327
+ applyStyleText(styleEntry.band2VText, colorScheme, style);
17328
+ applied = true;
16701
17329
  }
16702
17330
  }
16703
17331
  }
@@ -16705,7 +17333,7 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16705
17333
  // ── Header row (first row). ──
16706
17334
  if (tableData.firstRowHeader && rowIndex === 0) {
16707
17335
  style.fontWeight = 700;
16708
- style.backgroundColor = resolveFill(styleEntry?.firstRowFill, 'rgba(68, 114, 196, 0.85)');
17336
+ applyStyleFill(styleEntry?.firstRowFill, colorScheme, style, 'rgba(68, 114, 196, 0.85)');
16709
17337
  style.color = '#ffffff';
16710
17338
  applyStyleText(styleEntry?.firstRowText, colorScheme, style);
16711
17339
  applied = true;
@@ -16714,10 +17342,7 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16714
17342
  if (tableData.lastRow && rowIndex === rowCount - 1) {
16715
17343
  style.fontWeight = 700;
16716
17344
  if (styleEntry?.lastRowFill) {
16717
- const lastRowBg = resolveFill(styleEntry.lastRowFill, '');
16718
- if (lastRowBg) {
16719
- style.backgroundColor = lastRowBg;
16720
- }
17345
+ applyStyleFill(styleEntry.lastRowFill, colorScheme, style, '');
16721
17346
  }
16722
17347
  const borderColor = resolveFill(styleEntry?.firstRowFill, 'rgba(68, 114, 196, 0.7)');
16723
17348
  style.borderTop = `2px solid ${borderColor}`;
@@ -16728,10 +17353,7 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16728
17353
  if (tableData.firstCol && cellIndex === 0) {
16729
17354
  style.fontWeight = 700;
16730
17355
  if (styleEntry?.firstColFill) {
16731
- const firstColBg = resolveFill(styleEntry.firstColFill, '');
16732
- if (firstColBg) {
16733
- style.backgroundColor = firstColBg;
16734
- }
17356
+ applyStyleFill(styleEntry.firstColFill, colorScheme, style, '');
16735
17357
  }
16736
17358
  applyStyleText(styleEntry?.firstColText, colorScheme, style);
16737
17359
  applied = true;
@@ -16740,14 +17362,46 @@ function getTableCellBandStyle(tableData, rowIndex, cellIndex, rowCount, columnC
16740
17362
  if (tableData.lastCol && cellIndex === columnCount - 1) {
16741
17363
  style.fontWeight = 700;
16742
17364
  if (styleEntry?.lastColFill) {
16743
- const lastColBg = resolveFill(styleEntry.lastColFill, '');
16744
- if (lastColBg) {
16745
- style.backgroundColor = lastColBg;
16746
- }
17365
+ applyStyleFill(styleEntry.lastColFill, colorScheme, style, '');
16747
17366
  }
16748
17367
  applyStyleText(styleEntry?.lastColText, colorScheme, style);
16749
17368
  applied = true;
16750
17369
  }
17370
+ // ── Corner cells (highest fill/text precedence, issue #95). ──
17371
+ // Each corner overrides the intersection of a first/last row with a
17372
+ // first/last column (CT_TableStyle, ECMA-376 §21.1.3.16): nw = top-left,
17373
+ // ne = top-right, sw = bottom-left, se = bottom-right. Only applies when
17374
+ // both the row and column emphasis are active for this cell.
17375
+ if (styleEntry) {
17376
+ const atTop = Boolean(tableData.firstRowHeader) && rowIndex === 0;
17377
+ const atBottom = Boolean(tableData.lastRow) && rowIndex === rowCount - 1;
17378
+ const atLeft = Boolean(tableData.firstCol) && cellIndex === 0;
17379
+ const atRight = Boolean(tableData.lastCol) && cellIndex === columnCount - 1;
17380
+ let cornerFill;
17381
+ let cornerText = undefined;
17382
+ if (atTop && atLeft) {
17383
+ cornerFill = styleEntry.nwCellFill;
17384
+ cornerText = styleEntry.nwCellText;
17385
+ }
17386
+ else if (atTop && atRight) {
17387
+ cornerFill = styleEntry.neCellFill;
17388
+ cornerText = styleEntry.neCellText;
17389
+ }
17390
+ else if (atBottom && atLeft) {
17391
+ cornerFill = styleEntry.swCellFill;
17392
+ cornerText = styleEntry.swCellText;
17393
+ }
17394
+ else if (atBottom && atRight) {
17395
+ cornerFill = styleEntry.seCellFill;
17396
+ cornerText = styleEntry.seCellText;
17397
+ }
17398
+ if (cornerFill && applyStyleFill(cornerFill, colorScheme, style, '')) {
17399
+ applied = true;
17400
+ }
17401
+ if (applyStyleText(cornerText, colorScheme, style)) {
17402
+ applied = true;
17403
+ }
17404
+ }
16751
17405
  // ── Table-style borders (issue #71). ──
16752
17406
  // Resolve gridlines/edges the cell inherits from the table style and let
16753
17407
  // them supersede the hardcoded total-row line above. Per-cell explicit
@@ -23938,6 +24592,9 @@ function waypointsToPathD(waypoints) {
23938
24592
  /**
23939
24593
  * Compute connection sites for a rectangular bounding box. Returns the four
23940
24594
  * edge midpoints in element-local coordinates: top, right, bottom, left.
24595
+ *
24596
+ * This is the fallback used for shapes whose real connection sites are
24597
+ * unknown (preset shapes without a parsed `a:cxnLst`).
23941
24598
  */
23942
24599
  function getConnectionSites(width, height) {
23943
24600
  return [
@@ -23947,6 +24604,36 @@ function getConnectionSites(width, height) {
23947
24604
  { x: 0, y: height / 2, index: 3 }, // left center
23948
24605
  ];
23949
24606
  }
24607
+ /**
24608
+ * Resolve the connection sites of a shape element in element-local pixel
24609
+ * coordinates.
24610
+ *
24611
+ * When the shape carries typed custom-geometry connection sites (parsed from
24612
+ * `a:custGeom/a:cxnLst/a:cxn`), each `a:pos` formula is evaluated against the
24613
+ * shape's path coordinate space and scaled to the element's pixel box, so a
24614
+ * connector referencing `stCxn/@idx` on a non-rectangular shape attaches near
24615
+ * the real site rather than collapsing to an edge midpoint. Shapes with no
24616
+ * known sites fall back to the four edge midpoints.
24617
+ */
24618
+ function getShapeConnectionSites(shape) {
24619
+ const geo = shape;
24620
+ const cxn = geo.customGeometryConnectionSites;
24621
+ if (!cxn || cxn.length === 0) {
24622
+ return getConnectionSites(shape.width, shape.height);
24623
+ }
24624
+ // Path coordinate space the `a:pos` formulas are expressed in. Fall back to
24625
+ // the element's pixel dimensions (scale factor 1) when unavailable.
24626
+ const pathW = geo.pathWidth && geo.pathWidth > 0 ? geo.pathWidth : shape.width;
24627
+ const pathH = geo.pathHeight && geo.pathHeight > 0 ? geo.pathHeight : shape.height;
24628
+ const vars = createBuiltinVariables({ w: pathW, h: pathH });
24629
+ const scaleX = pathW > 0 ? shape.width / pathW : 1;
24630
+ const scaleY = pathH > 0 ? shape.height / pathH : 1;
24631
+ return cxn.map((site, index) => ({
24632
+ x: resolveCoordinate(site.posX, vars) * scaleX,
24633
+ y: resolveCoordinate(site.posY, vars) * scaleY,
24634
+ index,
24635
+ }));
24636
+ }
23950
24637
  /**
23951
24638
  * Find all connectors on the slide that reference any of the given element IDs
23952
24639
  * via `connectorStartConnection`/`connectorEndConnection`, and recalculate
@@ -24006,7 +24693,7 @@ function computeConnectorGeometry(connector, startConn, endConn, elementMap) {
24006
24693
  if (!startShape) {
24007
24694
  return null;
24008
24695
  }
24009
- const sites = getConnectionSites(startShape.width, startShape.height);
24696
+ const sites = getShapeConnectionSites(startShape);
24010
24697
  const siteIndex = startConn.connectionSiteIndex ?? 0;
24011
24698
  const site = sites[siteIndex] ?? sites[0];
24012
24699
  sx = startShape.x + site.x;
@@ -24024,7 +24711,7 @@ function computeConnectorGeometry(connector, startConn, endConn, elementMap) {
24024
24711
  if (!endShape) {
24025
24712
  return null;
24026
24713
  }
24027
- const sites = getConnectionSites(endShape.width, endShape.height);
24714
+ const sites = getShapeConnectionSites(endShape);
24028
24715
  const siteIndex = endConn.connectionSiteIndex ?? 0;
24029
24716
  const site = sites[siteIndex] ?? sites[0];
24030
24717
  ex = endShape.x + site.x;
@@ -24034,12 +24721,25 @@ function computeConnectorGeometry(connector, startConn, endConn, elementMap) {
24034
24721
  ex = connector.x + connector.width;
24035
24722
  ey = connector.y + connector.height;
24036
24723
  }
24724
+ // Recompute the flip flags from the relative order of the resolved
24725
+ // endpoints. `getConnectorPathGeometry` derives the start/end corners
24726
+ // (and hence line direction / arrowheads) from these flags:
24727
+ // flipH => start at local x=width, end at x=0
24728
+ // flipV => start at local y=height, end at y=0
24729
+ // Since the bounding box is anchored at min(sx,ex)/min(sy,ey), a start that
24730
+ // sits to the right of / below the end must be drawn from the far corner,
24731
+ // i.e. flipH when ex < sx and flipV when ey < sy. Equal coordinates keep the
24732
+ // flag false so a purely vertical / horizontal line is not spuriously flipped.
24733
+ const flipHorizontal = ex < sx;
24734
+ const flipVertical = ey < sy;
24037
24735
  return {
24038
24736
  id: connector.id,
24039
24737
  x: Math.min(sx, ex),
24040
24738
  y: Math.min(sy, ey),
24041
24739
  width: Math.abs(ex - sx) || 1,
24042
24740
  height: Math.abs(ey - sy) || 1,
24741
+ flipHorizontal,
24742
+ flipVertical,
24043
24743
  };
24044
24744
  }
24045
24745
  /**
@@ -24060,13 +24760,23 @@ function applyReroutedConnectors(elements, rerouted) {
24060
24760
  if (!update) {
24061
24761
  return el;
24062
24762
  }
24063
- return {
24763
+ const next = {
24064
24764
  ...el,
24065
24765
  x: update.x,
24066
24766
  y: update.y,
24067
24767
  width: update.width,
24068
24768
  height: update.height,
24069
24769
  };
24770
+ // Only overwrite the flip flags when the reroute recomputed them, so
24771
+ // callers that build ReroutedConnector without flip data (e.g. tests or
24772
+ // non-endpoint updates) leave the connector's existing flags intact.
24773
+ if (update.flipHorizontal !== undefined) {
24774
+ next.flipHorizontal = update.flipHorizontal;
24775
+ }
24776
+ if (update.flipVertical !== undefined) {
24777
+ next.flipVertical = update.flipVertical;
24778
+ }
24779
+ return next;
24070
24780
  });
24071
24781
  }
24072
24782
 
@@ -27882,6 +28592,322 @@ const DEFAULT_TRANSITION_DURATION_MS$1 = 1000;
27882
28592
  /** Easing applied to every transition animation. */
27883
28593
  const EASE = 'ease-in-out';
27884
28594
 
28595
+ /**
28596
+ * `p14-transition-keyframes` — CSS `@keyframes` for the 18 additional Office
28597
+ * 2010 (`p14` namespace) slide transitions, complementing the core
28598
+ * `slide-transition-keyframes`. All names share the `pptx-tr-*` prefix.
28599
+ *
28600
+ * Split into two string blocks purely to keep individual definitions grouped;
28601
+ * {@link P14_TRANSITION_KEYFRAMES_ALL} concatenates both for one-shot injection,
28602
+ * while {@link P14_TRANSITION_KEYFRAMES} / {@link P14_TRANSITION_KEYFRAMES_2}
28603
+ * preserve the React binding's original two-part public surface.
28604
+ *
28605
+ * @module render/p14-transition-keyframes
28606
+ */
28607
+ /** Part 1: conveyor / doors / ferris / flash / flythrough / gallery / glitter / honeycomb / pan. */
28608
+ const P14_TRANSITION_KEYFRAMES = `
28609
+ /* ── Conveyor (translate X with staggered timing) ──────────────────── */
28610
+ @keyframes pptx-tr-conveyor-in-from-right {
28611
+ from { transform: translateX(100%) rotateY(-30deg); }
28612
+ 60% { transform: translateX(20%) rotateY(-10deg); }
28613
+ to { transform: translateX(0) rotateY(0deg); }
28614
+ }
28615
+ @keyframes pptx-tr-conveyor-out-to-left {
28616
+ from { transform: translateX(0) rotateY(0deg); }
28617
+ 40% { transform: translateX(-20%) rotateY(10deg); }
28618
+ to { transform: translateX(-100%) rotateY(30deg); }
28619
+ }
28620
+ @keyframes pptx-tr-conveyor-in-from-left {
28621
+ from { transform: translateX(-100%) rotateY(30deg); }
28622
+ 60% { transform: translateX(-20%) rotateY(10deg); }
28623
+ to { transform: translateX(0) rotateY(0deg); }
28624
+ }
28625
+ @keyframes pptx-tr-conveyor-out-to-right {
28626
+ from { transform: translateX(0) rotateY(0deg); }
28627
+ 40% { transform: translateX(20%) rotateY(-10deg); }
28628
+ to { transform: translateX(100%) rotateY(-30deg); }
28629
+ }
28630
+
28631
+ /* ── Doors (clip-path from center split) ──────────────────────────── */
28632
+ @keyframes pptx-tr-doors-horz {
28633
+ from { clip-path: inset(0 50%); }
28634
+ to { clip-path: inset(0 0); }
28635
+ }
28636
+ @keyframes pptx-tr-doors-vert {
28637
+ from { clip-path: inset(50% 0); }
28638
+ to { clip-path: inset(0 0); }
28639
+ }
28640
+
28641
+ /* ── Ferris (rotate elements around center) ───────────────────────── */
28642
+ @keyframes pptx-tr-ferris-in-from-right {
28643
+ from { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }
28644
+ to { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28645
+ }
28646
+ @keyframes pptx-tr-ferris-out-to-left {
28647
+ from { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28648
+ to { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }
28649
+ }
28650
+ @keyframes pptx-tr-ferris-in-from-left {
28651
+ from { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }
28652
+ to { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28653
+ }
28654
+ @keyframes pptx-tr-ferris-out-to-right {
28655
+ from { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28656
+ to { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }
28657
+ }
28658
+
28659
+ /* ── Flash (bright flash opacity burst) ──────────────────────────── */
28660
+ @keyframes pptx-tr-flash-white {
28661
+ 0% { opacity: 1; }
28662
+ 30% { opacity: 0; }
28663
+ 50% { opacity: 0; }
28664
+ 100% { opacity: 1; }
28665
+ }
28666
+ @keyframes pptx-tr-flash-in {
28667
+ 0% { opacity: 0; }
28668
+ 50% { opacity: 0; }
28669
+ 70% { opacity: 1; }
28670
+ 100% { opacity: 1; }
28671
+ }
28672
+
28673
+ /* ── Flythrough (scale + translate Z-axis feel) ──────────────────── */
28674
+ @keyframes pptx-tr-flythrough-in {
28675
+ from { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }
28676
+ to { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28677
+ }
28678
+ @keyframes pptx-tr-flythrough-out {
28679
+ from { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28680
+ to { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }
28681
+ }
28682
+ @keyframes pptx-tr-flythrough-reverse-in {
28683
+ from { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }
28684
+ to { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28685
+ }
28686
+ @keyframes pptx-tr-flythrough-reverse-out {
28687
+ from { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28688
+ to { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }
28689
+ }
28690
+
28691
+ /* ── Gallery (translate with perspective) ─────────────────────────── */
28692
+ @keyframes pptx-tr-gallery-in-from-right {
28693
+ from { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }
28694
+ to { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28695
+ }
28696
+ @keyframes pptx-tr-gallery-out-to-left {
28697
+ from { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28698
+ to { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }
28699
+ }
28700
+ @keyframes pptx-tr-gallery-in-from-left {
28701
+ from { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }
28702
+ to { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28703
+ }
28704
+ @keyframes pptx-tr-gallery-out-to-right {
28705
+ from { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28706
+ to { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }
28707
+ }
28708
+
28709
+ /* ── Glitter (particle dissolve effect) ──────────────────────────── */
28710
+ @keyframes pptx-tr-glitter-in {
28711
+ from { opacity: 0; filter: brightness(1.5) contrast(1.3) blur(2px); }
28712
+ 60% { opacity: 0.7; filter: brightness(1.2) contrast(1.1) blur(1px); }
28713
+ to { opacity: 1; filter: brightness(1) contrast(1) blur(0); }
28714
+ }
28715
+
28716
+ /* ── Honeycomb (hexagonal reveal) ────────────────────────────────── */
28717
+ @keyframes pptx-tr-honeycomb-in {
28718
+ from {
28719
+ clip-path: polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%);
28720
+ opacity: 0;
28721
+ }
28722
+ to {
28723
+ clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
28724
+ opacity: 1;
28725
+ }
28726
+ }
28727
+ @keyframes pptx-tr-honeycomb-out {
28728
+ from { opacity: 1; }
28729
+ to { opacity: 0; filter: blur(2px); }
28730
+ }
28731
+
28732
+ /* ── Pan (large-scale translate) ─────────────────────────────────── */
28733
+ @keyframes pptx-tr-pan-from-right {
28734
+ from { transform: translateX(100%); }
28735
+ to { transform: translateX(0); }
28736
+ }
28737
+ @keyframes pptx-tr-pan-to-left {
28738
+ from { transform: translateX(0); }
28739
+ to { transform: translateX(-100%); }
28740
+ }
28741
+ @keyframes pptx-tr-pan-from-left {
28742
+ from { transform: translateX(-100%); }
28743
+ to { transform: translateX(0); }
28744
+ }
28745
+ @keyframes pptx-tr-pan-to-right {
28746
+ from { transform: translateX(0); }
28747
+ to { transform: translateX(100%); }
28748
+ }
28749
+ @keyframes pptx-tr-pan-from-bottom {
28750
+ from { transform: translateY(100%); }
28751
+ to { transform: translateY(0); }
28752
+ }
28753
+ @keyframes pptx-tr-pan-to-top {
28754
+ from { transform: translateY(0); }
28755
+ to { transform: translateY(-100%); }
28756
+ }
28757
+ @keyframes pptx-tr-pan-from-top {
28758
+ from { transform: translateY(-100%); }
28759
+ to { transform: translateY(0); }
28760
+ }
28761
+ @keyframes pptx-tr-pan-to-bottom {
28762
+ from { transform: translateY(0); }
28763
+ to { transform: translateY(100%); }
28764
+ }
28765
+ `;
28766
+ /** Part 2: prism / reveal / ripple / shred / switch / vortex / warp / wheelReverse / window. */
28767
+ const P14_TRANSITION_KEYFRAMES_2 = `
28768
+ /* ── Prism (3D rotation via perspective transform) ───────────────── */
28769
+ @keyframes pptx-tr-prism-in-from-right {
28770
+ from { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }
28771
+ to { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28772
+ }
28773
+ @keyframes pptx-tr-prism-out-to-left {
28774
+ from { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28775
+ to { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }
28776
+ }
28777
+ @keyframes pptx-tr-prism-in-from-left {
28778
+ from { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }
28779
+ to { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28780
+ }
28781
+ @keyframes pptx-tr-prism-out-to-right {
28782
+ from { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28783
+ to { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }
28784
+ }
28785
+ @keyframes pptx-tr-prism-in-from-bottom {
28786
+ from { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }
28787
+ to { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28788
+ }
28789
+ @keyframes pptx-tr-prism-out-to-top {
28790
+ from { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28791
+ to { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }
28792
+ }
28793
+ @keyframes pptx-tr-prism-in-from-top {
28794
+ from { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }
28795
+ to { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28796
+ }
28797
+ @keyframes pptx-tr-prism-out-to-bottom {
28798
+ from { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28799
+ to { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }
28800
+ }
28801
+
28802
+ /* ── Reveal (slide away reveal) ──────────────────────────────────── */
28803
+ @keyframes pptx-tr-reveal-out-to-right {
28804
+ from { transform: translateX(0); }
28805
+ to { transform: translateX(100%); }
28806
+ }
28807
+ @keyframes pptx-tr-reveal-out-to-left {
28808
+ from { transform: translateX(0); }
28809
+ to { transform: translateX(-100%); }
28810
+ }
28811
+ @keyframes pptx-tr-reveal-in {
28812
+ from { opacity: 0.5; }
28813
+ to { opacity: 1; }
28814
+ }
28815
+
28816
+ /* ── Ripple (expanding ring clip-path) ───────────────────────────── */
28817
+ @keyframes pptx-tr-ripple-in {
28818
+ from { clip-path: circle(0% at 50% 50%); opacity: 0.5; }
28819
+ 30% { clip-path: circle(20% at 50% 50%); opacity: 0.7; }
28820
+ 60% { clip-path: circle(50% at 50% 50%); opacity: 0.9; }
28821
+ to { clip-path: circle(75% at 50% 50%); opacity: 1; }
28822
+ }
28823
+
28824
+ /* ── Shred (fragmented clip-path pieces) ─────────────────────────── */
28825
+ @keyframes pptx-tr-shred-strips-in {
28826
+ from { clip-path: inset(0 100% 0 0); opacity: 0; }
28827
+ 30% { clip-path: inset(0 60% 0 0); opacity: 0.5; }
28828
+ to { clip-path: inset(0); opacity: 1; }
28829
+ }
28830
+ @keyframes pptx-tr-shred-rectangles-in {
28831
+ from { clip-path: inset(50%); opacity: 0; }
28832
+ 40% { clip-path: inset(20%); opacity: 0.6; }
28833
+ to { clip-path: inset(0); opacity: 1; }
28834
+ }
28835
+ @keyframes pptx-tr-shred-out {
28836
+ from { opacity: 1; }
28837
+ to { opacity: 0; filter: blur(2px); }
28838
+ }
28839
+
28840
+ /* ── Switch (flip/rotate swap) ───────────────────────────────────── */
28841
+ @keyframes pptx-tr-switch-in-from-right {
28842
+ from { transform: perspective(800px) rotateY(-180deg); opacity: 0; }
28843
+ to { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28844
+ }
28845
+ @keyframes pptx-tr-switch-out-to-left {
28846
+ from { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28847
+ to { transform: perspective(800px) rotateY(180deg); opacity: 0; }
28848
+ }
28849
+ @keyframes pptx-tr-switch-in-from-left {
28850
+ from { transform: perspective(800px) rotateY(180deg); opacity: 0; }
28851
+ to { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28852
+ }
28853
+ @keyframes pptx-tr-switch-out-to-right {
28854
+ from { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28855
+ to { transform: perspective(800px) rotateY(-180deg); opacity: 0; }
28856
+ }
28857
+
28858
+ /* ── Vortex (rotate + scale spiral) ──────────────────────────────── */
28859
+ @keyframes pptx-tr-vortex-in {
28860
+ from { transform: rotate(720deg) scale(0); opacity: 0; }
28861
+ to { transform: rotate(0deg) scale(1); opacity: 1; }
28862
+ }
28863
+ @keyframes pptx-tr-vortex-out {
28864
+ from { transform: rotate(0deg) scale(1); opacity: 1; }
28865
+ to { transform: rotate(-720deg) scale(0); opacity: 0; }
28866
+ }
28867
+
28868
+ /* ── Warp (skew distortion) ──────────────────────────────────────── */
28869
+ @keyframes pptx-tr-warp-in {
28870
+ from { transform: scale(0.3) skewX(30deg) skewY(15deg); opacity: 0; }
28871
+ 50% { transform: scale(0.8) skewX(-5deg) skewY(-3deg); opacity: 0.7; }
28872
+ to { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; }
28873
+ }
28874
+ @keyframes pptx-tr-warp-out {
28875
+ from { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; }
28876
+ 50% { transform: scale(0.8) skewX(5deg) skewY(3deg); opacity: 0.7; }
28877
+ to { transform: scale(0.3) skewX(-30deg) skewY(-15deg); opacity: 0; }
28878
+ }
28879
+ @keyframes pptx-tr-warp-reverse-in {
28880
+ from { transform: scale(3) skewX(-20deg) skewY(-10deg); opacity: 0; filter: blur(4px); }
28881
+ to { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; filter: blur(0); }
28882
+ }
28883
+ @keyframes pptx-tr-warp-reverse-out {
28884
+ from { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; filter: blur(0); }
28885
+ to { transform: scale(3) skewX(20deg) skewY(10deg); opacity: 0; filter: blur(4px); }
28886
+ }
28887
+
28888
+ /* ── WheelReverse (reverse wheel rotation) ───────────────────────── */
28889
+ @keyframes pptx-tr-wheel-reverse-in {
28890
+ from { clip-path: circle(0% at 50% 50%); transform: rotate(180deg); }
28891
+ to { clip-path: circle(75% at 50% 50%); transform: rotate(0deg); }
28892
+ }
28893
+
28894
+ /* ── Window (scale from center with border) ──────────────────────── */
28895
+ @keyframes pptx-tr-window-horz {
28896
+ from { clip-path: inset(0 50%); }
28897
+ to { clip-path: inset(0 0); }
28898
+ }
28899
+ @keyframes pptx-tr-window-vert {
28900
+ from { clip-path: inset(50% 0); }
28901
+ to { clip-path: inset(0 0); }
28902
+ }
28903
+ @keyframes pptx-tr-window-out {
28904
+ from { opacity: 1; transform: scale(1); }
28905
+ to { opacity: 0; transform: scale(0.9); }
28906
+ }
28907
+ `;
28908
+ /** Both p14 keyframe blocks concatenated, for single `<style>` injection. */
28909
+ const P14_TRANSITION_KEYFRAMES_ALL = `${P14_TRANSITION_KEYFRAMES}\n${P14_TRANSITION_KEYFRAMES_2}`;
28910
+
27885
28911
  /**
27886
28912
  * `slide-transition-keyframes` — the full `@keyframes` block backing every
27887
28913
  * resolved slide transition. Inject it once per overlay via a `<style>` element
@@ -27896,9 +28922,14 @@ const EASE = 'ease-in-out';
27896
28922
  * same string — the bindings historically exported it under both names, so the
27897
28923
  * alias preserves their public surface.
27898
28924
  *
28925
+ * The faithful Office 2010 (`p14`) keyframes are appended (via
28926
+ * {@link P14_TRANSITION_KEYFRAMES_ALL}) so the exotic / 3-D transitions routed
28927
+ * through `getP14TransitionAnimations` animate wherever this block is injected,
28928
+ * with no per-binding wiring.
28929
+ *
27899
28930
  * @module render/slide-transition-keyframes
27900
28931
  */
27901
- const SLIDE_TRANSITION_KEYFRAMES = `
28932
+ const CORE_SLIDE_TRANSITION_KEYFRAMES = `
27902
28933
  /* ── Fade ───────────────────────────────────────────────────────────── */
27903
28934
  @keyframes pptx-tr-fade-in {
27904
28935
  from { opacity: 0; }
@@ -28161,641 +29192,18 @@ const SLIDE_TRANSITION_KEYFRAMES = `
28161
29192
  to { clip-path: circle(75% at 50% 50%); transform: rotate(0deg); }
28162
29193
  }
28163
29194
  `;
29195
+ /**
29196
+ * The full slide-transition `@keyframes` block: the classic set plus the
29197
+ * faithful Office 2010 (`p14`) keyframes, so both the classic and exotic / 3-D
29198
+ * transitions animate wherever this single string is injected.
29199
+ */
29200
+ const SLIDE_TRANSITION_KEYFRAMES = `${CORE_SLIDE_TRANSITION_KEYFRAMES}\n${P14_TRANSITION_KEYFRAMES_ALL}`;
28164
29201
  /**
28165
29202
  * Alias of {@link SLIDE_TRANSITION_KEYFRAMES} under the `_CSS` name the Vue
28166
29203
  * binding historically exported.
28167
29204
  */
28168
29205
  const SLIDE_TRANSITION_KEYFRAMES_CSS = SLIDE_TRANSITION_KEYFRAMES;
28169
29206
 
28170
- /**
28171
- * `slide-transition-css` — pure mapping from a {@link PptxSlideTransition}
28172
- * (type + duration + direction/orientation) to the CSS `animation` shorthand
28173
- * pieces used by each binding's presentation-mode transition overlay during a
28174
- * slide change.
28175
- *
28176
- * Consolidates the React `transition-resolver` / `transition-helpers` /
28177
- * `transition-keyframes` trio, the Vue `slide-transition-css`, and the Angular
28178
- * `transition-helpers` into one framework-agnostic module:
28179
- *
28180
- * - {@link getSlideTransitionAnimations} resolves a transition to the
28181
- * `animation` shorthand strings for the outgoing (old) and incoming (new)
28182
- * slide layers, plus whether the outgoing layer sits on top.
28183
- * - the `@keyframes` referenced live in `slide-transition-keyframes`
28184
- * (`SLIDE_TRANSITION_KEYFRAMES`), injected once via a `<style>` element.
28185
- *
28186
- * Superset note: the exotic / 3-D transition family (`pan`/`gallery`/
28187
- * `conveyor`/`reveal`/`doors`/`switch`/`flythrough`/`ferris`/`prism`/`ripple`/
28188
- * `honeycomb`/`glitter`/`shred`/`flash`) is approximated with the closest
28189
- * well-tested 2-D case (originally an Angular-only refinement) rather than a
28190
- * plain fade. Truly-unknown types still fall back to a symmetrical cross-fade.
28191
- * A more faithful per-effect p14 keyframe set is available separately via
28192
- * `p14-transition-keyframes` + {@link getP14TransitionAnimations}.
28193
- *
28194
- * Everything here is pure and unit-testable: no framework imports, no DOM.
28195
- *
28196
- * @module render/slide-transition-css
28197
- */
28198
- /**
28199
- * Map a {@link PptxTransitionType} (+ duration/direction/orient/spokes) to the
28200
- * concrete CSS `animation` descriptors for the outgoing and incoming layers.
28201
- *
28202
- * Unknown types fall back to a symmetrical cross-fade.
28203
- */
28204
- function getSlideTransitionAnimations(type, durationMs, direction, orient, spokes) {
28205
- const dur = `${durationMs}ms`;
28206
- // `spokes` is reserved for future wheel spoke-count support; forwarded only
28207
- // through recursive calls (random/pull/exotic aliases).
28208
- void spokes;
28209
- switch (type) {
28210
- case 'none':
28211
- case 'cut':
28212
- return INSTANT;
28213
- case 'fade':
28214
- return {
28215
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28216
- incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
28217
- outgoingOnTop: true,
28218
- };
28219
- case 'push': {
28220
- const dir = resolveDirection(direction, 'left');
28221
- const configs = {
28222
- left: {
28223
- outgoing: `pptx-tr-push-out-to-left ${dur} ${EASE} forwards`,
28224
- incoming: `pptx-tr-push-in-from-right ${dur} ${EASE} forwards`,
28225
- outgoingOnTop: false,
28226
- },
28227
- right: {
28228
- outgoing: `pptx-tr-push-out-to-right ${dur} ${EASE} forwards`,
28229
- incoming: `pptx-tr-push-in-from-left ${dur} ${EASE} forwards`,
28230
- outgoingOnTop: false,
28231
- },
28232
- up: {
28233
- outgoing: `pptx-tr-push-out-to-top ${dur} ${EASE} forwards`,
28234
- incoming: `pptx-tr-push-in-from-bottom ${dur} ${EASE} forwards`,
28235
- outgoingOnTop: false,
28236
- },
28237
- down: {
28238
- outgoing: `pptx-tr-push-out-to-bottom ${dur} ${EASE} forwards`,
28239
- incoming: `pptx-tr-push-in-from-top ${dur} ${EASE} forwards`,
28240
- outgoingOnTop: false,
28241
- },
28242
- };
28243
- return configs[dir];
28244
- }
28245
- case 'wipe': {
28246
- const dir = resolveDirection(direction, 'left');
28247
- const wipeNames = {
28248
- left: `pptx-tr-wipe-from-left ${dur} ${EASE} forwards`,
28249
- right: `pptx-tr-wipe-from-right ${dur} ${EASE} forwards`,
28250
- up: `pptx-tr-wipe-from-top ${dur} ${EASE} forwards`,
28251
- down: `pptx-tr-wipe-from-bottom ${dur} ${EASE} forwards`,
28252
- };
28253
- return {
28254
- outgoing: 'none',
28255
- incoming: wipeNames[dir],
28256
- outgoingOnTop: false,
28257
- };
28258
- }
28259
- case 'cover': {
28260
- const dir = resolveDirection8(direction, 'left');
28261
- const coverMap = {
28262
- left: `pptx-tr-cover-from-left ${dur} ${EASE} forwards`,
28263
- right: `pptx-tr-cover-from-right ${dur} ${EASE} forwards`,
28264
- up: `pptx-tr-cover-from-top ${dur} ${EASE} forwards`,
28265
- down: `pptx-tr-cover-from-bottom ${dur} ${EASE} forwards`,
28266
- lu: `pptx-tr-cover-from-lu ${dur} ${EASE} forwards`,
28267
- ld: `pptx-tr-cover-from-ld ${dur} ${EASE} forwards`,
28268
- ru: `pptx-tr-cover-from-ru ${dur} ${EASE} forwards`,
28269
- rd: `pptx-tr-cover-from-rd ${dur} ${EASE} forwards`,
28270
- };
28271
- return {
28272
- outgoing: 'none',
28273
- incoming: coverMap[dir],
28274
- outgoingOnTop: false,
28275
- };
28276
- }
28277
- case 'uncover': {
28278
- const dir = resolveDirection8(direction, 'left');
28279
- const uncoverMap = {
28280
- left: `pptx-tr-uncover-to-left ${dur} ${EASE} forwards`,
28281
- right: `pptx-tr-uncover-to-right ${dur} ${EASE} forwards`,
28282
- up: `pptx-tr-uncover-to-top ${dur} ${EASE} forwards`,
28283
- down: `pptx-tr-uncover-to-bottom ${dur} ${EASE} forwards`,
28284
- lu: `pptx-tr-uncover-to-lu ${dur} ${EASE} forwards`,
28285
- ld: `pptx-tr-uncover-to-ld ${dur} ${EASE} forwards`,
28286
- ru: `pptx-tr-uncover-to-ru ${dur} ${EASE} forwards`,
28287
- rd: `pptx-tr-uncover-to-rd ${dur} ${EASE} forwards`,
28288
- };
28289
- return {
28290
- outgoing: uncoverMap[dir],
28291
- incoming: 'none',
28292
- outgoingOnTop: true,
28293
- };
28294
- }
28295
- case 'split': {
28296
- const o = resolveOrientation(undefined, orient);
28297
- const isOut = direction !== 'in';
28298
- if (isOut) {
28299
- return {
28300
- outgoing: 'none',
28301
- incoming: o === 'vert'
28302
- ? `pptx-tr-split-v-out ${dur} ${EASE} forwards`
28303
- : `pptx-tr-split-h-out ${dur} ${EASE} forwards`,
28304
- outgoingOnTop: false,
28305
- };
28306
- }
28307
- return {
28308
- outgoing: o === 'vert'
28309
- ? `pptx-tr-split-v-in ${dur} ${EASE} forwards`
28310
- : `pptx-tr-split-h-in ${dur} ${EASE} forwards`,
28311
- incoming: 'none',
28312
- outgoingOnTop: true,
28313
- };
28314
- }
28315
- case 'dissolve':
28316
- return {
28317
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28318
- incoming: `pptx-tr-dissolve-in ${dur} ${EASE} forwards`,
28319
- outgoingOnTop: true,
28320
- };
28321
- case 'circle':
28322
- return {
28323
- outgoing: 'none',
28324
- incoming: `pptx-tr-circle-in ${dur} ${EASE} forwards`,
28325
- outgoingOnTop: false,
28326
- };
28327
- case 'diamond':
28328
- return {
28329
- outgoing: 'none',
28330
- incoming: `pptx-tr-diamond-in ${dur} ${EASE} forwards`,
28331
- outgoingOnTop: false,
28332
- };
28333
- case 'plus':
28334
- return {
28335
- outgoing: 'none',
28336
- incoming: `pptx-tr-plus-in ${dur} ${EASE} forwards`,
28337
- outgoingOnTop: false,
28338
- };
28339
- case 'wedge':
28340
- return {
28341
- outgoing: 'none',
28342
- incoming: `pptx-tr-wedge-in ${dur} ${EASE} forwards`,
28343
- outgoingOnTop: false,
28344
- };
28345
- case 'wheel':
28346
- return {
28347
- outgoing: 'none',
28348
- incoming: `pptx-tr-wheel-in ${dur} ${EASE} forwards`,
28349
- outgoingOnTop: false,
28350
- };
28351
- case 'zoom':
28352
- return {
28353
- outgoing: `pptx-tr-zoom-out ${dur} ${EASE} forwards`,
28354
- incoming: `pptx-tr-zoom-in ${dur} ${EASE} forwards`,
28355
- outgoingOnTop: true,
28356
- };
28357
- case 'blinds': {
28358
- const o = resolveOrientation(direction, orient);
28359
- return {
28360
- outgoing: 'none',
28361
- incoming: o === 'vert'
28362
- ? `pptx-tr-blinds-v ${dur} ${EASE} forwards`
28363
- : `pptx-tr-blinds-h ${dur} ${EASE} forwards`,
28364
- outgoingOnTop: false,
28365
- };
28366
- }
28367
- case 'checker':
28368
- return {
28369
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28370
- incoming: `pptx-tr-checker-in ${dur} ${EASE} forwards`,
28371
- outgoingOnTop: true,
28372
- };
28373
- case 'comb': {
28374
- const o = resolveOrientation(direction, orient);
28375
- return {
28376
- outgoing: 'none',
28377
- incoming: o === 'vert'
28378
- ? `pptx-tr-comb-v ${dur} ${EASE} forwards`
28379
- : `pptx-tr-comb-h ${dur} ${EASE} forwards`,
28380
- outgoingOnTop: false,
28381
- };
28382
- }
28383
- case 'strips': {
28384
- const stripDir = direction === 'lu' || direction === 'ld' || direction === 'ru' || direction === 'rd'
28385
- ? direction
28386
- : 'lu';
28387
- return {
28388
- outgoing: 'none',
28389
- incoming: `pptx-tr-strips-${stripDir} ${dur} ${EASE} forwards`,
28390
- outgoingOnTop: false,
28391
- };
28392
- }
28393
- case 'randomBar': {
28394
- const o = resolveOrientation(direction, orient);
28395
- return {
28396
- outgoing: 'none',
28397
- incoming: o === 'vert'
28398
- ? `pptx-tr-randombar-v ${dur} ${EASE} forwards`
28399
- : `pptx-tr-randombar-h ${dur} ${EASE} forwards`,
28400
- outgoingOnTop: false,
28401
- };
28402
- }
28403
- case 'newsflash':
28404
- return {
28405
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28406
- incoming: `pptx-tr-newsflash-in ${dur} ${EASE} forwards`,
28407
- outgoingOnTop: false,
28408
- };
28409
- // `pull` is the directional alias of `uncover`.
28410
- case 'pull':
28411
- return getSlideTransitionAnimations('uncover', durationMs, direction, orient, spokes);
28412
- case 'morph':
28413
- return {
28414
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28415
- incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
28416
- outgoingOnTop: true,
28417
- };
28418
- case 'random': {
28419
- const randomType = RANDOM_ELIGIBLE_TYPES[Math.floor(Math.random() * RANDOM_ELIGIBLE_TYPES.length)];
28420
- return getSlideTransitionAnimations(randomType, durationMs, direction, orient, spokes);
28421
- }
28422
- // ── Exotic / 3-D transitions — approximated with the closest well-tested
28423
- // 2-D CSS behaviour (delegates to an existing case rather than emitting a
28424
- // plain fade). A faithful per-effect keyframe set is available via
28425
- // `getP14TransitionAnimations`.
28426
- case 'pan':
28427
- case 'gallery':
28428
- case 'conveyor':
28429
- return getSlideTransitionAnimations('push', durationMs, direction, orient, spokes);
28430
- case 'reveal':
28431
- return getSlideTransitionAnimations('wipe', durationMs, direction, orient, spokes);
28432
- case 'doors':
28433
- return getSlideTransitionAnimations('split', durationMs, direction, orient, spokes);
28434
- case 'switch':
28435
- case 'flythrough':
28436
- case 'ferris':
28437
- case 'prism':
28438
- return getSlideTransitionAnimations('zoom', durationMs, direction, orient, spokes);
28439
- case 'ripple':
28440
- case 'honeycomb':
28441
- case 'glitter':
28442
- case 'shred':
28443
- return getSlideTransitionAnimations('dissolve', durationMs, direction, orient, spokes);
28444
- case 'flash':
28445
- return getSlideTransitionAnimations('fade', durationMs, direction, orient, spokes);
28446
- // Fallback (unknown / not-yet-mapped type) — symmetrical cross-fade.
28447
- default:
28448
- return {
28449
- outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
28450
- incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
28451
- outgoingOnTop: true,
28452
- };
28453
- }
28454
- }
28455
- /**
28456
- * Convenience wrapper that reads everything off a {@link PptxSlideTransition},
28457
- * applying the React/Vue default duration when none is set. `none`/`cut` and a
28458
- * transition with a non-positive duration resolve to {@link INSTANT}.
28459
- */
28460
- function resolveSlideTransition(transition) {
28461
- if (!transition || transition.type === 'none' || transition.type === 'cut') {
28462
- return INSTANT;
28463
- }
28464
- const durationMs = typeof transition.durationMs === 'number' && transition.durationMs > 0
28465
- ? transition.durationMs
28466
- : DEFAULT_TRANSITION_DURATION_MS$1;
28467
- return getSlideTransitionAnimations(transition.type, durationMs, transition.direction, transition.orient, transition.spokes);
28468
- }
28469
- /**
28470
- * The effective duration (ms) for a transition under the React/Vue policy — the
28471
- * configured `durationMs`, or {@link DEFAULT_TRANSITION_DURATION_MS} when
28472
- * unset/invalid. `none`/`cut` resolve to `0` (instant).
28473
- */
28474
- function resolveTransitionDurationMs(transition) {
28475
- if (!transition || transition.type === 'none' || transition.type === 'cut') {
28476
- return 0;
28477
- }
28478
- return typeof transition.durationMs === 'number' && transition.durationMs > 0
28479
- ? transition.durationMs
28480
- : DEFAULT_TRANSITION_DURATION_MS$1;
28481
- }
28482
-
28483
- /**
28484
- * `p14-transition-keyframes` — CSS `@keyframes` for the 18 additional Office
28485
- * 2010 (`p14` namespace) slide transitions, complementing the core
28486
- * `slide-transition-keyframes`. All names share the `pptx-tr-*` prefix.
28487
- *
28488
- * Split into two string blocks purely to keep individual definitions grouped;
28489
- * {@link P14_TRANSITION_KEYFRAMES_ALL} concatenates both for one-shot injection,
28490
- * while {@link P14_TRANSITION_KEYFRAMES} / {@link P14_TRANSITION_KEYFRAMES_2}
28491
- * preserve the React binding's original two-part public surface.
28492
- *
28493
- * @module render/p14-transition-keyframes
28494
- */
28495
- /** Part 1: conveyor / doors / ferris / flash / flythrough / gallery / glitter / honeycomb / pan. */
28496
- const P14_TRANSITION_KEYFRAMES = `
28497
- /* ── Conveyor (translate X with staggered timing) ──────────────────── */
28498
- @keyframes pptx-tr-conveyor-in-from-right {
28499
- from { transform: translateX(100%) rotateY(-30deg); }
28500
- 60% { transform: translateX(20%) rotateY(-10deg); }
28501
- to { transform: translateX(0) rotateY(0deg); }
28502
- }
28503
- @keyframes pptx-tr-conveyor-out-to-left {
28504
- from { transform: translateX(0) rotateY(0deg); }
28505
- 40% { transform: translateX(-20%) rotateY(10deg); }
28506
- to { transform: translateX(-100%) rotateY(30deg); }
28507
- }
28508
- @keyframes pptx-tr-conveyor-in-from-left {
28509
- from { transform: translateX(-100%) rotateY(30deg); }
28510
- 60% { transform: translateX(-20%) rotateY(10deg); }
28511
- to { transform: translateX(0) rotateY(0deg); }
28512
- }
28513
- @keyframes pptx-tr-conveyor-out-to-right {
28514
- from { transform: translateX(0) rotateY(0deg); }
28515
- 40% { transform: translateX(20%) rotateY(-10deg); }
28516
- to { transform: translateX(100%) rotateY(-30deg); }
28517
- }
28518
-
28519
- /* ── Doors (clip-path from center split) ──────────────────────────── */
28520
- @keyframes pptx-tr-doors-horz {
28521
- from { clip-path: inset(0 50%); }
28522
- to { clip-path: inset(0 0); }
28523
- }
28524
- @keyframes pptx-tr-doors-vert {
28525
- from { clip-path: inset(50% 0); }
28526
- to { clip-path: inset(0 0); }
28527
- }
28528
-
28529
- /* ── Ferris (rotate elements around center) ───────────────────────── */
28530
- @keyframes pptx-tr-ferris-in-from-right {
28531
- from { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }
28532
- to { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28533
- }
28534
- @keyframes pptx-tr-ferris-out-to-left {
28535
- from { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28536
- to { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }
28537
- }
28538
- @keyframes pptx-tr-ferris-in-from-left {
28539
- from { transform: translateX(-80%) rotate(-45deg) scale(0.6); opacity: 0; }
28540
- to { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28541
- }
28542
- @keyframes pptx-tr-ferris-out-to-right {
28543
- from { transform: translateX(0) rotate(0deg) scale(1); opacity: 1; }
28544
- to { transform: translateX(80%) rotate(45deg) scale(0.6); opacity: 0; }
28545
- }
28546
-
28547
- /* ── Flash (bright flash opacity burst) ──────────────────────────── */
28548
- @keyframes pptx-tr-flash-white {
28549
- 0% { opacity: 1; }
28550
- 30% { opacity: 0; }
28551
- 50% { opacity: 0; }
28552
- 100% { opacity: 1; }
28553
- }
28554
- @keyframes pptx-tr-flash-in {
28555
- 0% { opacity: 0; }
28556
- 50% { opacity: 0; }
28557
- 70% { opacity: 1; }
28558
- 100% { opacity: 1; }
28559
- }
28560
-
28561
- /* ── Flythrough (scale + translate Z-axis feel) ──────────────────── */
28562
- @keyframes pptx-tr-flythrough-in {
28563
- from { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }
28564
- to { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28565
- }
28566
- @keyframes pptx-tr-flythrough-out {
28567
- from { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28568
- to { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }
28569
- }
28570
- @keyframes pptx-tr-flythrough-reverse-in {
28571
- from { transform: scale(0.1) translateZ(-200px); opacity: 0; filter: blur(8px); }
28572
- to { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28573
- }
28574
- @keyframes pptx-tr-flythrough-reverse-out {
28575
- from { transform: scale(1) translateZ(0); opacity: 1; filter: blur(0); }
28576
- to { transform: scale(4) translateZ(200px); opacity: 0; filter: blur(8px); }
28577
- }
28578
-
28579
- /* ── Gallery (translate with perspective) ─────────────────────────── */
28580
- @keyframes pptx-tr-gallery-in-from-right {
28581
- from { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }
28582
- to { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28583
- }
28584
- @keyframes pptx-tr-gallery-out-to-left {
28585
- from { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28586
- to { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }
28587
- }
28588
- @keyframes pptx-tr-gallery-in-from-left {
28589
- from { transform: perspective(800px) translateX(-100%) rotateY(45deg); opacity: 0.5; }
28590
- to { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28591
- }
28592
- @keyframes pptx-tr-gallery-out-to-right {
28593
- from { transform: perspective(800px) translateX(0) rotateY(0deg); opacity: 1; }
28594
- to { transform: perspective(800px) translateX(100%) rotateY(-45deg); opacity: 0.5; }
28595
- }
28596
-
28597
- /* ── Glitter (particle dissolve effect) ──────────────────────────── */
28598
- @keyframes pptx-tr-glitter-in {
28599
- from { opacity: 0; filter: brightness(1.5) contrast(1.3) blur(2px); }
28600
- 60% { opacity: 0.7; filter: brightness(1.2) contrast(1.1) blur(1px); }
28601
- to { opacity: 1; filter: brightness(1) contrast(1) blur(0); }
28602
- }
28603
-
28604
- /* ── Honeycomb (hexagonal reveal) ────────────────────────────────── */
28605
- @keyframes pptx-tr-honeycomb-in {
28606
- from {
28607
- clip-path: polygon(50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%, 50% 50%);
28608
- opacity: 0;
28609
- }
28610
- to {
28611
- clip-path: polygon(50% 0%, 100% 25%, 100% 75%, 50% 100%, 0% 75%, 0% 25%);
28612
- opacity: 1;
28613
- }
28614
- }
28615
- @keyframes pptx-tr-honeycomb-out {
28616
- from { opacity: 1; }
28617
- to { opacity: 0; filter: blur(2px); }
28618
- }
28619
-
28620
- /* ── Pan (large-scale translate) ─────────────────────────────────── */
28621
- @keyframes pptx-tr-pan-from-right {
28622
- from { transform: translateX(100%); }
28623
- to { transform: translateX(0); }
28624
- }
28625
- @keyframes pptx-tr-pan-to-left {
28626
- from { transform: translateX(0); }
28627
- to { transform: translateX(-100%); }
28628
- }
28629
- @keyframes pptx-tr-pan-from-left {
28630
- from { transform: translateX(-100%); }
28631
- to { transform: translateX(0); }
28632
- }
28633
- @keyframes pptx-tr-pan-to-right {
28634
- from { transform: translateX(0); }
28635
- to { transform: translateX(100%); }
28636
- }
28637
- @keyframes pptx-tr-pan-from-bottom {
28638
- from { transform: translateY(100%); }
28639
- to { transform: translateY(0); }
28640
- }
28641
- @keyframes pptx-tr-pan-to-top {
28642
- from { transform: translateY(0); }
28643
- to { transform: translateY(-100%); }
28644
- }
28645
- @keyframes pptx-tr-pan-from-top {
28646
- from { transform: translateY(-100%); }
28647
- to { transform: translateY(0); }
28648
- }
28649
- @keyframes pptx-tr-pan-to-bottom {
28650
- from { transform: translateY(0); }
28651
- to { transform: translateY(100%); }
28652
- }
28653
- `;
28654
- /** Part 2: prism / reveal / ripple / shred / switch / vortex / warp / wheelReverse / window. */
28655
- const P14_TRANSITION_KEYFRAMES_2 = `
28656
- /* ── Prism (3D rotation via perspective transform) ───────────────── */
28657
- @keyframes pptx-tr-prism-in-from-right {
28658
- from { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }
28659
- to { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28660
- }
28661
- @keyframes pptx-tr-prism-out-to-left {
28662
- from { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28663
- to { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }
28664
- }
28665
- @keyframes pptx-tr-prism-in-from-left {
28666
- from { transform: perspective(800px) rotateY(90deg) translateX(-50%); opacity: 0; }
28667
- to { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28668
- }
28669
- @keyframes pptx-tr-prism-out-to-right {
28670
- from { transform: perspective(800px) rotateY(0deg) translateX(0); opacity: 1; }
28671
- to { transform: perspective(800px) rotateY(-90deg) translateX(50%); opacity: 0; }
28672
- }
28673
- @keyframes pptx-tr-prism-in-from-bottom {
28674
- from { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }
28675
- to { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28676
- }
28677
- @keyframes pptx-tr-prism-out-to-top {
28678
- from { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28679
- to { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }
28680
- }
28681
- @keyframes pptx-tr-prism-in-from-top {
28682
- from { transform: perspective(800px) rotateX(-90deg) translateY(-50%); opacity: 0; }
28683
- to { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28684
- }
28685
- @keyframes pptx-tr-prism-out-to-bottom {
28686
- from { transform: perspective(800px) rotateX(0deg) translateY(0); opacity: 1; }
28687
- to { transform: perspective(800px) rotateX(90deg) translateY(50%); opacity: 0; }
28688
- }
28689
-
28690
- /* ── Reveal (slide away reveal) ──────────────────────────────────── */
28691
- @keyframes pptx-tr-reveal-out-to-right {
28692
- from { transform: translateX(0); }
28693
- to { transform: translateX(100%); }
28694
- }
28695
- @keyframes pptx-tr-reveal-out-to-left {
28696
- from { transform: translateX(0); }
28697
- to { transform: translateX(-100%); }
28698
- }
28699
- @keyframes pptx-tr-reveal-in {
28700
- from { opacity: 0.5; }
28701
- to { opacity: 1; }
28702
- }
28703
-
28704
- /* ── Ripple (expanding ring clip-path) ───────────────────────────── */
28705
- @keyframes pptx-tr-ripple-in {
28706
- from { clip-path: circle(0% at 50% 50%); opacity: 0.5; }
28707
- 30% { clip-path: circle(20% at 50% 50%); opacity: 0.7; }
28708
- 60% { clip-path: circle(50% at 50% 50%); opacity: 0.9; }
28709
- to { clip-path: circle(75% at 50% 50%); opacity: 1; }
28710
- }
28711
-
28712
- /* ── Shred (fragmented clip-path pieces) ─────────────────────────── */
28713
- @keyframes pptx-tr-shred-strips-in {
28714
- from { clip-path: inset(0 100% 0 0); opacity: 0; }
28715
- 30% { clip-path: inset(0 60% 0 0); opacity: 0.5; }
28716
- to { clip-path: inset(0); opacity: 1; }
28717
- }
28718
- @keyframes pptx-tr-shred-rectangles-in {
28719
- from { clip-path: inset(50%); opacity: 0; }
28720
- 40% { clip-path: inset(20%); opacity: 0.6; }
28721
- to { clip-path: inset(0); opacity: 1; }
28722
- }
28723
- @keyframes pptx-tr-shred-out {
28724
- from { opacity: 1; }
28725
- to { opacity: 0; filter: blur(2px); }
28726
- }
28727
-
28728
- /* ── Switch (flip/rotate swap) ───────────────────────────────────── */
28729
- @keyframes pptx-tr-switch-in-from-right {
28730
- from { transform: perspective(800px) rotateY(-180deg); opacity: 0; }
28731
- to { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28732
- }
28733
- @keyframes pptx-tr-switch-out-to-left {
28734
- from { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28735
- to { transform: perspective(800px) rotateY(180deg); opacity: 0; }
28736
- }
28737
- @keyframes pptx-tr-switch-in-from-left {
28738
- from { transform: perspective(800px) rotateY(180deg); opacity: 0; }
28739
- to { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28740
- }
28741
- @keyframes pptx-tr-switch-out-to-right {
28742
- from { transform: perspective(800px) rotateY(0deg); opacity: 1; }
28743
- to { transform: perspective(800px) rotateY(-180deg); opacity: 0; }
28744
- }
28745
-
28746
- /* ── Vortex (rotate + scale spiral) ──────────────────────────────── */
28747
- @keyframes pptx-tr-vortex-in {
28748
- from { transform: rotate(720deg) scale(0); opacity: 0; }
28749
- to { transform: rotate(0deg) scale(1); opacity: 1; }
28750
- }
28751
- @keyframes pptx-tr-vortex-out {
28752
- from { transform: rotate(0deg) scale(1); opacity: 1; }
28753
- to { transform: rotate(-720deg) scale(0); opacity: 0; }
28754
- }
28755
-
28756
- /* ── Warp (skew distortion) ──────────────────────────────────────── */
28757
- @keyframes pptx-tr-warp-in {
28758
- from { transform: scale(0.3) skewX(30deg) skewY(15deg); opacity: 0; }
28759
- 50% { transform: scale(0.8) skewX(-5deg) skewY(-3deg); opacity: 0.7; }
28760
- to { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; }
28761
- }
28762
- @keyframes pptx-tr-warp-out {
28763
- from { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; }
28764
- 50% { transform: scale(0.8) skewX(5deg) skewY(3deg); opacity: 0.7; }
28765
- to { transform: scale(0.3) skewX(-30deg) skewY(-15deg); opacity: 0; }
28766
- }
28767
- @keyframes pptx-tr-warp-reverse-in {
28768
- from { transform: scale(3) skewX(-20deg) skewY(-10deg); opacity: 0; filter: blur(4px); }
28769
- to { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; filter: blur(0); }
28770
- }
28771
- @keyframes pptx-tr-warp-reverse-out {
28772
- from { transform: scale(1) skewX(0deg) skewY(0deg); opacity: 1; filter: blur(0); }
28773
- to { transform: scale(3) skewX(20deg) skewY(10deg); opacity: 0; filter: blur(4px); }
28774
- }
28775
-
28776
- /* ── WheelReverse (reverse wheel rotation) ───────────────────────── */
28777
- @keyframes pptx-tr-wheel-reverse-in {
28778
- from { clip-path: circle(0% at 50% 50%); transform: rotate(180deg); }
28779
- to { clip-path: circle(75% at 50% 50%); transform: rotate(0deg); }
28780
- }
28781
-
28782
- /* ── Window (scale from center with border) ──────────────────────── */
28783
- @keyframes pptx-tr-window-horz {
28784
- from { clip-path: inset(0 50%); }
28785
- to { clip-path: inset(0 0); }
28786
- }
28787
- @keyframes pptx-tr-window-vert {
28788
- from { clip-path: inset(50% 0); }
28789
- to { clip-path: inset(0 0); }
28790
- }
28791
- @keyframes pptx-tr-window-out {
28792
- from { opacity: 1; transform: scale(1); }
28793
- to { opacity: 0; transform: scale(0.9); }
28794
- }
28795
- `;
28796
- /** Both p14 keyframe blocks concatenated, for single `<style>` injection. */
28797
- const P14_TRANSITION_KEYFRAMES_ALL = `${P14_TRANSITION_KEYFRAMES}\n${P14_TRANSITION_KEYFRAMES_2}`;
28798
-
28799
29207
  /**
28800
29208
  * `p14-transition-css` — animation resolver for the Office 2010 (`p14`
28801
29209
  * namespace) slide transitions. Maps each p14 transition type to the faithful
@@ -28840,7 +29248,10 @@ function resolveCardinal(direction) {
28840
29248
  return 'left';
28841
29249
  }
28842
29250
  }
28843
- /** Build a directional transition pair given a per-direction keyframe prefix. */
29251
+ /**
29252
+ * Build a directional pair using the bare `to-X` / `from-Y` suffixes (the `pan`
29253
+ * keyframes use this naming).
29254
+ */
28844
29255
  function directionalPair(direction, prefix, dur, ease) {
28845
29256
  const dir = resolveCardinal(direction);
28846
29257
  const opposites = {
@@ -28856,6 +29267,25 @@ function directionalPair(direction, prefix, dur, ease) {
28856
29267
  outgoingOnTop: false,
28857
29268
  };
28858
29269
  }
29270
+ /**
29271
+ * Build a directional pair using the explicit `out-to-X` / `in-from-Y` suffixes
29272
+ * (the `prism` keyframes use this naming, matching conveyor/switch/gallery).
29273
+ */
29274
+ function cardinalOutInPair(direction, prefix, dur, ease) {
29275
+ const dir = resolveCardinal(direction);
29276
+ const map = {
29277
+ left: ['out-to-left', 'in-from-right'],
29278
+ right: ['out-to-right', 'in-from-left'],
29279
+ up: ['out-to-top', 'in-from-bottom'],
29280
+ down: ['out-to-bottom', 'in-from-top'],
29281
+ };
29282
+ const [outSuffix, inSuffix] = map[dir];
29283
+ return {
29284
+ outgoing: `${prefix}-${outSuffix} ${dur} ${ease} forwards`,
29285
+ incoming: `${prefix}-${inSuffix} ${dur} ${ease} forwards`,
29286
+ outgoingOnTop: false,
29287
+ };
29288
+ }
28859
29289
  /**
28860
29290
  * Return CSS animation descriptors for p14 transition types. Returns
28861
29291
  * `undefined` when the type is not a p14 transition.
@@ -28955,7 +29385,7 @@ function getP14TransitionAnimations(type, durationMs, direction, orient) {
28955
29385
  case 'pan':
28956
29386
  return directionalPair(direction, 'pptx-tr-pan', dur, ease);
28957
29387
  case 'prism':
28958
- return directionalPair(direction, 'pptx-tr-prism', dur, ease);
29388
+ return cardinalOutInPair(direction, 'pptx-tr-prism', dur, ease);
28959
29389
  case 'reveal': {
28960
29390
  const lr = resolveLR(direction);
28961
29391
  return {
@@ -29039,6 +29469,314 @@ function getP14TransitionAnimations(type, durationMs, direction, orient) {
29039
29469
  }
29040
29470
  }
29041
29471
 
29472
+ /**
29473
+ * `slide-transition-css` — pure mapping from a {@link PptxSlideTransition}
29474
+ * (type + duration + direction/orientation) to the CSS `animation` shorthand
29475
+ * pieces used by each binding's presentation-mode transition overlay during a
29476
+ * slide change.
29477
+ *
29478
+ * Consolidates the React `transition-resolver` / `transition-helpers` /
29479
+ * `transition-keyframes` trio, the Vue `slide-transition-css`, and the Angular
29480
+ * `transition-helpers` into one framework-agnostic module:
29481
+ *
29482
+ * - {@link getSlideTransitionAnimations} resolves a transition to the
29483
+ * `animation` shorthand strings for the outgoing (old) and incoming (new)
29484
+ * slide layers, plus whether the outgoing layer sits on top.
29485
+ * - the `@keyframes` referenced live in `slide-transition-keyframes`
29486
+ * (`SLIDE_TRANSITION_KEYFRAMES`), injected once via a `<style>` element.
29487
+ *
29488
+ * Superset note: the exotic / 3-D transition family (`pan`/`gallery`/
29489
+ * `conveyor`/`reveal`/`doors`/`switch`/`flythrough`/`ferris`/`prism`/`ripple`/
29490
+ * `honeycomb`/`glitter`/`shred`/`flash`/`vortex`/`warp`/`wheelReverse`/`window`)
29491
+ * is rendered faithfully by delegating to {@link getP14TransitionAnimations}
29492
+ * (its `@keyframes` live in `p14-transition-keyframes` and are folded into
29493
+ * `SLIDE_TRANSITION_KEYFRAMES`). The classic set and the newer p15 cinematic
29494
+ * types with no dedicated keyframes (`cube`/`flip`/`rotate`/`orbit`/`fracture`/
29495
+ * `peelOff`/`pageCurl*`/`airplane`/`origami`, etc.) fall back to a symmetrical
29496
+ * cross-fade.
29497
+ *
29498
+ * Everything here is pure and unit-testable: no framework imports, no DOM.
29499
+ *
29500
+ * @module render/slide-transition-css
29501
+ */
29502
+ /**
29503
+ * Map a {@link PptxTransitionType} (+ duration/direction/orient/spokes) to the
29504
+ * concrete CSS `animation` descriptors for the outgoing and incoming layers.
29505
+ *
29506
+ * Unknown types fall back to a symmetrical cross-fade.
29507
+ */
29508
+ function getSlideTransitionAnimations(type, durationMs, direction, orient, spokes) {
29509
+ const dur = `${durationMs}ms`;
29510
+ // `spokes` is reserved for future wheel spoke-count support; forwarded only
29511
+ // through recursive calls (random / pull aliases).
29512
+ void spokes;
29513
+ // Prefer the faithful Office 2010 (p14) keyframe set for the exotic / 3-D
29514
+ // transition family (conveyor/doors/ferris/flash/flythrough/gallery/glitter/
29515
+ // honeycomb/pan/prism/reveal/ripple/shred/switch/vortex/warp/wheelReverse/
29516
+ // window). Returns `undefined` for the classic set, which falls through to
29517
+ // the 2-D CSS cases below. The p14 `@keyframes` are folded into
29518
+ // `SLIDE_TRANSITION_KEYFRAMES`, so every binding that injects that block
29519
+ // animates these faithfully with no per-binding wiring.
29520
+ const p14 = getP14TransitionAnimations(type, durationMs, direction, orient);
29521
+ if (p14) {
29522
+ return p14;
29523
+ }
29524
+ switch (type) {
29525
+ case 'none':
29526
+ case 'cut':
29527
+ return INSTANT;
29528
+ case 'fade':
29529
+ return {
29530
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29531
+ incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
29532
+ outgoingOnTop: true,
29533
+ };
29534
+ case 'push': {
29535
+ const dir = resolveDirection(direction, 'left');
29536
+ const configs = {
29537
+ left: {
29538
+ outgoing: `pptx-tr-push-out-to-left ${dur} ${EASE} forwards`,
29539
+ incoming: `pptx-tr-push-in-from-right ${dur} ${EASE} forwards`,
29540
+ outgoingOnTop: false,
29541
+ },
29542
+ right: {
29543
+ outgoing: `pptx-tr-push-out-to-right ${dur} ${EASE} forwards`,
29544
+ incoming: `pptx-tr-push-in-from-left ${dur} ${EASE} forwards`,
29545
+ outgoingOnTop: false,
29546
+ },
29547
+ up: {
29548
+ outgoing: `pptx-tr-push-out-to-top ${dur} ${EASE} forwards`,
29549
+ incoming: `pptx-tr-push-in-from-bottom ${dur} ${EASE} forwards`,
29550
+ outgoingOnTop: false,
29551
+ },
29552
+ down: {
29553
+ outgoing: `pptx-tr-push-out-to-bottom ${dur} ${EASE} forwards`,
29554
+ incoming: `pptx-tr-push-in-from-top ${dur} ${EASE} forwards`,
29555
+ outgoingOnTop: false,
29556
+ },
29557
+ };
29558
+ return configs[dir];
29559
+ }
29560
+ case 'wipe': {
29561
+ const dir = resolveDirection(direction, 'left');
29562
+ const wipeNames = {
29563
+ left: `pptx-tr-wipe-from-left ${dur} ${EASE} forwards`,
29564
+ right: `pptx-tr-wipe-from-right ${dur} ${EASE} forwards`,
29565
+ up: `pptx-tr-wipe-from-top ${dur} ${EASE} forwards`,
29566
+ down: `pptx-tr-wipe-from-bottom ${dur} ${EASE} forwards`,
29567
+ };
29568
+ return {
29569
+ outgoing: 'none',
29570
+ incoming: wipeNames[dir],
29571
+ outgoingOnTop: false,
29572
+ };
29573
+ }
29574
+ case 'cover': {
29575
+ const dir = resolveDirection8(direction, 'left');
29576
+ const coverMap = {
29577
+ left: `pptx-tr-cover-from-left ${dur} ${EASE} forwards`,
29578
+ right: `pptx-tr-cover-from-right ${dur} ${EASE} forwards`,
29579
+ up: `pptx-tr-cover-from-top ${dur} ${EASE} forwards`,
29580
+ down: `pptx-tr-cover-from-bottom ${dur} ${EASE} forwards`,
29581
+ lu: `pptx-tr-cover-from-lu ${dur} ${EASE} forwards`,
29582
+ ld: `pptx-tr-cover-from-ld ${dur} ${EASE} forwards`,
29583
+ ru: `pptx-tr-cover-from-ru ${dur} ${EASE} forwards`,
29584
+ rd: `pptx-tr-cover-from-rd ${dur} ${EASE} forwards`,
29585
+ };
29586
+ return {
29587
+ outgoing: 'none',
29588
+ incoming: coverMap[dir],
29589
+ outgoingOnTop: false,
29590
+ };
29591
+ }
29592
+ case 'uncover': {
29593
+ const dir = resolveDirection8(direction, 'left');
29594
+ const uncoverMap = {
29595
+ left: `pptx-tr-uncover-to-left ${dur} ${EASE} forwards`,
29596
+ right: `pptx-tr-uncover-to-right ${dur} ${EASE} forwards`,
29597
+ up: `pptx-tr-uncover-to-top ${dur} ${EASE} forwards`,
29598
+ down: `pptx-tr-uncover-to-bottom ${dur} ${EASE} forwards`,
29599
+ lu: `pptx-tr-uncover-to-lu ${dur} ${EASE} forwards`,
29600
+ ld: `pptx-tr-uncover-to-ld ${dur} ${EASE} forwards`,
29601
+ ru: `pptx-tr-uncover-to-ru ${dur} ${EASE} forwards`,
29602
+ rd: `pptx-tr-uncover-to-rd ${dur} ${EASE} forwards`,
29603
+ };
29604
+ return {
29605
+ outgoing: uncoverMap[dir],
29606
+ incoming: 'none',
29607
+ outgoingOnTop: true,
29608
+ };
29609
+ }
29610
+ case 'split': {
29611
+ const o = resolveOrientation(undefined, orient);
29612
+ const isOut = direction !== 'in';
29613
+ if (isOut) {
29614
+ return {
29615
+ outgoing: 'none',
29616
+ incoming: o === 'vert'
29617
+ ? `pptx-tr-split-v-out ${dur} ${EASE} forwards`
29618
+ : `pptx-tr-split-h-out ${dur} ${EASE} forwards`,
29619
+ outgoingOnTop: false,
29620
+ };
29621
+ }
29622
+ return {
29623
+ outgoing: o === 'vert'
29624
+ ? `pptx-tr-split-v-in ${dur} ${EASE} forwards`
29625
+ : `pptx-tr-split-h-in ${dur} ${EASE} forwards`,
29626
+ incoming: 'none',
29627
+ outgoingOnTop: true,
29628
+ };
29629
+ }
29630
+ case 'dissolve':
29631
+ return {
29632
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29633
+ incoming: `pptx-tr-dissolve-in ${dur} ${EASE} forwards`,
29634
+ outgoingOnTop: true,
29635
+ };
29636
+ case 'circle':
29637
+ return {
29638
+ outgoing: 'none',
29639
+ incoming: `pptx-tr-circle-in ${dur} ${EASE} forwards`,
29640
+ outgoingOnTop: false,
29641
+ };
29642
+ case 'diamond':
29643
+ return {
29644
+ outgoing: 'none',
29645
+ incoming: `pptx-tr-diamond-in ${dur} ${EASE} forwards`,
29646
+ outgoingOnTop: false,
29647
+ };
29648
+ case 'plus':
29649
+ return {
29650
+ outgoing: 'none',
29651
+ incoming: `pptx-tr-plus-in ${dur} ${EASE} forwards`,
29652
+ outgoingOnTop: false,
29653
+ };
29654
+ case 'wedge':
29655
+ return {
29656
+ outgoing: 'none',
29657
+ incoming: `pptx-tr-wedge-in ${dur} ${EASE} forwards`,
29658
+ outgoingOnTop: false,
29659
+ };
29660
+ case 'wheel':
29661
+ return {
29662
+ outgoing: 'none',
29663
+ incoming: `pptx-tr-wheel-in ${dur} ${EASE} forwards`,
29664
+ outgoingOnTop: false,
29665
+ };
29666
+ case 'zoom':
29667
+ return {
29668
+ outgoing: `pptx-tr-zoom-out ${dur} ${EASE} forwards`,
29669
+ incoming: `pptx-tr-zoom-in ${dur} ${EASE} forwards`,
29670
+ outgoingOnTop: true,
29671
+ };
29672
+ case 'blinds': {
29673
+ const o = resolveOrientation(direction, orient);
29674
+ return {
29675
+ outgoing: 'none',
29676
+ incoming: o === 'vert'
29677
+ ? `pptx-tr-blinds-v ${dur} ${EASE} forwards`
29678
+ : `pptx-tr-blinds-h ${dur} ${EASE} forwards`,
29679
+ outgoingOnTop: false,
29680
+ };
29681
+ }
29682
+ case 'checker':
29683
+ return {
29684
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29685
+ incoming: `pptx-tr-checker-in ${dur} ${EASE} forwards`,
29686
+ outgoingOnTop: true,
29687
+ };
29688
+ case 'comb': {
29689
+ const o = resolveOrientation(direction, orient);
29690
+ return {
29691
+ outgoing: 'none',
29692
+ incoming: o === 'vert'
29693
+ ? `pptx-tr-comb-v ${dur} ${EASE} forwards`
29694
+ : `pptx-tr-comb-h ${dur} ${EASE} forwards`,
29695
+ outgoingOnTop: false,
29696
+ };
29697
+ }
29698
+ case 'strips': {
29699
+ const stripDir = direction === 'lu' || direction === 'ld' || direction === 'ru' || direction === 'rd'
29700
+ ? direction
29701
+ : 'lu';
29702
+ return {
29703
+ outgoing: 'none',
29704
+ incoming: `pptx-tr-strips-${stripDir} ${dur} ${EASE} forwards`,
29705
+ outgoingOnTop: false,
29706
+ };
29707
+ }
29708
+ case 'randomBar': {
29709
+ const o = resolveOrientation(direction, orient);
29710
+ return {
29711
+ outgoing: 'none',
29712
+ incoming: o === 'vert'
29713
+ ? `pptx-tr-randombar-v ${dur} ${EASE} forwards`
29714
+ : `pptx-tr-randombar-h ${dur} ${EASE} forwards`,
29715
+ outgoingOnTop: false,
29716
+ };
29717
+ }
29718
+ case 'newsflash':
29719
+ return {
29720
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29721
+ incoming: `pptx-tr-newsflash-in ${dur} ${EASE} forwards`,
29722
+ outgoingOnTop: false,
29723
+ };
29724
+ // `pull` is the directional alias of `uncover`.
29725
+ case 'pull':
29726
+ return getSlideTransitionAnimations('uncover', durationMs, direction, orient, spokes);
29727
+ case 'morph':
29728
+ return {
29729
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29730
+ incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
29731
+ outgoingOnTop: true,
29732
+ };
29733
+ case 'random': {
29734
+ const randomType = RANDOM_ELIGIBLE_TYPES[Math.floor(Math.random() * RANDOM_ELIGIBLE_TYPES.length)];
29735
+ return getSlideTransitionAnimations(randomType, durationMs, direction, orient, spokes);
29736
+ }
29737
+ // The exotic / 3-D transition family (conveyor/doors/ferris/flash/
29738
+ // flythrough/gallery/glitter/honeycomb/pan/prism/reveal/ripple/shred/
29739
+ // switch/vortex/warp/wheelReverse/window) is handled faithfully above via
29740
+ // `getP14TransitionAnimations` and never reaches this switch.
29741
+ // Fallback (unknown / not-yet-mapped type, e.g. the p15 cinematic set:
29742
+ // cube/flip/rotate/orbit/fracture/peelOff/pageCurl*/airplane/origami)
29743
+ // — symmetrical cross-fade.
29744
+ default:
29745
+ return {
29746
+ outgoing: `pptx-tr-fade-out ${dur} ${EASE} forwards`,
29747
+ incoming: `pptx-tr-fade-in ${dur} ${EASE} forwards`,
29748
+ outgoingOnTop: true,
29749
+ };
29750
+ }
29751
+ }
29752
+ /**
29753
+ * Convenience wrapper that reads everything off a {@link PptxSlideTransition},
29754
+ * applying the React/Vue default duration when none is set. `none`/`cut` and a
29755
+ * transition with a non-positive duration resolve to {@link INSTANT}.
29756
+ */
29757
+ function resolveSlideTransition(transition) {
29758
+ if (!transition || transition.type === 'none' || transition.type === 'cut') {
29759
+ return INSTANT;
29760
+ }
29761
+ const durationMs = typeof transition.durationMs === 'number' && transition.durationMs > 0
29762
+ ? transition.durationMs
29763
+ : DEFAULT_TRANSITION_DURATION_MS$1;
29764
+ return getSlideTransitionAnimations(transition.type, durationMs, transition.direction, transition.orient, transition.spokes);
29765
+ }
29766
+ /**
29767
+ * The effective duration (ms) for a transition under the React/Vue policy — the
29768
+ * configured `durationMs`, or {@link DEFAULT_TRANSITION_DURATION_MS} when
29769
+ * unset/invalid. `none`/`cut` resolve to `0` (instant).
29770
+ */
29771
+ function resolveTransitionDurationMs(transition) {
29772
+ if (!transition || transition.type === 'none' || transition.type === 'cut') {
29773
+ return 0;
29774
+ }
29775
+ return typeof transition.durationMs === 'number' && transition.durationMs > 0
29776
+ ? transition.durationMs
29777
+ : DEFAULT_TRANSITION_DURATION_MS$1;
29778
+ }
29779
+
29042
29780
  /**
29043
29781
  * SmartArt layout engine — pure colour / style / tree / family-resolution
29044
29782
  * helpers shared by the React, Vue, and Angular bindings.
@@ -29872,6 +30610,29 @@ function computeTargetLayout(nodes, box, palette, style, elementId) {
29872
30610
  * `import … from 'pptx-viewer-shared'` (or a thin binding shim) yields the full
29873
30611
  * surface the renderers and colocated tests expect.
29874
30612
  */
30613
+ /**
30614
+ * Expand a colour palette across `count` nodes.
30615
+ *
30616
+ * For `span`, distributes the nodes evenly along the palette and interpolates
30617
+ * intermediate colours in HSL space (honouring `hueDirection`), so e.g. a
30618
+ * two-colour "colorful range" scheme fades smoothly across many nodes. For
30619
+ * `cycle`/`repeat`/unset, wraps the palette by index (the historic behaviour).
30620
+ */
30621
+ function interpolateSmartArtPalette(palette, count, method, hueDirection) {
30622
+ if (count <= 0 || palette.length === 0) {
30623
+ return [];
30624
+ }
30625
+ if (method !== 'span' || palette.length < 2 || count <= palette.length) {
30626
+ return Array.from({ length: count }, (_, i) => palette[i % palette.length]);
30627
+ }
30628
+ const segments = palette.length - 1;
30629
+ return Array.from({ length: count }, (_, i) => {
30630
+ const pos = (i / (count - 1)) * segments;
30631
+ const lower = Math.min(Math.floor(pos), segments - 1);
30632
+ const frac = pos - lower;
30633
+ return interpolateColor(palette[lower], palette[lower + 1], frac, 'hsl', hueDirection);
30634
+ });
30635
+ }
29875
30636
  /**
29876
30637
  * Compute the SVG layout for a SmartArt element when drawing shapes are absent.
29877
30638
  *
@@ -29882,32 +30643,40 @@ function computeTargetLayout(nodes, box, palette, style, elementId) {
29882
30643
  * @param elementId - Element ID (used for stable SVG key generation).
29883
30644
  * @param resolvedLayoutType - Layout type string from the core parser.
29884
30645
  * @param layout - Named layout preset.
30646
+ * @param interpolation - Optional colour-list span/cycle interpolation
30647
+ * (from the diagram's colour scheme). When `span`,
30648
+ * the palette is expanded into a per-node gradient
30649
+ * before layout; otherwise the palette is used
30650
+ * as-is and cycled by the family computers.
29885
30651
  * @returns Complete layout geometry for the resolved family.
29886
30652
  */
29887
- function computeSmartArtLayout(nodes, box, palette, style, elementId, resolvedLayoutType, layout) {
30653
+ function computeSmartArtLayout(nodes, box, palette, style, elementId, resolvedLayoutType, layout, interpolation) {
29888
30654
  const flat = flattenNodes(nodes);
29889
30655
  const family = resolveLayoutFamily(nodes, resolvedLayoutType, layout);
30656
+ const pal = interpolation?.method === 'span'
30657
+ ? interpolateSmartArtPalette(palette, flat.length, 'span', interpolation.hueDirection)
30658
+ : palette;
29890
30659
  switch (family) {
29891
30660
  case 'list':
29892
- return computeListLayout(flat, box, palette, style, elementId);
30661
+ return computeListLayout(flat, box, pal, style, elementId);
29893
30662
  case 'process':
29894
- return computeProcessLayout(flat, box, palette, style, elementId);
30663
+ return computeProcessLayout(flat, box, pal, style, elementId);
29895
30664
  case 'cycle':
29896
- return computeCycleLayout(flat, box, palette, style, elementId);
30665
+ return computeCycleLayout(flat, box, pal, style, elementId);
29897
30666
  case 'hierarchy':
29898
- return computeHierarchyLayout(nodes, box, palette, style, elementId);
30667
+ return computeHierarchyLayout(nodes, box, pal, style, elementId);
29899
30668
  case 'matrix':
29900
- return computeMatrixLayout(flat, box, palette, style, elementId);
30669
+ return computeMatrixLayout(flat, box, pal, style, elementId);
29901
30670
  case 'radial':
29902
- return computeRadialLayout(flat, box, palette, style, elementId);
30671
+ return computeRadialLayout(flat, box, pal, style, elementId);
29903
30672
  case 'pyramid':
29904
- return computePyramidLayout(flat, box, palette, style, elementId);
30673
+ return computePyramidLayout(flat, box, pal, style, elementId);
29905
30674
  case 'venn':
29906
- return computeVennLayout(flat, box, palette, style, elementId);
30675
+ return computeVennLayout(flat, box, pal, style, elementId);
29907
30676
  case 'funnel':
29908
- return computeFunnelLayout(flat, box, palette, style, elementId);
30677
+ return computeFunnelLayout(flat, box, pal, style, elementId);
29909
30678
  case 'target':
29910
- return computeTargetLayout(flat, box, palette, style, elementId);
30679
+ return computeTargetLayout(flat, box, pal, style, elementId);
29911
30680
  }
29912
30681
  }
29913
30682
 
@@ -37323,6 +38092,20 @@ function updateViewerPreference(preferences, key, value) {
37323
38092
  function shouldLoopContinuously(input) {
37324
38093
  return Boolean(input.loopContinuously) || input.showType === 'kiosk';
37325
38094
  }
38095
+ /**
38096
+ * PowerPoint's "On Mouse Click" advance gate. An on-slide click / tap / swipe
38097
+ * advances the show only when the current slide's transition allows it: a slide
38098
+ * whose transition sets `advanceOnClick` to false is advanced solely by timings
38099
+ * or by explicit navigation (keyboard, on-screen next/prev buttons). An
38100
+ * undefined flag defaults to allowed, preserving the historical
38101
+ * click-to-advance behaviour.
38102
+ *
38103
+ * Only the click / tap / swipe advance may consult this. Keyboard, on-screen
38104
+ * next/prev buttons and timed auto-advance must never be gated by it.
38105
+ */
38106
+ function isClickAdvanceAllowed(slide) {
38107
+ return slide?.transition?.advanceOnClick !== false;
38108
+ }
37326
38109
  function applyRehearsalTimings(slides, timings) {
37327
38110
  return slides.map((slide, index) => {
37328
38111
  const advanceAfterMs = timings[index];
@@ -68154,6 +68937,16 @@ function hasExitedFullscreen(doc) {
68154
68937
  return !d?.fullscreenElement;
68155
68938
  }
68156
68939
 
68940
+ /**
68941
+ * Whether a click/tap/swipe advance must be swallowed instead of moving to the
68942
+ * next slide. A click still steps the current slide's remaining animation
68943
+ * builds, so this only blocks once they are exhausted (`playbackComplete`) and
68944
+ * only when the slide's transition sets advanceOnClick to false. Keyboard and
68945
+ * the on-screen next/prev buttons never consult this.
68946
+ */
68947
+ function shouldBlockClickAdvance(playbackComplete, slide) {
68948
+ return playbackComplete && !isClickAdvanceAllowed(slide);
68949
+ }
68157
68950
  /**
68158
68951
  * Clamp `index` to the valid range [0, count - 1].
68159
68952
  * Returns 0 when `count` is 0 to avoid -1 states.
@@ -68941,8 +69734,16 @@ class PresentationOverlayComponent {
68941
69734
  getScale: () => 1,
68942
69735
  callbacks: {
68943
69736
  onSwipe: (direction) => {
68944
- // direction 1 = swipe right (previous), -1 = swipe left (next).
68945
- this.navigate(direction === 1 ? 'prev' : 'next');
69737
+ // direction 1 = swipe right (previous), -1 = swipe left (next). A
69738
+ // swipe is PowerPoint's on-click advance, so the forward case is
69739
+ // gated by the current slide's advanceOnClick flag; a backward
69740
+ // swipe is explicit navigation and never gated.
69741
+ if (direction === 1) {
69742
+ this.navigate('prev');
69743
+ }
69744
+ else {
69745
+ this.advanceFromClick();
69746
+ }
68946
69747
  },
68947
69748
  },
68948
69749
  });
@@ -69053,6 +69854,19 @@ class PresentationOverlayComponent {
69053
69854
  if (this.annotations.tool() !== 'none') {
69054
69855
  return;
69055
69856
  }
69857
+ this.advanceFromClick();
69858
+ }
69859
+ /**
69860
+ * Click/tap/swipe advance. Like every forward step it first reveals the
69861
+ * current slide's next animation build; only once the builds are exhausted
69862
+ * does it advance the slide, and then only when the slide's transition allows
69863
+ * click-advance (advanceOnClick !== false). Keyboard and the on-screen
69864
+ * next/prev buttons call navigate() directly and are never gated.
69865
+ */
69866
+ advanceFromClick() {
69867
+ if (shouldBlockClickAdvance(this.playback.isComplete(), this.currentSlide())) {
69868
+ return;
69869
+ }
69056
69870
  this.navigate('next');
69057
69871
  }
69058
69872
  /** Toggle an annotation tool (clicking the active one disarms it). */
@@ -74130,7 +74944,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.7", ngImpor
74130
74944
  }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
74131
74945
 
74132
74946
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
74133
- const PPTX_ANGULAR_VIEWER_VERSION = "1.31.3";
74947
+ const PPTX_ANGULAR_VIEWER_VERSION = "1.31.4";
74134
74948
 
74135
74949
  /**
74136
74950
  * account-page.component.ts: File > Account content.
@@ -100957,5 +101771,5 @@ function cn(...values) {
100957
101771
  * Generated bundle index. Do not edit.
100958
101772
  */
100959
101773
 
100960
- export { ALIGN_OPTIONS, AUDIENCE_HASH, AUDIENCE_NONCE_KEY, AVATAR_COLOR_SWATCHES, AccessibilityPanelComponent, AccessibilityService, AccountPageComponent, ActionSettingsPanelComponent, AdvancedChartEditorComponent, AnimationAuthorPanelComponent, AnimationPanelComponent, AnimationPlaybackService, AutosaveService, BroadcastDialogComponent, CHART_EDITOR_STYLES, CURSOR_PALETTE, CanvasFitService, ChartAxisOptionsComponent, ChartAxisStyleOptionsComponent, ChartComboTypeOptionsComponent, ChartDataEditorComponent, ChartDataLabelOptionsComponent, ChartDatapointOptionsComponent, ChartDisplayOptionsComponent, ChartElementViewComponent, ChartErrorBarOptionsComponent, ChartMarkerOptionsComponent, ChartPartSelectionService, ChartPrimitivesComponent, ChartRendererComponent, ChartTrendlineOptionsComponent, CollaborationCursorsComponent, CollaborationService, ColorChangedImageComponent, CommentsPanelComponent, CommentsService, ComparePanelComponent, ConnectorRendererComponent, ConnectorTextOverlayComponent, CustomShowsComponent, DATA_TABLE_HEADER_H, DATA_TABLE_KEY_W, DATA_TABLE_PADDING, DATA_TABLE_ROW_H, DEFAULT_BOUNDS, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_COLOR_SCHEME, DEFAULT_FILL_COLOR, DEFAULT_LAYOUT, DEFAULT_PALETTE$1 as DEFAULT_PALETTE, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_STYLE, DEFAULT_TABLE_ROW_HEIGHT, DEFAULT_TEXT_COLOR$1 as DEFAULT_TEXT_COLOR, DEFAULT_VIEWER_PROFILE, DIRECTIONAL_PRESETS, DIRECTION_OPTIONS, DocumentPropertiesCardComponent, EMBEDDED_FONTS_STYLE_ID, EMPHASIS_PRESETS, ENTRANCE_PRESETS, TEMPLATES as EQUATION_TEMPLATES, EXIT_PRESETS, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, EffectsPanelComponent, ElementRendererComponent, EmbeddedFontsService, EncryptedFileDialogComponent, EquationEditorDialogComponent, EquationRendererComponent, EquationTemplateGalleryComponent, ExportProgressModalComponent, ExportService, FieldContextService, FindBarComponent, FindReplaceBarComponent, FollowModeBarComponent, FontEmbeddingListComponent, FontEmbeddingPanelComponent, GALLERY_THEME_PRESETS, GradientPickerComponent, HANDOUT_OPTIONS, HeaderFooterDialogComponent, HyperlinkDialogComponent, ImagePropertiesPanelComponent, InkDrawingService, InkRendererComponent, InsertSmartArtDialogComponent, InspectorPaneHeaderComponent, InspectorPanelComponent, IsMobileService, KeepAnnotationsDialogComponent, LOCALE_CATALOG, LONG_PRESS_DURATION_MS, LONG_PRESS_MOVE_TOLERANCE_PX, LoadContentService, LocalPresencePublisher, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, MediaPreviewComponent, MediaPropertiesPanelComponent, MediaRendererComponent, MediaTrimTimelineComponent, MobileBottomBarComponent, MobileMenuSheetComponent, MobilePresenterViewComponent, MobileSheetComponent, MobileSlidesSheetComponent, MobileToolbarComponent, ModalDialogComponent, Model3DRendererComponent, NotesHandoutCardComponent, NotesPanelComponent, NotesToolbarComponent, OleRendererComponent, POWER_POINT_VIEWER_PROVIDERS, PRESENTER_CHANNEL_NAME, PRESENTER_MSG_ORIGIN, PasswordProtectionDialogComponent, PasswordStrengthMeterComponent, PowerPointViewerComponent, PresentationAnnotationOverlayComponent, PresentationAnnotationsService, PresentationOverlayComponent, PresentationPropertiesPanelComponent, PresentationSettingsCardComponent, PresentationSubtitleBarComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PresenterWindowService, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, REPEAT_MODE_OPTIONS, RESIZE_HANDLES, RULER_THICKNESS, RemoteSelectionOverlayComponent, RibbonAnimationsSectionComponent, RibbonArrangeSectionComponent, RibbonColorPopoverComponent, RibbonComponent, RibbonDesignSectionComponent, RibbonDrawSectionComponent, RibbonDrawingGroupComponent, RibbonEditingSectionComponent, RibbonFileSectionComponent, RibbonFontControlsComponent, RibbonHomeSectionComponent, RibbonInsertFieldsComponent, RibbonInsertSectionComponent, RibbonParagraphControlsComponent, RibbonPrimaryRowComponent, RibbonReviewSectionComponent, RibbonSlideshowSectionComponent, RibbonTransitionsSectionComponent, RibbonViewSectionComponent, RulerGuidesService, SEQUENCE_OPTIONS, SEVERITY_GROUPS, SEVERITY_LABELS, SHORTCUT_REFERENCE_ITEMS, SLIDE_PX_PER_INCH, SLIDE_TRANSITION_KEYFRAMES, DEFAULT_PALETTE as SMARTART_DEFAULT_PALETTE, PALETTES$1 as SMARTART_PALETTES, SMART_ART_COLOR_SCHEMES, SMART_ART_STYLE_OPTIONS, SUB_ITEM_LABEL, SVG_WARP_PRESETS, SWIPE_MAX_VERTICAL_PX, SWIPE_THRESHOLD_PX, SelectionPaneComponent, SetUpSlideShowDialogComponent, SettingsAppearanceTabComponent, SettingsDialogComponent, SettingsLanguageTabComponent, ShareDialogComponent, ShortcutPanelComponent, ShowOptionsFieldsetComponent, ShowSlidesFieldsetComponent, SignatureStrippedDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideDefaultInspectorComponent, SlideDiffChangesComponent, SlideDiffRowComponent, SlideDiffThumbnailsComponent, SlideSizeCardComponent, SlideSorterOverlayComponent, SlideThemeOverridePanelComponent, SlidesPanelComponent, SmartArt3DRendererComponent, SmartArt3DService, SmartArtPreviewComponent, SmartArtPropertiesComponent, SmartArtRendererComponent, StatusBarComponent, TABLE_STRUCTURE_TOGGLES, TEXT_DIRECTION_OPTIONS$1 as TEXT_DIRECTION_OPTIONS, THEME_CATALOG, TIMING_CURVE_OPTIONS, TRIGGER_OPTIONS, TYPE_LABELS, TableCellAdvancedFillComponent, TableCellFormattingComponent, TableDataEditorComponent, TablePropertiesComponent, TableRendererComponent, TableResizeOverlayComponent, TableSelectionService, TextAdvancedPanelComponent, ThemeEditorFieldsComponent, ThemeGalleryComponent, ThemeSelectorCardComponent, TitleBarComponent, VALIGN_OPTIONS, VIEWER_THEME, VersionHistoryPanelComponent, ViewerCanvasEditingService, ViewerCollabCursorService, ViewerCollaborationSessionService, ViewerCompareService, ViewerCustomShowsService, ViewerDialogsService, ViewerDocumentPropertiesService, ViewerExportService, ViewerExtraDialogsComponent, ViewerFileIOService, ViewerFindReplaceService, ViewerFormatPainterService, ViewerInspectorPanelService, ViewerKeyboardService, ViewerMobileSheetService, ViewerPresentationModeService, ViewerThemeGalleryService, ViewerTouchGesturesService, ViewerZoomService, WEBM_MIME_CANDIDATES, WriteBackScheduler, ZoomNavigationService, ZoomRendererComponent, ZoomTargetService, addCategory, addCommentToList, addGradientStopPatch, addItem, addSeries, addSubItem, advanceStep, alignPatch, animationFor, annotationMapToInkInserts, applyAcceptedDiff, applyAnimationPreset, applyFindReplacements, applyFormatToElement, applyMove, applyResize, applyTableStylePreset, asMediaElement, assignUserColor, attachTouchGestures, beginNodeEdit, boolFromEvent, bringForward, bringToFront, buildBarActions, buildBroadcastConfig, buildBroadcastViewerUrl, buildCategoryLabels, buildCellParagraphs, buildChartViewModel, buildChromeStyle, buildClearHyperlinkPatch, buildClickGroups, buildColStyles, buildCollaborationConfig, buildComboViewModel, buildCssGradientFromShapeStyle, buildDuotoneFilter, buildDuotoneFilterId, buildEmbeddedFontStyles, buildEquationElement, buildEquationSegment, buildFallbackViewModel, buildFontFaceRule, buildGradientFillCss, buildGridlinesAndLabels, buildHyperlinkPatch, buildInkContainerStyle, buildInkStrokes, buildLegend, buildModel3DContainerStyle, buildModel3DViewModel, buildOleActionModel, buildOleInfoRows, buildPatternFillCss, buildPrintHtmlDocument as buildPrintDocument, buildPropertiesPatch, buildRegionMapViewModel, buildSaveSlides, buildShareUrl, buildSmartArtInsertElement, buildSmartArtNodes, buildStockViewModel, buildSurfaceViewModel, buildTableViewModel, buildTreemapViewModel, buildTrimFragment, buildWaterfallViewModel, buildZeroLine, buildZoomContainerStyle, buildZoomViewModel, bulletIndentPx, canAddTopLevelNode, canRemoveTopLevelNode, canStartBroadcast, canStartShare, canUseClipboard, captionDisplayText, cellRunStyle, cellStyleToStyleMap, cellTdStyle, changeCountLabel, changeIcon, characterSpacingPatch, checkFontAvailable, clampCursorPosition, clampGifDimensions, clampIndex, clampNotesFontSize, clampScale, clampStep, clearAllLocalViewerData, clearAudienceContent, cn, collectAccessibilityIssues, collectElementText, collectSlideText, collectUsedFontFamilies, columnWidthStyle, commitNodeText, computeAlign, computeAxisTitlePrimitives, computeBarRects, computeBubbleRadius, computeCornerHandle, computeDataTablePrimitives, computeDistribute, computeDrawingViewBox, computeErrorBarPrimitives, computeHandleBoxes, computeHandoutLayout, computeIsMobile, computeIsTablet, computeLinePoints, computeLinearRegression, computePageCount, computePieLayout, computePieSlicePath, computePieSlices, computePlotLayout, computeRSquared, computeRadarPoints, computeScatterDots, computeSelectionBoxes, computeSingleSelected, computeSlideIndices, computeSnap, computeStackedBarRects, computeStackedValueRange, computeTextLines, computeTimerProgress, computeTrendlinePrimitives, computeValueRange, convertOmmlToMathMl, copyFormatFromElement, countAccessibilityIssues, countAnnotationStrokes, createCustomShow, createSwipeDismissDrag, createWebrtcBundle, createWebsocketBundle, cssObjectToStyleMap, currentColorScheme, currentLayout, currentStyle, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, deleteVersion as deleteRecoveryVersion, demoteNode, deriveModel3DBlobUrl, derivePresenceList, describeSmartArtBounds, disableGlowPatch, disableInnerShadowPatch, disableOuterShadowPatch, disableReflectionPatch, disableSoftEdgePatch, duplicateElementById, durationOf, effectsStateOf, enableGlowPatch, enableInnerShadowPatch, enableOuterShadowPatch, enableReflectionPatch, enableSoftEdgePatch, encodeGif, estimatePageCount, evenColumnWidths, evenRowHeights, exitPresentationFullscreen, extractPathPoints, eyedropperAvailable, fillColorOf, findInSlides, findOwningSlideIndex, findSlideIndexByElementId, fitPolynomial, fitZoom, fontMimeForFormat, fontSizeOf, formatAutoNumber, formatAxisValue, formatBytes, formatCursorLabel, formatElapsed, formatFileSize, formatPropertyDate, formatTime, fpsToFrameIntervalMs, generateBroadcastRoomId, generateCommentId, generateCustomShowId, generatePressureCircles, generateRulerTicks, getClrChangeParams, getContainerStyle, getDuotoneFilterDef, getImageSrc, getLocalStorageUsageSummary, getOleAriaLabel, getOleBadgeLabel, getOleDisplayName, getOleDownloadFileName, getOleTypeColor, getOleTypeLabel, getPasswordStrength, getPatternSvg, getPlaceholderStyle, getVersions as getRecoveryVersions, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getSmartArtNodeBounds, getSpeechRecognitionCtor, getTextBlockStyle, getTextWarp, getTouchDistance, getWarpCategory, getWarpPath, gradientStateFromStyle, gradientStateOf, gradientStatePatch, gridColumns, groupElements, groupIssuesBySeverity, hasAnimation, hasCopyableFormat, hasExistingLink, hasExitedFullscreen, hasGradientFill, hasPressureVariation, headerLabel, inkViewBox, insertColumn, insertRow, interpolateWidth, isAudienceTab, isBold, isBrowserOpenableMime, isChildNode, isElementInteractive, isInjectableUrl, isItalic, isPpactionUrl, isPresenterMessage, isSigned, isTextElement, isUnderline, isUrlSafe, isValidRoomId, isViewportBackgroundPressTarget, isZoomActivationKey, issueTrackKey, issueTypeLabel, keyToLabel, latexToMathml, linePointsToSvgString, lineSpacingPatch, loadAudienceContent, mergeCaptionResults, mergeDown, mergeRight, mergeSelection, moveElementBy, moveNodeDown, moveNodeUp, msToFrameDelayCs, narrowToCircle, narrowToPolygon, narrowToRect, newChartElement, newEquationElement, newPresetShapeElement, newShapeElement, newSmartArtElement, newTableElement, newTextElement, nextVisibleIndex, nodeBold, nodeEditBox, nodeFillColor, nodeFontColor, nodeIdFromKey, nodeItalic, nodeStyle, normalizeFontFormat, normalizeSlidesPerPage, normalizeValue, numFromEvent, ommlToMathml, ooxmlDashToCssBorderStyle, openNativeEyeDropper, overallStatus, paletteColor, parseAudienceNonce, parseNodeTextarea, partitionSlides, patchChartData, patchChartStyle, patchTableData, patchTextStyle, pendingElementStyles, pickColorByClickFallback, pickSupportedMimeType, planGifFrames, planVideoSegments, pointsToSvgPathD, presenceToCursors, presetByLayout, presetsForCategory, pressuresToWidths, prevVisibleIndex, projectDrawingShapes, promoteNode, provideViewerTheme, radarAngle, radarRingPoints, recordWebm, redistributeColumnWidth, removeAnimation, removeCategory, removeColumn, removeCommentFromList, removeElementAnimation, removeGradientStopPatch, removeNode, removeRow, removeSeries, renderToCanvas, reorderAnimationDown, reorderAnimationUp, replaceInSlides, replaceMatch, requestPresentationFullscreen, resizeElement, resolveCaptionTracks, resolveChartKind, resolveFontVariant, resolveHyperlinkHref, resolveInteractiveElementId, resolveMediaSrc, resolveOleType, resolveParagraphBullet, resolvePresenterNotes, resolveProfileInitial, resolveRegionCode, resolvePalette as resolveSmartArtPalette, resolveThemeCatalogEntry, resolveTransitionDuration, revealedElementStyles, routeOrthogonalConnector, rowStyle, sampleColorFromSlide, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, saveViewerProfile, scanAvailableFonts, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, segmentFrameCount, selectValue$2 as selectValue, sendBackward, sendToBack, sequentialColorScale, serializeWriteBack, seriesColor, setAnimationEmphasis, setAnimationEntrance, setAnimationExit, setAxis, setAxisLogScale, setAxisTitleStyle, setCategoryLabel, setCellText, setColorScheme, setDataLabels, setDataPointExplosion, setDataPointFill, setDataPointLabel, setDelay, setDirection, setDuration, setElementPosition, setGridlineStyle, setLayout, setLegend, setNodeStyle, setNodeText, setRepeatCount, setRepeatMode, setSequence, setSeriesChartType, setSeriesColor, setSeriesErrorBars, setSeriesMarker, setSeriesName, setSeriesTrendline, setSeriesValue, setStyle, setTimingCurve, setTitle, setTrigger, setTriggerShapeId, shapeStylePatch, sheetAfterNavigate, shouldUseSvgWarp, showDirectionPicker, showsTemplateAffordance, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusLabel as slideDiffStatusLabel, slideNumberOf, smartArtNodes, paletteColour as smartArtPaletteColour, snapToGridStep, splitCursorCell, splitMergedCell, statusKind, statusLabel$1 as statusLabel, storeAudienceContent, stringFromEvent$5 as stringFromEvent, strokeColorOf, strokeToInkElement, styleShadowFilter, textAdvancedPatch, textAdvancedStateFromStyle, textAdvancedStateOf, textColorOf, textDirectionPatch, textStyleOf, textStylePatch, themeStyle, themeToCssVars, thumbnailHeight, thumbnailZoom, toggleCommentResolvedInList, toggleNodeBold, toggleNodeItalic, toggleSheet, topLevelNodeCount, transformSelectedTextCase, translationsEn, ungroupElements, updateElementById, updateGlowPatch, updateGradientStopPatch, updateInnerShadowPatch, updateOuterShadowPatch, updateReflectionPatch, vAlignPatch, validatePassword, validatePrintSettings, validateRoomId, valueToY, vermilionDarkColors, vermilionDarkTheme, vermilionLightColors, vermilionLightTheme, vermilionRadius, waypointsToPathD, worstStatus, zoomTargetSlideIndex };
101774
+ export { ALIGN_OPTIONS, AUDIENCE_HASH, AUDIENCE_NONCE_KEY, AVATAR_COLOR_SWATCHES, AccessibilityPanelComponent, AccessibilityService, AccountPageComponent, ActionSettingsPanelComponent, AdvancedChartEditorComponent, AnimationAuthorPanelComponent, AnimationPanelComponent, AnimationPlaybackService, AutosaveService, BroadcastDialogComponent, CHART_EDITOR_STYLES, CURSOR_PALETTE, CanvasFitService, ChartAxisOptionsComponent, ChartAxisStyleOptionsComponent, ChartComboTypeOptionsComponent, ChartDataEditorComponent, ChartDataLabelOptionsComponent, ChartDatapointOptionsComponent, ChartDisplayOptionsComponent, ChartElementViewComponent, ChartErrorBarOptionsComponent, ChartMarkerOptionsComponent, ChartPartSelectionService, ChartPrimitivesComponent, ChartRendererComponent, ChartTrendlineOptionsComponent, CollaborationCursorsComponent, CollaborationService, ColorChangedImageComponent, CommentsPanelComponent, CommentsService, ComparePanelComponent, ConnectorRendererComponent, ConnectorTextOverlayComponent, CustomShowsComponent, DATA_TABLE_HEADER_H, DATA_TABLE_KEY_W, DATA_TABLE_PADDING, DATA_TABLE_ROW_H, DEFAULT_BOUNDS, DEFAULT_BROADCAST_SERVER_URL, DEFAULT_CANVAS_HEIGHT, DEFAULT_CANVAS_WIDTH, DEFAULT_COLOR_SCHEME, DEFAULT_FILL_COLOR, DEFAULT_LAYOUT, DEFAULT_PALETTE$1 as DEFAULT_PALETTE, DEFAULT_PRINT_SETTINGS, DEFAULT_SLIDE_BACKGROUND, DEFAULT_STROKE_COLOR, DEFAULT_STYLE, DEFAULT_TABLE_ROW_HEIGHT, DEFAULT_TEXT_COLOR$1 as DEFAULT_TEXT_COLOR, DEFAULT_VIEWER_PROFILE, DIRECTIONAL_PRESETS, DIRECTION_OPTIONS, DocumentPropertiesCardComponent, EMBEDDED_FONTS_STYLE_ID, EMPHASIS_PRESETS, ENTRANCE_PRESETS, TEMPLATES as EQUATION_TEMPLATES, EXIT_PRESETS, EditorContextMenuComponent, EditorHistory, EditorStateService, EditorToolbarComponent, EffectsPanelComponent, ElementRendererComponent, EmbeddedFontsService, EncryptedFileDialogComponent, EquationEditorDialogComponent, EquationRendererComponent, EquationTemplateGalleryComponent, ExportProgressModalComponent, ExportService, FieldContextService, FindBarComponent, FindReplaceBarComponent, FollowModeBarComponent, FontEmbeddingListComponent, FontEmbeddingPanelComponent, GALLERY_THEME_PRESETS, GradientPickerComponent, HANDOUT_OPTIONS, HeaderFooterDialogComponent, HyperlinkDialogComponent, ImagePropertiesPanelComponent, InkDrawingService, InkRendererComponent, InsertSmartArtDialogComponent, InspectorPaneHeaderComponent, InspectorPanelComponent, IsMobileService, KeepAnnotationsDialogComponent, LOCALE_CATALOG, LONG_PRESS_DURATION_MS, LONG_PRESS_MOVE_TOLERANCE_PX, LoadContentService, LocalPresencePublisher, MAX_ZOOM_SCALE, MIN_ZOOM_SCALE, MediaPreviewComponent, MediaPropertiesPanelComponent, MediaRendererComponent, MediaTrimTimelineComponent, MobileBottomBarComponent, MobileMenuSheetComponent, MobilePresenterViewComponent, MobileSheetComponent, MobileSlidesSheetComponent, MobileToolbarComponent, ModalDialogComponent, Model3DRendererComponent, NotesHandoutCardComponent, NotesPanelComponent, NotesToolbarComponent, OleRendererComponent, POWER_POINT_VIEWER_PROVIDERS, PRESENTER_CHANNEL_NAME, PRESENTER_MSG_ORIGIN, PasswordProtectionDialogComponent, PasswordStrengthMeterComponent, PowerPointViewerComponent, PresentationAnnotationOverlayComponent, PresentationAnnotationsService, PresentationOverlayComponent, PresentationPropertiesPanelComponent, PresentationSettingsCardComponent, PresentationSubtitleBarComponent, PresentationTransitionOverlayComponent, PresenterViewComponent, PresenterWindowService, PrintDialogComponent, PrintService, PrintSettingsPanelComponent, PropertiesDialogComponent, REPEAT_MODE_OPTIONS, RESIZE_HANDLES, RULER_THICKNESS, RemoteSelectionOverlayComponent, RibbonAnimationsSectionComponent, RibbonArrangeSectionComponent, RibbonColorPopoverComponent, RibbonComponent, RibbonDesignSectionComponent, RibbonDrawSectionComponent, RibbonDrawingGroupComponent, RibbonEditingSectionComponent, RibbonFileSectionComponent, RibbonFontControlsComponent, RibbonHomeSectionComponent, RibbonInsertFieldsComponent, RibbonInsertSectionComponent, RibbonParagraphControlsComponent, RibbonPrimaryRowComponent, RibbonReviewSectionComponent, RibbonSlideshowSectionComponent, RibbonTransitionsSectionComponent, RibbonViewSectionComponent, RulerGuidesService, SEQUENCE_OPTIONS, SEVERITY_GROUPS, SEVERITY_LABELS, SHORTCUT_REFERENCE_ITEMS, SLIDE_PX_PER_INCH, SLIDE_TRANSITION_KEYFRAMES, DEFAULT_PALETTE as SMARTART_DEFAULT_PALETTE, PALETTES$1 as SMARTART_PALETTES, SMART_ART_COLOR_SCHEMES, SMART_ART_STYLE_OPTIONS, SUB_ITEM_LABEL, SVG_WARP_PRESETS, SWIPE_MAX_VERTICAL_PX, SWIPE_THRESHOLD_PX, SelectionPaneComponent, SetUpSlideShowDialogComponent, SettingsAppearanceTabComponent, SettingsDialogComponent, SettingsLanguageTabComponent, ShareDialogComponent, ShortcutPanelComponent, ShowOptionsFieldsetComponent, ShowSlidesFieldsetComponent, SignatureStrippedDialogComponent, SignaturesPanelComponent, SignaturesService, SlideCanvasComponent, SlideDefaultInspectorComponent, SlideDiffChangesComponent, SlideDiffRowComponent, SlideDiffThumbnailsComponent, SlideSizeCardComponent, SlideSorterOverlayComponent, SlideThemeOverridePanelComponent, SlidesPanelComponent, SmartArt3DRendererComponent, SmartArt3DService, SmartArtPreviewComponent, SmartArtPropertiesComponent, SmartArtRendererComponent, StatusBarComponent, TABLE_STRUCTURE_TOGGLES, TEXT_DIRECTION_OPTIONS$1 as TEXT_DIRECTION_OPTIONS, THEME_CATALOG, TIMING_CURVE_OPTIONS, TRIGGER_OPTIONS, TYPE_LABELS, TableCellAdvancedFillComponent, TableCellFormattingComponent, TableDataEditorComponent, TablePropertiesComponent, TableRendererComponent, TableResizeOverlayComponent, TableSelectionService, TextAdvancedPanelComponent, ThemeEditorFieldsComponent, ThemeGalleryComponent, ThemeSelectorCardComponent, TitleBarComponent, VALIGN_OPTIONS, VIEWER_THEME, VersionHistoryPanelComponent, ViewerCanvasEditingService, ViewerCollabCursorService, ViewerCollaborationSessionService, ViewerCompareService, ViewerCustomShowsService, ViewerDialogsService, ViewerDocumentPropertiesService, ViewerExportService, ViewerExtraDialogsComponent, ViewerFileIOService, ViewerFindReplaceService, ViewerFormatPainterService, ViewerInspectorPanelService, ViewerKeyboardService, ViewerMobileSheetService, ViewerPresentationModeService, ViewerThemeGalleryService, ViewerTouchGesturesService, ViewerZoomService, WEBM_MIME_CANDIDATES, WriteBackScheduler, ZoomNavigationService, ZoomRendererComponent, ZoomTargetService, addCategory, addCommentToList, addGradientStopPatch, addItem, addSeries, addSubItem, advanceStep, alignPatch, animationFor, annotationMapToInkInserts, applyAcceptedDiff, applyAnimationPreset, applyFindReplacements, applyFormatToElement, applyMove, applyResize, applyTableStylePreset, asMediaElement, assignUserColor, attachTouchGestures, beginNodeEdit, boolFromEvent, bringForward, bringToFront, buildBarActions, buildBroadcastConfig, buildBroadcastViewerUrl, buildCategoryLabels, buildCellParagraphs, buildChartViewModel, buildChromeStyle, buildClearHyperlinkPatch, buildClickGroups, buildColStyles, buildCollaborationConfig, buildComboViewModel, buildCssGradientFromShapeStyle, buildDuotoneFilter, buildDuotoneFilterId, buildEmbeddedFontStyles, buildEquationElement, buildEquationSegment, buildFallbackViewModel, buildFontFaceRule, buildGradientFillCss, buildGridlinesAndLabels, buildHyperlinkPatch, buildInkContainerStyle, buildInkStrokes, buildLegend, buildModel3DContainerStyle, buildModel3DViewModel, buildOleActionModel, buildOleInfoRows, buildPatternFillCss, buildPrintHtmlDocument as buildPrintDocument, buildPropertiesPatch, buildRegionMapViewModel, buildSaveSlides, buildShareUrl, buildSmartArtInsertElement, buildSmartArtNodes, buildStockViewModel, buildSurfaceViewModel, buildTableViewModel, buildTreemapViewModel, buildTrimFragment, buildWaterfallViewModel, buildZeroLine, buildZoomContainerStyle, buildZoomViewModel, bulletIndentPx, canAddTopLevelNode, canRemoveTopLevelNode, canStartBroadcast, canStartShare, canUseClipboard, captionDisplayText, cellRunStyle, cellStyleToStyleMap, cellTdStyle, changeCountLabel, changeIcon, characterSpacingPatch, checkFontAvailable, clampCursorPosition, clampGifDimensions, clampIndex, clampNotesFontSize, clampScale, clampStep, clearAllLocalViewerData, clearAudienceContent, cn, collectAccessibilityIssues, collectElementText, collectSlideText, collectUsedFontFamilies, columnWidthStyle, commitNodeText, computeAlign, computeAxisTitlePrimitives, computeBarRects, computeBubbleRadius, computeCornerHandle, computeDataTablePrimitives, computeDistribute, computeDrawingViewBox, computeErrorBarPrimitives, computeHandleBoxes, computeHandoutLayout, computeIsMobile, computeIsTablet, computeLinePoints, computeLinearRegression, computePageCount, computePieLayout, computePieSlicePath, computePieSlices, computePlotLayout, computeRSquared, computeRadarPoints, computeScatterDots, computeSelectionBoxes, computeSingleSelected, computeSlideIndices, computeSnap, computeStackedBarRects, computeStackedValueRange, computeTextLines, computeTimerProgress, computeTrendlinePrimitives, computeValueRange, convertOmmlToMathMl, copyFormatFromElement, countAccessibilityIssues, countAnnotationStrokes, createCustomShow, createSwipeDismissDrag, createWebrtcBundle, createWebsocketBundle, cssObjectToStyleMap, currentColorScheme, currentLayout, currentStyle, defaultCssVars, defaultRadius, defaultThemeColors, deleteElementsByIds, deleteVersion as deleteRecoveryVersion, demoteNode, deriveModel3DBlobUrl, derivePresenceList, describeSmartArtBounds, disableGlowPatch, disableInnerShadowPatch, disableOuterShadowPatch, disableReflectionPatch, disableSoftEdgePatch, duplicateElementById, durationOf, effectsStateOf, enableGlowPatch, enableInnerShadowPatch, enableOuterShadowPatch, enableReflectionPatch, enableSoftEdgePatch, encodeGif, estimatePageCount, evenColumnWidths, evenRowHeights, exitPresentationFullscreen, extractPathPoints, eyedropperAvailable, fillColorOf, findInSlides, findOwningSlideIndex, findSlideIndexByElementId, fitPolynomial, fitZoom, fontMimeForFormat, fontSizeOf, formatAutoNumber, formatAxisValue, formatBytes, formatCursorLabel, formatElapsed, formatFileSize, formatPropertyDate, formatTime, fpsToFrameIntervalMs, generateBroadcastRoomId, generateCommentId, generateCustomShowId, generatePressureCircles, generateRulerTicks, getClrChangeParams, getContainerStyle, getDuotoneFilterDef, getImageSrc, getLocalStorageUsageSummary, getOleAriaLabel, getOleBadgeLabel, getOleDisplayName, getOleDownloadFileName, getOleTypeColor, getOleTypeLabel, getPasswordStrength, getPatternSvg, getPlaceholderStyle, getVersions as getRecoveryVersions, getResolvedShapeClipPath, getResolvedShapeClipPathFor, getShapeFillStrokeStyle, getSlideBackgroundStyle, getSlideTransitionAnimations, getSmartArtNodeBounds, getSpeechRecognitionCtor, getTextBlockStyle, getTextWarp, getTouchDistance, getWarpCategory, getWarpPath, gradientStateFromStyle, gradientStateOf, gradientStatePatch, gridColumns, groupElements, groupIssuesBySeverity, hasAnimation, hasCopyableFormat, hasExistingLink, hasExitedFullscreen, hasGradientFill, hasPressureVariation, headerLabel, inkViewBox, insertColumn, insertRow, interpolateWidth, isAudienceTab, isBold, isBrowserOpenableMime, isChildNode, isElementInteractive, isInjectableUrl, isItalic, isPpactionUrl, isPresenterMessage, isSigned, isTextElement, isUnderline, isUrlSafe, isValidRoomId, isViewportBackgroundPressTarget, isZoomActivationKey, issueTrackKey, issueTypeLabel, keyToLabel, latexToMathml, linePointsToSvgString, lineSpacingPatch, loadAudienceContent, mergeCaptionResults, mergeDown, mergeRight, mergeSelection, moveElementBy, moveNodeDown, moveNodeUp, msToFrameDelayCs, narrowToCircle, narrowToPolygon, narrowToRect, newChartElement, newEquationElement, newPresetShapeElement, newShapeElement, newSmartArtElement, newTableElement, newTextElement, nextVisibleIndex, nodeBold, nodeEditBox, nodeFillColor, nodeFontColor, nodeIdFromKey, nodeItalic, nodeStyle, normalizeFontFormat, normalizeSlidesPerPage, normalizeValue, numFromEvent, ommlToMathml, ooxmlDashToCssBorderStyle, openNativeEyeDropper, overallStatus, paletteColor, parseAudienceNonce, parseNodeTextarea, partitionSlides, patchChartData, patchChartStyle, patchTableData, patchTextStyle, pendingElementStyles, pickColorByClickFallback, pickSupportedMimeType, planGifFrames, planVideoSegments, pointsToSvgPathD, presenceToCursors, presetByLayout, presetsForCategory, pressuresToWidths, prevVisibleIndex, projectDrawingShapes, promoteNode, provideViewerTheme, radarAngle, radarRingPoints, recordWebm, redistributeColumnWidth, removeAnimation, removeCategory, removeColumn, removeCommentFromList, removeElementAnimation, removeGradientStopPatch, removeNode, removeRow, removeSeries, renderToCanvas, reorderAnimationDown, reorderAnimationUp, replaceInSlides, replaceMatch, requestPresentationFullscreen, resizeElement, resolveCaptionTracks, resolveChartKind, resolveFontVariant, resolveHyperlinkHref, resolveInteractiveElementId, resolveMediaSrc, resolveOleType, resolveParagraphBullet, resolvePresenterNotes, resolveProfileInitial, resolveRegionCode, resolvePalette as resolveSmartArtPalette, resolveThemeCatalogEntry, resolveTransitionDuration, revealedElementStyles, routeOrthogonalConnector, rowStyle, sampleColorFromSlide, sanitizeColor, sanitizeSlideIndex, sanitizeUserName, saveViewerProfile, scanAvailableFonts, searchSlides, seedBroadcastFields, seedHyperlinkDraft, seedPropertiesDraft, seedShareFields, segmentFrameCount, selectValue$2 as selectValue, sendBackward, sendToBack, sequentialColorScale, serializeWriteBack, seriesColor, setAnimationEmphasis, setAnimationEntrance, setAnimationExit, setAxis, setAxisLogScale, setAxisTitleStyle, setCategoryLabel, setCellText, setColorScheme, setDataLabels, setDataPointExplosion, setDataPointFill, setDataPointLabel, setDelay, setDirection, setDuration, setElementPosition, setGridlineStyle, setLayout, setLegend, setNodeStyle, setNodeText, setRepeatCount, setRepeatMode, setSequence, setSeriesChartType, setSeriesColor, setSeriesErrorBars, setSeriesMarker, setSeriesName, setSeriesTrendline, setSeriesValue, setStyle, setTimingCurve, setTitle, setTrigger, setTriggerShapeId, shapeStylePatch, sheetAfterNavigate, shouldBlockClickAdvance, shouldUseSvgWarp, showDirectionPicker, showsTemplateAffordance, signatureCountLabel, signatureKey, signatureTimestamp, signerName, statusLabel as slideDiffStatusLabel, slideNumberOf, smartArtNodes, paletteColour as smartArtPaletteColour, snapToGridStep, splitCursorCell, splitMergedCell, statusKind, statusLabel$1 as statusLabel, storeAudienceContent, stringFromEvent$5 as stringFromEvent, strokeColorOf, strokeToInkElement, styleShadowFilter, textAdvancedPatch, textAdvancedStateFromStyle, textAdvancedStateOf, textColorOf, textDirectionPatch, textStyleOf, textStylePatch, themeStyle, themeToCssVars, thumbnailHeight, thumbnailZoom, toggleCommentResolvedInList, toggleNodeBold, toggleNodeItalic, toggleSheet, topLevelNodeCount, transformSelectedTextCase, translationsEn, ungroupElements, updateElementById, updateGlowPatch, updateGradientStopPatch, updateInnerShadowPatch, updateOuterShadowPatch, updateReflectionPatch, vAlignPatch, validatePassword, validatePrintSettings, validateRoomId, valueToY, vermilionDarkColors, vermilionDarkTheme, vermilionLightColors, vermilionLightTheme, vermilionRadius, waypointsToPathD, worstStatus, zoomTargetSlideIndex };
100961
101775
  //# sourceMappingURL=pptx-angular-viewer.mjs.map