pptx-angular-viewer 3.19.2 → 3.20.1

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.
@@ -8,7 +8,7 @@ import DOMPurify from 'dompurify';
8
8
  import { z } from 'zod';
9
9
  import * as mcp from 'pptx-viewer-mcp';
10
10
  import * as mcpSchemas from 'pptx-viewer-mcp/schemas';
11
- import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucideLayers, LucideMessageSquare, LucidePlus, LucideSettings2, LucideStickyNote, LucideDownload, LucideMenu, LucidePresentation, LucideRedo, LucideShare2, LucideSparkles, LucideUndo, LucideChevronRight, LucideChevronLeft, LucideEraser, LucideHighlighter, LucideMousePointer2, LucidePanelRight, LucidePenTool, LucideTimer, LucideArrowLeftRight, LucideCaptions, LucideCirclePause, LucideCirclePlay, LucideGrid2x2, LucideMonitor, LucideMonitorOff, LucideRotateCcw, LucideScan, LucideZoomIn, LucideZoomOut, LucideSave, LucidePlay, LucidePrinter, LucideFileDown, LucideSearch, LucideStar, LucideMoveRight, LucideMousePointerClick, LucidePaintbrush, LucideClock3, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucideLayoutTemplate, LucideScissors, LucideLink, LucideImage, LucideVideo, LucideDatabase, LucidePanelLeft, LucideEllipsis, LucideEye, LucideEyeOff, LucideColumns2, LucideCheck, LucideBug, LucideSend, LucideCrosshair, LucideGitMerge, LucidePin, LucidePinOff, LucideHistory, LucideMessageSquarePlus, LucideWrench, LucideLoaderCircle, LucideTriangleAlert, LucideShapes, LucidePalette, LucideTable, LucideChartColumn, LucideMove, LucideNavigation, LucideFilm, LucideBot, LucideUser } from '@lucide/angular';
11
+ import { LucideX, LucideSquare, LucideCircle, LucideSlash, LucideCopy, LucideTrash2, LucideChevronsUp, LucideChevronsDown, LucideArrowUp, LucideArrowDown, LucideGroup, LucideUngroup, LucideTextAlignStart, LucideTextAlignCenter, LucideTextAlignEnd, LucideChevronUp, LucideChevronDown, LucideAlignHorizontalSpaceAround, LucideAlignVerticalSpaceAround, LucidePlus, LucidePaintbrush, LucideFilter, LucideLayers, LucideMessageSquare, LucideSettings2, LucideStickyNote, LucideDownload, LucideMenu, LucidePresentation, LucideRedo, LucideShare2, LucideSparkles, LucideUndo, LucideChevronRight, LucideChevronLeft, LucideEraser, LucideHighlighter, LucideMousePointer2, LucidePanelRight, LucidePenTool, LucideTimer, LucideArrowLeftRight, LucideCaptions, LucideCirclePause, LucideCirclePlay, LucideGrid2x2, LucideMonitor, LucideMonitorOff, LucideRotateCcw, LucideScan, LucideZoomIn, LucideZoomOut, LucideSave, LucidePlay, LucidePrinter, LucideFileDown, LucideSearch, LucideStar, LucideMoveRight, LucideMousePointerClick, LucideClock3, LucidePencil, LucideType, LucideMinus, LucideSpline, LucideArrowLeft, LucideFilePlus2, LucideFolderOpen, LucideHome, LucideInfo, LucideSettings, LucideUpload, LucideUserRound, LucideAArrowUp, LucideAArrowDown, LucideRemoveFormatting, LucideList, LucideListOrdered, LucideListIndentDecrease, LucideListIndentIncrease, LucideTextAlignJustify, LucideClipboardPaste, LucideFolderPlus, LucideLayoutGrid, LucideLayoutTemplate, LucideScissors, LucideLink, LucideImage, LucideVideo, LucideDatabase, LucidePanelLeft, LucideEllipsis, LucideEye, LucideEyeOff, LucideColumns2, LucideCheck, LucideBug, LucideSend, LucideCrosshair, LucideGitMerge, LucidePin, LucidePinOff, LucideHistory, LucideMessageSquarePlus, LucideWrench, LucideLoaderCircle, LucideTriangleAlert, LucideShapes, LucidePalette, LucideTable, LucideChartColumn, LucideMove, LucideNavigation, LucideFilm, LucideBot, LucideUser } from '@lucide/angular';
12
12
  import { XMLParser } from 'fast-xml-parser';
13
13
  import JSZip from 'jszip';
14
14
  import { DomSanitizer } from '@angular/platform-browser';
