pptx-angular-viewer 3.8.0 → 3.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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, inject, computed, ChangeDetectionStrategy, Component, signal, Injectable, DestroyRef, viewChild, effect, Injector, untracked, ElementRef, HostListener, afterNextRender, Renderer2, ViewEncapsulation, forwardRef, Directive } from '@angular/core';
4
4
  import { TranslateService, TranslatePipe, translate } from '@ngx-translate/core';
5
- import { THEME_PRESETS, guideEmuToPx, evaluateCustomGeometryPathData, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, evaluateCustomGeometryPaths, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, chartDataChangeType, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, formatAutoNumberMarker, DEFAULT_POWERPOINT_TABLE_STYLE_ID, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, getPresetConnectionSites, resolveCustomGeometryToken, resolveCustomGeometryGuideContext, lookupPresetShape, normalizeStShapeType, evaluateGuides, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, parseDataUrlToBytes, deobfuscateFont, detectFontFormat, createEditorId, makeStoreAwareId, reassignDescendantIds, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, THEME_COLOR_PALETTE_COLUMNS, resolveThemeColorRef, hexToRgbChannels as hexToRgbChannels$2, rgbToHsl as rgbToHsl$1, renameSlideMaster, deleteSlideMaster, duplicateSlideMaster, insertSlideMaster, renameLayout, deleteLayout, duplicateLayout, insertLayout, detectFileFormat, cloneElement, duplicateElement, serializePptxToJson, PPTX_JSON_MIME_TYPE, PptxMarkdownConverter, ThemePresets, formatCommentTimestamp as formatCommentTimestamp$1, EncryptedFileError, decodeXmlEntities, parseSignatureXml, groupElements, ungroupElements, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, isZoomElement, SvgExporter, applyThemeToData, reResolveElementColors, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointMarker, setChartDataPointExplosion, getOleObjectTypeLabel, addSmartArtNodeAsChild, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, TRANSITION_VALID_DIRECTIONS } from 'pptx-viewer-core';
5
+ import { THEME_PRESETS, guideEmuToPx, evaluateCustomGeometryPathData, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, evaluateCustomGeometryPaths, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, flattenChartUserShapes, chartDataChangeType, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, formatAutoNumberMarker, DEFAULT_POWERPOINT_TABLE_STYLE_ID, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, getPresetConnectionSites, resolveCustomGeometryToken, resolveCustomGeometryGuideContext, lookupPresetShape, normalizeStShapeType, evaluateGuides, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, parseDataUrlToBytes, deobfuscateFont, detectFontFormat, createEditorId, makeStoreAwareId, reassignDescendantIds, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, THEME_COLOR_PALETTE_COLUMNS, resolveThemeColorRef, hexToRgbChannels as hexToRgbChannels$2, rgbToHsl as rgbToHsl$1, renameSlideMaster, deleteSlideMaster, duplicateSlideMaster, insertSlideMaster, renameLayout, deleteLayout, duplicateLayout, insertLayout, detectFileFormat, cloneElement, duplicateElement, TABLE_STYLE_PART_SEQUENCE, serializePptxToJson, PPTX_JSON_MIME_TYPE, PptxMarkdownConverter, ThemePresets, formatCommentTimestamp as formatCommentTimestamp$1, EncryptedFileError, decodeXmlEntities, parseSignatureXml, groupElements, ungroupElements, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, isZoomElement, SvgExporter, applyThemeToData, reResolveElementColors, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointMarker, setChartDataPointExplosion, getOleObjectTypeLabel, addSmartArtNodeAsChild, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, TRANSITION_VALID_DIRECTIONS } from 'pptx-viewer-core';
6
6
  import DOMPurify from 'dompurify';
7
7
  import { z } from 'zod';
8
8
  import * as mcp from 'pptx-viewer-mcp';
@@ -17530,6 +17530,73 @@ function buildTreemapViewModel(element, chartData, categoryLabels) {
17530
17530
  };
17531
17531
  }
17532
17532
 
17533
+ /**
17534
+ * Resolve `chartData.titleRuns` into per-run SVG `<tspan>` descriptors, each
17535
+ * run's own bold/italic/size/colour falling back to the title's cascade
17536
+ * (`resolveChartTitleTextStyle`) for whatever it does not override.
17537
+ *
17538
+ * Returns `undefined` when the title has no typed runs at all (an auto/plain
17539
+ * title, or one authored as a linked-cell reference), so a binding should
17540
+ * keep rendering the flat `vm.title` in `vm.titleStyle` unchanged. A single
17541
+ * run still resolves to a one-element array: this lets a per-run override
17542
+ * (e.g. italic on the title's only run) render even when
17543
+ * `resolveChartTitleTextStyle`'s coarser `chartData.style.titleFont*` cascade
17544
+ * does not carry it.
17545
+ */
17546
+ function resolveChartTitleRunSpans(chartData) {
17547
+ const runs = chartData?.titleRuns;
17548
+ if (!runs || runs.length === 0) {
17549
+ return undefined;
17550
+ }
17551
+ const base = resolveChartTitleTextStyle(chartData);
17552
+ return runs.map((run) => ({
17553
+ text: run.text,
17554
+ fontSize: run.fontSize !== undefined ? chartFontPx(run.fontSize) : base.fontSize,
17555
+ fontWeight: run.bold !== undefined ? (run.bold ? 700 : 400) : base.fontWeight,
17556
+ ...(run.italic ? { fontStyle: 'italic' } : {}),
17557
+ fill: run.color ?? base.fill,
17558
+ ...(base.fontFamily ? { fontFamily: base.fontFamily } : {}),
17559
+ }));
17560
+ }
17561
+ /**
17562
+ * The dominant style among `runs`: the longest run's (by text length; ties
17563
+ * keep the first), since that is the style covering most of the visible
17564
+ * title text.
17565
+ */
17566
+ function dominantRunStyle(runs) {
17567
+ let best = runs[0];
17568
+ for (const run of runs.slice(1)) {
17569
+ if (run.text.length > best.text.length) {
17570
+ best = run;
17571
+ }
17572
+ }
17573
+ const { bold, italic, fontSize, color } = best;
17574
+ return {
17575
+ ...(bold !== undefined ? { bold } : {}),
17576
+ ...(italic !== undefined ? { italic } : {}),
17577
+ ...(fontSize !== undefined ? { fontSize } : {}),
17578
+ ...(color !== undefined ? { color } : {}),
17579
+ };
17580
+ }
17581
+ /**
17582
+ * Compute the `{ title, titleRuns }` patch for an inspector's flat title-text
17583
+ * field being edited to `newText`. Every binding's chart title input should
17584
+ * call this instead of patching `title` alone.
17585
+ *
17586
+ * A title with zero or one run just gets the new flat text (`titleRuns`
17587
+ * untouched, letting core's single-run patch path preserve that run's full
17588
+ * authored formatting). A title with two or more runs collapses to ONE run
17589
+ * carrying `newText` in the dominant style, so the edit does not leave a
17590
+ * second, now-stale run's text trailing the new title.
17591
+ */
17592
+ function collapseChartTitleRunsForEdit(chartData, newText) {
17593
+ const runs = chartData?.titleRuns;
17594
+ if (!runs || runs.length <= 1) {
17595
+ return { title: newText };
17596
+ }
17597
+ return { title: newText, titleRuns: [{ ...dominantRunStyle(runs), text: newText }] };
17598
+ }
17599
+
17533
17600
  /**
17534
17601
  * Chart drawing-overlay projector (`c:userShapes`).
17535
17602
  *
@@ -17540,6 +17607,11 @@ function buildTreemapViewModel(element, chartData, categoryLabels) {
17540
17607
  * `absSizeAnchor` extents are EMU converted to pixels. Rendered last so the
17541
17608
  * overlay sits above the data marks.
17542
17609
  *
17610
+ * A `grpSp` entry (grouped annotation shapes with their own nested
17611
+ * transform) is expanded into positioned leaves via core's
17612
+ * `flattenChartUserShapes` before projecting, so this module never has to
17613
+ * know about groups itself.
17614
+ *
17543
17615
  * @module chart-user-shape-overlay
17544
17616
  */
17545
17617
  /** EMU per CSS pixel at 96 DPI, mirroring core's `EMU_PER_PIXEL`. */
@@ -17637,7 +17709,8 @@ function buildChartUserShapeOverlay(userShapes, svgWidth, svgHeight) {
17637
17709
  if (!userShapes || userShapes.length === 0) {
17638
17710
  return [];
17639
17711
  }
17640
- return userShapes.flatMap((shape) => projectShape(shape, svgWidth, svgHeight));
17712
+ const leaves = flattenChartUserShapes(userShapes);
17713
+ return leaves.flatMap((shape) => projectShape(shape, svgWidth, svgHeight));
17641
17714
  }
17642
17715
 
17643
17716
  /**
@@ -19518,11 +19591,13 @@ function withLegendEntries(vm, chartData) {
19518
19591
  * declares `<a:noFill/>` gets `areaFill: undefined` and no rect at all.
19519
19592
  */
19520
19593
  function withChartAreaFill(vm, chartData) {
19594
+ const titleRunSpans = resolveChartTitleRunSpans(chartData);
19521
19595
  return {
19522
19596
  ...vm,
19523
19597
  areaFill: chartAreaFill(chartData),
19524
19598
  areaRadius: chartAreaCornerRadius(chartData),
19525
19599
  titleStyle: resolveChartTitleTextStyle(chartData),
19600
+ ...(titleRunSpans ? { titleRunSpans } : {}),
19526
19601
  plotFill: plotAreaFill(chartData),
19527
19602
  };
19528
19603
  }
@@ -20786,6 +20861,127 @@ function setChartCellValue(data, seriesIndex, categoryIndex, raw) {
20786
20861
  return chartDataUpdatePoint(data, seriesIndex, categoryIndex, value);
20787
20862
  }
20788
20863
 
20864
+ const TWO_PI = Math.PI * 2;
20865
+ /** Keep the dragged span strictly inside (0, 2*PI) so the share never hits 0 or 1. */
20866
+ const ANGLE_EPSILON = TWO_PI * 0.001;
20867
+ /**
20868
+ * Resolve the drag geometry for series 0's slice at `pointIndex`, or `null`
20869
+ * when `chartData` is not a pie/doughnut, has no series, or the index is out
20870
+ * of range. `element` is the chart's frame box (EMU-agnostic width/height, the
20871
+ * same units `PptxElement.width/height` and `computePieLayout` use).
20872
+ */
20873
+ function buildPieDragGeometry(element, chartData, pointIndex) {
20874
+ if (chartData.chartType !== 'pie' && chartData.chartType !== 'doughnut') {
20875
+ return null;
20876
+ }
20877
+ const series = chartData.series[0];
20878
+ if (!series || pointIndex < 0 || pointIndex >= series.values.length) {
20879
+ return null;
20880
+ }
20881
+ const isDoughnut = chartData.chartType === 'doughnut', { cx, cy } = computePieLayout(element.width, element.height, chartData, isDoughnut),
20882
+ // Mirrors buildPieViewModel's own startAngle line exactly (chart-view-model-pie.ts).
20883
+ startAngle = -Math.PI / 2 + ((chartData.firstSliceAngle ?? 0) * Math.PI) / 180;
20884
+ return { cx, cy, values: series.values, pointIndex, startAngle };
20885
+ }
20886
+ /**
20887
+ * New value for the dragged slice given the pointer's (view-box) position.
20888
+ * The slice's leading edge stays put; the span from there to the pointer's
20889
+ * angle becomes the slice's new share of the series total, and
20890
+ * {@link shareToValue} converts that share back to an absolute value holding
20891
+ * every other (unchanged) slice's value fixed.
20892
+ */
20893
+ function resolvePieDragValue(geometry, pointerX, pointerY) {
20894
+ const { cx, cy, values, pointIndex, startAngle } = geometry, total = values.reduce((sum, v) => sum + Math.abs(v), 0) || 1, before = values.slice(0, pointIndex).reduce((sum, v) => sum + Math.abs(v), 0), leadingAngle = startAngle + (before / total) * TWO_PI, pointerAngle = Math.atan2(pointerY - cy, pointerX - cx), rawSpan = ((pointerAngle - leadingAngle) % TWO_PI) + TWO_PI, span = Math.min(Math.max(rawSpan % TWO_PI, ANGLE_EPSILON), TWO_PI - ANGLE_EPSILON), share = span / TWO_PI, own = values[pointIndex] ?? 0, sign = own < 0 ? -1 : 1, others = total - Math.abs(own), absValue = shareToValue(share, others), range = {
20895
+ min: 0,
20896
+ max: Math.max(total, absValue, 1),
20897
+ span: Math.max(total, absValue, 1),
20898
+ };
20899
+ return roundDragValue(sign * absValue, range);
20900
+ }
20901
+
20902
+ /**
20903
+ * Resolve the drag geometry for `pointIndex`'s vertex, or `null` when
20904
+ * `chartData` is not a radar chart or the index is out of range. Mirrors
20905
+ * `buildRadarViewModel`'s own cx/cy/radius/maxVal derivation exactly
20906
+ * (chart-view-model-radar.ts) so the drag target never drifts from what is
20907
+ * actually drawn.
20908
+ */
20909
+ function buildRadarDragGeometry(element, chartData, categoryLabels, pointIndex) {
20910
+ if (chartData.chartType !== 'radar') {
20911
+ return null;
20912
+ }
20913
+ const catCount = Math.max(categoryLabels.length, 1);
20914
+ if (pointIndex < 0 || pointIndex >= catCount) {
20915
+ return null;
20916
+ }
20917
+ const layout = computePlotLayout(element.width, element.height, chartData, false), cx = layout.plotLeft + layout.plotWidth / 2, cy = layout.plotTop + layout.plotHeight / 2, radius = Math.max(Math.min(layout.plotWidth, layout.plotHeight) / 2 - 4, 1), maxVal = Math.max(1, ...chartData.series.flatMap((s) => s.values.map((v) => Math.abs(v)))), angle = radarAngle(pointIndex, catCount);
20918
+ return { cx, cy, radius, maxVal, angle };
20919
+ }
20920
+ /**
20921
+ * New value for the dragged vertex given the pointer's (view-box) position:
20922
+ * the pointer vector from the centre is projected onto the spoke direction
20923
+ * (perpendicular drift is ignored, matching "radial drag along the category
20924
+ * spoke"), clamped to non-negative, then scaled back from ring radius to
20925
+ * value via the same `radius / maxVal` ratio the renderer draws with.
20926
+ */
20927
+ function resolveRadarDragValue(geometry, pointerX, pointerY) {
20928
+ const { cx, cy, radius, maxVal, angle } = geometry, dx = pointerX - cx, dy = pointerY - cy, radial = Math.max(dx * Math.cos(angle) + dy * Math.sin(angle), 0), value = (radial / radius) * maxVal, range = {
20929
+ min: 0,
20930
+ max: Math.max(maxVal, value, 1),
20931
+ span: Math.max(maxVal, value, 1),
20932
+ };
20933
+ return roundDragValue(value, range);
20934
+ }
20935
+
20936
+ /**
20937
+ * Resolve the drag geometry for one (seriesIndex, pointIndex) stacked
20938
+ * segment, or `null` when the chart is not stacked/percentStacked, the series
20939
+ * has no values, or the point is out of range.
20940
+ */
20941
+ function buildStackedDragGeometry(element, chartData, seriesIndex, pointIndex) {
20942
+ const grouping = chartData.grouping;
20943
+ if (grouping !== 'stacked' && grouping !== 'percentStacked') {
20944
+ return null;
20945
+ }
20946
+ const seriesValues = chartData.series.map((s) => s.values), draggedValues = seriesValues[seriesIndex];
20947
+ if (!draggedValues || pointIndex < 0 || pointIndex >= draggedValues.length) {
20948
+ return null;
20949
+ }
20950
+ const percent = grouping === 'percentStacked', catCount = Math.max(chartData.categories.length, ...seriesValues.map((values) => values.length), pointIndex + 1), plots = computeStackedSeriesPlots(seriesValues, catCount, percent), baseValue = plots[seriesIndex]?.base[pointIndex] ?? 0, otherAbsSum = seriesValues.reduce((sum, values, si) => (si === seriesIndex ? sum : sum + Math.abs(values[pointIndex] ?? 0)), 0), range = percent
20951
+ ? { min: 0, max: 100, span: 100 }
20952
+ : computeStackedValueRange(chartData.series, catCount), layoutOpts = computeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length), layout = computePlotLayout(element.width, element.height, chartData, true, layoutOpts);
20953
+ return {
20954
+ range,
20955
+ plotTop: layout.plotTop,
20956
+ plotBottom: layout.plotBottom,
20957
+ baseValue,
20958
+ otherAbsSum,
20959
+ percent,
20960
+ };
20961
+ }
20962
+ /**
20963
+ * New value for the dragged series at this category given the pointer's Y
20964
+ * (view-box units). The pointer projects to a cumulative value/percent at the
20965
+ * segment's top edge; subtracting the fixed base below it gives the dragged
20966
+ * series' own new share. A plain stacked chart uses that directly (the other
20967
+ * series' absolute values are untouched, so the category total simply grows
20968
+ * or shrinks); percentStacked instead treats it as a percentage SHARE and
20969
+ * converts it back to an absolute value via {@link shareToValue}, holding
20970
+ * every other series' value fixed (matching the pie slice renormalisation).
20971
+ */
20972
+ function resolveStackedDragValue(geometry, pointerY) {
20973
+ const { range, plotTop, plotBottom, baseValue, otherAbsSum, percent } = geometry, pointerScalar = valueFromY(pointerY, range, plotTop, plotBottom), delta = pointerScalar - baseValue;
20974
+ if (!percent) {
20975
+ return roundDragValue(delta, range);
20976
+ }
20977
+ const sign = delta < 0 ? -1 : 1, absValue = shareToValue(Math.abs(delta) / 100, otherAbsSum), valueRange = {
20978
+ min: 0,
20979
+ max: Math.max(otherAbsSum, absValue, 1),
20980
+ span: Math.max(otherAbsSum, absValue, 1),
20981
+ };
20982
+ return roundDragValue(sign * absValue, valueRange);
20983
+ }
20984
+
20789
20985
  // ─────────────────────────────────────────────────────────────────────────────
20790
20986
  // DOM data-attribute bridge
20791
20987
  // ─────────────────────────────────────────────────────────────────────────────
@@ -20886,6 +21082,23 @@ function roundDragValue(value, range) {
20886
21082
  // Snap away float noise from the multiplication (e.g. 0.30000000000000004).
20887
21083
  return Number.parseFloat(rounded.toPrecision(12));
20888
21084
  }
21085
+ /**
21086
+ * Convert a target SHARE (0..1, exclusive) of a whole back to an absolute
21087
+ * value, holding every other part's absolute value (`otherAbsSum`) fixed:
21088
+ * `share = value / (value + otherAbsSum)` solved for `value`. Used by both a
21089
+ * dragged pie/doughnut slice's angle share and a dragged percentStacked
21090
+ * segment's percent share, so the two renormalise identically. `share` is
21091
+ * clamped short of 1 so a lone part (no others to renormalise against) still
21092
+ * returns a finite, monotonically increasing value instead of Infinity.
21093
+ */
21094
+ function shareToValue(share, otherAbsSum) {
21095
+ const clamped = Math.min(Math.max(share, 0), 0.999999);
21096
+ if (clamped <= 0) {
21097
+ return 0;
21098
+ }
21099
+ const ratio = clamped / (1 - clamped);
21100
+ return otherAbsSum > 0 ? ratio * otherAbsSum : ratio;
21101
+ }
20889
21102
  /** The value range a series maps against (secondary when axis-mapped there). */
20890
21103
  function rangeForSeries(drag, seriesIndex) {
20891
21104
  const useSecondary = drag.secondaryRange !== undefined &&
@@ -20937,10 +21150,53 @@ function withChartTitle(chartData, title) {
20937
21150
  const trimmed = title.trim();
20938
21151
  return {
20939
21152
  ...chartData,
20940
- title: trimmed,
21153
+ // A multi-run title collapses to one run in its dominant style so this
21154
+ // edit does not leave another, now-stale run's text trailing the new
21155
+ // title; see `collapseChartTitleRunsForEdit`'s doc.
21156
+ ...collapseChartTitleRunsForEdit(chartData, trimmed),
20941
21157
  style: { ...chartData.style, hasTitle: trimmed.length > 0 },
20942
21158
  };
20943
21159
  }
21160
+ /**
21161
+ * Resolve a mark drag's geometry for the given chart kind and part, or `null`
21162
+ * when that kind/part combination has no drag meaning (e.g. a clustered bar,
21163
+ * which uses `ChartValueDrag`/`dragValueForPart` instead).
21164
+ */
21165
+ function buildChartMarkDragGeometry(params) {
21166
+ const { kind, element, chartData, categoryLabels, seriesIndex, pointIndex } = params;
21167
+ if (kind === 'pie' || kind === 'doughnut') {
21168
+ const geometry = buildPieDragGeometry(element, chartData, pointIndex);
21169
+ return geometry ? { kind: 'pie', ...geometry } : null;
21170
+ }
21171
+ if (kind === 'radar') {
21172
+ const geometry = buildRadarDragGeometry(element, chartData, categoryLabels, pointIndex);
21173
+ return geometry ? { kind: 'radar', ...geometry } : null;
21174
+ }
21175
+ if (kind === 'bar' || kind === 'line' || kind === 'area') {
21176
+ const geometry = buildStackedDragGeometry(element, chartData, seriesIndex, pointIndex);
21177
+ return geometry ? { kind: 'stackedSegment', ...geometry } : null;
21178
+ }
21179
+ return null;
21180
+ }
21181
+ /**
21182
+ * New value for a dragged mark, dispatched by the geometry's own `kind`. This
21183
+ * is the single entry point every binding's pointer handler calls; each kind's
21184
+ * actual math lives in its own `chart-interaction-*.ts` sibling.
21185
+ */
21186
+ function resolveChartDragValue(geometry, pointer) {
21187
+ switch (geometry.kind) {
21188
+ case 'pie':
21189
+ return resolvePieDragValue(geometry, pointer.x, pointer.y);
21190
+ case 'radar':
21191
+ return resolveRadarDragValue(geometry, pointer.x, pointer.y);
21192
+ case 'stackedSegment':
21193
+ return resolveStackedDragValue(geometry, pointer.y);
21194
+ default: {
21195
+ const exhaustive = geometry;
21196
+ return exhaustive;
21197
+ }
21198
+ }
21199
+ }
20944
21200
 
20945
21201
  /**
20946
21202
  * Minimum pointer travel (px) before a mark press becomes a value drag.
@@ -21184,6 +21440,65 @@ function validateChartUserShapeAnchor(shape) {
21184
21440
  return undefined;
21185
21441
  }
21186
21442
 
21443
+ /**
21444
+ * Map a client-space pointer position into the chart's SVG view-box units,
21445
+ * given the rendered `<svg>`'s bounding rect.
21446
+ */
21447
+ function clientPointToViewBox(clientX, clientY, rect, svgWidth, svgHeight) {
21448
+ if (rect.width === 0 || rect.height === 0) {
21449
+ return { x: 0, y: 0 };
21450
+ }
21451
+ return {
21452
+ x: ((clientX - rect.left) / rect.width) * svgWidth,
21453
+ y: ((clientY - rect.top) / rect.height) * svgHeight,
21454
+ };
21455
+ }
21456
+ /**
21457
+ * Start a mark drag, or return `null` when there is no geometry for this part
21458
+ * (not a draggable mark kind, or the press was not on a `dataPoint`).
21459
+ */
21460
+ function beginChartMarkDrag(params) {
21461
+ const { part, geometry, chartData, svgWidth, svgHeight, clientX, clientY } = params;
21462
+ if (!geometry || part.role !== 'dataPoint' || part.pointIndex === undefined) {
21463
+ return null;
21464
+ }
21465
+ return {
21466
+ part,
21467
+ geometry,
21468
+ svgWidth,
21469
+ svgHeight,
21470
+ baseChartData: chartData,
21471
+ startClientX: clientX,
21472
+ startClientY: clientY,
21473
+ moved: false,
21474
+ lastData: null,
21475
+ };
21476
+ }
21477
+ /**
21478
+ * Advance an in-flight mark drag to the pointer's current client position.
21479
+ *
21480
+ * Returns `null` (leaving `state` untouched) while the press is still inside
21481
+ * the click threshold or `rect` is not measurable. Otherwise MUTATES
21482
+ * `state.moved` / `state.lastData` and returns the step, so the caller can
21483
+ * preview it and commit `state.lastData` once on release.
21484
+ */
21485
+ function advanceChartMarkDrag(state, clientX, clientY, rect) {
21486
+ if (state.part.pointIndex === undefined) {
21487
+ return null;
21488
+ }
21489
+ const travelled = Math.hypot(clientX - state.startClientX, clientY - state.startClientY);
21490
+ if (!state.moved && travelled < CHART_DRAG_THRESHOLD_PX) {
21491
+ return null;
21492
+ }
21493
+ if (rect.width === 0 || rect.height === 0) {
21494
+ return null;
21495
+ }
21496
+ state.moved = true;
21497
+ const pointer = clientPointToViewBox(clientX, clientY, rect, state.svgWidth, state.svgHeight), value = resolveChartDragValue(state.geometry, pointer), chartData = withChartPointValue(state.baseChartData, state.part.seriesIndex, state.part.pointIndex, value);
21498
+ state.lastData = chartData;
21499
+ return { chartData, value };
21500
+ }
21501
+
21187
21502
  /**
21188
21503
  * `animation-mask-reveal`: CSS `mask`-based reveal states for the clip family
21189
21504
  * of entrance/exit effects (wipe, peek, blinds, split, box, random bars).
@@ -22993,8 +23308,10 @@ const EXTENDED_ENTR_PRESETS = {
22993
23308
  * Split) had no dedicated exit keyframe at all before this pass, unlike their
22994
23309
  * entrance counterparts; the new `peekOut`/`splitOut` keyframes in
22995
23310
  * `animation-keyframes-exit-shapes.ts` reuse the same mask-reveal technique
22996
- * in reverse. exit.11 and exit.12 are intentionally NOT in this table: see
22997
- * the leading comment on `PRESET_ID_TO_EFFECT.exit` in `animation-presets.ts`.
23311
+ * in reverse. exit.11 and exit.12 are intentionally NOT in this table: both
23312
+ * now have dedicated playback keyframes (`flashOnceOut`, `peekOutDown`)
23313
+ * wired directly in `animation-presets-exit.ts` alongside this pass's other
23314
+ * directly-verified ids, rather than through this extended table.
22998
23315
  */
22999
23316
  const EXTENDED_EXIT_PRESETS = {
23000
23317
  7: 'flyOutBottom', // Crawl Out
@@ -23161,10 +23478,21 @@ const ENTR_PRESETS = {
23161
23478
  */
23162
23479
  /** OOXML exit `p:cTn/@presetId` -> playback effect name. */
23163
23480
  const EXIT_PRESETS$1 = {
23164
- // exit.11 (Flash Once) and exit.12 are the only two of the 68 exit IDs
23165
- // deliberately left unmapped after this pass; see the module doc on
23166
- // `animation-presets-extended.ts` for why (exit.12 has no authoring
23167
- // identity at all today and would collide with exit.16's Peek Out).
23481
+ // exit.11 (Flash Once), verified via COM: `msoAnimEffectFlashOnce` with
23482
+ // `Effect.Exit = True` serializes as presetID 11 with no `@filter`,
23483
+ // matching entr.11's `flashIn`. Plays via its own `flashOnceOut` keyframe
23484
+ // (a `style.visibility` flicker ending hidden) rather than the entrance
23485
+ // keyframe played backwards, since PowerPoint's own authored effect is a
23486
+ // discrete visibility toggle pair, not a smooth opacity ramp.
23487
+ 11: 'flashOnceOut',
23488
+ // exit.12 (Peek Out, presetSubtype 4 / bottom edge), verified via COM
23489
+ // (this repo's own PowerShell automation): `AddEffect` with the Peek In
23490
+ // `MsoAnimEffect` constant then `Effect.Exit = True` re-emits
23491
+ // `presetID="12"` with `filter="wipe(down)"`. Named `peekOutDown` (not
23492
+ // `peekOut`) because that name is already bound to exit.16's own
23493
+ // (pre-existing, out-of-scope) "Peek Out" mismatch; see
23494
+ // `animation-keyframes-exit-shapes.ts`'s note on both keyframes.
23495
+ 12: 'peekOutDown',
23168
23496
  1: 'disappear',
23169
23497
  2: 'flyOutBottom',
23170
23498
  // exit.6 = Circle, confirmed via COM (`msoAnimEffectCircle` with
@@ -23335,6 +23663,310 @@ const PRESET_ID_TO_EFFECT = {
23335
23663
  emph: EMPH_PRESETS,
23336
23664
  };
23337
23665
 
23666
+ /**
23667
+ * `animation-text-style-resolve` - resolves the discrete font-style / colour /
23668
+ * size override PowerPoint's font-style emphasis effects apply to their
23669
+ * target's text: Bold Flash, Bold Reveal, Underline, Brush On Underline,
23670
+ * Font Style / Change Font Style, Change Font Size, and the font-style `p:set`
23671
+ * siblings composed alongside Wave / Grow With Color / Teeter.
23672
+ *
23673
+ * PowerPoint authors these two ways, both already parsed by core:
23674
+ * - A `p:set` discrete (non-interpolated) assignment
23675
+ * ({@link PptxNativeAnimation.setAnimations}, ECMA-376 S19.5.79
23676
+ * CT_TLSetBehavior): the value snaps on once and holds until the effect's
23677
+ * `p:cTn/@fill` says otherwise (Bold Reveal, Underline / Brush On
23678
+ * Underline).
23679
+ * - A generic `p:anim` ramp ({@link PptxNativeAnimation.attributeAnimations},
23680
+ * ECMA-376 S19.5.2 CT_TLAnimateBehavior) whose `p:tavLst` stops are not
23681
+ * numerically interpolatable for a boolean attribute (Bold Flash): only the
23682
+ * LAST stop's value is meaningful, the same "snap at the end" reading
23683
+ * PowerPoint itself gives a discrete `calcMode` ramp.
23684
+ *
23685
+ * Ground truth (COM `AddEffect` + raw OOXML inspection, see
23686
+ * `animation-emphasis-ground-truth-early.ts`): `style.fontWeight` (bold),
23687
+ * `style.fontStyle` (italic), `style.textDecorationUnderline` (underline),
23688
+ * `style.fontSize` (a numeric ramp: this module reads its FIRST/LAST stop
23689
+ * ratio as {@link TextStyleAnimationDescriptor.fontScale}, a relative
23690
+ * multiplier rather than an absolute size, since a shape's runs may not all
23691
+ * share the authored effect's own reference size), and `style.color` (font
23692
+ * colour, distinct from `fillcolor`/`stroke.color`, which the existing
23693
+ * `p:animClr` colour-animation path already owns).
23694
+ *
23695
+ * Deliberately does NOT model a "during" vs "after" phase distinction: the
23696
+ * hold-vs-revert decision this effect's `p:cTn/@fill` makes is already
23697
+ * computed once, correctly, by `animation-fill-repeat.ts`'s
23698
+ * `shouldHoldEndState` (the exact same rule CSS-animation steps already use
23699
+ * to decide whether their final frame persists on cleanup) and surfaced on
23700
+ * {@link import('./animation-timeline-types').TimelineStep.holdEndState}.
23701
+ * `animation-text-style-state.ts` reuses that flag rather than recomputing
23702
+ * hold/revert semantics a second time here.
23703
+ *
23704
+ * @module render/animation-text-style-resolve
23705
+ */
23706
+ /** The three boolean-valued style attrs a `p:set`/`p:anim` can drive. */
23707
+ const BOOLEAN_ATTR_FIELD = {
23708
+ 'style.fontweight': 'bold',
23709
+ 'style.fontstyle': 'italic',
23710
+ 'style.textdecorationunderline': 'underline',
23711
+ // Tolerate the shorter spelling some non-PowerPoint producers use.
23712
+ 'style.underline': 'underline',
23713
+ };
23714
+ const RECOGNIZED_ATTRS = new Set([
23715
+ ...Object.keys(BOOLEAN_ATTR_FIELD),
23716
+ 'style.fontsize',
23717
+ 'style.color',
23718
+ ]);
23719
+ /** Decode a `p:set`/`p:tav` value into the boolean a style attr expects. */
23720
+ function decodeBooleanAttr(attrName, value) {
23721
+ if (typeof value === 'boolean') {
23722
+ return value;
23723
+ }
23724
+ if (typeof value === 'number') {
23725
+ return value !== 0;
23726
+ }
23727
+ const normalized = value.trim().toLowerCase();
23728
+ if (normalized === 'true' || normalized === '1') {
23729
+ return true;
23730
+ }
23731
+ if (normalized === 'false' || normalized === '0' || normalized === '') {
23732
+ return false;
23733
+ }
23734
+ if (attrName === 'style.fontweight') {
23735
+ return normalized === 'bold' || normalized === '700';
23736
+ }
23737
+ if (attrName === 'style.fontstyle') {
23738
+ return normalized === 'italic';
23739
+ }
23740
+ return normalized === 'underline';
23741
+ }
23742
+ /** Apply one decoded (attrName, value) pair onto the descriptor being built. */
23743
+ function applyDecodedValue(descriptor, attrName, value) {
23744
+ const boolField = BOOLEAN_ATTR_FIELD[attrName];
23745
+ if (boolField) {
23746
+ descriptor[boolField] = decodeBooleanAttr(attrName, value);
23747
+ return;
23748
+ }
23749
+ if (attrName === 'style.color' && typeof value === 'string' && value !== '') {
23750
+ descriptor.color = value;
23751
+ }
23752
+ }
23753
+ function applySetAnimation(descriptor, entry) {
23754
+ applyDecodedValue(descriptor, entry.attrName, entry.value);
23755
+ }
23756
+ /**
23757
+ * Apply one `p:anim` ramp component. `style.fontsize` is read as a
23758
+ * first-stop -> last-stop RATIO (see the module doc). A boolean attr (Bold
23759
+ * Flash's `style.fontweight`) is read as "true if ANY stop is true", not just
23760
+ * the last: PowerPoint composes the whole flash-and-revert pattern (e.g.
23761
+ * normal -> bold -> normal) inside the SAME ramp, so reading only the final
23762
+ * stop would resolve to "never bold" and the flash would never render at
23763
+ * all. `style.color`'s last stop is used as-is (there is no boolean
23764
+ * "any"-style reading for a colour).
23765
+ */
23766
+ function applyAttributeRamp(descriptor, component) {
23767
+ const stops = component.keyframes;
23768
+ if (stops.length === 0) {
23769
+ return;
23770
+ }
23771
+ const last = stops[stops.length - 1];
23772
+ if (component.attrName === 'style.fontsize') {
23773
+ const firstNumeric = Number(stops[0].value);
23774
+ const lastNumeric = Number(last.value);
23775
+ if (Number.isFinite(firstNumeric) && firstNumeric !== 0 && Number.isFinite(lastNumeric)) {
23776
+ descriptor.fontScale = lastNumeric / firstNumeric;
23777
+ }
23778
+ return;
23779
+ }
23780
+ const boolField = BOOLEAN_ATTR_FIELD[component.attrName];
23781
+ if (boolField) {
23782
+ descriptor[boolField] = stops.some((stop) => decodeBooleanAttr(component.attrName, stop.value));
23783
+ return;
23784
+ }
23785
+ applyDecodedValue(descriptor, component.attrName, last.value);
23786
+ }
23787
+ /**
23788
+ * Resolve the text-style override an authored effect composes via `p:set`
23789
+ * siblings and/or a `style.fontsize`/boolean `p:anim` ramp. Returns
23790
+ * `undefined` when the effect carries none of the recognised attrs, so a
23791
+ * caller can fall back to the neutral emphasis animation exactly as before.
23792
+ */
23793
+ function resolveTextStyleAnimation(anim) {
23794
+ const descriptor = {};
23795
+ for (const entry of anim.setAnimations ?? []) {
23796
+ applySetAnimation(descriptor, entry);
23797
+ }
23798
+ for (const component of anim.attributeAnimations ?? []) {
23799
+ if (RECOGNIZED_ATTRS.has(component.attrName)) {
23800
+ applyAttributeRamp(descriptor, component);
23801
+ }
23802
+ }
23803
+ return Object.keys(descriptor).length > 0 ? descriptor : undefined;
23804
+ }
23805
+
23806
+ /**
23807
+ * `animation-text-style-css` - builds a scoped, `!important` CSS rule that
23808
+ * applies an active {@link TextStyleAnimationDescriptor} on top of an
23809
+ * element's own rendered text runs.
23810
+ *
23811
+ * Every binding already stamps its top-level rendered element wrapper with
23812
+ * `data-element-id="<id>"` (selection, hit-testing, the four non-React
23813
+ * bindings' post-render DOM pass). A run span always carries its OWN inline
23814
+ * `style` attribute (bold/italic/underline/size are declared there
23815
+ * unconditionally, see `text-run-style.ts`), so plain CSS inheritance from an
23816
+ * ancestor can never reach it: only a stylesheet rule with `!important`
23817
+ * outranks another element's own inline style. Scoping the selector to this
23818
+ * element's `data-element-id` keeps the override from leaking onto sibling
23819
+ * elements that reuse the same generic run markup.
23820
+ *
23821
+ * `fontScale` is applied as `calc(1em * <scale>)` rather than an absolute
23822
+ * size: once this rule wins, the run's own inline `font-size` is not
23823
+ * consulted at all, so the `em` here resolves against the INHERITED
23824
+ * (ancestor) font-size, giving a reasonable relative-size approximation
23825
+ * without needing per-run size bookkeeping at the override layer.
23826
+ *
23827
+ * @module render/animation-text-style-css
23828
+ */
23829
+ /** Escape a value for safe use inside a double-quoted CSS attribute selector. */
23830
+ function escapeCssAttributeValue$1(value) {
23831
+ return value.replaceAll('\\', '\\\\').replaceAll('"', '\\"');
23832
+ }
23833
+ /**
23834
+ * Build the CSS override rule for one element's active text-style animation,
23835
+ * or `undefined` when there is nothing to override (so a binding can skip
23836
+ * rendering a `<style>` tag entirely).
23837
+ *
23838
+ * Emits TWO scoped rules, both keyed off the SAME `data-element-id`, so one
23839
+ * call covers every element type a font-style emphasis effect can target
23840
+ * (text/shape, a table cell, a connector caption, a chart title/label/legend,
23841
+ * a SmartArt node caption): a binding no longer needs to gate this call on
23842
+ * "is this a plain text element" - PowerPoint animates a table cell or a
23843
+ * chart title exactly the same way.
23844
+ *
23845
+ * - The `[style]` rule targets ordinary HTML text (paragraph runs, table
23846
+ * cell spans, connector caption spans): every one of those already carries
23847
+ * its OWN inline `style` attribute (see the module doc), which plain CSS
23848
+ * inheritance cannot reach.
23849
+ * - The `text, tspan` rule targets SVG text (chart titles/axis
23850
+ * labels/data labels/legend, SmartArt node captions): every binding draws
23851
+ * those as raw SVG presentation ATTRIBUTES (`fill=`, `font-weight=`, ...),
23852
+ * never an inline `style`, so the `[style]` rule's selector never matches
23853
+ * them at all. `font-weight`/`font-style`/`font-size`/`text-decoration`
23854
+ * are CSS properties SVG text already honours; `color` is not (SVG paints
23855
+ * text via `fill`), so the colour case is re-expressed as `fill` here
23856
+ * instead of reusing the `color` declaration.
23857
+ *
23858
+ * Neither rule leaks onto a chart's non-text SVG (bars, slices, borders):
23859
+ * `text, tspan` is a plain type selector, not `*`, so nothing else in the
23860
+ * element's subtree matches it.
23861
+ */
23862
+ function buildTextStyleOverrideCss(elementId, style) {
23863
+ if (!style) {
23864
+ return undefined;
23865
+ }
23866
+ const declarations = [];
23867
+ const svgDeclarations = [];
23868
+ if (style.bold !== undefined) {
23869
+ const decl = `font-weight: ${style.bold ? 'bold' : 'normal'} !important;`;
23870
+ declarations.push(decl);
23871
+ svgDeclarations.push(decl);
23872
+ }
23873
+ if (style.italic !== undefined) {
23874
+ const decl = `font-style: ${style.italic ? 'italic' : 'normal'} !important;`;
23875
+ declarations.push(decl);
23876
+ svgDeclarations.push(decl);
23877
+ }
23878
+ if (style.underline !== undefined) {
23879
+ const decl = `text-decoration-line: ${style.underline ? 'underline' : 'none'} !important;`;
23880
+ declarations.push(decl);
23881
+ svgDeclarations.push(decl);
23882
+ }
23883
+ if (typeof style.fontScale === 'number' &&
23884
+ Number.isFinite(style.fontScale) &&
23885
+ style.fontScale > 0) {
23886
+ const decl = `font-size: calc(1em * ${style.fontScale}) !important;`;
23887
+ declarations.push(decl);
23888
+ svgDeclarations.push(decl);
23889
+ }
23890
+ if (style.color) {
23891
+ declarations.push(`color: ${style.color} !important;`);
23892
+ svgDeclarations.push(`fill: ${style.color} !important;`);
23893
+ }
23894
+ if (declarations.length === 0) {
23895
+ return undefined;
23896
+ }
23897
+ const scope = `[data-element-id="${escapeCssAttributeValue$1(elementId)}"]`;
23898
+ const htmlRule = `${scope} [style] { ${declarations.join(' ')} }`;
23899
+ const svgRule = `${scope} text, ${scope} tspan { ${svgDeclarations.join(' ')} }`;
23900
+ return `${htmlRule}\n${svgRule}`;
23901
+ }
23902
+ /**
23903
+ * A visually inert `@keyframes` block for an emphasis step whose ONLY effect
23904
+ * is a text-style change (Bold Reveal, Underline, Style Emphasis, ...).
23905
+ *
23906
+ * The timeline builder needs every step to own a CSS animation so the
23907
+ * playback engine's timing (delay, duration, cleanup) has something to hang
23908
+ * off, but the unmapped-preset safety net used to hand these steps a neutral
23909
+ * `pulse`, so PowerPoint's plain "the text turns bold" played with a scale
23910
+ * throb on top. This keyframe holds the element exactly as rendered while the
23911
+ * `textStyle` override does the visible work.
23912
+ */
23913
+ function buildTextStyleHoldKeyframe(uid) {
23914
+ const keyframeName = `pptx-tl-textstyle-hold-${uid}`;
23915
+ return {
23916
+ keyframeName,
23917
+ css: `@keyframes ${keyframeName} {\n\tfrom { opacity: 1; }\n\tto { opacity: 1; }\n}`,
23918
+ };
23919
+ }
23920
+
23921
+ /**
23922
+ * `animation-text-style-state` - pure merge/revert helpers for carrying a
23923
+ * {@link TextStyleAnimationDescriptor} through `animation-playback-engine.ts`'s
23924
+ * step-start and step-cleanup writes, mirroring how `carryBuildState` already
23925
+ * carries `build`/`chartReveal`/`diagramReveal` forward so one step's write
23926
+ * never clobbers a concern a DIFFERENT still-active step on the same element
23927
+ * owns.
23928
+ *
23929
+ * @module render/animation-text-style-state
23930
+ */
23931
+ /**
23932
+ * Merge a step's text-style override onto whatever the element already
23933
+ * carries (from a still-active earlier step), on step START. The new step's
23934
+ * fields win on a conflict; fields it does not mention pass through
23935
+ * unchanged.
23936
+ */
23937
+ function mergeTextStyleOnStart(carried, stepStyle) {
23938
+ if (!stepStyle) {
23939
+ return carried;
23940
+ }
23941
+ return { ...carried, ...stepStyle };
23942
+ }
23943
+ /**
23944
+ * Resolve the text-style override left after a step's CLEANUP.
23945
+ *
23946
+ * `holdEndState` mirrors `p:cTn/@fill="hold"/"freeze"/"transition"` (see
23947
+ * `animation-fill-repeat.ts`'s `shouldHoldEndState`, the same flag that keeps
23948
+ * a CSS animation's final frame attached instead of clearing it): when set,
23949
+ * the step's fields stay merged in permanently; otherwise only the KEYS this
23950
+ * step itself set are reverted, so a different still-active step's fields
23951
+ * (e.g. a concurrent colour change) are not clobbered.
23952
+ */
23953
+ function resolveTextStyleOnCleanup(carried, stepStyle, holdEndState) {
23954
+ if (!stepStyle) {
23955
+ return carried;
23956
+ }
23957
+ if (holdEndState) {
23958
+ return { ...carried, ...stepStyle };
23959
+ }
23960
+ if (!carried) {
23961
+ return undefined;
23962
+ }
23963
+ const remaining = { ...carried };
23964
+ for (const key of Object.keys(stepStyle)) {
23965
+ delete remaining[key];
23966
+ }
23967
+ return Object.keys(remaining).length > 0 ? remaining : undefined;
23968
+ }
23969
+
23338
23970
  /**
23339
23971
  * `animation-filter-random`: resolves the `random` SMIL/ECMA-376
23340
23972
  * `p:animEffect/@filter` family (see `animation-filter-effects`'s module doc
@@ -24063,6 +24695,19 @@ const EXIT_KEYFRAME_DEFINITIONS = {
24063
24695
  0% { opacity: 1; }
24064
24696
  99% { opacity: 1; }
24065
24697
  100% { opacity: 0; }
24698
+ }`,
24699
+ // Flash Once (exit.11), verified via COM: `msoAnimEffectFlashOnce` with
24700
+ // `Effect.Exit = True` serializes as presetID 11 with no `@filter` (the
24701
+ // exit-gallery counterpart of entr.11's `flashIn`, which also carries no
24702
+ // filter). The real authored effect is a `style.visibility` set pair
24703
+ // (hidden/visible flashed a few times); this mirrors `flashIn`'s opacity
24704
+ // flicker but ends HIDDEN rather than visible, since this is an exit.
24705
+ flashOnceOut: `@keyframes pptx-flashOnceOut {
24706
+ 0% { opacity: 1; }
24707
+ 25% { opacity: 0; }
24708
+ 50% { opacity: 1; }
24709
+ 75% { opacity: 0; }
24710
+ 100% { opacity: 0; }
24066
24711
  }`,
24067
24712
  };
24068
24713
 
@@ -24125,6 +24770,19 @@ const EXIT_SHAPE_KEYFRAME_DEFINITIONS = {
24125
24770
  peekOut: `@keyframes pptx-peekOut {
24126
24771
  from { ${maskEdgeDecl('bottom', 'shown')} opacity: 1; }
24127
24772
  to { ${maskEdgeDecl('bottom', 'hidden')} opacity: 0; }
24773
+ }`,
24774
+ // Peek Out (exit.12), verified via COM (this repo's own PowerShell
24775
+ // automation): `AddEffect` with the Peek In `MsoAnimEffect` constant then
24776
+ // `Effect.Exit = True` re-emits `presetID="12" presetSubtype="4"` with a
24777
+ // child `p:animEffect[@filter="wipe(down)"]` - a DIFFERENT, distinct
24778
+ // preset id from exit.16 above (whose own "Peek Out" naming is a
24779
+ // pre-existing, out-of-scope mismatch; see that entry's note), so this
24780
+ // gets its own non-colliding keyframe name. `presetSubtype="4"` is the
24781
+ // bottom-edge bit (matching entr.12's `peekIn`, also bottom-origin), so
24782
+ // this reuses the identical mask technique.
24783
+ peekOutDown: `@keyframes pptx-peekOutDown {
24784
+ from { ${maskEdgeDecl('bottom', 'shown')} opacity: 1; }
24785
+ to { ${maskEdgeDecl('bottom', 'hidden')} opacity: 0; }
24128
24786
  }`,
24129
24787
  // Split (exit.17): the exit-gallery counterpart of Split, closing the
24130
24788
  // centred band back to nothing rather than growing it outward.
@@ -24860,11 +25518,12 @@ function revealedStageCount(progress, totalStages) {
24860
25518
  // State folding
24861
25519
  // ==========================================================================
24862
25520
  /**
24863
- * Fold a revealing step's staged-build + colour-target descriptors onto an
24864
- * {@link ElementAnimationState}. Mutates `state` in place, adding `build`
24865
- * (with progress resolved at `options.elapsedMs`), `animatesFill`, and
24866
- * `animatesStroke` only when the step actually carries those descriptors, so a
24867
- * plain whole-element entrance leaves the state untouched.
25521
+ * Fold a revealing step's staged-build + colour-target + text-style
25522
+ * descriptors onto an {@link ElementAnimationState}. Mutates `state` in
25523
+ * place, adding `build` (with progress resolved at `options.elapsedMs`),
25524
+ * `animatesFill`, `animatesStroke`, and `textStyle` only when the step
25525
+ * actually carries those descriptors, so a plain whole-element entrance
25526
+ * leaves the state untouched.
24868
25527
  */
24869
25528
  function applyStepBuildMetadata(state, step, options) {
24870
25529
  if (!step) {
@@ -24882,6 +25541,9 @@ function applyStepBuildMetadata(state, step, options) {
24882
25541
  state.animatesStroke = true;
24883
25542
  }
24884
25543
  }
25544
+ if (step.textStyle) {
25545
+ state.textStyle = step.textStyle;
25546
+ }
24885
25547
  }
24886
25548
 
24887
25549
  /**
@@ -28452,6 +29114,14 @@ function fallbackEffectForClass(presetClass) {
28452
29114
  }
28453
29115
  return undefined;
28454
29116
  }
29117
+ /**
29118
+ * An emphasis whose visible work is entirely a `p:set`/`p:anim` text-style
29119
+ * change (no mapped preset effect, no transform). Such a step must not fall
29120
+ * through to the neutral `pulse` safety net.
29121
+ */
29122
+ function isTextStyleOnlyEmphasis(anim) {
29123
+ return anim.presetClass === 'emph' && resolveTextStyleAnimation(anim) !== undefined;
29124
+ }
28455
29125
  // ==========================================================================
28456
29126
  // Timeline builder
28457
29127
  // ==========================================================================
@@ -28600,11 +29270,19 @@ function buildTimeline(nativeAnimations) {
28600
29270
  // sequenced so the playback layer can act on it at the right time.
28601
29271
  const isCommand = !effect && !dynamic && isMediaCommandAnimation(singleAnim);
28602
29272
  if (!effect && !dynamic && !isCommand) {
28603
- // Unmapped preset: fall back so an entrance is still hidden until
28604
- // its start and an exit still hides, rather than being dropped.
28605
- effect = fallbackEffectForClass(singleAnim.presetClass);
28606
- if (!effect) {
28607
- continue;
29273
+ if (isTextStyleOnlyEmphasis(singleAnim)) {
29274
+ // Bold Reveal / Underline / Style Emphasis: the `textStyle`
29275
+ // override is the whole effect, so hold the element still
29276
+ // instead of layering the neutral pulse on top of it.
29277
+ dynamic = buildTextStyleHoldKeyframe(dynamicUid++);
29278
+ }
29279
+ else {
29280
+ // Unmapped preset: fall back so an entrance is still hidden until
29281
+ // its start and an exit still hides, rather than being dropped.
29282
+ effect = fallbackEffectForClass(singleAnim.presetClass);
29283
+ if (!effect) {
29284
+ continue;
29285
+ }
28608
29286
  }
28609
29287
  }
28610
29288
  let keyframe = '';
@@ -28763,6 +29441,7 @@ function buildTimeline(nativeAnimations) {
28763
29441
  build: isCommand ? undefined : resolveStepBuildDescriptor(singleAnim),
28764
29442
  graphicElement: isCommand ? undefined : extractStepGraphicElement(singleAnim),
28765
29443
  colorTargets: isCommand ? undefined : stepColorTargets(singleAnim, tavColorApplied),
29444
+ textStyle: isCommand ? undefined : resolveTextStyleAnimation(singleAnim),
28766
29445
  holdEndState: afterFields.holdEndState || undefined,
28767
29446
  hideAfterEffect: afterFields.hideAfterEffect,
28768
29447
  pendingHideOnNextClick: afterFields.pendingHideOnNextClick,
@@ -28916,10 +29595,15 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
28916
29595
  // command was dropped in silence.
28917
29596
  const isCommand = !effect && !dynamic && isMediaCommandAnimation(anim);
28918
29597
  if (!effect && !dynamic && !isCommand) {
28919
- // Same unmapped-preset safety net as the main timeline loop.
28920
- effect = fallbackEffectForClass(anim.presetClass);
28921
- if (!effect) {
28922
- continue;
29598
+ if (isTextStyleOnlyEmphasis(anim)) {
29599
+ dynamic = buildTextStyleHoldKeyframe(dynamicUid++);
29600
+ }
29601
+ else {
29602
+ // Same unmapped-preset safety net as the main timeline loop.
29603
+ effect = fallbackEffectForClass(anim.presetClass);
29604
+ if (!effect) {
29605
+ continue;
29606
+ }
28923
29607
  }
28924
29608
  }
28925
29609
  const keyframe = isCommand ? '' : effect ? cssKeyframeName(effect) : dynamic.keyframeName;
@@ -29006,6 +29690,7 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
29006
29690
  build: isCommand ? undefined : resolveStepBuildDescriptor(anim),
29007
29691
  graphicElement: isCommand ? undefined : extractStepGraphicElement(anim),
29008
29692
  colorTargets: isCommand ? undefined : stepColorTargets(anim, tavColorApplied),
29693
+ textStyle: isCommand ? undefined : resolveTextStyleAnimation(anim),
29009
29694
  holdEndState: afterFields.holdEndState || undefined,
29010
29695
  hideAfterEffect: afterFields.hideAfterEffect,
29011
29696
  pendingHideOnNextClick: afterFields.pendingHideOnNextClick,
@@ -38054,7 +38739,7 @@ const animationPresetTranslationsEn = {
38054
38739
  'pptx.animation.catalogPreset.entr8': 'Diamond',
38055
38740
  'pptx.animation.catalogPreset.entr9': 'Dissolve In',
38056
38741
  'pptx.animation.catalogPreset.entr10': 'Fade',
38057
- 'pptx.animation.catalogPreset.entr11': 'Flash Bulb',
38742
+ 'pptx.animation.catalogPreset.entr11': 'Flash Once',
38058
38743
  'pptx.animation.catalogPreset.entr12': 'Flash Once',
38059
38744
  'pptx.animation.catalogPreset.entr13': 'Plus',
38060
38745
  'pptx.animation.catalogPreset.entr14': 'Random Bars',
@@ -38123,8 +38808,8 @@ const animationPresetTranslationsEn = {
38123
38808
  'pptx.animation.catalogPreset.exit8': 'Diamond',
38124
38809
  'pptx.animation.catalogPreset.exit9': 'Dissolve Out',
38125
38810
  'pptx.animation.catalogPreset.exit10': 'Fade',
38126
- 'pptx.animation.catalogPreset.exit11': 'Flash Bulb',
38127
- 'pptx.animation.catalogPreset.exit12': 'Flash Once',
38811
+ 'pptx.animation.catalogPreset.exit11': 'Flash Once',
38812
+ 'pptx.animation.catalogPreset.exit12': 'Peek Out',
38128
38813
  'pptx.animation.catalogPreset.exit13': 'Plus',
38129
38814
  'pptx.animation.catalogPreset.exit14': 'Random Bars',
38130
38815
  'pptx.animation.catalogPreset.exit15': 'Spiral Out',
@@ -38483,6 +39168,12 @@ const translationsEn = {
38483
39168
  'pptx.accessibility.error': 'Error: ',
38484
39169
  'pptx.accessibility.warning': 'Warning: ',
38485
39170
  'pptx.accessibility.info': 'Info: ',
39171
+ // Element-level alt text / title (shape, text box, connector). A picture's
39172
+ // own alt text field uses `pptx.image.altText` / `pptx.image.altTextPlaceholder`.
39173
+ 'pptx.elementAccessibility.altText': 'Alt text',
39174
+ 'pptx.elementAccessibility.altTextPlaceholder': 'Describe this element for accessibility',
39175
+ 'pptx.elementAccessibility.title': 'Title',
39176
+ 'pptx.elementAccessibility.titlePlaceholder': 'Accessibility title (optional)',
38486
39177
  // Animations
38487
39178
  'pptx.animations.previewTooltip': 'Preview animation on selected element',
38488
39179
  'pptx.animations.preview': 'Preview',
@@ -41746,6 +42437,51 @@ const translationsEn = {
41746
42437
  'pptx.hyperlink.actionOpenPresentation': 'Open presentation',
41747
42438
  'pptx.hyperlink.actionPlayMedia': 'Play media',
41748
42439
  'pptx.hyperlink.actionOleVerb': 'Object action',
42440
+ // Table style (a:tblStyleLst) definition editor.
42441
+ 'pptx.tableStyleEditor.editButton': 'Edit style...',
42442
+ 'pptx.tableStyleEditor.title': 'Table Style Editor',
42443
+ 'pptx.tableStyleEditor.close': 'Close',
42444
+ 'pptx.tableStyleEditor.noStyleSelected': 'Select a table style to edit its definition.',
42445
+ 'pptx.tableStyleEditor.styleName': 'Style name',
42446
+ 'pptx.tableStyleEditor.sections': 'Sections',
42447
+ 'pptx.tableStyleEditor.newFromCurrent': 'New style from current',
42448
+ 'pptx.tableStyleEditor.newStyle': 'Create new style',
42449
+ 'pptx.tableStyleEditor.deleteStyle': 'Delete style',
42450
+ 'pptx.tableStyleEditor.deleteConfirm': 'Delete this table style? This cannot be undone.',
42451
+ 'pptx.tableStyleEditor.newStyleNamePrompt': 'Name for the new style',
42452
+ 'pptx.tableStyleEditor.part.wholeTbl': 'Whole Table',
42453
+ 'pptx.tableStyleEditor.part.firstRow': 'First Row',
42454
+ 'pptx.tableStyleEditor.part.lastRow': 'Last Row',
42455
+ 'pptx.tableStyleEditor.part.firstCol': 'First Column',
42456
+ 'pptx.tableStyleEditor.part.lastCol': 'Last Column',
42457
+ 'pptx.tableStyleEditor.part.band1H': 'Band 1 Horizontal',
42458
+ 'pptx.tableStyleEditor.part.band2H': 'Band 2 Horizontal',
42459
+ 'pptx.tableStyleEditor.part.band1V': 'Band 1 Vertical',
42460
+ 'pptx.tableStyleEditor.part.band2V': 'Band 2 Vertical',
42461
+ 'pptx.tableStyleEditor.part.neCell': 'NE Cell',
42462
+ 'pptx.tableStyleEditor.part.nwCell': 'NW Cell',
42463
+ 'pptx.tableStyleEditor.part.seCell': 'SE Cell',
42464
+ 'pptx.tableStyleEditor.part.swCell': 'SW Cell',
42465
+ 'pptx.tableStyleEditor.part.background': 'Background',
42466
+ 'pptx.tableStyleEditor.fillSection': 'Fill',
42467
+ 'pptx.tableStyleEditor.noFill': 'No fill',
42468
+ 'pptx.tableStyleEditor.textSection': 'Text',
42469
+ 'pptx.tableStyleEditor.textColor': 'Text color',
42470
+ 'pptx.tableStyleEditor.bordersSection': 'Borders',
42471
+ 'pptx.tableStyleEditor.borderDash': 'Dash style',
42472
+ 'pptx.tableStyleEditor.noBorder': 'No border',
42473
+ 'pptx.tableStyleEditor.cell3DSection': '3D bevel',
42474
+ 'pptx.tableStyleEditor.bevelWidth': 'Bevel width',
42475
+ 'pptx.tableStyleEditor.bevelHeight': 'Bevel height',
42476
+ 'pptx.tableStyleEditor.bevelPreset': 'Bevel preset',
42477
+ 'pptx.tableStyleEditor.side.left': 'Left',
42478
+ 'pptx.tableStyleEditor.side.right': 'Right',
42479
+ 'pptx.tableStyleEditor.side.top': 'Top',
42480
+ 'pptx.tableStyleEditor.side.bottom': 'Bottom',
42481
+ 'pptx.tableStyleEditor.side.insideH': 'Inside horizontal',
42482
+ 'pptx.tableStyleEditor.side.insideV': 'Inside vertical',
42483
+ 'pptx.tableStyleEditor.side.tl2br': 'Diagonal top-left to bottom-right',
42484
+ 'pptx.tableStyleEditor.side.tr2bl': 'Diagonal top-right to bottom-left',
41749
42485
  };
41750
42486
  /**
41751
42487
  * Convert a dotted translation key to a human-readable label when no
@@ -57843,7 +58579,7 @@ function createWriteBackScheduler(deps) {
57843
58579
  const merged = deps.mergeTemplateElements
57844
58580
  ? deps.mergeTemplateElements(slides, deps.getTemplateElements?.() ?? {})
57845
58581
  : slides;
57846
- const bytes = await handler.save(merged);
58582
+ const bytes = await handler.save(merged, deps.getSaveOptions?.());
57847
58583
  config.onWriteBack(bytes);
57848
58584
  }
57849
58585
  catch {
@@ -76208,6 +76944,79 @@ function applyRenderedElementAccessibility(stage, elements, options = {}) {
76208
76944
  return applied;
76209
76945
  }
76210
76946
 
76947
+ /**
76948
+ * Which element kinds model an accessibility description (`altText`) and
76949
+ * title (`title`) on `p:cNvPr` (`@descr` / `@title`, `PptxNonVisualDescription`
76950
+ * in core), and a pure descriptor every binding's inspector can use to decide
76951
+ * whether to show the alt-text / title editing fields for the selected
76952
+ * element.
76953
+ *
76954
+ * Before this module existed, a picture's own alt-text field was the only
76955
+ * one any binding's inspector rendered; a plain shape, text box or connector
76956
+ * had nowhere to author the same PowerPoint Accessibility-pane text even
76957
+ * after core started parsing it. Centralising the "which element kinds get
76958
+ * which field" decision here means a new kind reaches every binding's
76959
+ * inspector by editing one set, not five.
76960
+ *
76961
+ * @module render/element-non-visual-description
76962
+ */
76963
+ /** Element kinds whose core type models `altText` (`p:cNvPr/@descr`). */
76964
+ const ALT_TEXT_ELEMENT_TYPES = new Set([
76965
+ 'image',
76966
+ 'picture',
76967
+ 'table',
76968
+ 'chart',
76969
+ 'smartArt',
76970
+ 'ole',
76971
+ 'media',
76972
+ 'text',
76973
+ 'shape',
76974
+ 'connector',
76975
+ ]);
76976
+ /**
76977
+ * Element kinds whose core type models `title` (`p:cNvPr/@title`). A picture
76978
+ * is deliberately excluded: `ImagePptxElement`/`PicturePptxElement` only ever
76979
+ * carry `altText` (no `title` field), matching how PowerPoint's own Alt Text
76980
+ * pane has no separate title box for a picture.
76981
+ */
76982
+ const TITLE_ELEMENT_TYPES = new Set([
76983
+ 'table',
76984
+ 'chart',
76985
+ 'smartArt',
76986
+ 'ole',
76987
+ 'media',
76988
+ 'text',
76989
+ 'shape',
76990
+ 'connector',
76991
+ ]);
76992
+ /** Whether `type`'s core element models an `altText` field. */
76993
+ function supportsAltTextField(type) {
76994
+ return ALT_TEXT_ELEMENT_TYPES.has(type);
76995
+ }
76996
+ /** Whether `type`'s core element models a `title` field. */
76997
+ function supportsTitleField(type) {
76998
+ return TITLE_ELEMENT_TYPES.has(type);
76999
+ }
77000
+ /** Reads `element.altText` / `element.title` without a per-type cast. */
77001
+ function readStringField(element, field) {
77002
+ const value = element[field];
77003
+ return typeof value === 'string' ? value : '';
77004
+ }
77005
+ /**
77006
+ * Computes the alt-text / title field descriptor for `element`. See
77007
+ * {@link NonVisualDescriptionFields}.
77008
+ */
77009
+ function getNonVisualDescriptionFields(element) {
77010
+ const showAltText = supportsAltTextField(element.type);
77011
+ const showTitle = supportsTitleField(element.type);
77012
+ return {
77013
+ showAltText,
77014
+ showTitle,
77015
+ altText: showAltText ? readStringField(element, 'altText') : '',
77016
+ title: showTitle ? readStringField(element, 'title') : '',
77017
+ };
77018
+ }
77019
+
76211
77020
  /**
76212
77021
  * Which slide element does a pointer event select?
76213
77022
  *
@@ -82543,6 +83352,94 @@ function isEncryptedDeckBytes(bytes) {
82543
83352
  return detectFileFormat(buffer).encrypted;
82544
83353
  }
82545
83354
 
83355
+ /**
83356
+ * Apply a whole-map replacement (an edit to one style's fill/text/borders/
83357
+ * cell3D facet via `applyTableStyleFieldEdit`, or a brand-new style added via
83358
+ * `createTableStyleEntry` + `addTableStyleToMap`) coming from the editor's
83359
+ * `onStyleMapChange` callback.
83360
+ */
83361
+ function applyTableStyleMapChange(state, nextMap) {
83362
+ return {
83363
+ tableStyleMap: nextMap,
83364
+ tableStylesToDelete: state.tableStylesToDelete.filter((id) => !(id in nextMap)),
83365
+ };
83366
+ }
83367
+ /**
83368
+ * Apply a style deletion coming from the editor's `onDeleteStyle` callback:
83369
+ * removes the entry from the map and records the id for save-time removal
83370
+ * from `ppt/tableStyles.xml`. Safe to call more than once for the same id.
83371
+ */
83372
+ function applyTableStyleDelete(state, styleId) {
83373
+ const nextMap = { ...(state.tableStyleMap ?? {}) };
83374
+ delete nextMap[styleId];
83375
+ return {
83376
+ tableStyleMap: nextMap,
83377
+ tableStylesToDelete: state.tableStylesToDelete.includes(styleId)
83378
+ ? [...state.tableStylesToDelete]
83379
+ : [...state.tableStylesToDelete, styleId],
83380
+ };
83381
+ }
83382
+ /**
83383
+ * Pick the three `ppt/tableStyles.xml` save option fields off a viewer
83384
+ * state's table-style pieces, for spreading into every
83385
+ * `handler.save(...)` / `saveDeckWithPassword(...)` options object. Omits a
83386
+ * field entirely (rather than passing it as `undefined`) when there is
83387
+ * nothing to say, matching every other optional save-option picker in this
83388
+ * module.
83389
+ */
83390
+ function tableStyleSaveOptions(state) {
83391
+ return {
83392
+ ...(state.tableStyleMap ? { tableStyles: state.tableStyleMap } : {}),
83393
+ ...(state.tableStylesDefaultId ? { tableStylesDefaultId: state.tableStylesDefaultId } : {}),
83394
+ ...(state.tableStylesToDelete.length > 0
83395
+ ? { tableStylesToDelete: [...state.tableStylesToDelete] }
83396
+ : {}),
83397
+ };
83398
+ }
83399
+ /**
83400
+ * The table-data patch to apply when the table-style DEFINITION editor's
83401
+ * "create new style" action (or the style gallery's "pick a style") assigns
83402
+ * `styleId` to the table being edited. A single-key object so every binding
83403
+ * spreads it through the exact same `updateTableData(...)` /
83404
+ * `onUpdateElement(...)` path the style gallery already uses, rather than
83405
+ * hand-rolling `{ tableStyleId: styleId }` five times.
83406
+ */
83407
+ function tableStyleAssignmentUpdate(styleId) {
83408
+ return { tableStyleId: styleId };
83409
+ }
83410
+
83411
+ /**
83412
+ * Assemble the full `PptxHandlerSaveOptions` for a binding's main save path.
83413
+ * Array-valued fields are omitted (not passed as an empty array) when empty,
83414
+ * matching every binding's pre-existing convention and the option docs on
83415
+ * `PptxHandlerSaveOptions` itself (an omitted field round-trips the original
83416
+ * part verbatim; an empty array would instead clear it).
83417
+ */
83418
+ function buildDeckSaveOptions(state) {
83419
+ return {
83420
+ headerFooter: state.headerFooter,
83421
+ presentationProperties: state.presentationProperties,
83422
+ viewProperties: state.viewProperties,
83423
+ customShows: state.customShows.length > 0 ? [...state.customShows] : undefined,
83424
+ sections: state.sections.length > 0 ? [...state.sections] : undefined,
83425
+ coreProperties: state.coreProperties,
83426
+ appProperties: state.appProperties,
83427
+ customProperties: state.customProperties.length > 0 ? [...state.customProperties] : undefined,
83428
+ tags: state.tagCollections.length > 0 ? [...state.tagCollections] : undefined,
83429
+ slideMasters: state.slideMasters ? [...state.slideMasters] : [],
83430
+ notesMaster: state.notesMaster,
83431
+ handoutMaster: state.handoutMaster,
83432
+ slideSize: state.slideSize,
83433
+ outputFormat: state.outputFormat,
83434
+ ...tableStyleSaveOptions({
83435
+ tableStyleMap: state.tableStyleMap,
83436
+ tableStylesDefaultId: state.tableStylesDefaultId,
83437
+ tableStylesToDelete: state.tableStylesToDelete,
83438
+ }),
83439
+ ...embeddedFontSaveOptions(state.embedFonts ?? true),
83440
+ };
83441
+ }
83442
+
82546
83443
  const DEFAULT_VIEWER_PREFERENCES = {
82547
83444
  autoSave: true,
82548
83445
  spellCheck: false,
@@ -84598,6 +85495,9 @@ function carryBuildState(state) {
84598
85495
  if (state.diagramReveal) {
84599
85496
  carried.diagramReveal = state.diagramReveal;
84600
85497
  }
85498
+ if (state.textStyle) {
85499
+ carried.textStyle = state.textStyle;
85500
+ }
84601
85501
  return carried;
84602
85502
  }
84603
85503
  /**
@@ -84642,12 +85542,14 @@ function applyAnimationGroupSteps(group, ctx) {
84642
85542
  }
84643
85543
  const current = next.get(step.elementId);
84644
85544
  const shouldBeVisible = step.presetClass === 'exit' ? (current?.visible ?? true) : true;
85545
+ const carried = carryBuildState(current);
84645
85546
  next.set(step.elementId, {
84646
- ...carryBuildState(current),
85547
+ ...carried,
84647
85548
  visible: shouldBeVisible,
84648
85549
  cssAnimation: step.cssAnimation,
84649
85550
  animatesFill: step.colorTargets?.includes('fill') ? true : undefined,
84650
85551
  animatesStroke: step.colorTargets?.includes('stroke') ? true : undefined,
85552
+ textStyle: mergeTextStyleOnStart(carried.textStyle, step.textStyle),
84651
85553
  });
84652
85554
  }
84653
85555
  return next;
@@ -84668,11 +85570,14 @@ function applyAnimationGroupSteps(group, ctx) {
84668
85570
  ? false
84669
85571
  : (current?.visible ?? true);
84670
85572
  // `p:cTn/@fill="hold"`/`"freeze"`: keep the CSS animation attached so
84671
- // its final frame persists instead of reverting on cleanup.
85573
+ // its final frame persists instead of reverting on cleanup. A
85574
+ // font-style emphasis's text-style override follows the SAME flag.
85575
+ const carried = carryBuildState(current);
84672
85576
  next.set(step.elementId, {
84673
- ...carryBuildState(current),
85577
+ ...carried,
84674
85578
  visible: visibleAfter,
84675
85579
  cssAnimation: step.holdEndState ? step.cssAnimation : undefined,
85580
+ textStyle: resolveTextStyleOnCleanup(carried.textStyle, step.textStyle, step.holdEndState),
84676
85581
  });
84677
85582
  return next;
84678
85583
  });
@@ -86037,6 +86942,315 @@ function mruColorsPatch(recent) {
86037
86942
  return { mruColors: dedupeAndCap(normalized) };
86038
86943
  }
86039
86944
 
86945
+ /**
86946
+ * Every editable part, in the display order PowerPoint's own "Modify Table
86947
+ * Style" dialog uses (structural regions grouped, background last) - NOT
86948
+ * `TABLE_STYLE_PART_SEQUENCE`'s order, which exists to answer "which section
86949
+ * wins on a given cell" rather than "what order to list them in a picker".
86950
+ */
86951
+ const TABLE_STYLE_EDITOR_PARTS = [
86952
+ { id: 'wholeTbl', labelKey: 'pptx.tableStyleEditor.part.wholeTbl' },
86953
+ { id: 'firstRow', labelKey: 'pptx.tableStyleEditor.part.firstRow' },
86954
+ { id: 'lastRow', labelKey: 'pptx.tableStyleEditor.part.lastRow' },
86955
+ { id: 'firstCol', labelKey: 'pptx.tableStyleEditor.part.firstCol' },
86956
+ { id: 'lastCol', labelKey: 'pptx.tableStyleEditor.part.lastCol' },
86957
+ { id: 'band1H', labelKey: 'pptx.tableStyleEditor.part.band1H' },
86958
+ { id: 'band2H', labelKey: 'pptx.tableStyleEditor.part.band2H' },
86959
+ { id: 'band1V', labelKey: 'pptx.tableStyleEditor.part.band1V' },
86960
+ { id: 'band2V', labelKey: 'pptx.tableStyleEditor.part.band2V' },
86961
+ { id: 'neCell', labelKey: 'pptx.tableStyleEditor.part.neCell' },
86962
+ { id: 'nwCell', labelKey: 'pptx.tableStyleEditor.part.nwCell' },
86963
+ { id: 'seCell', labelKey: 'pptx.tableStyleEditor.part.seCell' },
86964
+ { id: 'swCell', labelKey: 'pptx.tableStyleEditor.part.swCell' },
86965
+ { id: 'background', labelKey: 'pptx.tableStyleEditor.part.background' },
86966
+ ];
86967
+ /** Whether a part id is one of the 13 real `CT_TableStyle` sections (not the synthetic background). */
86968
+ function isTableStylePartName(id) {
86969
+ return TABLE_STYLE_PART_SEQUENCE.includes(id);
86970
+ }
86971
+ /** The 8 border sides a section's `a:tcStyle/a:tcBdr` can carry (both diagonals included). */
86972
+ const TABLE_STYLE_BORDER_SIDES = [
86973
+ 'left',
86974
+ 'right',
86975
+ 'top',
86976
+ 'bottom',
86977
+ 'insideH',
86978
+ 'insideV',
86979
+ 'tl2br',
86980
+ 'tr2bl',
86981
+ ];
86982
+ /** i18n key for each border side's label. */
86983
+ const TABLE_STYLE_BORDER_SIDE_LABEL_KEYS = {
86984
+ left: 'pptx.tableStyleEditor.side.left',
86985
+ right: 'pptx.tableStyleEditor.side.right',
86986
+ top: 'pptx.tableStyleEditor.side.top',
86987
+ bottom: 'pptx.tableStyleEditor.side.bottom',
86988
+ insideH: 'pptx.tableStyleEditor.side.insideH',
86989
+ insideV: 'pptx.tableStyleEditor.side.insideV',
86990
+ tl2br: 'pptx.tableStyleEditor.side.tl2br',
86991
+ tr2bl: 'pptx.tableStyleEditor.side.tr2bl',
86992
+ };
86993
+ /** OOXML `a:prstDash@val` choices offered by the dash picker. */
86994
+ const TABLE_STYLE_DASH_PRESETS = [
86995
+ 'solid',
86996
+ 'dot',
86997
+ 'dash',
86998
+ 'lgDash',
86999
+ 'dashDot',
87000
+ 'lgDashDot',
87001
+ 'lgDashDotDot',
87002
+ 'sysDash',
87003
+ 'sysDot',
87004
+ 'sysDashDot',
87005
+ 'sysDashDotDot',
87006
+ ];
87007
+
87008
+ const DEFAULT_FILL_HEX = '#ffffff';
87009
+ const DEFAULT_TEXT_HEX = '#000000';
87010
+ const DEFAULT_BORDER_HEX = '#808080';
87011
+ /** Resolve a `ParsedTableStyleFill` (or a border's colour choice) to a paintable colour + ref. */
87012
+ function fillToColor(fill, themeColorMap, fallbackHex) {
87013
+ if (!fill) {
87014
+ return { hex: fallbackHex, ref: undefined };
87015
+ }
87016
+ if (fill.schemeColor) {
87017
+ const ref = {
87018
+ scheme: fill.schemeColor,
87019
+ tint: fill.tint,
87020
+ shade: fill.shade,
87021
+ };
87022
+ return { hex: resolveThemeColorRef(ref, themeColorMap) ?? fallbackHex, ref };
87023
+ }
87024
+ if (fill.color) {
87025
+ return { hex: fill.color, ref: undefined };
87026
+ }
87027
+ return { hex: fallbackHex, ref: undefined };
87028
+ }
87029
+ /** Bidirectional inverse of {@link fillToColor}: build the `ParsedTableStyleFill` a commit writes. */
87030
+ function colorToFill(hex, ref) {
87031
+ if (ref) {
87032
+ return { schemeColor: ref.scheme, tint: ref.tint, shade: ref.shade };
87033
+ }
87034
+ return { schemeColor: '', color: hex };
87035
+ }
87036
+ function describeFill(fill, themeColorMap) {
87037
+ return {
87038
+ color: fillToColor(fill, themeColorMap, DEFAULT_FILL_HEX),
87039
+ noFill: fill?.noFill ?? false,
87040
+ isSet: fill !== undefined,
87041
+ };
87042
+ }
87043
+ function describeText(text, themeColorMap) {
87044
+ const asFill = text
87045
+ ? {
87046
+ schemeColor: text.fontSchemeColor ?? '',
87047
+ tint: text.fontTint,
87048
+ shade: text.fontShade,
87049
+ color: text.fontColor,
87050
+ }
87051
+ : undefined;
87052
+ return {
87053
+ bold: text?.bold ?? false,
87054
+ italic: text?.italic ?? false,
87055
+ underline: text?.underline ?? false,
87056
+ color: fillToColor(asFill, themeColorMap, DEFAULT_TEXT_HEX),
87057
+ isSet: text !== undefined,
87058
+ };
87059
+ }
87060
+ function borderSideColor(border, themeColorMap) {
87061
+ if (border?.fill) {
87062
+ return fillToColor(border.fill, themeColorMap, DEFAULT_BORDER_HEX);
87063
+ }
87064
+ if (border?.color) {
87065
+ return { hex: border.color, ref: undefined };
87066
+ }
87067
+ return { hex: DEFAULT_BORDER_HEX, ref: undefined };
87068
+ }
87069
+ function describeBorders(borders, themeColorMap) {
87070
+ const result = {};
87071
+ for (const side of TABLE_STYLE_BORDER_SIDES) {
87072
+ const border = borders?.[side];
87073
+ result[side] = {
87074
+ color: borderSideColor(border, themeColorMap),
87075
+ width: border?.width ?? 1,
87076
+ dash: border?.dash ?? 'solid',
87077
+ noFill: border?.noFill ?? false,
87078
+ isSet: border !== undefined,
87079
+ };
87080
+ }
87081
+ return result;
87082
+ }
87083
+ function describeCell3D(cell3D) {
87084
+ return {
87085
+ bevelWidth: cell3D?.bevelWidth,
87086
+ bevelHeight: cell3D?.bevelHeight,
87087
+ bevelPreset: cell3D?.bevelPreset,
87088
+ isSet: cell3D !== undefined,
87089
+ };
87090
+ }
87091
+ /**
87092
+ * Build the descriptor for `entry`'s `selectedPart`. Returns `undefined` only
87093
+ * when `entry` itself is `undefined` (no style loaded / selected yet).
87094
+ */
87095
+ function describeTableStyleEditor(entry, selectedPart, themeColorMap) {
87096
+ if (!entry) {
87097
+ return undefined;
87098
+ }
87099
+ const keyed = entry;
87100
+ const hasTextAndBorders = isTableStylePartName(selectedPart);
87101
+ const fill = selectedPart === 'background'
87102
+ ? entry.tableBackground?.fill
87103
+ : keyed[`${selectedPart}Fill`];
87104
+ const text = hasTextAndBorders
87105
+ ? keyed[`${selectedPart}Text`]
87106
+ : undefined;
87107
+ const borders = hasTextAndBorders
87108
+ ? keyed[`${selectedPart}Borders`]
87109
+ : undefined;
87110
+ const cell3D = hasTextAndBorders
87111
+ ? keyed[`${selectedPart}Cell3D`]
87112
+ : undefined;
87113
+ return {
87114
+ styleId: entry.styleId,
87115
+ styleName: entry.styleName ?? '',
87116
+ selectedPart,
87117
+ hasTextAndBorders,
87118
+ fill: describeFill(fill, themeColorMap),
87119
+ text: describeText(text, themeColorMap),
87120
+ borders: describeBorders(borders, themeColorMap),
87121
+ cell3D: describeCell3D(cell3D),
87122
+ };
87123
+ }
87124
+
87125
+ function patchBorderSide(borders, side, patch) {
87126
+ const current = borders?.[side] ?? {};
87127
+ return { ...borders, [side]: { ...current, ...patch } };
87128
+ }
87129
+ /**
87130
+ * Apply one field edit to `entry`'s `part`, returning the new entry plus the
87131
+ * SDK-shaped payload. `part === 'background'` only honours `fillColor` /
87132
+ * `fillNone` (background has no text/borders/cell3D facet); any other edit
87133
+ * kind on the background part is a no-op (returns `entry` unchanged, payload
87134
+ * with no facets set) so a caller does not need to pre-filter by part.
87135
+ */
87136
+ function applyTableStyleFieldEdit(entry, part, edit) {
87137
+ if (part === 'background') {
87138
+ return applyBackgroundEdit(entry, edit);
87139
+ }
87140
+ const keyed = entry;
87141
+ const fillKey = `${part}Fill`;
87142
+ const textKey = `${part}Text`;
87143
+ const bordersKey = `${part}Borders`;
87144
+ const cell3DKey = `${part}Cell3D`;
87145
+ switch (edit.kind) {
87146
+ case 'fillColor':
87147
+ keyed[fillKey] = colorToFill(edit.hex, edit.ref);
87148
+ break;
87149
+ case 'fillNone': {
87150
+ const current = keyed[fillKey];
87151
+ keyed[fillKey] = { schemeColor: current?.schemeColor ?? '', ...current, noFill: edit.noFill };
87152
+ break;
87153
+ }
87154
+ case 'textBold':
87155
+ keyed[textKey] = {
87156
+ ...keyed[textKey],
87157
+ bold: edit.value,
87158
+ };
87159
+ break;
87160
+ case 'textItalic':
87161
+ keyed[textKey] = {
87162
+ ...keyed[textKey],
87163
+ italic: edit.value,
87164
+ };
87165
+ break;
87166
+ case 'textUnderline':
87167
+ keyed[textKey] = {
87168
+ ...keyed[textKey],
87169
+ underline: edit.value,
87170
+ };
87171
+ break;
87172
+ case 'textColor': {
87173
+ const fill = colorToFill(edit.hex, edit.ref);
87174
+ keyed[textKey] = {
87175
+ ...keyed[textKey],
87176
+ fontSchemeColor: fill.schemeColor,
87177
+ fontTint: fill.tint,
87178
+ fontShade: fill.shade,
87179
+ fontColor: fill.color,
87180
+ };
87181
+ break;
87182
+ }
87183
+ case 'borderColor':
87184
+ keyed[bordersKey] = patchBorderSide(keyed[bordersKey], edit.side, { fill: colorToFill(edit.hex, edit.ref), color: edit.ref ? undefined : edit.hex });
87185
+ break;
87186
+ case 'borderWidth':
87187
+ keyed[bordersKey] = patchBorderSide(keyed[bordersKey], edit.side, { width: edit.width });
87188
+ break;
87189
+ case 'borderDash':
87190
+ keyed[bordersKey] = patchBorderSide(keyed[bordersKey], edit.side, { dash: edit.dash });
87191
+ break;
87192
+ case 'borderNone':
87193
+ keyed[bordersKey] = patchBorderSide(keyed[bordersKey], edit.side, { noFill: edit.noFill });
87194
+ break;
87195
+ case 'cell3DBevelWidth':
87196
+ keyed[cell3DKey] = {
87197
+ ...keyed[cell3DKey],
87198
+ bevelWidth: edit.value,
87199
+ };
87200
+ break;
87201
+ case 'cell3DBevelHeight':
87202
+ keyed[cell3DKey] = {
87203
+ ...keyed[cell3DKey],
87204
+ bevelHeight: edit.value,
87205
+ };
87206
+ break;
87207
+ case 'cell3DBevelPreset':
87208
+ keyed[cell3DKey] = {
87209
+ ...keyed[cell3DKey],
87210
+ bevelPreset: edit.value,
87211
+ };
87212
+ break;
87213
+ }
87214
+ const nextEntry = keyed;
87215
+ return {
87216
+ entry: nextEntry,
87217
+ payload: {
87218
+ styleId: entry.styleId,
87219
+ section: part,
87220
+ ...(isTableStylePartName(part)
87221
+ ? {
87222
+ fill: keyed[fillKey],
87223
+ text: keyed[textKey],
87224
+ borders: keyed[bordersKey],
87225
+ cell3D: keyed[cell3DKey],
87226
+ }
87227
+ : {}),
87228
+ },
87229
+ };
87230
+ }
87231
+ function applyBackgroundEdit(entry, edit) {
87232
+ const current = entry.tableBackground;
87233
+ let nextBackground = current;
87234
+ if (edit.kind === 'fillColor') {
87235
+ nextBackground = { ...current, fill: colorToFill(edit.hex, edit.ref), fillRef: undefined };
87236
+ }
87237
+ else if (edit.kind === 'fillNone') {
87238
+ nextBackground = {
87239
+ ...current,
87240
+ fill: {
87241
+ schemeColor: current?.fill?.schemeColor ?? '',
87242
+ ...current?.fill,
87243
+ noFill: edit.noFill,
87244
+ },
87245
+ };
87246
+ }
87247
+ const nextEntry = { ...entry, tableBackground: nextBackground };
87248
+ return {
87249
+ entry: nextEntry,
87250
+ payload: { styleId: entry.styleId, section: 'background' },
87251
+ };
87252
+ }
87253
+
86040
87254
  /**
86041
87255
  * Framework-agnostic rendering & editing helpers shared by the React, Vue, and
86042
87256
  * Angular `pptx-viewer` bindings. Pure TypeScript (no framework imports) — each
@@ -89517,6 +90731,26 @@ function resetAiSdkCache() {
89517
90731
  cached = undefined;
89518
90732
  }
89519
90733
 
90734
+ /**
90735
+ * deckDataFieldChanged: structural-equality check used by every binding's AI
90736
+ * bridge `applyDeckData()` to decide whether a top-level `PptxData` field
90737
+ * changed before committing it back through the binding's own history/write
90738
+ * path.
90739
+ *
90740
+ * Before this module existed, React, Vue, Angular, Svelte and Vanilla each
90741
+ * declared the identical `const differs = (a, b) => JSON.stringify(a) !==
90742
+ * JSON.stringify(b)` locally inside their `useAiBridge` / `ai-bridge`
90743
+ * modules: a pure helper with no framework imports, duplicated five times
90744
+ * (the exact Rule 2 extraction trigger in CLAUDE.md). Bindings should import
90745
+ * this instead of re-declaring their own copy.
90746
+ *
90747
+ * @module ai/deck-data-diff
90748
+ */
90749
+ /** True when `a` and `b` are not structurally (deep-value) equal. */
90750
+ function deckDataFieldChanged(a, b) {
90751
+ return JSON.stringify(a) !== JSON.stringify(b);
90752
+ }
90753
+
89520
90754
  /**
89521
90755
  * Host-facing configuration types for the framework-agnostic AI assistant, plus
89522
90756
  * {@link resolveChatTransport}, which turns a declarative {@link PptxAiConnection}
@@ -91142,7 +92376,7 @@ function createLocalStorageBackend(namespace) {
91142
92376
  /** Try IndexedDB first; fall back to localStorage on any failure. */
91143
92377
  async function resolveBackend(dbName, namespace) {
91144
92378
  try {
91145
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BxlsOXEi.mjs');
92379
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BHSiNfjU.mjs');
91146
92380
  const db = await openChatDb(dbName);
91147
92381
  return createIdbBackend(db);
91148
92382
  }
@@ -92416,9 +93650,13 @@ function createAngularAiBridge(deps) {
92416
93650
  customProperties: [...deps.getCustomProperties()],
92417
93651
  coreProperties: deps.getCoreProperties(),
92418
93652
  appProperties: deps.getAppProperties(),
93653
+ viewProperties: deps.getViewProperties(),
93654
+ tableStyleMap: deps.getTableStyleMap(),
93655
+ tableStylesDefaultId: deps.getTableStylesDefaultId(),
93656
+ tags: [...deps.getTagCollections()],
92419
93657
  };
92420
93658
  };
92421
- const differs = (a, b) => JSON.stringify(a) !== JSON.stringify(b);
93659
+ const differs = deckDataFieldChanged;
92422
93660
  return {
92423
93661
  getDeckMeta() {
92424
93662
  const slides = deps.getSlides();
@@ -92490,6 +93728,19 @@ function createAngularAiBridge(deps) {
92490
93728
  if (differs(before.appProperties, after.appProperties)) {
92491
93729
  deps.setAppProperties(after.appProperties);
92492
93730
  }
93731
+ if (differs(before.viewProperties, after.viewProperties)) {
93732
+ deps.setViewProperties(after.viewProperties);
93733
+ }
93734
+ if (differs(before.tableStyleMap, after.tableStyleMap)) {
93735
+ deps.setTableStyleMap(after.tableStyleMap);
93736
+ }
93737
+ if (differs(before.tableStylesDefaultId, after.tableStylesDefaultId)) {
93738
+ deps.setTableStylesDefaultId(after.tableStylesDefaultId);
93739
+ }
93740
+ const nextTags = after.tags ?? before.tags ?? [];
93741
+ if (differs(before.tags, nextTags)) {
93742
+ deps.setTagCollections(nextTags);
93743
+ }
92493
93744
  },
92494
93745
  getFocusedTargets() {
92495
93746
  return (deps.getFocusedTargets?.() ?? [{ kind: 'slide', slideIndex: deps.getActiveSlideIndex() }]);
@@ -94497,12 +95748,17 @@ const WRITE_BACK_DEBOUNCE_MS = 5_000;
94497
95748
  * Serialize the current Y.Doc slide state (with the separated master/layout
94498
95749
  * template elements merged back) into `.pptx` bytes. `sourceBytes` seeds the
94499
95750
  * handler so package parts the CRDT does not carry (media, fonts, rels) survive.
95751
+ *
95752
+ * `saveOptions` carries the session-level save options (view properties,
95753
+ * table styles, tags, deck properties, ...) built the same way as the
95754
+ * Save/Export path (`buildDeckSaveOptions`). Without it the write-back
95755
+ * dropped every session-level edit outside `slides`.
94500
95756
  */
94501
- async function serializeWriteBack(ydoc, sourceBytes, templateElements) {
95757
+ async function serializeWriteBack(ydoc, sourceBytes, templateElements, saveOptions) {
94502
95758
  const handler = new PptxHandler();
94503
95759
  await handler.load(sourceBytes.buffer);
94504
95760
  const slides = buildSaveSlides(readSlidesFromYDoc(ydoc), templateElements);
94505
- return handler.save(slides);
95761
+ return handler.save(slides, saveOptions);
94506
95762
  }
94507
95763
  /**
94508
95764
  * Debounced elected-writer write-back. Only the session `owner` with an
@@ -94513,7 +95769,7 @@ class WriteBackScheduler {
94513
95769
  constructor() {
94514
95770
  this.timer = null;
94515
95771
  }
94516
- schedule(config, ydoc, getSourceBytes, getTemplateElements) {
95772
+ schedule(config, ydoc, getSourceBytes, getTemplateElements, getSaveOptions) {
94517
95773
  if (!config?.onWriteBack || config.role !== 'owner' || !ydoc) {
94518
95774
  return;
94519
95775
  }
@@ -94525,7 +95781,7 @@ class WriteBackScheduler {
94525
95781
  if (!bytes || !config.onWriteBack) {
94526
95782
  return;
94527
95783
  }
94528
- void serializeWriteBack(ydoc, bytes, getTemplateElements?.() ?? {})
95784
+ void serializeWriteBack(ydoc, bytes, getTemplateElements?.() ?? {}, getSaveOptions?.())
94529
95785
  .then((out) => config.onWriteBack?.(out))
94530
95786
  .catch(() => {
94531
95787
  /* non-fatal */
@@ -94609,6 +95865,7 @@ class CollaborationService {
94609
95865
  this.canvasHeight = DEFAULT_CANVAS_BOUND;
94610
95866
  this.getSourceBytes = null;
94611
95867
  this.getTemplateElements = null;
95868
+ this.getSaveOptions = null;
94612
95869
  this.currentConfig = null;
94613
95870
  this.lastConfig = null;
94614
95871
  this.lastOptions = {};
@@ -94681,6 +95938,7 @@ class CollaborationService {
94681
95938
  this.canvasHeight = options.canvasHeight ?? DEFAULT_CANVAS_BOUND;
94682
95939
  this.getSourceBytes = options.getSourceBytes ?? null;
94683
95940
  this.getTemplateElements = options.getTemplateElements ?? null;
95941
+ this.getSaveOptions = options.getSaveOptions ?? null;
94684
95942
  this.currentConfig = config;
94685
95943
  this.activeRole.set(config.role);
94686
95944
  this.status.set('connecting');
@@ -94787,7 +96045,7 @@ class CollaborationService {
94787
96045
  this.followedClientId.set(clientId);
94788
96046
  }
94789
96047
  scheduleWriteBack() {
94790
- this.writeBack.schedule(this.currentConfig, this.session?.ydoc ?? null, this.getSourceBytes, this.getTemplateElements);
96048
+ this.writeBack.schedule(this.currentConfig, this.session?.ydoc ?? null, this.getSourceBytes, this.getTemplateElements, this.getSaveOptions);
94791
96049
  }
94792
96050
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CollaborationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
94793
96051
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: CollaborationService }); }
@@ -96213,6 +97471,16 @@ class LoadContentService {
96213
97471
  /** Parsed table-style definitions from `ppt/tableStyles.xml` (banding/diagonals). */
96214
97472
  this.tableStyleMap = signal(undefined, /* @ts-ignore */
96215
97473
  ...(ngDevMode ? [{ debugName: "tableStyleMap" }] : /* istanbul ignore next */ []));
97474
+ /** `ppt/tableStyles.xml`'s `<a:tblStyleLst @def>` default style GUID. */
97475
+ this.tableStylesDefaultId = signal(undefined, /* @ts-ignore */
97476
+ ...(ngDevMode ? [{ debugName: "tableStylesDefaultId" }] : /* istanbul ignore next */ []));
97477
+ /**
97478
+ * Style GUIDs deleted from `tableStyleMap` via the table style editor,
97479
+ * pending removal from `ppt/tableStyles.xml` on the next save. See
97480
+ * `tableStyleSaveOptions` / `applyTableStyleDelete` in `pptx-viewer-shared`.
97481
+ */
97482
+ this.tableStylesToDelete = signal([], /* @ts-ignore */
97483
+ ...(ngDevMode ? [{ debugName: "tableStylesToDelete" }] : /* istanbul ignore next */ []));
96216
97484
  /** Slide masters (for placeholder/background resolution). */
96217
97485
  this.slideMasters = signal([], /* @ts-ignore */
96218
97486
  ...(ngDevMode ? [{ debugName: "slideMasters" }] : /* istanbul ignore next */ []));
@@ -96376,28 +97644,35 @@ class LoadContentService {
96376
97644
  // Shared decision (see `deck-save-encryption` in `pptx-viewer-shared`): a
96377
97645
  // password set in the protection dialog routes through `saveEncrypted`, so
96378
97646
  // the produced file is a real encrypted OLE2 container.
96379
- return saveDeckWithPassword(this.handler, [...slides], {
97647
+ return saveDeckWithPassword(this.handler, [...slides], buildDeckSaveOptions({
96380
97648
  headerFooter: this.headerFooter(),
96381
97649
  presentationProperties: this.presentationProperties(),
96382
97650
  slideMasters: this.slideMasters(),
96383
97651
  notesMaster: this.notesMaster(),
96384
97652
  handoutMaster: this.handoutMaster(),
96385
- sections: sections.length > 0 ? [...sections] : undefined,
97653
+ sections,
96386
97654
  // Without this the Custom Shows dialog was write-only: shows created
96387
97655
  // in it never reached `p:custShowLst`, and a deck that arrived with
96388
97656
  // shows lost them on save.
96389
- customShows: customShows.length > 0 ? customShows.map((show) => ({ ...show })) : undefined,
97657
+ customShows,
96390
97658
  // The only route a slide-size edit has into the saved `p:sldSz`.
96391
97659
  slideSize: this.slideSizeSelection().size,
96392
97660
  coreProperties: this.coreProperties(),
96393
97661
  appProperties: this.appProperties(),
96394
- customProperties: customProperties.length > 0 ? [...customProperties] : undefined,
96395
- tags: tags.length > 0 ? tags.map((col) => ({ ...col, tags: [...col.tags] })) : undefined,
97662
+ customProperties,
97663
+ tagCollections: tags,
96396
97664
  outputFormat,
97665
+ // Without this core falls back to `viewProps.xml` as it was FIRST
97666
+ // opened, so every View-ribbon grid/guide/snap toggle silently
97667
+ // reverted at the file boundary.
97668
+ viewProperties: this.viewProperties(),
97669
+ tableStyleMap: this.tableStyleMap(),
97670
+ tableStylesDefaultId: this.tableStylesDefaultId(),
97671
+ tableStylesToDelete: this.tableStylesToDelete(),
96397
97672
  // The Fonts panel's toggle used to move and change nothing; it now
96398
97673
  // decides whether the deck's embedded font data survives the save.
96399
- ...embeddedFontSaveOptions(this.embedFonts()),
96400
- }, password);
97674
+ embedFonts: this.embedFonts(),
97675
+ }), password);
96401
97676
  }
96402
97677
  /** Parse the supplied `.pptx` bytes into the reactive signals. */
96403
97678
  async load(raw) {
@@ -96538,6 +97813,8 @@ class LoadContentService {
96538
97813
  this.theme.set(parsed.theme);
96539
97814
  this.themeColorMap.set(parsed.themeColorMap);
96540
97815
  this.tableStyleMap.set(nextTableStyleMap);
97816
+ this.tableStylesDefaultId.set(parsed.tableStylesDefaultId);
97817
+ this.tableStylesToDelete.set([]);
96541
97818
  this.slideMasters.set(parsed.slideMasters ?? []);
96542
97819
  this.notesMaster.set(parsed.notesMaster);
96543
97820
  this.handoutMaster.set(parsed.handoutMaster);
@@ -102158,7 +103435,21 @@ class ChartRendererComponent {
102158
103435
  [attr.fill]="vm().titleStyle?.fill ?? '#1e293b'"
102159
103436
  data-chart-part="title"
102160
103437
  >
102161
- {{ vm().title }}
103438
+ @if (vm().titleRunSpans; as titleRunSpans) {
103439
+ @for (run of titleRunSpans; track $index) {
103440
+ <tspan
103441
+ [attr.font-size]="run.fontSize"
103442
+ [attr.font-weight]="run.fontWeight"
103443
+ [attr.font-style]="run.fontStyle"
103444
+ [attr.font-family]="run.fontFamily"
103445
+ [attr.fill]="run.fill"
103446
+ >
103447
+ {{ run.text }}
103448
+ </tspan>
103449
+ }
103450
+ } @else {
103451
+ {{ vm().title }}
103452
+ }
102162
103453
  </text>
102163
103454
  }
102164
103455
 
@@ -102357,7 +103648,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
102357
103648
  [attr.fill]="vm().titleStyle?.fill ?? '#1e293b'"
102358
103649
  data-chart-part="title"
102359
103650
  >
102360
- {{ vm().title }}
103651
+ @if (vm().titleRunSpans; as titleRunSpans) {
103652
+ @for (run of titleRunSpans; track $index) {
103653
+ <tspan
103654
+ [attr.font-size]="run.fontSize"
103655
+ [attr.font-weight]="run.fontWeight"
103656
+ [attr.font-style]="run.fontStyle"
103657
+ [attr.font-family]="run.fontFamily"
103658
+ [attr.fill]="run.fill"
103659
+ >
103660
+ {{ run.text }}
103661
+ </tspan>
103662
+ }
103663
+ } @else {
103664
+ {{ vm().title }}
103665
+ }
102361
103666
  </text>
102362
103667
  }
102363
103668
 
@@ -102789,6 +104094,17 @@ function chartDragCommitData(session, commit) {
102789
104094
  }
102790
104095
  return session.lastData;
102791
104096
  }
104097
+ /**
104098
+ * Same gate as {@link chartDragCommitData}, for a pie/radar/stacked mark drag
104099
+ * ({@link ChartMarkDragState} carries the same `moved`/`lastData` shape as the
104100
+ * cartesian value-drag session, just resolved through a different geometry).
104101
+ */
104102
+ function chartMarkDragCommitData(session, commit) {
104103
+ if (!commit || !session?.moved) {
104104
+ return null;
104105
+ }
104106
+ return session.lastData;
104107
+ }
102792
104108
  /**
102793
104109
  * Commit an on-canvas chart edit through the editor's normal element-update
102794
104110
  * path (the exact channel the inspector uses: one history snapshot per call).
@@ -103381,6 +104697,12 @@ class ChartElementViewComponent {
103381
104697
  ...(ngDevMode ? [{ debugName: "titleEditor" }] : /* istanbul ignore next */ []));
103382
104698
  /** In-flight vertical value drag, or null. */
103383
104699
  this.dragSession = null;
104700
+ /**
104701
+ * In-flight pie/doughnut slice, radar vertex, or stacked segment drag, or
104702
+ * null. Runs through a parallel state machine (no single vertical value
104703
+ * axis), never both at once.
104704
+ */
104705
+ this.markDragSession = null;
103384
104706
  /** Local drag preview: rendered instead of the committed data mid-drag. */
103385
104707
  this.previewData = signal(null, /* @ts-ignore */
103386
104708
  ...(ngDevMode ? [{ debugName: "previewData" }] : /* istanbul ignore next */ []));
@@ -103541,13 +104863,46 @@ class ChartElementViewComponent {
103541
104863
  if (!chartData || !vm) {
103542
104864
  return;
103543
104865
  }
103544
- const session = beginChartValueDrag({
103545
- part,
103546
- viewModel: vm,
103547
- chartData,
103548
- clientY: event.clientY,
103549
- });
103550
- if (!session) {
104866
+ let captured = false;
104867
+ // Pie/doughnut/radar/stacked marks: try the angle/radial/segment drag first.
104868
+ const chartKind = resolveChartKind(chartData.chartType ?? 'bar');
104869
+ if (part.pointIndex !== undefined && chartKind !== 'unsupported') {
104870
+ const markGeometry = buildChartMarkDragGeometry({
104871
+ kind: chartKind,
104872
+ element: this.element(),
104873
+ chartData,
104874
+ categoryLabels: chartData.categories,
104875
+ seriesIndex: part.seriesIndex,
104876
+ pointIndex: part.pointIndex,
104877
+ });
104878
+ const markSession = beginChartMarkDrag({
104879
+ part,
104880
+ geometry: markGeometry,
104881
+ chartData,
104882
+ svgWidth: vm.svgWidth,
104883
+ svgHeight: vm.svgHeight,
104884
+ clientX: event.clientX,
104885
+ clientY: event.clientY,
104886
+ });
104887
+ if (markSession) {
104888
+ this.markDragSession = markSession;
104889
+ captured = true;
104890
+ }
104891
+ }
104892
+ // Clustered bar/line/scatter/bubble: the existing vertical value-axis drag.
104893
+ if (!captured) {
104894
+ const session = beginChartValueDrag({
104895
+ part,
104896
+ viewModel: vm,
104897
+ chartData,
104898
+ clientY: event.clientY,
104899
+ });
104900
+ if (session) {
104901
+ this.dragSession = session;
104902
+ captured = true;
104903
+ }
104904
+ }
104905
+ if (!captured) {
103551
104906
  return;
103552
104907
  }
103553
104908
  event.preventDefault();
@@ -103559,9 +104914,21 @@ class ChartElementViewComponent {
103559
104914
  catch {
103560
104915
  // Non-fatal: the drag still works while the pointer stays over the chart.
103561
104916
  }
103562
- this.dragSession = session;
103563
104917
  }
103564
104918
  onPointerMove(event) {
104919
+ const markSession = this.markDragSession;
104920
+ if (markSession) {
104921
+ const rect = this.wrapper()?.nativeElement.querySelector('svg')?.getBoundingClientRect();
104922
+ if (!rect) {
104923
+ return;
104924
+ }
104925
+ const step = advanceChartMarkDrag(markSession, event.clientX, event.clientY, rect);
104926
+ if (step) {
104927
+ this.previewData.set(step.chartData);
104928
+ this.dragValue.set(step.value);
104929
+ }
104930
+ return;
104931
+ }
103565
104932
  const session = this.dragSession;
103566
104933
  if (!session) {
103567
104934
  return;
@@ -103575,19 +104942,21 @@ class ChartElementViewComponent {
103575
104942
  }
103576
104943
  }
103577
104944
  onPointerUp() {
103578
- if (this.dragSession) {
104945
+ if (this.dragSession || this.markDragSession) {
103579
104946
  this.endDrag(true);
103580
104947
  }
103581
104948
  }
103582
104949
  /** Cancel an in-flight value drag with Escape (document-level, like React). */
103583
104950
  onEscape() {
103584
- if (this.dragSession) {
104951
+ if (this.dragSession || this.markDragSession) {
103585
104952
  this.endDrag(false);
103586
104953
  }
103587
104954
  }
103588
104955
  endDrag(commit) {
103589
- const data = chartDragCommitData(this.dragSession, commit);
104956
+ const data = chartDragCommitData(this.dragSession, commit) ??
104957
+ chartMarkDragCommitData(this.markDragSession, commit);
103590
104958
  this.dragSession = null;
104959
+ this.markDragSession = null;
103591
104960
  this.previewData.set(null);
103592
104961
  this.dragValue.set(null);
103593
104962
  if (data) {
@@ -103949,6 +105318,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
103949
105318
  }]
103950
105319
  }], propDecorators: { text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: false }] }], segments: [{ type: i0.Input, args: [{ isSignal: true, alias: "segments", required: false }] }], textStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "textStyle", required: false }] }] } });
103951
105320
 
105321
+ /**
105322
+ * `pptx-dynamic-style`: a `<style>` element whose text follows a signal.
105323
+ *
105324
+ * Angular's template compiler strips every literal `<style>` from a component
105325
+ * template and folds its STATIC text into the component's styles, so both
105326
+ * `<style>{{ css }}</style>` and `<style [textContent]="css">` render nothing
105327
+ * at runtime (the former even trips esbuild's CSS parser on the `{{`). The
105328
+ * other four bindings interpolate into a real `<style>` (Svelte via
105329
+ * `<svelte:element this={'style'}>`, Vue via `<component :is="'style'">`);
105330
+ * this component is Angular's equivalent: it creates the element imperatively
105331
+ * through `Renderer2`, which the compiler never sees, and keeps its
105332
+ * `textContent` in step with the `css` input.
105333
+ *
105334
+ * Used for per-element animation CSS that must live in the document rather
105335
+ * than in component styles: the text-style emphasis override
105336
+ * (`animation-text-style-css.ts`) and the ink replay keyframes.
105337
+ *
105338
+ * @module viewer/dynamic-style.component
105339
+ */
105340
+ class DynamicStyleComponent {
105341
+ constructor() {
105342
+ /** The stylesheet text; `undefined`/empty removes the `<style>` element. */
105343
+ this.css = input(undefined, /* @ts-ignore */
105344
+ ...(ngDevMode ? [{ debugName: "css" }] : /* istanbul ignore next */ []));
105345
+ this.host = inject(ElementRef);
105346
+ this.renderer = inject(Renderer2);
105347
+ effect(() => {
105348
+ const text = this.css();
105349
+ if (!text) {
105350
+ if (this.styleEl) {
105351
+ this.renderer.removeChild(this.host.nativeElement, this.styleEl);
105352
+ this.styleEl = undefined;
105353
+ }
105354
+ return;
105355
+ }
105356
+ if (!this.styleEl) {
105357
+ this.styleEl = this.renderer.createElement('style');
105358
+ this.renderer.appendChild(this.host.nativeElement, this.styleEl);
105359
+ }
105360
+ this.renderer.setProperty(this.styleEl, 'textContent', text);
105361
+ });
105362
+ }
105363
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DynamicStyleComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
105364
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "22.1.3", type: DynamicStyleComponent, isStandalone: true, selector: "pptx-dynamic-style", inputs: { css: { classPropertyName: "css", publicName: "css", isSignal: true, isRequired: false, transformFunction: null } }, host: { styleAttribute: "display: contents" }, ngImport: i0, template: '', isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
105365
+ }
105366
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: DynamicStyleComponent, decorators: [{
105367
+ type: Component,
105368
+ args: [{
105369
+ selector: 'pptx-dynamic-style',
105370
+ standalone: true,
105371
+ changeDetection: ChangeDetectionStrategy.OnPush,
105372
+ template: '',
105373
+ host: { style: 'display: contents' },
105374
+ }]
105375
+ }], ctorParameters: () => [], propDecorators: { css: [{ type: i0.Input, args: [{ isSignal: true, alias: "css", required: false }] }] } });
105376
+
103952
105377
  /**
103953
105378
  * ConnectorRendererComponent: Angular port of the Vue `ConnectorRenderer.vue`
103954
105379
  * (and the React `ConnectorElementRenderer`, basic subset).
@@ -104010,6 +105435,14 @@ class ConnectorRendererComponent {
104010
105435
  */
104011
105436
  this.animationState = input(undefined, /* @ts-ignore */
104012
105437
  ...(ngDevMode ? [{ debugName: "animationState" }] : /* istanbul ignore next */ []));
105438
+ /**
105439
+ * Scoped `!important` CSS override for an active font-style emphasis effect
105440
+ * (Bold Flash, Bold Reveal, Underline, Change Font Style/Size), built by the
105441
+ * parent `ElementRendererComponent` (`buildTextStyleOverrideCss`) so a
105442
+ * connector's own caption animates the same way a shape's text does.
105443
+ */
105444
+ this.textStyleOverrideCss = input(undefined, /* @ts-ignore */
105445
+ ...(ngDevMode ? [{ debugName: "textStyleOverrideCss" }] : /* istanbul ignore next */ []));
104013
105446
  /** All derived geometry, recomputed on every input change. */
104014
105447
  this.geo = computed(() => {
104015
105448
  const obstacles = this.obstacles();
@@ -104076,13 +105509,18 @@ class ConnectorRendererComponent {
104076
105509
  ...(ngDevMode ? [{ debugName: "connectorTextStyle" }] : /* istanbul ignore next */ []));
104077
105510
  }
104078
105511
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConnectorRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
104079
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ConnectorRendererComponent, isStandalone: true, selector: "pptx-connector-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, obstacles: { classPropertyName: "obstacles", publicName: "obstacles", isSignal: true, isRequired: false, transformFunction: null }, canvasWidth: { classPropertyName: "canvasWidth", publicName: "canvasWidth", isSignal: true, isRequired: false, transformFunction: null }, canvasHeight: { classPropertyName: "canvasHeight", publicName: "canvasHeight", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, marked: { classPropertyName: "marked", publicName: "marked", isSignal: true, isRequired: false, transformFunction: null }, exposeElementId: { classPropertyName: "exposeElementId", publicName: "exposeElementId", isSignal: true, isRequired: false, transformFunction: null }, animationState: { classPropertyName: "animationState", publicName: "animationState", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
105512
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ConnectorRendererComponent, isStandalone: true, selector: "pptx-connector-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, obstacles: { classPropertyName: "obstacles", publicName: "obstacles", isSignal: true, isRequired: false, transformFunction: null }, canvasWidth: { classPropertyName: "canvasWidth", publicName: "canvasWidth", isSignal: true, isRequired: false, transformFunction: null }, canvasHeight: { classPropertyName: "canvasHeight", publicName: "canvasHeight", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, marked: { classPropertyName: "marked", publicName: "marked", isSignal: true, isRequired: false, transformFunction: null }, exposeElementId: { classPropertyName: "exposeElementId", publicName: "exposeElementId", isSignal: true, isRequired: false, transformFunction: null }, animationState: { classPropertyName: "animationState", publicName: "animationState", isSignal: true, isRequired: false, transformFunction: null }, textStyleOverrideCss: { classPropertyName: "textStyleOverrideCss", publicName: "textStyleOverrideCss", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
104080
105513
  <div
104081
105514
  class="pptx-ng-element pptx-ng-connector"
104082
105515
  [style]="wrapperStyle()"
104083
105516
  [attr.data-element-id]="elementIdAttr()"
104084
105517
  [attr.data-pptx-element]="interactive() || marked() ? 'true' : null"
104085
105518
  >
105519
+ <!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,
105520
+ Change Font Style/Size) overrides the caption's own inline
105521
+ bold/italic/underline/size, which plain CSS inheritance cannot
105522
+ reach. See animation-text-style-css.ts. -->
105523
+ <pptx-dynamic-style [css]="textStyleOverrideCss()" />
104086
105524
  <svg
104087
105525
  [attr.width]="geo().svgW"
104088
105526
  [attr.height]="geo().svgH"
@@ -104196,7 +105634,7 @@ class ConnectorRendererComponent {
104196
105634
  [textStyle]="connectorTextStyle()"
104197
105635
  />
104198
105636
  </div>
104199
- `, isInline: true, dependencies: [{ kind: "component", type: ConnectorTextOverlayComponent, selector: "pptx-connector-text-overlay", inputs: ["text", "segments", "textStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
105637
+ `, isInline: true, dependencies: [{ kind: "component", type: ConnectorTextOverlayComponent, selector: "pptx-connector-text-overlay", inputs: ["text", "segments", "textStyle"] }, { kind: "component", type: DynamicStyleComponent, selector: "pptx-dynamic-style", inputs: ["css"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
104200
105638
  }
104201
105639
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ConnectorRendererComponent, decorators: [{
104202
105640
  type: Component,
@@ -104204,7 +105642,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
104204
105642
  selector: 'pptx-connector-renderer',
104205
105643
  standalone: true,
104206
105644
  changeDetection: ChangeDetectionStrategy.OnPush,
104207
- imports: [ConnectorTextOverlayComponent],
105645
+ imports: [ConnectorTextOverlayComponent, DynamicStyleComponent],
104208
105646
  template: `
104209
105647
  <div
104210
105648
  class="pptx-ng-element pptx-ng-connector"
@@ -104212,6 +105650,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
104212
105650
  [attr.data-element-id]="elementIdAttr()"
104213
105651
  [attr.data-pptx-element]="interactive() || marked() ? 'true' : null"
104214
105652
  >
105653
+ <!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,
105654
+ Change Font Style/Size) overrides the caption's own inline
105655
+ bold/italic/underline/size, which plain CSS inheritance cannot
105656
+ reach. See animation-text-style-css.ts. -->
105657
+ <pptx-dynamic-style [css]="textStyleOverrideCss()" />
104215
105658
  <svg
104216
105659
  [attr.width]="geo().svgW"
104217
105660
  [attr.height]="geo().svgH"
@@ -104327,7 +105770,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
104327
105770
  </div>
104328
105771
  `,
104329
105772
  }]
104330
- }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], obstacles: [{ type: i0.Input, args: [{ isSignal: true, alias: "obstacles", required: false }] }], canvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasWidth", required: false }] }], canvasHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasHeight", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], marked: [{ type: i0.Input, args: [{ isSignal: true, alias: "marked", required: false }] }], exposeElementId: [{ type: i0.Input, args: [{ isSignal: true, alias: "exposeElementId", required: false }] }], animationState: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationState", required: false }] }] } });
105773
+ }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], obstacles: [{ type: i0.Input, args: [{ isSignal: true, alias: "obstacles", required: false }] }], canvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasWidth", required: false }] }], canvasHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasHeight", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], marked: [{ type: i0.Input, args: [{ isSignal: true, alias: "marked", required: false }] }], exposeElementId: [{ type: i0.Input, args: [{ isSignal: true, alias: "exposeElementId", required: false }] }], animationState: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationState", required: false }] }], textStyleOverrideCss: [{ type: i0.Input, args: [{ isSignal: true, alias: "textStyleOverrideCss", required: false }] }] } });
104331
105774
 
104332
105775
  /**
104333
105776
  * Scalar viewer defaults, shared across the React, Vue, and Angular bindings
@@ -105205,15 +106648,15 @@ class ContentPartRendererComponent {
105205
106648
  [attr.data-pptx-element]="markElement() ? 'true' : null"
105206
106649
  >
105207
106650
  @if (strokes().length > 0) {
106651
+ @if (replay()) {
106652
+ <pptx-dynamic-style [css]="replayKeyframes" />
106653
+ }
105208
106654
  <svg
105209
106655
  class="pptx-ng-contentpart-svg"
105210
106656
  [attr.viewBox]="viewBox()"
105211
106657
  preserveAspectRatio="none"
105212
106658
  style="width:100%;height:100%;pointer-events:none;display:block"
105213
106659
  >
105214
- @if (replay()) {
105215
- <style [textContent]="replayKeyframes"></style>
105216
- }
105217
106660
  @for (stroke of strokes(); track stroke.key) {
105218
106661
  @if (stroke.nibMarks && stroke.nibMarks.length > 0) {
105219
106662
  <g [attr.opacity]="stroke.opacity">
@@ -105263,11 +106706,11 @@ class ContentPartRendererComponent {
105263
106706
  </div>
105264
106707
  }
105265
106708
  </div>
105266
- `, isInline: true, styles: [".pptx-ng-contentpart-fallback{width:100%;height:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:1px dashed rgba(100,116,139,.6);border-radius:4px;background:#94a3b814}.pptx-ng-contentpart-fallback-label{font-size:11px;font-family:system-ui,sans-serif;color:#64748be6;text-transform:uppercase;letter-spacing:.08em}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
106709
+ `, isInline: true, styles: [".pptx-ng-contentpart-fallback{width:100%;height:100%;box-sizing:border-box;display:flex;align-items:center;justify-content:center;border:1px dashed rgba(100,116,139,.6);border-radius:4px;background:#94a3b814}.pptx-ng-contentpart-fallback-label{font-size:11px;font-family:system-ui,sans-serif;color:#64748be6;text-transform:uppercase;letter-spacing:.08em}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: DynamicStyleComponent, selector: "pptx-dynamic-style", inputs: ["css"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
105267
106710
  }
105268
106711
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ContentPartRendererComponent, decorators: [{
105269
106712
  type: Component,
105270
- args: [{ selector: 'pptx-content-part-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle], template: `
106713
+ args: [{ selector: 'pptx-content-part-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, DynamicStyleComponent], template: `
105271
106714
  <div
105272
106715
  class="pptx-ng-element pptx-ng-contentpart"
105273
106716
  [ngStyle]="containerStyle()"
@@ -105275,15 +106718,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
105275
106718
  [attr.data-pptx-element]="markElement() ? 'true' : null"
105276
106719
  >
105277
106720
  @if (strokes().length > 0) {
106721
+ @if (replay()) {
106722
+ <pptx-dynamic-style [css]="replayKeyframes" />
106723
+ }
105278
106724
  <svg
105279
106725
  class="pptx-ng-contentpart-svg"
105280
106726
  [attr.viewBox]="viewBox()"
105281
106727
  preserveAspectRatio="none"
105282
106728
  style="width:100%;height:100%;pointer-events:none;display:block"
105283
106729
  >
105284
- @if (replay()) {
105285
- <style [textContent]="replayKeyframes"></style>
105286
- }
105287
106730
  @for (stroke of strokes(); track stroke.key) {
105288
106731
  @if (stroke.nibMarks && stroke.nibMarks.length > 0) {
105289
106732
  <g [attr.opacity]="stroke.opacity">
@@ -108632,6 +110075,18 @@ class ElementRendererComponent {
108632
110075
  */
108633
110076
  this.animationState = computed(() => this.playback?.presentationElementStates().get(this.element().id), /* @ts-ignore */
108634
110077
  ...(ngDevMode ? [{ debugName: "animationState" }] : /* istanbul ignore next */ []));
110078
+ /**
110079
+ * A font-style emphasis effect (Bold Flash, Bold Reveal, Underline, Change
110080
+ * Font Style/Size) overrides the runs' own inline bold/italic/underline/
110081
+ * size, which plain CSS inheritance cannot reach (the runs declare those
110082
+ * unconditionally). See `animation-text-style-css.ts`. NOT gated on
110083
+ * `hasTextProperties`: a table cell, a chart title/label/legend, and a
110084
+ * SmartArt node caption all animate this way too, and shared's selector
110085
+ * already scopes itself to this element's `data-element-id`, which every
110086
+ * branch of the template below carries on its own root.
110087
+ */
110088
+ this.textStyleOverrideCss = computed(() => buildTextStyleOverrideCss(this.element().id, this.animationState()?.textStyle), /* @ts-ignore */
110089
+ ...(ngDevMode ? [{ debugName: "textStyleOverrideCss" }] : /* istanbul ignore next */ []));
108635
110090
  /**
108636
110091
  * Per-paragraph split for a staged text build (by paragraph / word / letter),
108637
110092
  * or `undefined` entries to render the runs normally. PowerPoint's "Animate
@@ -108806,7 +110261,7 @@ class ElementRendererComponent {
108806
110261
  return { ...(span.style ?? {}), ...textBuildSpanStyle(span) };
108807
110262
  }
108808
110263
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ElementRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
108809
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ElementRendererComponent, isStandalone: true, selector: "pptx-element-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, obstacles: { classPropertyName: "obstacles", publicName: "obstacles", isSignal: true, isRequired: false, transformFunction: null }, canvasWidth: { classPropertyName: "canvasWidth", publicName: "canvasWidth", isSignal: true, isRequired: false, transformFunction: null }, canvasHeight: { classPropertyName: "canvasHeight", publicName: "canvasHeight", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, marked: { classPropertyName: "marked", publicName: "marked", isSignal: true, isRequired: false, transformFunction: null }, exposeElementId: { classPropertyName: "exposeElementId", publicName: "exposeElementId", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, fieldContext: { classPropertyName: "fieldContext", publicName: "fieldContext", isSignal: true, isRequired: false, transformFunction: null }, slideElements: { classPropertyName: "slideElements", publicName: "slideElements", isSignal: true, isRequired: false, transformFunction: null }, editTemplateMode: { classPropertyName: "editTemplateMode", publicName: "editTemplateMode", isSignal: true, isRequired: false, transformFunction: null }, parentGroupFill: { classPropertyName: "parentGroupFill", publicName: "parentGroupFill", isSignal: true, isRequired: false, transformFunction: null }, editingElementId: { classPropertyName: "editingElementId", publicName: "editingElementId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellCommit: "cellCommit", tableChange: "tableChange" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@switch (true) {\n\t@case (isHidden()) {\n\t\t<!--\n\t\t\tHidden via the Selection Pane: draw nothing, exactly as PowerPoint\n\t\t\tdoes. This is the FIRST case on purpose - @switch takes the first\n\t\t\tmatch, so one empty branch suppresses every element type at once\n\t\t\twithout wrapping (and re-indenting) the whole template. The host\n\t\t\tcarries \\`display: contents\\`, so an empty component collapses.\n\t\t\tRendering nothing (rather than an invisible box) is what keeps the\n\t\t\telement out of hit-testing, the tab order and the export raster; it\n\t\t\tstays listed in and selectable from the Selection Pane, which reads\n\t\t\tthe slide model rather than the DOM.\n\t\t-->\n\t}\n\t@case (element().type === 'connector') {\n\t\t<pptx-connector-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[obstacles]=\"obstacles()\"\n\t\t\t[canvasWidth]=\"canvasWidth()\"\n\t\t\t[canvasHeight]=\"canvasHeight()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[animationState]=\"animationState()\"\n\t\t/>\n\t}\n\t@case (element().type === 'ink') {\n\t\t<!--\n\t\t\tThis renderer (and zoom / model3d / 3D SmartArt below) positions its\n\t\t\town root box, so it takes the neutral element marker\n\t\t\t(data-pptx-element) as an input instead of being wrapped in a marked\n\t\t\tbox the way chart / table / OLE are: an outer positioned box would\n\t\t\toffset it twice.\n\t\t-->\n\t\t<pptx-ink-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'contentPart') {\n\t\t<!--\n\t\t\tReal PowerPoint ink. Same positioning contract as pptx-ink-renderer\n\t\t\tabove: the renderer's own root is absolutely positioned, so it takes\n\t\t\tthe neutral element marker as an input rather than being wrapped.\n\t\t-->\n\t\t<pptx-content-part-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'zoom') {\n\t\t<pptx-zoom-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'model3d') {\n\t\t<pptx-model3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt' && smartArt3D()) {\n\t\t<pptx-smart-art-3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[canEdit]=\"interactive() && editable()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-smartart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-smart-art-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'ole') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-ole\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-ole-renderer [element]=\"element()\" />\n\t\t</div>\n\t}\n\t@case (element().type === 'chart') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-chart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-chart-element-view\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'table') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-table\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-table-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t(cellCommit)=\"cellCommit.emit({ id: element().id, commit: $event })\"\n\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'group') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-group\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t@for (child of children(); track child.id) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"child\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"$index\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[marked]=\"marked()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"slideElements()\"\n\t\t\t\t\t[parentGroupFill]=\"childParentGroupFill()\"\n\t\t\t\t\t[editingElementId]=\"editingElementId()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t</div>\n\t}\n\t@case (isImageLike()) {\n\t\t<pptx-image-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'media') {\n\t\t<pptx-media-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[presenting]=\"presenting()\"\n\t\t\t[placeholderLabel]=\"placeholderLabel()\"\n\t\t/>\n\t}\n\t@case (isShapeLike()) {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-shape\"\n\t\t\t[ngStyle]=\"shapeContainerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- Per-sub-path fill overlay: a multi-sub-path preset (`smileyFace`'s\n\t\t\t open eyes, `actionButtonBlank`'s darkened bevel well) or custom\n\t\t\t geometry whose sub-paths cannot share one CSS background-color. -->\n\t\t\t@if (subpathFill(); as sf) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-subpath-fill\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"subpathFillViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; width: 100%; height: 100%\"\n\t\t\t\t>\n\t\t\t\t\t@for (paint of sf.paints; track $index) {\n\t\t\t\t\t\t<path [attr.d]=\"paint.d\" [attr.fill]=\"paint.fill\" stroke=\"none\" />\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t@if (fillOverlay(); as ov) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-fill-overlay\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none\"\n\t\t\t\t\t[style.background]=\"ov.color\"\n\t\t\t\t\t[style.mix-blend-mode]=\"ov.blendMode\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t<!-- Mirrored reflection sibling (`a:reflection`): cross-browser, unlike\n\t\t\t the `-webkit-box-reflect` this replaced (Firefox never implemented\n\t\t\t that property, so reflections were invisible there entirely). -->\n\t\t\t@if (reflection(); as refl) {\n\t\t\t\t<div class=\"pptx-ng-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl.wrapperStyle\">\n\t\t\t\t\t@if (refl.imgSrc) {\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t[src]=\"refl.imgSrc\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tdraggable=\"false\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[ngStyle]=\"refl.imgFitStyle\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (refl.fill) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[style.background-color]=\"refl.fill.backgroundColor\"\n\t\t\t\t\t\t\t[style.background-image]=\"refl.fill.backgroundImage\"\n\t\t\t\t\t\t\t[style.background-size]=\"refl.fill.backgroundSize\"\n\t\t\t\t\t\t\t[style.background-position]=\"refl.fill.backgroundPosition\"\n\t\t\t\t\t\t\t[style.background-repeat]=\"refl.fill.backgroundRepeat\"\n\t\t\t\t\t\t></div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t\t<!-- Hollow frame hit target: an unfilled, textless shape is hit-tested\n\t\t\t on its outline only, so its interior lets clicks through. -->\n\t\t\t@if (hollowHit(); as hit) {\n\t\t\t\t<svg\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\t[attr.d]=\"hit.d\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"transparent\"\n\t\t\t\t\t\t[attr.stroke-width]=\"hit.strokeWidth\"\n\t\t\t\t\t\tstyle=\"pointer-events: stroke\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- Stroked outline: a CSS border takes one flat colour, and cannot\n\t\t\t outline an open preset (`line`, `arc`) at all. -->\n\t\t\t@if (gradientOutline(); as go) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-gradient-outline\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t@if (go.paint; as paint) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (paint.kind === 'pattern') {\n\t\t\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'rectPath') {\n\t\t\t\t\t\t\t\t<pattern [attr.id]=\"paint.id\" patternUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t\t\t\t\twidth=\"1\"\n\t\t\t\t\t\t\t\t\t\theight=\"1\"\n\t\t\t\t\t\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"paint.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"paint.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"paint.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"paint.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"paint.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"paint.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"paint.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@for (strand of go.strands; track $index) {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"go.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"go.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"strand.strokeWidth\"\n\t\t\t\t\t\t\t[attr.stroke-dasharray]=\"go.dashArray\"\n\t\t\t\t\t\t\t[attr.stroke-linecap]=\"go.lineCap\"\n\t\t\t\t\t\t\t[attr.stroke-linejoin]=\"go.lineJoin\"\n\t\t\t\t\t\t\t[style.transform]=\"\n\t\t\t\t\t\t\t\tstrand.offset !== 0 ? 'translate(0, ' + strand.offset + 'px)' : null\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- While this element is open in the inline text editor, its live text\n\t\t\t is drawn by that overlay instead (see `isBeingInlineEdited`);\n\t\t\t rendering it here too produced a duplicate, offset \"text shadow\"\n\t\t\t (issue #182). -->\n\t\t\t@if (!isBeingInlineEdited()) {\n\t\t\t\t@if (pathWarp(); as warp) {\n\t\t\t\t\t<svg\n\t\t\t\t\t\t[attr.width]=\"warp.width\"\n\t\t\t\t\t\t[attr.height]=\"warp.height\"\n\t\t\t\t\t\t[attr.viewBox]=\"'0 0 ' + warp.width + ' ' + warp.height\"\n\t\t\t\t\t\tstyle=\"position: absolute; inset: 0; overflow: visible; pointer-events: none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t\t<path [attr.id]=\"line.pathId\" [attr.d]=\"line.d\" fill=\"none\" />\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t[attr.font-size]=\"warp.baseFontSize\"\n\t\t\t\t\t\t\t\t[attr.font-family]=\"warp.baseFontFamily\"\n\t\t\t\t\t\t\t\t[attr.fill]=\"warp.baseColor\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<textPath\n\t\t\t\t\t\t\t\t\t[attr.href]=\"'#' + line.pathId\"\n\t\t\t\t\t\t\t\t\t[attr.startOffset]=\"warp.startOffset\"\n\t\t\t\t\t\t\t\t\t[attr.text-anchor]=\"warp.textAnchor\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (seg of line.segments; track $index) {\n\t\t\t\t\t\t\t\t\t\t<tspan\n\t\t\t\t\t\t\t\t\t\t\t[attr.fill]=\"seg.style?.color ?? warp.baseColor\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-weight]=\"seg.style?.bold ? 700 : 400\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-style]=\"seg.style?.italic ? 'italic' : 'normal'\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{{ seg.text }}\n\t\t\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</textPath>\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t}\n\t\t\t\t\t</svg>\n\t\t\t\t} @else if (placeholderPrompt(); as prompt) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"prompt.style\">{{ prompt.text }}</div>\n\t\t\t\t} @else if (hasText()) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"warpedTextStyle()\">\n\t\t\t\t\t\t@for (para of paragraphs(); track $index) {\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-para\"\n\t\t\t\t\t\t\t\t[ngStyle]=\"para.paragraphStyle ?? null\"\n\t\t\t\t\t\t\t\t[style.padding-left.px]=\"para.indentPx\"\n\t\t\t\t\t\t\t\t[style.text-indent.px]=\"para.textIndentPx ?? null\"\n\t\t\t\t\t\t\t\t[style.line-height]=\"para.lineHeight ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-top.px]=\"para.spaceBeforePx ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-bottom.px]=\"para.spaceAfterPx ?? null\"\n\t\t\t\t\t\t\t\t[style.font-size.px]=\"para.strutFontSizePx ?? null\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (para.bulletPicture?.src) {\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet-image\"\n\t\t\t\t\t\t\t\t\t\t[src]=\"para.bulletPicture.src\"\n\t\t\t\t\t\t\t\t\t\t[alt]=\"para.bulletPicture.accessibleLabel\"\n\t\t\t\t\t\t\t\t\t\t[style.width.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\t[style.height.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"\n\t\t\t\t\t\t\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\t\t\t\t\t\t\tvertical-align: middle;\n\t\t\t\t\t\t\t\t\t\t\tmargin-inline-end: 4px;\n\t\t\t\t\t\t\t\t\t\t\tobject-fit: contain;\n\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t} @else if (para.bulletMarker) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet\"\n\t\t\t\t\t\t\t\t\t\t[ngStyle]=\"para.bulletStyle\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"para.bulletPicture?.accessibleLabel ?? null\"\n\t\t\t\t\t\t\t\t\t\t>{{ para.bulletMarker }}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (textBuildSpecs()[$index]; as spec) {\n\t\t\t\t\t\t\t\t\t<!-- Staged text build: render the split pieces so each one\n\t\t\t\t\t\t\t\t carries its own sub-animation. -->\n\t\t\t\t\t\t\t\t\t@if (spec.granularity === 'paragraph') {\n\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"spec.animId\" [ngStyle]=\"buildSpanStyle(spec)\">{{\n\t\t\t\t\t\t\t\t\t\t\tparagraphText(para)\n\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t@for (span of spec.spans ?? []; track $index) {\n\t\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"span.animId\" [ngStyle]=\"buildSpanStyle(span)\">{{\n\t\t\t\t\t\t\t\t\t\t\t\tspan.text\n\t\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t@for (run of para.runs; track $index) {\n\t\t\t\t\t\t\t\t\t\t@if (run.equationXml) {\n\t\t\t\t\t\t\t\t\t\t\t<pptx-equation-renderer\n\t\t\t\t\t\t\t\t\t\t\t\t[equationXml]=\"run.equationXml\"\n\t\t\t\t\t\t\t\t\t\t\t\t[equationNumber]=\"run.equationNumber\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t} @else if (\n\t\t\t\t\t\t\t\t\t\t\trun.text ===\n\t\t\t\t\t\t\t\t\t\t\t'\n'\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t\t\t} @else if (run.reflection; as refl) {\n\t\t\t\t\t\t\t\t\t\t\t<!-- `a:reflection`: wrapped HERE, around the whole base\n\t\t\t\t\t\t\t\t\t\t run (`runBase`), rather than inside its href/ruby/plain\n\t\t\t\t\t\t\t\t\t\t branches - a `<ruby>` run's own `display: ruby` (which\n\t\t\t\t\t\t\t\t\t\t positions the annotation above its base text) would\n\t\t\t\t\t\t\t\t\t\t break if forced to `display: inline-block` to host the\n\t\t\t\t\t\t\t\t\t\t mirror. Cross-browser, unlike the `-webkit-box-reflect`\n\t\t\t\t\t\t\t\t\t\t this replaced (Firefox never implemented it). -->\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"position: relative; display: inline-block\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pptx-ng-text-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t><span [ngStyle]=\"run.style\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t><ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*ngTemplateOutlet=\"runContent; context: { run: run }\" /></span\n\t\t\t\t\t\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (para.isEmpty) {\n\t\t\t\t\t\t\t\t\t<!-- An authored blank line has no runs, so without this the\n\t\t\t\t\t\t\t\t <p> collapses to zero height and the gap a deck puts\n\t\t\t\t\t\t\t\t between a heading and its bullet list disappears. -->\n\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t}\n\t\t</div>\n\t}\n\t@default {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-unsupported\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-placeholder\">{{ placeholderLabel() }}</div>\n\t\t</div>\n\t}\n}\n\n<!-- Soft-edge feather <filter> def, referenced via filter: url(#soft-edge-<id>). -->\n@if (softEdgeFilter(); as sef) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter\n\t\t\t\t[attr.id]=\"sef.id\"\n\t\t\t\tx=\"-20%\"\n\t\t\t\ty=\"-20%\"\n\t\t\t\twidth=\"140%\"\n\t\t\t\theight=\"140%\"\n\t\t\t\tcolor-interpolation-filters=\"sRGB\"\n\t\t\t>\n\t\t\t\t<feGaussianBlur in=\"SourceAlpha\" [attr.stdDeviation]=\"sef.radius\" result=\"softEdgeAlpha\" />\n\t\t\t\t<feComposite in=\"SourceGraphic\" in2=\"softEdgeAlpha\" operator=\"in\" />\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!-- Duotone image-effect <filter> def, referenced via filter: url(#id). -->\n@if (duotoneFilter(); as df) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter [attr.id]=\"df.id\" color-interpolation-filters=\"sRGB\">\n\t\t\t\t<feColorMatrix type=\"matrix\" [attr.values]=\"df.primitives[0].values\" />\n\t\t\t\t<feComponentTransfer>\n\t\t\t\t\t<feFuncR\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[0].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[0].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncG\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[1].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[1].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncB\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[2].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[2].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t</feComponentTransfer>\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!--\n\tOne run's base element (hyperlink / ruby / plain span), reused via\n\t`ngTemplateOutlet` both directly and inside the `a:reflection` wrapper above,\n\tso the reflection case does not duplicate this three-way branch.\n-->\n<ng-template #runBase let-run=\"run\">\n\t@if (run.href) {\n\t\t<a\n\t\t\tclass=\"pptx-ng-link\"\n\t\t\t[href]=\"run.href\"\n\t\t\t[attr.target]=\"run.target ?? '_blank'\"\n\t\t\t[attr.rel]=\"run.rel ?? 'noopener noreferrer'\"\n\t\t\t[attr.title]=\"run.tooltip ?? null\"\n\t\t\t[ngStyle]=\"run.style\"\n\t\t\t(click)=\"onHyperlinkClick($event, run.href)\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></a>\n\t} @else if (run.rubyText) {\n\t\t<!-- `a:ruby`: the phonetic guide sits above its base\n\t\t text; the <rp> parentheses are the fallback for a\n\t\t browser without ruby support. -->\n\t\t<ruby [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\" /><rp>(</rp\n\t\t\t><rt [ngStyle]=\"run.rubyStyle\">{{ run.rubyText }}</rt\n\t\t\t><rp>)</rp></ruby\n\t\t>\n\t} @else {\n\t\t<span [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></span>\n\t}\n</ng-template>\n\n<!--\n\tA run's text content, honouring shared's per-script font split\n\t(`run.scriptRuns`) and measured tab-stop layout (`run.tabLines`) when\n\teither is present. Both descriptors come from `pptx-viewer-shared`'s\n\t`buildParagraphs` (the per-script split was React-only before this\n\ttemplate existed: CJK, Arabic, Hebrew and Thai text rendered in the wrong\n\ttypeface here; the tab layout was likewise React-only, so a TOC-style row\n\tlost its leader dots and right-aligned page number). Reused via\n\t`ngTemplateOutlet` for the run's span / anchor / ruby base text, so all\n\tthree carry the same content logic.\n-->\n<ng-template #runContent let-run=\"run\">\n\t@if (run.tabLines) {\n\t\t@for (line of run.tabLines; track $index) {\n\t\t\t<span style=\"display: inline-block; white-space: nowrap\">\n\t\t\t\t@for (piece of line.pieces; track $index) {\n\t\t\t\t\t@if (piece.leaderStyle) {\n\t\t\t\t\t\t<span aria-hidden=\"true\" [ngStyle]=\"piece.leaderStyle\">{{ piece.leaderText }}</span>\n\t\t\t\t\t}\n\t\t\t\t\t<!-- `u=\"words\"`: one sibling span per word/gap in place of the piece span. -->\n\t\t\t\t\t@if (piece.words) {\n\t\t\t\t\t\t@for (word of piece.words; track $index) {\n\t\t\t\t\t\t\t<span [ngStyle]=\"word.style\">{{ word.text }}</span>\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</span>\n\t\t\t@if (!$last) {\n\t\t\t\t<br />\n\t\t\t}\n\t\t}\n\t} @else if (run.scriptRuns || run.underlineWordPieces) {\n\t\t<!--\n\t\t\tA bare interpolation as the sole content of an `@if`/`@else` block\n\t\t\tleaks a real leading + trailing whitespace text node: Angular does\n\t\t\tnot collapse that whitespace the way it collapses whitespace between\n\t\t\telement TAGS. Worse, oxfmt's Angular-template printer always breaks a\n\t\t\tblock's content onto its own indented line, even when the block was\n\t\t\twritten as a single line with the braces touching, so writing the\n\t\t\t`{{ x }}` compact ourselves does not survive the next `bun run fmt` /\n\t\t\tpre-commit `lint-staged` pass: it silently re-introduces the leak\n\t\t\t(this happened twice, see `20d4d177`, `18eebb6f`). `<ng-container>`\n\t\t\tdoes not render any DOM node of its own, so wrapping the\n\t\t\tinterpolation in one keeps the no-wrapper-element behaviour of\n\t\t\tReact's `<>{piece.text}</>` fragment while making the interpolation\n\t\t\ttag-adjacent, which both Angular AND oxfmt already treat as safely\n\t\t\tcollapsible (see the many `<span>{{ x }}</span>` one-liners in this\n\t\t\tfile). That was invisible while a paragraph was one run per script\n\t\t\t(two stray spaces at the run's own edges, trimmed visually by the\n\t\t\tbrowser but still present in `textContent`), but shared's per-word /\n\t\t\tper-gap metric split (`text-run-spacing.ts`, issue #149) re-emits\n\t\t\tevery WORD and inter-word GAP as its own sibling run, so the same\n\t\t\tone-space leak lands between every word: \"will choose\" rendered as\n\t\t\t\"will choose\" (five spaces: the word's own trailing leak, the\n\t\t\tgap run's real space plus its OWN two leaks, the next word's leading\n\t\t\tleak). The same leak also showed up one paragraph at a time:\n\t\t\t\"Project\" / \"Atlas\" as two separate paragraphs read back as\n\t\t\t\"ProjectAtlas\" instead of React's \"Project Atlas\", because the\n\t\t\tplain-run `@else` below had the same bug.\n\t\t-->\n\t\t@for (piece of run.scriptRuns ?? run.underlineWordPieces; track $index) {\n\t\t\t@if (piece.style) {\n\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t} @else {\n\t\t\t\t<ng-container>{{ piece.text }}</ng-container>\n\t\t\t}\n\t\t}\n\t} @else {\n\t\t<ng-container>{{ run.text }}</ng-container>\n\t}\n</ng-template>\n", dependencies: [{ kind: "component", type: ElementRendererComponent, selector: "pptx-element-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "obstacles", "canvasWidth", "canvasHeight", "interactive", "marked", "exposeElementId", "presenting", "editable", "fieldContext", "slideElements", "editTemplateMode", "parentGroupFill", "editingElementId"], outputs: ["cellCommit", "tableChange"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ConnectorRendererComponent, selector: "pptx-connector-renderer", inputs: ["element", "zIndex", "obstacles", "canvasWidth", "canvasHeight", "interactive", "marked", "exposeElementId", "animationState"] }, { kind: "component", type: TableRendererComponent, selector: "pptx-table-renderer", inputs: ["element", "editable"], outputs: ["cellCommit", "tableChange"] }, { kind: "component", type: ChartElementViewComponent, selector: "pptx-chart-element-view", inputs: ["element", "editable", "animationState"] }, { kind: "component", type: SmartArtRendererComponent, selector: "pptx-smart-art-renderer", inputs: ["element", "editable", "animationState"] }, { kind: "component", type: SmartArt3DRendererComponent, selector: "pptx-smart-art-3d-renderer", inputs: ["element", "zIndex", "canEdit", "markElement"] }, { kind: "component", type: InkRendererComponent, selector: "pptx-ink-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "replay", "markElement", "exposeElementId"] }, { kind: "component", type: ContentPartRendererComponent, selector: "pptx-content-part-renderer", inputs: ["element", "zIndex", "replay", "markElement", "exposeElementId"] }, { kind: "component", type: MediaRendererComponent, selector: "pptx-media-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "interactive", "marked", "exposeElementId", "presenting", "placeholderLabel"] }, { kind: "component", type: OleRendererComponent, selector: "pptx-ole-renderer", inputs: ["element"] }, { kind: "component", type: Model3DRendererComponent, selector: "pptx-model3d-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "interactive", "markElement", "exposeElementId"] }, { kind: "component", type: ZoomRendererComponent, selector: "pptx-zoom-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "markElement"] }, { kind: "component", type: EquationRendererComponent, selector: "pptx-equation-renderer", inputs: ["equationXml", "equationNumber"] }, { kind: "component", type: ImageRendererComponent, selector: "pptx-image-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "interactive", "marked", "exposeElementId"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
110264
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: ElementRendererComponent, isStandalone: true, selector: "pptx-element-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, zIndex: { classPropertyName: "zIndex", publicName: "zIndex", isSignal: true, isRequired: false, transformFunction: null }, obstacles: { classPropertyName: "obstacles", publicName: "obstacles", isSignal: true, isRequired: false, transformFunction: null }, canvasWidth: { classPropertyName: "canvasWidth", publicName: "canvasWidth", isSignal: true, isRequired: false, transformFunction: null }, canvasHeight: { classPropertyName: "canvasHeight", publicName: "canvasHeight", isSignal: true, isRequired: false, transformFunction: null }, interactive: { classPropertyName: "interactive", publicName: "interactive", isSignal: true, isRequired: false, transformFunction: null }, marked: { classPropertyName: "marked", publicName: "marked", isSignal: true, isRequired: false, transformFunction: null }, exposeElementId: { classPropertyName: "exposeElementId", publicName: "exposeElementId", isSignal: true, isRequired: false, transformFunction: null }, presenting: { classPropertyName: "presenting", publicName: "presenting", isSignal: true, isRequired: false, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, fieldContext: { classPropertyName: "fieldContext", publicName: "fieldContext", isSignal: true, isRequired: false, transformFunction: null }, slideElements: { classPropertyName: "slideElements", publicName: "slideElements", isSignal: true, isRequired: false, transformFunction: null }, editTemplateMode: { classPropertyName: "editTemplateMode", publicName: "editTemplateMode", isSignal: true, isRequired: false, transformFunction: null }, parentGroupFill: { classPropertyName: "parentGroupFill", publicName: "parentGroupFill", isSignal: true, isRequired: false, transformFunction: null }, editingElementId: { classPropertyName: "editingElementId", publicName: "editingElementId", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { cellCommit: "cellCommit", tableChange: "tableChange" }, host: { classAttribute: "contents" }, ngImport: i0, template: "@switch (true) {\n\t@case (isHidden()) {\n\t\t<!--\n\t\t\tHidden via the Selection Pane: draw nothing, exactly as PowerPoint\n\t\t\tdoes. This is the FIRST case on purpose - @switch takes the first\n\t\t\tmatch, so one empty branch suppresses every element type at once\n\t\t\twithout wrapping (and re-indenting) the whole template. The host\n\t\t\tcarries \\`display: contents\\`, so an empty component collapses.\n\t\t\tRendering nothing (rather than an invisible box) is what keeps the\n\t\t\telement out of hit-testing, the tab order and the export raster; it\n\t\t\tstays listed in and selectable from the Selection Pane, which reads\n\t\t\tthe slide model rather than the DOM.\n\t\t-->\n\t}\n\t@case (element().type === 'connector') {\n\t\t<pptx-connector-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[obstacles]=\"obstacles()\"\n\t\t\t[canvasWidth]=\"canvasWidth()\"\n\t\t\t[canvasHeight]=\"canvasHeight()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[animationState]=\"animationState()\"\n\t\t\t[textStyleOverrideCss]=\"textStyleOverrideCss()\"\n\t\t/>\n\t}\n\t@case (element().type === 'ink') {\n\t\t<!--\n\t\t\tThis renderer (and zoom / model3d / 3D SmartArt below) positions its\n\t\t\town root box, so it takes the neutral element marker\n\t\t\t(data-pptx-element) as an input instead of being wrapped in a marked\n\t\t\tbox the way chart / table / OLE are: an outer positioned box would\n\t\t\toffset it twice.\n\t\t-->\n\t\t<pptx-ink-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'contentPart') {\n\t\t<!--\n\t\t\tReal PowerPoint ink. Same positioning contract as pptx-ink-renderer\n\t\t\tabove: the renderer's own root is absolutely positioned, so it takes\n\t\t\tthe neutral element marker as an input rather than being wrapped.\n\t\t-->\n\t\t<pptx-content-part-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'zoom') {\n\t\t<pptx-zoom-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'model3d') {\n\t\t<pptx-model3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt' && smartArt3D()) {\n\t\t<pptx-smart-art-3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[canEdit]=\"interactive() && editable()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-smartart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a SmartArt node caption's own\n\t\t\t inline bold/italic/underline/size, which plain CSS inheritance\n\t\t\t cannot reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-smart-art-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'ole') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-ole\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-ole-renderer [element]=\"element()\" />\n\t\t</div>\n\t}\n\t@case (element().type === 'chart') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-chart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a chart title/label/legend's\n\t\t\t own SVG text attributes, which plain CSS inheritance cannot\n\t\t\t reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-chart-element-view\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'table') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-table\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a table cell's own inline\n\t\t\t bold/italic/underline/size, which plain CSS inheritance cannot\n\t\t\t reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-table-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t(cellCommit)=\"cellCommit.emit({ id: element().id, commit: $event })\"\n\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'group') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-group\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t@for (child of children(); track child.id) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"child\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"$index\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[marked]=\"marked()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"slideElements()\"\n\t\t\t\t\t[parentGroupFill]=\"childParentGroupFill()\"\n\t\t\t\t\t[editingElementId]=\"editingElementId()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t</div>\n\t}\n\t@case (isImageLike()) {\n\t\t<pptx-image-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'media') {\n\t\t<pptx-media-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[presenting]=\"presenting()\"\n\t\t\t[placeholderLabel]=\"placeholderLabel()\"\n\t\t/>\n\t}\n\t@case (isShapeLike()) {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-shape\"\n\t\t\t[ngStyle]=\"shapeContainerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides the runs' own inline\n\t\t\t bold/italic/underline/size, which plain CSS inheritance cannot\n\t\t\t reach (the runs declare those unconditionally). -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<!-- Per-sub-path fill overlay: a multi-sub-path preset (`smileyFace`'s\n\t\t\t open eyes, `actionButtonBlank`'s darkened bevel well) or custom\n\t\t\t geometry whose sub-paths cannot share one CSS background-color. -->\n\t\t\t@if (subpathFill(); as sf) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-subpath-fill\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"subpathFillViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; width: 100%; height: 100%\"\n\t\t\t\t>\n\t\t\t\t\t@for (paint of sf.paints; track $index) {\n\t\t\t\t\t\t<path [attr.d]=\"paint.d\" [attr.fill]=\"paint.fill\" stroke=\"none\" />\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t@if (fillOverlay(); as ov) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-fill-overlay\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none\"\n\t\t\t\t\t[style.background]=\"ov.color\"\n\t\t\t\t\t[style.mix-blend-mode]=\"ov.blendMode\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t<!-- Mirrored reflection sibling (`a:reflection`): cross-browser, unlike\n\t\t\t the `-webkit-box-reflect` this replaced (Firefox never implemented\n\t\t\t that property, so reflections were invisible there entirely). -->\n\t\t\t@if (reflection(); as refl) {\n\t\t\t\t<div class=\"pptx-ng-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl.wrapperStyle\">\n\t\t\t\t\t@if (refl.imgSrc) {\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t[src]=\"refl.imgSrc\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tdraggable=\"false\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[ngStyle]=\"refl.imgFitStyle\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (refl.fill) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[style.background-color]=\"refl.fill.backgroundColor\"\n\t\t\t\t\t\t\t[style.background-image]=\"refl.fill.backgroundImage\"\n\t\t\t\t\t\t\t[style.background-size]=\"refl.fill.backgroundSize\"\n\t\t\t\t\t\t\t[style.background-position]=\"refl.fill.backgroundPosition\"\n\t\t\t\t\t\t\t[style.background-repeat]=\"refl.fill.backgroundRepeat\"\n\t\t\t\t\t\t></div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t\t<!-- Hollow frame hit target: an unfilled, textless shape is hit-tested\n\t\t\t on its outline only, so its interior lets clicks through. -->\n\t\t\t@if (hollowHit(); as hit) {\n\t\t\t\t<svg\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\t[attr.d]=\"hit.d\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"transparent\"\n\t\t\t\t\t\t[attr.stroke-width]=\"hit.strokeWidth\"\n\t\t\t\t\t\tstyle=\"pointer-events: stroke\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- Stroked outline: a CSS border takes one flat colour, and cannot\n\t\t\t outline an open preset (`line`, `arc`) at all. -->\n\t\t\t@if (gradientOutline(); as go) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-gradient-outline\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t@if (go.paint; as paint) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (paint.kind === 'pattern') {\n\t\t\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'rectPath') {\n\t\t\t\t\t\t\t\t<pattern [attr.id]=\"paint.id\" patternUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t\t\t\t\twidth=\"1\"\n\t\t\t\t\t\t\t\t\t\theight=\"1\"\n\t\t\t\t\t\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"paint.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"paint.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"paint.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"paint.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"paint.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"paint.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"paint.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@for (strand of go.strands; track $index) {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"go.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"go.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"strand.strokeWidth\"\n\t\t\t\t\t\t\t[attr.stroke-dasharray]=\"go.dashArray\"\n\t\t\t\t\t\t\t[attr.stroke-linecap]=\"go.lineCap\"\n\t\t\t\t\t\t\t[attr.stroke-linejoin]=\"go.lineJoin\"\n\t\t\t\t\t\t\t[style.transform]=\"\n\t\t\t\t\t\t\t\tstrand.offset !== 0 ? 'translate(0, ' + strand.offset + 'px)' : null\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- While this element is open in the inline text editor, its live text\n\t\t\t is drawn by that overlay instead (see `isBeingInlineEdited`);\n\t\t\t rendering it here too produced a duplicate, offset \"text shadow\"\n\t\t\t (issue #182). -->\n\t\t\t@if (!isBeingInlineEdited()) {\n\t\t\t\t@if (pathWarp(); as warp) {\n\t\t\t\t\t<svg\n\t\t\t\t\t\t[attr.width]=\"warp.width\"\n\t\t\t\t\t\t[attr.height]=\"warp.height\"\n\t\t\t\t\t\t[attr.viewBox]=\"'0 0 ' + warp.width + ' ' + warp.height\"\n\t\t\t\t\t\tstyle=\"position: absolute; inset: 0; overflow: visible; pointer-events: none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t\t<path [attr.id]=\"line.pathId\" [attr.d]=\"line.d\" fill=\"none\" />\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t[attr.font-size]=\"warp.baseFontSize\"\n\t\t\t\t\t\t\t\t[attr.font-family]=\"warp.baseFontFamily\"\n\t\t\t\t\t\t\t\t[attr.fill]=\"warp.baseColor\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<textPath\n\t\t\t\t\t\t\t\t\t[attr.href]=\"'#' + line.pathId\"\n\t\t\t\t\t\t\t\t\t[attr.startOffset]=\"warp.startOffset\"\n\t\t\t\t\t\t\t\t\t[attr.text-anchor]=\"warp.textAnchor\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (seg of line.segments; track $index) {\n\t\t\t\t\t\t\t\t\t\t<tspan\n\t\t\t\t\t\t\t\t\t\t\t[attr.fill]=\"seg.style?.color ?? warp.baseColor\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-weight]=\"seg.style?.bold ? 700 : 400\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-style]=\"seg.style?.italic ? 'italic' : 'normal'\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{{ seg.text }}\n\t\t\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</textPath>\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t}\n\t\t\t\t\t</svg>\n\t\t\t\t} @else if (placeholderPrompt(); as prompt) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"prompt.style\">{{ prompt.text }}</div>\n\t\t\t\t} @else if (hasText()) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"warpedTextStyle()\">\n\t\t\t\t\t\t@for (para of paragraphs(); track $index) {\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-para\"\n\t\t\t\t\t\t\t\t[ngStyle]=\"para.paragraphStyle ?? null\"\n\t\t\t\t\t\t\t\t[style.padding-left.px]=\"para.indentPx\"\n\t\t\t\t\t\t\t\t[style.text-indent.px]=\"para.textIndentPx ?? null\"\n\t\t\t\t\t\t\t\t[style.line-height]=\"para.lineHeight ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-top.px]=\"para.spaceBeforePx ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-bottom.px]=\"para.spaceAfterPx ?? null\"\n\t\t\t\t\t\t\t\t[style.font-size.px]=\"para.strutFontSizePx ?? null\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (para.bulletPicture?.src) {\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet-image\"\n\t\t\t\t\t\t\t\t\t\t[src]=\"para.bulletPicture.src\"\n\t\t\t\t\t\t\t\t\t\t[alt]=\"para.bulletPicture.accessibleLabel\"\n\t\t\t\t\t\t\t\t\t\t[style.width.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\t[style.height.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"\n\t\t\t\t\t\t\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\t\t\t\t\t\t\tvertical-align: middle;\n\t\t\t\t\t\t\t\t\t\t\tmargin-inline-end: 4px;\n\t\t\t\t\t\t\t\t\t\t\tobject-fit: contain;\n\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t} @else if (para.bulletMarker) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet\"\n\t\t\t\t\t\t\t\t\t\t[ngStyle]=\"para.bulletStyle\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"para.bulletPicture?.accessibleLabel ?? null\"\n\t\t\t\t\t\t\t\t\t\t>{{ para.bulletMarker }}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (textBuildSpecs()[$index]; as spec) {\n\t\t\t\t\t\t\t\t\t<!-- Staged text build: render the split pieces so each one\n\t\t\t\t\t\t\t\t carries its own sub-animation. -->\n\t\t\t\t\t\t\t\t\t@if (spec.granularity === 'paragraph') {\n\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"spec.animId\" [ngStyle]=\"buildSpanStyle(spec)\">{{\n\t\t\t\t\t\t\t\t\t\t\tparagraphText(para)\n\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t@for (span of spec.spans ?? []; track $index) {\n\t\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"span.animId\" [ngStyle]=\"buildSpanStyle(span)\">{{\n\t\t\t\t\t\t\t\t\t\t\t\tspan.text\n\t\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t@for (run of para.runs; track $index) {\n\t\t\t\t\t\t\t\t\t\t@if (run.equationXml) {\n\t\t\t\t\t\t\t\t\t\t\t<pptx-equation-renderer\n\t\t\t\t\t\t\t\t\t\t\t\t[equationXml]=\"run.equationXml\"\n\t\t\t\t\t\t\t\t\t\t\t\t[equationNumber]=\"run.equationNumber\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t} @else if (\n\t\t\t\t\t\t\t\t\t\t\trun.text ===\n\t\t\t\t\t\t\t\t\t\t\t'\n'\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t\t\t} @else if (run.reflection; as refl) {\n\t\t\t\t\t\t\t\t\t\t\t<!-- `a:reflection`: wrapped HERE, around the whole base\n\t\t\t\t\t\t\t\t\t\t run (`runBase`), rather than inside its href/ruby/plain\n\t\t\t\t\t\t\t\t\t\t branches - a `<ruby>` run's own `display: ruby` (which\n\t\t\t\t\t\t\t\t\t\t positions the annotation above its base text) would\n\t\t\t\t\t\t\t\t\t\t break if forced to `display: inline-block` to host the\n\t\t\t\t\t\t\t\t\t\t mirror. Cross-browser, unlike the `-webkit-box-reflect`\n\t\t\t\t\t\t\t\t\t\t this replaced (Firefox never implemented it). -->\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"position: relative; display: inline-block\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pptx-ng-text-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t><span [ngStyle]=\"run.style\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t><ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*ngTemplateOutlet=\"runContent; context: { run: run }\" /></span\n\t\t\t\t\t\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (para.isEmpty) {\n\t\t\t\t\t\t\t\t\t<!-- An authored blank line has no runs, so without this the\n\t\t\t\t\t\t\t\t <p> collapses to zero height and the gap a deck puts\n\t\t\t\t\t\t\t\t between a heading and its bullet list disappears. -->\n\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t}\n\t\t</div>\n\t}\n\t@default {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-unsupported\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-placeholder\">{{ placeholderLabel() }}</div>\n\t\t</div>\n\t}\n}\n\n<!-- Soft-edge feather <filter> def, referenced via filter: url(#soft-edge-<id>). -->\n@if (softEdgeFilter(); as sef) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter\n\t\t\t\t[attr.id]=\"sef.id\"\n\t\t\t\tx=\"-20%\"\n\t\t\t\ty=\"-20%\"\n\t\t\t\twidth=\"140%\"\n\t\t\t\theight=\"140%\"\n\t\t\t\tcolor-interpolation-filters=\"sRGB\"\n\t\t\t>\n\t\t\t\t<feGaussianBlur in=\"SourceAlpha\" [attr.stdDeviation]=\"sef.radius\" result=\"softEdgeAlpha\" />\n\t\t\t\t<feComposite in=\"SourceGraphic\" in2=\"softEdgeAlpha\" operator=\"in\" />\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!-- Duotone image-effect <filter> def, referenced via filter: url(#id). -->\n@if (duotoneFilter(); as df) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter [attr.id]=\"df.id\" color-interpolation-filters=\"sRGB\">\n\t\t\t\t<feColorMatrix type=\"matrix\" [attr.values]=\"df.primitives[0].values\" />\n\t\t\t\t<feComponentTransfer>\n\t\t\t\t\t<feFuncR\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[0].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[0].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncG\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[1].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[1].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncB\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[2].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[2].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t</feComponentTransfer>\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!--\n\tOne run's base element (hyperlink / ruby / plain span), reused via\n\t`ngTemplateOutlet` both directly and inside the `a:reflection` wrapper above,\n\tso the reflection case does not duplicate this three-way branch.\n-->\n<ng-template #runBase let-run=\"run\">\n\t@if (run.href) {\n\t\t<a\n\t\t\tclass=\"pptx-ng-link\"\n\t\t\t[href]=\"run.href\"\n\t\t\t[attr.target]=\"run.target ?? '_blank'\"\n\t\t\t[attr.rel]=\"run.rel ?? 'noopener noreferrer'\"\n\t\t\t[attr.title]=\"run.tooltip ?? null\"\n\t\t\t[ngStyle]=\"run.style\"\n\t\t\t(click)=\"onHyperlinkClick($event, run.href)\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></a>\n\t} @else if (run.rubyText) {\n\t\t<!-- `a:ruby`: the phonetic guide sits above its base\n\t\t text; the <rp> parentheses are the fallback for a\n\t\t browser without ruby support. -->\n\t\t<ruby [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\" /><rp>(</rp\n\t\t\t><rt [ngStyle]=\"run.rubyStyle\">{{ run.rubyText }}</rt\n\t\t\t><rp>)</rp></ruby\n\t\t>\n\t} @else {\n\t\t<span [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></span>\n\t}\n</ng-template>\n\n<!--\n\tA run's text content, honouring shared's per-script font split\n\t(`run.scriptRuns`) and measured tab-stop layout (`run.tabLines`) when\n\teither is present. Both descriptors come from `pptx-viewer-shared`'s\n\t`buildParagraphs` (the per-script split was React-only before this\n\ttemplate existed: CJK, Arabic, Hebrew and Thai text rendered in the wrong\n\ttypeface here; the tab layout was likewise React-only, so a TOC-style row\n\tlost its leader dots and right-aligned page number). Reused via\n\t`ngTemplateOutlet` for the run's span / anchor / ruby base text, so all\n\tthree carry the same content logic.\n-->\n<ng-template #runContent let-run=\"run\">\n\t@if (run.tabLines) {\n\t\t@for (line of run.tabLines; track $index) {\n\t\t\t<span style=\"display: inline-block; white-space: nowrap\">\n\t\t\t\t@for (piece of line.pieces; track $index) {\n\t\t\t\t\t@if (piece.leaderStyle) {\n\t\t\t\t\t\t<span aria-hidden=\"true\" [ngStyle]=\"piece.leaderStyle\">{{ piece.leaderText }}</span>\n\t\t\t\t\t}\n\t\t\t\t\t<!-- `u=\"words\"`: one sibling span per word/gap in place of the piece span. -->\n\t\t\t\t\t@if (piece.words) {\n\t\t\t\t\t\t@for (word of piece.words; track $index) {\n\t\t\t\t\t\t\t<span [ngStyle]=\"word.style\">{{ word.text }}</span>\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</span>\n\t\t\t@if (!$last) {\n\t\t\t\t<br />\n\t\t\t}\n\t\t}\n\t} @else if (run.scriptRuns || run.underlineWordPieces) {\n\t\t<!--\n\t\t\tA bare interpolation as the sole content of an `@if`/`@else` block\n\t\t\tleaks a real leading + trailing whitespace text node: Angular does\n\t\t\tnot collapse that whitespace the way it collapses whitespace between\n\t\t\telement TAGS. Worse, oxfmt's Angular-template printer always breaks a\n\t\t\tblock's content onto its own indented line, even when the block was\n\t\t\twritten as a single line with the braces touching, so writing the\n\t\t\t`{{ x }}` compact ourselves does not survive the next `bun run fmt` /\n\t\t\tpre-commit `lint-staged` pass: it silently re-introduces the leak\n\t\t\t(this happened twice, see `20d4d177`, `18eebb6f`). `<ng-container>`\n\t\t\tdoes not render any DOM node of its own, so wrapping the\n\t\t\tinterpolation in one keeps the no-wrapper-element behaviour of\n\t\t\tReact's `<>{piece.text}</>` fragment while making the interpolation\n\t\t\ttag-adjacent, which both Angular AND oxfmt already treat as safely\n\t\t\tcollapsible (see the many `<span>{{ x }}</span>` one-liners in this\n\t\t\tfile). That was invisible while a paragraph was one run per script\n\t\t\t(two stray spaces at the run's own edges, trimmed visually by the\n\t\t\tbrowser but still present in `textContent`), but shared's per-word /\n\t\t\tper-gap metric split (`text-run-spacing.ts`, issue #149) re-emits\n\t\t\tevery WORD and inter-word GAP as its own sibling run, so the same\n\t\t\tone-space leak lands between every word: \"will choose\" rendered as\n\t\t\t\"will choose\" (five spaces: the word's own trailing leak, the\n\t\t\tgap run's real space plus its OWN two leaks, the next word's leading\n\t\t\tleak). The same leak also showed up one paragraph at a time:\n\t\t\t\"Project\" / \"Atlas\" as two separate paragraphs read back as\n\t\t\t\"ProjectAtlas\" instead of React's \"Project Atlas\", because the\n\t\t\tplain-run `@else` below had the same bug.\n\t\t-->\n\t\t@for (piece of run.scriptRuns ?? run.underlineWordPieces; track $index) {\n\t\t\t@if (piece.style) {\n\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t} @else {\n\t\t\t\t<ng-container>{{ piece.text }}</ng-container>\n\t\t\t}\n\t\t}\n\t} @else {\n\t\t<ng-container>{{ run.text }}</ng-container>\n\t}\n</ng-template>\n", dependencies: [{ kind: "component", type: ElementRendererComponent, selector: "pptx-element-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "obstacles", "canvasWidth", "canvasHeight", "interactive", "marked", "exposeElementId", "presenting", "editable", "fieldContext", "slideElements", "editTemplateMode", "parentGroupFill", "editingElementId"], outputs: ["cellCommit", "tableChange"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: ConnectorRendererComponent, selector: "pptx-connector-renderer", inputs: ["element", "zIndex", "obstacles", "canvasWidth", "canvasHeight", "interactive", "marked", "exposeElementId", "animationState", "textStyleOverrideCss"] }, { kind: "component", type: DynamicStyleComponent, selector: "pptx-dynamic-style", inputs: ["css"] }, { kind: "component", type: TableRendererComponent, selector: "pptx-table-renderer", inputs: ["element", "editable"], outputs: ["cellCommit", "tableChange"] }, { kind: "component", type: ChartElementViewComponent, selector: "pptx-chart-element-view", inputs: ["element", "editable", "animationState"] }, { kind: "component", type: SmartArtRendererComponent, selector: "pptx-smart-art-renderer", inputs: ["element", "editable", "animationState"] }, { kind: "component", type: SmartArt3DRendererComponent, selector: "pptx-smart-art-3d-renderer", inputs: ["element", "zIndex", "canEdit", "markElement"] }, { kind: "component", type: InkRendererComponent, selector: "pptx-ink-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "replay", "markElement", "exposeElementId"] }, { kind: "component", type: ContentPartRendererComponent, selector: "pptx-content-part-renderer", inputs: ["element", "zIndex", "replay", "markElement", "exposeElementId"] }, { kind: "component", type: MediaRendererComponent, selector: "pptx-media-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "interactive", "marked", "exposeElementId", "presenting", "placeholderLabel"] }, { kind: "component", type: OleRendererComponent, selector: "pptx-ole-renderer", inputs: ["element"] }, { kind: "component", type: Model3DRendererComponent, selector: "pptx-model3d-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "interactive", "markElement", "exposeElementId"] }, { kind: "component", type: ZoomRendererComponent, selector: "pptx-zoom-renderer", inputs: ["element", "zIndex", "mediaDataUrls", "markElement"] }, { kind: "component", type: EquationRendererComponent, selector: "pptx-equation-renderer", inputs: ["equationXml", "equationNumber"] }, { kind: "component", type: ImageRendererComponent, selector: "pptx-image-renderer", inputs: ["element", "mediaDataUrls", "zIndex", "interactive", "marked", "exposeElementId"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
108810
110265
  }
108811
110266
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: ElementRendererComponent, decorators: [{
108812
110267
  type: Component,
@@ -108814,6 +110269,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
108814
110269
  NgStyle,
108815
110270
  NgTemplateOutlet,
108816
110271
  ConnectorRendererComponent,
110272
+ DynamicStyleComponent,
108817
110273
  TableRendererComponent,
108818
110274
  ChartElementViewComponent,
108819
110275
  SmartArtRendererComponent,
@@ -108826,7 +110282,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
108826
110282
  ZoomRendererComponent,
108827
110283
  EquationRendererComponent,
108828
110284
  ImageRendererComponent,
108829
- ], template: "@switch (true) {\n\t@case (isHidden()) {\n\t\t<!--\n\t\t\tHidden via the Selection Pane: draw nothing, exactly as PowerPoint\n\t\t\tdoes. This is the FIRST case on purpose - @switch takes the first\n\t\t\tmatch, so one empty branch suppresses every element type at once\n\t\t\twithout wrapping (and re-indenting) the whole template. The host\n\t\t\tcarries \\`display: contents\\`, so an empty component collapses.\n\t\t\tRendering nothing (rather than an invisible box) is what keeps the\n\t\t\telement out of hit-testing, the tab order and the export raster; it\n\t\t\tstays listed in and selectable from the Selection Pane, which reads\n\t\t\tthe slide model rather than the DOM.\n\t\t-->\n\t}\n\t@case (element().type === 'connector') {\n\t\t<pptx-connector-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[obstacles]=\"obstacles()\"\n\t\t\t[canvasWidth]=\"canvasWidth()\"\n\t\t\t[canvasHeight]=\"canvasHeight()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[animationState]=\"animationState()\"\n\t\t/>\n\t}\n\t@case (element().type === 'ink') {\n\t\t<!--\n\t\t\tThis renderer (and zoom / model3d / 3D SmartArt below) positions its\n\t\t\town root box, so it takes the neutral element marker\n\t\t\t(data-pptx-element) as an input instead of being wrapped in a marked\n\t\t\tbox the way chart / table / OLE are: an outer positioned box would\n\t\t\toffset it twice.\n\t\t-->\n\t\t<pptx-ink-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'contentPart') {\n\t\t<!--\n\t\t\tReal PowerPoint ink. Same positioning contract as pptx-ink-renderer\n\t\t\tabove: the renderer's own root is absolutely positioned, so it takes\n\t\t\tthe neutral element marker as an input rather than being wrapped.\n\t\t-->\n\t\t<pptx-content-part-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'zoom') {\n\t\t<pptx-zoom-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'model3d') {\n\t\t<pptx-model3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt' && smartArt3D()) {\n\t\t<pptx-smart-art-3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[canEdit]=\"interactive() && editable()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-smartart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-smart-art-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'ole') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-ole\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-ole-renderer [element]=\"element()\" />\n\t\t</div>\n\t}\n\t@case (element().type === 'chart') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-chart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-chart-element-view\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'table') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-table\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-table-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t(cellCommit)=\"cellCommit.emit({ id: element().id, commit: $event })\"\n\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'group') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-group\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t@for (child of children(); track child.id) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"child\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"$index\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[marked]=\"marked()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"slideElements()\"\n\t\t\t\t\t[parentGroupFill]=\"childParentGroupFill()\"\n\t\t\t\t\t[editingElementId]=\"editingElementId()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t</div>\n\t}\n\t@case (isImageLike()) {\n\t\t<pptx-image-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'media') {\n\t\t<pptx-media-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[presenting]=\"presenting()\"\n\t\t\t[placeholderLabel]=\"placeholderLabel()\"\n\t\t/>\n\t}\n\t@case (isShapeLike()) {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-shape\"\n\t\t\t[ngStyle]=\"shapeContainerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- Per-sub-path fill overlay: a multi-sub-path preset (`smileyFace`'s\n\t\t\t open eyes, `actionButtonBlank`'s darkened bevel well) or custom\n\t\t\t geometry whose sub-paths cannot share one CSS background-color. -->\n\t\t\t@if (subpathFill(); as sf) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-subpath-fill\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"subpathFillViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; width: 100%; height: 100%\"\n\t\t\t\t>\n\t\t\t\t\t@for (paint of sf.paints; track $index) {\n\t\t\t\t\t\t<path [attr.d]=\"paint.d\" [attr.fill]=\"paint.fill\" stroke=\"none\" />\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t@if (fillOverlay(); as ov) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-fill-overlay\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none\"\n\t\t\t\t\t[style.background]=\"ov.color\"\n\t\t\t\t\t[style.mix-blend-mode]=\"ov.blendMode\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t<!-- Mirrored reflection sibling (`a:reflection`): cross-browser, unlike\n\t\t\t the `-webkit-box-reflect` this replaced (Firefox never implemented\n\t\t\t that property, so reflections were invisible there entirely). -->\n\t\t\t@if (reflection(); as refl) {\n\t\t\t\t<div class=\"pptx-ng-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl.wrapperStyle\">\n\t\t\t\t\t@if (refl.imgSrc) {\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t[src]=\"refl.imgSrc\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tdraggable=\"false\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[ngStyle]=\"refl.imgFitStyle\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (refl.fill) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[style.background-color]=\"refl.fill.backgroundColor\"\n\t\t\t\t\t\t\t[style.background-image]=\"refl.fill.backgroundImage\"\n\t\t\t\t\t\t\t[style.background-size]=\"refl.fill.backgroundSize\"\n\t\t\t\t\t\t\t[style.background-position]=\"refl.fill.backgroundPosition\"\n\t\t\t\t\t\t\t[style.background-repeat]=\"refl.fill.backgroundRepeat\"\n\t\t\t\t\t\t></div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t\t<!-- Hollow frame hit target: an unfilled, textless shape is hit-tested\n\t\t\t on its outline only, so its interior lets clicks through. -->\n\t\t\t@if (hollowHit(); as hit) {\n\t\t\t\t<svg\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\t[attr.d]=\"hit.d\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"transparent\"\n\t\t\t\t\t\t[attr.stroke-width]=\"hit.strokeWidth\"\n\t\t\t\t\t\tstyle=\"pointer-events: stroke\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- Stroked outline: a CSS border takes one flat colour, and cannot\n\t\t\t outline an open preset (`line`, `arc`) at all. -->\n\t\t\t@if (gradientOutline(); as go) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-gradient-outline\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t@if (go.paint; as paint) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (paint.kind === 'pattern') {\n\t\t\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'rectPath') {\n\t\t\t\t\t\t\t\t<pattern [attr.id]=\"paint.id\" patternUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t\t\t\t\twidth=\"1\"\n\t\t\t\t\t\t\t\t\t\theight=\"1\"\n\t\t\t\t\t\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"paint.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"paint.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"paint.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"paint.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"paint.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"paint.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"paint.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@for (strand of go.strands; track $index) {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"go.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"go.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"strand.strokeWidth\"\n\t\t\t\t\t\t\t[attr.stroke-dasharray]=\"go.dashArray\"\n\t\t\t\t\t\t\t[attr.stroke-linecap]=\"go.lineCap\"\n\t\t\t\t\t\t\t[attr.stroke-linejoin]=\"go.lineJoin\"\n\t\t\t\t\t\t\t[style.transform]=\"\n\t\t\t\t\t\t\t\tstrand.offset !== 0 ? 'translate(0, ' + strand.offset + 'px)' : null\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- While this element is open in the inline text editor, its live text\n\t\t\t is drawn by that overlay instead (see `isBeingInlineEdited`);\n\t\t\t rendering it here too produced a duplicate, offset \"text shadow\"\n\t\t\t (issue #182). -->\n\t\t\t@if (!isBeingInlineEdited()) {\n\t\t\t\t@if (pathWarp(); as warp) {\n\t\t\t\t\t<svg\n\t\t\t\t\t\t[attr.width]=\"warp.width\"\n\t\t\t\t\t\t[attr.height]=\"warp.height\"\n\t\t\t\t\t\t[attr.viewBox]=\"'0 0 ' + warp.width + ' ' + warp.height\"\n\t\t\t\t\t\tstyle=\"position: absolute; inset: 0; overflow: visible; pointer-events: none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t\t<path [attr.id]=\"line.pathId\" [attr.d]=\"line.d\" fill=\"none\" />\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t[attr.font-size]=\"warp.baseFontSize\"\n\t\t\t\t\t\t\t\t[attr.font-family]=\"warp.baseFontFamily\"\n\t\t\t\t\t\t\t\t[attr.fill]=\"warp.baseColor\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<textPath\n\t\t\t\t\t\t\t\t\t[attr.href]=\"'#' + line.pathId\"\n\t\t\t\t\t\t\t\t\t[attr.startOffset]=\"warp.startOffset\"\n\t\t\t\t\t\t\t\t\t[attr.text-anchor]=\"warp.textAnchor\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (seg of line.segments; track $index) {\n\t\t\t\t\t\t\t\t\t\t<tspan\n\t\t\t\t\t\t\t\t\t\t\t[attr.fill]=\"seg.style?.color ?? warp.baseColor\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-weight]=\"seg.style?.bold ? 700 : 400\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-style]=\"seg.style?.italic ? 'italic' : 'normal'\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{{ seg.text }}\n\t\t\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</textPath>\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t}\n\t\t\t\t\t</svg>\n\t\t\t\t} @else if (placeholderPrompt(); as prompt) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"prompt.style\">{{ prompt.text }}</div>\n\t\t\t\t} @else if (hasText()) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"warpedTextStyle()\">\n\t\t\t\t\t\t@for (para of paragraphs(); track $index) {\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-para\"\n\t\t\t\t\t\t\t\t[ngStyle]=\"para.paragraphStyle ?? null\"\n\t\t\t\t\t\t\t\t[style.padding-left.px]=\"para.indentPx\"\n\t\t\t\t\t\t\t\t[style.text-indent.px]=\"para.textIndentPx ?? null\"\n\t\t\t\t\t\t\t\t[style.line-height]=\"para.lineHeight ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-top.px]=\"para.spaceBeforePx ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-bottom.px]=\"para.spaceAfterPx ?? null\"\n\t\t\t\t\t\t\t\t[style.font-size.px]=\"para.strutFontSizePx ?? null\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (para.bulletPicture?.src) {\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet-image\"\n\t\t\t\t\t\t\t\t\t\t[src]=\"para.bulletPicture.src\"\n\t\t\t\t\t\t\t\t\t\t[alt]=\"para.bulletPicture.accessibleLabel\"\n\t\t\t\t\t\t\t\t\t\t[style.width.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\t[style.height.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"\n\t\t\t\t\t\t\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\t\t\t\t\t\t\tvertical-align: middle;\n\t\t\t\t\t\t\t\t\t\t\tmargin-inline-end: 4px;\n\t\t\t\t\t\t\t\t\t\t\tobject-fit: contain;\n\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t} @else if (para.bulletMarker) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet\"\n\t\t\t\t\t\t\t\t\t\t[ngStyle]=\"para.bulletStyle\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"para.bulletPicture?.accessibleLabel ?? null\"\n\t\t\t\t\t\t\t\t\t\t>{{ para.bulletMarker }}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (textBuildSpecs()[$index]; as spec) {\n\t\t\t\t\t\t\t\t\t<!-- Staged text build: render the split pieces so each one\n\t\t\t\t\t\t\t\t carries its own sub-animation. -->\n\t\t\t\t\t\t\t\t\t@if (spec.granularity === 'paragraph') {\n\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"spec.animId\" [ngStyle]=\"buildSpanStyle(spec)\">{{\n\t\t\t\t\t\t\t\t\t\t\tparagraphText(para)\n\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t@for (span of spec.spans ?? []; track $index) {\n\t\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"span.animId\" [ngStyle]=\"buildSpanStyle(span)\">{{\n\t\t\t\t\t\t\t\t\t\t\t\tspan.text\n\t\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t@for (run of para.runs; track $index) {\n\t\t\t\t\t\t\t\t\t\t@if (run.equationXml) {\n\t\t\t\t\t\t\t\t\t\t\t<pptx-equation-renderer\n\t\t\t\t\t\t\t\t\t\t\t\t[equationXml]=\"run.equationXml\"\n\t\t\t\t\t\t\t\t\t\t\t\t[equationNumber]=\"run.equationNumber\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t} @else if (\n\t\t\t\t\t\t\t\t\t\t\trun.text ===\n\t\t\t\t\t\t\t\t\t\t\t'\n'\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t\t\t} @else if (run.reflection; as refl) {\n\t\t\t\t\t\t\t\t\t\t\t<!-- `a:reflection`: wrapped HERE, around the whole base\n\t\t\t\t\t\t\t\t\t\t run (`runBase`), rather than inside its href/ruby/plain\n\t\t\t\t\t\t\t\t\t\t branches - a `<ruby>` run's own `display: ruby` (which\n\t\t\t\t\t\t\t\t\t\t positions the annotation above its base text) would\n\t\t\t\t\t\t\t\t\t\t break if forced to `display: inline-block` to host the\n\t\t\t\t\t\t\t\t\t\t mirror. Cross-browser, unlike the `-webkit-box-reflect`\n\t\t\t\t\t\t\t\t\t\t this replaced (Firefox never implemented it). -->\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"position: relative; display: inline-block\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pptx-ng-text-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t><span [ngStyle]=\"run.style\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t><ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*ngTemplateOutlet=\"runContent; context: { run: run }\" /></span\n\t\t\t\t\t\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (para.isEmpty) {\n\t\t\t\t\t\t\t\t\t<!-- An authored blank line has no runs, so without this the\n\t\t\t\t\t\t\t\t <p> collapses to zero height and the gap a deck puts\n\t\t\t\t\t\t\t\t between a heading and its bullet list disappears. -->\n\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t}\n\t\t</div>\n\t}\n\t@default {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-unsupported\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-placeholder\">{{ placeholderLabel() }}</div>\n\t\t</div>\n\t}\n}\n\n<!-- Soft-edge feather <filter> def, referenced via filter: url(#soft-edge-<id>). -->\n@if (softEdgeFilter(); as sef) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter\n\t\t\t\t[attr.id]=\"sef.id\"\n\t\t\t\tx=\"-20%\"\n\t\t\t\ty=\"-20%\"\n\t\t\t\twidth=\"140%\"\n\t\t\t\theight=\"140%\"\n\t\t\t\tcolor-interpolation-filters=\"sRGB\"\n\t\t\t>\n\t\t\t\t<feGaussianBlur in=\"SourceAlpha\" [attr.stdDeviation]=\"sef.radius\" result=\"softEdgeAlpha\" />\n\t\t\t\t<feComposite in=\"SourceGraphic\" in2=\"softEdgeAlpha\" operator=\"in\" />\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!-- Duotone image-effect <filter> def, referenced via filter: url(#id). -->\n@if (duotoneFilter(); as df) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter [attr.id]=\"df.id\" color-interpolation-filters=\"sRGB\">\n\t\t\t\t<feColorMatrix type=\"matrix\" [attr.values]=\"df.primitives[0].values\" />\n\t\t\t\t<feComponentTransfer>\n\t\t\t\t\t<feFuncR\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[0].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[0].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncG\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[1].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[1].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncB\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[2].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[2].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t</feComponentTransfer>\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!--\n\tOne run's base element (hyperlink / ruby / plain span), reused via\n\t`ngTemplateOutlet` both directly and inside the `a:reflection` wrapper above,\n\tso the reflection case does not duplicate this three-way branch.\n-->\n<ng-template #runBase let-run=\"run\">\n\t@if (run.href) {\n\t\t<a\n\t\t\tclass=\"pptx-ng-link\"\n\t\t\t[href]=\"run.href\"\n\t\t\t[attr.target]=\"run.target ?? '_blank'\"\n\t\t\t[attr.rel]=\"run.rel ?? 'noopener noreferrer'\"\n\t\t\t[attr.title]=\"run.tooltip ?? null\"\n\t\t\t[ngStyle]=\"run.style\"\n\t\t\t(click)=\"onHyperlinkClick($event, run.href)\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></a>\n\t} @else if (run.rubyText) {\n\t\t<!-- `a:ruby`: the phonetic guide sits above its base\n\t\t text; the <rp> parentheses are the fallback for a\n\t\t browser without ruby support. -->\n\t\t<ruby [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\" /><rp>(</rp\n\t\t\t><rt [ngStyle]=\"run.rubyStyle\">{{ run.rubyText }}</rt\n\t\t\t><rp>)</rp></ruby\n\t\t>\n\t} @else {\n\t\t<span [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></span>\n\t}\n</ng-template>\n\n<!--\n\tA run's text content, honouring shared's per-script font split\n\t(`run.scriptRuns`) and measured tab-stop layout (`run.tabLines`) when\n\teither is present. Both descriptors come from `pptx-viewer-shared`'s\n\t`buildParagraphs` (the per-script split was React-only before this\n\ttemplate existed: CJK, Arabic, Hebrew and Thai text rendered in the wrong\n\ttypeface here; the tab layout was likewise React-only, so a TOC-style row\n\tlost its leader dots and right-aligned page number). Reused via\n\t`ngTemplateOutlet` for the run's span / anchor / ruby base text, so all\n\tthree carry the same content logic.\n-->\n<ng-template #runContent let-run=\"run\">\n\t@if (run.tabLines) {\n\t\t@for (line of run.tabLines; track $index) {\n\t\t\t<span style=\"display: inline-block; white-space: nowrap\">\n\t\t\t\t@for (piece of line.pieces; track $index) {\n\t\t\t\t\t@if (piece.leaderStyle) {\n\t\t\t\t\t\t<span aria-hidden=\"true\" [ngStyle]=\"piece.leaderStyle\">{{ piece.leaderText }}</span>\n\t\t\t\t\t}\n\t\t\t\t\t<!-- `u=\"words\"`: one sibling span per word/gap in place of the piece span. -->\n\t\t\t\t\t@if (piece.words) {\n\t\t\t\t\t\t@for (word of piece.words; track $index) {\n\t\t\t\t\t\t\t<span [ngStyle]=\"word.style\">{{ word.text }}</span>\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</span>\n\t\t\t@if (!$last) {\n\t\t\t\t<br />\n\t\t\t}\n\t\t}\n\t} @else if (run.scriptRuns || run.underlineWordPieces) {\n\t\t<!--\n\t\t\tA bare interpolation as the sole content of an `@if`/`@else` block\n\t\t\tleaks a real leading + trailing whitespace text node: Angular does\n\t\t\tnot collapse that whitespace the way it collapses whitespace between\n\t\t\telement TAGS. Worse, oxfmt's Angular-template printer always breaks a\n\t\t\tblock's content onto its own indented line, even when the block was\n\t\t\twritten as a single line with the braces touching, so writing the\n\t\t\t`{{ x }}` compact ourselves does not survive the next `bun run fmt` /\n\t\t\tpre-commit `lint-staged` pass: it silently re-introduces the leak\n\t\t\t(this happened twice, see `20d4d177`, `18eebb6f`). `<ng-container>`\n\t\t\tdoes not render any DOM node of its own, so wrapping the\n\t\t\tinterpolation in one keeps the no-wrapper-element behaviour of\n\t\t\tReact's `<>{piece.text}</>` fragment while making the interpolation\n\t\t\ttag-adjacent, which both Angular AND oxfmt already treat as safely\n\t\t\tcollapsible (see the many `<span>{{ x }}</span>` one-liners in this\n\t\t\tfile). That was invisible while a paragraph was one run per script\n\t\t\t(two stray spaces at the run's own edges, trimmed visually by the\n\t\t\tbrowser but still present in `textContent`), but shared's per-word /\n\t\t\tper-gap metric split (`text-run-spacing.ts`, issue #149) re-emits\n\t\t\tevery WORD and inter-word GAP as its own sibling run, so the same\n\t\t\tone-space leak lands between every word: \"will choose\" rendered as\n\t\t\t\"will choose\" (five spaces: the word's own trailing leak, the\n\t\t\tgap run's real space plus its OWN two leaks, the next word's leading\n\t\t\tleak). The same leak also showed up one paragraph at a time:\n\t\t\t\"Project\" / \"Atlas\" as two separate paragraphs read back as\n\t\t\t\"ProjectAtlas\" instead of React's \"Project Atlas\", because the\n\t\t\tplain-run `@else` below had the same bug.\n\t\t-->\n\t\t@for (piece of run.scriptRuns ?? run.underlineWordPieces; track $index) {\n\t\t\t@if (piece.style) {\n\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t} @else {\n\t\t\t\t<ng-container>{{ piece.text }}</ng-container>\n\t\t\t}\n\t\t}\n\t} @else {\n\t\t<ng-container>{{ run.text }}</ng-container>\n\t}\n</ng-template>\n" }]
110285
+ ], template: "@switch (true) {\n\t@case (isHidden()) {\n\t\t<!--\n\t\t\tHidden via the Selection Pane: draw nothing, exactly as PowerPoint\n\t\t\tdoes. This is the FIRST case on purpose - @switch takes the first\n\t\t\tmatch, so one empty branch suppresses every element type at once\n\t\t\twithout wrapping (and re-indenting) the whole template. The host\n\t\t\tcarries \\`display: contents\\`, so an empty component collapses.\n\t\t\tRendering nothing (rather than an invisible box) is what keeps the\n\t\t\telement out of hit-testing, the tab order and the export raster; it\n\t\t\tstays listed in and selectable from the Selection Pane, which reads\n\t\t\tthe slide model rather than the DOM.\n\t\t-->\n\t}\n\t@case (element().type === 'connector') {\n\t\t<pptx-connector-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[obstacles]=\"obstacles()\"\n\t\t\t[canvasWidth]=\"canvasWidth()\"\n\t\t\t[canvasHeight]=\"canvasHeight()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[animationState]=\"animationState()\"\n\t\t\t[textStyleOverrideCss]=\"textStyleOverrideCss()\"\n\t\t/>\n\t}\n\t@case (element().type === 'ink') {\n\t\t<!--\n\t\t\tThis renderer (and zoom / model3d / 3D SmartArt below) positions its\n\t\t\town root box, so it takes the neutral element marker\n\t\t\t(data-pptx-element) as an input instead of being wrapped in a marked\n\t\t\tbox the way chart / table / OLE are: an outer positioned box would\n\t\t\toffset it twice.\n\t\t-->\n\t\t<pptx-ink-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'contentPart') {\n\t\t<!--\n\t\t\tReal PowerPoint ink. Same positioning contract as pptx-ink-renderer\n\t\t\tabove: the renderer's own root is absolutely positioned, so it takes\n\t\t\tthe neutral element marker as an input rather than being wrapped.\n\t\t-->\n\t\t<pptx-content-part-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[replay]=\"presenting()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'zoom') {\n\t\t<pptx-zoom-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'model3d') {\n\t\t<pptx-model3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt' && smartArt3D()) {\n\t\t<pptx-smart-art-3d-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[canEdit]=\"interactive() && editable()\"\n\t\t\t[markElement]=\"elementMarked()\"\n\t\t/>\n\t}\n\t@case (element().type === 'smartArt') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-smartart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a SmartArt node caption's own\n\t\t\t inline bold/italic/underline/size, which plain CSS inheritance\n\t\t\t cannot reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-smart-art-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'ole') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-ole\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<pptx-ole-renderer [element]=\"element()\" />\n\t\t</div>\n\t}\n\t@case (element().type === 'chart') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-chart\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a chart title/label/legend's\n\t\t\t own SVG text attributes, which plain CSS inheritance cannot\n\t\t\t reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-chart-element-view\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t[animationState]=\"animationState()\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'table') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-table\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides a table cell's own inline\n\t\t\t bold/italic/underline/size, which plain CSS inheritance cannot\n\t\t\t reach. See `animation-text-style-css.ts`. -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<pptx-table-renderer\n\t\t\t\t[element]=\"element()\"\n\t\t\t\t[editable]=\"interactive() && editable()\"\n\t\t\t\t(cellCommit)=\"cellCommit.emit({ id: element().id, commit: $event })\"\n\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t/>\n\t\t</div>\n\t}\n\t@case (element().type === 'group') {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-group\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t@for (child of children(); track child.id) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"child\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"$index\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[marked]=\"marked()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"slideElements()\"\n\t\t\t\t\t[parentGroupFill]=\"childParentGroupFill()\"\n\t\t\t\t\t[editingElementId]=\"editingElementId()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t</div>\n\t}\n\t@case (isImageLike()) {\n\t\t<pptx-image-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t/>\n\t}\n\t@case (element().type === 'media') {\n\t\t<pptx-media-renderer\n\t\t\t[element]=\"element()\"\n\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t[zIndex]=\"zIndex()\"\n\t\t\t[interactive]=\"interactive()\"\n\t\t\t[marked]=\"elementMarked()\"\n\t\t\t[exposeElementId]=\"exposeElementId()\"\n\t\t\t[presenting]=\"presenting()\"\n\t\t\t[placeholderLabel]=\"placeholderLabel()\"\n\t\t/>\n\t}\n\t@case (isShapeLike()) {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-shape\"\n\t\t\t[ngStyle]=\"shapeContainerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<!-- A font-style emphasis effect (Bold Flash, Bold Reveal, Underline,\n\t\t\t Change Font Style/Size) overrides the runs' own inline\n\t\t\t bold/italic/underline/size, which plain CSS inheritance cannot\n\t\t\t reach (the runs declare those unconditionally). -->\n\t\t\t<pptx-dynamic-style [css]=\"textStyleOverrideCss()\" />\n\t\t\t<!-- Per-sub-path fill overlay: a multi-sub-path preset (`smileyFace`'s\n\t\t\t open eyes, `actionButtonBlank`'s darkened bevel well) or custom\n\t\t\t geometry whose sub-paths cannot share one CSS background-color. -->\n\t\t\t@if (subpathFill(); as sf) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-subpath-fill\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"subpathFillViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; width: 100%; height: 100%\"\n\t\t\t\t>\n\t\t\t\t\t@for (paint of sf.paints; track $index) {\n\t\t\t\t\t\t<path [attr.d]=\"paint.d\" [attr.fill]=\"paint.fill\" stroke=\"none\" />\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t@if (fillOverlay(); as ov) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-fill-overlay\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none\"\n\t\t\t\t\t[style.background]=\"ov.color\"\n\t\t\t\t\t[style.mix-blend-mode]=\"ov.blendMode\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t<!-- Mirrored reflection sibling (`a:reflection`): cross-browser, unlike\n\t\t\t the `-webkit-box-reflect` this replaced (Firefox never implemented\n\t\t\t that property, so reflections were invisible there entirely). -->\n\t\t\t@if (reflection(); as refl) {\n\t\t\t\t<div class=\"pptx-ng-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl.wrapperStyle\">\n\t\t\t\t\t@if (refl.imgSrc) {\n\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t[src]=\"refl.imgSrc\"\n\t\t\t\t\t\t\talt=\"\"\n\t\t\t\t\t\t\tdraggable=\"false\"\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[ngStyle]=\"refl.imgFitStyle\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (refl.fill) {\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tstyle=\"width: 100%; height: 100%\"\n\t\t\t\t\t\t\t[style.background-color]=\"refl.fill.backgroundColor\"\n\t\t\t\t\t\t\t[style.background-image]=\"refl.fill.backgroundImage\"\n\t\t\t\t\t\t\t[style.background-size]=\"refl.fill.backgroundSize\"\n\t\t\t\t\t\t\t[style.background-position]=\"refl.fill.backgroundPosition\"\n\t\t\t\t\t\t\t[style.background-repeat]=\"refl.fill.backgroundRepeat\"\n\t\t\t\t\t\t></div>\n\t\t\t\t\t}\n\t\t\t\t</div>\n\t\t\t}\n\t\t\t<!-- Hollow frame hit target: an unfilled, textless shape is hit-tested\n\t\t\t on its outline only, so its interior lets clicks through. -->\n\t\t\t@if (hollowHit(); as hit) {\n\t\t\t\t<svg\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t<path\n\t\t\t\t\t\t[attr.d]=\"hit.d\"\n\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\tstroke=\"transparent\"\n\t\t\t\t\t\t[attr.stroke-width]=\"hit.strokeWidth\"\n\t\t\t\t\t\tstyle=\"pointer-events: stroke\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- Stroked outline: a CSS border takes one flat colour, and cannot\n\t\t\t outline an open preset (`line`, `arc`) at all. -->\n\t\t\t@if (gradientOutline(); as go) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-gradient-outline\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.viewBox]=\"outlineViewBox()\"\n\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\tstyle=\"\n\t\t\t\t\t\tposition: absolute;\n\t\t\t\t\t\tinset: 0;\n\t\t\t\t\t\twidth: 100%;\n\t\t\t\t\t\theight: 100%;\n\t\t\t\t\t\toverflow: visible;\n\t\t\t\t\t\tpointer-events: none;\n\t\t\t\t\t\"\n\t\t\t\t>\n\t\t\t\t\t@if (go.paint; as paint) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (paint.kind === 'pattern') {\n\t\t\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\t[attr.width]=\"paint.width\"\n\t\t\t\t\t\t\t\t\t\t[attr.height]=\"paint.height\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'rectPath') {\n\t\t\t\t\t\t\t\t<pattern [attr.id]=\"paint.id\" patternUnits=\"objectBoundingBox\" width=\"1\" height=\"1\">\n\t\t\t\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t\t\t\t[attr.href]=\"paint.href\"\n\t\t\t\t\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t\t\t\t\twidth=\"1\"\n\t\t\t\t\t\t\t\t\t\theight=\"1\"\n\t\t\t\t\t\t\t\t\t\tpreserveAspectRatio=\"none\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t</pattern>\n\t\t\t\t\t\t\t} @else if (paint.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"paint.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"paint.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"paint.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"paint.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"paint.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"paint.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"paint.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"paint.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of paint.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@for (strand of go.strands; track $index) {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"go.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"go.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"strand.strokeWidth\"\n\t\t\t\t\t\t\t[attr.stroke-dasharray]=\"go.dashArray\"\n\t\t\t\t\t\t\t[attr.stroke-linecap]=\"go.lineCap\"\n\t\t\t\t\t\t\t[attr.stroke-linejoin]=\"go.lineJoin\"\n\t\t\t\t\t\t\t[style.transform]=\"\n\t\t\t\t\t\t\t\tstrand.offset !== 0 ? 'translate(0, ' + strand.offset + 'px)' : null\n\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\t\t\t<!-- While this element is open in the inline text editor, its live text\n\t\t\t is drawn by that overlay instead (see `isBeingInlineEdited`);\n\t\t\t rendering it here too produced a duplicate, offset \"text shadow\"\n\t\t\t (issue #182). -->\n\t\t\t@if (!isBeingInlineEdited()) {\n\t\t\t\t@if (pathWarp(); as warp) {\n\t\t\t\t\t<svg\n\t\t\t\t\t\t[attr.width]=\"warp.width\"\n\t\t\t\t\t\t[attr.height]=\"warp.height\"\n\t\t\t\t\t\t[attr.viewBox]=\"'0 0 ' + warp.width + ' ' + warp.height\"\n\t\t\t\t\t\tstyle=\"position: absolute; inset: 0; overflow: visible; pointer-events: none\"\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t>\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t\t<path [attr.id]=\"line.pathId\" [attr.d]=\"line.d\" fill=\"none\" />\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t\t@for (line of warp.pathLines; track line.pathId) {\n\t\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t\t[attr.font-size]=\"warp.baseFontSize\"\n\t\t\t\t\t\t\t\t[attr.font-family]=\"warp.baseFontFamily\"\n\t\t\t\t\t\t\t\t[attr.fill]=\"warp.baseColor\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t<textPath\n\t\t\t\t\t\t\t\t\t[attr.href]=\"'#' + line.pathId\"\n\t\t\t\t\t\t\t\t\t[attr.startOffset]=\"warp.startOffset\"\n\t\t\t\t\t\t\t\t\t[attr.text-anchor]=\"warp.textAnchor\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (seg of line.segments; track $index) {\n\t\t\t\t\t\t\t\t\t\t<tspan\n\t\t\t\t\t\t\t\t\t\t\t[attr.fill]=\"seg.style?.color ?? warp.baseColor\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-weight]=\"seg.style?.bold ? 700 : 400\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.font-style]=\"seg.style?.italic ? 'italic' : 'normal'\"\n\t\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t\t\t{{ seg.text }}\n\t\t\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</textPath>\n\t\t\t\t\t\t\t</text>\n\t\t\t\t\t\t}\n\t\t\t\t\t</svg>\n\t\t\t\t} @else if (placeholderPrompt(); as prompt) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"prompt.style\">{{ prompt.text }}</div>\n\t\t\t\t} @else if (hasText()) {\n\t\t\t\t\t<div class=\"pptx-ng-text\" [ngStyle]=\"warpedTextStyle()\">\n\t\t\t\t\t\t@for (para of paragraphs(); track $index) {\n\t\t\t\t\t\t\t<p\n\t\t\t\t\t\t\t\tclass=\"pptx-ng-para\"\n\t\t\t\t\t\t\t\t[ngStyle]=\"para.paragraphStyle ?? null\"\n\t\t\t\t\t\t\t\t[style.padding-left.px]=\"para.indentPx\"\n\t\t\t\t\t\t\t\t[style.text-indent.px]=\"para.textIndentPx ?? null\"\n\t\t\t\t\t\t\t\t[style.line-height]=\"para.lineHeight ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-top.px]=\"para.spaceBeforePx ?? null\"\n\t\t\t\t\t\t\t\t[style.margin-bottom.px]=\"para.spaceAfterPx ?? null\"\n\t\t\t\t\t\t\t\t[style.font-size.px]=\"para.strutFontSizePx ?? null\"\n\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t@if (para.bulletPicture?.src) {\n\t\t\t\t\t\t\t\t\t<img\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet-image\"\n\t\t\t\t\t\t\t\t\t\t[src]=\"para.bulletPicture.src\"\n\t\t\t\t\t\t\t\t\t\t[alt]=\"para.bulletPicture.accessibleLabel\"\n\t\t\t\t\t\t\t\t\t\t[style.width.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\t[style.height.px]=\"para.bulletPicture.sizePx\"\n\t\t\t\t\t\t\t\t\t\tstyle=\"\n\t\t\t\t\t\t\t\t\t\t\tdisplay: inline-block;\n\t\t\t\t\t\t\t\t\t\t\tvertical-align: middle;\n\t\t\t\t\t\t\t\t\t\t\tmargin-inline-end: 4px;\n\t\t\t\t\t\t\t\t\t\t\tobject-fit: contain;\n\t\t\t\t\t\t\t\t\t\t\"\n\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t} @else if (para.bulletMarker) {\n\t\t\t\t\t\t\t\t\t<span\n\t\t\t\t\t\t\t\t\t\tclass=\"pptx-ng-bullet\"\n\t\t\t\t\t\t\t\t\t\t[ngStyle]=\"para.bulletStyle\"\n\t\t\t\t\t\t\t\t\t\t[attr.aria-label]=\"para.bulletPicture?.accessibleLabel ?? null\"\n\t\t\t\t\t\t\t\t\t\t>{{ para.bulletMarker }}</span\n\t\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (textBuildSpecs()[$index]; as spec) {\n\t\t\t\t\t\t\t\t\t<!-- Staged text build: render the split pieces so each one\n\t\t\t\t\t\t\t\t carries its own sub-animation. -->\n\t\t\t\t\t\t\t\t\t@if (spec.granularity === 'paragraph') {\n\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"spec.animId\" [ngStyle]=\"buildSpanStyle(spec)\">{{\n\t\t\t\t\t\t\t\t\t\t\tparagraphText(para)\n\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t@for (span of spec.spans ?? []; track $index) {\n\t\t\t\t\t\t\t\t\t\t\t<span [attr.data-anim-id]=\"span.animId\" [ngStyle]=\"buildSpanStyle(span)\">{{\n\t\t\t\t\t\t\t\t\t\t\t\tspan.text\n\t\t\t\t\t\t\t\t\t\t\t}}</span>\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t@for (run of para.runs; track $index) {\n\t\t\t\t\t\t\t\t\t\t@if (run.equationXml) {\n\t\t\t\t\t\t\t\t\t\t\t<pptx-equation-renderer\n\t\t\t\t\t\t\t\t\t\t\t\t[equationXml]=\"run.equationXml\"\n\t\t\t\t\t\t\t\t\t\t\t\t[equationNumber]=\"run.equationNumber\"\n\t\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t\t} @else if (\n\t\t\t\t\t\t\t\t\t\t\trun.text ===\n\t\t\t\t\t\t\t\t\t\t\t'\n'\n\t\t\t\t\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t\t\t} @else if (run.reflection; as refl) {\n\t\t\t\t\t\t\t\t\t\t\t<!-- `a:reflection`: wrapped HERE, around the whole base\n\t\t\t\t\t\t\t\t\t\t run (`runBase`), rather than inside its href/ruby/plain\n\t\t\t\t\t\t\t\t\t\t branches - a `<ruby>` run's own `display: ruby` (which\n\t\t\t\t\t\t\t\t\t\t positions the annotation above its base text) would\n\t\t\t\t\t\t\t\t\t\t break if forced to `display: inline-block` to host the\n\t\t\t\t\t\t\t\t\t\t mirror. Cross-browser, unlike the `-webkit-box-reflect`\n\t\t\t\t\t\t\t\t\t\t this replaced (Firefox never implemented it). -->\n\t\t\t\t\t\t\t\t\t\t\t<span style=\"position: relative; display: inline-block\">\n\t\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t\t\t<span class=\"pptx-ng-text-reflection\" aria-hidden=\"true\" [ngStyle]=\"refl\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t><span [ngStyle]=\"run.style\"\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t><ng-container\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t*ngTemplateOutlet=\"runContent; context: { run: run }\" /></span\n\t\t\t\t\t\t\t\t\t\t\t\t></span>\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t\t\t\t<ng-container *ngTemplateOutlet=\"runBase; context: { run: run }\" />\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t@if (para.isEmpty) {\n\t\t\t\t\t\t\t\t\t<!-- An authored blank line has no runs, so without this the\n\t\t\t\t\t\t\t\t <p> collapses to zero height and the gap a deck puts\n\t\t\t\t\t\t\t\t between a heading and its bullet list disappears. -->\n\t\t\t\t\t\t\t\t\t<br />\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t</p>\n\t\t\t\t\t\t}\n\t\t\t\t\t</div>\n\t\t\t\t}\n\t\t\t}\n\t\t</div>\n\t}\n\t@default {\n\t\t<div\n\t\t\tclass=\"pptx-ng-element pptx-ng-unsupported\"\n\t\t\t[ngStyle]=\"containerStyle()\"\n\t\t\t[style.pointer-events]=\"rootPointerEvents()\"\n\t\t\t[attr.data-element-id]=\"elementIdAttr()\"\n\t\t\t[attr.data-pptx-element]=\"elementMarked() ? 'true' : null\"\n\t\t>\n\t\t\t<div class=\"pptx-ng-placeholder\">{{ placeholderLabel() }}</div>\n\t\t</div>\n\t}\n}\n\n<!-- Soft-edge feather <filter> def, referenced via filter: url(#soft-edge-<id>). -->\n@if (softEdgeFilter(); as sef) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter\n\t\t\t\t[attr.id]=\"sef.id\"\n\t\t\t\tx=\"-20%\"\n\t\t\t\ty=\"-20%\"\n\t\t\t\twidth=\"140%\"\n\t\t\t\theight=\"140%\"\n\t\t\t\tcolor-interpolation-filters=\"sRGB\"\n\t\t\t>\n\t\t\t\t<feGaussianBlur in=\"SourceAlpha\" [attr.stdDeviation]=\"sef.radius\" result=\"softEdgeAlpha\" />\n\t\t\t\t<feComposite in=\"SourceGraphic\" in2=\"softEdgeAlpha\" operator=\"in\" />\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!-- Duotone image-effect <filter> def, referenced via filter: url(#id). -->\n@if (duotoneFilter(); as df) {\n\t<svg\n\t\twidth=\"0\"\n\t\theight=\"0\"\n\t\taria-hidden=\"true\"\n\t\tstyle=\"position: absolute; width: 0; height: 0; overflow: hidden\"\n\t>\n\t\t<defs>\n\t\t\t<filter [attr.id]=\"df.id\" color-interpolation-filters=\"sRGB\">\n\t\t\t\t<feColorMatrix type=\"matrix\" [attr.values]=\"df.primitives[0].values\" />\n\t\t\t\t<feComponentTransfer>\n\t\t\t\t\t<feFuncR\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[0].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[0].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncG\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[1].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[1].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t\t<feFuncB\n\t\t\t\t\t\ttype=\"linear\"\n\t\t\t\t\t\t[attr.slope]=\"df.primitives[1].channels[2].slope\"\n\t\t\t\t\t\t[attr.intercept]=\"df.primitives[1].channels[2].intercept\"\n\t\t\t\t\t/>\n\t\t\t\t</feComponentTransfer>\n\t\t\t</filter>\n\t\t</defs>\n\t</svg>\n}\n\n<!--\n\tOne run's base element (hyperlink / ruby / plain span), reused via\n\t`ngTemplateOutlet` both directly and inside the `a:reflection` wrapper above,\n\tso the reflection case does not duplicate this three-way branch.\n-->\n<ng-template #runBase let-run=\"run\">\n\t@if (run.href) {\n\t\t<a\n\t\t\tclass=\"pptx-ng-link\"\n\t\t\t[href]=\"run.href\"\n\t\t\t[attr.target]=\"run.target ?? '_blank'\"\n\t\t\t[attr.rel]=\"run.rel ?? 'noopener noreferrer'\"\n\t\t\t[attr.title]=\"run.tooltip ?? null\"\n\t\t\t[ngStyle]=\"run.style\"\n\t\t\t(click)=\"onHyperlinkClick($event, run.href)\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></a>\n\t} @else if (run.rubyText) {\n\t\t<!-- `a:ruby`: the phonetic guide sits above its base\n\t\t text; the <rp> parentheses are the fallback for a\n\t\t browser without ruby support. -->\n\t\t<ruby [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\" /><rp>(</rp\n\t\t\t><rt [ngStyle]=\"run.rubyStyle\">{{ run.rubyText }}</rt\n\t\t\t><rp>)</rp></ruby\n\t\t>\n\t} @else {\n\t\t<span [ngStyle]=\"run.style\"\n\t\t\t><ng-container *ngTemplateOutlet=\"runContent; context: { run: run }\"\n\t\t/></span>\n\t}\n</ng-template>\n\n<!--\n\tA run's text content, honouring shared's per-script font split\n\t(`run.scriptRuns`) and measured tab-stop layout (`run.tabLines`) when\n\teither is present. Both descriptors come from `pptx-viewer-shared`'s\n\t`buildParagraphs` (the per-script split was React-only before this\n\ttemplate existed: CJK, Arabic, Hebrew and Thai text rendered in the wrong\n\ttypeface here; the tab layout was likewise React-only, so a TOC-style row\n\tlost its leader dots and right-aligned page number). Reused via\n\t`ngTemplateOutlet` for the run's span / anchor / ruby base text, so all\n\tthree carry the same content logic.\n-->\n<ng-template #runContent let-run=\"run\">\n\t@if (run.tabLines) {\n\t\t@for (line of run.tabLines; track $index) {\n\t\t\t<span style=\"display: inline-block; white-space: nowrap\">\n\t\t\t\t@for (piece of line.pieces; track $index) {\n\t\t\t\t\t@if (piece.leaderStyle) {\n\t\t\t\t\t\t<span aria-hidden=\"true\" [ngStyle]=\"piece.leaderStyle\">{{ piece.leaderText }}</span>\n\t\t\t\t\t}\n\t\t\t\t\t<!-- `u=\"words\"`: one sibling span per word/gap in place of the piece span. -->\n\t\t\t\t\t@if (piece.words) {\n\t\t\t\t\t\t@for (word of piece.words; track $index) {\n\t\t\t\t\t\t\t<span [ngStyle]=\"word.style\">{{ word.text }}</span>\n\t\t\t\t\t\t}\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</span>\n\t\t\t@if (!$last) {\n\t\t\t\t<br />\n\t\t\t}\n\t\t}\n\t} @else if (run.scriptRuns || run.underlineWordPieces) {\n\t\t<!--\n\t\t\tA bare interpolation as the sole content of an `@if`/`@else` block\n\t\t\tleaks a real leading + trailing whitespace text node: Angular does\n\t\t\tnot collapse that whitespace the way it collapses whitespace between\n\t\t\telement TAGS. Worse, oxfmt's Angular-template printer always breaks a\n\t\t\tblock's content onto its own indented line, even when the block was\n\t\t\twritten as a single line with the braces touching, so writing the\n\t\t\t`{{ x }}` compact ourselves does not survive the next `bun run fmt` /\n\t\t\tpre-commit `lint-staged` pass: it silently re-introduces the leak\n\t\t\t(this happened twice, see `20d4d177`, `18eebb6f`). `<ng-container>`\n\t\t\tdoes not render any DOM node of its own, so wrapping the\n\t\t\tinterpolation in one keeps the no-wrapper-element behaviour of\n\t\t\tReact's `<>{piece.text}</>` fragment while making the interpolation\n\t\t\ttag-adjacent, which both Angular AND oxfmt already treat as safely\n\t\t\tcollapsible (see the many `<span>{{ x }}</span>` one-liners in this\n\t\t\tfile). That was invisible while a paragraph was one run per script\n\t\t\t(two stray spaces at the run's own edges, trimmed visually by the\n\t\t\tbrowser but still present in `textContent`), but shared's per-word /\n\t\t\tper-gap metric split (`text-run-spacing.ts`, issue #149) re-emits\n\t\t\tevery WORD and inter-word GAP as its own sibling run, so the same\n\t\t\tone-space leak lands between every word: \"will choose\" rendered as\n\t\t\t\"will choose\" (five spaces: the word's own trailing leak, the\n\t\t\tgap run's real space plus its OWN two leaks, the next word's leading\n\t\t\tleak). The same leak also showed up one paragraph at a time:\n\t\t\t\"Project\" / \"Atlas\" as two separate paragraphs read back as\n\t\t\t\"ProjectAtlas\" instead of React's \"Project Atlas\", because the\n\t\t\tplain-run `@else` below had the same bug.\n\t\t-->\n\t\t@for (piece of run.scriptRuns ?? run.underlineWordPieces; track $index) {\n\t\t\t@if (piece.style) {\n\t\t\t\t<span [ngStyle]=\"piece.style\">{{ piece.text }}</span>\n\t\t\t} @else {\n\t\t\t\t<ng-container>{{ piece.text }}</ng-container>\n\t\t\t}\n\t\t}\n\t} @else {\n\t\t<ng-container>{{ run.text }}</ng-container>\n\t}\n</ng-template>\n" }]
108830
110286
  }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], obstacles: [{ type: i0.Input, args: [{ isSignal: true, alias: "obstacles", required: false }] }], canvasWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasWidth", required: false }] }], canvasHeight: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasHeight", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], marked: [{ type: i0.Input, args: [{ isSignal: true, alias: "marked", required: false }] }], exposeElementId: [{ type: i0.Input, args: [{ isSignal: true, alias: "exposeElementId", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], fieldContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "fieldContext", required: false }] }], slideElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideElements", required: false }] }], editTemplateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTemplateMode", required: false }] }], parentGroupFill: [{ type: i0.Input, args: [{ isSignal: true, alias: "parentGroupFill", required: false }] }], editingElementId: [{ type: i0.Input, args: [{ isSignal: true, alias: "editingElementId", required: false }] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], tableChange: [{ type: i0.Output, args: ["tableChange"] }] } });
108831
110287
 
108832
110288
  /**
@@ -115108,6 +116564,7 @@ class ViewerCollaborationSessionService {
115108
116564
  canvasHeight: size.height,
115109
116565
  getSourceBytes: () => host.getSourceBytes(),
115110
116566
  getTemplateElements: () => host.getTemplateElements(),
116567
+ getSaveOptions: () => host.getSaveOptions(),
115111
116568
  };
115112
116569
  }
115113
116570
  /**
@@ -128581,7 +130038,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
128581
130038
  }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }], selectedElement: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedElement", required: false }] }] } });
128582
130039
 
128583
130040
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
128584
- const PPTX_ANGULAR_VIEWER_VERSION = "3.7.0";
130041
+ const PPTX_ANGULAR_VIEWER_VERSION = "3.8.0";
128585
130042
 
128586
130043
  /**
128587
130044
  * account-page.component.ts: File > Account content.
@@ -134416,6 +135873,99 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
134416
135873
  `, styles: [".hdr{display:flex;align-items:center;justify-content:space-between;gap:8px;padding:8px 10px;border-bottom:1px solid var(--pptx-inspector-border, rgba(0, 0, 0, .1))}.hdr__tabs{display:flex;align-items:center;gap:2px;border-radius:4px;background:var(--pptx-inspector-input-bg, rgba(0, 0, 0, .06));padding:2px}.hdr__tab{display:flex;align-items:center;gap:4px;padding:3px 8px;border:none;border-radius:3px;background:transparent;color:var(--pptx-inspector-muted, #888);font-size:11px;font-family:inherit;cursor:pointer}.hdr__tab.is-active{background:var(--pptx-inspector-active, #0078d4);color:#fff}.hdr__icon{width:14px;height:14px;flex-shrink:0}.hdr__icon--close{width:16px;height:16px}.hdr__close{display:flex;align-items:center;justify-content:center;padding:4px;border:none;border-radius:3px;background:transparent;color:var(--pptx-inspector-muted, #888);cursor:pointer}.hdr__close:hover,.hdr__tab:not(.is-active):hover{color:inherit}\n"] }]
134417
135874
  }], propDecorators: { activeTab: [{ type: i0.Input, args: [{ isSignal: true, alias: "activeTab", required: true }] }], tabChange: [{ type: i0.Output, args: ["tabChange"] }], closePane: [{ type: i0.Output, args: ["closePane"] }] } });
134418
135875
 
135876
+ /**
135877
+ * Alt text / title editor for a plain shape, text box or connector, at
135878
+ * parity with React's `AccessibilityTextSection` and Vue's
135879
+ * `AccessibilityPanel.vue`.
135880
+ *
135881
+ * A picture's own alt text field lives in `ImagePropertiesPanelComponent`;
135882
+ * this covers the three element kinds that only started modelling `altText`
135883
+ * / `title` once core parsed `p:cNvPr/@descr` / `@title` on `p:sp` / `p:cxnSp`
135884
+ * (see `PptxNonVisualDescription`). `getNonVisualDescriptionFields` (shared)
135885
+ * decides which fields apply so this component stays a thin view.
135886
+ */
135887
+ class AccessibilityTextPanelComponent {
135888
+ constructor() {
135889
+ this.element = input.required(/* @ts-ignore */
135890
+ ...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
135891
+ this.patch = output();
135892
+ this.fields = computed(() => getNonVisualDescriptionFields(this.element()), /* @ts-ignore */
135893
+ ...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
135894
+ }
135895
+ /** Whether the selected element kind supports either field. */
135896
+ static supports(element) {
135897
+ return element.type === 'text' || element.type === 'shape' || element.type === 'connector';
135898
+ }
135899
+ onAltText(event) {
135900
+ this.patch.emit({
135901
+ altText: event.target.value,
135902
+ });
135903
+ }
135904
+ onTitle(event) {
135905
+ this.patch.emit({ title: event.target.value });
135906
+ }
135907
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AccessibilityTextPanelComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
135908
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: AccessibilityTextPanelComponent, isStandalone: true, selector: "pptx-accessibility-text-panel", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null } }, outputs: { patch: "patch" }, ngImport: i0, template: `
135909
+ @if (fields().showAltText || fields().showTitle) {
135910
+ <div class="pptx-ng-accessibility-text" data-pptx-accessibility-text>
135911
+ @if (fields().showAltText) {
135912
+ <label class="field field--stacked">
135913
+ <span>{{ 'pptx.elementAccessibility.altText' | translate }}</span>
135914
+ <textarea
135915
+ rows="2"
135916
+ [value]="fields().altText"
135917
+ [placeholder]="'pptx.elementAccessibility.altTextPlaceholder' | translate"
135918
+ (input)="onAltText($event)"
135919
+ ></textarea>
135920
+ </label>
135921
+ }
135922
+ @if (fields().showTitle) {
135923
+ <label class="field field--stacked">
135924
+ <span>{{ 'pptx.elementAccessibility.title' | translate }}</span>
135925
+ <input
135926
+ type="text"
135927
+ [value]="fields().title"
135928
+ [placeholder]="'pptx.elementAccessibility.titlePlaceholder' | translate"
135929
+ (input)="onTitle($event)"
135930
+ />
135931
+ </label>
135932
+ }
135933
+ </div>
135934
+ }
135935
+ `, isInline: true, styles: [".pptx-ng-accessibility-text{display:grid;gap:9px;font-size:11px}.field{display:grid;gap:4px;color:var(--pptx-inspector-muted, #aaa)}.field--stacked{grid-template-columns:1fr}input[type=text],textarea{box-sizing:border-box;width:100%;padding:4px 6px;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit;font:inherit;resize:vertical}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
135936
+ }
135937
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: AccessibilityTextPanelComponent, decorators: [{
135938
+ type: Component,
135939
+ args: [{ selector: 'pptx-accessibility-text-panel', standalone: true, imports: [TranslatePipe], changeDetection: ChangeDetectionStrategy.OnPush, template: `
135940
+ @if (fields().showAltText || fields().showTitle) {
135941
+ <div class="pptx-ng-accessibility-text" data-pptx-accessibility-text>
135942
+ @if (fields().showAltText) {
135943
+ <label class="field field--stacked">
135944
+ <span>{{ 'pptx.elementAccessibility.altText' | translate }}</span>
135945
+ <textarea
135946
+ rows="2"
135947
+ [value]="fields().altText"
135948
+ [placeholder]="'pptx.elementAccessibility.altTextPlaceholder' | translate"
135949
+ (input)="onAltText($event)"
135950
+ ></textarea>
135951
+ </label>
135952
+ }
135953
+ @if (fields().showTitle) {
135954
+ <label class="field field--stacked">
135955
+ <span>{{ 'pptx.elementAccessibility.title' | translate }}</span>
135956
+ <input
135957
+ type="text"
135958
+ [value]="fields().title"
135959
+ [placeholder]="'pptx.elementAccessibility.titlePlaceholder' | translate"
135960
+ (input)="onTitle($event)"
135961
+ />
135962
+ </label>
135963
+ }
135964
+ </div>
135965
+ }
135966
+ `, styles: [".pptx-ng-accessibility-text{display:grid;gap:9px;font-size:11px}.field{display:grid;gap:4px;color:var(--pptx-inspector-muted, #aaa)}.field--stacked{grid-template-columns:1fr}input[type=text],textarea{box-sizing:border-box;width:100%;padding:4px 6px;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit;font:inherit;resize:vertical}\n"] }]
135967
+ }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], patch: [{ type: i0.Output, args: ["patch"] }] } });
135968
+
134419
135969
  /**
134420
135970
  * action-target-fields.component.ts: the target input for one Action Settings
134421
135971
  * trigger, split out of `ActionSettingsPanelComponent` to keep that file under
@@ -139602,7 +141152,10 @@ class ChartTypeSelectorComponent {
139602
141152
  onTitle(event) {
139603
141153
  const target = event.target;
139604
141154
  if (target instanceof HTMLInputElement) {
139605
- this.emit({ title: target.value });
141155
+ // A multi-run title collapses to one run in its dominant style so an
141156
+ // edit does not leave another, now-stale run's text trailing the new
141157
+ // title; see `collapseChartTitleRunsForEdit`'s doc.
141158
+ this.emit(collapseChartTitleRunsForEdit(this.data(), target.value));
139606
141159
  }
139607
141160
  }
139608
141161
  onType(event) {
@@ -143533,7 +145086,7 @@ class SmartArtPropertiesComponent {
143533
145086
  this.commit(moveNodeDown(this.smartArtData(), nodeId));
143534
145087
  }
143535
145088
  onNodeFillColor(event, nodeId) {
143536
- const value = inputValue$2(event);
145089
+ const value = inputValue$3(event);
143537
145090
  if (value === null) {
143538
145091
  return;
143539
145092
  }
@@ -143541,7 +145094,7 @@ class SmartArtPropertiesComponent {
143541
145094
  this.recentColors?.push(value);
143542
145095
  }
143543
145096
  onNodeFontColor(event, nodeId) {
143544
- const value = inputValue$2(event);
145097
+ const value = inputValue$3(event);
143545
145098
  if (value === null) {
143546
145099
  return;
143547
145100
  }
@@ -143555,7 +145108,7 @@ class SmartArtPropertiesComponent {
143555
145108
  this.commit(toggleNodeItalic(this.smartArtData(), node));
143556
145109
  }
143557
145110
  onNodeText(event, nodeId) {
143558
- const value = inputValue$2(event);
145111
+ const value = inputValue$3(event);
143559
145112
  if (value === null) {
143560
145113
  return;
143561
145114
  }
@@ -144050,7 +145603,7 @@ function selectValue$1(event) {
144050
145603
  return target instanceof HTMLSelectElement ? target.value : null;
144051
145604
  }
144052
145605
  /** Read the value of an `<input>` change event. */
144053
- function inputValue$2(event) {
145606
+ function inputValue$3(event) {
144054
145607
  const target = event.target;
144055
145608
  return target instanceof HTMLInputElement ? target.value : null;
144056
145609
  }
@@ -144225,7 +145778,7 @@ class TableCellAdvancedFillComponent {
144225
145778
  this.emitGradient(this.stops(), this.gradType(), angle);
144226
145779
  }
144227
145780
  onStopColor(index, event) {
144228
- const color = inputValue$1(event);
145781
+ const color = inputValue$2(event);
144229
145782
  this.updateStop(index, { color });
144230
145783
  }
144231
145784
  onStopPos(index, event) {
@@ -144240,10 +145793,10 @@ class TableCellAdvancedFillComponent {
144240
145793
  this.styleChange.emit({ patternFillPreset: selectValue(event) });
144241
145794
  }
144242
145795
  onPatternFg(event) {
144243
- this.styleChange.emit({ patternFillForeground: inputValue$1(event) });
145796
+ this.styleChange.emit({ patternFillForeground: inputValue$2(event) });
144244
145797
  }
144245
145798
  onPatternBg(event) {
144246
- this.styleChange.emit({ patternFillBackground: inputValue$1(event) });
145799
+ this.styleChange.emit({ patternFillBackground: inputValue$2(event) });
144247
145800
  }
144248
145801
  onMargin(key, event) {
144249
145802
  const value = numberValue(event);
@@ -144256,7 +145809,7 @@ class TableCellAdvancedFillComponent {
144256
145809
  * colour into the shared "Recent colours" list.
144257
145810
  */
144258
145811
  pushRecentColor(event) {
144259
- const value = inputValue$1(event);
145812
+ const value = inputValue$2(event);
144260
145813
  if (value) {
144261
145814
  this.recentColors?.push(value);
144262
145815
  }
@@ -144579,7 +146132,7 @@ function selectValue(event) {
144579
146132
  const t = event.target;
144580
146133
  return t instanceof HTMLSelectElement ? t.value : '';
144581
146134
  }
144582
- function inputValue$1(event) {
146135
+ function inputValue$2(event) {
144583
146136
  const t = event.target;
144584
146137
  return t instanceof HTMLInputElement ? t.value : '';
144585
146138
  }
@@ -144629,14 +146182,14 @@ class TableCellColorFieldComponent {
144629
146182
  }
144630
146183
  /** Live preview while dragging the native picker: no theme identity, so always clears the ref. */
144631
146184
  onNativeChange(event) {
144632
- const value = inputValue(event);
146185
+ const value = inputValue$1(event);
144633
146186
  if (value) {
144634
146187
  this.commit.emit({ hex: value, ref: undefined });
144635
146188
  }
144636
146189
  }
144637
146190
  /** The committed (native `change`, not the live-preview `input`) colour: record it as recent. */
144638
146191
  onNativeCommit(event) {
144639
- const value = inputValue(event);
146192
+ const value = inputValue$1(event);
144640
146193
  if (value) {
144641
146194
  this.recentColors?.push(value);
144642
146195
  }
@@ -144689,7 +146242,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
144689
146242
  </label>
144690
146243
  `, styles: [".pptx-tccf__field{display:flex;flex-direction:column;gap:.2rem}.pptx-tccf__lbl{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tccf__color{width:28px;height:22px;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}\n"] }]
144691
146244
  }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }], fallback: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallback", required: true }] }], selectedRef: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedRef", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], commit: [{ type: i0.Output, args: ["commit"] }] } });
144692
- function inputValue(event) {
146245
+ function inputValue$1(event) {
144693
146246
  const t = event.target;
144694
146247
  return t instanceof HTMLInputElement ? t.value : '';
144695
146248
  }
@@ -145655,6 +147208,616 @@ function stringFromEvent$1(event) {
145655
147208
  return target.value;
145656
147209
  }
145657
147210
 
147211
+ /**
147212
+ * table-style-editor-fields.component.ts: field editors (fill/text/borders)
147213
+ * for whichever part `TableStyleEditorComponent` currently has selected.
147214
+ * Split out from that shell purely to keep both files under the repo's
147215
+ * 300-LOC budget. Mirrors React's `TableStyleEditorFields.tsx` and Vue's
147216
+ * `TableStyleEditorFields.vue`.
147217
+ *
147218
+ * @module viewer/table-style-editor-fields
147219
+ */
147220
+ function inputValue(event) {
147221
+ const t = event.target;
147222
+ return t instanceof HTMLInputElement || t instanceof HTMLSelectElement ? t.value : '';
147223
+ }
147224
+ function checkedValue(event) {
147225
+ const t = event.target;
147226
+ return t instanceof HTMLInputElement ? t.checked : false;
147227
+ }
147228
+ class TableStyleEditorFieldsComponent {
147229
+ constructor() {
147230
+ this.descriptor = input.required(/* @ts-ignore */
147231
+ ...(ngDevMode ? [{ debugName: "descriptor" }] : /* istanbul ignore next */ []));
147232
+ this.canEdit = input(true, /* @ts-ignore */
147233
+ ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
147234
+ this.edit = output();
147235
+ this.sides = TABLE_STYLE_BORDER_SIDES;
147236
+ this.dashPresets = TABLE_STYLE_DASH_PRESETS;
147237
+ this.borderSideLabelKeys = TABLE_STYLE_BORDER_SIDE_LABEL_KEYS;
147238
+ }
147239
+ inputValue(event) {
147240
+ return inputValue(event);
147241
+ }
147242
+ /** Templates cannot reach the `Number` global, so the coercion lives here. */
147243
+ inputNumber(event) {
147244
+ return Number(inputValue(event));
147245
+ }
147246
+ checkedValue(event) {
147247
+ return checkedValue(event);
147248
+ }
147249
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorFieldsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
147250
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: TableStyleEditorFieldsComponent, isStandalone: true, selector: "pptx-table-style-editor-fields", inputs: { descriptor: { classPropertyName: "descriptor", publicName: "descriptor", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { edit: "edit" }, ngImport: i0, template: `
147251
+ @if (descriptor(); as d) {
147252
+ <div class="pptx-tse-fields">
147253
+ <div class="pptx-tse-fields__group">
147254
+ <div class="pptx-tse-fields__hdg">
147255
+ {{ 'pptx.tableStyleEditor.fillSection' | translate }}
147256
+ </div>
147257
+ <div class="pptx-tse-fields__row">
147258
+ <input
147259
+ type="color"
147260
+ class="pptx-tse-fields__color"
147261
+ [disabled]="!canEdit()"
147262
+ [value]="d.fill.color.hex"
147263
+ (change)="edit.emit({ kind: 'fillColor', hex: inputValue($event), ref: undefined })"
147264
+ />
147265
+ <label class="pptx-tse-fields__check">
147266
+ <input
147267
+ type="checkbox"
147268
+ [disabled]="!canEdit()"
147269
+ [checked]="d.fill.noFill"
147270
+ (change)="edit.emit({ kind: 'fillNone', noFill: checkedValue($event) })"
147271
+ />
147272
+ {{ 'pptx.tableStyleEditor.noFill' | translate }}
147273
+ </label>
147274
+ </div>
147275
+ <pptx-theme-color-swatch-grid
147276
+ [disabled]="!canEdit()"
147277
+ [selectedRef]="d.fill.color.ref"
147278
+ [selectedHex]="d.fill.color.hex"
147279
+ (pick)="edit.emit({ kind: 'fillColor', hex: $event.hex, ref: $event.ref })"
147280
+ />
147281
+ </div>
147282
+
147283
+ @if (d.hasTextAndBorders) {
147284
+ <div class="pptx-tse-fields__group">
147285
+ <div class="pptx-tse-fields__hdg">
147286
+ {{ 'pptx.tableStyleEditor.textSection' | translate }}
147287
+ </div>
147288
+ <div class="pptx-tse-fields__row">
147289
+ <button
147290
+ type="button"
147291
+ [disabled]="!canEdit()"
147292
+ [class.pptx-tse-fields__active]="d.text.bold"
147293
+ (click)="edit.emit({ kind: 'textBold', value: !d.text.bold })"
147294
+ >
147295
+ {{ 'pptx.format.bold' | translate }}
147296
+ </button>
147297
+ <button
147298
+ type="button"
147299
+ [disabled]="!canEdit()"
147300
+ [class.pptx-tse-fields__active]="d.text.italic"
147301
+ (click)="edit.emit({ kind: 'textItalic', value: !d.text.italic })"
147302
+ >
147303
+ {{ 'pptx.format.italic' | translate }}
147304
+ </button>
147305
+ <button
147306
+ type="button"
147307
+ [disabled]="!canEdit()"
147308
+ [class.pptx-tse-fields__active]="d.text.underline"
147309
+ (click)="edit.emit({ kind: 'textUnderline', value: !d.text.underline })"
147310
+ >
147311
+ {{ 'pptx.format.underline' | translate }}
147312
+ </button>
147313
+ </div>
147314
+ <label class="pptx-tse-fields__row">
147315
+ <span>{{ 'pptx.tableStyleEditor.textColor' | translate }}</span>
147316
+ <input
147317
+ type="color"
147318
+ class="pptx-tse-fields__color"
147319
+ [disabled]="!canEdit()"
147320
+ [value]="d.text.color.hex"
147321
+ (change)="edit.emit({ kind: 'textColor', hex: inputValue($event), ref: undefined })"
147322
+ />
147323
+ </label>
147324
+ <pptx-theme-color-swatch-grid
147325
+ [disabled]="!canEdit()"
147326
+ [selectedRef]="d.text.color.ref"
147327
+ [selectedHex]="d.text.color.hex"
147328
+ (pick)="edit.emit({ kind: 'textColor', hex: $event.hex, ref: $event.ref })"
147329
+ />
147330
+ </div>
147331
+
147332
+ <div class="pptx-tse-fields__group">
147333
+ <div class="pptx-tse-fields__hdg">
147334
+ {{ 'pptx.tableStyleEditor.bordersSection' | translate }}
147335
+ </div>
147336
+ @for (side of sides; track side) {
147337
+ <div class="pptx-tse-fields__border-row">
147338
+ <span class="pptx-tse-fields__side-lbl">{{
147339
+ borderSideLabelKeys[side] | translate
147340
+ }}</span>
147341
+ <input
147342
+ type="color"
147343
+ class="pptx-tse-fields__color pptx-tse-fields__color--sm"
147344
+ [disabled]="!canEdit()"
147345
+ [value]="d.borders[side].color.hex"
147346
+ (change)="
147347
+ edit.emit({
147348
+ kind: 'borderColor',
147349
+ side,
147350
+ hex: inputValue($event),
147351
+ ref: undefined,
147352
+ })
147353
+ "
147354
+ />
147355
+ <input
147356
+ type="number"
147357
+ min="0"
147358
+ max="20"
147359
+ class="pptx-tse-fields__num"
147360
+ [disabled]="!canEdit()"
147361
+ [value]="d.borders[side].width"
147362
+ (change)="edit.emit({ kind: 'borderWidth', side, width: inputNumber($event) })"
147363
+ />
147364
+ <select
147365
+ class="pptx-tse-fields__dash"
147366
+ [disabled]="!canEdit()"
147367
+ [value]="d.borders[side].dash"
147368
+ (change)="edit.emit({ kind: 'borderDash', side, dash: inputValue($event) })"
147369
+ >
147370
+ @for (dash of dashPresets; track dash) {
147371
+ <option [value]="dash" [selected]="dash === d.borders[side].dash">
147372
+ {{ dash }}
147373
+ </option>
147374
+ }
147375
+ </select>
147376
+ <label class="pptx-tse-fields__check">
147377
+ <input
147378
+ type="checkbox"
147379
+ [disabled]="!canEdit()"
147380
+ [checked]="d.borders[side].noFill"
147381
+ (change)="edit.emit({ kind: 'borderNone', side, noFill: checkedValue($event) })"
147382
+ />
147383
+ {{ 'pptx.tableStyleEditor.noBorder' | translate }}
147384
+ </label>
147385
+ </div>
147386
+ }
147387
+ </div>
147388
+ }
147389
+ </div>
147390
+ }
147391
+ `, isInline: true, styles: [".pptx-tse-fields{display:flex;flex-direction:column;gap:.5rem}.pptx-tse-fields__group{display:flex;flex-direction:column;gap:.25rem}.pptx-tse-fields__hdg{font-size:10px;text-transform:uppercase;letter-spacing:.03em;color:var(--pptx-inspector-muted, #888)}.pptx-tse-fields__row{display:flex;align-items:center;gap:.5rem;font-size:11px}.pptx-tse-fields__check{display:flex;align-items:center;gap:.25rem;font-size:11px}.pptx-tse-fields__color{height:1.5rem;width:2rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-tse-fields__color--sm{width:1.75rem}.pptx-tse-fields__border-row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-tse-fields__side-lbl{width:7rem;flex-shrink:0;color:var(--pptx-inspector-muted, #888)}.pptx-tse-fields__num{width:3rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit}.pptx-tse-fields__dash{border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit}.pptx-tse-fields__active{background:var(--pptx-inspector-active, #3a3a3a)}\n"], dependencies: [{ kind: "component", type: ThemeColorSwatchGridComponent, selector: "pptx-theme-color-swatch-grid", inputs: ["disabled", "selectedRef", "selectedHex"], outputs: ["pick"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
147392
+ }
147393
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorFieldsComponent, decorators: [{
147394
+ type: Component,
147395
+ args: [{ selector: 'pptx-table-style-editor-fields', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, ThemeColorSwatchGridComponent], template: `
147396
+ @if (descriptor(); as d) {
147397
+ <div class="pptx-tse-fields">
147398
+ <div class="pptx-tse-fields__group">
147399
+ <div class="pptx-tse-fields__hdg">
147400
+ {{ 'pptx.tableStyleEditor.fillSection' | translate }}
147401
+ </div>
147402
+ <div class="pptx-tse-fields__row">
147403
+ <input
147404
+ type="color"
147405
+ class="pptx-tse-fields__color"
147406
+ [disabled]="!canEdit()"
147407
+ [value]="d.fill.color.hex"
147408
+ (change)="edit.emit({ kind: 'fillColor', hex: inputValue($event), ref: undefined })"
147409
+ />
147410
+ <label class="pptx-tse-fields__check">
147411
+ <input
147412
+ type="checkbox"
147413
+ [disabled]="!canEdit()"
147414
+ [checked]="d.fill.noFill"
147415
+ (change)="edit.emit({ kind: 'fillNone', noFill: checkedValue($event) })"
147416
+ />
147417
+ {{ 'pptx.tableStyleEditor.noFill' | translate }}
147418
+ </label>
147419
+ </div>
147420
+ <pptx-theme-color-swatch-grid
147421
+ [disabled]="!canEdit()"
147422
+ [selectedRef]="d.fill.color.ref"
147423
+ [selectedHex]="d.fill.color.hex"
147424
+ (pick)="edit.emit({ kind: 'fillColor', hex: $event.hex, ref: $event.ref })"
147425
+ />
147426
+ </div>
147427
+
147428
+ @if (d.hasTextAndBorders) {
147429
+ <div class="pptx-tse-fields__group">
147430
+ <div class="pptx-tse-fields__hdg">
147431
+ {{ 'pptx.tableStyleEditor.textSection' | translate }}
147432
+ </div>
147433
+ <div class="pptx-tse-fields__row">
147434
+ <button
147435
+ type="button"
147436
+ [disabled]="!canEdit()"
147437
+ [class.pptx-tse-fields__active]="d.text.bold"
147438
+ (click)="edit.emit({ kind: 'textBold', value: !d.text.bold })"
147439
+ >
147440
+ {{ 'pptx.format.bold' | translate }}
147441
+ </button>
147442
+ <button
147443
+ type="button"
147444
+ [disabled]="!canEdit()"
147445
+ [class.pptx-tse-fields__active]="d.text.italic"
147446
+ (click)="edit.emit({ kind: 'textItalic', value: !d.text.italic })"
147447
+ >
147448
+ {{ 'pptx.format.italic' | translate }}
147449
+ </button>
147450
+ <button
147451
+ type="button"
147452
+ [disabled]="!canEdit()"
147453
+ [class.pptx-tse-fields__active]="d.text.underline"
147454
+ (click)="edit.emit({ kind: 'textUnderline', value: !d.text.underline })"
147455
+ >
147456
+ {{ 'pptx.format.underline' | translate }}
147457
+ </button>
147458
+ </div>
147459
+ <label class="pptx-tse-fields__row">
147460
+ <span>{{ 'pptx.tableStyleEditor.textColor' | translate }}</span>
147461
+ <input
147462
+ type="color"
147463
+ class="pptx-tse-fields__color"
147464
+ [disabled]="!canEdit()"
147465
+ [value]="d.text.color.hex"
147466
+ (change)="edit.emit({ kind: 'textColor', hex: inputValue($event), ref: undefined })"
147467
+ />
147468
+ </label>
147469
+ <pptx-theme-color-swatch-grid
147470
+ [disabled]="!canEdit()"
147471
+ [selectedRef]="d.text.color.ref"
147472
+ [selectedHex]="d.text.color.hex"
147473
+ (pick)="edit.emit({ kind: 'textColor', hex: $event.hex, ref: $event.ref })"
147474
+ />
147475
+ </div>
147476
+
147477
+ <div class="pptx-tse-fields__group">
147478
+ <div class="pptx-tse-fields__hdg">
147479
+ {{ 'pptx.tableStyleEditor.bordersSection' | translate }}
147480
+ </div>
147481
+ @for (side of sides; track side) {
147482
+ <div class="pptx-tse-fields__border-row">
147483
+ <span class="pptx-tse-fields__side-lbl">{{
147484
+ borderSideLabelKeys[side] | translate
147485
+ }}</span>
147486
+ <input
147487
+ type="color"
147488
+ class="pptx-tse-fields__color pptx-tse-fields__color--sm"
147489
+ [disabled]="!canEdit()"
147490
+ [value]="d.borders[side].color.hex"
147491
+ (change)="
147492
+ edit.emit({
147493
+ kind: 'borderColor',
147494
+ side,
147495
+ hex: inputValue($event),
147496
+ ref: undefined,
147497
+ })
147498
+ "
147499
+ />
147500
+ <input
147501
+ type="number"
147502
+ min="0"
147503
+ max="20"
147504
+ class="pptx-tse-fields__num"
147505
+ [disabled]="!canEdit()"
147506
+ [value]="d.borders[side].width"
147507
+ (change)="edit.emit({ kind: 'borderWidth', side, width: inputNumber($event) })"
147508
+ />
147509
+ <select
147510
+ class="pptx-tse-fields__dash"
147511
+ [disabled]="!canEdit()"
147512
+ [value]="d.borders[side].dash"
147513
+ (change)="edit.emit({ kind: 'borderDash', side, dash: inputValue($event) })"
147514
+ >
147515
+ @for (dash of dashPresets; track dash) {
147516
+ <option [value]="dash" [selected]="dash === d.borders[side].dash">
147517
+ {{ dash }}
147518
+ </option>
147519
+ }
147520
+ </select>
147521
+ <label class="pptx-tse-fields__check">
147522
+ <input
147523
+ type="checkbox"
147524
+ [disabled]="!canEdit()"
147525
+ [checked]="d.borders[side].noFill"
147526
+ (change)="edit.emit({ kind: 'borderNone', side, noFill: checkedValue($event) })"
147527
+ />
147528
+ {{ 'pptx.tableStyleEditor.noBorder' | translate }}
147529
+ </label>
147530
+ </div>
147531
+ }
147532
+ </div>
147533
+ }
147534
+ </div>
147535
+ }
147536
+ `, styles: [".pptx-tse-fields{display:flex;flex-direction:column;gap:.5rem}.pptx-tse-fields__group{display:flex;flex-direction:column;gap:.25rem}.pptx-tse-fields__hdg{font-size:10px;text-transform:uppercase;letter-spacing:.03em;color:var(--pptx-inspector-muted, #888)}.pptx-tse-fields__row{display:flex;align-items:center;gap:.5rem;font-size:11px}.pptx-tse-fields__check{display:flex;align-items:center;gap:.25rem;font-size:11px}.pptx-tse-fields__color{height:1.5rem;width:2rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:transparent;cursor:pointer}.pptx-tse-fields__color--sm{width:1.75rem}.pptx-tse-fields__border-row{display:flex;align-items:center;gap:.4rem;font-size:11px}.pptx-tse-fields__side-lbl{width:7rem;flex-shrink:0;color:var(--pptx-inspector-muted, #888)}.pptx-tse-fields__num{width:3rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit}.pptx-tse-fields__dash{border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;background:var(--pptx-inspector-input-bg, #2d2d2d);color:inherit}.pptx-tse-fields__active{background:var(--pptx-inspector-active, #3a3a3a)}\n"] }]
147537
+ }], propDecorators: { descriptor: [{ type: i0.Input, args: [{ isSignal: true, alias: "descriptor", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], edit: [{ type: i0.Output, args: ["edit"] }] } });
147538
+
147539
+ /**
147540
+ * table-style-editor.component.ts: "Edit style..." panel for a table style's
147541
+ * own DEFINITION (`a:tblStyleLst` section fill/text/borders/cell3D), distinct
147542
+ * from `TablePropertiesComponent`'s "which style does this table use" picker.
147543
+ * Angular port of React's `TableStyleEditor.tsx` / Vue's `TableStyleEditor.vue`.
147544
+ *
147545
+ * @module viewer/table-style-editor
147546
+ */
147547
+ class TableStyleEditorComponent {
147548
+ constructor() {
147549
+ this.styleMap = input(undefined, /* @ts-ignore */
147550
+ ...(ngDevMode ? [{ debugName: "styleMap" }] : /* istanbul ignore next */ []));
147551
+ /** The style currently assigned to the table being edited. */
147552
+ this.styleId = input(undefined, /* @ts-ignore */
147553
+ ...(ngDevMode ? [{ debugName: "styleId" }] : /* istanbul ignore next */ []));
147554
+ this.canEdit = input(true, /* @ts-ignore */
147555
+ ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
147556
+ /** Commit a full replacement style map (section edit, create, or delete already applied). */
147557
+ this.styleMapChange = output();
147558
+ /** Record a styleId for save-time removal from `ppt/tableStyles.xml`. */
147559
+ this.deleteStyle = output();
147560
+ /** A newly-created style, for a parent that wants to assign it to the table. */
147561
+ this.assignStyle = output();
147562
+ this.close = output();
147563
+ this.translate = inject(TranslateService);
147564
+ this.loader = inject(LoadContentService, { optional: true });
147565
+ this.parts = TABLE_STYLE_EDITOR_PARTS;
147566
+ this.selectedPart = signal('wholeTbl', /* @ts-ignore */
147567
+ ...(ngDevMode ? [{ debugName: "selectedPart" }] : /* istanbul ignore next */ []));
147568
+ this.activeStyleId = signal('', /* @ts-ignore */
147569
+ ...(ngDevMode ? [{ debugName: "activeStyleId" }] : /* istanbul ignore next */ []));
147570
+ this.entry = computed(() => {
147571
+ const id = this.activeStyleId() || (this.styleId() ? normalizeTableStyleGuid(this.styleId()) : '');
147572
+ return id ? this.styleMap()?.[id] : undefined;
147573
+ }, /* @ts-ignore */
147574
+ ...(ngDevMode ? [{ debugName: "entry" }] : /* istanbul ignore next */ []));
147575
+ this.descriptor = computed(() => describeTableStyleEditor(this.entry(), this.selectedPart(), this.loader?.themeColorMap?.()), /* @ts-ignore */
147576
+ ...(ngDevMode ? [{ debugName: "descriptor" }] : /* istanbul ignore next */ []));
147577
+ }
147578
+ onFieldEdit(fieldEdit) {
147579
+ const entry = this.entry();
147580
+ const map = this.styleMap();
147581
+ if (!entry || !map) {
147582
+ return;
147583
+ }
147584
+ const { entry: nextEntry } = applyTableStyleFieldEdit(entry, this.selectedPart(), fieldEdit);
147585
+ this.styleMapChange.emit({ ...map, [nextEntry.styleId]: nextEntry });
147586
+ }
147587
+ createFromCurrent() {
147588
+ const entry = this.entry();
147589
+ const name = window.prompt(this.translate.instant('pptx.tableStyleEditor.newStyleNamePrompt'), entry ? `${entry.styleName ?? ''} Copy`.trim() : '');
147590
+ if (!name) {
147591
+ return;
147592
+ }
147593
+ const nextMap = { ...(this.styleMap() ?? {}) };
147594
+ const created = createTableStyleEntry(nextMap, { styleName: name, basedOn: entry });
147595
+ addTableStyleToMap(nextMap, created);
147596
+ this.styleMapChange.emit(nextMap);
147597
+ this.activeStyleId.set(created.styleId);
147598
+ this.assignStyle.emit(created.styleId);
147599
+ }
147600
+ handleDelete() {
147601
+ const entry = this.entry();
147602
+ const map = this.styleMap();
147603
+ if (!entry ||
147604
+ !map ||
147605
+ !window.confirm(this.translate.instant('pptx.tableStyleEditor.deleteConfirm'))) {
147606
+ return;
147607
+ }
147608
+ const nextMap = { ...map };
147609
+ deleteTableStyleFromMap(nextMap, entry.styleId);
147610
+ this.styleMapChange.emit(nextMap);
147611
+ this.deleteStyle.emit(entry.styleId);
147612
+ this.close.emit();
147613
+ }
147614
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
147615
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: TableStyleEditorComponent, isStandalone: true, selector: "pptx-table-style-editor", inputs: { styleMap: { classPropertyName: "styleMap", publicName: "styleMap", isSignal: true, isRequired: false, transformFunction: null }, styleId: { classPropertyName: "styleId", publicName: "styleId", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { styleMapChange: "styleMapChange", deleteStyle: "deleteStyle", assignStyle: "assignStyle", close: "close" }, ngImport: i0, template: `
147616
+ <div class="pptx-tse" data-testid="table-style-editor">
147617
+ <div class="pptx-tse__hdr">
147618
+ <div class="pptx-tse__hdg">{{ 'pptx.tableStyleEditor.title' | translate }}</div>
147619
+ <button type="button" class="pptx-tse__btn" (click)="close.emit()">
147620
+ {{ 'pptx.tableStyleEditor.close' | translate }}
147621
+ </button>
147622
+ </div>
147623
+
147624
+ @if (!entry()) {
147625
+ <div class="pptx-tse__empty">{{ 'pptx.tableStyleEditor.noStyleSelected' | translate }}</div>
147626
+ }
147627
+
147628
+ @if (entry()) {
147629
+ <div class="pptx-tse__parts">
147630
+ @for (part of parts; track part.id) {
147631
+ <button
147632
+ type="button"
147633
+ class="pptx-tse__btn"
147634
+ [class.pptx-tse__btn--active]="selectedPart() === part.id"
147635
+ [disabled]="!canEdit()"
147636
+ (click)="selectedPart.set(part.id)"
147637
+ >
147638
+ {{ part.labelKey | translate }}
147639
+ </button>
147640
+ }
147641
+ </div>
147642
+ }
147643
+
147644
+ @if (descriptor(); as d) {
147645
+ <pptx-table-style-editor-fields
147646
+ [descriptor]="d"
147647
+ [canEdit]="canEdit()"
147648
+ (edit)="onFieldEdit($event)"
147649
+ />
147650
+ }
147651
+
147652
+ <div class="pptx-tse__actions">
147653
+ <button
147654
+ type="button"
147655
+ class="pptx-tse__btn"
147656
+ [disabled]="!canEdit()"
147657
+ (click)="createFromCurrent()"
147658
+ >
147659
+ {{
147660
+ (entry() ? 'pptx.tableStyleEditor.newFromCurrent' : 'pptx.tableStyleEditor.newStyle')
147661
+ | translate
147662
+ }}
147663
+ </button>
147664
+ @if (entry()) {
147665
+ <button
147666
+ type="button"
147667
+ class="pptx-tse__btn"
147668
+ [disabled]="!canEdit()"
147669
+ (click)="handleDelete()"
147670
+ >
147671
+ {{ 'pptx.tableStyleEditor.deleteStyle' | translate }}
147672
+ </button>
147673
+ }
147674
+ </div>
147675
+ </div>
147676
+ `, isInline: true, styles: [".pptx-tse{display:flex;flex-direction:column;gap:.5rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:4px;padding:.5rem}.pptx-tse__hdr{display:flex;align-items:center;justify-content:space-between}.pptx-tse__hdg{font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--pptx-inspector-muted, #888)}.pptx-tse__empty{font-size:11px;color:var(--pptx-inspector-muted, #888)}.pptx-tse__parts{display:flex;flex-wrap:wrap;gap:.25rem}.pptx-tse__actions{display:flex;gap:.4rem;padding-top:.25rem;border-top:1px solid var(--pptx-inspector-border, #444)}.pptx-tse__btn{font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 6px;cursor:pointer}.pptx-tse__btn--active{background:var(--pptx-inspector-active, #3a3a3a)}.pptx-tse__btn:disabled{opacity:.4;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: TableStyleEditorFieldsComponent, selector: "pptx-table-style-editor-fields", inputs: ["descriptor", "canEdit"], outputs: ["edit"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
147677
+ }
147678
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorComponent, decorators: [{
147679
+ type: Component,
147680
+ args: [{ selector: 'pptx-table-style-editor', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, TableStyleEditorFieldsComponent], template: `
147681
+ <div class="pptx-tse" data-testid="table-style-editor">
147682
+ <div class="pptx-tse__hdr">
147683
+ <div class="pptx-tse__hdg">{{ 'pptx.tableStyleEditor.title' | translate }}</div>
147684
+ <button type="button" class="pptx-tse__btn" (click)="close.emit()">
147685
+ {{ 'pptx.tableStyleEditor.close' | translate }}
147686
+ </button>
147687
+ </div>
147688
+
147689
+ @if (!entry()) {
147690
+ <div class="pptx-tse__empty">{{ 'pptx.tableStyleEditor.noStyleSelected' | translate }}</div>
147691
+ }
147692
+
147693
+ @if (entry()) {
147694
+ <div class="pptx-tse__parts">
147695
+ @for (part of parts; track part.id) {
147696
+ <button
147697
+ type="button"
147698
+ class="pptx-tse__btn"
147699
+ [class.pptx-tse__btn--active]="selectedPart() === part.id"
147700
+ [disabled]="!canEdit()"
147701
+ (click)="selectedPart.set(part.id)"
147702
+ >
147703
+ {{ part.labelKey | translate }}
147704
+ </button>
147705
+ }
147706
+ </div>
147707
+ }
147708
+
147709
+ @if (descriptor(); as d) {
147710
+ <pptx-table-style-editor-fields
147711
+ [descriptor]="d"
147712
+ [canEdit]="canEdit()"
147713
+ (edit)="onFieldEdit($event)"
147714
+ />
147715
+ }
147716
+
147717
+ <div class="pptx-tse__actions">
147718
+ <button
147719
+ type="button"
147720
+ class="pptx-tse__btn"
147721
+ [disabled]="!canEdit()"
147722
+ (click)="createFromCurrent()"
147723
+ >
147724
+ {{
147725
+ (entry() ? 'pptx.tableStyleEditor.newFromCurrent' : 'pptx.tableStyleEditor.newStyle')
147726
+ | translate
147727
+ }}
147728
+ </button>
147729
+ @if (entry()) {
147730
+ <button
147731
+ type="button"
147732
+ class="pptx-tse__btn"
147733
+ [disabled]="!canEdit()"
147734
+ (click)="handleDelete()"
147735
+ >
147736
+ {{ 'pptx.tableStyleEditor.deleteStyle' | translate }}
147737
+ </button>
147738
+ }
147739
+ </div>
147740
+ </div>
147741
+ `, styles: [".pptx-tse{display:flex;flex-direction:column;gap:.5rem;border:1px solid var(--pptx-inspector-border, #444);border-radius:4px;padding:.5rem}.pptx-tse__hdr{display:flex;align-items:center;justify-content:space-between}.pptx-tse__hdg{font-size:11px;text-transform:uppercase;letter-spacing:.03em;color:var(--pptx-inspector-muted, #888)}.pptx-tse__empty{font-size:11px;color:var(--pptx-inspector-muted, #888)}.pptx-tse__parts{display:flex;flex-wrap:wrap;gap:.25rem}.pptx-tse__actions{display:flex;gap:.4rem;padding-top:.25rem;border-top:1px solid var(--pptx-inspector-border, #444)}.pptx-tse__btn{font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 6px;cursor:pointer}.pptx-tse__btn--active{background:var(--pptx-inspector-active, #3a3a3a)}.pptx-tse__btn:disabled{opacity:.4;cursor:not-allowed}\n"] }]
147742
+ }], propDecorators: { styleMap: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleMap", required: false }] }], styleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleId", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], styleMapChange: [{ type: i0.Output, args: ["styleMapChange"] }], deleteStyle: [{ type: i0.Output, args: ["deleteStyle"] }], assignStyle: [{ type: i0.Output, args: ["assignStyle"] }], close: [{ type: i0.Output, args: ["close"] }] } });
147743
+
147744
+ /**
147745
+ * table-style-editor-launcher.component.ts: the "Edit style..." button +
147746
+ * open/close state for `TableStyleEditorComponent`, extracted so
147747
+ * `TablePropertiesComponent` (already over this repo's 300-LOC file budget)
147748
+ * gains only a single wiring line rather than growing further.
147749
+ *
147750
+ * @module viewer/table-style-editor-launcher
147751
+ */
147752
+ class TableStyleEditorLauncherComponent {
147753
+ constructor() {
147754
+ this.tableStyleMap = input(undefined, /* @ts-ignore */
147755
+ ...(ngDevMode ? [{ debugName: "tableStyleMap" }] : /* istanbul ignore next */ []));
147756
+ this.styleId = input(undefined, /* @ts-ignore */
147757
+ ...(ngDevMode ? [{ debugName: "styleId" }] : /* istanbul ignore next */ []));
147758
+ this.canEdit = input(true, /* @ts-ignore */
147759
+ ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
147760
+ this.tableStyleMapChange = output();
147761
+ this.deleteTableStyle = output();
147762
+ /** A newly-created style, for a parent that wants to assign it to the table. */
147763
+ this.assignStyle = output();
147764
+ this.open = signal(false, /* @ts-ignore */
147765
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
147766
+ }
147767
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorLauncherComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
147768
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: TableStyleEditorLauncherComponent, isStandalone: true, selector: "pptx-table-style-editor-launcher", inputs: { tableStyleMap: { classPropertyName: "tableStyleMap", publicName: "tableStyleMap", isSignal: true, isRequired: false, transformFunction: null }, styleId: { classPropertyName: "styleId", publicName: "styleId", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { tableStyleMapChange: "tableStyleMapChange", deleteTableStyle: "deleteTableStyle", assignStyle: "assignStyle" }, ngImport: i0, template: `
147769
+ @if (tableStyleMap() !== undefined) {
147770
+ <button
147771
+ type="button"
147772
+ class="pptx-tsel__btn"
147773
+ [disabled]="!canEdit()"
147774
+ (click)="open.set(!open())"
147775
+ >
147776
+ {{ 'pptx.tableStyleEditor.editButton' | translate }}
147777
+ </button>
147778
+
147779
+ @if (open()) {
147780
+ <pptx-table-style-editor
147781
+ [styleMap]="tableStyleMap()"
147782
+ [styleId]="styleId()"
147783
+ [canEdit]="canEdit()"
147784
+ (styleMapChange)="tableStyleMapChange.emit($event)"
147785
+ (deleteStyle)="deleteTableStyle.emit($event)"
147786
+ (assignStyle)="assignStyle.emit($event)"
147787
+ (close)="open.set(false)"
147788
+ />
147789
+ }
147790
+ }
147791
+ `, isInline: true, styles: [".pptx-tsel__btn{margin-top:.35rem;align-self:flex-start;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 6px;cursor:pointer}.pptx-tsel__btn:disabled{opacity:.4;cursor:not-allowed}\n"], dependencies: [{ kind: "component", type: TableStyleEditorComponent, selector: "pptx-table-style-editor", inputs: ["styleMap", "styleId", "canEdit"], outputs: ["styleMapChange", "deleteStyle", "assignStyle", "close"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
147792
+ }
147793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TableStyleEditorLauncherComponent, decorators: [{
147794
+ type: Component,
147795
+ args: [{ selector: 'pptx-table-style-editor-launcher', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, TableStyleEditorComponent], template: `
147796
+ @if (tableStyleMap() !== undefined) {
147797
+ <button
147798
+ type="button"
147799
+ class="pptx-tsel__btn"
147800
+ [disabled]="!canEdit()"
147801
+ (click)="open.set(!open())"
147802
+ >
147803
+ {{ 'pptx.tableStyleEditor.editButton' | translate }}
147804
+ </button>
147805
+
147806
+ @if (open()) {
147807
+ <pptx-table-style-editor
147808
+ [styleMap]="tableStyleMap()"
147809
+ [styleId]="styleId()"
147810
+ [canEdit]="canEdit()"
147811
+ (styleMapChange)="tableStyleMapChange.emit($event)"
147812
+ (deleteStyle)="deleteTableStyle.emit($event)"
147813
+ (assignStyle)="assignStyle.emit($event)"
147814
+ (close)="open.set(false)"
147815
+ />
147816
+ }
147817
+ }
147818
+ `, styles: [".pptx-tsel__btn{margin-top:.35rem;align-self:flex-start;font-size:11px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 6px;cursor:pointer}.pptx-tsel__btn:disabled{opacity:.4;cursor:not-allowed}\n"] }]
147819
+ }], propDecorators: { tableStyleMap: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableStyleMap", required: false }] }], styleId: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleId", required: false }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], tableStyleMapChange: [{ type: i0.Output, args: ["tableStyleMapChange"] }], deleteTableStyle: [{ type: i0.Output, args: ["deleteTableStyle"] }], assignStyle: [{ type: i0.Output, args: ["assignStyle"] }] } });
147820
+
145658
147821
  /**
145659
147822
  * table-properties.component.ts: table-level style inspector.
145660
147823
  *
@@ -145679,6 +147842,16 @@ class TablePropertiesComponent {
145679
147842
  ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
145680
147843
  /** Emits the fully-updated element after any edit. */
145681
147844
  this.elementChange = output();
147845
+ /**
147846
+ * The deck's parsed `ppt/tableStyles.xml` map, for "Edit style...". `undefined`
147847
+ * means the host has not wired the table-style-editor feature through; the
147848
+ * launcher then simply does not render its button.
147849
+ */
147850
+ this.tableStyleMap = input(undefined, /* @ts-ignore */
147851
+ ...(ngDevMode ? [{ debugName: "tableStyleMap" }] : /* istanbul ignore next */ []));
147852
+ this.tableStyleMapChange = output();
147853
+ /** Record a styleId for save-time removal from `ppt/tableStyles.xml`. */
147854
+ this.deleteTableStyle = output();
145682
147855
  this.toggles = TABLE_STRUCTURE_TOGGLES;
145683
147856
  this.presets = TABLE_STYLE_PRESETS;
145684
147857
  this.defaultRowHeight = DEFAULT_TABLE_ROW_HEIGHT;
@@ -145735,11 +147908,15 @@ class TablePropertiesComponent {
145735
147908
  const rows = data.rows.map((r, i) => (i === index ? { ...r, height: n } : r));
145736
147909
  this.emit({ rows });
145737
147910
  }
147911
+ /** A newly-created style (from "Edit style...") becomes this table's style. */
147912
+ onAssignStyle(styleId) {
147913
+ this.emit(tableStyleAssignmentUpdate(styleId));
147914
+ }
145738
147915
  emit(patch) {
145739
147916
  this.elementChange.emit(patchTableData(this.element(), patch));
145740
147917
  }
145741
147918
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TablePropertiesComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
145742
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: TablePropertiesComponent, isStandalone: true, selector: "pptx-table-properties", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange" }, ngImport: i0, template: `
147919
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: TablePropertiesComponent, isStandalone: true, selector: "pptx-table-properties", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, tableStyleMap: { classPropertyName: "tableStyleMap", publicName: "tableStyleMap", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { elementChange: "elementChange", tableStyleMapChange: "tableStyleMapChange", deleteTableStyle: "deleteTableStyle" }, ngImport: i0, template: `
145743
147920
  @if (td(); as data) {
145744
147921
  <div class="pptx-tp">
145745
147922
  <div class="pptx-tp__dims">{{ data.rows.length }} rows × {{ colCount() }} cols</div>
@@ -145803,6 +147980,14 @@ class TablePropertiesComponent {
145803
147980
  </button>
145804
147981
  }
145805
147982
  </div>
147983
+ <pptx-table-style-editor-launcher
147984
+ [tableStyleMap]="tableStyleMap()"
147985
+ [styleId]="data.tableStyleId"
147986
+ [canEdit]="canEdit()"
147987
+ (tableStyleMapChange)="tableStyleMapChange.emit($event)"
147988
+ (deleteTableStyle)="deleteTableStyle.emit($event)"
147989
+ (assignStyle)="onAssignStyle($event)"
147990
+ />
145806
147991
 
145807
147992
  <div class="pptx-tp__row-head">
145808
147993
  <span class="pptx-tp__lbl">{{ 'pptx.table.columnWidths' | translate }}</span>
@@ -145859,11 +148044,11 @@ class TablePropertiesComponent {
145859
148044
  }
145860
148045
  </div>
145861
148046
  }
145862
- `, isInline: true, styles: [".pptx-tp{display:flex;flex-direction:column;gap:.35rem}.pptx-tp__dims{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__toggles{display:flex;flex-direction:column;gap:.2rem}.pptx-tp__check{display:flex;align-items:center;gap:.4rem;font-size:11px;cursor:pointer}.pptx-tp__field{display:flex;align-items:center;gap:.35rem;font-size:11px}.pptx-tp__row-head{display:flex;align-items:center;justify-content:space-between}.pptx-tp__lbl{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__idx{width:1.2rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__num{width:3.5rem;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 4px;font-size:11px}.pptx-tp__range{flex:1;min-width:0}.pptx-tp__pct{width:2.5rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__even{font-size:10px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:1px 6px;cursor:pointer}.pptx-tp__presets{display:grid;grid-template-columns:repeat(3,1fr);gap:.3rem}.pptx-tp__preset{display:flex;flex-direction:column;height:2.5rem;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;overflow:hidden;cursor:pointer}.pptx-tp__preset:disabled{opacity:.4;cursor:not-allowed}.pptx-tp__swatch{flex:1;display:block}\n"], dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
148047
+ `, isInline: true, styles: [".pptx-tp{display:flex;flex-direction:column;gap:.35rem}.pptx-tp__dims{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__toggles{display:flex;flex-direction:column;gap:.2rem}.pptx-tp__check{display:flex;align-items:center;gap:.4rem;font-size:11px;cursor:pointer}.pptx-tp__field{display:flex;align-items:center;gap:.35rem;font-size:11px}.pptx-tp__row-head{display:flex;align-items:center;justify-content:space-between}.pptx-tp__lbl{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__idx{width:1.2rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__num{width:3.5rem;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 4px;font-size:11px}.pptx-tp__range{flex:1;min-width:0}.pptx-tp__pct{width:2.5rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__even{font-size:10px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:1px 6px;cursor:pointer}.pptx-tp__presets{display:grid;grid-template-columns:repeat(3,1fr);gap:.3rem}.pptx-tp__preset{display:flex;flex-direction:column;height:2.5rem;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;overflow:hidden;cursor:pointer}.pptx-tp__preset:disabled{opacity:.4;cursor:not-allowed}.pptx-tp__swatch{flex:1;display:block}\n"], dependencies: [{ kind: "component", type: TableStyleEditorLauncherComponent, selector: "pptx-table-style-editor-launcher", inputs: ["tableStyleMap", "styleId", "canEdit"], outputs: ["tableStyleMapChange", "deleteTableStyle", "assignStyle"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
145863
148048
  }
145864
148049
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: TablePropertiesComponent, decorators: [{
145865
148050
  type: Component,
145866
- args: [{ selector: 'pptx-table-properties', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe], template: `
148051
+ args: [{ selector: 'pptx-table-properties', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, TableStyleEditorLauncherComponent], template: `
145867
148052
  @if (td(); as data) {
145868
148053
  <div class="pptx-tp">
145869
148054
  <div class="pptx-tp__dims">{{ data.rows.length }} rows × {{ colCount() }} cols</div>
@@ -145927,6 +148112,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
145927
148112
  </button>
145928
148113
  }
145929
148114
  </div>
148115
+ <pptx-table-style-editor-launcher
148116
+ [tableStyleMap]="tableStyleMap()"
148117
+ [styleId]="data.tableStyleId"
148118
+ [canEdit]="canEdit()"
148119
+ (tableStyleMapChange)="tableStyleMapChange.emit($event)"
148120
+ (deleteTableStyle)="deleteTableStyle.emit($event)"
148121
+ (assignStyle)="onAssignStyle($event)"
148122
+ />
145930
148123
 
145931
148124
  <div class="pptx-tp__row-head">
145932
148125
  <span class="pptx-tp__lbl">{{ 'pptx.table.columnWidths' | translate }}</span>
@@ -145984,7 +148177,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
145984
148177
  </div>
145985
148178
  }
145986
148179
  `, styles: [".pptx-tp{display:flex;flex-direction:column;gap:.35rem}.pptx-tp__dims{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__toggles{display:flex;flex-direction:column;gap:.2rem}.pptx-tp__check{display:flex;align-items:center;gap:.4rem;font-size:11px;cursor:pointer}.pptx-tp__field{display:flex;align-items:center;gap:.35rem;font-size:11px}.pptx-tp__row-head{display:flex;align-items:center;justify-content:space-between}.pptx-tp__lbl{font-size:10px;color:var(--pptx-inspector-muted, #888)}.pptx-tp__idx{width:1.2rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__num{width:3.5rem;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 4px;font-size:11px}.pptx-tp__range{flex:1;min-width:0}.pptx-tp__pct{width:2.5rem;text-align:right;color:var(--pptx-inspector-muted, #888)}.pptx-tp__even{font-size:10px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:1px 6px;cursor:pointer}.pptx-tp__presets{display:grid;grid-template-columns:repeat(3,1fr);gap:.3rem}.pptx-tp__preset{display:flex;flex-direction:column;height:2.5rem;padding:0;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;overflow:hidden;cursor:pointer}.pptx-tp__preset:disabled{opacity:.4;cursor:not-allowed}.pptx-tp__swatch{flex:1;display:block}\n"] }]
145987
- }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }] } });
148180
+ }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], elementChange: [{ type: i0.Output, args: ["elementChange"] }], tableStyleMap: [{ type: i0.Input, args: [{ isSignal: true, alias: "tableStyleMap", required: false }] }], tableStyleMapChange: [{ type: i0.Output, args: ["tableStyleMapChange"] }], deleteTableStyle: [{ type: i0.Output, args: ["deleteTableStyle"] }] } });
145988
148181
  function numberFrom(event) {
145989
148182
  const t = event.target;
145990
148183
  if (!(t instanceof HTMLInputElement)) {
@@ -147131,6 +149324,12 @@ class InspectorPanelComponent {
147131
149324
  this.canEdit = input(true, /* @ts-ignore */
147132
149325
  ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
147133
149326
  this.editor = inject(EditorStateService);
149327
+ /**
149328
+ * Optional: absent in a standalone-thumbnail/export render context.
149329
+ * Feeds the table properties panel's "Edit style..." (`tableStyleMap`),
149330
+ * see {@link onTableStyleMapChange} / {@link onDeleteTableStyle}.
149331
+ */
149332
+ this.loader = inject(LoadContentService, { optional: true });
147134
149333
  /** Reactive viewport / pointer flags (drives the bottom-sheet layout). */
147135
149334
  this.mobile = inject(IsMobileService);
147136
149335
  /** "Recent colours" row backing the fill/stroke/text colour pickers below. */
@@ -147235,6 +149434,17 @@ class InspectorPanelComponent {
147235
149434
  ...(ngDevMode ? [{ debugName: "chartEl" }] : /* istanbul ignore next */ []));
147236
149435
  this.imageEl = computed(() => ImagePropertiesPanelComponent.supports(this.el()) ? this.el() : undefined, /* @ts-ignore */
147237
149436
  ...(ngDevMode ? [{ debugName: "imageEl" }] : /* istanbul ignore next */ []));
149437
+ /**
149438
+ * The selected element narrowed to a plain shape/text box/connector, or
149439
+ * `undefined`. Gates `AccessibilityTextPanelComponent` (alt text / title):
149440
+ * a picture's own alt text lives in `imageEl` above, so this must not
149441
+ * also match `image`/`picture`, and stays restricted to the three kinds
149442
+ * `PptxNonVisualDescription` was added to (not every graphic-frame kind
149443
+ * the shared descriptor recognises), so it does not duplicate a
149444
+ * table/chart/smartArt/media/ole panel's own alt-text UI.
149445
+ */
149446
+ this.accessibilityTextEl = computed(() => AccessibilityTextPanelComponent.supports(this.el()) ? this.el() : undefined, /* @ts-ignore */
149447
+ ...(ngDevMode ? [{ debugName: "accessibilityTextEl" }] : /* istanbul ignore next */ []));
147238
149448
  this.mediaEl = computed(() => this.el().type === 'media' ? this.el() : undefined, /* @ts-ignore */
147239
149449
  ...(ngDevMode ? [{ debugName: "mediaEl" }] : /* istanbul ignore next */ []));
147240
149450
  /** The selected element narrowed to SmartArt, or undefined. */
@@ -147281,6 +149491,40 @@ class InspectorPanelComponent {
147281
149491
  onElementReplace(updated) {
147282
149492
  this.editor.updateElement(this.slideIndex(), updated.id, updated);
147283
149493
  }
149494
+ /**
149495
+ * Table style DEFINITION edits ("Edit style...") are a whole-map
149496
+ * replacement or a delete, never a per-element patch, so they bypass
149497
+ * {@link onElementReplace} entirely and write straight to the loader's
149498
+ * `tableStyleMap`/`tableStylesToDelete` signals. `applyTableStyleMapChange`/
149499
+ * `applyTableStyleDelete` (shared) keep `tableStylesToDelete` in sync, the
149500
+ * accumulator {@link LoadContentService.saveSlides} forwards via
149501
+ * `tableStyleSaveOptions`.
149502
+ */
149503
+ onTableStyleMapChange(nextMap) {
149504
+ if (!this.loader) {
149505
+ return;
149506
+ }
149507
+ const result = applyTableStyleMapChange({
149508
+ tableStyleMap: this.loader.tableStyleMap(),
149509
+ tableStylesToDelete: this.loader.tableStylesToDelete(),
149510
+ }, nextMap);
149511
+ this.loader.tableStyleMap.set(result.tableStyleMap);
149512
+ this.loader.tableStylesToDelete.set(result.tableStylesToDelete);
149513
+ this.editor.dirty.set(true);
149514
+ }
149515
+ /** Record a styleId for save-time removal from `ppt/tableStyles.xml`. */
149516
+ onDeleteTableStyle(styleId) {
149517
+ if (!this.loader) {
149518
+ return;
149519
+ }
149520
+ const result = applyTableStyleDelete({
149521
+ tableStyleMap: this.loader.tableStyleMap(),
149522
+ tableStylesToDelete: this.loader.tableStylesToDelete(),
149523
+ }, styleId);
149524
+ this.loader.tableStyleMap.set(result.tableStyleMap);
149525
+ this.loader.tableStylesToDelete.set(result.tableStylesToDelete);
149526
+ this.editor.dirty.set(true);
149527
+ }
147284
149528
  /** Commit an updated slide-level animation list as one history entry. */
147285
149529
  onAnimationsChange(animations) {
147286
149530
  this.editor.updateSlide(this.slideIndex(), { animations });
@@ -147670,6 +149914,15 @@ class InspectorPanelComponent {
147670
149914
  </details>
147671
149915
  }
147672
149916
 
149917
+ @if (accessibilityTextEl(); as a11yEl) {
149918
+ <details class="pptx-ng-inspector__details" open>
149919
+ <summary class="pptx-ng-inspector__summary">
149920
+ {{ 'pptx.accessibility.heading' | translate }}
149921
+ </summary>
149922
+ <pptx-accessibility-text-panel [element]="a11yEl" (patch)="onPatch($event)" />
149923
+ </details>
149924
+ }
149925
+
147673
149926
  <!-- ── Arrange ────────────────────────────────────────────────────── -->
147674
149927
  <section class="pptx-ng-inspector__section">
147675
149928
  <div
@@ -147781,7 +150034,8 @@ class InspectorPanelComponent {
147781
150034
 
147782
150035
  <!-- ── Table data editor ──────────────────────────────────────────── -->
147783
150036
  @if (tableEl(); as t) {
147784
- <details class="pptx-ng-inspector__details">
150037
+ <!-- Open by default, as the other four bindings show these two sections. -->
150038
+ <details class="pptx-ng-inspector__details" open>
147785
150039
  <summary class="pptx-ng-inspector__summary">
147786
150040
  {{ 'pptx.inspector.tableData' | translate }}
147787
150041
  </summary>
@@ -147789,11 +150043,17 @@ class InspectorPanelComponent {
147789
150043
  </details>
147790
150044
 
147791
150045
  <!-- ── Table style (structure, presets, widths, heights) ─────────── -->
147792
- <details class="pptx-ng-inspector__details">
150046
+ <details class="pptx-ng-inspector__details" open>
147793
150047
  <summary class="pptx-ng-inspector__summary">
147794
150048
  {{ 'pptx.inspector.tableStyle' | translate }}
147795
150049
  </summary>
147796
- <pptx-table-properties [element]="t" (elementChange)="onElementReplace($event)" />
150050
+ <pptx-table-properties
150051
+ [element]="t"
150052
+ [tableStyleMap]="loader?.tableStyleMap()"
150053
+ (elementChange)="onElementReplace($event)"
150054
+ (tableStyleMapChange)="onTableStyleMapChange($event)"
150055
+ (deleteTableStyle)="onDeleteTableStyle($event)"
150056
+ />
147797
150057
  </details>
147798
150058
 
147799
150059
  <!-- ── Selected cell formatting ─────────────────────────────────── -->
@@ -147886,11 +150146,12 @@ class InspectorPanelComponent {
147886
150146
  </div>
147887
150147
  </section>
147888
150148
  </aside>
147889
- `, isInline: true, styles: [".pptx-ng-inspector{display:flex;flex-direction:column;gap:0;padding:.5rem;background:var(--pptx-inspector-bg, #1e1e1e);color:var(--pptx-inspector-fg, #e0e0e0);font-size:12px;min-width:220px;overflow-y:auto}.pptx-ng-inspector__section{padding:.5rem 0;border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-ng-inspector__section:last-child{border-bottom:none}.pptx-ng-inspector__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0 0 .35rem}.pptx-ng-inspector__details{border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-ng-inspector__summary{padding:.5rem 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-inspector__row{display:flex;align-items:center;gap:.35rem;margin-bottom:.35rem}.pptx-ng-inspector__row:last-child{margin-bottom:0}.pptx-ng-inspector__row--toggles{gap:.25rem}.pptx-ng-inspector__label{font-size:10px;color:var(--pptx-inspector-muted, #888);min-width:32px;text-align:right;flex-shrink:0}.pptx-ng-inspector__input{background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 4px;font-size:12px}.pptx-ng-inspector__input--number{width:62px;text-align:right}.pptx-ng-inspector__color{width:32px;height:22px;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;padding:1px;cursor:pointer;background:transparent;flex-shrink:0}.pptx-ng-inspector__toggle{width:26px;height:22px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px}.pptx-ng-inspector.is-mobile{width:100%;min-width:0;box-sizing:border-box;font-size:14px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__row{flex-wrap:wrap;gap:.5rem}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__label{min-width:28px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__input{flex:1 1 auto;min-height:40px;font-size:16px;padding:6px 8px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__input--number{width:auto;min-width:72px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__color{width:44px;height:40px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__toggle{min-width:44px;width:auto;flex:1 1 auto;height:40px;font-size:15px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__btn{min-height:40px;padding:8px 10px;font-size:13px}@media(pointer:coarse),(max-width:767px){.pptx-ng-inspector{width:100%;min-width:0;box-sizing:border-box;font-size:14px}.pptx-ng-inspector__row{flex-wrap:wrap;gap:.5rem}.pptx-ng-inspector__label{min-width:28px}.pptx-ng-inspector__input{flex:1 1 auto;min-height:40px;font-size:16px;padding:6px 8px}.pptx-ng-inspector__input--number{width:auto;min-width:72px}.pptx-ng-inspector__color{width:44px;height:40px}.pptx-ng-inspector__toggle{min-width:44px;width:auto;flex:1 1 auto;height:40px;font-size:15px}.pptx-ng-inspector__btn{min-height:40px;padding:8px 10px;font-size:13px}}.pptx-ng-inspector__toggle.is-active{background:var(--pptx-inspector-active, #0078d4);border-color:var(--pptx-inspector-active, #0078d4);color:#fff}.pptx-ng-inspector__btn{flex:1;padding:3px 6px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;font-size:11px;white-space:nowrap}.pptx-ng-inspector__btn:hover{background:var(--pptx-inspector-hover, #3a3a3a)}.pptx-ng-inspector__btn--danger{color:var(--pptx-inspector-danger, #f47c7c);border-color:var(--pptx-inspector-danger-border, #6b2a2a)}.pptx-ng-inspector__btn--danger:hover{background:var(--pptx-inspector-danger-hover, #4a1a1a)}\n"], dependencies: [{ kind: "component", type: GradientPickerComponent, selector: "pptx-gradient-picker", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: EffectsPanelComponent, selector: "pptx-effects-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: LineFormatPanelComponent, selector: "pptx-line-format-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: PatternFillPanelComponent, selector: "pptx-pattern-fill-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TextAdvancedPanelComponent, selector: "pptx-text-advanced-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TableDataEditorComponent, selector: "pptx-table-data-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: TablePropertiesComponent, selector: "pptx-table-properties", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: TableCellFormattingComponent, selector: "pptx-table-cell-formatting", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartDataEditorComponent, selector: "pptx-chart-data-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartTypeSelectorComponent, selector: "pptx-chart-type-selector", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: SmartArtPropertiesComponent, selector: "pptx-smart-art-properties", inputs: ["smartArtData", "canEdit"], outputs: ["smartArtDataChange"] }, { kind: "component", type: AnimationAuthorPanelComponent, selector: "pptx-animation-author-panel", inputs: ["element", "slideIndex", "animations", "slideElements", "animationTimelineAnchors", "canEdit"], outputs: ["animationsChange"] }, { kind: "component", type: ActionSettingsPanelComponent, selector: "pptx-action-settings-panel", inputs: ["element", "slideCount"], outputs: ["patch"] }, { kind: "component", type: ImagePropertiesPanelComponent, selector: "pptx-image-properties-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: MediaPropertiesPanelComponent, selector: "pptx-media-properties-panel", inputs: ["element", "canEdit"], outputs: ["patch"] }, { kind: "component", type: ElementMiscPropertiesComponent, selector: "pptx-element-misc-properties", inputs: ["element", "canEdit"], outputs: ["patch"] }, { kind: "component", type: ElementFlipControlsComponent, selector: "pptx-element-flip-controls", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: ShapeAuthoringPanelComponent, selector: "pptx-shape-authoring-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: Text3DPanelComponent, selector: "pptx-text-3d-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TextWarpGalleryComponent, selector: "pptx-text-warp-gallery", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: RecentColorsRowComponent, selector: "pptx-recent-colors-row", inputs: ["colors", "disabled"], outputs: ["pick"] }, { kind: "component", type: ThemeColorSwatchGridComponent, selector: "pptx-theme-color-swatch-grid", inputs: ["disabled", "selectedRef", "selectedHex"], outputs: ["pick"] }, { kind: "component", type: LucideArrowUp, selector: "svg[lucideArrowUp]" }, { kind: "component", type: LucideArrowDown, selector: "svg[lucideArrowDown]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
150149
+ `, isInline: true, styles: [".pptx-ng-inspector{display:flex;flex-direction:column;gap:0;padding:.5rem;background:var(--pptx-inspector-bg, #1e1e1e);color:var(--pptx-inspector-fg, #e0e0e0);font-size:12px;min-width:220px;overflow-y:auto}.pptx-ng-inspector__section{padding:.5rem 0;border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-ng-inspector__section:last-child{border-bottom:none}.pptx-ng-inspector__heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0 0 .35rem}.pptx-ng-inspector__details{border-bottom:1px solid var(--pptx-inspector-border, #333)}.pptx-ng-inspector__summary{padding:.5rem 0;font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);cursor:pointer;-webkit-user-select:none;user-select:none}.pptx-ng-inspector__row{display:flex;align-items:center;gap:.35rem;margin-bottom:.35rem}.pptx-ng-inspector__row:last-child{margin-bottom:0}.pptx-ng-inspector__row--toggles{gap:.25rem}.pptx-ng-inspector__label{font-size:10px;color:var(--pptx-inspector-muted, #888);min-width:32px;text-align:right;flex-shrink:0}.pptx-ng-inspector__input{background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;padding:2px 4px;font-size:12px}.pptx-ng-inspector__input--number{width:62px;text-align:right}.pptx-ng-inspector__color{width:32px;height:22px;border:1px solid var(--pptx-inspector-border, #444);border-radius:3px;padding:1px;cursor:pointer;background:transparent;flex-shrink:0}.pptx-ng-inspector__toggle{width:26px;height:22px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;display:flex;align-items:center;justify-content:center;font-size:12px}.pptx-ng-inspector.is-mobile{width:100%;min-width:0;box-sizing:border-box;font-size:14px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__row{flex-wrap:wrap;gap:.5rem}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__label{min-width:28px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__input{flex:1 1 auto;min-height:40px;font-size:16px;padding:6px 8px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__input--number{width:auto;min-width:72px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__color{width:44px;height:40px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__toggle{min-width:44px;width:auto;flex:1 1 auto;height:40px;font-size:15px}.pptx-ng-inspector.is-mobile .pptx-ng-inspector__btn{min-height:40px;padding:8px 10px;font-size:13px}@media(pointer:coarse),(max-width:767px){.pptx-ng-inspector{width:100%;min-width:0;box-sizing:border-box;font-size:14px}.pptx-ng-inspector__row{flex-wrap:wrap;gap:.5rem}.pptx-ng-inspector__label{min-width:28px}.pptx-ng-inspector__input{flex:1 1 auto;min-height:40px;font-size:16px;padding:6px 8px}.pptx-ng-inspector__input--number{width:auto;min-width:72px}.pptx-ng-inspector__color{width:44px;height:40px}.pptx-ng-inspector__toggle{min-width:44px;width:auto;flex:1 1 auto;height:40px;font-size:15px}.pptx-ng-inspector__btn{min-height:40px;padding:8px 10px;font-size:13px}}.pptx-ng-inspector__toggle.is-active{background:var(--pptx-inspector-active, #0078d4);border-color:var(--pptx-inspector-active, #0078d4);color:#fff}.pptx-ng-inspector__btn{flex:1;padding:3px 6px;background:var(--pptx-inspector-input-bg, #2d2d2d);border:1px solid var(--pptx-inspector-border, #444);color:inherit;border-radius:3px;cursor:pointer;font-size:11px;white-space:nowrap}.pptx-ng-inspector__btn:hover{background:var(--pptx-inspector-hover, #3a3a3a)}.pptx-ng-inspector__btn--danger{color:var(--pptx-inspector-danger, #f47c7c);border-color:var(--pptx-inspector-danger-border, #6b2a2a)}.pptx-ng-inspector__btn--danger:hover{background:var(--pptx-inspector-danger-hover, #4a1a1a)}\n"], dependencies: [{ kind: "component", type: AccessibilityTextPanelComponent, selector: "pptx-accessibility-text-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: GradientPickerComponent, selector: "pptx-gradient-picker", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: EffectsPanelComponent, selector: "pptx-effects-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: LineFormatPanelComponent, selector: "pptx-line-format-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: PatternFillPanelComponent, selector: "pptx-pattern-fill-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TextAdvancedPanelComponent, selector: "pptx-text-advanced-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TableDataEditorComponent, selector: "pptx-table-data-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: TablePropertiesComponent, selector: "pptx-table-properties", inputs: ["element", "canEdit", "tableStyleMap"], outputs: ["elementChange", "tableStyleMapChange", "deleteTableStyle"] }, { kind: "component", type: TableCellFormattingComponent, selector: "pptx-table-cell-formatting", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartDataEditorComponent, selector: "pptx-chart-data-editor", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: ChartTypeSelectorComponent, selector: "pptx-chart-type-selector", inputs: ["element", "canEdit"], outputs: ["elementChange"] }, { kind: "component", type: SmartArtPropertiesComponent, selector: "pptx-smart-art-properties", inputs: ["smartArtData", "canEdit"], outputs: ["smartArtDataChange"] }, { kind: "component", type: AnimationAuthorPanelComponent, selector: "pptx-animation-author-panel", inputs: ["element", "slideIndex", "animations", "slideElements", "animationTimelineAnchors", "canEdit"], outputs: ["animationsChange"] }, { kind: "component", type: ActionSettingsPanelComponent, selector: "pptx-action-settings-panel", inputs: ["element", "slideCount"], outputs: ["patch"] }, { kind: "component", type: ImagePropertiesPanelComponent, selector: "pptx-image-properties-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: MediaPropertiesPanelComponent, selector: "pptx-media-properties-panel", inputs: ["element", "canEdit"], outputs: ["patch"] }, { kind: "component", type: ElementMiscPropertiesComponent, selector: "pptx-element-misc-properties", inputs: ["element", "canEdit"], outputs: ["patch"] }, { kind: "component", type: ElementFlipControlsComponent, selector: "pptx-element-flip-controls", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: ShapeAuthoringPanelComponent, selector: "pptx-shape-authoring-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: Text3DPanelComponent, selector: "pptx-text-3d-panel", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: TextWarpGalleryComponent, selector: "pptx-text-warp-gallery", inputs: ["element"], outputs: ["patch"] }, { kind: "component", type: RecentColorsRowComponent, selector: "pptx-recent-colors-row", inputs: ["colors", "disabled"], outputs: ["pick"] }, { kind: "component", type: ThemeColorSwatchGridComponent, selector: "pptx-theme-color-swatch-grid", inputs: ["disabled", "selectedRef", "selectedHex"], outputs: ["pick"] }, { kind: "component", type: LucideArrowUp, selector: "svg[lucideArrowUp]" }, { kind: "component", type: LucideArrowDown, selector: "svg[lucideArrowDown]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
147890
150150
  }
147891
150151
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: InspectorPanelComponent, decorators: [{
147892
150152
  type: Component,
147893
150153
  args: [{ selector: 'pptx-inspector-panel', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [
150154
+ AccessibilityTextPanelComponent,
147894
150155
  GradientPickerComponent,
147895
150156
  EffectsPanelComponent,
147896
150157
  LineFormatPanelComponent,
@@ -148177,6 +150438,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
148177
150438
  </details>
148178
150439
  }
148179
150440
 
150441
+ @if (accessibilityTextEl(); as a11yEl) {
150442
+ <details class="pptx-ng-inspector__details" open>
150443
+ <summary class="pptx-ng-inspector__summary">
150444
+ {{ 'pptx.accessibility.heading' | translate }}
150445
+ </summary>
150446
+ <pptx-accessibility-text-panel [element]="a11yEl" (patch)="onPatch($event)" />
150447
+ </details>
150448
+ }
150449
+
148180
150450
  <!-- ── Arrange ────────────────────────────────────────────────────── -->
148181
150451
  <section class="pptx-ng-inspector__section">
148182
150452
  <div
@@ -148288,7 +150558,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
148288
150558
 
148289
150559
  <!-- ── Table data editor ──────────────────────────────────────────── -->
148290
150560
  @if (tableEl(); as t) {
148291
- <details class="pptx-ng-inspector__details">
150561
+ <!-- Open by default, as the other four bindings show these two sections. -->
150562
+ <details class="pptx-ng-inspector__details" open>
148292
150563
  <summary class="pptx-ng-inspector__summary">
148293
150564
  {{ 'pptx.inspector.tableData' | translate }}
148294
150565
  </summary>
@@ -148296,11 +150567,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
148296
150567
  </details>
148297
150568
 
148298
150569
  <!-- ── Table style (structure, presets, widths, heights) ─────────── -->
148299
- <details class="pptx-ng-inspector__details">
150570
+ <details class="pptx-ng-inspector__details" open>
148300
150571
  <summary class="pptx-ng-inspector__summary">
148301
150572
  {{ 'pptx.inspector.tableStyle' | translate }}
148302
150573
  </summary>
148303
- <pptx-table-properties [element]="t" (elementChange)="onElementReplace($event)" />
150574
+ <pptx-table-properties
150575
+ [element]="t"
150576
+ [tableStyleMap]="loader?.tableStyleMap()"
150577
+ (elementChange)="onElementReplace($event)"
150578
+ (tableStyleMapChange)="onTableStyleMapChange($event)"
150579
+ (deleteTableStyle)="onDeleteTableStyle($event)"
150580
+ />
148304
150581
  </details>
148305
150582
 
148306
150583
  <!-- ── Selected cell formatting ─────────────────────────────────── -->
@@ -159028,6 +161305,10 @@ class PowerPointViewerComponent {
159028
161305
  getCustomProperties: () => this.loader.customProperties(),
159029
161306
  getCoreProperties: () => this.loader.coreProperties(),
159030
161307
  getAppProperties: () => this.loader.appProperties(),
161308
+ getViewProperties: () => this.loader.viewProperties(),
161309
+ getTableStyleMap: () => this.loader.tableStyleMap(),
161310
+ getTableStylesDefaultId: () => this.loader.tableStylesDefaultId(),
161311
+ getTagCollections: () => this.loader.tagCollections(),
159031
161312
  setCanvasSize: (size) => {
159032
161313
  this.loader.canvasSize.set(size);
159033
161314
  this.editor.dirty.set(true);
@@ -159052,6 +161333,22 @@ class PowerPointViewerComponent {
159052
161333
  this.loader.appProperties.set(props);
159053
161334
  this.editor.dirty.set(true);
159054
161335
  },
161336
+ setViewProperties: (props) => {
161337
+ this.loader.viewProperties.set(props);
161338
+ this.editor.dirty.set(true);
161339
+ },
161340
+ setTableStyleMap: (map) => {
161341
+ this.loader.tableStyleMap.set(map);
161342
+ this.editor.dirty.set(true);
161343
+ },
161344
+ setTableStylesDefaultId: (id) => {
161345
+ this.loader.tableStylesDefaultId.set(id);
161346
+ this.editor.dirty.set(true);
161347
+ },
161348
+ setTagCollections: (tags) => {
161349
+ this.loader.tagCollections.set([...tags]);
161350
+ this.editor.dirty.set(true);
161351
+ },
159055
161352
  // Scope the assistant to the user's AI picks / pinned focus / live
159056
161353
  // selection (see AiPanelStore); falls back to the whole active slide.
159057
161354
  getFocusedTargets: () => this.aiPanelStore.getFocusedTargets(),
@@ -159415,6 +161712,29 @@ class PowerPointViewerComponent {
159415
161712
  applyRemoteSlides: (slides) => this.editor.applyRemoteSlides(slides),
159416
161713
  canvasSize: () => this.loader.canvasSize(),
159417
161714
  getSourceBytes: () => this.fileIO.sourceBytes(),
161715
+ // Session-level save options (view properties, table styles, tags, deck
161716
+ // properties, ...), built the same way as `loader.saveSlides`, so an
161717
+ // owner's write-back file no longer drops every session-level edit
161718
+ // outside `slides`.
161719
+ getSaveOptions: () => buildDeckSaveOptions({
161720
+ headerFooter: this.loader.headerFooter(),
161721
+ presentationProperties: this.loader.presentationProperties(),
161722
+ viewProperties: this.loader.viewProperties(),
161723
+ customShows: this.loader.customShows(),
161724
+ sections: this.loader.sections(),
161725
+ coreProperties: this.loader.coreProperties(),
161726
+ appProperties: this.loader.appProperties(),
161727
+ customProperties: this.loader.customProperties(),
161728
+ tagCollections: this.loader.tagCollections(),
161729
+ slideMasters: this.loader.slideMasters(),
161730
+ notesMaster: this.loader.notesMaster(),
161731
+ handoutMaster: this.loader.handoutMaster(),
161732
+ slideSize: this.loader.slideSizeSelection().size,
161733
+ tableStyleMap: this.loader.tableStyleMap(),
161734
+ tableStylesDefaultId: this.loader.tableStylesDefaultId(),
161735
+ tableStylesToDelete: this.loader.tableStylesToDelete(),
161736
+ embedFonts: this.loader.embedFonts(),
161737
+ }),
159418
161738
  currentSlides: () => this.editor.slides(),
159419
161739
  emitStart: (config) => this.startCollaboration.emit(config),
159420
161740
  emitStop: () => this.stopCollaboration.emit(),
@@ -164689,5 +167009,5 @@ function cn(...values) {
164689
167009
  * Generated bundle index. Do not edit.
164690
167010
  */
164691
167011
 
164692
- export { ColorChangedImageComponent as $, AFTER_ANIMATION_VALUES as A, AnimationPanelComponent as B, AnimationPlaybackService as C, AutosaveRecoveryDialogComponent as D, AutosaveService as E, BroadcastDialogComponent as F, CHART_EDITOR_STYLES as G, CURSOR_PALETTE as H, CanvasFitService as I, ChartAxisOptionsComponent as J, ChartAxisStyleOptionsComponent as K, ChartComboTypeOptionsComponent as L, ChartDataEditorComponent as M, ChartDataLabelOptionsComponent as N, ChartDatapointMarkerOptionsComponent as O, ChartDatapointOptionsComponent as P, ChartDisplayOptionsComponent as Q, ChartElementViewComponent as R, ChartErrorBarOptionsComponent as S, ChartMarkerOptionsComponent as T, ChartPartSelectionService as U, ChartPrimitivesComponent as V, ChartRendererComponent as W, ChartTrendlineOptionsComponent as X, ChartTypeSelectorComponent as Y, CollaborationCursorsComponent as Z, CollaborationService as _, ALIGN_OPTIONS as a, InspectorPanelComponent as a$, CommentMarkersOverlayComponent as a0, CommentsPanelComponent as a1, CommentsService as a2, ComparePanelComponent as a3, ConnectorRendererComponent as a4, ConnectorTextOverlayComponent as a5, CustomShowsComponent as a6, DEFAULT_BOUNDS as a7, DEFAULT_BROADCAST_SERVER_URL as a8, DEFAULT_CANVAS_HEIGHT as a9, ElementRendererComponent as aA, EmbeddedFontsService as aB, EncryptedFileDialogComponent as aC, EquationEditorDialogComponent as aD, EquationRendererComponent as aE, EquationTemplateGalleryComponent as aF, ExportProgressModalComponent as aG, ExportService as aH, FieldContextService as aI, FindBarComponent as aJ, FindReplaceBarComponent as aK, FollowModeBarComponent as aL, FontEmbeddingListComponent as aM, FontEmbeddingPanelComponent as aN, GALLERY_THEME_PRESETS as aO, GOOGLE_WEBFONTS_LINK_ID as aP, GRIDLINE_COLOR$1 as aQ, GoogleWebfontsService as aR, GradientPickerComponent as aS, HANDOUT_OPTIONS as aT, HeaderFooterDialogComponent as aU, HyperlinkDialogComponent as aV, ImagePropertiesPanelComponent as aW, InkDrawingService as aX, InkRendererComponent as aY, InsertSmartArtDialogComponent as aZ, InspectorPaneHeaderComponent as a_, DEFAULT_CANVAS_WIDTH as aa, DEFAULT_COLOR_SCHEME as ab, DEFAULT_FILL_COLOR$1 as ac, DEFAULT_LAYOUT as ad, DEFAULT_PALETTE$1 as ae, DEFAULT_PATTERN_FILL_PRESET as af, DEFAULT_PRINT_SETTINGS as ag, DEFAULT_SLIDE_BACKGROUND as ah, DEFAULT_STROKE_COLOR as ai, DEFAULT_STYLE as aj, DEFAULT_TABLE_ROW_HEIGHT as ak, DEFAULT_TEXT_COLOR$2 as al, DEFAULT_VIEWER_PROFILE as am, DIRECTIONAL_PRESETS as an, DIRECTION_OPTIONS as ao, DocumentPropertiesCardComponent as ap, EMBEDDED_FONTS_STYLE_ID as aq, EMPHASIS_PRESETS as ar, ENTRANCE_PRESETS as as, TEMPLATES as at, EXIT_PRESETS as au, EditorContextMenuComponent as av, EditorHistory as aw, EditorStateService as ax, EditorToolbarComponent as ay, EffectsPanelComponent as az, ANIMATION_PRESET_CATEGORIES as b, RibbonComponent as b$, IsMobileService as b0, KeepAnnotationsDialogComponent as b1, LOCALE_CATALOG as b2, LONG_PRESS_DURATION_MS as b3, LONG_PRESS_MOVE_TOLERANCE_PX as b4, LoadContentService as b5, LocalPresencePublisher as b6, MAX_ZOOM_SCALE as b7, MIN_ZOOM_SCALE as b8, MOTION_PATH_COLUMNS as b9, PasswordStrengthMeterComponent as bA, PowerPointViewerComponent as bB, PresentToolbarAutoHide as bC, PresentationAnnotationOverlayComponent as bD, PresentationAnnotationsService as bE, PresentationOverlayComponent as bF, PresentationPropertiesPanelComponent as bG, PresentationSettingsCardComponent as bH, PresentationSubtitleBarComponent as bI, PresentationToolbarComponent as bJ, PresentationTransitionOverlayComponent as bK, PresenterViewComponent as bL, PresenterWindowService as bM, PrintDialogComponent as bN, PrintService as bO, PrintSettingsPanelComponent as bP, PropertiesDialogComponent as bQ, REPEAT_MODE_OPTIONS as bR, RESIZE_HANDLES as bS, RULER_FONT_SIZE as bT, RULER_THICKNESS as bU, ReadingViewOverlayComponent as bV, RemoteSelectionOverlayComponent as bW, RibbonAnimationGalleryComponent as bX, RibbonAnimationsSectionComponent as bY, RibbonArrangeSectionComponent as bZ, RibbonColorPopoverComponent as b_, MediaPreviewComponent as ba, MediaPropertiesPanelComponent as bb, MediaRendererComponent as bc, MediaTrimTimelineComponent as bd, MobileBottomBarComponent as be, MobileMenuSheetComponent as bf, MobilePresenterViewComponent as bg, MobileSheetComponent as bh, MobileSlidesSheetComponent as bi, MobileToolbarComponent as bj, ModalDialogComponent as bk, Model3DRendererComponent as bl, NotesHandoutCardComponent as bm, NotesPanelComponent as bn, NotesToolbarComponent as bo, OleRendererComponent as bp, OutlineViewOverlayComponent as bq, POWER_POINT_VIEWER_PROVIDERS as br, PPTX_OPEN_ACCEPT as bs, PRESENTATION_OPEN_EXTENSIONS as bt, PRESENTER_CHANNEL_NAME as bu, PRESENTER_MSG_ORIGIN as bv, PRESENTER_TIMER_SEGMENT_MS as bw, PX_PER_CM as bx, PX_PER_INCH as by, PasswordProtectionDialogComponent as bz, AUDIENCE_HASH as c, TEXT_3D_TOP_BEVEL_KEYS as c$, RibbonDesignSectionComponent as c0, RibbonDrawSectionComponent as c1, RibbonDrawingGroupComponent as c2, RibbonEditingSectionComponent as c3, RibbonFileSectionComponent as c4, RibbonFontControlsComponent as c5, RibbonHomeSectionComponent as c6, RibbonHyperlinkButtonComponent as c7, RibbonInsertFieldsComponent as c8, RibbonInsertSectionComponent as c9, SettingsLanguageTabComponent as cA, ShareDialogComponent as cB, ShortcutPanelComponent as cC, ShowOptionsFieldsetComponent as cD, ShowSlidesFieldsetComponent as cE, SignatureStrippedDialogComponent as cF, SignaturesPanelComponent as cG, SignaturesService as cH, SlideBackgroundCardComponent as cI, SlideCanvasComponent as cJ, SlideDefaultInspectorComponent as cK, SlideDiffChangesComponent as cL, SlideDiffRowComponent as cM, SlideDiffThumbnailsComponent as cN, SlideSizeCardComponent as cO, SlideSorterOverlayComponent as cP, SlideThemeOverridePanelComponent as cQ, SlideTransitionCardComponent as cR, SlidesPanelComponent as cS, SmartArt3DRendererComponent as cT, SmartArt3DService as cU, SmartArtPreviewComponent as cV, SmartArtPropertiesComponent as cW, SmartArtRendererComponent as cX, StatusBarComponent as cY, TABLE_STRUCTURE_TOGGLES as cZ, TEXT_3D_BOTTOM_BEVEL_KEYS as c_, RibbonMotionPathGalleryComponent as ca, RibbonParagraphControlsComponent as cb, RibbonPrimaryRowComponent as cc, RibbonReviewSectionComponent as cd, RibbonShapeExtrasComponent as ce, RibbonSlideshowSectionComponent as cf, RibbonTransitionsSectionComponent as cg, RibbonViewSectionComponent as ch, RulerGuidesService as ci, SEQUENCE_OPTIONS as cj, SEVERITY_GROUPS as ck, SEVERITY_LABELS as cl, SHORTCUT_REFERENCE_ITEMS as cm, SLIDE_TRANSITION_KEYFRAMES as cn, DEFAULT_PALETTE as co, PALETTES$1 as cp, SMART_ART_COLOR_SCHEMES as cq, SMART_ART_STYLE_OPTIONS as cr, SUB_ITEM_LABEL as cs, SVG_WARP_PRESETS as ct, SWIPE_MAX_VERTICAL_PX as cu, SWIPE_THRESHOLD_PX as cv, SelectionPaneComponent as cw, SetUpSlideShowDialogComponent as cx, SettingsAppearanceTabComponent as cy, SettingsDialogComponent as cz, AUDIENCE_NONCE_KEY as d, animationPresetLabelKey as d$, TEXT_DIRECTION_OPTIONS$1 as d0, THEME_CATALOG as d1, TIMING_CURVE_OPTIONS as d2, TRIGGER_OPTIONS as d3, TYPE_LABELS as d4, TableCellAdvancedFillComponent as d5, TableCellFormattingComponent as d6, TableDataEditorComponent as d7, TablePropertiesComponent as d8, TableRendererComponent as d9, ViewerFileIOService as dA, ViewerFindReplaceService as dB, ViewerFormatPainterService as dC, ViewerInspectorPanelService as dD, ViewerKeyboardService as dE, ViewerMobileSheetService as dF, ViewerPresentationModeService as dG, ViewerThemeGalleryService as dH, ViewerTouchGesturesService as dI, ViewerZoomService as dJ, WEBM_MIME_CANDIDATES as dK, WriteBackScheduler as dL, ZERO_LINE_COLOR as dM, ZoomNavigationService as dN, ZoomRendererComponent as dO, ZoomTargetService as dP, addCategory as dQ, addCommentToList as dR, addGradientStopPatch as dS, addItem as dT, addSeries as dU, addSubItem as dV, advanceStep as dW, affordanceElements as dX, aiToggleVisible as dY, alignPatch as dZ, animationFor as d_, TableResizeOverlayComponent as da, TableSelectionService as db, TagsCardComponent as dc, Text3DBevelSectionComponent as dd, Text3DPanelComponent as de, TextAdvancedPanelComponent as df, ThemeEditorFieldsComponent as dg, ThemeGalleryComponent as dh, ThemeSelectorCardComponent as di, TitleBarComponent as dj, TitleBarSearchComponent as dk, TransitionDirectionPickerComponent as dl, TransitionPreviewComponent as dm, VALIGN_OPTIONS as dn, VIEWER_THEME as dp, VersionHistoryPanelComponent as dq, ViewerCanvasEditingService as dr, ViewerCollabCursorService as ds, ViewerCollaborationSessionService as dt, ViewerCompareService as du, ViewerCustomShowsService as dv, ViewerDialogsService as dw, ViewerDocumentPropertiesService as dx, ViewerExportService as dy, ViewerExtraDialogsComponent as dz, AVATAR_COLOR_SWATCHES as e, buildTreemapViewModel as e$, annotationMapToInkInserts as e0, applyAcceptedDiff as e1, applyAnimationPreset as e2, applyFindReplacements as e3, applyFormatToElement as e4, applyMove as e5, applyResize as e6, asMediaElement as e7, assignUserColor as e8, attachShowVisibilityPause as e9, buildEquationSegment as eA, buildFallbackViewModel as eB, buildFontFaceRule as eC, buildGradientFillCss as eD, buildGridlinesAndLabels as eE, buildHyperlinkPatch as eF, buildInkContainerStyle as eG, buildInkStrokes as eH, buildLegend as eI, buildMarkTooltip as eJ, buildModel3DContainerStyle as eK, buildModel3DViewModel as eL, buildOleActionModel as eM, buildOleInfoRows as eN, buildPatternFillCss as eO, buildPieViewModel as eP, buildPrintHtmlDocument as eQ, buildPropertiesPatch as eR, buildRadarViewModel as eS, buildRegionMapViewModel as eT, buildSaveSlides as eU, buildShareUrl as eV, buildSmartArtInsertElement as eW, buildSmartArtNodes as eX, buildStockViewModel as eY, buildSurfaceViewModel as eZ, buildTableViewModel as e_, attachTouchGestures as ea, axisTickValues as eb, beginNodeEdit as ec, bevelSizePatch as ed, boolFromEvent as ee, bringForward as ef, bringToFront as eg, buildBarActions as eh, buildBroadcastConfig as ei, buildBroadcastViewerUrl as ej, buildCategoryLabels as ek, buildCellParagraphs as el, buildChartViewModel as em, buildChatLogExport as en, buildChatLogMarkdown as eo, buildChromeStyle as ep, buildClearHyperlinkPatch as eq, buildClickGroups as er, buildColStyles as es, buildCollaborationConfig as et, buildComboViewModel as eu, buildCssGradientFromShapeStyle as ev, buildDuotoneFilter as ew, buildDuotoneFilterId as ex, buildEmbeddedFontStyles as ey, buildEquationElement as ez, AXIS_LABEL_COLOR as f, computeResizeHandleBoxes as f$, buildTrimFragment as f0, buildWaterfallViewModel as f1, buildZeroLine as f2, buildZoomContainerStyle as f3, buildZoomViewModel as f4, bulletIndentPx as f5, canAddTopLevelNode as f6, canEditSmartArtNodes as f7, canGroupSelection as f8, canRemoveTopLevelNode as f9, collectStoredChats as fA, collectUsedFontFamilies as fB, columnWidthStyle as fC, commitNodeText as fD, computeAlign as fE, computeAxisTitlePrimitives as fF, computeBarRects as fG, computeBubbleRadius as fH, computeCornerHandle as fI, computeDistribute as fJ, computeDrawingViewBox as fK, computeErrorBarPrimitives as fL, computeFocusTargets as fM, computeGridSpacingPx as fN, computeHandleBoxes as fO, computeHandoutLayout as fP, computeIsMobile as fQ, computeIsTablet as fR, computeLinePoints as fS, computeLinearRegression as fT, computePageCount as fU, computePieLayout as fV, computePieSlicePath as fW, computePieSlices as fX, computePlotLayout as fY, computeRSquared as fZ, computeRadarPoints as f_, canSetStrokeWidth as fa, canStartBroadcast as fb, canStartShare as fc, canUngroupSelection as fd, canUseClipboard as fe, captionDisplayText as ff, cellRunStyle as fg, cellStyleToStyleMap as fh, cellTdStyle as fi, changeCountLabel as fj, changeIcon as fk, characterSpacingPatch as fl, chartPreserveAspectRatio as fm, checkFontAvailable as fn, clampCursorPosition as fo, clampGifDimensions as fp, clampIndex as fq, clampNotesFontSize as fr, clampScale as fs, clampStep as ft, clearAllLocalViewerData as fu, clearAudienceContent as fv, cn as fw, collectAccessibilityIssues as fx, collectElementText as fy, collectSlideText as fz, AccessibilityPanelComponent as g, forgetSessionDeck as g$, computeRotateHandleBox as g0, computeScatterDots as g1, computeScatterXDomain as g2, computeSelectionBoxes as g3, computeSingleSelected as g4, computeSlideIndices as g5, computeSnap as g6, computeStackedBarRects as g7, computeStackedValueRange as g8, computeTrendlinePrimitives as g9, disableReflectionPatch as gA, disableSoftEdgePatch as gB, duplicateElementById as gC, durationOf as gD, effectsStateOf as gE, enableGlowPatch as gF, enableInnerShadowPatch as gG, enableOuterShadowPatch as gH, enableReflectionPatch as gI, enableSoftEdgePatch as gJ, encodeGif as gK, endShowMediaCleanup as gL, estimatePageCount as gM, exitPresentationFullscreen as gN, exportAiChatLogs as gO, extractPathPoints as gP, eyedropperAvailable as gQ, fillColorOf$1 as gR, findInSlides as gS, findOwningSlideIndex as gT, findSlideIndexByElementId as gU, firstVisibleIndex as gV, fitPolynomial as gW, fitZoom as gX, focusTargetChips as gY, fontMimeForFormat as gZ, fontSizeOf as g_, computeValueRange as ga, convertOmmlToMathMl as gb, copyFormatFromElement as gc, countAccessibilityIssues as gd, countAnnotationStrokes as ge, createAngularAiBridge as gf, createCustomShow as gg, createSwipeDismissDrag as gh, createWebrtcBundle as gi, createWebsocketBundle as gj, cssObjectToStyleMap as gk, currentColorScheme as gl, currentLayout as gm, currentStyle as gn, defaultCssVars as go, defaultRadius as gp, defaultThemeColors as gq, deleteElementsByIds as gr, deleteVersion as gs, demoteNode as gt, deriveModel3DBlobUrl as gu, derivePresenceList as gv, describeSmartArtBounds as gw, disableGlowPatch as gx, disableInnerShadowPatch as gy, disableOuterShadowPatch as gz, AccessibilityService as h, isBrowserOpenableMime as h$, formatAxisValue as h0, formatBytes as h1, formatCursorLabel as h2, formatElapsed as h3, formatFileSize as h4, formatPropertyDate as h5, formatTime as h6, fpsToFrameIntervalMs as h7, generateBroadcastRoomId as h8, generateCommentId as h9, getSpeechRecognitionCtor as hA, getTextBlockStyle as hB, getTextWarp as hC, getTouchDistance as hD, getWarpCategory as hE, getWarpPath as hF, gradientStateFromStyle as hG, gradientStateOf as hH, gradientStatePatch as hI, gradientStopColorCommitPatch as hJ, gridColumns as hK, groupIssuesBySeverity as hL, hasAnimation as hM, hasCopyableFormat as hN, hasExistingLink as hO, hasExitedFullscreen as hP, hasGradientFill as hQ, hasPressureVariation as hR, hasVisibleSlideAfter as hS, headerLabel as hT, imageDimensions as hU, inkViewBox as hV, insertTableElementColumn as hW, insertTableElementRow as hX, interpolateWidth as hY, isAudienceTab as hZ, isBold as h_, generateCustomShowId as ha, generatePressureCircles as hb, generateTicks as hc, getClrChangeParams as hd, getContainerStyle as he, getDuotoneFilterDef as hf, getEffectSoundState as hg, getImageSrc as hh, getLocalStorageUsageSummary as hi, getOleAriaLabel as hj, getOleBadgeLabel as hk, getOleDisplayName as hl, getOleDownloadFileName as hm, getOleTypeColor as hn, getOleTypeLabel as ho, getPasswordStrength as hp, getPatternSvg as hq, getPlaceholderStyle as hr, getVersions as hs, getResolvedShapeClipPath as ht, getResolvedShapeClipPathFor as hu, getSessionTabId as hv, getShapeFillStrokeStyle as hw, getSlideBackgroundStyle as hx, getSlideTransitionAnimations as hy, getSmartArtNodeBounds as hz, AccountPageComponent as i, ooxmlDashToCssBorderStyle as i$, isChildNode as i0, isElementInteractive as i1, isInjectableUrl as i2, isItalic as i3, isLegacyBinaryPresentation as i4, isPpactionUrl as i5, isPresenterMessage as i6, isSigned as i7, isSupportedPresentationFile as i8, isTextElement as i9, moveElementBy as iA, moveNodeDown as iB, moveNodeUp as iC, msToFrameDelayCs as iD, narrowToCircle as iE, narrowToPolygon as iF, narrowToRect as iG, newChartElement as iH, newEquationElement as iI, newPresetShapeElement as iJ, newShapeElement as iK, newSmartArtElement as iL, newTableElement as iM, newTextElement as iN, nextVisibleIndex as iO, nodeBold as iP, nodeEditBox as iQ, nodeFillColor as iR, nodeFontColor as iS, nodeIdFromKey as iT, nodeItalic as iU, nodeStyle as iV, normalizeFontFormat as iW, normalizeSlidesPerPage as iX, normalizeValue as iY, numFromEvent as iZ, ommlToMathml as i_, isTwoTableFocus as ia, isUnderline as ib, isUrlSafe as ic, isValidRoomId as id, isViewportBackgroundPressTarget as ie, isZoomActivationKey as ig, issueTrackKey as ih, issueTypeLabel as ii, keyToLabel as ij, lastVisibleIndex as ik, latexToMathml as il, layoutConnectorPaints as im, layoutNodeLabels as io, linePointsToSvgString as ip, lineSpacingPatch as iq, loadAudienceContent as ir, loadSessionDeck as is, mediaFallbackFor as it, mediaSurfaceFor as iu, mergeCaptionResults as iv, mergeDown as iw, mergeRight as ix, mergeSelection as iy, mergeTablesDirective as iz, ActionSettingsPanelComponent as j, resolveSlideAutoAdvanceMs as j$, openNativeEyeDropper as j0, overallStatus as j1, paletteColor as j2, parseAudienceNonce as j3, parseNodeTextarea as j4, partitionSlides as j5, patchChartData as j6, patchChartStyle as j7, patchTableData as j8, patchTextStyle as j9, removeCategory as jA, removeTableElementColumn as jB, removeCommentFromList as jC, removeElementAnimation as jD, removeGradientStopPatch as jE, removeNode as jF, removeTableElementRow as jG, removeSeries as jH, renderToCanvas as jI, reorderAnimationDown as jJ, reorderAnimationUp as jK, replaceInSlides as jL, replaceMatch as jM, requestPresentationFullscreen as jN, resizeElement as jO, resolveCaptionTracks as jP, resolveChartKind as jQ, resolveFontVariant as jR, resolveHyperlinkHref as jS, resolveInteractiveElementId as jT, resolveMediaSrc as jU, resolveOleType as jV, resolveParagraphBullet as jW, resolvePresenterNotes as jX, resolveProfileInitial as jY, resolveRegionCode as jZ, resolveRibbonCanGroup as j_, patternPresetOptions as ja, pendingElementStyles as jb, pickColorByClickFallback as jc, pickFile as jd, pickSupportedMimeType as je, planGifFrames as jf, planVideoSegments as jg, pointsToSvgPathD as jh, presenceToCursors as ji, presentationBaseName as jj, presentationStageStyle as jk, presenterTimerProgress as jl, presetByLayout as jm, presetsForCategory as jn, pressuresToWidths as jo, prevVisibleIndex as jp, projectDrawingShapes as jq, promoteNode as jr, provideViewerTheme as js, radarAngle as jt, radarRingPoints as ju, readAsDataUrl as jv, recordWebm as jw, registerCrossSlideAudio as jx, rememberSessionDeck as jy, removeAnimation as jz, AdvancedChartEditorComponent as k, setSeriesTrendline as k$, resolvePalette as k0, resolveThemeCatalogEntry as k1, resolveTransitionDuration as k2, restoreSessionDeck as k3, revealedElementStyles as k4, routeOrthogonalConnector as k5, rowStyle as k6, rulerDragToGuidePosition as k7, rulerHighlight as k8, rulerStripTicks as k9, setAxisTitleStyle as kA, setCategoryLabel as kB, setCellText as kC, setColorScheme as kD, setDataLabels as kE, setDataPointExplosion as kF, setDataPointFill as kG, setDataPointLabel as kH, setDataPointMarker as kI, setDelay as kJ, setDirection as kK, setDuration as kL, setEffectSound as kM, setElementPosition as kN, setGridlineStyle as kO, setLayout as kP, setLegend as kQ, setNodeStyle as kR, setNodeText as kS, setRepeatCount as kT, setRepeatMode as kU, setSequence as kV, setSeriesChartType as kW, setSeriesColor as kX, setSeriesErrorBars as kY, setSeriesMarker as kZ, setSeriesName as k_, sampleColorFromSlide as ka, sanitizeColor as kb, sanitizeSlideIndex as kc, sanitizeUserName as kd, saveViewerProfile as ke, savedPresentationFileName as kf, scanAvailableFonts as kg, searchSlides as kh, seedBroadcastFields as ki, seedHyperlinkDraft as kj, seedPropertiesDraft as kk, seedShareFields as kl, segmentFrameCount as km, selectValue$3 as kn, sendBackward as ko, sendToBack as kp, sequentialColorScale as kq, serializeWriteBack as kr, seriesColor as ks, setAfterAnimation as kt, setAfterAnimationColor as ku, setAnimationEmphasis as kv, setAnimationEntrance as kw, setAnimationExit as kx, setAxis as ky, setAxisLogScale as kz, AiChangeOverlayComponent as l, vermilionDarkColors as l$, setSeriesValue as l0, setStyle as l1, setTimingCurve as l2, setTitle as l3, setTrigger as l4, setTriggerShapeId as l5, shapeStylePatch$1 as l6, sheetAfterNavigate as l7, shouldBlockClickAdvance as l8, shouldUseSvgWarp as l9, textColorOf as lA, textDirectionPatch as lB, textFontSizePatch as lC, textStyleOf as lD, textStylePatch as lE, themeStyle as lF, themeToCssVars as lG, thumbnailHeight as lH, thumbnailZoom as lI, toggleCommentResolvedInList as lJ, toggleNodeBold as lK, toggleNodeItalic as lL, toggleSheet as lM, topLevelNodeCount as lN, transformSelectedTextCase as lO, translationsEn as lP, updateElementById as lQ, updateGlowPatch as lR, updateGradientStopPatch as lS, updateInnerShadowPatch as lT, updateOuterShadowPatch as lU, updateReflectionPatch as lV, vAlignPatch as lW, validatePassword as lX, validatePrintSettings as lY, validateRoomId as lZ, valueToY as l_, showDirectionPicker as la, showsTemplateAffordance as lb, signatureCountLabel as lc, signatureKey as ld, signatureTimestamp as le, signerName as lf, statusLabel as lg, slideNumberOf as lh, slidesWithReappliedLayout as li, smartArtNodes as lj, paletteColour as lk, snapToGridStep as ll, splitCursorCell as lm, splitMergedCell as ln, statusKind as lo, statusLabel$1 as lp, storeAudienceContent as lq, stringFromEvent$5 as lr, strokeColorOf as ls, strokeToInkElement as lt, strokeWidthOf as lu, styleShadowFilter as lv, surfaceColor as lw, textAdvancedPatch as lx, textAdvancedStateFromStyle as ly, textAdvancedStateOf as lz, AiChatPanelComponent as m, vermilionDarkTheme as m0, vermilionLightColors as m1, vermilionLightTheme as m2, vermilionRadius as m3, waypointsToPathD as m4, withManualLayouts as m5, worstStatus as m6, zoomTargetSlideIndex as m7, AiChatService as n, AiComposerComponent as o, AiFocusBarComponent as p, AiFocusHighlightOverlayComponent as q, AiHistoryMenuComponent as r, AiHistoryService as s, toChatSummary as t, AiMessageListComponent as u, AiPanelStore as v, AiProposalCardComponent as w, AiSettingsSectionComponent as x, AiToolCallCardComponent as y, AnimationAuthorPanelComponent as z };
164693
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-3iTbE0x6.mjs.map
167012
+ export { CollaborationService as $, AFTER_ANIMATION_VALUES as A, AnimationAuthorPanelComponent as B, AnimationPanelComponent as C, AnimationPlaybackService as D, AutosaveRecoveryDialogComponent as E, AutosaveService as F, BroadcastDialogComponent as G, CHART_EDITOR_STYLES as H, CURSOR_PALETTE as I, CanvasFitService as J, ChartAxisOptionsComponent as K, ChartAxisStyleOptionsComponent as L, ChartComboTypeOptionsComponent as M, ChartDataEditorComponent as N, ChartDataLabelOptionsComponent as O, ChartDatapointMarkerOptionsComponent as P, ChartDatapointOptionsComponent as Q, ChartDisplayOptionsComponent as R, ChartElementViewComponent as S, ChartErrorBarOptionsComponent as T, ChartMarkerOptionsComponent as U, ChartPartSelectionService as V, ChartPrimitivesComponent as W, ChartRendererComponent as X, ChartTrendlineOptionsComponent as Y, ChartTypeSelectorComponent as Z, CollaborationCursorsComponent as _, ALIGN_OPTIONS as a, InspectorPaneHeaderComponent as a$, ColorChangedImageComponent as a0, CommentMarkersOverlayComponent as a1, CommentsPanelComponent as a2, CommentsService as a3, ComparePanelComponent as a4, ConnectorRendererComponent as a5, ConnectorTextOverlayComponent as a6, CustomShowsComponent as a7, DEFAULT_BOUNDS as a8, DEFAULT_BROADCAST_SERVER_URL as a9, EffectsPanelComponent as aA, ElementRendererComponent as aB, EmbeddedFontsService as aC, EncryptedFileDialogComponent as aD, EquationEditorDialogComponent as aE, EquationRendererComponent as aF, EquationTemplateGalleryComponent as aG, ExportProgressModalComponent as aH, ExportService as aI, FieldContextService as aJ, FindBarComponent as aK, FindReplaceBarComponent as aL, FollowModeBarComponent as aM, FontEmbeddingListComponent as aN, FontEmbeddingPanelComponent as aO, GALLERY_THEME_PRESETS as aP, GOOGLE_WEBFONTS_LINK_ID as aQ, GRIDLINE_COLOR$1 as aR, GoogleWebfontsService as aS, GradientPickerComponent as aT, HANDOUT_OPTIONS as aU, HeaderFooterDialogComponent as aV, HyperlinkDialogComponent as aW, ImagePropertiesPanelComponent as aX, InkDrawingService as aY, InkRendererComponent as aZ, InsertSmartArtDialogComponent as a_, DEFAULT_CANVAS_HEIGHT as aa, DEFAULT_CANVAS_WIDTH as ab, DEFAULT_COLOR_SCHEME as ac, DEFAULT_FILL_COLOR$1 as ad, DEFAULT_LAYOUT as ae, DEFAULT_PALETTE$1 as af, DEFAULT_PATTERN_FILL_PRESET as ag, DEFAULT_PRINT_SETTINGS as ah, DEFAULT_SLIDE_BACKGROUND as ai, DEFAULT_STROKE_COLOR as aj, DEFAULT_STYLE as ak, DEFAULT_TABLE_ROW_HEIGHT as al, DEFAULT_TEXT_COLOR$2 as am, DEFAULT_VIEWER_PROFILE as an, DIRECTIONAL_PRESETS as ao, DIRECTION_OPTIONS as ap, DocumentPropertiesCardComponent as aq, EMBEDDED_FONTS_STYLE_ID as ar, EMPHASIS_PRESETS as as, ENTRANCE_PRESETS as at, TEMPLATES as au, EXIT_PRESETS as av, EditorContextMenuComponent as aw, EditorHistory as ax, EditorStateService as ay, EditorToolbarComponent as az, ANIMATION_PRESET_CATEGORIES as b, RibbonColorPopoverComponent as b$, InspectorPanelComponent as b0, IsMobileService as b1, KeepAnnotationsDialogComponent as b2, LOCALE_CATALOG as b3, LONG_PRESS_DURATION_MS as b4, LONG_PRESS_MOVE_TOLERANCE_PX as b5, LoadContentService as b6, LocalPresencePublisher as b7, MAX_ZOOM_SCALE as b8, MIN_ZOOM_SCALE as b9, PasswordProtectionDialogComponent as bA, PasswordStrengthMeterComponent as bB, PowerPointViewerComponent as bC, PresentToolbarAutoHide as bD, PresentationAnnotationOverlayComponent as bE, PresentationAnnotationsService as bF, PresentationOverlayComponent as bG, PresentationPropertiesPanelComponent as bH, PresentationSettingsCardComponent as bI, PresentationSubtitleBarComponent as bJ, PresentationToolbarComponent as bK, PresentationTransitionOverlayComponent as bL, PresenterViewComponent as bM, PresenterWindowService as bN, PrintDialogComponent as bO, PrintService as bP, PrintSettingsPanelComponent as bQ, PropertiesDialogComponent as bR, REPEAT_MODE_OPTIONS as bS, RESIZE_HANDLES as bT, RULER_FONT_SIZE as bU, RULER_THICKNESS as bV, ReadingViewOverlayComponent as bW, RemoteSelectionOverlayComponent as bX, RibbonAnimationGalleryComponent as bY, RibbonAnimationsSectionComponent as bZ, RibbonArrangeSectionComponent as b_, MOTION_PATH_COLUMNS as ba, MediaPreviewComponent as bb, MediaPropertiesPanelComponent as bc, MediaRendererComponent as bd, MediaTrimTimelineComponent as be, MobileBottomBarComponent as bf, MobileMenuSheetComponent as bg, MobilePresenterViewComponent as bh, MobileSheetComponent as bi, MobileSlidesSheetComponent as bj, MobileToolbarComponent as bk, ModalDialogComponent as bl, Model3DRendererComponent as bm, NotesHandoutCardComponent as bn, NotesPanelComponent as bo, NotesToolbarComponent as bp, OleRendererComponent as bq, OutlineViewOverlayComponent as br, POWER_POINT_VIEWER_PROVIDERS as bs, PPTX_OPEN_ACCEPT as bt, PRESENTATION_OPEN_EXTENSIONS as bu, PRESENTER_CHANNEL_NAME as bv, PRESENTER_MSG_ORIGIN as bw, PRESENTER_TIMER_SEGMENT_MS as bx, PX_PER_CM as by, PX_PER_INCH as bz, AUDIENCE_HASH as c, TEXT_3D_BOTTOM_BEVEL_KEYS as c$, RibbonComponent as c0, RibbonDesignSectionComponent as c1, RibbonDrawSectionComponent as c2, RibbonDrawingGroupComponent as c3, RibbonEditingSectionComponent as c4, RibbonFileSectionComponent as c5, RibbonFontControlsComponent as c6, RibbonHomeSectionComponent as c7, RibbonHyperlinkButtonComponent as c8, RibbonInsertFieldsComponent as c9, SettingsDialogComponent as cA, SettingsLanguageTabComponent as cB, ShareDialogComponent as cC, ShortcutPanelComponent as cD, ShowOptionsFieldsetComponent as cE, ShowSlidesFieldsetComponent as cF, SignatureStrippedDialogComponent as cG, SignaturesPanelComponent as cH, SignaturesService as cI, SlideBackgroundCardComponent as cJ, SlideCanvasComponent as cK, SlideDefaultInspectorComponent as cL, SlideDiffChangesComponent as cM, SlideDiffRowComponent as cN, SlideDiffThumbnailsComponent as cO, SlideSizeCardComponent as cP, SlideSorterOverlayComponent as cQ, SlideThemeOverridePanelComponent as cR, SlideTransitionCardComponent as cS, SlidesPanelComponent as cT, SmartArt3DRendererComponent as cU, SmartArt3DService as cV, SmartArtPreviewComponent as cW, SmartArtPropertiesComponent as cX, SmartArtRendererComponent as cY, StatusBarComponent as cZ, TABLE_STRUCTURE_TOGGLES as c_, RibbonInsertSectionComponent as ca, RibbonMotionPathGalleryComponent as cb, RibbonParagraphControlsComponent as cc, RibbonPrimaryRowComponent as cd, RibbonReviewSectionComponent as ce, RibbonShapeExtrasComponent as cf, RibbonSlideshowSectionComponent as cg, RibbonTransitionsSectionComponent as ch, RibbonViewSectionComponent as ci, RulerGuidesService as cj, SEQUENCE_OPTIONS as ck, SEVERITY_GROUPS as cl, SEVERITY_LABELS as cm, SHORTCUT_REFERENCE_ITEMS as cn, SLIDE_TRANSITION_KEYFRAMES as co, DEFAULT_PALETTE as cp, PALETTES$1 as cq, SMART_ART_COLOR_SCHEMES as cr, SMART_ART_STYLE_OPTIONS as cs, SUB_ITEM_LABEL as ct, SVG_WARP_PRESETS as cu, SWIPE_MAX_VERTICAL_PX as cv, SWIPE_THRESHOLD_PX as cw, SelectionPaneComponent as cx, SetUpSlideShowDialogComponent as cy, SettingsAppearanceTabComponent as cz, AUDIENCE_NONCE_KEY as d, animationFor as d$, TEXT_3D_TOP_BEVEL_KEYS as d0, TEXT_DIRECTION_OPTIONS$1 as d1, THEME_CATALOG as d2, TIMING_CURVE_OPTIONS as d3, TRIGGER_OPTIONS as d4, TYPE_LABELS as d5, TableCellAdvancedFillComponent as d6, TableCellFormattingComponent as d7, TableDataEditorComponent as d8, TablePropertiesComponent as d9, ViewerExtraDialogsComponent as dA, ViewerFileIOService as dB, ViewerFindReplaceService as dC, ViewerFormatPainterService as dD, ViewerInspectorPanelService as dE, ViewerKeyboardService as dF, ViewerMobileSheetService as dG, ViewerPresentationModeService as dH, ViewerThemeGalleryService as dI, ViewerTouchGesturesService as dJ, ViewerZoomService as dK, WEBM_MIME_CANDIDATES as dL, WriteBackScheduler as dM, ZERO_LINE_COLOR as dN, ZoomNavigationService as dO, ZoomRendererComponent as dP, ZoomTargetService as dQ, addCategory as dR, addCommentToList as dS, addGradientStopPatch as dT, addItem as dU, addSeries as dV, addSubItem as dW, advanceStep as dX, affordanceElements as dY, aiToggleVisible as dZ, alignPatch as d_, TableRendererComponent as da, TableResizeOverlayComponent as db, TableSelectionService as dc, TagsCardComponent as dd, Text3DBevelSectionComponent as de, Text3DPanelComponent as df, TextAdvancedPanelComponent as dg, ThemeEditorFieldsComponent as dh, ThemeGalleryComponent as di, ThemeSelectorCardComponent as dj, TitleBarComponent as dk, TitleBarSearchComponent as dl, TransitionDirectionPickerComponent as dm, TransitionPreviewComponent as dn, VALIGN_OPTIONS as dp, VIEWER_THEME as dq, VersionHistoryPanelComponent as dr, ViewerCanvasEditingService as ds, ViewerCollabCursorService as dt, ViewerCollaborationSessionService as du, ViewerCompareService as dv, ViewerCustomShowsService as dw, ViewerDialogsService as dx, ViewerDocumentPropertiesService as dy, ViewerExportService as dz, AVATAR_COLOR_SWATCHES as e, buildTableViewModel as e$, animationPresetLabelKey as e0, annotationMapToInkInserts as e1, applyAcceptedDiff as e2, applyAnimationPreset as e3, applyFindReplacements as e4, applyFormatToElement as e5, applyMove as e6, applyResize as e7, asMediaElement as e8, assignUserColor as e9, buildEquationElement as eA, buildEquationSegment as eB, buildFallbackViewModel as eC, buildFontFaceRule as eD, buildGradientFillCss as eE, buildGridlinesAndLabels as eF, buildHyperlinkPatch as eG, buildInkContainerStyle as eH, buildInkStrokes as eI, buildLegend as eJ, buildMarkTooltip as eK, buildModel3DContainerStyle as eL, buildModel3DViewModel as eM, buildOleActionModel as eN, buildOleInfoRows as eO, buildPatternFillCss as eP, buildPieViewModel as eQ, buildPrintHtmlDocument as eR, buildPropertiesPatch as eS, buildRadarViewModel as eT, buildRegionMapViewModel as eU, buildSaveSlides as eV, buildShareUrl as eW, buildSmartArtInsertElement as eX, buildSmartArtNodes as eY, buildStockViewModel as eZ, buildSurfaceViewModel as e_, attachShowVisibilityPause as ea, attachTouchGestures as eb, axisTickValues as ec, beginNodeEdit as ed, bevelSizePatch as ee, boolFromEvent as ef, bringForward as eg, bringToFront as eh, buildBarActions as ei, buildBroadcastConfig as ej, buildBroadcastViewerUrl as ek, buildCategoryLabels as el, buildCellParagraphs as em, buildChartViewModel as en, buildChatLogExport as eo, buildChatLogMarkdown as ep, buildChromeStyle as eq, buildClearHyperlinkPatch as er, buildClickGroups as es, buildColStyles as et, buildCollaborationConfig as eu, buildComboViewModel as ev, buildCssGradientFromShapeStyle as ew, buildDuotoneFilter as ex, buildDuotoneFilterId as ey, buildEmbeddedFontStyles as ez, AXIS_LABEL_COLOR as f, computeRadarPoints as f$, buildTreemapViewModel as f0, buildTrimFragment as f1, buildWaterfallViewModel as f2, buildZeroLine as f3, buildZoomContainerStyle as f4, buildZoomViewModel as f5, bulletIndentPx as f6, canAddTopLevelNode as f7, canEditSmartArtNodes as f8, canGroupSelection as f9, collectSlideText as fA, collectStoredChats as fB, collectUsedFontFamilies as fC, columnWidthStyle as fD, commitNodeText as fE, computeAlign as fF, computeAxisTitlePrimitives as fG, computeBarRects as fH, computeBubbleRadius as fI, computeCornerHandle as fJ, computeDistribute as fK, computeDrawingViewBox as fL, computeErrorBarPrimitives as fM, computeFocusTargets as fN, computeGridSpacingPx as fO, computeHandleBoxes as fP, computeHandoutLayout as fQ, computeIsMobile as fR, computeIsTablet as fS, computeLinePoints as fT, computeLinearRegression as fU, computePageCount as fV, computePieLayout as fW, computePieSlicePath as fX, computePieSlices as fY, computePlotLayout as fZ, computeRSquared as f_, canRemoveTopLevelNode as fa, canSetStrokeWidth as fb, canStartBroadcast as fc, canStartShare as fd, canUngroupSelection as fe, canUseClipboard as ff, captionDisplayText as fg, cellRunStyle as fh, cellStyleToStyleMap as fi, cellTdStyle as fj, changeCountLabel as fk, changeIcon as fl, characterSpacingPatch as fm, chartPreserveAspectRatio as fn, checkFontAvailable as fo, clampCursorPosition as fp, clampGifDimensions as fq, clampIndex as fr, clampNotesFontSize as fs, clampScale as ft, clampStep as fu, clearAllLocalViewerData as fv, clearAudienceContent as fw, cn as fx, collectAccessibilityIssues as fy, collectElementText as fz, AccessibilityPanelComponent as g, fontSizeOf as g$, computeResizeHandleBoxes as g0, computeRotateHandleBox as g1, computeScatterDots as g2, computeScatterXDomain as g3, computeSelectionBoxes as g4, computeSingleSelected as g5, computeSlideIndices as g6, computeSnap as g7, computeStackedBarRects as g8, computeStackedValueRange as g9, disableOuterShadowPatch as gA, disableReflectionPatch as gB, disableSoftEdgePatch as gC, duplicateElementById as gD, durationOf as gE, effectsStateOf as gF, enableGlowPatch as gG, enableInnerShadowPatch as gH, enableOuterShadowPatch as gI, enableReflectionPatch as gJ, enableSoftEdgePatch as gK, encodeGif as gL, endShowMediaCleanup as gM, estimatePageCount as gN, exitPresentationFullscreen as gO, exportAiChatLogs as gP, extractPathPoints as gQ, eyedropperAvailable as gR, fillColorOf$1 as gS, findInSlides as gT, findOwningSlideIndex as gU, findSlideIndexByElementId as gV, firstVisibleIndex as gW, fitPolynomial as gX, fitZoom as gY, focusTargetChips as gZ, fontMimeForFormat as g_, computeTrendlinePrimitives as ga, computeValueRange as gb, convertOmmlToMathMl as gc, copyFormatFromElement as gd, countAccessibilityIssues as ge, countAnnotationStrokes as gf, createAngularAiBridge as gg, createCustomShow as gh, createSwipeDismissDrag as gi, createWebrtcBundle as gj, createWebsocketBundle as gk, cssObjectToStyleMap as gl, currentColorScheme as gm, currentLayout as gn, currentStyle as go, defaultCssVars as gp, defaultRadius as gq, defaultThemeColors as gr, deleteElementsByIds as gs, deleteVersion as gt, demoteNode as gu, deriveModel3DBlobUrl as gv, derivePresenceList as gw, describeSmartArtBounds as gx, disableGlowPatch as gy, disableInnerShadowPatch as gz, AccessibilityService as h, isBold as h$, forgetSessionDeck as h0, formatAxisValue as h1, formatBytes as h2, formatCursorLabel as h3, formatElapsed as h4, formatFileSize as h5, formatPropertyDate as h6, formatTime as h7, fpsToFrameIntervalMs as h8, generateBroadcastRoomId as h9, getSmartArtNodeBounds as hA, getSpeechRecognitionCtor as hB, getTextBlockStyle as hC, getTextWarp as hD, getTouchDistance as hE, getWarpCategory as hF, getWarpPath as hG, gradientStateFromStyle as hH, gradientStateOf as hI, gradientStatePatch as hJ, gradientStopColorCommitPatch as hK, gridColumns as hL, groupIssuesBySeverity as hM, hasAnimation as hN, hasCopyableFormat as hO, hasExistingLink as hP, hasExitedFullscreen as hQ, hasGradientFill as hR, hasPressureVariation as hS, hasVisibleSlideAfter as hT, headerLabel as hU, imageDimensions as hV, inkViewBox as hW, insertTableElementColumn as hX, insertTableElementRow as hY, interpolateWidth as hZ, isAudienceTab as h_, generateCommentId as ha, generateCustomShowId as hb, generatePressureCircles as hc, generateTicks as hd, getClrChangeParams as he, getContainerStyle as hf, getDuotoneFilterDef as hg, getEffectSoundState as hh, getImageSrc as hi, getLocalStorageUsageSummary as hj, getOleAriaLabel as hk, getOleBadgeLabel as hl, getOleDisplayName as hm, getOleDownloadFileName as hn, getOleTypeColor as ho, getOleTypeLabel as hp, getPasswordStrength as hq, getPatternSvg as hr, getPlaceholderStyle as hs, getVersions as ht, getResolvedShapeClipPath as hu, getResolvedShapeClipPathFor as hv, getSessionTabId as hw, getShapeFillStrokeStyle as hx, getSlideBackgroundStyle as hy, getSlideTransitionAnimations as hz, AccessibilityTextPanelComponent as i, ommlToMathml as i$, isBrowserOpenableMime as i0, isChildNode as i1, isElementInteractive as i2, isInjectableUrl as i3, isItalic as i4, isLegacyBinaryPresentation as i5, isPpactionUrl as i6, isPresenterMessage as i7, isSigned as i8, isSupportedPresentationFile as i9, mergeTablesDirective as iA, moveElementBy as iB, moveNodeDown as iC, moveNodeUp as iD, msToFrameDelayCs as iE, narrowToCircle as iF, narrowToPolygon as iG, narrowToRect as iH, newChartElement as iI, newEquationElement as iJ, newPresetShapeElement as iK, newShapeElement as iL, newSmartArtElement as iM, newTableElement as iN, newTextElement as iO, nextVisibleIndex as iP, nodeBold as iQ, nodeEditBox as iR, nodeFillColor as iS, nodeFontColor as iT, nodeIdFromKey as iU, nodeItalic as iV, nodeStyle as iW, normalizeFontFormat as iX, normalizeSlidesPerPage as iY, normalizeValue as iZ, numFromEvent as i_, isTextElement as ia, isTwoTableFocus as ib, isUnderline as ic, isUrlSafe as id, isValidRoomId as ie, isViewportBackgroundPressTarget as ig, isZoomActivationKey as ih, issueTrackKey as ii, issueTypeLabel as ij, keyToLabel as ik, lastVisibleIndex as il, latexToMathml as im, layoutConnectorPaints as io, layoutNodeLabels as ip, linePointsToSvgString as iq, lineSpacingPatch as ir, loadAudienceContent as is, loadSessionDeck as it, mediaFallbackFor as iu, mediaSurfaceFor as iv, mergeCaptionResults as iw, mergeDown as ix, mergeRight as iy, mergeSelection as iz, AccountPageComponent as j, resolveRibbonCanGroup as j$, ooxmlDashToCssBorderStyle as j0, openNativeEyeDropper as j1, overallStatus as j2, paletteColor as j3, parseAudienceNonce as j4, parseNodeTextarea as j5, partitionSlides as j6, patchChartData as j7, patchChartStyle as j8, patchTableData as j9, removeAnimation as jA, removeCategory as jB, removeTableElementColumn as jC, removeCommentFromList as jD, removeElementAnimation as jE, removeGradientStopPatch as jF, removeNode as jG, removeTableElementRow as jH, removeSeries as jI, renderToCanvas as jJ, reorderAnimationDown as jK, reorderAnimationUp as jL, replaceInSlides as jM, replaceMatch as jN, requestPresentationFullscreen as jO, resizeElement as jP, resolveCaptionTracks as jQ, resolveChartKind as jR, resolveFontVariant as jS, resolveHyperlinkHref as jT, resolveInteractiveElementId as jU, resolveMediaSrc as jV, resolveOleType as jW, resolveParagraphBullet as jX, resolvePresenterNotes as jY, resolveProfileInitial as jZ, resolveRegionCode as j_, patchTextStyle as ja, patternPresetOptions as jb, pendingElementStyles as jc, pickColorByClickFallback as jd, pickFile as je, pickSupportedMimeType as jf, planGifFrames as jg, planVideoSegments as jh, pointsToSvgPathD as ji, presenceToCursors as jj, presentationBaseName as jk, presentationStageStyle as jl, presenterTimerProgress as jm, presetByLayout as jn, presetsForCategory as jo, pressuresToWidths as jp, prevVisibleIndex as jq, projectDrawingShapes as jr, promoteNode as js, provideViewerTheme as jt, radarAngle as ju, radarRingPoints as jv, readAsDataUrl as jw, recordWebm as jx, registerCrossSlideAudio as jy, rememberSessionDeck as jz, ActionSettingsPanelComponent as k, setSeriesName as k$, resolveSlideAutoAdvanceMs as k0, resolvePalette as k1, resolveThemeCatalogEntry as k2, resolveTransitionDuration as k3, restoreSessionDeck as k4, revealedElementStyles as k5, routeOrthogonalConnector as k6, rowStyle as k7, rulerDragToGuidePosition as k8, rulerHighlight as k9, setAxisLogScale as kA, setAxisTitleStyle as kB, setCategoryLabel as kC, setCellText as kD, setColorScheme as kE, setDataLabels as kF, setDataPointExplosion as kG, setDataPointFill as kH, setDataPointLabel as kI, setDataPointMarker as kJ, setDelay as kK, setDirection as kL, setDuration as kM, setEffectSound as kN, setElementPosition as kO, setGridlineStyle as kP, setLayout as kQ, setLegend as kR, setNodeStyle as kS, setNodeText as kT, setRepeatCount as kU, setRepeatMode as kV, setSequence as kW, setSeriesChartType as kX, setSeriesColor as kY, setSeriesErrorBars as kZ, setSeriesMarker as k_, rulerStripTicks as ka, sampleColorFromSlide as kb, sanitizeColor as kc, sanitizeSlideIndex as kd, sanitizeUserName as ke, saveViewerProfile as kf, savedPresentationFileName as kg, scanAvailableFonts as kh, searchSlides as ki, seedBroadcastFields as kj, seedHyperlinkDraft as kk, seedPropertiesDraft as kl, seedShareFields as km, segmentFrameCount as kn, selectValue$3 as ko, sendBackward as kp, sendToBack as kq, sequentialColorScale as kr, serializeWriteBack as ks, seriesColor as kt, setAfterAnimation as ku, setAfterAnimationColor as kv, setAnimationEmphasis as kw, setAnimationEntrance as kx, setAnimationExit as ky, setAxis as kz, AdvancedChartEditorComponent as l, valueToY as l$, setSeriesTrendline as l0, setSeriesValue as l1, setStyle as l2, setTimingCurve as l3, setTitle as l4, setTrigger as l5, setTriggerShapeId as l6, shapeStylePatch$1 as l7, sheetAfterNavigate as l8, shouldBlockClickAdvance as l9, textAdvancedStateOf as lA, textColorOf as lB, textDirectionPatch as lC, textFontSizePatch as lD, textStyleOf as lE, textStylePatch as lF, themeStyle as lG, themeToCssVars as lH, thumbnailHeight as lI, thumbnailZoom as lJ, toggleCommentResolvedInList as lK, toggleNodeBold as lL, toggleNodeItalic as lM, toggleSheet as lN, topLevelNodeCount as lO, transformSelectedTextCase as lP, translationsEn as lQ, updateElementById as lR, updateGlowPatch as lS, updateGradientStopPatch as lT, updateInnerShadowPatch as lU, updateOuterShadowPatch as lV, updateReflectionPatch as lW, vAlignPatch as lX, validatePassword as lY, validatePrintSettings as lZ, validateRoomId as l_, shouldUseSvgWarp as la, showDirectionPicker as lb, showsTemplateAffordance as lc, signatureCountLabel as ld, signatureKey as le, signatureTimestamp as lf, signerName as lg, statusLabel as lh, slideNumberOf as li, slidesWithReappliedLayout as lj, smartArtNodes as lk, paletteColour as ll, snapToGridStep as lm, splitCursorCell as ln, splitMergedCell as lo, statusKind as lp, statusLabel$1 as lq, storeAudienceContent as lr, stringFromEvent$5 as ls, strokeColorOf as lt, strokeToInkElement as lu, strokeWidthOf as lv, styleShadowFilter as lw, surfaceColor as lx, textAdvancedPatch as ly, textAdvancedStateFromStyle as lz, AiChangeOverlayComponent as m, vermilionDarkColors as m0, vermilionDarkTheme as m1, vermilionLightColors as m2, vermilionLightTheme as m3, vermilionRadius as m4, waypointsToPathD as m5, withManualLayouts as m6, worstStatus as m7, zoomTargetSlideIndex as m8, AiChatPanelComponent as n, AiChatService as o, AiComposerComponent as p, AiFocusBarComponent as q, AiFocusHighlightOverlayComponent as r, AiHistoryMenuComponent as s, toChatSummary as t, AiHistoryService as u, AiMessageListComponent as v, AiPanelStore as w, AiProposalCardComponent as x, AiSettingsSectionComponent as y, AiToolCallCardComponent as z };
167013
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-BzS7I0F9.mjs.map