@@ -13504,12 +13504,79 @@ function compileEquationTemplateMathMl() {
13504
13504
  const NICE_STEPS = [1, 2, 2.5, 5, 10];
13505
13505
  /** The fraction of the data span added as headroom beyond the last data point. */
13506
13506
  const HEADROOM = 0.05;
13507
+ /**
13508
+ * Plot-area points of vertical room PowerPoint reserves per gridline before it
13509
+ * asks for another one, and the ceiling/floor on how many it will ever ask
13510
+ * for. See {@link axisTargetIntervals}'s doc comment for the PowerPoint COM
13511
+ * measurements these were fit to.
13512
+ */
13513
+ const POINTS_PER_GRIDLINE = 20;
13514
+ const MIN_TARGET_INTERVALS = 1;
13515
+ const MAX_TARGET_INTERVALS = 10;
13516
+ /**
13517
+ * Pixels per point in the "px" unit `computePlotLayout` (and every renderer in
13518
+ * this engine) works in: 96 px per inch, 72 points per inch, so 4/3 px per pt.
13519
+ * Mirrors `EMU_PER_PIXEL` (core/constants.ts): `EMU_PER_POINT / EMU_PER_PIXEL`
13520
+ * reduces to the same 4/3.
13521
+ */
13522
+ const PX_PER_POINT$1 = 4 / 3;
13523
+ /** {@link niceValueAxisBounds}'s `targetIntervals` when no plot height is known. */
13524
+ const DEFAULT_TARGET_INTERVALS = 4;
13507
13525
  /**
13508
13526
  * How close the smaller end of the data has to be to the larger before the axis
13509
13527
  * stops anchoring at zero. Below 5/6, zero anchoring keeps the bars readable;
13510
13528
  * above it, the data is a narrow band and zero would squash it flat.
13511
13529
  */
13512
13530
  const ZERO_ANCHOR_RATIO = 5 / 6;
13531
+ /**
13532
+ * How many gridline intervals PowerPoint's automatic value-axis scale aims
13533
+ * for, given the chart's plot-area height in the "px" unit `computePlotLayout`
13534
+ * returns (96 px/inch; see `PX_PER_POINT` above).
13535
+ *
13536
+ * This is NOT a universal constant (see this module's original doc comment,
13537
+ * which admitted as much: "matches the axes PowerPoint draws for a chart of
13538
+ * ORDINARY height"): a short chart gets fewer, coarser gridlines than a tall
13539
+ * one, up to a point, because PowerPoint only has room to label so many
13540
+ * without the axis text crowding.
13541
+ *
13542
+ * Measured via PowerPoint COM automation (`New-Object -ComObject
13543
+ * PowerPoint.Application`, `Shapes.AddChart2`, reading back
13544
+ * `chart.Axes(2).MinimumScale/.MaximumScale/.MajorUnit`): building a fresh
13545
+ * clustered-column chart at increasing shape heights with the SAME 8-point,
13546
+ * single-category data (values 1.2-3.2, the exact case reported against this
13547
+ * engine, which this engine rendered 0-4 while PowerPoint drew 0-3.5):
13548
+ *
13549
+ * | chart height | plot height | PowerPoint axis | gridlines |
13550
+ * |--------------|-------------|------------------|-----------|
13551
+ * | 100pt | ~33pt | 0 to 5, unit 5 | 1 |
13552
+ * | 150pt | ~83pt | 0 to 4, unit 1 | 4 |
13553
+ * | 200pt | ~133pt | 0 to 3.5, unit 0.5 | 7 |
13554
+ * | 300pt | ~233pt | 0 to 3.5, unit 0.5 | 7 |
13555
+ * | 1000pt | ~933pt | 0 to 3.5, unit 0.5 | 7 (unchanged) |
13556
+ *
13557
+ * Cross-checked against two more datasets (0-52 and 0-9) at the same set of
13558
+ * heights to separate "the target interval count" from "which nice-number
13559
+ * bucket a particular span happens to round into": PowerPoint never asked for
13560
+ * more than about 10 intervals even at a 1000pt-tall chart, it only asks for
13561
+ * FEWER on a plot area too short to fit that many labels. That saturation
13562
+ * (not a straight line) is why this is clamped at the top, not just scaled.
13563
+ *
13564
+ * Modelled as one gridline interval per ~20pt of plot height (roughly one
13565
+ * axis-label line plus padding), clamped to `[1, 10]`. This will not be exact
13566
+ * for every data range: the actual PowerPoint algorithm also nudges the count
13567
+ * by how the span happens to snap to a nice number (see the module doc
13568
+ * comment), which this simplified model does not attempt to reproduce. It is
13569
+ * a large improvement over hard-coding the short-chart answer (4) for every
13570
+ * chart regardless of size, which is the bug this was added to fix.
13571
+ */
13572
+ function axisTargetIntervals(plotHeightPx) {
13573
+ if (!Number.isFinite(plotHeightPx) || plotHeightPx <= 0) {
13574
+ return DEFAULT_TARGET_INTERVALS;
13575
+ }
13576
+ const plotHeightPt = plotHeightPx / PX_PER_POINT$1;
13577
+ const raw = Math.round(plotHeightPt / POINTS_PER_GRIDLINE);
13578
+ return Math.min(MAX_TARGET_INTERVALS, Math.max(MIN_TARGET_INTERVALS, raw));
13579
+ }
13513
13580
  /** The smallest nice step at or above `value`. */
13514
13581
  function niceAxisStep(value) {
13515
13582
  if (!Number.isFinite(value) || value <= 0) {
@@ -13534,10 +13601,13 @@ function snap(value, unit, direction) {
13534
13601
  * @param dataMin Smallest plotted value.
13535
13602
  * @param dataMax Largest plotted value.
13536
13603
  * @param targetIntervals Roughly how many gridline steps to aim for. The snap to
13537
- * a round unit means the result is usually one fewer. Four matches the axes
13538
- * PowerPoint draws for a chart of ordinary height.
13604
+ * a round unit means the result is usually one fewer. Defaults to 4 only
13605
+ * when the caller has no idea how tall the chart's plot area is; pass
13606
+ * {@link axisTargetIntervals}`(plotHeightPx)` instead whenever that height is
13607
+ * known; see that function's doc comment for why a fixed constant undershot
13608
+ * real PowerPoint on any chart of ordinary-or-larger size.
13539
13609
  */
13540
- function niceValueAxisBounds(dataMin, dataMax, targetIntervals = 4) {
13610
+ function niceValueAxisBounds(dataMin, dataMax, targetIntervals = DEFAULT_TARGET_INTERVALS) {
13541
13611
  if (!Number.isFinite(dataMin) || !Number.isFinite(dataMax)) {
13542
13612
  return { min: 0, max: 1, majorUnit: 0.5 };
13543
13613
  }
@@ -14131,13 +14201,19 @@ function paletteColor$1(index, styleId, colorPalette) {
14131
14201
  * sensibly, padded, and rounded out to whole major units. See
14132
14202
  * `chart-axis-nice.ts` for the rules. Running the axis to the raw data maximum
14133
14203
  * instead put the top gridline on whatever the tallest bar happened to be.
14204
+ *
14205
+ * @param plotHeightPx The chart's plot-area height (same "px" unit
14206
+ * `computePlotLayout` returns), when the caller has it. PowerPoint's real
14207
+ * gridline count depends on how much vertical room the axis has to label
14208
+ * them in; omitting this falls back to a constant tuned for a short chart
14209
+ * (see `axisTargetIntervals`'s doc comment).
14134
14210
  */
14135
- function computeValueRange$1(series) {
14211
+ function computeValueRange$1(series, plotHeightPx) {
14136
14212
  const allValues = series.flatMap((s) => s.values);
14137
14213
  if (allValues.length === 0) {
14138
14214
  return { min: 0, max: 1, span: 1 };
14139
14215
  }
14140
- const { min, max, majorUnit } = niceValueAxisBounds(Math.min(...allValues), Math.max(...allValues));
14216
+ const { min, max, majorUnit } = niceValueAxisBounds(Math.min(...allValues), Math.max(...allValues), plotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined);
14141
14217
  return { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };
14142
14218
  }
14143
14219
  /**
@@ -14704,15 +14780,24 @@ function computeLogValueRange(series, logBase) {
14704
14780
  logBase,
14705
14781
  };
14706
14782
  }
14707
- /** Compute a value range using one parsed value axis's scale and bounds. */
14708
- function computeValueRangeForAxis(series, axis) {
14783
+ /**
14784
+ * Compute a value range using one parsed value axis's scale and bounds.
14785
+ *
14786
+ * @param plotHeightPx The chart's plot-area height, when known; forwarded to
14787
+ * `computeValueRange`'s automatic-scale gridline count (see
14788
+ * `axisTargetIntervals`'s doc comment). Not used on the log-scale branch,
14789
+ * which snaps to powers of the log base regardless of chart size.
14790
+ */
14791
+ function computeValueRangeForAxis(series, axis, plotHeightPx) {
14709
14792
  const requestedLogBase = axis?.logBase ?? 10;
14710
14793
  const logBase = axis?.logScale && Number.isFinite(requestedLogBase) && requestedLogBase > 1
14711
14794
  ? requestedLogBase
14712
14795
  : axis?.logScale
14713
14796
  ? 10
14714
14797
  : undefined;
14715
- const automatic = logBase ? computeLogValueRange(series, logBase) : computeValueRange$1(series);
14798
+ const automatic = logBase
14799
+ ? computeLogValueRange(series, logBase)
14800
+ : computeValueRange$1(series, plotHeightPx);
14716
14801
  const validMin = typeof axis?.min === 'number' && Number.isFinite(axis.min) && (!logBase || axis.min > 0)
14717
14802
  ? axis.min
14718
14803
  : undefined;
@@ -14808,11 +14893,15 @@ function generateMinorAxisTicks(range, axis) {
14808
14893
  function findLogAxis(axes) {
14809
14894
  return axes?.find((axis) => axis.axisType === 'valAx' && axis.logScale);
14810
14895
  }
14811
- /** Compute the primary value range for a chart. */
14812
- function computeValueRangeForChart(series, axes) {
14896
+ /**
14897
+ * Compute the primary value range for a chart.
14898
+ *
14899
+ * @param plotHeightPx See `computeValueRangeForAxis`'s parameter of the same name.
14900
+ */
14901
+ function computeValueRangeForChart(series, axes, plotHeightPx) {
14813
14902
  const primaryAxis = axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'l') ??
14814
14903
  axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'r');
14815
- return computeValueRangeForAxis(series, primaryAxis);
14904
+ return computeValueRangeForAxis(series, primaryAxis, plotHeightPx);
14816
14905
  }
14817
14906
 
14818
14907
  // ── Display units ────────────────────────────────────────────────
@@ -15041,6 +15130,160 @@ function shade(hex, amount) {
15041
15130
  return rgbToHex$3(r * (1 - amount), g * (1 - amount), b * (1 - amount));
15042
15131
  }
15043
15132
 
15133
+ /**
15134
+ * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for
15135
+ * line / scatter / area chart data points.
15136
+ *
15137
+ * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,
15138
+ * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an
15139
+ * optional `c:size` (2-72 points). The base view-model historically drew every
15140
+ * data point as a fixed-radius circle, ignoring both. This helper resolves the
15141
+ * parsed marker into the correct `SvgPrimitive` at the requested size, and
15142
+ * returns `null` for `symbol === 'none'` so no dot is drawn.
15143
+ *
15144
+ * @module chart-marker-shape
15145
+ */
15146
+ /**
15147
+ * PowerPoint's automatic marker-symbol cycle: the fixed shape sequence a
15148
+ * "Line/Scatter with Markers" chart cycles through when a series' `c:marker`
15149
+ * carries no `c:symbol` (only its fill/line colour is "automatic"; the shape
15150
+ * itself was assumed to always be a circle before this was measured).
15151
+ *
15152
+ * COM-measured ground truth (`PowerPoint.Application`, a stacked
15153
+ * Line-with-Markers chart, N series each with `<c:marker><c:spPr>.../></c:marker>`
15154
+ * and no `c:symbol`, `SeriesCollection(i).MarkerStyle` read back after a real
15155
+ * save/reopen round trip): idx 0..8 resolved to
15156
+ * Diamond, Square, Triangle, X, Star, Circle, Plus, Dot, Dash - a clean
15157
+ * 9-element cycle with no partial/ambiguous entries across 9 independent
15158
+ * series (this is ALSO what the chart-style-driven, explicit-symbol path a
15159
+ * modern "Line with Markers" preset writes on save resolves every series to a
15160
+ * uniform Circle, so that path is unrelated: this cycle is specifically
15161
+ * what PowerPoint's renderer falls back to for a chart with no `c:symbol` at
15162
+ * all). Confirmed against a real-world deck: series `c:idx="1"`/`"2"` (a
15163
+ * gapped, 1-based pair, not `0`/`1`) resolved to Square/Triangle exactly as
15164
+ * this cycle predicts (`AUTOMATIC_MARKER_CYCLE[1]` / `[2]`).
15165
+ */
15166
+ const AUTOMATIC_MARKER_CYCLE = [
15167
+ 'diamond',
15168
+ 'square',
15169
+ 'triangle',
15170
+ 'x',
15171
+ 'star',
15172
+ 'circle',
15173
+ 'plus',
15174
+ 'dot',
15175
+ 'dash',
15176
+ ];
15177
+ /**
15178
+ * Resolve the automatic marker shape for a series with no authored
15179
+ * `c:symbol`, keyed by the series' `c:idx` (or its array position when the
15180
+ * chart has none): {@link AUTOMATIC_MARKER_CYCLE} repeats every 9 series.
15181
+ */
15182
+ function automaticMarkerSymbol(seriesIdx) {
15183
+ const length = AUTOMATIC_MARKER_CYCLE.length;
15184
+ const normalized = ((seriesIdx % length) + length) % length;
15185
+ return AUTOMATIC_MARKER_CYCLE[normalized];
15186
+ }
15187
+ /** Resolve the drawn radius (px) from the parsed point size or the default. */
15188
+ function markerRadius(size, defaultRadius) {
15189
+ if (size === undefined || !Number.isFinite(size) || size <= 0) {
15190
+ return defaultRadius;
15191
+ }
15192
+ // OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.
15193
+ return size / 2;
15194
+ }
15195
+ /** Build the SVG points string for a regular/irregular polygon vertex list. */
15196
+ function polygonPoints(vertices) {
15197
+ return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');
15198
+ }
15199
+ function starVertices(cx, cy, r) {
15200
+ const inner = r * 0.5;
15201
+ const out = [];
15202
+ for (let i = 0; i < 10; i++) {
15203
+ const radius = i % 2 === 0 ? r : inner;
15204
+ const angle = -Math.PI / 2 + (Math.PI * i) / 5;
15205
+ out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
15206
+ }
15207
+ return out;
15208
+ }
15209
+ /**
15210
+ * Build the marker primitive for one data point, honouring `symbol` and `size`.
15211
+ * Returns `null` when `symbol === 'none'` (draw nothing).
15212
+ */
15213
+ function buildMarkerPrimitive(input) {
15214
+ const { symbol, cx, cy, fill, part } = input;
15215
+ if (symbol === 'none') {
15216
+ return null;
15217
+ }
15218
+ const r = markerRadius(input.size, input.defaultRadius);
15219
+ const stroke = fill;
15220
+ switch (symbol) {
15221
+ case 'square':
15222
+ return { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };
15223
+ case 'dash':
15224
+ return { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };
15225
+ case 'diamond':
15226
+ return {
15227
+ kind: 'polygon',
15228
+ points: polygonPoints([
15229
+ [cx, cy - r],
15230
+ [cx + r, cy],
15231
+ [cx, cy + r],
15232
+ [cx - r, cy],
15233
+ ]),
15234
+ fill,
15235
+ stroke,
15236
+ strokeWidth: 0,
15237
+ part,
15238
+ };
15239
+ case 'triangle':
15240
+ return {
15241
+ kind: 'polygon',
15242
+ points: polygonPoints([
15243
+ [cx, cy - r],
15244
+ [cx + r * 0.9, cy + r * 0.75],
15245
+ [cx - r * 0.9, cy + r * 0.75],
15246
+ ]),
15247
+ fill,
15248
+ stroke,
15249
+ strokeWidth: 0,
15250
+ part,
15251
+ };
15252
+ case 'star':
15253
+ return {
15254
+ kind: 'polygon',
15255
+ points: polygonPoints(starVertices(cx, cy, r)),
15256
+ fill,
15257
+ stroke,
15258
+ strokeWidth: 0,
15259
+ part,
15260
+ };
15261
+ case 'plus':
15262
+ return {
15263
+ kind: 'path',
15264
+ d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
15265
+ fill: 'none',
15266
+ stroke,
15267
+ strokeWidth: Math.max(1, r * 0.4),
15268
+ part,
15269
+ };
15270
+ case 'x':
15271
+ return {
15272
+ kind: 'path',
15273
+ d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
15274
+ fill: 'none',
15275
+ stroke,
15276
+ strokeWidth: Math.max(1, r * 0.4),
15277
+ part,
15278
+ };
15279
+ case 'dot':
15280
+ return { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };
15281
+ default:
15282
+ // circle / auto / picture / undefined -> filled circle.
15283
+ return { kind: 'circle', cx, cy, r, fill, part };
15284
+ }
15285
+ }
15286
+
15044
15287
  /**
15045
15288
  * chart-datapoint-style.ts: framework-agnostic resolution of per-data-point
15046
15289
  * formatting overrides (`c:dPt`).
@@ -15101,11 +15344,25 @@ function resolveDataPointExplosion(series, pointIndex) {
15101
15344
  * looked at `series.marker`, so editing a point marker changed the file and
15102
15345
  * left the canvas untouched. Resolving it here fixes every binding at once,
15103
15346
  * since they all paint the same shared view model.
15347
+ *
15348
+ * A resolved symbol of `'auto'` (or a marker present with no `c:symbol` at
15349
+ * all, which the core parser also normalises to `'auto'`) is resolved to a
15350
+ * concrete shape via {@link automaticMarkerSymbol}, keyed by `series.idx`
15351
+ * (falling back to `seriesPosition`, the series' array index, when the chart
15352
+ * carries no `c:idx`). A series/point with NO marker element at all
15353
+ * (`marker` and `point` both `undefined`) keeps `symbol: undefined`
15354
+ * unchanged: that is a chart type that draws no marker at all, not an
15355
+ * automatic one, and must not start cycling shapes.
15104
15356
  */
15105
- function resolveDataPointMarker(series, pointIndex) {
15357
+ function resolveDataPointMarker(series, pointIndex, seriesPosition = 0) {
15106
15358
  const point = findDataPoint(series, pointIndex)?.marker;
15359
+ const hasMarker = point !== undefined || series.marker !== undefined;
15360
+ const rawSymbol = point?.symbol ?? series.marker?.symbol;
15361
+ const symbol = hasMarker && (rawSymbol === undefined || rawSymbol === 'auto')
15362
+ ? automaticMarkerSymbol(series.idx ?? seriesPosition)
15363
+ : rawSymbol;
15107
15364
  return {
15108
- symbol: point?.symbol ?? series.marker?.symbol,
15365
+ symbol,
15109
15366
  size: point?.size ?? series.marker?.size,
15110
15367
  fill: point?.spPr?.fillColor ?? series.marker?.spPr?.fillColor,
15111
15368
  };
@@ -15837,119 +16094,6 @@ function computeChartLegendLayout(vm) {
15837
16094
  });
15838
16095
  }
15839
16096
 
15840
- /**
15841
- * chart-marker-shape.ts: framework-agnostic marker-symbol primitive builder for
15842
- * line / scatter / area chart data points.
15843
- *
15844
- * OOXML line/scatter series carry a `c:marker` with a `c:symbol` (circle,
15845
- * diamond, square, triangle, star, x, plus, dot, dash, none, ...) and an
15846
- * optional `c:size` (2-72 points). The base view-model historically drew every
15847
- * data point as a fixed-radius circle, ignoring both. This helper resolves the
15848
- * parsed marker into the correct `SvgPrimitive` at the requested size, and
15849
- * returns `null` for `symbol === 'none'` so no dot is drawn.
15850
- *
15851
- * @module chart-marker-shape
15852
- */
15853
- /** Resolve the drawn radius (px) from the parsed point size or the default. */
15854
- function markerRadius(size, defaultRadius) {
15855
- if (size === undefined || !Number.isFinite(size) || size <= 0) {
15856
- return defaultRadius;
15857
- }
15858
- // OOXML marker size is a point diameter; treat 1pt ~ 1px at chart scale.
15859
- return size / 2;
15860
- }
15861
- /** Build the SVG points string for a regular/irregular polygon vertex list. */
15862
- function polygonPoints(vertices) {
15863
- return vertices.map(([x, y]) => `${x.toFixed(2)},${y.toFixed(2)}`).join(' ');
15864
- }
15865
- function starVertices(cx, cy, r) {
15866
- const inner = r * 0.5;
15867
- const out = [];
15868
- for (let i = 0; i < 10; i++) {
15869
- const radius = i % 2 === 0 ? r : inner;
15870
- const angle = -Math.PI / 2 + (Math.PI * i) / 5;
15871
- out.push([cx + radius * Math.cos(angle), cy + radius * Math.sin(angle)]);
15872
- }
15873
- return out;
15874
- }
15875
- /**
15876
- * Build the marker primitive for one data point, honouring `symbol` and `size`.
15877
- * Returns `null` when `symbol === 'none'` (draw nothing).
15878
- */
15879
- function buildMarkerPrimitive(input) {
15880
- const { symbol, cx, cy, fill, part } = input;
15881
- if (symbol === 'none') {
15882
- return null;
15883
- }
15884
- const r = markerRadius(input.size, input.defaultRadius);
15885
- const stroke = fill;
15886
- switch (symbol) {
15887
- case 'square':
15888
- return { kind: 'rect', x: cx - r, y: cy - r, w: r * 2, h: r * 2, fill, part };
15889
- case 'dash':
15890
- return { kind: 'rect', x: cx - r, y: cy - r * 0.32, w: r * 2, h: r * 0.64, fill, part };
15891
- case 'diamond':
15892
- return {
15893
- kind: 'polygon',
15894
- points: polygonPoints([
15895
- [cx, cy - r],
15896
- [cx + r, cy],
15897
- [cx, cy + r],
15898
- [cx - r, cy],
15899
- ]),
15900
- fill,
15901
- stroke,
15902
- strokeWidth: 0,
15903
- part,
15904
- };
15905
- case 'triangle':
15906
- return {
15907
- kind: 'polygon',
15908
- points: polygonPoints([
15909
- [cx, cy - r],
15910
- [cx + r * 0.9, cy + r * 0.75],
15911
- [cx - r * 0.9, cy + r * 0.75],
15912
- ]),
15913
- fill,
15914
- stroke,
15915
- strokeWidth: 0,
15916
- part,
15917
- };
15918
- case 'star':
15919
- return {
15920
- kind: 'polygon',
15921
- points: polygonPoints(starVertices(cx, cy, r)),
15922
- fill,
15923
- stroke,
15924
- strokeWidth: 0,
15925
- part,
15926
- };
15927
- case 'plus':
15928
- return {
15929
- kind: 'path',
15930
- d: `M${(cx - r).toFixed(2)},${cy.toFixed(2)} L${(cx + r).toFixed(2)},${cy.toFixed(2)} M${cx.toFixed(2)},${(cy - r).toFixed(2)} L${cx.toFixed(2)},${(cy + r).toFixed(2)}`,
15931
- fill: 'none',
15932
- stroke,
15933
- strokeWidth: Math.max(1, r * 0.4),
15934
- part,
15935
- };
15936
- case 'x':
15937
- return {
15938
- kind: 'path',
15939
- d: `M${(cx - r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx + r).toFixed(2)},${(cy + r).toFixed(2)} M${(cx + r).toFixed(2)},${(cy - r).toFixed(2)} L${(cx - r).toFixed(2)},${(cy + r).toFixed(2)}`,
15940
- fill: 'none',
15941
- stroke,
15942
- strokeWidth: Math.max(1, r * 0.4),
15943
- part,
15944
- };
15945
- case 'dot':
15946
- return { kind: 'circle', cx, cy, r: Math.max(r * 0.6, 1), fill, part };
15947
- default:
15948
- // circle / auto / picture / undefined -> filled circle.
15949
- return { kind: 'circle', cx, cy, r, fill, part };
15950
- }
15951
- }
15952
-
15953
16097
  /** Legend swatch line width in px: a fixed icon size, independent of the plotted series' own stroke width. */
15954
16098
  const LEGEND_LINE_SWATCH_WIDTH = 2;
15955
16099
  /** Legend swatch marker radius in px: a fixed icon size, independent of the series' own `c:marker/c:size`. */
@@ -15981,8 +16125,8 @@ function resolveLegendSwatchKind(kind) {
15981
16125
  * `c:marker/c:size`, so the legend icon stays a consistent small size
15982
16126
  * regardless of how large the plotted markers are.
15983
16127
  */
15984
- function buildLineLegendSwatch(series, color) {
15985
- const resolved = resolveDataPointMarker(series, -1), primitives = [];
16128
+ function buildLineLegendSwatch(series, color, seriesPosition = 0) {
16129
+ const resolved = resolveDataPointMarker(series, -1, seriesPosition), primitives = [];
15986
16130
  if (!series.lineNoFill) {
15987
16131
  primitives.push({
15988
16132
  kind: 'line',
@@ -16153,8 +16297,12 @@ function seriesColor(series, index, colorPalette) {
16153
16297
  /**
16154
16298
  * Automatic Y-axis range, on PowerPoint's terms. See `chart-axis-nice.ts`; this
16155
16299
  * mirrors `computeValueRange` in `chart-helpers.ts`.
16300
+ *
16301
+ * @param plotHeightPx The chart's plot-area height (`PlotLayout.plotHeight`),
16302
+ * when the caller has it; see `axisTargetIntervals`'s doc comment for why
16303
+ * this changes the gridline count PowerPoint's automatic scale picks.
16156
16304
  */
16157
- function computeValueRange(series) {
16305
+ function computeValueRange(series, plotHeightPx) {
16158
16306
  let dataMin = Number.POSITIVE_INFINITY, dataMax = Number.NEGATIVE_INFINITY;
16159
16307
  for (const item of series) {
16160
16308
  for (const value of item.values) {
@@ -16169,14 +16317,16 @@ function computeValueRange(series) {
16169
16317
  if (dataMin === Number.POSITIVE_INFINITY) {
16170
16318
  return { min: 0, max: 1, span: 1 };
16171
16319
  }
16172
- const { min, max, majorUnit } = niceValueAxisBounds(dataMin, dataMax);
16320
+ const { min, max, majorUnit } = niceValueAxisBounds(dataMin, dataMax, plotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined);
16173
16321
  return { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };
16174
16322
  }
16175
16323
  /**
16176
16324
  * Value range for a stacked bar: the per-category sums, then the same automatic
16177
16325
  * scale as any other value axis.
16326
+ *
16327
+ * @param plotHeightPx See `computeValueRange`'s parameter of the same name.
16178
16328
  */
16179
- function computeStackedValueRange(series, catCount) {
16329
+ function computeStackedValueRange(series, catCount, plotHeightPx) {
16180
16330
  let maxSum = 0, minSum = 0;
16181
16331
  for (let ci = 0; ci < catCount; ci++) {
16182
16332
  let pos = 0, neg = 0;
@@ -16192,7 +16342,7 @@ function computeStackedValueRange(series, catCount) {
16192
16342
  maxSum = Math.max(maxSum, pos);
16193
16343
  minSum = Math.min(minSum, neg);
16194
16344
  }
16195
- const { min, max, majorUnit } = niceValueAxisBounds(Math.min(minSum, 0), Math.max(maxSum, 0));
16345
+ const { min, max, majorUnit } = niceValueAxisBounds(Math.min(minSum, 0), Math.max(maxSum, 0), plotHeightPx !== undefined ? axisTargetIntervals(plotHeightPx) : undefined);
16196
16346
  return { min, max, span: Math.max(max - min, Number.EPSILON), majorUnit };
16197
16347
  }
16198
16348
  /**
@@ -16271,7 +16421,7 @@ function buildLegend(series, colorPalette, svgWidth, legendPos, svgHeight, plotT
16271
16421
  return {
16272
16422
  color,
16273
16423
  label: s.name,
16274
- ...(kind === 'line' ? { lineSwatch: buildLineLegendSwatch(s, color) } : {}),
16424
+ ...(kind === 'line' ? { lineSwatch: buildLineLegendSwatch(s, color, i) } : {}),
16275
16425
  };
16276
16426
  });
16277
16427
  let legendX = svgWidth / 2, legendY = svgHeight - 8, legendAnchor = 'middle';
@@ -17318,8 +17468,8 @@ function xyMarkTooltip(seriesName, xVal, yVal, numberFormat) {
17318
17468
  * fewer points than the series declares and the override must still land on the
17319
17469
  * point the author picked.
17320
17470
  */
17321
- function pushMarker(out, series, pointIndex, cx, cy, fill, defaultRadius, part, opacity, title) {
17322
- const marker = resolveDataPointMarker(series, pointIndex), m = buildMarkerPrimitive({
17471
+ function pushMarker(out, series, pointIndex, cx, cy, fill, defaultRadius, part, opacity, title, seriesPosition = part.seriesIndex ?? 0) {
17472
+ const marker = resolveDataPointMarker(series, pointIndex, seriesPosition), m = buildMarkerPrimitive({
17323
17473
  symbol: marker.symbol,
17324
17474
  size: marker.size,
17325
17475
  cx,
@@ -19336,11 +19486,15 @@ function barFill(chartData, series, seriesIndex, pointIndex) {
19336
19486
  * clustered / stacked / percentStacked geometry with the axes transposed.
19337
19487
  */
19338
19488
  function buildHorizontalBarViewModel(element, chartData, categoryLabels) {
19339
- const layout = computePlotLayout(element.width, element.height, chartData, true), catCount = Math.max(categoryLabels.length, 1), series = chartData.series, grouping = chartData.grouping ?? 'clustered', isStacked = grouping === 'stacked' || grouping === 'percentStacked', isPercent = grouping === 'percentStacked', range = isPercent
19489
+ const layout = computePlotLayout(element.width, element.height, chartData, true), catCount = Math.max(categoryLabels.length, 1), series = chartData.series, grouping = chartData.grouping ?? 'clustered', isStacked = grouping === 'stacked' || grouping === 'percentStacked', isPercent = grouping === 'percentStacked',
19490
+ // The value axis runs along the WIDTH here (categories run down the left,
19491
+ // values along the bottom: this builder transposes the column engine), so
19492
+ // the gridline-count budget is keyed off plotWidth, not plotHeight.
19493
+ range = isPercent
19340
19494
  ? { min: 0, max: 100, span: 100 }
19341
19495
  : isStacked
19342
- ? computeStackedValueRange(series, catCount)
19343
- : computeValueRangeForChart(series, chartData.axes), { gridlines, axisLabels } = buildTransposedValueAxis(range, layout), zeroX = valueToX(0, range, layout.plotLeft, layout.plotRight), zeroLine = range.min < 0 && range.max > 0
19496
+ ? computeStackedValueRange(series, catCount, layout.plotWidth)
19497
+ : computeValueRangeForChart(series, chartData.axes, layout.plotWidth), { gridlines, axisLabels } = buildTransposedValueAxis(range, layout), zeroX = valueToX(0, range, layout.plotLeft, layout.plotRight), zeroLine = range.min < 0 && range.max > 0
19344
19498
  ? {
19345
19499
  kind: 'line',
19346
19500
  x1: zeroX,
@@ -20056,11 +20210,11 @@ function computeTrendlinePrimitives(chartData, catCount, layout, range, mode = '
20056
20210
  * @module chart-overlays
20057
20211
  */
20058
20212
 
20059
- function stackedRange(chartData, catCount, isPercent) {
20213
+ function stackedRange(chartData, catCount, isPercent, plotHeightPx) {
20060
20214
  if (isPercent) {
20061
20215
  return { min: 0, max: 100, span: 100 };
20062
20216
  }
20063
- return computeStackedValueRange(chartData.series, catCount);
20217
+ return computeStackedValueRange(chartData.series, catCount, plotHeightPx);
20064
20218
  }
20065
20219
  /**
20066
20220
  * Build the enriched cartesian view-model for bar / line / area / scatter /
@@ -20111,13 +20265,13 @@ function buildCartesianViewModel(element, chartData, categoryLabels, kind) {
20111
20265
  // eslint-disable-next-line one-var -- pre-existing, unrelated to this change
20112
20266
  const primaryRange = isStacked
20113
20267
  ? {
20114
- ...stackedRange(chartData, catCount, isPercent),
20268
+ ...stackedRange(chartData, catCount, isPercent, layout.autoPlotHeight),
20115
20269
  ...(primaryAxis?.orientation === 'maxMin' ? { reverseOrder: true } : {}),
20116
20270
  }
20117
- : computeValueRangeForChart(primaryPlotSeries.length > 0 ? primaryPlotSeries : chartData.series, chartData.axes);
20271
+ : computeValueRangeForChart(primaryPlotSeries.length > 0 ? primaryPlotSeries : chartData.series, chartData.axes, layout.autoPlotHeight);
20118
20272
  // eslint-disable-next-line one-var -- pre-existing, unrelated to this change
20119
20273
  const secondaryRange = useSecondary && secondaryPlotSeries.length > 0
20120
- ? computeValueRangeForAxis(secondaryPlotSeries, chartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'r'))
20274
+ ? computeValueRangeForAxis(secondaryPlotSeries, chartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos === 'r'), layout.autoPlotHeight)
20121
20275
  : undefined;
20122
20276
  // eslint-disable-next-line one-var -- pre-existing, unrelated to this change
20123
20277
  const axisRes = buildCartesianAxes(chartData, layout, primaryRange, secondaryRange, catCount);
@@ -20342,9 +20496,9 @@ function buildComboViewModel(element, chartData, categoryLabels) {
20342
20496
  const primaryAxisId = getPrimaryValueAxisId(chartData.axes);
20343
20497
  const primaryAxis = chartData.axes?.find((axis) => axis.axisId === primaryAxisId);
20344
20498
  const secondaryAxisFormatting = getSecondaryValueAxis(chartData.axes);
20345
- const primaryRange = computeValueRangeForAxis(primarySeries, primaryAxis);
20499
+ const primaryRange = computeValueRangeForAxis(primarySeries, primaryAxis, layout.autoPlotHeight);
20346
20500
  const secondaryRange = secondary.length > 0
20347
- ? computeValueRangeForAxis(secondary.map((entry) => entry.series), secondaryAxisFormatting)
20501
+ ? computeValueRangeForAxis(secondary.map((entry) => entry.series), secondaryAxisFormatting, layout.autoPlotHeight)
20348
20502
  : undefined;
20349
20503
  const primaryCategoryAxis = chartData.axes?.find((axis) => (axis.axisType === 'catAx' || axis.axisType === 'dateAx') &&
20350
20504
  axis.axisId === primaryAxis?.crossAxisId);
@@ -20503,7 +20657,7 @@ function buildStockViewModel(element, chartData, categoryLabels) {
20503
20657
  // Through `computeValueRangeForChart`, not the bare linear helper: a stock
20504
20658
  // chart is as entitled to a log or display-unit value axis as any other
20505
20659
  // cartesian kind, and the bare helper silently ignores `c:scaling`.
20506
- const range = computeValueRangeForChart(chartData.series, chartData.axes);
20660
+ const range = computeValueRangeForChart(chartData.series, chartData.axes, layout.plotHeight);
20507
20661
  const valueAxis = chartData.axes?.find((axis) => axis.axisType === 'valAx' && axis.axPos !== 'r');
20508
20662
  const categoryAxis = chartData.axes?.find((axis) => (axis.axisType === 'catAx' || axis.axisType === 'dateAx') &&
20509
20663
  axis.axisId === valueAxis?.crossAxisId);
@@ -21324,22 +21478,26 @@ function buildSunburstViewModel(element, chartData, categoryLabels) {
21324
21478
  }
21325
21479
 
21326
21480
  /**
21327
- * Filter deleted entries and attach per-entry text-style overrides.
21328
- * Returns the input array unchanged (same reference) when there is nothing to
21329
- * apply, so callers with no `c:legendEntry` overrides pay no extra cost.
21481
+ * Filter deleted entries and attach per-entry text-style overrides, falling
21482
+ * back to the chart-level legend default (`PptxChartStyle.legendTextStyle`,
21483
+ * itself `c:legend/c:txPr` or `c:chartSpace/c:txPr`) for any entry that has no
21484
+ * `c:legendEntry/c:txPr` override of its own. Returns the input array
21485
+ * unchanged (same reference) when there is nothing to apply, so a chart with
21486
+ * neither kind of override pays no extra cost.
21330
21487
  */
21331
- function applyLegendEntryOverrides(legend, entries) {
21332
- if (!entries || entries.length === 0) {
21488
+ function applyLegendEntryOverrides(legend, entries, defaultTextStyle) {
21489
+ if ((!entries || entries.length === 0) && !defaultTextStyle) {
21333
21490
  return legend;
21334
21491
  }
21335
- const byIndex = new Map(entries.map((entry) => [entry.index, entry]));
21492
+ const byIndex = new Map((entries ?? []).map((entry) => [entry.index, entry]));
21336
21493
  const result = [];
21337
21494
  legend.forEach((item, index) => {
21338
21495
  const override = byIndex.get(index);
21339
21496
  if (override?.deleted) {
21340
21497
  return;
21341
21498
  }
21342
- result.push(override?.textStyle ? { ...item, textStyle: override.textStyle } : item);
21499
+ const textStyle = override?.textStyle ?? defaultTextStyle;
21500
+ result.push(textStyle ? { ...item, textStyle } : item);
21343
21501
  });
21344
21502
  return result;
21345
21503
  }
@@ -21738,7 +21896,7 @@ function buildSurfaceWallPanels(cols, rows, cellSize, zScale, offsetX, offsetY,
21738
21896
  */
21739
21897
  function buildIsometricSurfaceViewModel(element, chartData, categoryLabels) {
21740
21898
  const layout = computePlotLayout(element.width, element.height, chartData, false);
21741
- const range = computeValueRange(chartData.series);
21899
+ const range = computeValueRange(chartData.series, layout.autoPlotHeight);
21742
21900
  const catCount = Math.max(categoryLabels.length, 1);
21743
21901
  const seriesCount = chartData.series.length;
21744
21902
  // Grid cell count (vertices = cells + 1 in each dimension).
@@ -21884,7 +22042,7 @@ function buildIsometricSurfaceViewModel(element, chartData, categoryLabels) {
21884
22042
  */
21885
22043
  function buildFlatSurfaceViewModel(element, chartData, categoryLabels) {
21886
22044
  const layout = computePlotLayout(element.width, element.height, chartData, false);
21887
- const range = computeValueRange(chartData.series);
22045
+ const range = computeValueRange(chartData.series, layout.autoPlotHeight);
21888
22046
  const catCount = Math.max(categoryLabels.length, 1);
21889
22047
  const seriesCount = chartData.series.length;
21890
22048
  const cellW = layout.plotWidth / Math.max(catCount - 1, 1);
@@ -23064,6 +23222,9 @@ function computePlotLayout(elementWidth, elementHeight, chartData, hasAxes, opti
23064
23222
  const rowCount = options.dataTableRowCount ?? 1;
23065
23223
  plotBottom -= 14 + rowCount * 14;
23066
23224
  }
23225
+ // The automatic plot height, before any manual layout override below can
23226
+ // change it: see `PlotLayout.autoPlotHeight`'s doc comment.
23227
+ const autoPlotHeight = Math.max(plotBottom - plotTop, 1);
23067
23228
  // c:plotArea/c:layout/c:manualLayout: the author placed the plot area by
23068
23229
  // hand. Each field the layout omits keeps the automatic value above, which
23069
23230
  // is also what a `factor`-mode offset is relative to. An `outer` target
@@ -23090,6 +23251,7 @@ function computePlotLayout(elementWidth, elementHeight, chartData, hasAxes, opti
23090
23251
  plotBottom: plotTop + plotHeight,
23091
23252
  plotWidth,
23092
23253
  plotHeight,
23254
+ autoPlotHeight,
23093
23255
  };
23094
23256
  }
23095
23257
 
@@ -24093,14 +24255,20 @@ function buildWaterfallSteps(values, options) {
24093
24255
  }
24094
24256
  return steps;
24095
24257
  }
24096
- /** Compute a value range containing every cumulative and absolute bar endpoint. */
24097
- function computeWaterfallRange(steps) {
24258
+ /**
24259
+ * Compute a value range containing every cumulative and absolute bar endpoint.
24260
+ *
24261
+ * @param plotHeightPx The chart's plot-area height, when known; see
24262
+ * `axisTargetIntervals`'s doc comment for why this changes the automatic
24263
+ * scale's gridline count.
24264
+ */
24265
+ function computeWaterfallRange(steps, plotHeightPx) {
24098
24266
  return computeValueRange([
24099
24267
  {
24100
24268
  name: 'Waterfall range',
24101
24269
  values: steps.flatMap((step) => [step.startValue, step.endValue]),
24102
24270
  },
24103
- ]);
24271
+ ], plotHeightPx);
24104
24272
  }
24105
24273
 
24106
24274
  /**
@@ -24143,7 +24311,7 @@ function buildWaterfallViewModel(element, chartData, categoryLabels) {
24143
24311
  const series = chartData.series[0];
24144
24312
  const values = series?.values ?? [];
24145
24313
  const steps = buildWaterfallSteps(values, series?.waterfallOptions);
24146
- const range = computeWaterfallRange(steps);
24314
+ const range = computeWaterfallRange(steps, layout.autoPlotHeight);
24147
24315
  const catCount = Math.max(categoryLabels.length, values.length, 1);
24148
24316
  const barWidth = (layout.plotWidth / catCount) * 0.6;
24149
24317
  const gap = (layout.plotWidth / catCount) * 0.2;
@@ -24342,7 +24510,7 @@ function withDataPointPictureFills(vm, chartData, elementId) {
24342
24510
  * `chart-legend-entries.ts`.
24343
24511
  */
24344
24512
  function withLegendEntries(vm, chartData) {
24345
- const legend = applyLegendEntryOverrides(vm.legend, chartData.style?.legendEntries);
24513
+ const legend = applyLegendEntryOverrides(vm.legend, chartData.style?.legendEntries, chartData.style?.legendTextStyle);
24346
24514
  return legend === vm.legend ? vm : { ...vm, legend };
24347
24515
  }
24348
24516
  /**
@@ -25759,27 +25927,36 @@ function setChartCellValue(data, seriesIndex, categoryIndex, raw) {
25759
25927
  * Hide a currently-visible series (PowerPoint's Chart Filters "uncheck a
25760
25928
  * series"): moves it out of {@link PptxChartData.series} into
25761
25929
  * {@link PptxChartData.filteredSeries}, keeping its data and identity. The
25762
- * chart must keep at least one visible series. `idx`/`order` on the new
25763
- * filtered entry take the series' position among ALL series (visible and
25764
- * already-filtered combined), matching how PowerPoint numbers them.
25930
+ * chart must keep at least one visible series.
25931
+ *
25932
+ * The new filtered entry's `idx`/`order` reuse the series' OWN `c:idx` when
25933
+ * it has one (every real OOXML `c:ser` does): this value is what
25934
+ * {@link restoreFilteredSeries} and the Chart Filters popover
25935
+ * (`chart-quick-actions.ts`'s `buildFilters`) key a series' position on, so a
25936
+ * chart with non-sequential idx values (a filtered series in the original
25937
+ * file, or one authored idx 1/2 rather than 0/1, both real-world cases)
25938
+ * keeps its true identity instead of being renumbered to "the smallest idx
25939
+ * not yet taken," which used to reorder the Chart Filters list and lose a
25940
+ * restored series' original position. Only a source series with no idx at
25941
+ * all (a synthetic/malformed chart) falls back to that smallest-free-slot
25942
+ * scheme, to guarantee every idx in the combined visible+filtered set stays
25943
+ * distinct.
25765
25944
  */
25766
25945
  function hideChartSeries(data, seriesIndex) {
25767
25946
  if (data.series.length <= 1 || seriesIndex < 0 || seriesIndex >= data.series.length) {
25768
25947
  return null;
25769
25948
  }
25770
25949
  const series = data.series[seriesIndex];
25771
- // The smallest idx not already used by another VISIBLE series or an
25772
- // already-filtered one. With nothing else filtered this is just
25773
- // `seriesIndex` itself (PowerPoint numbers idx/order 0..N-1 across visible
25774
- // and filtered series together); a prior filtered series can force a
25775
- // higher one, keeping every idx distinct.
25776
- const takenIndices = new Set([
25777
- ...data.series.map((_, i) => i).filter((i) => i !== seriesIndex),
25778
- ...(data.filteredSeries ?? []).map((f) => f.idx),
25779
- ]);
25780
- let idx = 0;
25781
- while (takenIndices.has(idx)) {
25782
- idx++;
25950
+ let idx = series.idx;
25951
+ if (idx === undefined) {
25952
+ const taken = new Set([
25953
+ ...data.series.map((_, i) => i).filter((i) => i !== seriesIndex),
25954
+ ...(data.filteredSeries ?? []).map((f) => f.idx),
25955
+ ]);
25956
+ idx = 0;
25957
+ while (taken.has(idx)) {
25958
+ idx++;
25959
+ }
25783
25960
  }
25784
25961
  const filteredEntry = {
25785
25962
  idx,
@@ -25788,6 +25965,11 @@ function hideChartSeries(data, seriesIndex) {
25788
25965
  categories: data.categories,
25789
25966
  values: series.values,
25790
25967
  ...(series.uniqueId ? { uniqueId: series.uniqueId } : {}),
25968
+ // Full snapshot so restoreFilteredSeries can bring back everything
25969
+ // (fill/line formatting, marker, data labels, ...), not just name and
25970
+ // values: this used to silently reset a series with a picture fill
25971
+ // or any other non-default formatting to plain defaults on restore.
25972
+ originalSeries: series,
25791
25973
  };
25792
25974
  return {
25793
25975
  ...data,
@@ -25798,11 +25980,15 @@ function hideChartSeries(data, seriesIndex) {
25798
25980
  /**
25799
25981
  * Restore a series PowerPoint's Chart Filters hid (the reverse of
25800
25982
  * {@link hideChartSeries}): moves it from {@link PptxChartData.filteredSeries}
25801
- * back into {@link PptxChartData.series}. When the filtered entry itself
25802
- * carries no cached name (PowerPoint auto-generated one, e.g. "Series 3"),
25803
- * falls back to {@link PptxChartData.filteredSeriesTitle}; when it carries no
25804
- * cached categories, falls back to {@link PptxChartData.filteredCategoryTitle}
25805
- * or the chart's current categories.
25983
+ * back into {@link PptxChartData.series}, reinserted at the position its
25984
+ * `idx` puts it among the currently-visible series (not always appended
25985
+ * last, which used to leave a restored series permanently reordered to the
25986
+ * end of the chart, its legend, and its plot/stacking order). When the
25987
+ * filtered entry itself carries no cached name (PowerPoint auto-generated
25988
+ * one, e.g. "Series 3"), falls back to {@link PptxChartData.filteredSeriesTitle};
25989
+ * when it carries no cached categories, falls back to
25990
+ * {@link PptxChartData.filteredCategoryTitle} or the chart's current
25991
+ * categories.
25806
25992
  */
25807
25993
  function restoreFilteredSeries(data, filteredIndex) {
25808
25994
  const filtered = data.filteredSeries?.[filteredIndex];
@@ -25814,15 +26000,33 @@ function restoreFilteredSeries(data, filteredIndex) {
25814
26000
  const values = filtered.values ??
25815
26001
  (filtered.categories ?? data.filteredCategoryTitle)?.map(() => 0) ??
25816
26002
  categories.map(() => 0);
25817
- const restored = {
25818
- name,
25819
- values,
25820
- ...(filtered.uniqueId ? { uniqueId: filtered.uniqueId } : {}),
25821
- };
26003
+ // A series hidden by hideChartSeries this session carries a full
26004
+ // originalSeries snapshot: use it as-is (fill/line formatting, marker,
26005
+ // data labels, everything) rather than the bare name/values reconstruction
26006
+ // below, which used to reset a series with a picture fill or any other
26007
+ // non-default formatting to plain defaults on restore. A filtered series
26008
+ // that came from parsing the file (already hidden when opened) has no
26009
+ // snapshot to draw on, since the parser only reads name/cat/val/uniqueId
26010
+ // off the real c15:ser node; that case keeps the bare reconstruction.
26011
+ const restored = filtered.originalSeries
26012
+ ? { ...filtered.originalSeries, idx: filtered.idx }
26013
+ : {
26014
+ name,
26015
+ values,
26016
+ idx: filtered.idx,
26017
+ ...(filtered.uniqueId ? { uniqueId: filtered.uniqueId } : {}),
26018
+ };
26019
+ // The first currently-visible series whose own idx sorts after the
26020
+ // restored one; splicing in there reproduces its original relative
26021
+ // position. A series with no idx info at all falls back to its array
26022
+ // position, matching hideChartSeries's own fallback.
26023
+ const insertAt = data.series.findIndex((s, i) => (s.idx ?? i) > filtered.idx);
26024
+ const nextSeries = [...data.series];
26025
+ nextSeries.splice(insertAt === -1 ? nextSeries.length : insertAt, 0, restored);
25822
26026
  const remainingFiltered = (data.filteredSeries ?? []).filter((_, i) => i !== filteredIndex);
25823
26027
  return {
25824
26028
  ...data,
25825
- series: [...data.series, restored],
26029
+ series: nextSeries,
25826
26030
  ...(remainingFiltered.length > 0
25827
26031
  ? { filteredSeries: remainingFiltered }
25828
26032
  : { filteredSeries: undefined }),
@@ -25853,6 +26057,248 @@ function setDataLabelsRangeCache(series, pointIndex, text) {
25853
26057
  };
25854
26058
  }
25855
26059
 
26060
+ /** The curated preset list: (id, label key, source `c:style/@val`). */
26061
+ const CHART_STYLE_PRESETS = [
26062
+ { id: 'colorful', labelKey: 'pptx.chart.styleColorful', styleId: 2 },
26063
+ { id: 'monochrome', labelKey: 'pptx.chart.styleMonochrome', styleId: 10 },
26064
+ { id: 'colorfulLight', labelKey: 'pptx.chart.styleColorfulLight', styleId: 18 },
26065
+ { id: 'colorfulDark', labelKey: 'pptx.chart.styleColorfulDark', styleId: 26 },
26066
+ { id: 'mutedDark', labelKey: 'pptx.chart.styleMutedDark', styleId: 34 },
26067
+ { id: 'pastel', labelKey: 'pptx.chart.stylePastel', styleId: 42 },
26068
+ ];
26069
+ function paletteEquals(a, b) {
26070
+ if (!b || a.length !== b.length) {
26071
+ return false;
26072
+ }
26073
+ return a.every((c, i) => c.toLowerCase() === b[i]?.toLowerCase());
26074
+ }
26075
+ /** Resolve the id -> styleId map entry, or `undefined` for an unknown id. */
26076
+ function findPreset(id) {
26077
+ return CHART_STYLE_PRESETS.find((p) => p.id === id);
26078
+ }
26079
+ /**
26080
+ * Build the "Chart Styles" gallery descriptor for the currently-selected
26081
+ * chart: every preset's resolved colours plus whether it is the one
26082
+ * currently applied (its resolved palette matches `chartData.colorPalette`).
26083
+ */
26084
+ function buildChartStylePresets(chartData) {
26085
+ return CHART_STYLE_PRESETS.map(({ id, labelKey, styleId }) => {
26086
+ const colors = getChartStylePalette(styleId);
26087
+ return {
26088
+ id,
26089
+ labelKey,
26090
+ colors,
26091
+ applied: paletteEquals(colors, chartData.colorPalette),
26092
+ };
26093
+ });
26094
+ }
26095
+ /** Drop a data point's own fill override, keeping every other field. */
26096
+ function clearDataPointFill(point) {
26097
+ const { spPr, marker, ...rest } = point;
26098
+ const nextSpPr = spPr && { ...spPr, fillColor: undefined };
26099
+ const nextMarker = marker?.spPr && {
26100
+ ...marker,
26101
+ spPr: { ...marker.spPr, fillColor: undefined },
26102
+ };
26103
+ return { ...rest, ...(spPr && { spPr: nextSpPr }), ...(nextMarker && { marker: nextMarker }) };
26104
+ }
26105
+ /** Drop a series' own colour overrides (and its points'), keeping shape/symbol/size. */
26106
+ function clearSeriesColor(series) {
26107
+ const { color: _color, marker, dataPoints, ...rest } = series;
26108
+ const nextMarker = marker?.spPr && { ...marker, spPr: { ...marker.spPr, fillColor: undefined } };
26109
+ return {
26110
+ ...rest,
26111
+ ...(marker && { marker: nextMarker ?? marker }),
26112
+ ...(dataPoints && { dataPoints: dataPoints.map(clearDataPointFill) }),
26113
+ };
26114
+ }
26115
+ /**
26116
+ * Apply a "Chart Styles" preset by id: resolves its palette via
26117
+ * `getChartStylePalette`, writes it onto `colorPalette` (also mirroring
26118
+ * `style.styleId`), and clears every series'/data-point's own explicit fill
26119
+ * so the new palette is not immediately shadowed by pre-existing colours
26120
+ * (see this module's header). Returns `null` for an unknown preset id so a
26121
+ * caller can no-op instead of silently clearing the chart's palette.
26122
+ */
26123
+ function applyChartStylePreset(chartData, presetId) {
26124
+ const preset = findPreset(presetId);
26125
+ if (!preset) {
26126
+ return null;
26127
+ }
26128
+ const colors = [...getChartStylePalette(preset.styleId)];
26129
+ return {
26130
+ ...chartData,
26131
+ colorPalette: colors,
26132
+ style: { ...chartData.style, styleId: preset.styleId },
26133
+ series: chartData.series.map(clearSeriesColor),
26134
+ };
26135
+ }
26136
+
26137
+ const AXIS_TYPES_WITH_TITLES = [
26138
+ 'catAx',
26139
+ 'valAx',
26140
+ 'dateAx',
26141
+ ];
26142
+ /** Default axis title text PowerPoint inserts when a title is turned on with none set. */
26143
+ const DEFAULT_AXIS_TITLE_TEXT = 'Axis Title';
26144
+ /**
26145
+ * Set/clear `deleted` on every category/value/date axis (PowerPoint's "Axes"
26146
+ * checklist item hides the whole axis, not just its gridlines/title).
26147
+ */
26148
+ function chartAxesVisibilityPatch(chartData, show) {
26149
+ const axes = (chartData.axes ?? []).map((axis) => AXIS_TYPES_WITH_TITLES.includes(axis.axisType) ? { ...axis, deleted: !show } : axis);
26150
+ return { axes };
26151
+ }
26152
+ /** Whether at least one axis is currently visible (not `deleted`). */
26153
+ function chartAxesVisibilityState(chartData) {
26154
+ const relevant = (chartData.axes ?? []).filter((axis) => AXIS_TYPES_WITH_TITLES.includes(axis.axisType));
26155
+ return relevant.length === 0 || relevant.some((axis) => !axis.deleted);
26156
+ }
26157
+ /**
26158
+ * Set/clear `titleText` on every category/value axis. Turning off blanks the
26159
+ * text (PowerPoint's own "None" removes the title box entirely, which this
26160
+ * codebase models as absent/empty `titleText`, see `chart-axis-render.ts`);
26161
+ * turning on with no existing text fills in the same placeholder PowerPoint
26162
+ * inserts ("Axis Title").
26163
+ */
26164
+ function chartAxisTitlesPatch(chartData, show) {
26165
+ const axes = (chartData.axes ?? []).map((axis) => {
26166
+ if (!AXIS_TYPES_WITH_TITLES.includes(axis.axisType)) {
26167
+ return axis;
26168
+ }
26169
+ if (!show) {
26170
+ return { ...axis, titleText: undefined };
26171
+ }
26172
+ return { ...axis, titleText: axis.titleText || DEFAULT_AXIS_TITLE_TEXT };
26173
+ });
26174
+ return { axes };
26175
+ }
26176
+ /** Whether at least one axis currently shows a non-empty title. */
26177
+ function chartAxisTitlesState(chartData) {
26178
+ return (chartData.axes ?? []).some((axis) => AXIS_TYPES_WITH_TITLES.includes(axis.axisType) && Boolean(axis.titleText));
26179
+ }
26180
+ /**
26181
+ * Apply one "Chart Elements" checklist toggle. The single entry point every
26182
+ * binding's quick-action popover calls on click; see this module's header.
26183
+ */
26184
+ function applyChartElementToggle(chartData, key, checked) {
26185
+ switch (key) {
26186
+ case 'title':
26187
+ return patchChartData$1(chartData, { style: { ...chartData.style, hasTitle: checked } });
26188
+ case 'legend':
26189
+ return patchChartData$1(chartData, { style: { ...chartData.style, hasLegend: checked } });
26190
+ case 'dataLabels':
26191
+ return patchChartData$1(chartData, { style: { ...chartData.style, hasDataLabels: checked } });
26192
+ case 'gridlines':
26193
+ return patchChartData$1(chartData, chartGridlinesPatch(chartData, checked));
26194
+ case 'axes':
26195
+ return patchChartData$1(chartData, chartAxesVisibilityPatch(chartData, checked));
26196
+ case 'axisTitles':
26197
+ return patchChartData$1(chartData, chartAxisTitlesPatch(chartData, checked));
26198
+ default:
26199
+ return chartData;
26200
+ }
26201
+ }
26202
+
26203
+ /** Button edge length, in the same units as the caller's `selectionBox`. */
26204
+ const CHART_QUICK_ACTION_BUTTON_SIZE = 24;
26205
+ /** Gap between stacked buttons. */
26206
+ const BUTTON_GAP = 6;
26207
+ /** Gap between the chart's selection box and the button column, matching PowerPoint's offset. */
26208
+ const OUTSIDE_GAP = 8;
26209
+ const BUTTON_ORDER = [
26210
+ { id: 'elements', labelKey: 'pptx.chart.quickElements' },
26211
+ { id: 'styles', labelKey: 'pptx.chart.quickStyles' },
26212
+ { id: 'filters', labelKey: 'pptx.chart.quickFilters' },
26213
+ ];
26214
+ function buildButtons(selectionBox, showFilters) {
26215
+ const x = selectionBox.x + selectionBox.width + OUTSIDE_GAP;
26216
+ return BUTTON_ORDER.filter((entry) => entry.id !== 'filters' || showFilters).map((entry, i) => ({
26217
+ ...entry,
26218
+ x,
26219
+ y: selectionBox.y + i * (CHART_QUICK_ACTION_BUTTON_SIZE + BUTTON_GAP),
26220
+ size: CHART_QUICK_ACTION_BUTTON_SIZE,
26221
+ }));
26222
+ }
26223
+ function buildElements(chartData) {
26224
+ const items = [
26225
+ { key: 'title', labelKey: 'pptx.chart.showTitle', checked: chartData.style?.hasTitle ?? false },
26226
+ {
26227
+ key: 'legend',
26228
+ labelKey: 'pptx.chart.showLegend',
26229
+ checked: chartData.style?.hasLegend ?? false,
26230
+ },
26231
+ {
26232
+ key: 'gridlines',
26233
+ labelKey: 'pptx.chart.showGridlines',
26234
+ checked: chartGridlinesState(chartData),
26235
+ },
26236
+ {
26237
+ key: 'dataLabels',
26238
+ labelKey: 'pptx.chart.showDataLabels',
26239
+ checked: chartData.style?.hasDataLabels ?? false,
26240
+ },
26241
+ ];
26242
+ if (chartData.axes && chartData.axes.length > 0) {
26243
+ items.push({
26244
+ key: 'axes',
26245
+ labelKey: 'pptx.chart.quickAxes',
26246
+ checked: chartAxesVisibilityState(chartData),
26247
+ });
26248
+ items.push({
26249
+ key: 'axisTitles',
26250
+ labelKey: 'pptx.chart.quickAxisTitles',
26251
+ checked: chartAxisTitlesState(chartData),
26252
+ });
26253
+ }
26254
+ return items;
26255
+ }
26256
+ function buildFilters(chartData) {
26257
+ const visibleSeries = chartData.series.map((series, index) => ({
26258
+ key: `visible-${index}`,
26259
+ name: series.name,
26260
+ visible: true,
26261
+ seriesIndex: index,
26262
+ sortKey: series.idx ?? index,
26263
+ }));
26264
+ const filtered = (chartData.filteredSeries ?? []).map((entry, index) => ({
26265
+ key: `filtered-${index}`,
26266
+ name: entry.name ?? chartData.filteredSeriesTitle ?? `Series ${index + 1}`,
26267
+ visible: false,
26268
+ filteredIndex: index,
26269
+ sortKey: entry.idx,
26270
+ }));
26271
+ // PowerPoint's Chart Filters list never reorders rows as they're (un)checked:
26272
+ // every series keeps its original position, keyed by its persistent c:idx
26273
+ // (falling back to array position for a chart with no idx info at all),
26274
+ // not by which of the two underlying arrays (series/filteredSeries)
26275
+ // currently holds it. Concatenating visible-then-filtered instead made a
26276
+ // hidden series jump to the bottom of the list (reported as "unticking
26277
+ // some of them changes the ordering").
26278
+ const series = [...visibleSeries, ...filtered]
26279
+ .sort((a, b) => a.sortKey - b.sortKey)
26280
+ .map(({ sortKey: _sortKey, ...rest }) => rest);
26281
+ return { visible: series.length > 1, series };
26282
+ }
26283
+ /**
26284
+ * Build the quick-action descriptor for the currently-selected element.
26285
+ * Returns `null` when the quick actions should not render (nothing selected,
26286
+ * the selection is not a chart, or the chart has no data yet).
26287
+ */
26288
+ function buildChartQuickActionsDescriptor(input) {
26289
+ if (!input.isChartSelected || !input.chartData) {
26290
+ return null;
26291
+ }
26292
+ const { chartData, selectionBox } = input;
26293
+ const filters = buildFilters(chartData);
26294
+ return {
26295
+ buttons: buildButtons(selectionBox, filters.visible),
26296
+ elements: buildElements(chartData),
26297
+ filters,
26298
+ styles: { presets: buildChartStylePresets(chartData) },
26299
+ };
26300
+ }
26301
+
25856
26302
  const TWO_PI = Math.PI * 2;
25857
26303
  /** Keep the dragged span strictly inside (0, 2*PI) so the share never hits 0 or 1. */
25858
26304
  const ANGLE_EPSILON = TWO_PI * 0.001;
@@ -25956,9 +26402,12 @@ function buildStackedDragGeometry(element, chartData, seriesIndex, pointIndex) {
25956
26402
  if (!draggedValues || pointIndex < 0 || pointIndex >= draggedValues.length) {
25957
26403
  return null;
25958
26404
  }
25959
- 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
26405
+ 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), layoutOpts = computeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length), layout = computePlotLayout(element.width, element.height, chartData, true, layoutOpts),
26406
+ // Computed from the SAME `layout.autoPlotHeight` `chart-cartesian.ts`'s
26407
+ // `stackedRange` uses, so a drag never disagrees with what is on screen.
26408
+ range = percent
25960
26409
  ? { min: 0, max: 100, span: 100 }
25961
- : computeStackedValueRange(chartData.series, catCount), layoutOpts = computeLayoutOptions(chartData.axes, chartData.dataTable, chartData.series.length), layout = computePlotLayout(element.width, element.height, chartData, true, layoutOpts);
26410
+ : computeStackedValueRange(chartData.series, catCount, layout.autoPlotHeight);
25962
26411
  return {
25963
26412
  range,
25964
26413
  plotTop: layout.plotTop,
@@ -48733,6 +49182,7 @@ const translationsEn = {
48733
49182
  'pptx.sections.addAfter': 'Add Section After',
48734
49183
  // Notes
48735
49184
  'pptx.notes.title': 'Notes',
49185
+ 'pptx.notes.hasNotes': '(has notes)',
48736
49186
  'pptx.notes.slideN': 'Slide {{n}}',
48737
49187
  'pptx.notes.noSlide': 'No slide selected',
48738
49188
  'pptx.notes.clickToAddNotes': 'Click to add notes',
@@ -48933,6 +49383,17 @@ const translationsEn = {
48933
49383
  'pptx.chart.chartFilters': 'Chart filters',
48934
49384
  'pptx.chart.hideSeries': 'Hide {{name}}',
48935
49385
  'pptx.chart.showSeries': 'Show {{name}}',
49386
+ 'pptx.chart.quickElements': 'Chart Elements',
49387
+ 'pptx.chart.quickStyles': 'Chart Styles',
49388
+ 'pptx.chart.quickFilters': 'Chart Filters',
49389
+ 'pptx.chart.quickAxes': 'Axes',
49390
+ 'pptx.chart.quickAxisTitles': 'Axis Titles',
49391
+ 'pptx.chart.styleColorful': 'Colorful',
49392
+ 'pptx.chart.styleMonochrome': 'Monochrome',
49393
+ 'pptx.chart.styleColorfulLight': 'Colorful Light',
49394
+ 'pptx.chart.styleColorfulDark': 'Colorful Dark',
49395
+ 'pptx.chart.styleMutedDark': 'Muted Dark',
49396
+ 'pptx.chart.stylePastel': 'Pastel',
48936
49397
  'pptx.chart.valueFromCells': 'Value from cells: {{name}}',
48937
49398
  'pptx.chart.removeCategory': 'Remove category',
48938
49399
  'pptx.chart.axes': 'Axes',
@@ -49077,6 +49538,8 @@ const translationsEn = {
49077
49538
  'pptx.slideShow.subtitles': 'Subtitles',
49078
49539
  // Record tab (camera overlay placeholders)
49079
49540
  'pptx.record.cameo': 'Cameo',
49541
+ 'pptx.record.manage': 'Manage',
49542
+ 'pptx.record.camera': 'Camera',
49080
49543
  'pptx.record.clear': 'Clear',
49081
49544
  'pptx.record.learnMore': 'Learn More',
49082
49545
  'pptx.record.resetToCameo': 'Reset to Cameo',
@@ -51186,6 +51649,7 @@ const translationsEn = {
51186
51649
  'pptx.textFormatting.paragraphBefore': 'Paragraph Before',
51187
51650
  'pptx.textFormatting.textFlow': 'Text Flow',
51188
51651
  'pptx.textProperties.advancedTextHeading': 'Advanced Text',
51652
+ 'pptx.textProperties.autoFitToShape': 'Auto-fit text to shape',
51189
51653
  'pptx.textProperties.defaultFontOption': 'Default ({{font}})',
51190
51654
  'pptx.textProperties.firstIndent': 'First Indent',
51191
51655
  'pptx.textProperties.leftMargin': 'Left Margin',
@@ -77278,7 +77742,9 @@ function buildSurfaceChart3DData(chartData, categoryLabels, options) {
77278
77742
  if (seriesCount === 0 || catCount === 0) {
77279
77743
  return null;
77280
77744
  }
77281
- const range = computeValueRange(chartData.series);
77745
+ // See the matching comment in `bar-chart-3d-data.ts`: the element height
77746
+ // stands in for a plot-area height this 3D scene doesn't separately compute.
77747
+ const range = computeValueRange(chartData.series, options.height);
77282
77748
  const heightMap = new Float32Array(seriesCount * catCount);
77283
77749
  const colorMap = new Float32Array(seriesCount * catCount * 3);
77284
77750
  // Raw (un-normalised) values, kept alongside the [0,1] heightMap so the
@@ -78419,11 +78885,16 @@ function buildBarChart3DData(chartData, categoryLabels, options) {
78419
78885
  const isPercent = grouping === 'percentStacked';
78420
78886
  const horizontal = chartData.barDirection === 'bar';
78421
78887
  const points = buildPoints$1(chartData, cols, isPercent);
78888
+ // No separate plot-area inset exists for the 3D scene the way the flat SVG
78889
+ // engine's `computePlotLayout` reserves one, so the full element height
78890
+ // stands in for it; see `axisTargetIntervals`'s doc comment for why this
78891
+ // only makes the automatic scale saturate at its gridline cap slightly
78892
+ // sooner; it does not change the "ordinary chart" result this was fixed for.
78422
78893
  const range = isPercent
78423
78894
  ? { min: 0, max: 100, span: 100 }
78424
78895
  : grouping === 'stacked'
78425
- ? computeStackedValueRange(chartData.series, cols)
78426
- : computeValueRange(chartData.series);
78896
+ ? computeStackedValueRange(chartData.series, cols, options.height)
78897
+ : computeValueRange(chartData.series, options.height);
78427
78898
  const depthPercent = chartData.view3D?.depthPercent;
78428
78899
  const boxes = layoutBarChart3D(points, cols, rows, range, grouping, depthPercent, horizontal);
78429
78900
  return {
@@ -78610,7 +79081,9 @@ function buildCartesianLine3DSceneData(chartData, categoryLabels, options) {
78610
79081
  return null;
78611
79082
  }
78612
79083
  const points = buildPoints(chartData, cols);
78613
- const range = computeValueRange(chartData.series);
79084
+ // See the matching comment in `bar-chart-3d-data.ts`: the element height
79085
+ // stands in for a plot-area height this 3D scene doesn't separately compute.
79086
+ const range = computeValueRange(chartData.series, options.height);
78614
79087
  const depthPercent = chartData.view3D?.depthPercent;
78615
79088
  const series = layoutCartesianLine3DSeries(points, cols, rows, range, depthPercent);
78616
79089
  return {
@@ -107165,7 +107638,7 @@ function createLocalStorageBackend(namespace) {
107165
107638
  /** Try IndexedDB first; fall back to localStorage on any failure. */
107166
107639
  async function resolveBackend(dbName, namespace) {
107167
107640
  try {
107168
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-HvkahiGW.mjs');
107641
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-DGdVQ5kC.mjs');
107169
107642
  const db = await openChatDb(dbName);
107170
107643
  return createIdbBackend(db);
107171
107644
  }
@@ -117837,6 +118310,457 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
117837
118310
  type: Injectable
117838
118311
  }] });
117839
118312
 
118313
+ // ─────────────────────────────────────────────────────────────────────────────
118314
+ // Direct part-editing gate
118315
+ // ─────────────────────────────────────────────────────────────────────────────
118316
+ /**
118317
+ * May this chart's individual parts (title, series, data points) be entered
118318
+ * for direct on-canvas editing?
118319
+ *
118320
+ * Pure so it is unit-testable without a full Angular injection context:
118321
+ * `ChartElementViewComponent`'s constructor runs an `effect()` that needs a
118322
+ * `ChangeDetectionScheduler` this package's TestBed-free suite doesn't
118323
+ * provide. G8: `a:graphicFrameLocks/@noDrilldown` forbids the drill-down,
118324
+ * even when the chart is otherwise selected + editable.
118325
+ */
118326
+ function chartCanEditParts(editable, isSelected, hasEditor, element) {
118327
+ return editable && isSelected && hasEditor && canDrillDown(element);
118328
+ }
118329
+ // ─────────────────────────────────────────────────────────────────────────────
118330
+ // Value-drag commit gate
118331
+ // ─────────────────────────────────────────────────────────────────────────────
118332
+ /**
118333
+ * The chart data a finished drag should commit, or null when nothing should
118334
+ * be committed (cancelled, or the press never became a drag).
118335
+ */
118336
+ function chartDragCommitData(session, commit) {
118337
+ if (!commit || !session?.moved) {
118338
+ return null;
118339
+ }
118340
+ return session.lastData;
118341
+ }
118342
+ /**
118343
+ * Same gate as {@link chartDragCommitData}, for a pie/radar/stacked mark drag
118344
+ * ({@link ChartMarkDragState} carries the same `moved`/`lastData` shape as the
118345
+ * cartesian value-drag session, just resolved through a different geometry).
118346
+ */
118347
+ function chartMarkDragCommitData(session, commit) {
118348
+ if (!commit || !session?.moved) {
118349
+ return null;
118350
+ }
118351
+ return session.lastData;
118352
+ }
118353
+ // ─────────────────────────────────────────────────────────────────────────────
118354
+ // 3D value-drag commit data (bar3D/line3D/area3D/pie3D/surface3D: no drag
118355
+ // state machine of their own, the shared three.js scene reports the
118356
+ // live/final value directly)
118357
+ // ─────────────────────────────────────────────────────────────────────────────
118358
+ /**
118359
+ * The chart data a 3D scene's `onValueDragPreview`/`onValueDragCommit` should
118360
+ * apply, or `null` when the part carries no point index (a series-level part,
118361
+ * or a part shape the 3D scenes never actually emit for a value drag) or there
118362
+ * is no chart data to update against.
118363
+ *
118364
+ * Pure so it is unit-testable without a WebGL context: `BarChart3DRendererComponent`
118365
+ * / `LineChart3DRendererComponent` / `AreaChart3DRendererComponent` /
118366
+ * `PieChart3DRendererComponent` / `SurfaceChart3DRendererComponent` forward
118367
+ * their `valueDragPreview`/`valueDragCommit` outputs here via
118368
+ * `ChartElementViewComponent`.
118369
+ */
118370
+ function chart3DPointValueUpdate(chartData, part, value) {
118371
+ if (!chartData || part.pointIndex === undefined) {
118372
+ return null;
118373
+ }
118374
+ return withChartPointValue(chartData, part.seriesIndex, part.pointIndex, value);
118375
+ }
118376
+ /**
118377
+ * Commit an on-canvas chart edit through the editor's normal element-update
118378
+ * path (the exact channel the inspector uses: one history snapshot per call).
118379
+ * No-op without an editor or when the element is not on any slide.
118380
+ *
118381
+ * `templateSlideId` is the id of the slide the hosting canvas renders (from
118382
+ * `SLIDE_CONTEXT`); it resolves template (master/layout) chart elements, which
118383
+ * live in the per-slide template store rather than in `slides[].elements`.
118384
+ */
118385
+ function commitChartElementData(editor, elementId, chartData, templateSlideId) {
118386
+ if (!editor) {
118387
+ return;
118388
+ }
118389
+ const slideIndex = findOwningSlideIndex(editor.slides(), elementId, templateSlideId);
118390
+ if (slideIndex < 0) {
118391
+ return;
118392
+ }
118393
+ editor.updateElement(slideIndex, elementId, { chartData });
118394
+ }
118395
+ // ─────────────────────────────────────────────────────────────────────────────
118396
+ // Interaction stylesheet (shared base rules + Angular's own badge/editor CSS)
118397
+ // ─────────────────────────────────────────────────────────────────────────────
118398
+ const STYLE_ELEMENT_ID = 'pptx-ng-chart-interaction-styles';
118399
+ /**
118400
+ * Angular-only interaction CSS, injected once into `document.head` alongside
118401
+ * the shared `[data-chart-part]` / selected-mark rules from
118402
+ * `ensureChartInteractionStyles` (`pptx-viewer-shared`). Component styles are
118403
+ * view-encapsulated in Angular, so they cannot reach into the chart
118404
+ * renderer's SVG or style the badge/title-input this component projects
118405
+ * next to it.
118406
+ */
118407
+ const INTERACTION_CSS = `
118408
+ .pptx-ng-chart-view { position: relative; width: 100%; height: 100%; }
118409
+ .pptx-ng-chart-drag-badge { position: absolute; top: 4px; right: 4px; z-index: 10; border-radius: 4px; background: rgba(37, 99, 235, 0.9); padding: 2px 6px; font-size: 10px; font-weight: 500; color: #fff; pointer-events: none; }
118410
+ .pptx-ng-chart-title-input { position: absolute; left: 50%; top: 2px; z-index: 10; width: 60%; transform: translateX(-50%); border: 1px solid #94a3b8; border-radius: 4px; background: #fff; padding: 2px 4px; text-align: center; font-size: 11px; color: #0f172a; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
118411
+ `;
118412
+ /**
118413
+ * Inject the interaction stylesheets for chart part hit targets: the shared
118414
+ * base rules (singleton, shared across all five bindings) plus Angular's own
118415
+ * badge/title-input CSS (singleton, this binding only).
118416
+ */
118417
+ function ensureChartInteractionStyles() {
118418
+ ensureChartInteractionStyles$1();
118419
+ if (typeof document === 'undefined' || document.getElementById(STYLE_ELEMENT_ID)) {
118420
+ return;
118421
+ }
118422
+ const style = document.createElement('style');
118423
+ style.id = STYLE_ELEMENT_ID;
118424
+ style.textContent = INTERACTION_CSS;
118425
+ document.head.appendChild(style);
118426
+ }
118427
+
118428
+ /**
118429
+ * chart-quick-actions-overlay.component.ts: PowerPoint's three floating
118430
+ * quick-action icons ("Chart Elements" +, "Chart Styles" paintbrush, "Chart
118431
+ * Filters" funnel) shown just outside a selected chart's top-right corner.
118432
+ *
118433
+ * Selector: `pptx-chart-quick-actions-overlay`
118434
+ *
118435
+ * Mounted inside `SlideCanvasComponent`'s template as a sibling of the
118436
+ * resize/rotate/adjust handle blocks, inside the same scaled
118437
+ * `.pptx-ng-canvas-stage`. Angular has no CSS inverse-scale variable (unlike
118438
+ * React's `--pptx-handle-inverse-scale`): this component follows the SAME
118439
+ * convention `selection-geometry.ts`'s `computeHandleBoxes`/
118440
+ * `computeCornerHandle` already use, computing every screen-constant
118441
+ * quantity (button size, gaps) as `screenPx / zoom` while leaving the
118442
+ * element's own x/y/width/height in raw slide px.
118443
+ *
118444
+ * All decision-making (which buttons render, checklist/gallery/filter state)
118445
+ * comes from the shared `buildChartQuickActionsDescriptor`; this component
118446
+ * only renders three buttons plus whichever popover is open, and commits
118447
+ * through `commitChartElementData` (the same on-canvas commit helper
118448
+ * `ChartElementViewComponent` uses for mark-drag/inline-title edits), so
118449
+ * undo/redo and the save round-trip are shared with every other on-canvas
118450
+ * chart edit. See the shared module's header for scope notes (Series-only
118451
+ * Chart Filters, no trendline/error-bar/up-down-bars rows).
118452
+ *
118453
+ * @module angular-viewer/chart-quick-actions-overlay
118454
+ */
118455
+ class ChartQuickActionsOverlayComponent {
118456
+ constructor() {
118457
+ this.element = input.required(/* @ts-ignore */
118458
+ ...(ngDevMode ? [{ debugName: "element" }] : /* istanbul ignore next */ []));
118459
+ this.canEdit = input(true, /* @ts-ignore */
118460
+ ...(ngDevMode ? [{ debugName: "canEdit" }] : /* istanbul ignore next */ []));
118461
+ /** Effective stage zoom, so screen-constant sizes/gaps divide it out. */
118462
+ this.zoom = input(1, /* @ts-ignore */
118463
+ ...(ngDevMode ? [{ debugName: "zoom" }] : /* istanbul ignore next */ []));
118464
+ this.CHART_QUICK_ACTION_BUTTON_SIZE = CHART_QUICK_ACTION_BUTTON_SIZE;
118465
+ this.editor = inject(EditorStateService, { optional: true });
118466
+ this.slideContext = inject(SLIDE_CONTEXT, { optional: true });
118467
+ this.hostRef = inject((ElementRef));
118468
+ this.open = signal(null, /* @ts-ignore */
118469
+ ...(ngDevMode ? [{ debugName: "open" }] : /* istanbul ignore next */ []));
118470
+ /** The stage scale, guarded against 0. */
118471
+ this.scale = computed(() => this.zoom() || 1, /* @ts-ignore */
118472
+ ...(ngDevMode ? [{ debugName: "scale" }] : /* istanbul ignore next */ []));
118473
+ /**
118474
+ * The descriptor's geometry, computed against a SCREEN-space box (the
118475
+ * element's box multiplied by the stage scale): every constant the shared
118476
+ * function adds (gaps, button size) is then correctly screen-constant, and
118477
+ * {@link screenPx} divides each resulting quantity back down to the slide
118478
+ * px this component renders in, mirroring `selection-geometry.ts`'s
118479
+ * `computeHandleBoxes`.
118480
+ */
118481
+ this.descriptor = computed(() => {
118482
+ const el = this.element();
118483
+ const scale = this.scale();
118484
+ return buildChartQuickActionsDescriptor({
118485
+ isChartSelected: true,
118486
+ chartData: el.chartData,
118487
+ selectionBox: {
118488
+ x: el.x * scale,
118489
+ y: el.y * scale,
118490
+ width: el.width * scale,
118491
+ height: el.height * scale,
118492
+ },
118493
+ });
118494
+ }, /* @ts-ignore */
118495
+ ...(ngDevMode ? [{ debugName: "descriptor" }] : /* istanbul ignore next */ []));
118496
+ }
118497
+ /** Close whichever popover is open on an outside click, mirroring every other binding's overlay. */
118498
+ onDocumentMouseDown(event) {
118499
+ if (this.open() && !this.hostRef.nativeElement.contains(event.target)) {
118500
+ this.open.set(null);
118501
+ }
118502
+ }
118503
+ /** Convert a screen-space quantity (from {@link descriptor}) back to slide px. */
118504
+ screenPx(value) {
118505
+ return value / this.scale();
118506
+ }
118507
+ toggle(id) {
118508
+ this.open.update((current) => (current === id ? null : id));
118509
+ }
118510
+ commit(chartData) {
118511
+ commitChartElementData(this.editor, this.element().id, chartData, this.slideContext?.slideId() ?? null);
118512
+ }
118513
+ onElementToggle(key, event) {
118514
+ const chartData = this.element().chartData;
118515
+ if (!chartData) {
118516
+ return;
118517
+ }
118518
+ const checked = event.target.checked;
118519
+ this.commit(applyChartElementToggle(chartData, key, checked));
118520
+ }
118521
+ onStylePreset(presetId) {
118522
+ const chartData = this.element().chartData;
118523
+ if (!chartData) {
118524
+ return;
118525
+ }
118526
+ const next = applyChartStylePreset(chartData, presetId);
118527
+ if (next) {
118528
+ this.commit(next);
118529
+ }
118530
+ }
118531
+ onFilterToggle(seriesIndex, filteredIndex) {
118532
+ const chartData = this.element().chartData;
118533
+ if (!chartData) {
118534
+ return;
118535
+ }
118536
+ const next = seriesIndex !== undefined
118537
+ ? hideChartSeries(chartData, seriesIndex)
118538
+ : restoreFilteredSeries(chartData, filteredIndex);
118539
+ if (next) {
118540
+ this.commit(next);
118541
+ }
118542
+ }
118543
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartQuickActionsOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
118544
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: ChartQuickActionsOverlayComponent, isStandalone: true, selector: "pptx-chart-quick-actions-overlay", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "data-pptx-chart-quick-actions": "true", "data-export-ignore": "true" }, listeners: { "pointerdown": "$event.stopPropagation()", "document:mousedown": "onDocumentMouseDown($event)" } }, ngImport: i0, template: `
118545
+ @if (descriptor(); as d) {
118546
+ @for (button of d.buttons; track button.id) {
118547
+ <button
118548
+ type="button"
118549
+ class="pptx-ng-chart-quick-btn"
118550
+ [disabled]="!canEdit()"
118551
+ [attr.data-testid]="'chart-quick-action-' + button.id"
118552
+ [attr.aria-label]="button.labelKey | translate"
118553
+ [title]="button.labelKey | translate"
118554
+ [style.left.px]="screenPx(button.x)"
118555
+ [style.top.px]="screenPx(button.y)"
118556
+ [style.width.px]="screenPx(button.size)"
118557
+ [style.height.px]="screenPx(button.size)"
118558
+ (click)="toggle(button.id)"
118559
+ >
118560
+ @if (button.id === 'elements') {
118561
+ <svg lucidePlus class="pptx-ng-chart-quick-icon"></svg>
118562
+ } @else if (button.id === 'styles') {
118563
+ <svg lucidePaintbrush class="pptx-ng-chart-quick-icon"></svg>
118564
+ } @else {
118565
+ <svg lucideFilter class="pptx-ng-chart-quick-icon"></svg>
118566
+ }
118567
+ </button>
118568
+
118569
+ @if (open() === button.id && button.id === 'elements') {
118570
+ <div
118571
+ class="pptx-ng-chart-quick-card"
118572
+ data-testid="chart-quick-elements-popover"
118573
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118574
+ [style.top.px]="screenPx(button.y)"
118575
+ >
118576
+ <h4 class="pptx-ng-chart-quick-heading">
118577
+ {{ 'pptx.chart.quickElements' | translate }}
118578
+ </h4>
118579
+ @for (item of d.elements; track item.key) {
118580
+ <label class="pptx-ng-chart-quick-check">
118581
+ <input
118582
+ type="checkbox"
118583
+ [disabled]="!canEdit()"
118584
+ [checked]="item.checked"
118585
+ [attr.data-testid]="'chart-quick-element-' + item.key"
118586
+ (change)="onElementToggle(item.key, $event)"
118587
+ />
118588
+ <span>{{ item.labelKey | translate }}</span>
118589
+ </label>
118590
+ }
118591
+ </div>
118592
+ }
118593
+
118594
+ @if (open() === button.id && button.id === 'styles') {
118595
+ <div
118596
+ class="pptx-ng-chart-quick-card pptx-ng-chart-quick-styles"
118597
+ data-testid="chart-quick-styles-popover"
118598
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118599
+ [style.top.px]="screenPx(button.y)"
118600
+ >
118601
+ @for (preset of d.styles.presets; track preset.id) {
118602
+ <button
118603
+ type="button"
118604
+ class="pptx-ng-chart-quick-swatch"
118605
+ [class.is-applied]="preset.applied"
118606
+ [disabled]="!canEdit()"
118607
+ [attr.data-testid]="'chart-quick-style-' + preset.id"
118608
+ [attr.aria-label]="preset.labelKey | translate"
118609
+ [attr.aria-pressed]="preset.applied"
118610
+ [title]="preset.labelKey | translate"
118611
+ (click)="onStylePreset(preset.id)"
118612
+ >
118613
+ <span class="pptx-ng-chart-quick-swatch-row">
118614
+ @for (c of preset.colors.slice(0, 5); track $index) {
118615
+ <span [style.background-color]="c"></span>
118616
+ }
118617
+ </span>
118618
+ </button>
118619
+ }
118620
+ </div>
118621
+ }
118622
+
118623
+ @if (open() === button.id && button.id === 'filters') {
118624
+ <div
118625
+ class="pptx-ng-chart-quick-card"
118626
+ data-testid="chart-quick-filters-popover"
118627
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118628
+ [style.top.px]="screenPx(button.y)"
118629
+ >
118630
+ <h4 class="pptx-ng-chart-quick-heading">{{ 'pptx.chart.quickFilters' | translate }}</h4>
118631
+ @for (row of d.filters.series; track row.key) {
118632
+ <label class="pptx-ng-chart-quick-check">
118633
+ <input
118634
+ type="checkbox"
118635
+ [disabled]="!canEdit()"
118636
+ [checked]="row.visible"
118637
+ [attr.data-testid]="'chart-quick-filter-' + row.key"
118638
+ (change)="onFilterToggle(row.seriesIndex, row.filteredIndex)"
118639
+ />
118640
+ <span class="pptx-ng-chart-quick-name">{{ row.name }}</span>
118641
+ </label>
118642
+ }
118643
+ </div>
118644
+ }
118645
+ }
118646
+ }
118647
+ `, isInline: true, styles: [":host{position:absolute;left:0;top:0;z-index:59}.pptx-ng-chart-quick-btn{position:absolute;display:flex;align-items:center;justify-content:center;border-radius:4px;border:1px solid #d1d5db;background:#fff;color:#374151;cursor:pointer}.pptx-ng-chart-quick-btn:hover{background:#f3f4f6}.pptx-ng-chart-quick-btn:disabled{opacity:.6;cursor:not-allowed}.pptx-ng-chart-quick-icon{width:14px;height:14px}.pptx-ng-chart-quick-card{position:absolute;z-index:10;display:flex;flex-direction:column;gap:.35rem;min-width:11rem;padding:.5rem;border-radius:6px;border:1px solid var(--pptx-inspector-border, #444);background:var(--pptx-inspector-input-bg, #2d2d2d);box-shadow:0 4px 16px #00000059}.pptx-ng-chart-quick-heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-ng-chart-quick-check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-ng-chart-quick-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-ng-chart-quick-styles{display:grid;grid-template-columns:repeat(3,1fr);gap:.35rem;min-width:12rem}.pptx-ng-chart-quick-swatch{border-radius:4px;overflow:hidden;border:1px solid var(--pptx-inspector-border, #444);padding:0;cursor:pointer}.pptx-ng-chart-quick-swatch.is-applied{border-color:var(--pptx-inspector-active, #0078d4);box-shadow:0 0 0 1px var(--pptx-inspector-active, #0078d4)}.pptx-ng-chart-quick-swatch-row{display:flex;height:20px;width:100%}.pptx-ng-chart-quick-swatch-row>span{flex:1 1 auto}\n"], dependencies: [{ kind: "component", type: LucidePlus, selector: "svg[lucidePlus]" }, { kind: "component", type: LucidePaintbrush, selector: "svg[lucidePaintbrush]" }, { kind: "component", type: LucideFilter, selector: "svg[lucideFunnel], svg[lucideFilter]" }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
118648
+ }
118649
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: ChartQuickActionsOverlayComponent, decorators: [{
118650
+ type: Component,
118651
+ args: [{ selector: 'pptx-chart-quick-actions-overlay', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe, LucidePlus, LucidePaintbrush, LucideFilter], host: {
118652
+ 'data-pptx-chart-quick-actions': 'true',
118653
+ 'data-export-ignore': 'true',
118654
+ '(pointerdown)': '$event.stopPropagation()',
118655
+ }, template: `
118656
+ @if (descriptor(); as d) {
118657
+ @for (button of d.buttons; track button.id) {
118658
+ <button
118659
+ type="button"
118660
+ class="pptx-ng-chart-quick-btn"
118661
+ [disabled]="!canEdit()"
118662
+ [attr.data-testid]="'chart-quick-action-' + button.id"
118663
+ [attr.aria-label]="button.labelKey | translate"
118664
+ [title]="button.labelKey | translate"
118665
+ [style.left.px]="screenPx(button.x)"
118666
+ [style.top.px]="screenPx(button.y)"
118667
+ [style.width.px]="screenPx(button.size)"
118668
+ [style.height.px]="screenPx(button.size)"
118669
+ (click)="toggle(button.id)"
118670
+ >
118671
+ @if (button.id === 'elements') {
118672
+ <svg lucidePlus class="pptx-ng-chart-quick-icon"></svg>
118673
+ } @else if (button.id === 'styles') {
118674
+ <svg lucidePaintbrush class="pptx-ng-chart-quick-icon"></svg>
118675
+ } @else {
118676
+ <svg lucideFilter class="pptx-ng-chart-quick-icon"></svg>
118677
+ }
118678
+ </button>
118679
+
118680
+ @if (open() === button.id && button.id === 'elements') {
118681
+ <div
118682
+ class="pptx-ng-chart-quick-card"
118683
+ data-testid="chart-quick-elements-popover"
118684
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118685
+ [style.top.px]="screenPx(button.y)"
118686
+ >
118687
+ <h4 class="pptx-ng-chart-quick-heading">
118688
+ {{ 'pptx.chart.quickElements' | translate }}
118689
+ </h4>
118690
+ @for (item of d.elements; track item.key) {
118691
+ <label class="pptx-ng-chart-quick-check">
118692
+ <input
118693
+ type="checkbox"
118694
+ [disabled]="!canEdit()"
118695
+ [checked]="item.checked"
118696
+ [attr.data-testid]="'chart-quick-element-' + item.key"
118697
+ (change)="onElementToggle(item.key, $event)"
118698
+ />
118699
+ <span>{{ item.labelKey | translate }}</span>
118700
+ </label>
118701
+ }
118702
+ </div>
118703
+ }
118704
+
118705
+ @if (open() === button.id && button.id === 'styles') {
118706
+ <div
118707
+ class="pptx-ng-chart-quick-card pptx-ng-chart-quick-styles"
118708
+ data-testid="chart-quick-styles-popover"
118709
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118710
+ [style.top.px]="screenPx(button.y)"
118711
+ >
118712
+ @for (preset of d.styles.presets; track preset.id) {
118713
+ <button
118714
+ type="button"
118715
+ class="pptx-ng-chart-quick-swatch"
118716
+ [class.is-applied]="preset.applied"
118717
+ [disabled]="!canEdit()"
118718
+ [attr.data-testid]="'chart-quick-style-' + preset.id"
118719
+ [attr.aria-label]="preset.labelKey | translate"
118720
+ [attr.aria-pressed]="preset.applied"
118721
+ [title]="preset.labelKey | translate"
118722
+ (click)="onStylePreset(preset.id)"
118723
+ >
118724
+ <span class="pptx-ng-chart-quick-swatch-row">
118725
+ @for (c of preset.colors.slice(0, 5); track $index) {
118726
+ <span [style.background-color]="c"></span>
118727
+ }
118728
+ </span>
118729
+ </button>
118730
+ }
118731
+ </div>
118732
+ }
118733
+
118734
+ @if (open() === button.id && button.id === 'filters') {
118735
+ <div
118736
+ class="pptx-ng-chart-quick-card"
118737
+ data-testid="chart-quick-filters-popover"
118738
+ [style.left.px]="screenPx(button.x + CHART_QUICK_ACTION_BUTTON_SIZE + 4)"
118739
+ [style.top.px]="screenPx(button.y)"
118740
+ >
118741
+ <h4 class="pptx-ng-chart-quick-heading">{{ 'pptx.chart.quickFilters' | translate }}</h4>
118742
+ @for (row of d.filters.series; track row.key) {
118743
+ <label class="pptx-ng-chart-quick-check">
118744
+ <input
118745
+ type="checkbox"
118746
+ [disabled]="!canEdit()"
118747
+ [checked]="row.visible"
118748
+ [attr.data-testid]="'chart-quick-filter-' + row.key"
118749
+ (change)="onFilterToggle(row.seriesIndex, row.filteredIndex)"
118750
+ />
118751
+ <span class="pptx-ng-chart-quick-name">{{ row.name }}</span>
118752
+ </label>
118753
+ }
118754
+ </div>
118755
+ }
118756
+ }
118757
+ }
118758
+ `, styles: [":host{position:absolute;left:0;top:0;z-index:59}.pptx-ng-chart-quick-btn{position:absolute;display:flex;align-items:center;justify-content:center;border-radius:4px;border:1px solid #d1d5db;background:#fff;color:#374151;cursor:pointer}.pptx-ng-chart-quick-btn:hover{background:#f3f4f6}.pptx-ng-chart-quick-btn:disabled{opacity:.6;cursor:not-allowed}.pptx-ng-chart-quick-icon{width:14px;height:14px}.pptx-ng-chart-quick-card{position:absolute;z-index:10;display:flex;flex-direction:column;gap:.35rem;min-width:11rem;padding:.5rem;border-radius:6px;border:1px solid var(--pptx-inspector-border, #444);background:var(--pptx-inspector-input-bg, #2d2d2d);box-shadow:0 4px 16px #00000059}.pptx-ng-chart-quick-heading{font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--pptx-inspector-muted, #888);margin:0}.pptx-ng-chart-quick-check{display:flex;align-items:center;gap:.35rem;font-size:11px;cursor:pointer}.pptx-ng-chart-quick-name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.pptx-ng-chart-quick-styles{display:grid;grid-template-columns:repeat(3,1fr);gap:.35rem;min-width:12rem}.pptx-ng-chart-quick-swatch{border-radius:4px;overflow:hidden;border:1px solid var(--pptx-inspector-border, #444);padding:0;cursor:pointer}.pptx-ng-chart-quick-swatch.is-applied{border-color:var(--pptx-inspector-active, #0078d4);box-shadow:0 0 0 1px var(--pptx-inspector-active, #0078d4)}.pptx-ng-chart-quick-swatch-row{display:flex;height:20px;width:100%}.pptx-ng-chart-quick-swatch-row>span{flex:1 1 auto}\n"] }]
118759
+ }], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], onDocumentMouseDown: [{
118760
+ type: HostListener,
118761
+ args: ['document:mousedown', ['$event']]
118762
+ }] } });
118763
+
117840
118764
  /**
117841
118765
  * Pure geometry for interactive element drag/resize.
117842
118766
  *
@@ -120210,121 +121134,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
120210
121134
  `, styles: [".pptx-ng-bar-chart-3d-scene{width:100%;height:100%;display:block}\n"] }]
120211
121135
  }], ctorParameters: () => [], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], selectedPart: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedPart", required: false }] }], textStyle: [{ type: i0.Input, args: [{ isSignal: true, alias: "textStyle", required: false }] }], partSelect: [{ type: i0.Output, args: ["partSelect"] }], valueDragPreview: [{ type: i0.Output, args: ["valueDragPreview"] }], valueDragCommit: [{ type: i0.Output, args: ["valueDragCommit"] }], sceneRef: [{ type: i0.ViewChild, args: ['scene', { isSignal: true }] }] } });
120212
121136
 
120213
- // ─────────────────────────────────────────────────────────────────────────────
120214
- // Direct part-editing gate
120215
- // ─────────────────────────────────────────────────────────────────────────────
120216
- /**
120217
- * May this chart's individual parts (title, series, data points) be entered
120218
- * for direct on-canvas editing?
120219
- *
120220
- * Pure so it is unit-testable without a full Angular injection context:
120221
- * `ChartElementViewComponent`'s constructor runs an `effect()` that needs a
120222
- * `ChangeDetectionScheduler` this package's TestBed-free suite doesn't
120223
- * provide. G8: `a:graphicFrameLocks/@noDrilldown` forbids the drill-down,
120224
- * even when the chart is otherwise selected + editable.
120225
- */
120226
- function chartCanEditParts(editable, isSelected, hasEditor, element) {
120227
- return editable && isSelected && hasEditor && canDrillDown(element);
120228
- }
120229
- // ─────────────────────────────────────────────────────────────────────────────
120230
- // Value-drag commit gate
120231
- // ─────────────────────────────────────────────────────────────────────────────
120232
- /**
120233
- * The chart data a finished drag should commit, or null when nothing should
120234
- * be committed (cancelled, or the press never became a drag).
120235
- */
120236
- function chartDragCommitData(session, commit) {
120237
- if (!commit || !session?.moved) {
120238
- return null;
120239
- }
120240
- return session.lastData;
120241
- }
120242
- /**
120243
- * Same gate as {@link chartDragCommitData}, for a pie/radar/stacked mark drag
120244
- * ({@link ChartMarkDragState} carries the same `moved`/`lastData` shape as the
120245
- * cartesian value-drag session, just resolved through a different geometry).
120246
- */
120247
- function chartMarkDragCommitData(session, commit) {
120248
- if (!commit || !session?.moved) {
120249
- return null;
120250
- }
120251
- return session.lastData;
120252
- }
120253
- // ─────────────────────────────────────────────────────────────────────────────
120254
- // 3D value-drag commit data (bar3D/line3D/area3D/pie3D/surface3D: no drag
120255
- // state machine of their own, the shared three.js scene reports the
120256
- // live/final value directly)
120257
- // ─────────────────────────────────────────────────────────────────────────────
120258
- /**
120259
- * The chart data a 3D scene's `onValueDragPreview`/`onValueDragCommit` should
120260
- * apply, or `null` when the part carries no point index (a series-level part,
120261
- * or a part shape the 3D scenes never actually emit for a value drag) or there
120262
- * is no chart data to update against.
120263
- *
120264
- * Pure so it is unit-testable without a WebGL context: `BarChart3DRendererComponent`
120265
- * / `LineChart3DRendererComponent` / `AreaChart3DRendererComponent` /
120266
- * `PieChart3DRendererComponent` / `SurfaceChart3DRendererComponent` forward
120267
- * their `valueDragPreview`/`valueDragCommit` outputs here via
120268
- * `ChartElementViewComponent`.
120269
- */
120270
- function chart3DPointValueUpdate(chartData, part, value) {
120271
- if (!chartData || part.pointIndex === undefined) {
120272
- return null;
120273
- }
120274
- return withChartPointValue(chartData, part.seriesIndex, part.pointIndex, value);
120275
- }
120276
- /**
120277
- * Commit an on-canvas chart edit through the editor's normal element-update
120278
- * path (the exact channel the inspector uses: one history snapshot per call).
120279
- * No-op without an editor or when the element is not on any slide.
120280
- *
120281
- * `templateSlideId` is the id of the slide the hosting canvas renders (from
120282
- * `SLIDE_CONTEXT`); it resolves template (master/layout) chart elements, which
120283
- * live in the per-slide template store rather than in `slides[].elements`.
120284
- */
120285
- function commitChartElementData(editor, elementId, chartData, templateSlideId) {
120286
- if (!editor) {
120287
- return;
120288
- }
120289
- const slideIndex = findOwningSlideIndex(editor.slides(), elementId, templateSlideId);
120290
- if (slideIndex < 0) {
120291
- return;
120292
- }
120293
- editor.updateElement(slideIndex, elementId, { chartData });
120294
- }
120295
- // ─────────────────────────────────────────────────────────────────────────────
120296
- // Interaction stylesheet (shared base rules + Angular's own badge/editor CSS)
120297
- // ─────────────────────────────────────────────────────────────────────────────
120298
- const STYLE_ELEMENT_ID = 'pptx-ng-chart-interaction-styles';
120299
- /**
120300
- * Angular-only interaction CSS, injected once into `document.head` alongside
120301
- * the shared `[data-chart-part]` / selected-mark rules from
120302
- * `ensureChartInteractionStyles` (`pptx-viewer-shared`). Component styles are
120303
- * view-encapsulated in Angular, so they cannot reach into the chart
120304
- * renderer's SVG or style the badge/title-input this component projects
120305
- * next to it.
120306
- */
120307
- const INTERACTION_CSS = `
120308
- .pptx-ng-chart-view { position: relative; width: 100%; height: 100%; }
120309
- .pptx-ng-chart-drag-badge { position: absolute; top: 4px; right: 4px; z-index: 10; border-radius: 4px; background: rgba(37, 99, 235, 0.9); padding: 2px 6px; font-size: 10px; font-weight: 500; color: #fff; pointer-events: none; }
120310
- .pptx-ng-chart-title-input { position: absolute; left: 50%; top: 2px; z-index: 10; width: 60%; transform: translateX(-50%); border: 1px solid #94a3b8; border-radius: 4px; background: #fff; padding: 2px 4px; text-align: center; font-size: 11px; color: #0f172a; box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2); }
120311
- `;
120312
- /**
120313
- * Inject the interaction stylesheets for chart part hit targets: the shared
120314
- * base rules (singleton, shared across all five bindings) plus Angular's own
120315
- * badge/title-input CSS (singleton, this binding only).
120316
- */
120317
- function ensureChartInteractionStyles() {
120318
- ensureChartInteractionStyles$1();
120319
- if (typeof document === 'undefined' || document.getElementById(STYLE_ELEMENT_ID)) {
120320
- return;
120321
- }
120322
- const style = document.createElement('style');
120323
- style.id = STYLE_ELEMENT_ID;
120324
- style.textContent = INTERACTION_CSS;
120325
- document.head.appendChild(style);
120326
- }
120327
-
120328
121137
  /**
120329
121138
  * chart-part-selection.service.ts: the bridge between on-canvas chart part
120330
121139
  * clicks (`ChartElementViewComponent`) and the chart inspector
@@ -128261,6 +129070,16 @@ class SlideCanvasComponent {
128261
129070
  return box ? (this.elementById(box.id) ?? null) : null;
128262
129071
  }, /* @ts-ignore */
128263
129072
  ...(ngDevMode ? [{ debugName: "singleSelectedElement" }] : /* istanbul ignore next */ []));
129073
+ /**
129074
+ * The single selected element when (and only when) it is a chart: gates
129075
+ * the "Chart Elements"/"Chart Styles"/"Chart Filters" quick-action overlay,
129076
+ * which only makes sense for exactly one selected chart.
129077
+ */
129078
+ this.quickActionsChartElement = computed(() => {
129079
+ const el = this.singleSelectedElement();
129080
+ return el && el.type === 'chart' ? el : null;
129081
+ }, /* @ts-ignore */
129082
+ ...(ngDevMode ? [{ debugName: "quickActionsChartElement" }] : /* istanbul ignore next */ []));
128264
129083
  /**
128265
129084
  * Resize-handle render boxes (stage coords) for the single selection. Empty
128266
129085
  * for an element whose authored `a:spLocks/@noResize` pins its size.
@@ -129218,7 +130037,7 @@ class SlideCanvasComponent {
129218
130037
  // SmartArt), so template (master/layout) element commits can resolve
129219
130038
  // their owning slide; template elements are absent from slides[].elements.
129220
130039
  { provide: SLIDE_CONTEXT, useExisting: forwardRef(() => SlideCanvasComponent) },
129221
- ], viewQueries: [{ propertyName: "textEditor", first: true, predicate: ["textEditor"], descendants: true, isSignal: true }, { propertyName: "listEditor", first: true, predicate: InlineListEditorComponent, descendants: true, isSignal: true }, { propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }, { propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n\t#viewport\n\tclass=\"pptx-ng-canvas-viewport\"\n\t[attr.data-pptx-viewport]=\"interactive() ? '' : null\"\n\t(pointerdown)=\"onViewportPointerDown($event)\"\n>\n\t<div class=\"pptx-ng-canvas-wrapper\" [ngStyle]=\"wrapperStyle()\">\n\t\t<div\n\t\t\t#stage\n\t\t\tclass=\"pptx-ng-canvas-stage\"\n\t\t\t[class.is-editable]=\"editable()\"\n\t\t\trole=\"region\"\n\t\t\t[attr.aria-roledescription]=\"interactive() || presenting() ? 'slide' : null\"\n\t\t\t[attr.data-pptx-ai-active]=\"aiActive() ? 'true' : null\"\n\t\t\t[ngStyle]=\"stageStyle()\"\n\t\t\t(pointerdown)=\"onStagePointerDown($event)\"\n\t\t\t(contextmenu)=\"onContextMenu($event)\"\n\t\t\t(dblclick)=\"onDblClick($event)\"\n\t\t>\n\t\t\t<!--\n\t\t\t\tTemplate layer: inherited master/layout elements, rendered BEHIND\n\t\t\t\tthe slide's own elements (lower z-index). Interactive + given the\n\t\t\t\tamber editable affordance only while editTemplateMode is on; when\n\t\t\t\toff they render inertly with no affordance, exactly as core\n\t\t\t\tdelivered them. `marked` keeps the data-pptx-element contract on\n\t\t\t\tthem even while locked: the marker means \"rendered slide element\",\n\t\t\t\tnot \"editable right now\".\n\t\t\t-->\n\t\t\t@for (element of visibleTemplateElements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive() && editTemplateMode()\"\n\t\t\t\t\t[marked]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[editable]=\"editable() && editTemplateMode()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"editTemplateMode()\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (element of elements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"visibleTemplateElements().length + i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[editable]=\"editable()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"false\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<pptx-activex-controls-overlay\n\t\t\t\t[controls]=\"slide()?.activeXControls ?? []\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t/>\n\t\t\t@if (aiHighlights().length > 0 || aiActive()) {\n\t\t\t\t<pptx-ai-focus-highlight-overlay\n\t\t\t\t\t[highlights]=\"aiHighlights()\"\n\t\t\t\t\t[elements]=\"elements()\"\n\t\t\t\t\t[activeSlideIndex]=\"aiActiveSlideIndex()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@if (aiChangeBatch(); as batch) {\n\t\t\t\t<pptx-ai-change-overlay [batch]=\"batch\" [activeSlideIndex]=\"aiActiveSlideIndex()\" />\n\t\t\t}\n\t\t\t@for (box of selectionBoxes(); track box.id) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-selection\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"box.x\"\n\t\t\t\t\t[style.top.px]=\"box.y\"\n\t\t\t\t\t[style.width.px]=\"box.width\"\n\t\t\t\t\t[style.height.px]=\"box.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (h of handleBoxes(); track h.handle) {\n\t\t\t\t@let controlArtwork = selectionControlArtwork(h, h.handle);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"resize\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.resize' | translate: { handle: h.handle }\"\n\t\t\t\t\t[ngStyle]=\"controlArtwork.frame\"\n\t\t\t\t\t[style.cursor]=\"h.cursor\"\n\t\t\t\t\t[style.--pptx-selection-width.px]=\"singleSelected()?.width\"\n\t\t\t\t\t[style.--pptx-selection-height.px]=\"singleSelected()?.height\"\n\t\t\t\t\t(pointerdown)=\"onHandlePointerDown($event, h.handle)\"\n\t\t\t\t\t(keydown)=\"onResizeHandleKeydown($event, h.handle)\"\n\t\t\t\t>\n\t\t\t\t\t<span data-pptx-handle-hit [ngStyle]=\"resizeHitAreaStyle(h.handle)\"></span>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"controlArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t@if (marqueeRect(); as mr) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-marquee\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"mr.x\"\n\t\t\t\t\t[style.top.px]=\"mr.y\"\n\t\t\t\t\t[style.width.px]=\"mr.width\"\n\t\t\t\t\t[style.height.px]=\"mr.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (g of snapGuides(); track $index) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-snap-guide\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : g.start\"\n\t\t\t\t\t[style.top.px]=\"g.axis === 'x' ? g.start : g.pos\"\n\t\t\t\t\t[style.width.px]=\"g.axis === 'x' ? 0 : g.end - g.start\"\n\t\t\t\t\t[style.height.px]=\"g.axis === 'x' ? g.end - g.start : 0\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@if (rotateHandle(); as rh) {\n\t\t\t\t@let rotateArtwork = selectionControlArtwork(rh);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-rotate-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.z-index]=\"editingBox() ? 10003 : null\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"rotate\"\n\t\t\t\t\t[pptxRotateHandleFor]=\"singleSelected()?.id\"\n\t\t\t\t\t[pptxRotateHandleStage]=\"stage\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.rotate' | translate\"\n\t\t\t\t\t[ngStyle]=\"rotateArtwork.frame\"\n\t\t\t\t\t(pointerdown)=\"onRotatePointerDown($event)\"\n\t\t\t\t\t(keydown)=\"onRotateHandleKeydown($event)\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"rotateArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tShape-adjustment affordances (amber diamonds), ONE per `a:avLst`\n\t\t\t\tguide. Existence, position and cursor all come from the SHARED\n\t\t\t\t`getShapeAdjustmentHandleDescriptors`, so they appear only for a\n\t\t\t\tgeometry with an adjustable parameter, sit where the other four\n\t\t\t\tbindings put them, and are absent for a shape locked with\n\t\t\t\t`noAdjustHandles`. Dragging one writes `shapeAdjustments`; it does\n\t\t\t\tNOT resize the element.\n\t\t\t-->\n\t\t\t@for (ah of adjustHandles(); track ah.key) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-adjust-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"adjust\"\n\t\t\t\t\t[attr.data-pptx-adjust-key]=\"ah.key\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.adjust' | translate\"\n\t\t\t\t\t[style.left.px]=\"ah.left\"\n\t\t\t\t\t[style.top.px]=\"ah.top\"\n\t\t\t\t\t[style.width.px]=\"ah.size\"\n\t\t\t\t\t[style.height.px]=\"ah.size\"\n\t\t\t\t\t[style.cursor]=\"ah.cursor\"\n\t\t\t\t\t(pointerdown)=\"onAdjustPointerDown($event, ah)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tConnector endpoint authoring: drag an end onto a shape's connection\n\t\t\t\tpoint to bind it (`a:stCxn` / `a:endCxn`), or off one to detach.\n\t\t\t\tCandidate sites are revealed only while an end is in flight so they\n\t\t\t\tnever obscure the deck at rest.\n\t\t\t-->\n\t\t\t@for (site of connectorSiteCandidates(); track site.key) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-connection-site\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-snapped]=\"site.snapped\"\n\t\t\t\t\tdata-pptx-connection-site\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[style.left.px]=\"site.left\"\n\t\t\t\t\t[style.top.px]=\"site.top\"\n\t\t\t\t\t[style.width.px]=\"site.size\"\n\t\t\t\t\t[style.height.px]=\"site.size\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (ep of connectorEndpoints(); track ep.kind) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-connector-endpoint\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.data-pptx-connector-endpoint]=\"ep.kind\"\n\t\t\t\t\t[attr.data-pptx-connector-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t(ep.kind === 'start'\n\t\t\t\t\t\t\t? 'pptx.canvas.connectorEndpointStart'\n\t\t\t\t\t\t\t: 'pptx.canvas.connectorEndpointEnd'\n\t\t\t\t\t\t) | translate\n\t\t\t\t\t\"\n\t\t\t\t\t[style.left.px]=\"ep.left\"\n\t\t\t\t\t[style.top.px]=\"ep.top\"\n\t\t\t\t\t[style.width.px]=\"ep.size\"\n\t\t\t\t\t[style.height.px]=\"ep.size\"\n\t\t\t\t\t(pointerdown)=\"onConnectorEndpointPointerDown($event, ep.kind)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t@if (editingBox(); as eb) {\n\t\t\t\t@if (inlineListSeed(); as seed) {\n\t\t\t\t\t@for (session of [seed]; track session) {\n\t\t\t\t\t\t<pptx-inline-list-editor\n\t\t\t\t\t\t\t[element]=\"eb.element\"\n\t\t\t\t\t\t\t[seed]=\"session\"\n\t\t\t\t\t\t\t[activationSelection]=\"listActivationSelection()\"\n\t\t\t\t\t\t\t[spellCheck]=\"spellCheck()\"\n\t\t\t\t\t\t\t(textInput)=\"textInput.emit($event)\"\n\t\t\t\t\t\t\t(textCommit)=\"textCommit.emit($event)\"\n\t\t\t\t\t\t\t(textCancel)=\"textCancel.emit()\"\n\t\t\t\t\t\t\t(textFormat)=\"textFormat.emit($event)\"\n\t\t\t\t\t\t\t(listSession)=\"listSession.emit($event)\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t} @else {\n\t\t\t\t\t<textarea\n\t\t\t\t\t\t#textEditor\n\t\t\t\t\t\tdata-inline-editor\n\t\t\t\t\t\tclass=\"pptx-ng-text-editor\"\n\t\t\t\t\t\taria-label=\"Edit slide text\"\n\t\t\t\t\t\t[spellcheck]=\"spellCheck()\"\n\t\t\t\t\t\t[style.left.px]=\"eb.x\"\n\t\t\t\t\t\t[style.top.px]=\"eb.y\"\n\t\t\t\t\t\t[style.width.px]=\"eb.width\"\n\t\t\t\t\t\t[style.height.px]=\"eb.height\"\n\t\t\t\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t\t\t\t(input)=\"onTextInput($event, eb.id)\"\n\t\t\t\t\t\t(blur)=\"commitText($event, eb.id)\"\n\t\t\t\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t\t\t\t></textarea>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tView overlays: editor aids only, never on thumbnails/preview/presentation.\n\t\t\t\tAll are pointer-events:none so they never break selection/drag.\n\t\t\t\tNone carry data-pptx-element / aria-roledescription / data-pptx-viewport.\n\t\t\t-->\n\t\t\t@if (interactive() && showGrid()) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-grid\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t[attr.id]=\"gridPatternId\"\n\t\t\t\t\t\t\t[attr.width]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\t[attr.height]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t[attr.cx]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\t[attr.cy]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\tr=\"0.6\"\n\t\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.55)\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</pattern>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\t\t[attr.fill]=\"'url(#' + gridPatternId + ')'\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t@if (interactive() && showGuides()) {\n\t\t\t\t<!--\n\t\t\t\t\tCenter crosshair: one horizontal line and one vertical line\n\t\t\t\t\tthrough the midpoint of the slide. Static; draggable guides\n\t\t\t\t\tare a follow-up.\n\t\t\t\t-->\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-guides\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<!-- Horizontal center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t[attr.y1]=\"canvasSize().height / 2\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height / 2\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t\t<!-- Vertical center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"canvasSize().width / 2\"\n\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width / 2\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tUser-created ruler guides.\n\t\t\t\tEach guide has a non-interactive line body and an interactive\n\t\t\t\tdrag handle. Double-click the handle to delete the guide.\n\n\t\t\t\tDeliberately OUTSIDE the showGuides() gate above (which owns the\n\t\t\t\tstatic centre crosshair): a guide the user just dragged off a ruler\n\t\t\t\tstrip must be visible immediately, as it is in Vue and Vanilla.\n\t\t\t\tWhile it lived under that gate, the drag-out gesture silently\n\t\t\t\tproduced an invisible guide unless View > Guides happened to be on.\n\t\t\t-->\n\t\t\t@if (interactive()) {\n\t\t\t\t@for (g of rulerGuidesSvc.rulerGuides(); track g.id) {\n\t\t\t\t\t<!-- Guide line body: pointer-events:none -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-line\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '1px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '1px' : '100%'\"\n\t\t\t\t\t></div>\n\t\t\t\t\t<!-- Drag handle: pointer-events:auto -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-handle\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.cursor]=\"g.axis === 'x' ? 'col-resize' : 'row-resize'\"\n\t\t\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onGuidePointerDown($event, g.id, g.axis)\"\n\t\t\t\t\t\t(dblclick)=\"rulerGuidesSvc.onGuideDoubleClick($event, g.id)\"\n\t\t\t\t\t\t[title]=\"'pptx.canvas.guideTooltip' | translate\"\n\t\t\t\t\t></div>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tLive ink stroke preview: shown while the user is drawing.\n\t\t\t\tpointer-events:none so it never intercepts element gestures.\n\t\t\t\tNo data-pptx-element / aria-roledescription / data-pptx-viewport.\n\n\t\t\t\tRenders `inkDrawing.liveStrokeView()`: the same plain-path /\n\t\t\t\tpressure-circle / tilt-nib decision `InkRendererComponent` makes for\n\t\t\t\ta committed stroke, so a calligraphic lean or pressure-variable\n\t\t\t\twidth shows up while the pointer is still down, not only after\n\t\t\t\trelease.\n\t\t\t-->\n\t\t\t@if (inkDrawing.active() && inkDrawing.liveStrokeView() && drawTool() !== 'select') {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-ink-preview\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none; z-index: 70\"\n\t\t\t\t>\n\t\t\t\t\t@if (inkDrawing.liveStrokeView()?.nibMarks; as nibMarks) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (m of nibMarks; track $index) {\n\t\t\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"m.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"m.cy\"\n\t\t\t\t\t\t\t\t\t[attr.rx]=\"m.rPerp\"\n\t\t\t\t\t\t\t\t\t[attr.ry]=\"m.rTilt\"\n\t\t\t\t\t\t\t\t\t[attr.transform]=\"'rotate(' + m.rotationDeg + ' ' + m.cx + ' ' + m.cy + ')'\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else if (inkDrawing.liveStrokeView()?.circles; as circles) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (c of circles; track $index) {\n\t\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"inkDrawing.liveStrokeView()?.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"inkDrawing.liveStrokeView()?.width\"\n\t\t\t\t\t\t\t[attr.stroke-opacity]=\"inkDrawing.liveStrokeView()?.opacity\"\n\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tProjected overlays (collaboration cursors + remote selections).\n\t\t\t\tThey live INSIDE the scaled stage so the stage's CSS\n\t\t\t\ttransform:scale() applies the on-screen scale exactly once and\n\t\t\t\tthey can be authored in raw, unscaled slide coordinates, exactly\n\t\t\t\tlike the React/Vue overlays.\n\t\t\t-->\n\t\t\t<ng-content />\n\t\t</div>\n\n\t\t<!--\n\t\t\tRuler strips: siblings to the scaled stage inside the wrapper div,\n\t\t\tabsolutely positioned at top:0/left:0 within the wrapper's padding area.\n\t\t\tThe wrapper's padding (RULER_THICKNESS px top+left) reserves space for\n\t\t\tthese strips so the stage content starts below/right of them.\n\t\t\tpointer-events:none so they never intercept element gestures.\n\t\t-->\n\t\t@if (interactive() && showRulers()) {\n\t\t\t<!-- Corner square at the intersection of the two ruler strips -->\n\t\t\t<div class=\"pptx-ng-ruler-corner\" aria-hidden=\"true\"></div>\n\n\t\t\t<!--\n\t\t\t\tHorizontal ruler: spans the top padding row of the wrapper.\n\t\t\t\tA guide is dropped on pointer-UP (not down), resolved by the shared\n\t\t\t\trulerDragToGuidePosition, so a stray click on the strip cannot\n\t\t\t\tdrop a guide the user never dragged out - the rule React, Vue,\n\t\t\t\tSvelte and Vanilla all follow.\n\t\t\t-->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-h\"\n\t\t\t\tdata-pptx-ruler=\"h\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t[style.cursor]=\"editable() ? 'row-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('h', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('h', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (hRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.x]=\"highlight.start\"\n\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t[attr.width]=\"highlight.span\"\n\t\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t[attr.y1]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.x2]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.y2]=\"rulerThickness - 0.5\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of hRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"tick.position\"\n\t\t\t\t\t\t[attr.y1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.x2]=\"tick.position\"\n\t\t\t\t\t\t[attr.y2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"tick.position + 2\"\n\t\t\t\t\t\t\t[attr.y]=\"rulerFontSize + 1\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\n\t\t\t<!-- Vertical ruler: spans the left padding column of the wrapper -->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-v\"\n\t\t\t\tdata-pptx-ruler=\"v\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t[style.cursor]=\"editable() ? 'col-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('v', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('v', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (vRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t[attr.y]=\"highlight.start\"\n\t\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.height]=\"highlight.span\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\t[attr.x1]=\"rulerThickness - 0.5\"\n\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t[attr.x2]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.y2]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of vRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.y1]=\"tick.position\"\n\t\t\t\t\t\t[attr.x2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\t[attr.y2]=\"tick.position\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx=\"2\"\n\t\t\t\t\t\t\t[attr.y]=\"tick.position + rulerFontSize + 2\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\t\t}\n\t</div>\n</div>\n", styles: [".pptx-ng-canvas-stage.is-editable{touch-action:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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: "component", type: AiFocusHighlightOverlayComponent, selector: "pptx-ai-focus-highlight-overlay", inputs: ["highlights", "elements", "activeSlideIndex"] }, { kind: "component", type: AiChangeOverlayComponent, selector: "pptx-ai-change-overlay", inputs: ["batch", "activeSlideIndex"] }, { kind: "component", type: ActiveXControlsOverlayComponent, selector: "pptx-activex-controls-overlay", inputs: ["controls", "canvasSize"] }, { kind: "component", type: InlineListEditorComponent, selector: "pptx-inline-list-editor", inputs: ["element", "seed", "spellCheck", "activationSelection"], outputs: ["textInput", "textCommit", "textCancel", "textFormat", "listSession"] }, { kind: "directive", type: RotateHandlePlacementDirective, selector: "[pptxRotateHandleFor]", inputs: ["pptxRotateHandleFor", "pptxRotateHandleStage"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
130040
+ ], viewQueries: [{ propertyName: "textEditor", first: true, predicate: ["textEditor"], descendants: true, isSignal: true }, { propertyName: "listEditor", first: true, predicate: InlineListEditorComponent, descendants: true, isSignal: true }, { propertyName: "stageRef", first: true, predicate: ["stage"], descendants: true, isSignal: true }, { propertyName: "viewportRef", first: true, predicate: ["viewport"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n\t#viewport\n\tclass=\"pptx-ng-canvas-viewport\"\n\t[attr.data-pptx-viewport]=\"interactive() ? '' : null\"\n\t(pointerdown)=\"onViewportPointerDown($event)\"\n>\n\t<div class=\"pptx-ng-canvas-wrapper\" [ngStyle]=\"wrapperStyle()\">\n\t\t<div\n\t\t\t#stage\n\t\t\tclass=\"pptx-ng-canvas-stage\"\n\t\t\t[class.is-editable]=\"editable()\"\n\t\t\trole=\"region\"\n\t\t\t[attr.aria-roledescription]=\"interactive() || presenting() ? 'slide' : null\"\n\t\t\t[attr.data-pptx-ai-active]=\"aiActive() ? 'true' : null\"\n\t\t\t[ngStyle]=\"stageStyle()\"\n\t\t\t(pointerdown)=\"onStagePointerDown($event)\"\n\t\t\t(contextmenu)=\"onContextMenu($event)\"\n\t\t\t(dblclick)=\"onDblClick($event)\"\n\t\t>\n\t\t\t<!--\n\t\t\t\tTemplate layer: inherited master/layout elements, rendered BEHIND\n\t\t\t\tthe slide's own elements (lower z-index). Interactive + given the\n\t\t\t\tamber editable affordance only while editTemplateMode is on; when\n\t\t\t\toff they render inertly with no affordance, exactly as core\n\t\t\t\tdelivered them. `marked` keeps the data-pptx-element contract on\n\t\t\t\tthem even while locked: the marker means \"rendered slide element\",\n\t\t\t\tnot \"editable right now\".\n\t\t\t-->\n\t\t\t@for (element of visibleTemplateElements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive() && editTemplateMode()\"\n\t\t\t\t\t[marked]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[editable]=\"editable() && editTemplateMode()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"editTemplateMode()\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (element of elements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"visibleTemplateElements().length + i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[editable]=\"editable()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"false\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<pptx-activex-controls-overlay\n\t\t\t\t[controls]=\"slide()?.activeXControls ?? []\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t/>\n\t\t\t@if (aiHighlights().length > 0 || aiActive()) {\n\t\t\t\t<pptx-ai-focus-highlight-overlay\n\t\t\t\t\t[highlights]=\"aiHighlights()\"\n\t\t\t\t\t[elements]=\"elements()\"\n\t\t\t\t\t[activeSlideIndex]=\"aiActiveSlideIndex()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@if (aiChangeBatch(); as batch) {\n\t\t\t\t<pptx-ai-change-overlay [batch]=\"batch\" [activeSlideIndex]=\"aiActiveSlideIndex()\" />\n\t\t\t}\n\t\t\t@for (box of selectionBoxes(); track box.id) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-selection\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"box.x\"\n\t\t\t\t\t[style.top.px]=\"box.y\"\n\t\t\t\t\t[style.width.px]=\"box.width\"\n\t\t\t\t\t[style.height.px]=\"box.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (h of handleBoxes(); track h.handle) {\n\t\t\t\t@let controlArtwork = selectionControlArtwork(h, h.handle);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"resize\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.resize' | translate: { handle: h.handle }\"\n\t\t\t\t\t[ngStyle]=\"controlArtwork.frame\"\n\t\t\t\t\t[style.cursor]=\"h.cursor\"\n\t\t\t\t\t[style.--pptx-selection-width.px]=\"singleSelected()?.width\"\n\t\t\t\t\t[style.--pptx-selection-height.px]=\"singleSelected()?.height\"\n\t\t\t\t\t(pointerdown)=\"onHandlePointerDown($event, h.handle)\"\n\t\t\t\t\t(keydown)=\"onResizeHandleKeydown($event, h.handle)\"\n\t\t\t\t>\n\t\t\t\t\t<span data-pptx-handle-hit [ngStyle]=\"resizeHitAreaStyle(h.handle)\"></span>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"controlArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t@if (marqueeRect(); as mr) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-marquee\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"mr.x\"\n\t\t\t\t\t[style.top.px]=\"mr.y\"\n\t\t\t\t\t[style.width.px]=\"mr.width\"\n\t\t\t\t\t[style.height.px]=\"mr.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (g of snapGuides(); track $index) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-snap-guide\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : g.start\"\n\t\t\t\t\t[style.top.px]=\"g.axis === 'x' ? g.start : g.pos\"\n\t\t\t\t\t[style.width.px]=\"g.axis === 'x' ? 0 : g.end - g.start\"\n\t\t\t\t\t[style.height.px]=\"g.axis === 'x' ? g.end - g.start : 0\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@if (rotateHandle(); as rh) {\n\t\t\t\t@let rotateArtwork = selectionControlArtwork(rh);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-rotate-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.z-index]=\"editingBox() ? 10003 : null\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"rotate\"\n\t\t\t\t\t[pptxRotateHandleFor]=\"singleSelected()?.id\"\n\t\t\t\t\t[pptxRotateHandleStage]=\"stage\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.rotate' | translate\"\n\t\t\t\t\t[ngStyle]=\"rotateArtwork.frame\"\n\t\t\t\t\t(pointerdown)=\"onRotatePointerDown($event)\"\n\t\t\t\t\t(keydown)=\"onRotateHandleKeydown($event)\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"rotateArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tShape-adjustment affordances (amber diamonds), ONE per `a:avLst`\n\t\t\t\tguide. Existence, position and cursor all come from the SHARED\n\t\t\t\t`getShapeAdjustmentHandleDescriptors`, so they appear only for a\n\t\t\t\tgeometry with an adjustable parameter, sit where the other four\n\t\t\t\tbindings put them, and are absent for a shape locked with\n\t\t\t\t`noAdjustHandles`. Dragging one writes `shapeAdjustments`; it does\n\t\t\t\tNOT resize the element.\n\t\t\t-->\n\t\t\t@for (ah of adjustHandles(); track ah.key) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-adjust-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"adjust\"\n\t\t\t\t\t[attr.data-pptx-adjust-key]=\"ah.key\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.adjust' | translate\"\n\t\t\t\t\t[style.left.px]=\"ah.left\"\n\t\t\t\t\t[style.top.px]=\"ah.top\"\n\t\t\t\t\t[style.width.px]=\"ah.size\"\n\t\t\t\t\t[style.height.px]=\"ah.size\"\n\t\t\t\t\t[style.cursor]=\"ah.cursor\"\n\t\t\t\t\t(pointerdown)=\"onAdjustPointerDown($event, ah)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tPowerPoint's floating \"Chart Elements\"/\"Chart Styles\"/\"Chart\n\t\t\t\tFilters\" quick-action icons, shown just outside the chart's\n\t\t\t\ttop-right corner when it is the single selected element.\n\t\t\t-->\n\t\t\t@if (editable() && quickActionsChartElement(); as chartEl) {\n\t\t\t\t<pptx-chart-quick-actions-overlay\n\t\t\t\t\t[element]=\"chartEl\"\n\t\t\t\t\t[canEdit]=\"editable()\"\n\t\t\t\t\t[zoom]=\"effectiveScalePublic()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tConnector endpoint authoring: drag an end onto a shape's connection\n\t\t\t\tpoint to bind it (`a:stCxn` / `a:endCxn`), or off one to detach.\n\t\t\t\tCandidate sites are revealed only while an end is in flight so they\n\t\t\t\tnever obscure the deck at rest.\n\t\t\t-->\n\t\t\t@for (site of connectorSiteCandidates(); track site.key) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-connection-site\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-snapped]=\"site.snapped\"\n\t\t\t\t\tdata-pptx-connection-site\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[style.left.px]=\"site.left\"\n\t\t\t\t\t[style.top.px]=\"site.top\"\n\t\t\t\t\t[style.width.px]=\"site.size\"\n\t\t\t\t\t[style.height.px]=\"site.size\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (ep of connectorEndpoints(); track ep.kind) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-connector-endpoint\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.data-pptx-connector-endpoint]=\"ep.kind\"\n\t\t\t\t\t[attr.data-pptx-connector-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t(ep.kind === 'start'\n\t\t\t\t\t\t\t? 'pptx.canvas.connectorEndpointStart'\n\t\t\t\t\t\t\t: 'pptx.canvas.connectorEndpointEnd'\n\t\t\t\t\t\t) | translate\n\t\t\t\t\t\"\n\t\t\t\t\t[style.left.px]=\"ep.left\"\n\t\t\t\t\t[style.top.px]=\"ep.top\"\n\t\t\t\t\t[style.width.px]=\"ep.size\"\n\t\t\t\t\t[style.height.px]=\"ep.size\"\n\t\t\t\t\t(pointerdown)=\"onConnectorEndpointPointerDown($event, ep.kind)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t@if (editingBox(); as eb) {\n\t\t\t\t@if (inlineListSeed(); as seed) {\n\t\t\t\t\t@for (session of [seed]; track session) {\n\t\t\t\t\t\t<pptx-inline-list-editor\n\t\t\t\t\t\t\t[element]=\"eb.element\"\n\t\t\t\t\t\t\t[seed]=\"session\"\n\t\t\t\t\t\t\t[activationSelection]=\"listActivationSelection()\"\n\t\t\t\t\t\t\t[spellCheck]=\"spellCheck()\"\n\t\t\t\t\t\t\t(textInput)=\"textInput.emit($event)\"\n\t\t\t\t\t\t\t(textCommit)=\"textCommit.emit($event)\"\n\t\t\t\t\t\t\t(textCancel)=\"textCancel.emit()\"\n\t\t\t\t\t\t\t(textFormat)=\"textFormat.emit($event)\"\n\t\t\t\t\t\t\t(listSession)=\"listSession.emit($event)\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t} @else {\n\t\t\t\t\t<textarea\n\t\t\t\t\t\t#textEditor\n\t\t\t\t\t\tdata-inline-editor\n\t\t\t\t\t\tclass=\"pptx-ng-text-editor\"\n\t\t\t\t\t\taria-label=\"Edit slide text\"\n\t\t\t\t\t\t[spellcheck]=\"spellCheck()\"\n\t\t\t\t\t\t[style.left.px]=\"eb.x\"\n\t\t\t\t\t\t[style.top.px]=\"eb.y\"\n\t\t\t\t\t\t[style.width.px]=\"eb.width\"\n\t\t\t\t\t\t[style.height.px]=\"eb.height\"\n\t\t\t\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t\t\t\t(input)=\"onTextInput($event, eb.id)\"\n\t\t\t\t\t\t(blur)=\"commitText($event, eb.id)\"\n\t\t\t\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t\t\t\t></textarea>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tView overlays: editor aids only, never on thumbnails/preview/presentation.\n\t\t\t\tAll are pointer-events:none so they never break selection/drag.\n\t\t\t\tNone carry data-pptx-element / aria-roledescription / data-pptx-viewport.\n\t\t\t-->\n\t\t\t@if (interactive() && showGrid()) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-grid\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t[attr.id]=\"gridPatternId\"\n\t\t\t\t\t\t\t[attr.width]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\t[attr.height]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t[attr.cx]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\t[attr.cy]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\tr=\"0.6\"\n\t\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.55)\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</pattern>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\t\t[attr.fill]=\"'url(#' + gridPatternId + ')'\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t@if (interactive() && showGuides()) {\n\t\t\t\t<!--\n\t\t\t\t\tCenter crosshair: one horizontal line and one vertical line\n\t\t\t\t\tthrough the midpoint of the slide. Static; draggable guides\n\t\t\t\t\tare a follow-up.\n\t\t\t\t-->\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-guides\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<!-- Horizontal center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t[attr.y1]=\"canvasSize().height / 2\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height / 2\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t\t<!-- Vertical center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"canvasSize().width / 2\"\n\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width / 2\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tUser-created ruler guides.\n\t\t\t\tEach guide has a non-interactive line body and an interactive\n\t\t\t\tdrag handle. Double-click the handle to delete the guide.\n\n\t\t\t\tDeliberately OUTSIDE the showGuides() gate above (which owns the\n\t\t\t\tstatic centre crosshair): a guide the user just dragged off a ruler\n\t\t\t\tstrip must be visible immediately, as it is in Vue and Vanilla.\n\t\t\t\tWhile it lived under that gate, the drag-out gesture silently\n\t\t\t\tproduced an invisible guide unless View > Guides happened to be on.\n\t\t\t-->\n\t\t\t@if (interactive()) {\n\t\t\t\t@for (g of rulerGuidesSvc.rulerGuides(); track g.id) {\n\t\t\t\t\t<!-- Guide line body: pointer-events:none -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-line\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '1px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '1px' : '100%'\"\n\t\t\t\t\t></div>\n\t\t\t\t\t<!-- Drag handle: pointer-events:auto -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-handle\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.cursor]=\"g.axis === 'x' ? 'col-resize' : 'row-resize'\"\n\t\t\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onGuidePointerDown($event, g.id, g.axis)\"\n\t\t\t\t\t\t(dblclick)=\"rulerGuidesSvc.onGuideDoubleClick($event, g.id)\"\n\t\t\t\t\t\t[title]=\"'pptx.canvas.guideTooltip' | translate\"\n\t\t\t\t\t></div>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tLive ink stroke preview: shown while the user is drawing.\n\t\t\t\tpointer-events:none so it never intercepts element gestures.\n\t\t\t\tNo data-pptx-element / aria-roledescription / data-pptx-viewport.\n\n\t\t\t\tRenders `inkDrawing.liveStrokeView()`: the same plain-path /\n\t\t\t\tpressure-circle / tilt-nib decision `InkRendererComponent` makes for\n\t\t\t\ta committed stroke, so a calligraphic lean or pressure-variable\n\t\t\t\twidth shows up while the pointer is still down, not only after\n\t\t\t\trelease.\n\t\t\t-->\n\t\t\t@if (inkDrawing.active() && inkDrawing.liveStrokeView() && drawTool() !== 'select') {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-ink-preview\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none; z-index: 70\"\n\t\t\t\t>\n\t\t\t\t\t@if (inkDrawing.liveStrokeView()?.nibMarks; as nibMarks) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (m of nibMarks; track $index) {\n\t\t\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"m.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"m.cy\"\n\t\t\t\t\t\t\t\t\t[attr.rx]=\"m.rPerp\"\n\t\t\t\t\t\t\t\t\t[attr.ry]=\"m.rTilt\"\n\t\t\t\t\t\t\t\t\t[attr.transform]=\"'rotate(' + m.rotationDeg + ' ' + m.cx + ' ' + m.cy + ')'\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else if (inkDrawing.liveStrokeView()?.circles; as circles) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (c of circles; track $index) {\n\t\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"inkDrawing.liveStrokeView()?.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"inkDrawing.liveStrokeView()?.width\"\n\t\t\t\t\t\t\t[attr.stroke-opacity]=\"inkDrawing.liveStrokeView()?.opacity\"\n\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tProjected overlays (collaboration cursors + remote selections).\n\t\t\t\tThey live INSIDE the scaled stage so the stage's CSS\n\t\t\t\ttransform:scale() applies the on-screen scale exactly once and\n\t\t\t\tthey can be authored in raw, unscaled slide coordinates, exactly\n\t\t\t\tlike the React/Vue overlays.\n\t\t\t-->\n\t\t\t<ng-content />\n\t\t</div>\n\n\t\t<!--\n\t\t\tRuler strips: siblings to the scaled stage inside the wrapper div,\n\t\t\tabsolutely positioned at top:0/left:0 within the wrapper's padding area.\n\t\t\tThe wrapper's padding (RULER_THICKNESS px top+left) reserves space for\n\t\t\tthese strips so the stage content starts below/right of them.\n\t\t\tpointer-events:none so they never intercept element gestures.\n\t\t-->\n\t\t@if (interactive() && showRulers()) {\n\t\t\t<!-- Corner square at the intersection of the two ruler strips -->\n\t\t\t<div class=\"pptx-ng-ruler-corner\" aria-hidden=\"true\"></div>\n\n\t\t\t<!--\n\t\t\t\tHorizontal ruler: spans the top padding row of the wrapper.\n\t\t\t\tA guide is dropped on pointer-UP (not down), resolved by the shared\n\t\t\t\trulerDragToGuidePosition, so a stray click on the strip cannot\n\t\t\t\tdrop a guide the user never dragged out - the rule React, Vue,\n\t\t\t\tSvelte and Vanilla all follow.\n\t\t\t-->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-h\"\n\t\t\t\tdata-pptx-ruler=\"h\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t[style.cursor]=\"editable() ? 'row-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('h', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('h', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (hRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.x]=\"highlight.start\"\n\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t[attr.width]=\"highlight.span\"\n\t\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t[attr.y1]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.x2]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.y2]=\"rulerThickness - 0.5\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of hRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"tick.position\"\n\t\t\t\t\t\t[attr.y1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.x2]=\"tick.position\"\n\t\t\t\t\t\t[attr.y2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"tick.position + 2\"\n\t\t\t\t\t\t\t[attr.y]=\"rulerFontSize + 1\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\n\t\t\t<!-- Vertical ruler: spans the left padding column of the wrapper -->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-v\"\n\t\t\t\tdata-pptx-ruler=\"v\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t[style.cursor]=\"editable() ? 'col-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('v', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('v', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (vRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t[attr.y]=\"highlight.start\"\n\t\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.height]=\"highlight.span\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\t[attr.x1]=\"rulerThickness - 0.5\"\n\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t[attr.x2]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.y2]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of vRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.y1]=\"tick.position\"\n\t\t\t\t\t\t[attr.x2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\t[attr.y2]=\"tick.position\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx=\"2\"\n\t\t\t\t\t\t\t[attr.y]=\"tick.position + rulerFontSize + 2\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\t\t}\n\t</div>\n</div>\n", styles: [".pptx-ng-canvas-stage.is-editable{touch-action:none}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { 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: "component", type: AiFocusHighlightOverlayComponent, selector: "pptx-ai-focus-highlight-overlay", inputs: ["highlights", "elements", "activeSlideIndex"] }, { kind: "component", type: AiChangeOverlayComponent, selector: "pptx-ai-change-overlay", inputs: ["batch", "activeSlideIndex"] }, { kind: "component", type: ActiveXControlsOverlayComponent, selector: "pptx-activex-controls-overlay", inputs: ["controls", "canvasSize"] }, { kind: "component", type: InlineListEditorComponent, selector: "pptx-inline-list-editor", inputs: ["element", "seed", "spellCheck", "activationSelection"], outputs: ["textInput", "textCommit", "textCancel", "textFormat", "listSession"] }, { kind: "directive", type: RotateHandlePlacementDirective, selector: "[pptxRotateHandleFor]", inputs: ["pptxRotateHandleFor", "pptxRotateHandleStage"] }, { kind: "component", type: ChartQuickActionsOverlayComponent, selector: "pptx-chart-quick-actions-overlay", inputs: ["element", "canEdit", "zoom"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
129222
130041
  }
129223
130042
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: SlideCanvasComponent, decorators: [{
129224
130043
  type: Component,
@@ -129239,7 +130058,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
129239
130058
  ActiveXControlsOverlayComponent,
129240
130059
  InlineListEditorComponent,
129241
130060
  RotateHandlePlacementDirective,
129242
- ], template: "<div\n\t#viewport\n\tclass=\"pptx-ng-canvas-viewport\"\n\t[attr.data-pptx-viewport]=\"interactive() ? '' : null\"\n\t(pointerdown)=\"onViewportPointerDown($event)\"\n>\n\t<div class=\"pptx-ng-canvas-wrapper\" [ngStyle]=\"wrapperStyle()\">\n\t\t<div\n\t\t\t#stage\n\t\t\tclass=\"pptx-ng-canvas-stage\"\n\t\t\t[class.is-editable]=\"editable()\"\n\t\t\trole=\"region\"\n\t\t\t[attr.aria-roledescription]=\"interactive() || presenting() ? 'slide' : null\"\n\t\t\t[attr.data-pptx-ai-active]=\"aiActive() ? 'true' : null\"\n\t\t\t[ngStyle]=\"stageStyle()\"\n\t\t\t(pointerdown)=\"onStagePointerDown($event)\"\n\t\t\t(contextmenu)=\"onContextMenu($event)\"\n\t\t\t(dblclick)=\"onDblClick($event)\"\n\t\t>\n\t\t\t<!--\n\t\t\t\tTemplate layer: inherited master/layout elements, rendered BEHIND\n\t\t\t\tthe slide's own elements (lower z-index). Interactive + given the\n\t\t\t\tamber editable affordance only while editTemplateMode is on; when\n\t\t\t\toff they render inertly with no affordance, exactly as core\n\t\t\t\tdelivered them. `marked` keeps the data-pptx-element contract on\n\t\t\t\tthem even while locked: the marker means \"rendered slide element\",\n\t\t\t\tnot \"editable right now\".\n\t\t\t-->\n\t\t\t@for (element of visibleTemplateElements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive() && editTemplateMode()\"\n\t\t\t\t\t[marked]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[editable]=\"editable() && editTemplateMode()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"editTemplateMode()\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (element of elements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"visibleTemplateElements().length + i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[editable]=\"editable()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"false\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<pptx-activex-controls-overlay\n\t\t\t\t[controls]=\"slide()?.activeXControls ?? []\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t/>\n\t\t\t@if (aiHighlights().length > 0 || aiActive()) {\n\t\t\t\t<pptx-ai-focus-highlight-overlay\n\t\t\t\t\t[highlights]=\"aiHighlights()\"\n\t\t\t\t\t[elements]=\"elements()\"\n\t\t\t\t\t[activeSlideIndex]=\"aiActiveSlideIndex()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@if (aiChangeBatch(); as batch) {\n\t\t\t\t<pptx-ai-change-overlay [batch]=\"batch\" [activeSlideIndex]=\"aiActiveSlideIndex()\" />\n\t\t\t}\n\t\t\t@for (box of selectionBoxes(); track box.id) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-selection\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"box.x\"\n\t\t\t\t\t[style.top.px]=\"box.y\"\n\t\t\t\t\t[style.width.px]=\"box.width\"\n\t\t\t\t\t[style.height.px]=\"box.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (h of handleBoxes(); track h.handle) {\n\t\t\t\t@let controlArtwork = selectionControlArtwork(h, h.handle);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"resize\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.resize' | translate: { handle: h.handle }\"\n\t\t\t\t\t[ngStyle]=\"controlArtwork.frame\"\n\t\t\t\t\t[style.cursor]=\"h.cursor\"\n\t\t\t\t\t[style.--pptx-selection-width.px]=\"singleSelected()?.width\"\n\t\t\t\t\t[style.--pptx-selection-height.px]=\"singleSelected()?.height\"\n\t\t\t\t\t(pointerdown)=\"onHandlePointerDown($event, h.handle)\"\n\t\t\t\t\t(keydown)=\"onResizeHandleKeydown($event, h.handle)\"\n\t\t\t\t>\n\t\t\t\t\t<span data-pptx-handle-hit [ngStyle]=\"resizeHitAreaStyle(h.handle)\"></span>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"controlArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t@if (marqueeRect(); as mr) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-marquee\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"mr.x\"\n\t\t\t\t\t[style.top.px]=\"mr.y\"\n\t\t\t\t\t[style.width.px]=\"mr.width\"\n\t\t\t\t\t[style.height.px]=\"mr.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (g of snapGuides(); track $index) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-snap-guide\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : g.start\"\n\t\t\t\t\t[style.top.px]=\"g.axis === 'x' ? g.start : g.pos\"\n\t\t\t\t\t[style.width.px]=\"g.axis === 'x' ? 0 : g.end - g.start\"\n\t\t\t\t\t[style.height.px]=\"g.axis === 'x' ? g.end - g.start : 0\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@if (rotateHandle(); as rh) {\n\t\t\t\t@let rotateArtwork = selectionControlArtwork(rh);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-rotate-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.z-index]=\"editingBox() ? 10003 : null\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"rotate\"\n\t\t\t\t\t[pptxRotateHandleFor]=\"singleSelected()?.id\"\n\t\t\t\t\t[pptxRotateHandleStage]=\"stage\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.rotate' | translate\"\n\t\t\t\t\t[ngStyle]=\"rotateArtwork.frame\"\n\t\t\t\t\t(pointerdown)=\"onRotatePointerDown($event)\"\n\t\t\t\t\t(keydown)=\"onRotateHandleKeydown($event)\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"rotateArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tShape-adjustment affordances (amber diamonds), ONE per `a:avLst`\n\t\t\t\tguide. Existence, position and cursor all come from the SHARED\n\t\t\t\t`getShapeAdjustmentHandleDescriptors`, so they appear only for a\n\t\t\t\tgeometry with an adjustable parameter, sit where the other four\n\t\t\t\tbindings put them, and are absent for a shape locked with\n\t\t\t\t`noAdjustHandles`. Dragging one writes `shapeAdjustments`; it does\n\t\t\t\tNOT resize the element.\n\t\t\t-->\n\t\t\t@for (ah of adjustHandles(); track ah.key) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-adjust-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"adjust\"\n\t\t\t\t\t[attr.data-pptx-adjust-key]=\"ah.key\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.adjust' | translate\"\n\t\t\t\t\t[style.left.px]=\"ah.left\"\n\t\t\t\t\t[style.top.px]=\"ah.top\"\n\t\t\t\t\t[style.width.px]=\"ah.size\"\n\t\t\t\t\t[style.height.px]=\"ah.size\"\n\t\t\t\t\t[style.cursor]=\"ah.cursor\"\n\t\t\t\t\t(pointerdown)=\"onAdjustPointerDown($event, ah)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tConnector endpoint authoring: drag an end onto a shape's connection\n\t\t\t\tpoint to bind it (`a:stCxn` / `a:endCxn`), or off one to detach.\n\t\t\t\tCandidate sites are revealed only while an end is in flight so they\n\t\t\t\tnever obscure the deck at rest.\n\t\t\t-->\n\t\t\t@for (site of connectorSiteCandidates(); track site.key) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-connection-site\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-snapped]=\"site.snapped\"\n\t\t\t\t\tdata-pptx-connection-site\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[style.left.px]=\"site.left\"\n\t\t\t\t\t[style.top.px]=\"site.top\"\n\t\t\t\t\t[style.width.px]=\"site.size\"\n\t\t\t\t\t[style.height.px]=\"site.size\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (ep of connectorEndpoints(); track ep.kind) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-connector-endpoint\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.data-pptx-connector-endpoint]=\"ep.kind\"\n\t\t\t\t\t[attr.data-pptx-connector-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t(ep.kind === 'start'\n\t\t\t\t\t\t\t? 'pptx.canvas.connectorEndpointStart'\n\t\t\t\t\t\t\t: 'pptx.canvas.connectorEndpointEnd'\n\t\t\t\t\t\t) | translate\n\t\t\t\t\t\"\n\t\t\t\t\t[style.left.px]=\"ep.left\"\n\t\t\t\t\t[style.top.px]=\"ep.top\"\n\t\t\t\t\t[style.width.px]=\"ep.size\"\n\t\t\t\t\t[style.height.px]=\"ep.size\"\n\t\t\t\t\t(pointerdown)=\"onConnectorEndpointPointerDown($event, ep.kind)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t@if (editingBox(); as eb) {\n\t\t\t\t@if (inlineListSeed(); as seed) {\n\t\t\t\t\t@for (session of [seed]; track session) {\n\t\t\t\t\t\t<pptx-inline-list-editor\n\t\t\t\t\t\t\t[element]=\"eb.element\"\n\t\t\t\t\t\t\t[seed]=\"session\"\n\t\t\t\t\t\t\t[activationSelection]=\"listActivationSelection()\"\n\t\t\t\t\t\t\t[spellCheck]=\"spellCheck()\"\n\t\t\t\t\t\t\t(textInput)=\"textInput.emit($event)\"\n\t\t\t\t\t\t\t(textCommit)=\"textCommit.emit($event)\"\n\t\t\t\t\t\t\t(textCancel)=\"textCancel.emit()\"\n\t\t\t\t\t\t\t(textFormat)=\"textFormat.emit($event)\"\n\t\t\t\t\t\t\t(listSession)=\"listSession.emit($event)\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t} @else {\n\t\t\t\t\t<textarea\n\t\t\t\t\t\t#textEditor\n\t\t\t\t\t\tdata-inline-editor\n\t\t\t\t\t\tclass=\"pptx-ng-text-editor\"\n\t\t\t\t\t\taria-label=\"Edit slide text\"\n\t\t\t\t\t\t[spellcheck]=\"spellCheck()\"\n\t\t\t\t\t\t[style.left.px]=\"eb.x\"\n\t\t\t\t\t\t[style.top.px]=\"eb.y\"\n\t\t\t\t\t\t[style.width.px]=\"eb.width\"\n\t\t\t\t\t\t[style.height.px]=\"eb.height\"\n\t\t\t\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t\t\t\t(input)=\"onTextInput($event, eb.id)\"\n\t\t\t\t\t\t(blur)=\"commitText($event, eb.id)\"\n\t\t\t\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t\t\t\t></textarea>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tView overlays: editor aids only, never on thumbnails/preview/presentation.\n\t\t\t\tAll are pointer-events:none so they never break selection/drag.\n\t\t\t\tNone carry data-pptx-element / aria-roledescription / data-pptx-viewport.\n\t\t\t-->\n\t\t\t@if (interactive() && showGrid()) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-grid\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t[attr.id]=\"gridPatternId\"\n\t\t\t\t\t\t\t[attr.width]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\t[attr.height]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t[attr.cx]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\t[attr.cy]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\tr=\"0.6\"\n\t\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.55)\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</pattern>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\t\t[attr.fill]=\"'url(#' + gridPatternId + ')'\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t@if (interactive() && showGuides()) {\n\t\t\t\t<!--\n\t\t\t\t\tCenter crosshair: one horizontal line and one vertical line\n\t\t\t\t\tthrough the midpoint of the slide. Static; draggable guides\n\t\t\t\t\tare a follow-up.\n\t\t\t\t-->\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-guides\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<!-- Horizontal center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t[attr.y1]=\"canvasSize().height / 2\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height / 2\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t\t<!-- Vertical center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"canvasSize().width / 2\"\n\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width / 2\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tUser-created ruler guides.\n\t\t\t\tEach guide has a non-interactive line body and an interactive\n\t\t\t\tdrag handle. Double-click the handle to delete the guide.\n\n\t\t\t\tDeliberately OUTSIDE the showGuides() gate above (which owns the\n\t\t\t\tstatic centre crosshair): a guide the user just dragged off a ruler\n\t\t\t\tstrip must be visible immediately, as it is in Vue and Vanilla.\n\t\t\t\tWhile it lived under that gate, the drag-out gesture silently\n\t\t\t\tproduced an invisible guide unless View > Guides happened to be on.\n\t\t\t-->\n\t\t\t@if (interactive()) {\n\t\t\t\t@for (g of rulerGuidesSvc.rulerGuides(); track g.id) {\n\t\t\t\t\t<!-- Guide line body: pointer-events:none -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-line\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '1px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '1px' : '100%'\"\n\t\t\t\t\t></div>\n\t\t\t\t\t<!-- Drag handle: pointer-events:auto -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-handle\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.cursor]=\"g.axis === 'x' ? 'col-resize' : 'row-resize'\"\n\t\t\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onGuidePointerDown($event, g.id, g.axis)\"\n\t\t\t\t\t\t(dblclick)=\"rulerGuidesSvc.onGuideDoubleClick($event, g.id)\"\n\t\t\t\t\t\t[title]=\"'pptx.canvas.guideTooltip' | translate\"\n\t\t\t\t\t></div>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tLive ink stroke preview: shown while the user is drawing.\n\t\t\t\tpointer-events:none so it never intercepts element gestures.\n\t\t\t\tNo data-pptx-element / aria-roledescription / data-pptx-viewport.\n\n\t\t\t\tRenders `inkDrawing.liveStrokeView()`: the same plain-path /\n\t\t\t\tpressure-circle / tilt-nib decision `InkRendererComponent` makes for\n\t\t\t\ta committed stroke, so a calligraphic lean or pressure-variable\n\t\t\t\twidth shows up while the pointer is still down, not only after\n\t\t\t\trelease.\n\t\t\t-->\n\t\t\t@if (inkDrawing.active() && inkDrawing.liveStrokeView() && drawTool() !== 'select') {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-ink-preview\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none; z-index: 70\"\n\t\t\t\t>\n\t\t\t\t\t@if (inkDrawing.liveStrokeView()?.nibMarks; as nibMarks) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (m of nibMarks; track $index) {\n\t\t\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"m.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"m.cy\"\n\t\t\t\t\t\t\t\t\t[attr.rx]=\"m.rPerp\"\n\t\t\t\t\t\t\t\t\t[attr.ry]=\"m.rTilt\"\n\t\t\t\t\t\t\t\t\t[attr.transform]=\"'rotate(' + m.rotationDeg + ' ' + m.cx + ' ' + m.cy + ')'\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else if (inkDrawing.liveStrokeView()?.circles; as circles) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (c of circles; track $index) {\n\t\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"inkDrawing.liveStrokeView()?.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"inkDrawing.liveStrokeView()?.width\"\n\t\t\t\t\t\t\t[attr.stroke-opacity]=\"inkDrawing.liveStrokeView()?.opacity\"\n\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tProjected overlays (collaboration cursors + remote selections).\n\t\t\t\tThey live INSIDE the scaled stage so the stage's CSS\n\t\t\t\ttransform:scale() applies the on-screen scale exactly once and\n\t\t\t\tthey can be authored in raw, unscaled slide coordinates, exactly\n\t\t\t\tlike the React/Vue overlays.\n\t\t\t-->\n\t\t\t<ng-content />\n\t\t</div>\n\n\t\t<!--\n\t\t\tRuler strips: siblings to the scaled stage inside the wrapper div,\n\t\t\tabsolutely positioned at top:0/left:0 within the wrapper's padding area.\n\t\t\tThe wrapper's padding (RULER_THICKNESS px top+left) reserves space for\n\t\t\tthese strips so the stage content starts below/right of them.\n\t\t\tpointer-events:none so they never intercept element gestures.\n\t\t-->\n\t\t@if (interactive() && showRulers()) {\n\t\t\t<!-- Corner square at the intersection of the two ruler strips -->\n\t\t\t<div class=\"pptx-ng-ruler-corner\" aria-hidden=\"true\"></div>\n\n\t\t\t<!--\n\t\t\t\tHorizontal ruler: spans the top padding row of the wrapper.\n\t\t\t\tA guide is dropped on pointer-UP (not down), resolved by the shared\n\t\t\t\trulerDragToGuidePosition, so a stray click on the strip cannot\n\t\t\t\tdrop a guide the user never dragged out - the rule React, Vue,\n\t\t\t\tSvelte and Vanilla all follow.\n\t\t\t-->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-h\"\n\t\t\t\tdata-pptx-ruler=\"h\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t[style.cursor]=\"editable() ? 'row-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('h', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('h', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (hRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.x]=\"highlight.start\"\n\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t[attr.width]=\"highlight.span\"\n\t\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t[attr.y1]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.x2]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.y2]=\"rulerThickness - 0.5\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of hRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"tick.position\"\n\t\t\t\t\t\t[attr.y1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.x2]=\"tick.position\"\n\t\t\t\t\t\t[attr.y2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"tick.position + 2\"\n\t\t\t\t\t\t\t[attr.y]=\"rulerFontSize + 1\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\n\t\t\t<!-- Vertical ruler: spans the left padding column of the wrapper -->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-v\"\n\t\t\t\tdata-pptx-ruler=\"v\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t[style.cursor]=\"editable() ? 'col-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('v', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('v', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (vRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t[attr.y]=\"highlight.start\"\n\t\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.height]=\"highlight.span\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\t[attr.x1]=\"rulerThickness - 0.5\"\n\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t[attr.x2]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.y2]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of vRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.y1]=\"tick.position\"\n\t\t\t\t\t\t[attr.x2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\t[attr.y2]=\"tick.position\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx=\"2\"\n\t\t\t\t\t\t\t[attr.y]=\"tick.position + rulerFontSize + 2\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\t\t}\n\t</div>\n</div>\n", styles: [".pptx-ng-canvas-stage.is-editable{touch-action:none}\n"] }]
130061
+ ChartQuickActionsOverlayComponent,
130062
+ ], template: "<div\n\t#viewport\n\tclass=\"pptx-ng-canvas-viewport\"\n\t[attr.data-pptx-viewport]=\"interactive() ? '' : null\"\n\t(pointerdown)=\"onViewportPointerDown($event)\"\n>\n\t<div class=\"pptx-ng-canvas-wrapper\" [ngStyle]=\"wrapperStyle()\">\n\t\t<div\n\t\t\t#stage\n\t\t\tclass=\"pptx-ng-canvas-stage\"\n\t\t\t[class.is-editable]=\"editable()\"\n\t\t\trole=\"region\"\n\t\t\t[attr.aria-roledescription]=\"interactive() || presenting() ? 'slide' : null\"\n\t\t\t[attr.data-pptx-ai-active]=\"aiActive() ? 'true' : null\"\n\t\t\t[ngStyle]=\"stageStyle()\"\n\t\t\t(pointerdown)=\"onStagePointerDown($event)\"\n\t\t\t(contextmenu)=\"onContextMenu($event)\"\n\t\t\t(dblclick)=\"onDblClick($event)\"\n\t\t>\n\t\t\t<!--\n\t\t\t\tTemplate layer: inherited master/layout elements, rendered BEHIND\n\t\t\t\tthe slide's own elements (lower z-index). Interactive + given the\n\t\t\t\tamber editable affordance only while editTemplateMode is on; when\n\t\t\t\toff they render inertly with no affordance, exactly as core\n\t\t\t\tdelivered them. `marked` keeps the data-pptx-element contract on\n\t\t\t\tthem even while locked: the marker means \"rendered slide element\",\n\t\t\t\tnot \"editable right now\".\n\t\t\t-->\n\t\t\t@for (element of visibleTemplateElements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive() && editTemplateMode()\"\n\t\t\t\t\t[marked]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[editable]=\"editable() && editTemplateMode()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"editTemplateMode()\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (element of elements(); track element.id; let i = $index) {\n\t\t\t\t<pptx-element-renderer\n\t\t\t\t\t[element]=\"element\"\n\t\t\t\t\t[mediaDataUrls]=\"mediaDataUrls()\"\n\t\t\t\t\t[zIndex]=\"visibleTemplateElements().length + i\"\n\t\t\t\t\t[obstacles]=\"connectorObstacles()\"\n\t\t\t\t\t[canvasWidth]=\"canvasSize().width\"\n\t\t\t\t\t[canvasHeight]=\"canvasSize().height\"\n\t\t\t\t\t[interactive]=\"interactive()\"\n\t\t\t\t\t[exposeElementId]=\"exposeElementIds()\"\n\t\t\t\t\t[presenting]=\"presenting()\"\n\t\t\t\t\t[editable]=\"editable()\"\n\t\t\t\t\t[fieldContext]=\"fieldContext()\"\n\t\t\t\t\t[slideElements]=\"allElements()\"\n\t\t\t\t\t[editTemplateMode]=\"false\"\n\t\t\t\t\t[editingElementId]=\"editingId()\"\n\t\t\t\t\t(cellCommit)=\"cellCommit.emit($event)\"\n\t\t\t\t\t(tableChange)=\"tableChange.emit($event)\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<pptx-activex-controls-overlay\n\t\t\t\t[controls]=\"slide()?.activeXControls ?? []\"\n\t\t\t\t[canvasSize]=\"canvasSize()\"\n\t\t\t/>\n\t\t\t@if (aiHighlights().length > 0 || aiActive()) {\n\t\t\t\t<pptx-ai-focus-highlight-overlay\n\t\t\t\t\t[highlights]=\"aiHighlights()\"\n\t\t\t\t\t[elements]=\"elements()\"\n\t\t\t\t\t[activeSlideIndex]=\"aiActiveSlideIndex()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@if (aiChangeBatch(); as batch) {\n\t\t\t\t<pptx-ai-change-overlay [batch]=\"batch\" [activeSlideIndex]=\"aiActiveSlideIndex()\" />\n\t\t\t}\n\t\t\t@for (box of selectionBoxes(); track box.id) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-selection\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"box.x\"\n\t\t\t\t\t[style.top.px]=\"box.y\"\n\t\t\t\t\t[style.width.px]=\"box.width\"\n\t\t\t\t\t[style.height.px]=\"box.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (h of handleBoxes(); track h.handle) {\n\t\t\t\t@let controlArtwork = selectionControlArtwork(h, h.handle);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"resize\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.resize' | translate: { handle: h.handle }\"\n\t\t\t\t\t[ngStyle]=\"controlArtwork.frame\"\n\t\t\t\t\t[style.cursor]=\"h.cursor\"\n\t\t\t\t\t[style.--pptx-selection-width.px]=\"singleSelected()?.width\"\n\t\t\t\t\t[style.--pptx-selection-height.px]=\"singleSelected()?.height\"\n\t\t\t\t\t(pointerdown)=\"onHandlePointerDown($event, h.handle)\"\n\t\t\t\t\t(keydown)=\"onResizeHandleKeydown($event, h.handle)\"\n\t\t\t\t>\n\t\t\t\t\t<span data-pptx-handle-hit [ngStyle]=\"resizeHitAreaStyle(h.handle)\"></span>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"controlArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t@if (marqueeRect(); as mr) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-marquee\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"mr.x\"\n\t\t\t\t\t[style.top.px]=\"mr.y\"\n\t\t\t\t\t[style.width.px]=\"mr.width\"\n\t\t\t\t\t[style.height.px]=\"mr.height\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (g of snapGuides(); track $index) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-snap-guide\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : g.start\"\n\t\t\t\t\t[style.top.px]=\"g.axis === 'x' ? g.start : g.pos\"\n\t\t\t\t\t[style.width.px]=\"g.axis === 'x' ? 0 : g.end - g.start\"\n\t\t\t\t\t[style.height.px]=\"g.axis === 'x' ? g.end - g.start : 0\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@if (rotateHandle(); as rh) {\n\t\t\t\t@let rotateArtwork = selectionControlArtwork(rh);\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-rotate-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[style.z-index]=\"editingBox() ? 10003 : null\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"rotate\"\n\t\t\t\t\t[pptxRotateHandleFor]=\"singleSelected()?.id\"\n\t\t\t\t\t[pptxRotateHandleStage]=\"stage\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.rotate' | translate\"\n\t\t\t\t\t[ngStyle]=\"rotateArtwork.frame\"\n\t\t\t\t\t(pointerdown)=\"onRotatePointerDown($event)\"\n\t\t\t\t\t(keydown)=\"onRotateHandleKeydown($event)\"\n\t\t\t\t>\n\t\t\t\t\t<span\n\t\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t\tclass=\"pptx-ng-control-artwork\"\n\t\t\t\t\t\tdata-pptx-handle-artwork\n\t\t\t\t\t\t[ngStyle]=\"rotateArtwork.artwork\"\n\t\t\t\t\t></span>\n\t\t\t\t</button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tShape-adjustment affordances (amber diamonds), ONE per `a:avLst`\n\t\t\t\tguide. Existence, position and cursor all come from the SHARED\n\t\t\t\t`getShapeAdjustmentHandleDescriptors`, so they appear only for a\n\t\t\t\tgeometry with an adjustable parameter, sit where the other four\n\t\t\t\tbindings put them, and are absent for a shape locked with\n\t\t\t\t`noAdjustHandles`. Dragging one writes `shapeAdjustments`; it does\n\t\t\t\tNOT resize the element.\n\t\t\t-->\n\t\t\t@for (ah of adjustHandles(); track ah.key) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-adjust-handle\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\tdata-pptx-handle-kind=\"adjust\"\n\t\t\t\t\t[attr.data-pptx-adjust-key]=\"ah.key\"\n\t\t\t\t\t[attr.aria-label]=\"'pptx.selectionOverlay.adjust' | translate\"\n\t\t\t\t\t[style.left.px]=\"ah.left\"\n\t\t\t\t\t[style.top.px]=\"ah.top\"\n\t\t\t\t\t[style.width.px]=\"ah.size\"\n\t\t\t\t\t[style.height.px]=\"ah.size\"\n\t\t\t\t\t[style.cursor]=\"ah.cursor\"\n\t\t\t\t\t(pointerdown)=\"onAdjustPointerDown($event, ah)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tPowerPoint's floating \"Chart Elements\"/\"Chart Styles\"/\"Chart\n\t\t\t\tFilters\" quick-action icons, shown just outside the chart's\n\t\t\t\ttop-right corner when it is the single selected element.\n\t\t\t-->\n\t\t\t@if (editable() && quickActionsChartElement(); as chartEl) {\n\t\t\t\t<pptx-chart-quick-actions-overlay\n\t\t\t\t\t[element]=\"chartEl\"\n\t\t\t\t\t[canEdit]=\"editable()\"\n\t\t\t\t\t[zoom]=\"effectiveScalePublic()\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t<!--\n\t\t\t\tConnector endpoint authoring: drag an end onto a shape's connection\n\t\t\t\tpoint to bind it (`a:stCxn` / `a:endCxn`), or off one to detach.\n\t\t\t\tCandidate sites are revealed only while an end is in flight so they\n\t\t\t\tnever obscure the deck at rest.\n\t\t\t-->\n\t\t\t@for (site of connectorSiteCandidates(); track site.key) {\n\t\t\t\t<div\n\t\t\t\t\tclass=\"pptx-ng-connection-site\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-snapped]=\"site.snapped\"\n\t\t\t\t\tdata-pptx-connection-site\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[style.left.px]=\"site.left\"\n\t\t\t\t\t[style.top.px]=\"site.top\"\n\t\t\t\t\t[style.width.px]=\"site.size\"\n\t\t\t\t\t[style.height.px]=\"site.size\"\n\t\t\t\t></div>\n\t\t\t}\n\t\t\t@for (ep of connectorEndpoints(); track ep.kind) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-connector-endpoint\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t[class.is-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.data-pptx-connector-endpoint]=\"ep.kind\"\n\t\t\t\t\t[attr.data-pptx-connector-attached]=\"ep.attached\"\n\t\t\t\t\t[attr.aria-label]=\"\n\t\t\t\t\t\t(ep.kind === 'start'\n\t\t\t\t\t\t\t? 'pptx.canvas.connectorEndpointStart'\n\t\t\t\t\t\t\t: 'pptx.canvas.connectorEndpointEnd'\n\t\t\t\t\t\t) | translate\n\t\t\t\t\t\"\n\t\t\t\t\t[style.left.px]=\"ep.left\"\n\t\t\t\t\t[style.top.px]=\"ep.top\"\n\t\t\t\t\t[style.width.px]=\"ep.size\"\n\t\t\t\t\t[style.height.px]=\"ep.size\"\n\t\t\t\t\t(pointerdown)=\"onConnectorEndpointPointerDown($event, ep.kind)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t\t@if (editingBox(); as eb) {\n\t\t\t\t@if (inlineListSeed(); as seed) {\n\t\t\t\t\t@for (session of [seed]; track session) {\n\t\t\t\t\t\t<pptx-inline-list-editor\n\t\t\t\t\t\t\t[element]=\"eb.element\"\n\t\t\t\t\t\t\t[seed]=\"session\"\n\t\t\t\t\t\t\t[activationSelection]=\"listActivationSelection()\"\n\t\t\t\t\t\t\t[spellCheck]=\"spellCheck()\"\n\t\t\t\t\t\t\t(textInput)=\"textInput.emit($event)\"\n\t\t\t\t\t\t\t(textCommit)=\"textCommit.emit($event)\"\n\t\t\t\t\t\t\t(textCancel)=\"textCancel.emit()\"\n\t\t\t\t\t\t\t(textFormat)=\"textFormat.emit($event)\"\n\t\t\t\t\t\t\t(listSession)=\"listSession.emit($event)\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t} @else {\n\t\t\t\t\t<textarea\n\t\t\t\t\t\t#textEditor\n\t\t\t\t\t\tdata-inline-editor\n\t\t\t\t\t\tclass=\"pptx-ng-text-editor\"\n\t\t\t\t\t\taria-label=\"Edit slide text\"\n\t\t\t\t\t\t[spellcheck]=\"spellCheck()\"\n\t\t\t\t\t\t[style.left.px]=\"eb.x\"\n\t\t\t\t\t\t[style.top.px]=\"eb.y\"\n\t\t\t\t\t\t[style.width.px]=\"eb.width\"\n\t\t\t\t\t\t[style.height.px]=\"eb.height\"\n\t\t\t\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t\t\t\t(input)=\"onTextInput($event, eb.id)\"\n\t\t\t\t\t\t(blur)=\"commitText($event, eb.id)\"\n\t\t\t\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t\t\t\t></textarea>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tView overlays: editor aids only, never on thumbnails/preview/presentation.\n\t\t\t\tAll are pointer-events:none so they never break selection/drag.\n\t\t\t\tNone carry data-pptx-element / aria-roledescription / data-pptx-viewport.\n\t\t\t-->\n\t\t\t@if (interactive() && showGrid()) {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-grid\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<defs>\n\t\t\t\t\t\t<pattern\n\t\t\t\t\t\t\t[attr.id]=\"gridPatternId\"\n\t\t\t\t\t\t\t[attr.width]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\t[attr.height]=\"gridSpacingPx()\"\n\t\t\t\t\t\t\tpatternUnits=\"userSpaceOnUse\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t[attr.cx]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\t[attr.cy]=\"gridSpacingPx() / 2\"\n\t\t\t\t\t\t\t\tr=\"0.6\"\n\t\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.55)\"\n\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t</pattern>\n\t\t\t\t\t</defs>\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\t\t[attr.fill]=\"'url(#' + gridPatternId + ')'\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t@if (interactive() && showGuides()) {\n\t\t\t\t<!--\n\t\t\t\t\tCenter crosshair: one horizontal line and one vertical line\n\t\t\t\t\tthrough the midpoint of the slide. Static; draggable guides\n\t\t\t\t\tare a follow-up.\n\t\t\t\t-->\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-overlay-guides\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t>\n\t\t\t\t\t<!-- Horizontal center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t\t[attr.y1]=\"canvasSize().height / 2\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height / 2\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t\t<!-- Vertical center guide -->\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"canvasSize().width / 2\"\n\t\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t\t[attr.x2]=\"canvasSize().width / 2\"\n\t\t\t\t\t\t[attr.y2]=\"canvasSize().height\"\n\t\t\t\t\t\tstroke=\"rgba(99,102,241,0.7)\"\n\t\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t\t\tstroke-dasharray=\"6 3\"\n\t\t\t\t\t/>\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tUser-created ruler guides.\n\t\t\t\tEach guide has a non-interactive line body and an interactive\n\t\t\t\tdrag handle. Double-click the handle to delete the guide.\n\n\t\t\t\tDeliberately OUTSIDE the showGuides() gate above (which owns the\n\t\t\t\tstatic centre crosshair): a guide the user just dragged off a ruler\n\t\t\t\tstrip must be visible immediately, as it is in Vue and Vanilla.\n\t\t\t\tWhile it lived under that gate, the drag-out gesture silently\n\t\t\t\tproduced an invisible guide unless View > Guides happened to be on.\n\t\t\t-->\n\t\t\t@if (interactive()) {\n\t\t\t\t@for (g of rulerGuidesSvc.rulerGuides(); track g.id) {\n\t\t\t\t\t<!-- Guide line body: pointer-events:none -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-line\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '1px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '1px' : '100%'\"\n\t\t\t\t\t></div>\n\t\t\t\t\t<!-- Drag handle: pointer-events:auto -->\n\t\t\t\t\t<div\n\t\t\t\t\t\tclass=\"pptx-ng-ruler-guide-handle\"\n\t\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\t\t[style.left.px]=\"g.axis === 'x' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.top.px]=\"g.axis === 'y' ? g.pos - 4 : 0\"\n\t\t\t\t\t\t[style.width]=\"g.axis === 'x' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.height]=\"g.axis === 'y' ? '9px' : '100%'\"\n\t\t\t\t\t\t[style.cursor]=\"g.axis === 'x' ? 'col-resize' : 'row-resize'\"\n\t\t\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onGuidePointerDown($event, g.id, g.axis)\"\n\t\t\t\t\t\t(dblclick)=\"rulerGuidesSvc.onGuideDoubleClick($event, g.id)\"\n\t\t\t\t\t\t[title]=\"'pptx.canvas.guideTooltip' | translate\"\n\t\t\t\t\t></div>\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tLive ink stroke preview: shown while the user is drawing.\n\t\t\t\tpointer-events:none so it never intercepts element gestures.\n\t\t\t\tNo data-pptx-element / aria-roledescription / data-pptx-viewport.\n\n\t\t\t\tRenders `inkDrawing.liveStrokeView()`: the same plain-path /\n\t\t\t\tpressure-circle / tilt-nib decision `InkRendererComponent` makes for\n\t\t\t\ta committed stroke, so a calligraphic lean or pressure-variable\n\t\t\t\twidth shows up while the pointer is still down, not only after\n\t\t\t\trelease.\n\t\t\t-->\n\t\t\t@if (inkDrawing.active() && inkDrawing.liveStrokeView() && drawTool() !== 'select') {\n\t\t\t\t<svg\n\t\t\t\t\tclass=\"pptx-ng-ink-preview\"\n\t\t\t\t\tdata-export-ignore=\"true\"\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\t[attr.width]=\"canvasSize().width\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height\"\n\t\t\t\t\tstyle=\"position: absolute; inset: 0; pointer-events: none; z-index: 70\"\n\t\t\t\t>\n\t\t\t\t\t@if (inkDrawing.liveStrokeView()?.nibMarks; as nibMarks) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (m of nibMarks; track $index) {\n\t\t\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"m.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"m.cy\"\n\t\t\t\t\t\t\t\t\t[attr.rx]=\"m.rPerp\"\n\t\t\t\t\t\t\t\t\t[attr.ry]=\"m.rTilt\"\n\t\t\t\t\t\t\t\t\t[attr.transform]=\"'rotate(' + m.rotationDeg + ' ' + m.cx + ' ' + m.cy + ')'\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else if (inkDrawing.liveStrokeView()?.circles; as circles) {\n\t\t\t\t\t\t<g [attr.opacity]=\"inkDrawing.liveStrokeView()?.opacity\">\n\t\t\t\t\t\t\t@for (c of circles; track $index) {\n\t\t\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t\t\t[attr.fill]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</g>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"inkDrawing.liveStrokeView()?.d\"\n\t\t\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t\t\t[attr.stroke]=\"inkDrawing.liveStrokeView()?.color\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"inkDrawing.liveStrokeView()?.width\"\n\t\t\t\t\t\t\t[attr.stroke-opacity]=\"inkDrawing.liveStrokeView()?.opacity\"\n\t\t\t\t\t\t\tstroke-linecap=\"round\"\n\t\t\t\t\t\t\tstroke-linejoin=\"round\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t</svg>\n\t\t\t}\n\n\t\t\t<!--\n\t\t\t\tProjected overlays (collaboration cursors + remote selections).\n\t\t\t\tThey live INSIDE the scaled stage so the stage's CSS\n\t\t\t\ttransform:scale() applies the on-screen scale exactly once and\n\t\t\t\tthey can be authored in raw, unscaled slide coordinates, exactly\n\t\t\t\tlike the React/Vue overlays.\n\t\t\t-->\n\t\t\t<ng-content />\n\t\t</div>\n\n\t\t<!--\n\t\t\tRuler strips: siblings to the scaled stage inside the wrapper div,\n\t\t\tabsolutely positioned at top:0/left:0 within the wrapper's padding area.\n\t\t\tThe wrapper's padding (RULER_THICKNESS px top+left) reserves space for\n\t\t\tthese strips so the stage content starts below/right of them.\n\t\t\tpointer-events:none so they never intercept element gestures.\n\t\t-->\n\t\t@if (interactive() && showRulers()) {\n\t\t\t<!-- Corner square at the intersection of the two ruler strips -->\n\t\t\t<div class=\"pptx-ng-ruler-corner\" aria-hidden=\"true\"></div>\n\n\t\t\t<!--\n\t\t\t\tHorizontal ruler: spans the top padding row of the wrapper.\n\t\t\t\tA guide is dropped on pointer-UP (not down), resolved by the shared\n\t\t\t\trulerDragToGuidePosition, so a stray click on the strip cannot\n\t\t\t\tdrop a guide the user never dragged out - the rule React, Vue,\n\t\t\t\tSvelte and Vanilla all follow.\n\t\t\t-->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-h\"\n\t\t\t\tdata-pptx-ruler=\"h\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t[style.cursor]=\"editable() ? 'row-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('h', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('h', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (hRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\t[attr.x]=\"highlight.start\"\n\t\t\t\t\t\ty=\"0\"\n\t\t\t\t\t\t[attr.width]=\"highlight.span\"\n\t\t\t\t\t\t[attr.height]=\"rulerThickness\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\tx1=\"0\"\n\t\t\t\t\t[attr.y1]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.x2]=\"canvasSize().width * effectiveScalePublic()\"\n\t\t\t\t\t[attr.y2]=\"rulerThickness - 0.5\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of hRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"tick.position\"\n\t\t\t\t\t\t[attr.y1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.x2]=\"tick.position\"\n\t\t\t\t\t\t[attr.y2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"tick.position + 2\"\n\t\t\t\t\t\t\t[attr.y]=\"rulerFontSize + 1\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\n\t\t\t<!-- Vertical ruler: spans the left padding column of the wrapper -->\n\t\t\t<svg\n\t\t\t\tclass=\"pptx-ng-ruler-v\"\n\t\t\t\tdata-pptx-ruler=\"v\"\n\t\t\t\trole=\"presentation\"\n\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t[style.cursor]=\"editable() ? 'col-resize' : null\"\n\t\t\t\t(pointerdown)=\"rulerGuidesSvc.onRulerPointerDown('v', $event)\"\n\t\t\t\t(pointerup)=\"rulerGuidesSvc.onRulerPointerUp('v', $event)\"\n\t\t\t>\n\t\t\t\t<rect\n\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t[attr.height]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tfill=\"#1e293b\"\n\t\t\t\t/>\n\t\t\t\t@if (vRulerHighlight(); as highlight) {\n\t\t\t\t\t<rect\n\t\t\t\t\t\tx=\"0\"\n\t\t\t\t\t\t[attr.y]=\"highlight.start\"\n\t\t\t\t\t\t[attr.width]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.height]=\"highlight.span\"\n\t\t\t\t\t\tfill=\"rgba(96,165,250,0.25)\"\n\t\t\t\t\t/>\n\t\t\t\t}\n\t\t\t\t<line\n\t\t\t\t\t[attr.x1]=\"rulerThickness - 0.5\"\n\t\t\t\t\ty1=\"0\"\n\t\t\t\t\t[attr.x2]=\"rulerThickness - 0.5\"\n\t\t\t\t\t[attr.y2]=\"canvasSize().height * effectiveScalePublic()\"\n\t\t\t\t\tstroke=\"rgba(255,255,255,0.15)\"\n\t\t\t\t\tstroke-width=\"1\"\n\t\t\t\t/>\n\t\t\t\t@for (tick of vRulerTicks(); track $index) {\n\t\t\t\t\t<line\n\t\t\t\t\t\t[attr.x1]=\"rulerThickness\"\n\t\t\t\t\t\t[attr.y1]=\"tick.position\"\n\t\t\t\t\t\t[attr.x2]=\"rulerThickness - rulerThickness * (tick.isMajor ? 0.6 : 0.3)\"\n\t\t\t\t\t\t[attr.y2]=\"tick.position\"\n\t\t\t\t\t\tstroke=\"rgba(156,163,175,0.7)\"\n\t\t\t\t\t\t[attr.stroke-width]=\"tick.isMajor ? 1 : 0.5\"\n\t\t\t\t\t/>\n\t\t\t\t\t@if (tick.label) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\tx=\"2\"\n\t\t\t\t\t\t\t[attr.y]=\"tick.position + rulerFontSize + 2\"\n\t\t\t\t\t\t\t[attr.font-size]=\"rulerFontSize\"\n\t\t\t\t\t\t\tfill=\"rgba(156,163,175,0.9)\"\n\t\t\t\t\t\t\tstyle=\"font-family: system-ui, sans-serif\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{{ tick.label }}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t</svg>\n\t\t}\n\t</div>\n</div>\n", styles: [".pptx-ng-canvas-stage.is-editable{touch-action:none}\n"] }]
129243
130063
  }], ctorParameters: () => [], propDecorators: { slide: [{ type: i0.Input, args: [{ isSignal: true, alias: "slide", required: false }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], fitPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "fitPadding", required: false }] }], maxFitScale: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxFitScale", required: false }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], showGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGrid", required: false }] }], showRulers: [{ type: i0.Input, args: [{ isSignal: true, alias: "showRulers", required: false }] }], rulerUnit: [{ type: i0.Input, args: [{ isSignal: true, alias: "rulerUnit", required: false }] }], showGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "showGuides", required: false }] }], snapToGrid: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGrid", required: false }] }], gridSpacing: [{ type: i0.Input, args: [{ isSignal: true, alias: "gridSpacing", required: false }] }], snapToShape: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToShape", required: false }] }], guideCommand: [{ type: i0.Input, args: [{ isSignal: true, alias: "guideCommand", required: false }] }], spellCheck: [{ type: i0.Input, args: [{ isSignal: true, alias: "spellCheck", required: false }] }], snapToGuides: [{ type: i0.Input, args: [{ isSignal: true, alias: "snapToGuides", required: false }] }], autoFit: [{ type: i0.Input, args: [{ isSignal: true, alias: "autoFit", required: false }] }], transparentBackground: [{ type: i0.Input, args: [{ isSignal: true, alias: "transparentBackground", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], exposeElementIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "exposeElementIds", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], selectedIds: [{ type: i0.Input, args: [{ isSignal: true, alias: "selectedIds", required: false }] }], editingId: [{ type: i0.Input, args: [{ isSignal: true, alias: "editingId", required: false }] }], editTemplateMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "editTemplateMode", required: false }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], aiHighlights: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiHighlights", required: false }] }], aiActive: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActive", required: false }] }], aiActiveSlideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiActiveSlideIndex", required: false }] }], aiChangeBatch: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiChangeBatch", required: false }] }], aiPickMode: [{ type: i0.Input, args: [{ isSignal: true, alias: "aiPickMode", required: false }] }], drawTool: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawTool", required: false }] }], drawColor: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawColor", required: false }] }], drawWidth: [{ type: i0.Input, args: [{ isSignal: true, alias: "drawWidth", required: false }] }], elementSelect: [{ type: i0.Output, args: ["elementSelect"] }], backgroundClick: [{ type: i0.Output, args: ["backgroundClick"] }], transformStart: [{ type: i0.Output, args: ["transformStart"] }], transformUpdate: [{ type: i0.Output, args: ["transformUpdate"] }], transformEnd: [{ type: i0.Output, args: ["transformEnd"] }], adjustUpdate: [{ type: i0.Output, args: ["adjustUpdate"] }], connectorEndpointUpdate: [{ type: i0.Output, args: ["connectorEndpointUpdate"] }], contextMenu: [{ type: i0.Output, args: ["contextMenu"] }], textEditStart: [{ type: i0.Output, args: ["textEditStart"] }], textCommit: [{ type: i0.Output, args: ["textCommit"] }], textInput: [{ type: i0.Output, args: ["textInput"] }], textCancel: [{ type: i0.Output, args: ["textCancel"] }], textFormat: [{ type: i0.Output, args: ["textFormat"] }], listSession: [{ type: i0.Output, args: ["listSession"] }], rotateUpdate: [{ type: i0.Output, args: ["rotateUpdate"] }], marqueeSelect: [{ type: i0.Output, args: ["marqueeSelect"] }], inkStrokeComplete: [{ type: i0.Output, args: ["inkStrokeComplete"] }], eraserHit: [{ type: i0.Output, args: ["eraserHit"] }], cellCommit: [{ type: i0.Output, args: ["cellCommit"] }], tableChange: [{ type: i0.Output, args: ["tableChange"] }], textEditor: [{ type: i0.ViewChild, args: ['textEditor', { isSignal: true }] }], listEditor: [{ type: i0.ViewChild, args: [i0.forwardRef(() => InlineListEditorComponent), { isSignal: true }] }], stageRef: [{ type: i0.ViewChild, args: ['stage', { isSignal: true }] }], viewportRef: [{ type: i0.ViewChild, args: ['viewport', { isSignal: true }] }], onPointerMove: [{
129244
130064
  type: HostListener,
129245
130065
  args: ['document:pointermove', ['$event']]
@@ -147931,7 +148751,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
147931
148751
  }], 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 }] }] } });
147932
148752
 
147933
148753
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
147934
- const PPTX_ANGULAR_VIEWER_VERSION = "3.19.1";
148754
+ const PPTX_ANGULAR_VIEWER_VERSION = "3.20.0";
147935
148755
 
147936
148756
  /**
147937
148757
  * account-page.component.ts: File > Account content.
@@ -154217,8 +155037,8 @@ class AnimationTimelineComponent {
154217
155037
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.6", ngImport: i0, type: AnimationTimelineComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
154218
155038
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.6", type: AnimationTimelineComponent, isStandalone: true, selector: "pptx-animation-timeline", inputs: { animations: { classPropertyName: "animations", publicName: "animations", isSignal: true, isRequired: true, transformFunction: null }, elements: { classPropertyName: "elements", publicName: "elements", isSignal: true, isRequired: false, transformFunction: null }, animationTimelineAnchors: { classPropertyName: "animationTimelineAnchors", publicName: "animationTimelineAnchors", isSignal: true, isRequired: false, transformFunction: null }, selectedElementId: { classPropertyName: "selectedElementId", publicName: "selectedElementId", isSignal: true, isRequired: false, transformFunction: null }, canEdit: { classPropertyName: "canEdit", publicName: "canEdit", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { animationsChange: "animationsChange" }, ngImport: i0, template: `
154219
155039
  @if (rows().length) {
154220
- <section class="timeline" aria-label="Animation timeline">
154221
- <h4>Timeline</h4>
155040
+ <section class="timeline" [attr.aria-label]="'pptx.animation.timeline' | translate">
155041
+ <h4>{{ 'pptx.animation.timeline' | translate }}</h4>
154222
155042
  <div class="bar" aria-hidden="true">
154223
155043
  @for (item of bars(); track item.elementId) {
154224
155044
  <span
@@ -154271,8 +155091,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
154271
155091
  type: Component,
154272
155092
  args: [{ selector: 'pptx-animation-timeline', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [TranslatePipe], template: `
154273
155093
  @if (rows().length) {
154274
- <section class="timeline" aria-label="Animation timeline">
154275
- <h4>Timeline</h4>
155094
+ <section class="timeline" [attr.aria-label]="'pptx.animation.timeline' | translate">
155095
+ <h4>{{ 'pptx.animation.timeline' | translate }}</h4>
154276
155096
  <div class="bar" aria-hidden="true">
154277
155097
  @for (item of bars(); track item.elementId) {
154278
155098
  <span
@@ -186196,4 +187016,4 @@ function cn(...values) {
186196
187016
  */
186197
187017
 
186198
187018
  export { CollaborationCursorsComponent 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, CINEMATIC_TRANSITION_KEYFRAMES as I, CURSOR_PALETTE as J, CanvasFitService as K, ChartAxisOptionsComponent as L, ChartAxisStyleOptionsComponent as M, ChartComboTypeOptionsComponent as N, ChartDataEditorComponent as O, ChartDataLabelOptionsComponent as P, ChartDatapointMarkerOptionsComponent as Q, ChartDatapointOptionsComponent as R, ChartDisplayOptionsComponent as S, ChartElementViewComponent as T, ChartErrorBarOptionsComponent as U, ChartMarkerOptionsComponent as V, ChartPartSelectionService as W, ChartPrimitivesComponent as X, ChartRendererComponent as Y, ChartTrendlineOptionsComponent as Z, ChartTypeSelectorComponent as _, ALIGN_OPTIONS as a, INSTANT as a$, CollaborationService as a0, ColorChangedImageComponent as a1, CommentMarkersOverlayComponent as a2, CommentsPanelComponent as a3, CommentsService as a4, ComparePanelComponent as a5, ConnectorRendererComponent as a6, ConnectorTextOverlayComponent as a7, CustomShowsComponent as a8, DEFAULT_BOUNDS as a9, EditorContextMenuComponent as aA, EditorHistory as aB, EditorStateService as aC, EditorToolbarComponent as aD, EffectsPanelComponent as aE, ElementRendererComponent as aF, EmbeddedFontsService as aG, EncryptedFileDialogComponent as aH, EquationEditorDialogComponent as aI, EquationRendererComponent as aJ, EquationTemplateGalleryComponent as aK, ExportProgressModalComponent as aL, ExportService as aM, FieldContextService as aN, FindBarComponent as aO, FindReplaceBarComponent as aP, FollowModeBarComponent as aQ, FontEmbeddingListComponent as aR, FontEmbeddingPanelComponent as aS, GALLERY_THEME_PRESETS as aT, GOOGLE_WEBFONTS_LINK_ID as aU, GRIDLINE_COLOR$1 as aV, GoogleWebfontsService as aW, GradientPickerComponent as aX, HANDOUT_OPTIONS as aY, HeaderFooterDialogComponent as aZ, HyperlinkDialogComponent as a_, DEFAULT_BROADCAST_SERVER_URL as aa, DEFAULT_CANVAS_HEIGHT as ab, DEFAULT_CANVAS_WIDTH as ac, DEFAULT_COLOR_SCHEME as ad, DEFAULT_FILL_COLOR$1 as ae, DEFAULT_LAYOUT as af, DEFAULT_MORPH_DURATION_MS as ag, DEFAULT_PALETTE$1 as ah, DEFAULT_PATTERN_FILL_PRESET as ai, DEFAULT_PRINT_SETTINGS as aj, DEFAULT_SLIDE_BACKGROUND as ak, DEFAULT_STROKE_COLOR as al, DEFAULT_STYLE as am, DEFAULT_TABLE_ROW_HEIGHT as an, DEFAULT_TEXT_COLOR$2 as ao, DEFAULT_VIEWER_PROFILE as ap, DIRECTIONAL_PRESETS as aq, DIRECTION_OPTIONS as ar, DocumentPropertiesCardComponent as as, EASE as at, EFFECT_SOUND_CATALOGUE as au, EMBEDDED_FONTS_STYLE_ID as av, EMPHASIS_PRESETS as aw, ENTRANCE_PRESETS as ax, TEMPLATES as ay, EXIT_PRESETS as az, ANIMATION_PRESET_CATEGORIES as b, REPEAT_MODE_OPTIONS as b$, ImagePropertiesPanelComponent as b0, InkDrawingService as b1, InkRendererComponent as b2, InsertSmartArtDialogComponent as b3, InspectorPaneHeaderComponent as b4, InspectorPanelComponent as b5, IsMobileService as b6, KeepAnnotationsDialogComponent as b7, LOCALE_CATALOG as b8, LONG_PRESS_DURATION_MS as b9, POWER_POINT_VIEWER_PROVIDERS as bA, PPTX_OPEN_ACCEPT as bB, PRESENTATION_OPEN_EXTENSIONS as bC, PRESENTER_CHANNEL_NAME as bD, PRESENTER_MSG_ORIGIN as bE, PRESENTER_TIMER_SEGMENT_MS as bF, PX_PER_CM as bG, PX_PER_INCH as bH, PasswordProtectionDialogComponent as bI, PasswordStrengthMeterComponent as bJ, PowerPointViewerComponent as bK, PresentToolbarAutoHide as bL, PresentationAnnotationOverlayComponent as bM, PresentationAnnotationsService as bN, PresentationOverlayComponent as bO, PresentationPropertiesPanelComponent as bP, PresentationSettingsCardComponent as bQ, PresentationSubtitleBarComponent as bR, PresentationToolbarComponent as bS, PresentationTransitionOverlayComponent as bT, PresenterViewComponent as bU, PresenterWindowService as bV, PrintDialogComponent as bW, PrintService as bX, PrintSettingsPanelComponent as bY, PropertiesDialogComponent as bZ, RANDOM_ELIGIBLE_TYPES as b_, LONG_PRESS_MOVE_TOLERANCE_PX as ba, LoadContentService as bb, LocalPresencePublisher as bc, MAX_ZOOM_SCALE as bd, MIN_ZOOM_SCALE as be, MOTION_PATH_COLUMNS as bf, MediaPreviewComponent as bg, MediaPropertiesPanelComponent as bh, MediaRendererComponent as bi, MediaTrimTimelineComponent as bj, MobileBottomBarComponent as bk, MobileMenuSheetComponent as bl, MobilePresenterViewComponent as bm, MobileSheetComponent as bn, MobileSlidesSheetComponent as bo, MobileToolbarComponent as bp, ModalDialogComponent as bq, Model3DRendererComponent as br, NotesHandoutCardComponent as bs, NotesPanelComponent as bt, NotesToolbarComponent as bu, OleRendererComponent as bv, OutlineViewOverlayComponent as bw, P14_TRANSITION_KEYFRAMES as bx, P14_TRANSITION_KEYFRAMES_2 as by, P14_TRANSITION_KEYFRAMES_ALL as bz, AUDIENCE_HASH as c, SlideSorterOverlayComponent as c$, RESIZE_HANDLES as c0, RULER_FONT_SIZE as c1, RULER_THICKNESS as c2, ReadingViewOverlayComponent as c3, RemoteSelectionOverlayComponent as c4, RibbonAnimationGalleryComponent as c5, RibbonAnimationsSectionComponent as c6, RibbonArrangeSectionComponent as c7, RibbonColorPopoverComponent as c8, RibbonComponent as c9, DEFAULT_PALETTE as cA, PALETTES$1 as cB, SMART_ART_COLOR_SCHEMES as cC, SMART_ART_STYLE_OPTIONS as cD, SUB_ITEM_LABEL as cE, SVG_WARP_PRESETS as cF, SWIPE_MAX_VERTICAL_PX as cG, SWIPE_THRESHOLD_PX as cH, SelectionPaneComponent as cI, SetUpSlideShowDialogComponent as cJ, SettingsAppearanceTabComponent as cK, SettingsDialogComponent as cL, SettingsLanguageTabComponent as cM, ShareDialogComponent as cN, ShortcutPanelComponent as cO, ShowOptionsFieldsetComponent as cP, ShowSlidesFieldsetComponent as cQ, SignatureStrippedDialogComponent as cR, SignaturesPanelComponent as cS, SignaturesService as cT, SlideBackgroundCardComponent as cU, SlideCanvasComponent as cV, SlideDefaultInspectorComponent as cW, SlideDiffChangesComponent as cX, SlideDiffRowComponent as cY, SlideDiffThumbnailsComponent as cZ, SlideSizeCardComponent as c_, RibbonDesignSectionComponent as ca, RibbonDrawSectionComponent as cb, RibbonDrawingGroupComponent as cc, RibbonEditingSectionComponent as cd, RibbonFileSectionComponent as ce, RibbonFontControlsComponent as cf, RibbonHomeSectionComponent as cg, RibbonHyperlinkButtonComponent as ch, RibbonInsertFieldsComponent as ci, RibbonInsertSectionComponent as cj, RibbonMotionPathGalleryComponent as ck, RibbonParagraphControlsComponent as cl, RibbonPrimaryRowComponent as cm, RibbonReviewSectionComponent as cn, RibbonShapeExtrasComponent as co, RibbonSlideshowSectionComponent as cp, RibbonTransitionsSectionComponent as cq, RibbonViewSectionComponent as cr, RulerGuidesService as cs, SEQUENCE_OPTIONS as ct, SEVERITY_GROUPS as cu, SEVERITY_LABELS as cv, DEFAULT_TRANSITION_DURATION_MS$1 as cw, SHORTCUT_REFERENCE_ITEMS as cx, SLIDE_TRANSITION_KEYFRAMES as cy, SLIDE_TRANSITION_KEYFRAMES_CSS as cz, AUDIENCE_NONCE_KEY as d, ZoomNavigationService as d$, SlideThemeOverridePanelComponent as d0, SlideTransitionCardComponent as d1, SlidesPanelComponent as d2, SmartArt3DRendererComponent as d3, SmartArt3DService as d4, SmartArtPreviewComponent as d5, SmartArtPropertiesComponent as d6, SmartArtRendererComponent as d7, StatusBarComponent as d8, TABLE_STRUCTURE_TOGGLES as d9, TransitionPreviewComponent as dA, VALIGN_OPTIONS as dB, VIEWER_THEME as dC, VersionHistoryPanelComponent as dD, ViewerCanvasEditingService as dE, ViewerCollabCursorService as dF, ViewerCollaborationSessionService as dG, ViewerCompareService as dH, ViewerCustomShowsService as dI, ViewerDialogsService as dJ, ViewerDocumentPropertiesService as dK, ViewerExportService as dL, ViewerExtraDialogsComponent as dM, ViewerFileIOService as dN, ViewerFindReplaceService as dO, ViewerFormatPainterService as dP, ViewerInspectorPanelService as dQ, ViewerKeyboardService as dR, ViewerMobileSheetService as dS, ViewerPresentationModeService as dT, ViewerThemeGalleryService as dU, ViewerTouchGesturesService as dV, ViewerZoomService as dW, WEBM_MIME_CANDIDATES as dX, WHEEL_SPOKE_COUNTS as dY, WriteBackScheduler as dZ, ZERO_LINE_COLOR as d_, TEXT_3D_BOTTOM_BEVEL_KEYS as da, TEXT_3D_TOP_BEVEL_KEYS as db, TEXT_DIRECTION_OPTIONS$1 as dc, THEME_CATALOG as dd, TIMING_CURVE_OPTIONS as de, TRANSITION_SPEED_DURATION_MS as df, TRIGGER_OPTIONS as dg, TYPE_LABELS as dh, TableCellAdvancedFillComponent as di, TableCellFormattingComponent as dj, TableDataEditorComponent as dk, TablePropertiesComponent as dl, TableRendererComponent as dm, TableResizeOverlayComponent as dn, TableSelectionService as dp, TagsCardComponent as dq, Text3DBevelSectionComponent as dr, Text3DPanelComponent as ds, TextAdvancedPanelComponent as dt, ThemeEditorFieldsComponent as du, ThemeGalleryComponent as dv, ThemeSelectorCardComponent as dw, TitleBarComponent as dx, TitleBarSearchComponent as dy, TransitionDirectionPickerComponent as dz, AVATAR_COLOR_SWATCHES as e, buildModel3DViewModel as e$, ZoomRendererComponent as e0, ZoomTargetService as e1, addCategory as e2, addCommentToList as e3, addGradientStopPatch as e4, addItem as e5, addSeries as e6, addSubItem as e7, advanceStep as e8, affordanceElements as e9, buildCellParagraphs as eA, buildChartViewModel as eB, buildChatLogExport as eC, buildChatLogMarkdown as eD, buildChromeStyle as eE, buildClearHyperlinkPatch as eF, buildClickGroups as eG, buildColStyles as eH, buildCollaborationConfig as eI, buildComboViewModel as eJ, buildCssGradientFromShapeStyle as eK, buildDuotoneFilter as eL, buildDuotoneFilterId as eM, buildEmbeddedFontStyles as eN, buildEquationElement as eO, buildEquationSegment as eP, buildFallbackViewModel as eQ, buildFontFaceRule as eR, buildGradientFillCss as eS, buildGridlinesAndLabels as eT, buildHyperlinkPatch as eU, buildInkContainerStyle as eV, buildInkStrokes as eW, buildLegend as eX, buildLiveInkStrokeView as eY, buildMarkTooltip as eZ, buildModel3DContainerStyle as e_, aiToggleVisible as ea, alignPatch as eb, animationFor as ec, animationPresetLabelKey as ed, annotationMapToInkInserts as ee, applyAcceptedDiff as ef, applyAnimationPreset as eg, applyFindReplacements as eh, applyFormatToElement as ei, applyMove as ej, applyResize as ek, asMediaElement as el, assignUserColor as em, attachShowVisibilityPause as en, attachTouchGestures as eo, axisTickValues as ep, beginDrawingNodeEdit as eq, beginNodeEdit as er, bevelSizePatch as es, boolFromEvent as et, bringForward as eu, bringToFront as ev, buildBarActions as ew, buildBroadcastConfig as ex, buildBroadcastViewerUrl as ey, buildCategoryLabels as ez, AXIS_LABEL_COLOR as f, computeErrorBarPrimitives as f$, buildOleActionModel as f0, buildOleInfoRows as f1, buildPatternFillCss as f2, buildPieViewModel as f3, buildPrintHtmlDocument as f4, buildPropertiesPatch as f5, buildRadarViewModel as f6, buildRegionMapViewModel as f7, buildSaveSlides as f8, buildShareUrl as f9, changeIcon as fA, characterSpacingPatch as fB, chartPreserveAspectRatio as fC, checkFontAvailable as fD, clampCursorPosition as fE, clampGifDimensions as fF, clampIndex as fG, clampNotesFontSize as fH, clampScale as fI, clampStep as fJ, clearAllLocalViewerData as fK, clearAudienceContent as fL, cn as fM, collectAccessibilityIssues as fN, collectElementText as fO, collectSlideText as fP, collectStoredChats as fQ, collectUsedFontFamilies as fR, columnWidthStyle as fS, commitNodeText as fT, computeAlign as fU, computeAxisTitlePrimitives as fV, computeBarRects as fW, computeBubbleRadius as fX, computeCornerHandle as fY, computeDistribute as fZ, computeDrawingViewBox as f_, buildSmartArtInsertElement as fa, buildSmartArtNodes as fb, buildStockViewModel as fc, buildSurfaceViewModel as fd, buildTableViewModel as fe, buildTreemapViewModel as ff, buildTrimFragment as fg, buildWaterfallViewModel as fh, buildZeroLine as fi, buildZoomContainerStyle as fj, buildZoomViewModel as fk, bulletIndentPx as fl, canAddTopLevelNode as fm, canEditSmartArtNodes as fn, canGroupSelection as fo, canRemoveTopLevelNode as fp, canSetStrokeWidth as fq, canStartBroadcast as fr, canStartShare as fs, canUngroupSelection as ft, canUseClipboard as fu, captionDisplayText as fv, cellRunStyle as fw, cellStyleToStyleMap as fx, cellTdStyle as fy, changeCountLabel as fz, AccessibilityPanelComponent as g, encodeGif as g$, computeFocusTargets as g0, computeGridSpacingPx as g1, computeHandleBoxes as g2, computeHandoutLayout as g3, computeIsMobile as g4, computeIsTablet as g5, computeLinePoints as g6, computeLinearRegression as g7, computePageCount as g8, computePieLayout as g9, createWebsocketBundle as gA, cssObjectToStyleMap as gB, currentColorScheme as gC, currentLayout as gD, currentStyle as gE, defaultCssVars as gF, defaultRadius as gG, defaultThemeColors as gH, deleteElementsByIds as gI, deleteVersion as gJ, demoteNode as gK, deriveModel3DBlobUrl as gL, derivePresenceList as gM, describeSmartArtBounds as gN, disableGlowPatch as gO, disableInnerShadowPatch as gP, disableOuterShadowPatch as gQ, disableReflectionPatch as gR, disableSoftEdgePatch as gS, duplicateElementById as gT, durationOf as gU, effectsStateOf as gV, enableGlowPatch as gW, enableInnerShadowPatch as gX, enableOuterShadowPatch as gY, enableReflectionPatch as gZ, enableSoftEdgePatch as g_, computePieSlicePath as ga, computePieSlices as gb, computePlotLayout as gc, computeRSquared as gd, computeRadarPoints as ge, computeResizeHandleBoxes as gf, computeRotateHandleBox as gg, computeScatterDots as gh, computeScatterXDomain as gi, computeSelectionBoxes as gj, computeSingleSelected as gk, computeSlideIndices as gl, computeSnap as gm, computeStackedBarRects as gn, computeStackedValueRange as go, computeTrendlinePrimitives as gp, computeValueRange as gq, convertOmmlToMathMl as gr, copyFormatFromElement as gs, countAccessibilityIssues as gt, countAnnotationStrokes as gu, createAngularAiBridge as gv, createCustomShow as gw, createImageElementFromFile as gx, createSwipeDismissDrag as gy, createWebrtcBundle as gz, AccessibilityService as h, gradientStateFromStyle as h$, endShowMediaCleanup as h0, estimatePageCount as h1, exitPresentationFullscreen as h2, exportAiChatLogs as h3, extractPathPoints as h4, eyedropperAvailable as h5, fillColorOf$1 as h6, findInSlides as h7, findOwningSlideIndex as h8, findSlideIndexByElementId as h9, getEffectSoundState as hA, getImageSrc as hB, getLocalStorageUsageSummary as hC, getOleAriaLabel as hD, getOleBadgeLabel as hE, getOleDisplayName as hF, getOleDownloadFileName as hG, getOleTypeColor as hH, getOleTypeLabel as hI, getP14TransitionAnimations as hJ, getPasswordStrength as hK, getPatternSvg as hL, getPlaceholderStyle as hM, getVersions as hN, getResolvedShapeClipPath as hO, getResolvedShapeClipPathFor as hP, getSessionTabId as hQ, getShapeFillStrokeStyle as hR, getSlideBackgroundStyle as hS, getSlideTransitionAnimations as hT, getSmartArtNodeBounds as hU, getSpeechRecognitionCtor as hV, getTextBlockStyle as hW, getTextWarp as hX, getTouchDistance as hY, getWarpCategory as hZ, getWarpPath as h_, firstVisibleIndex as ha, fitPolynomial as hb, fitZoom as hc, focusTargetChips as hd, fontMimeForFormat as he, fontSizeOf as hf, forgetSessionDeck as hg, formatAxisValue as hh, formatBytes as hi, formatCursorLabel as hj, formatElapsed as hk, formatFileSize as hl, formatInlineListStyle as hm, formatPropertyDate as hn, formatTime as ho, fpsToFrameIntervalMs as hp, generateBroadcastRoomId as hq, generateCommentId as hr, generateCustomShowId as hs, generatePressureCircles as ht, generateTicks as hu, getCinematicTransitionAnimations as hv, getClrChangeParams as hw, getContainerStyle as hx, getDuotoneFilterDef as hy, getEffectSoundAsset as hz, AccessibilityTextPanelComponent as i, narrowToRect as i$, gradientStateOf as i0, gradientStatePatch as i1, gradientStopColorCommitPatch as i2, gridColumns as i3, groupIssuesBySeverity as i4, hasAnimation as i5, hasCopyableFormat as i6, hasExistingLink as i7, hasExitedFullscreen as i8, hasGradientFill as i9, isValidRoomId as iA, isViewportBackgroundPressTarget as iB, isZoomActivationKey as iC, issueTrackKey as iD, issueTypeLabel as iE, keyToLabel as iF, lastVisibleIndex as iG, latexToMathml as iH, layoutConnectorPaints as iI, layoutNodeLabels as iJ, linePointsToSvgString as iK, lineSpacingPatch as iL, loadAudienceContent as iM, loadSessionDeck as iN, mediaFallbackFor as iO, mediaSurfaceFor as iP, mergeCaptionResults as iQ, mergeDown as iR, mergeRight as iS, mergeSelection as iT, mergeTablesDirective as iU, moveElementBy as iV, moveNodeDown as iW, moveNodeUp as iX, msToFrameDelayCs as iY, narrowToCircle as iZ, narrowToPolygon as i_, hasPressureVariation as ia, hasVisibleSlideAfter as ib, headerLabel as ic, imageDimensions as id, inkViewBox as ie, insertTableElementColumn as ig, insertTableElementRow as ih, interpolateWidth as ii, isAudienceTab as ij, isBold as ik, isBrowserOpenableMime as il, isChildNode as im, isElementInteractive as io, isInjectableUrl as ip, isItalic as iq, isLegacyBinaryPresentation as ir, isPpactionUrl as is, isPresenterMessage as it, isSigned as iu, isSupportedPresentationFile as iv, isTextElement as iw, isTwoTableFocus as ix, isUnderline as iy, isUrlSafe as iz, AccountPageComponent as j, removeNode as j$, newChartElement as j0, newEquationElement as j1, newPresetShapeElement as j2, newShapeElement as j3, newSmartArtElement as j4, newTableElement as j5, newTextElement as j6, nextVisibleIndex as j7, nodeBold as j8, nodeEditBox as j9, planGifFrames as jA, planVideoSegments as jB, pointFromPointerEvent as jC, pointsToSvgPathD as jD, presenceToCursors as jE, presentationBaseName as jF, presentationStageStyle as jG, presenterTimerProgress as jH, presetByLayout as jI, presetsForCategory as jJ, pressuresToWidths as jK, prevVisibleIndex as jL, projectDrawingShapes as jM, promoteNode as jN, provideViewerTheme as jO, radarAngle as jP, radarRingPoints as jQ, readAsDataUrl as jR, recordWebm as jS, registerCrossSlideAudio as jT, rememberSessionDeck as jU, removeAnimation as jV, removeCategory as jW, removeTableElementColumn as jX, removeCommentFromList as jY, removeElementAnimation as jZ, removeGradientStopPatch as j_, nodeFillColor as ja, nodeFontColor as jb, nodeIdFromKey as jc, nodeItalic as jd, nodeStyle as je, normalizeFontFormat as jf, normalizeSlidesPerPage as jg, normalizeValue as jh, numFromEvent as ji, ommlToMathml as jj, ooxmlDashToCssBorderStyle as jk, openNativeEyeDropper as jl, overallStatus as jm, paletteColor as jn, parseAudienceNonce as jo, parseNodeTextarea as jp, partitionSlides as jq, patchChartData as jr, patchChartStyle as js, patchTableData as jt, patchTextStyle as ju, patternPresetOptions as jv, pendingElementStyles as jw, pickColorByClickFallback as jx, pickFile as jy, pickSupportedMimeType as jz, ActionSettingsPanelComponent as k, setAxisLogScale as k$, removeTableElementRow as k0, removeSeries as k1, renderToCanvas as k2, reorderAnimationDown as k3, reorderAnimationUp as k4, replaceInSlides as k5, replaceMatch as k6, requestPresentationFullscreen as k7, resizeElement as k8, resolveCaptionTracks as k9, rulerHighlight as kA, rulerStripTicks as kB, sampleColorFromSlide as kC, sanitizeColor as kD, sanitizeSlideIndex as kE, sanitizeUserName as kF, saveViewerProfile as kG, savedPresentationFileName as kH, scanAvailableFonts as kI, searchSlides as kJ, seedBroadcastFields as kK, seedHyperlinkDraft as kL, seedPropertiesDraft as kM, seedShareFields as kN, segmentFrameCount as kO, selectValue$3 as kP, sendBackward as kQ, sendToBack as kR, sequentialColorScale as kS, serializeWriteBack as kT, seriesColor as kU, setAfterAnimation as kV, setAfterAnimationColor as kW, setAnimationEmphasis as kX, setAnimationEntrance as kY, setAnimationExit as kZ, setAxis as k_, resolveChartKind as ka, resolveDirection as kb, resolveDirection8 as kc, resolveFontVariant as kd, resolveHyperlinkHref as ke, resolveInteractiveElementId as kf, resolveMediaSrc as kg, resolveOleType as kh, resolveOrientation as ki, resolveParagraphBullet as kj, resolvePresenterNotes as kk, resolveProfileInitial as kl, resolveRegionCode as km, resolveRibbonCanGroup as kn, resolveSlideAutoAdvanceMs as ko, resolveSlideTransition as kp, resolvePalette as kq, resolveThemeCatalogEntry as kr, resolveTransitionDuration as ks, resolveTransitionDurationMs as kt, resolveWheelSpokeCount as ku, restoreSessionDeck as kv, revealedElementStyles as kw, routeOrthogonalConnector as kx, rowStyle as ky, rulerDragToGuidePosition as kz, AdvancedChartEditorComponent as l, textAdvancedStateFromStyle as l$, setAxisTitleStyle as l0, setCategoryLabel as l1, setCellText as l2, setColorScheme as l3, setDataLabels as l4, setDataPointExplosion as l5, setDataPointFill as l6, setDataPointLabel as l7, setDataPointMarker as l8, setDelay as l9, sheetAfterNavigate as lA, shouldBlockClickAdvance as lB, shouldUseSvgWarp as lC, showDirectionPicker as lD, showsTemplateAffordance as lE, signatureCountLabel as lF, signatureKey as lG, signatureTimestamp as lH, signerName as lI, statusLabel as lJ, slideNumberOf as lK, slidesWithReappliedLayout as lL, smartArtNodes as lM, paletteColour as lN, snapToGridStep as lO, splitCursorCell as lP, splitMergedCell as lQ, statusKind as lR, statusLabel$1 as lS, storeAudienceContent as lT, stringFromEvent$5 as lU, strokeColorOf as lV, strokeToInkElement as lW, strokeWidthOf as lX, styleShadowFilter as lY, surfaceColor as lZ, textAdvancedPatch as l_, setDirection as la, setDuration as lb, setEffectSound as lc, setEffectStockSound as ld, setElementPosition as le, setGridlineStyle as lf, setLayout as lg, setLegend as lh, setNodeStyle as li, setNodeText as lj, setRepeatCount as lk, setRepeatMode as ll, setSequence as lm, setSeriesChartType as ln, setSeriesColor as lo, setSeriesErrorBars as lp, setSeriesMarker as lq, setSeriesName as lr, setSeriesTrendline as ls, setSeriesValue as lt, setStyle as lu, setTimingCurve as lv, setTitle as lw, setTrigger as lx, setTriggerShapeId as ly, shapeStylePatch$1 as lz, AiChangeOverlayComponent as m, textAdvancedStateOf as m0, textColorOf as m1, textDirectionPatch as m2, textFontSizePatch as m3, textStyleOf as m4, textStylePatch as m5, themeStyle as m6, themeToCssVars as m7, thumbnailHeight as m8, thumbnailZoom as m9, zoomTargetSlideIndex as mA, toggleCommentResolvedInList as ma, toggleNodeBold as mb, toggleNodeItalic as mc, toggleSheet as md, topLevelNodeCount as me, transformSelectedTextCase as mf, translationsEn as mg, updateElementById as mh, updateGlowPatch as mi, updateGradientStopPatch as mj, updateInnerShadowPatch as mk, updateOuterShadowPatch as ml, updateReflectionPatch as mm, vAlignPatch as mn, validatePassword as mo, validatePrintSettings as mp, validateRoomId as mq, valueToY as mr, vermilionDarkColors as ms, vermilionDarkTheme as mt, vermilionLightColors as mu, vermilionLightTheme as mv, vermilionRadius as mw, waypointsToPathD as mx, withManualLayouts as my, worstStatus as mz, 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 };
186199
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-Di10-gYO.mjs.map
187019
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-De1uOCxq.mjs.map