pptx-angular-viewer 2.6.4 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24621,14 +24621,22 @@ function buildNotesPrintHtml(slides, slideLabel) {
24621
24621
  * export would make it ambiguous. Notes modules import it directly.
24622
24622
  */
24623
24623
 
24624
+ /**
24625
+ * PowerPoint's single-spacing line height as a unitless multiplier of the font
24626
+ * size. Measured against PowerPoint itself (COM `TextRange2.BoundHeight` on
24627
+ * the issue #131 deck): every single-spaced Arial paragraph lays out at
24628
+ * exactly 1.2x its point size (10.5pt -> 12.6pt, 10pt -> 12pt, 8pt -> 9.6pt),
24629
+ * and the browser default `normal` (~1.25 for Arial) accumulated a visible
24630
+ * vertical drift over a full text panel.
24631
+ */
24632
+ const DEFAULT_LINE_HEIGHT = 1.2;
24624
24633
  /**
24625
24634
  * Resolve a CSS `line-height` value from a TextStyle's spacing fields.
24626
24635
  *
24627
24636
  * - If `lineSpacingExactPt` is set (exact point mode from `a:lnSpc > a:spcPts`),
24628
24637
  * returns a fixed `"<n>pt"` string.
24629
24638
  * - Otherwise the proportional multiplier from `a:spcPct` (`lineSpacing`) is
24630
- * used, defaulting to `1.25` (or `1.35` when the block carries italics, which
24631
- * sit slightly taller).
24639
+ * used, defaulting to PowerPoint's single-spacing {@link DEFAULT_LINE_HEIGHT}.
24632
24640
  *
24633
24641
  * Returning a unitless multiplier (rather than relying on the browser's
24634
24642
  * font-dependent `normal`, which is ~1.2-1.5) lets the value scale with the
@@ -24636,14 +24644,17 @@ function buildNotesPrintHtml(slides, slideLabel) {
24636
24644
  *
24637
24645
  * @param textStyle The text style carrying the spacing fields (may be
24638
24646
  * `undefined`).
24639
- * @param hasItalicRuns Whether the block contains italic runs (loosens the
24640
- * default multiplier).
24647
+ * @param hasItalicRuns Whether the block contains italic runs. No longer
24648
+ * changes the default: PowerPoint does not add leading
24649
+ * for italics, and the old 1.35 bump pushed every italic
24650
+ * block visibly below its authored position.
24641
24651
  */
24642
24652
  function resolveLineHeight(textStyle, hasItalicRuns) {
24643
24653
  if (typeof textStyle?.lineSpacingExactPt === 'number' && textStyle.lineSpacingExactPt > 0) {
24644
24654
  return `${textStyle.lineSpacingExactPt}pt`;
24645
24655
  }
24646
- return textStyle?.lineSpacing || (hasItalicRuns ? 1.35 : 1.25);
24656
+ void hasItalicRuns;
24657
+ return textStyle?.lineSpacing || DEFAULT_LINE_HEIGHT;
24647
24658
  }
24648
24659
  /**
24649
24660
  * Map a parsed `textDirection` value to the corresponding CSS `writing-mode`.
@@ -24731,7 +24742,7 @@ function isVerticalTextDirection(textDirection) {
24731
24742
  * caller spreads the result over its own CSS object.
24732
24743
  */
24733
24744
  function computeAutoFitTextStyle(input) {
24734
- const { textStyle: ts, text, width, height, bodyInsetVertical, hasItalicRuns } = input;
24745
+ const { textStyle: ts, text, width, height, bodyInsetVertical } = input;
24735
24746
  if (!ts?.autoFit) {
24736
24747
  return {};
24737
24748
  }
@@ -24746,7 +24757,7 @@ function computeAutoFitTextStyle(input) {
24746
24757
  const textLength = text.length;
24747
24758
  const lineHeight = ts.lineSpacingExactPt
24748
24759
  ? ts.lineSpacingExactPt / baseFontSize
24749
- : ts.lineSpacing || (hasItalicRuns ? 1.35 : 1.25);
24760
+ : ts.lineSpacing || DEFAULT_LINE_HEIGHT;
24750
24761
  const approxCharsPerLine = Math.max(1, Math.floor(width / (baseFontSize * 0.6)));
24751
24762
  const estimatedLines = Math.max(1, Math.ceil(textLength / approxCharsPerLine));
24752
24763
  const requiredHeight = estimatedLines * baseFontSize * lineHeight;
@@ -24758,7 +24769,7 @@ function computeAutoFitTextStyle(input) {
24758
24769
  }
24759
24770
  // normAutofit with lnSpcReduction: reduce line height.
24760
24771
  if (ts.autoFitLineSpacingReduction !== undefined && ts.autoFitLineSpacingReduction > 0) {
24761
- const baseLineHeight = typeof ts.lineSpacing === 'number' ? ts.lineSpacing : hasItalicRuns ? 1.35 : 1.25;
24772
+ const baseLineHeight = typeof ts.lineSpacing === 'number' ? ts.lineSpacing : DEFAULT_LINE_HEIGHT;
24762
24773
  result.lineHeight = baseLineHeight * (1 - ts.autoFitLineSpacingReduction);
24763
24774
  }
24764
24775
  return result;
@@ -25897,15 +25908,21 @@ function buildParagraphs(element, fieldContext) {
25897
25908
  return element.text ? [{ runs: [{ text: element.text, style: {} }], bulletStyle: {} }] : [];
25898
25909
  }
25899
25910
  const paragraphIndents = element.paragraphIndents;
25900
- const grouped = [{ paraSegments: [] }];
25911
+ const grouped = [
25912
+ { paraSegments: [] },
25913
+ ];
25901
25914
  for (const seg of segments) {
25902
25915
  if (seg.isParagraphBreak || (seg.text === '\n' && !seg.isLineBreak)) {
25916
+ // Keep the separator: for an EMPTY paragraph it is the only carrier
25917
+ // of the authored `a:endParaRPr` style (core stamps its font size on
25918
+ // it), which sizes the blank line's box below.
25919
+ grouped[grouped.length - 1].terminator = seg;
25903
25920
  grouped.push({ paraSegments: [] });
25904
25921
  continue;
25905
25922
  }
25906
25923
  grouped[grouped.length - 1].paraSegments.push(seg);
25907
25924
  }
25908
- const result = grouped.map(({ paraSegments }, paraIndex) => {
25925
+ const result = grouped.map(({ paraSegments, terminator }, paraIndex) => {
25909
25926
  const firstSeg = paraSegments[0];
25910
25927
  const baseFontSize = firstSeg?.style?.fontSize ?? element.textStyle?.fontSize ?? 16;
25911
25928
  const bulletResult = resolveParagraphBullet(firstSeg, baseFontSize);
@@ -25969,6 +25986,11 @@ function buildParagraphs(element, fieldContext) {
25969
25986
  ? -indent.textIndentPx
25970
25987
  : undefined;
25971
25988
  bulletStyle.display = 'inline-block';
25989
+ // `text-indent` inherits, and an inline-block is a block container:
25990
+ // without this reset the marker box applies the paragraph's negative
25991
+ // first-line indent AGAIN internally and paints the glyph a full
25992
+ // hang-width left of its own box (outside the text inset).
25993
+ bulletStyle.textIndent = '0px';
25972
25994
  if (hangPx !== undefined) {
25973
25995
  bulletStyle.minWidth = `${hangPx}px`;
25974
25996
  }
@@ -25976,8 +25998,11 @@ function buildParagraphs(element, fieldContext) {
25976
25998
  bulletStyle.marginInlineEnd = '0.35em';
25977
25999
  }
25978
26000
  }
25979
- const spacing = resolveParagraphSpacing$1(firstSeg?.paragraphProperties);
25980
- const strutFontSizePx = resolveParagraphStrutFontSize(paraSegments, hasTextProperties(element) ? element.textStyle?.fontSize : undefined);
26001
+ // An empty paragraph's own `a:pPr` / `a:endParaRPr` ride its terminator
26002
+ // segment (there is no run to carry them), so read them from there.
26003
+ const propsCarrier = firstSeg ?? (paraSegments.length === 0 ? terminator : undefined);
26004
+ const spacing = resolveParagraphSpacing$1(propsCarrier?.paragraphProperties);
26005
+ const strutFontSizePx = resolveParagraphStrutFontSize(paraSegments.length > 0 ? paraSegments : terminator ? [terminator] : [], hasTextProperties(element) ? element.textStyle?.fontSize : undefined);
25981
26006
  return {
25982
26007
  runs,
25983
26008
  bulletMarker: bullet?.picture?.src ? undefined : bullet?.marker,
@@ -26467,6 +26492,101 @@ function generateGeometryMorphAnimation(pair, durationMs, pairIndex, steps = GEO
26467
26492
  };
26468
26493
  }
26469
26494
 
26495
+ /**
26496
+ * Decompose groups that take part in a morph, so a `!!`-named shape can be
26497
+ * matched across a grouping boundary.
26498
+ *
26499
+ * PowerPoint's `!!` naming convention pairs two shapes for Morph by name alone,
26500
+ * wherever they sit in the shape tree: a shape can be top-level on one slide
26501
+ * and nested inside a group on the next, and PowerPoint still carries it
26502
+ * through as one continuing object. Our matcher only ever saw a slide's
26503
+ * TOP-LEVEL elements, so such a pair never matched and both halves faded
26504
+ * instead (issue #131: the wheel deck keeps its centre as a bare shape on the
26505
+ * overview slide and wraps the identical artwork in a `!!Circle` group on every
26506
+ * topic slide).
26507
+ *
26508
+ * A group is decomposed only when it CONTAINS a `!!`-named descendant, which is
26509
+ * the deck author's explicit signal that its contents take part in the morph.
26510
+ * Every other group is left whole, so ordinary grouped artwork keeps animating
26511
+ * as a single unit exactly as before.
26512
+ *
26513
+ * Decomposed children are returned with ABSOLUTE slide coordinates, because
26514
+ * that is the space every downstream geometry calculation (deltas, proximity,
26515
+ * same-box) works in. A binding renders group children as absolutely positioned
26516
+ * boxes inside the group's own box, and the group carries no extra scale, so a
26517
+ * translation delta in slide space is also correct inside the group - which is
26518
+ * what lets the incoming half animate the child's own node in place.
26519
+ *
26520
+ * @module render/morph-flatten
26521
+ */
26522
+ /** Children of `element` when it is a group, else `undefined`. */
26523
+ function groupChildren(element) {
26524
+ if (element.type !== 'group') {
26525
+ return undefined;
26526
+ }
26527
+ const children = element.children;
26528
+ return Array.isArray(children) && children.length > 0 ? children : undefined;
26529
+ }
26530
+ /** Whether `element` or any descendant carries a `!!` morph name. */
26531
+ function containsMorphNamedDescendant(element) {
26532
+ const children = groupChildren(element);
26533
+ if (!children) {
26534
+ return false;
26535
+ }
26536
+ for (const child of children) {
26537
+ if (getElementMorphName(child) !== undefined || containsMorphNamedDescendant(child)) {
26538
+ return true;
26539
+ }
26540
+ }
26541
+ return false;
26542
+ }
26543
+ /**
26544
+ * Re-express a group child in absolute slide coordinates.
26545
+ *
26546
+ * Group children are stored relative to their group's box origin, already in
26547
+ * the group's rendered scale, so an absolute position is the running sum of the
26548
+ * ancestors' origins.
26549
+ */
26550
+ function toAbsolute(child, offsetX, offsetY) {
26551
+ if (offsetX === 0 && offsetY === 0) {
26552
+ return child;
26553
+ }
26554
+ return { ...child, x: child.x + offsetX, y: child.y + offsetY };
26555
+ }
26556
+ /**
26557
+ * The elements of `elements` that a morph should treat as individual units.
26558
+ *
26559
+ * Groups holding a `!!`-named descendant are replaced by their children (in
26560
+ * document order, recursively, in absolute coordinates); everything else is
26561
+ * passed through untouched.
26562
+ */
26563
+ function flattenMorphElements(elements, offsetX = 0, offsetY = 0) {
26564
+ const out = [];
26565
+ for (const element of elements) {
26566
+ const children = groupChildren(element);
26567
+ if (children && containsMorphNamedDescendant(element)) {
26568
+ out.push(...flattenMorphElements(children, offsetX + element.x, offsetY + element.y));
26569
+ continue;
26570
+ }
26571
+ out.push(toAbsolute(element, offsetX, offsetY));
26572
+ }
26573
+ return out;
26574
+ }
26575
+ /**
26576
+ * True when `elements` holds a group that {@link flattenMorphElements} would
26577
+ * decompose. Lets a caller skip the copy entirely for the overwhelmingly common
26578
+ * case of a slide with no `!!`-named group content.
26579
+ */
26580
+ function needsMorphFlattening(elements) {
26581
+ return elements.some((element) => containsMorphNamedDescendant(element));
26582
+ }
26583
+
26584
+ /**
26585
+ * Tolerance (px, slide coordinates) within which two boxes count as identical
26586
+ * for the same-box pass. Sub-pixel only: this pass ignores element type, so it
26587
+ * must never absorb a shape that merely sits close by.
26588
+ */
26589
+ const SAME_BOX_TOLERANCE_PX = 0.5;
26470
26590
  // ---------------------------------------------------------------------------
26471
26591
  // Element name extraction
26472
26592
  // ---------------------------------------------------------------------------
@@ -26502,6 +26622,51 @@ function getElementMorphName(element) {
26502
26622
  return undefined;
26503
26623
  }
26504
26624
  // ---------------------------------------------------------------------------
26625
+ // Creation identity (`a16:creationId`)
26626
+ // ---------------------------------------------------------------------------
26627
+ /** Non-visual property containers a `p:cNvPr` can live under, per element kind. */
26628
+ const NV_PR_KEYS = [
26629
+ 'p:nvSpPr',
26630
+ 'p:nvPicPr',
26631
+ 'p:nvGrpSpPr',
26632
+ 'p:nvCxnSpPr',
26633
+ 'p:nvGraphicFramePr',
26634
+ ];
26635
+ /**
26636
+ * The shape's `a16:creationId` GUID from its preserved raw XML
26637
+ * (`p:cNvPr/a:extLst/a:ext/a16:creationId/@id`), or `undefined`.
26638
+ *
26639
+ * This is the identity PowerPoint itself tracks across slides: duplicating a
26640
+ * slide copies each shape's creationId, so equal GUIDs mean "the same shape,
26641
+ * possibly moved/restyled" with none of the ambiguity of the numeric
26642
+ * `p:cNvPr/@id` (which is just a per-slide counter that independently
26643
+ * authored slides reuse for unrelated shapes).
26644
+ */
26645
+ function getElementCreationId(element) {
26646
+ const raw = element.rawXml;
26647
+ if (!raw) {
26648
+ return undefined;
26649
+ }
26650
+ for (const nvKey of NV_PR_KEYS) {
26651
+ const nvPr = raw[nvKey];
26652
+ const cNvPr = nvPr?.['p:cNvPr'];
26653
+ const extLst = cNvPr?.['a:extLst'];
26654
+ const extRaw = extLst?.['a:ext'];
26655
+ if (!extRaw) {
26656
+ continue;
26657
+ }
26658
+ const exts = Array.isArray(extRaw) ? extRaw : [extRaw];
26659
+ for (const ext of exts) {
26660
+ const creation = ext?.['a16:creationId'];
26661
+ const guid = creation?.['@_id'];
26662
+ if (typeof guid === 'string' && guid.length > 0) {
26663
+ return guid;
26664
+ }
26665
+ }
26666
+ }
26667
+ return undefined;
26668
+ }
26669
+ // ---------------------------------------------------------------------------
26505
26670
  // Match elements between slides
26506
26671
  // ---------------------------------------------------------------------------
26507
26672
  /**
@@ -26509,8 +26674,9 @@ function getElementMorphName(element) {
26509
26674
  *
26510
26675
  * Matching passes (in priority order):
26511
26676
  * 1. Explicit !! naming convention (element name from cNvPr/@name, or text content)
26512
- * 2. Element ID matching (same `id` on both slides)
26513
- * 3. Type + proximity matching (same type within 300px euclidean distance)
26677
+ * 2a. `a16:creationId` GUID (PowerPoint's own cross-slide shape identity)
26678
+ * 2b. Native shape id from `p:cNvPr/@id` (only when creationIds are absent)
26679
+ * 3. Type + proximity + size matching (same type within 300px, similar box)
26514
26680
  *
26515
26681
  * Returns only matched pairs (no unmatched elements).
26516
26682
  *
@@ -26533,13 +26699,20 @@ function matchMorphElementsFull(fromSlide, toSlide) {
26533
26699
  const pairs = [];
26534
26700
  const usedFrom = new Set();
26535
26701
  const usedTo = new Set();
26702
+ // A group holding a `!!`-named shape is decomposed into its children (in
26703
+ // absolute coordinates) so that shape can be paired across the grouping
26704
+ // boundary, which is what the `!!` convention is for. Groups without such a
26705
+ // descendant - the overwhelming majority - stay whole and animate as one
26706
+ // unit exactly as before. See `morph-flatten`.
26707
+ const fromElements = flattenMorphElements(fromSlide.elements);
26708
+ const toElements = flattenMorphElements(toSlide.elements);
26536
26709
  // Pass 1: match by !! naming convention
26537
- for (const fromEl of fromSlide.elements) {
26710
+ for (const fromEl of fromElements) {
26538
26711
  const fromName = getElementMorphName(fromEl);
26539
26712
  if (!fromName) {
26540
26713
  continue;
26541
26714
  }
26542
- for (const toEl of toSlide.elements) {
26715
+ for (const toEl of toElements) {
26543
26716
  if (usedTo.has(toEl.id)) {
26544
26717
  continue;
26545
26718
  }
@@ -26552,23 +26725,66 @@ function matchMorphElementsFull(fromSlide, toSlide) {
26552
26725
  }
26553
26726
  }
26554
26727
  }
26555
- // Pass 2: match by the shape's native OOXML id (`p:cNvPr/@id`), which
26556
- // PowerPoint preserves when a slide is duplicated and is what it pairs on.
26728
+ // Pass 2a: match by `a16:creationId` GUID - the identity PowerPoint itself
26729
+ // preserves when a slide (or shape) is duplicated, and the strongest
26730
+ // "same shape" signal available. Equal GUIDs pair regardless of position,
26731
+ // which is exactly what a morph is for.
26732
+ const creationIds = new Map();
26733
+ const creationIdOf = (el) => {
26734
+ if (!creationIds.has(el.id)) {
26735
+ creationIds.set(el.id, getElementCreationId(el));
26736
+ }
26737
+ return creationIds.get(el.id);
26738
+ };
26739
+ for (const fromEl of fromElements) {
26740
+ if (usedFrom.has(fromEl.id)) {
26741
+ continue;
26742
+ }
26743
+ const fromGuid = creationIdOf(fromEl);
26744
+ if (!fromGuid) {
26745
+ continue;
26746
+ }
26747
+ for (const toEl of toElements) {
26748
+ if (usedTo.has(toEl.id) || fromEl.type !== toEl.type) {
26749
+ continue;
26750
+ }
26751
+ if (creationIdOf(toEl) === fromGuid) {
26752
+ pairs.push({ fromElement: fromEl, toElement: toEl });
26753
+ usedFrom.add(fromEl.id);
26754
+ usedTo.add(toEl.id);
26755
+ break;
26756
+ }
26757
+ }
26758
+ }
26759
+ // Pass 2b: match by the shape's native OOXML id (`p:cNvPr/@id`) - a
26760
+ // fallback for decks whose producer emits no creationIds.
26557
26761
  //
26558
26762
  // This deliberately does NOT compare `element.id`: that is the loader's
26559
26763
  // synthetic identity and embeds the slide path
26560
26764
  // (`ppt/slides/slide3.xml-shape-1`), so it can never be equal across two
26561
26765
  // slides and the pass was dead code. `shapeId` is only unique WITHIN a
26562
26766
  // slide, hence the `usedFrom`/`usedTo` guards below.
26563
- for (const fromEl of fromSlide.elements) {
26767
+ //
26768
+ // When BOTH shapes carry creationIds and pass 2a did not pair them, their
26769
+ // GUIDs differ: they are provably NOT the same object, and the numeric id
26770
+ // coinciding is an authoring accident. The issue #131 wheel deck reuses
26771
+ // the same ids AND names for DIFFERENT wedges on different topic slides
26772
+ // (shifted by one spTree position), and id-pairing there sent every wedge
26773
+ // and label gliding one sector around the wheel - the reporter's "phantom
26774
+ // arrow to another selected item". Such shapes must fall through to the
26775
+ // proximity pass (which pairs the same-position counterparts) instead.
26776
+ for (const fromEl of fromElements) {
26564
26777
  if (usedFrom.has(fromEl.id) || !fromEl.shapeId) {
26565
26778
  continue;
26566
26779
  }
26567
- for (const toEl of toSlide.elements) {
26780
+ for (const toEl of toElements) {
26568
26781
  if (usedTo.has(toEl.id)) {
26569
26782
  continue;
26570
26783
  }
26571
26784
  if (toEl.shapeId && fromEl.shapeId === toEl.shapeId && fromEl.type === toEl.type) {
26785
+ if (creationIdOf(fromEl) && creationIdOf(toEl)) {
26786
+ continue;
26787
+ }
26572
26788
  pairs.push({ fromElement: fromEl, toElement: toEl });
26573
26789
  usedFrom.add(fromEl.id);
26574
26790
  usedTo.add(toEl.id);
@@ -26588,13 +26804,13 @@ function matchMorphElementsFull(fromSlide, toSlide) {
26588
26804
  // selection marker mid-glide. Same-shaped counterparts pass at ratio 1;
26589
26805
  // anything more than 2x apart on either axis dissolves in place instead,
26590
26806
  // which is what PowerPoint does with shapes it cannot confidently pair.
26591
- for (const fromEl of fromSlide.elements) {
26807
+ for (const fromEl of fromElements) {
26592
26808
  if (usedFrom.has(fromEl.id)) {
26593
26809
  continue;
26594
26810
  }
26595
26811
  let bestMatch = null;
26596
26812
  let bestDist = Infinity;
26597
- for (const toEl of toSlide.elements) {
26813
+ for (const toEl of toElements) {
26598
26814
  if (usedTo.has(toEl.id)) {
26599
26815
  continue;
26600
26816
  }
@@ -26620,9 +26836,39 @@ function matchMorphElementsFull(fromSlide, toSlide) {
26620
26836
  usedTo.add(bestMatch.id);
26621
26837
  }
26622
26838
  }
26839
+ // Pass 4: pair leftovers that occupy the EXACT same box, even across element
26840
+ // types. A deck often restructures the same visual between slides - the
26841
+ // issue #131 wheel keeps its centre as a bare shape on one slide and wraps
26842
+ // the identical artwork in a group on the others - and PowerPoint carries
26843
+ // that through as one continuing object. Left unmatched, the two halves
26844
+ // fade out and in independently, so the middle of the transition showed the
26845
+ // background straight through a disc that should stay solid.
26846
+ //
26847
+ // The box must agree on all four numbers (within a sub-pixel tolerance),
26848
+ // which is a far stricter test than the proximity pass and cannot pull in a
26849
+ // merely nearby shape.
26850
+ for (const fromEl of fromElements) {
26851
+ if (usedFrom.has(fromEl.id)) {
26852
+ continue;
26853
+ }
26854
+ for (const toEl of toElements) {
26855
+ if (usedTo.has(toEl.id)) {
26856
+ continue;
26857
+ }
26858
+ if (Math.abs(fromEl.x - toEl.x) <= SAME_BOX_TOLERANCE_PX &&
26859
+ Math.abs(fromEl.y - toEl.y) <= SAME_BOX_TOLERANCE_PX &&
26860
+ Math.abs(fromEl.width - toEl.width) <= SAME_BOX_TOLERANCE_PX &&
26861
+ Math.abs(fromEl.height - toEl.height) <= SAME_BOX_TOLERANCE_PX) {
26862
+ pairs.push({ fromElement: fromEl, toElement: toEl });
26863
+ usedFrom.add(fromEl.id);
26864
+ usedTo.add(toEl.id);
26865
+ break;
26866
+ }
26867
+ }
26868
+ }
26623
26869
  // Collect unmatched elements
26624
- const unmatchedFrom = fromSlide.elements.filter((el) => !usedFrom.has(el.id));
26625
- const unmatchedTo = toSlide.elements.filter((el) => !usedTo.has(el.id));
26870
+ const unmatchedFrom = fromElements.filter((el) => !usedFrom.has(el.id));
26871
+ const unmatchedTo = toElements.filter((el) => !usedTo.has(el.id));
26626
26872
  return { pairs, unmatchedFrom, unmatchedTo };
26627
26873
  }
26628
26874
 
@@ -27083,17 +27329,25 @@ function generateMorphAnimations(pairs, durationMs, _mode = 'object') {
27083
27329
  // instead of `rotate(from)->rotate(to)`, sweeping giant arcs across the
27084
27330
  // slide. Flips use the incoming element's, stated after the rotation to
27085
27331
  // match the static order (right-to-left: flip first, then rotate).
27086
- const fromRot = fromElement.rotation ?? 0;
27332
+ // Animate FROM an equivalent start angle that reaches the element's own
27333
+ // authored rotation over the shorter arc; the `to` frame must keep the
27334
+ // authored value so the element lands exactly on its static transform.
27087
27335
  const toRot = toElement.rotation ?? 0;
27336
+ const fromRot = shortestRotationTarget(toRot, fromElement.rotation ?? 0);
27088
27337
  const flips = `${toElement.flipHorizontal ? ' scaleX(-1)' : ''}${toElement.flipVertical ? ' scaleY(-1)' : ''}`;
27089
- // A pair whose appearance changes fades IN over its outgoing ghost (see
27090
- // `generateMorphGhostAnimations`); one that only moves stays fully
27091
- // opaque so the glide reads as a single continuous object.
27092
- const crossfades = morphPairNeedsCrossfade(fromElement, toElement);
27338
+ // A restyled pair dissolves via its outgoing GHOST, which is painted in
27339
+ // the overlay directly above this element and fades 1 -> 0 (see
27340
+ // `generateMorphGhostAnimations`). This half therefore has to stay at its
27341
+ // final opacity for the whole flight: fading it IN as well left both
27342
+ // layers part-transparent in the middle of the transition, so the
27343
+ // background showed straight through what should be a solid object and
27344
+ // both states were legible at once (issue #131: the wheel's centre disc
27345
+ // went see-through mid-morph where PowerPoint keeps it solid and only
27346
+ // dissolves the content on top of it).
27093
27347
  // Build from/to property blocks
27094
27348
  const fromProps = [
27095
27349
  `\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${fromRot}deg)${flips};`,
27096
- `\t\topacity: ${crossfades ? 0 : fromOpacity};`,
27350
+ `\t\topacity: ${fromOpacity};`,
27097
27351
  ];
27098
27352
  const toProps = [
27099
27353
  `\t\ttransform: translate(0, 0) scale(1, 1) rotate(${toRot}deg)${flips};`,
@@ -27166,8 +27420,10 @@ function generateMorphGhostAnimations(pairs, durationMs, startIndex) {
27166
27420
  const dy = toElement.y + toElement.height / 2 - (fromElement.y + fromElement.height / 2);
27167
27421
  const sx = Math.max(toElement.width, 1) / Math.max(fromElement.width, 1);
27168
27422
  const sy = Math.max(toElement.height, 1) / Math.max(fromElement.height, 1);
27423
+ // The ghost starts on its own authored rotation, so the SHORTEST-arc
27424
+ // adjustment goes on the target angle here (mirror of the incoming half).
27169
27425
  const fromRot = fromElement.rotation ?? 0;
27170
- const toRot = toElement.rotation ?? 0;
27426
+ const toRot = shortestRotationTarget(fromRot, toElement.rotation ?? 0);
27171
27427
  const flips = `${fromElement.flipHorizontal ? ' scaleX(-1)' : ''}${fromElement.flipVertical ? ' scaleY(-1)' : ''}`;
27172
27428
  const keyframes = `
27173
27429
  @keyframes ${safeName} {
@@ -27190,6 +27446,31 @@ function generateMorphGhostAnimations(pairs, durationMs, startIndex) {
27190
27446
  }
27191
27447
  return animations;
27192
27448
  }
27449
+ /**
27450
+ * The target angle to animate TO so the element turns the short way round.
27451
+ *
27452
+ * CSS interpolates `rotate(a)` -> `rotate(b)` numerically, so a pair authored
27453
+ * at 315deg and 0deg spins -315deg (almost a full turn anti-clockwise) when
27454
+ * the shapes are only 45deg apart. PowerPoint always takes the shorter arc.
27455
+ * Returns `fromDeg` plus the delta wrapped into (-180, 180], which is the same
27456
+ * final orientation modulo 360 but the rotation a viewer expects: the issue
27457
+ * #131 deck's wheel points its arrow at the selected wedge by rotating a ring
27458
+ * in 45deg steps, so clicking the neighbouring wedge sent the arrow the long
27459
+ * way around the dial.
27460
+ *
27461
+ * A half turn is ambiguous; +180 (clockwise) is chosen so the direction is at
27462
+ * least deterministic.
27463
+ */
27464
+ function shortestRotationTarget(fromDeg, toDeg) {
27465
+ let delta = (toDeg - fromDeg) % 360;
27466
+ if (delta > 180) {
27467
+ delta -= 360;
27468
+ }
27469
+ else if (delta <= -180) {
27470
+ delta += 360;
27471
+ }
27472
+ return fromDeg + delta;
27473
+ }
27193
27474
  /**
27194
27475
  * Restated static transform suffix (`rotate(N) scaleX(-1) scaleY(-1)`) for an
27195
27476
  * element. Keyframe `transform`s REPLACE the container's static transform, so
@@ -27378,7 +27659,14 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = 'object
27378
27659
  // Element ids embed their slide path, so the two id spaces do not overlap,
27379
27660
  // but partitioning on this set (rather than on id shape) keeps that an
27380
27661
  // implementation detail of core rather than an assumption here.
27381
- const outgoingElements = [...fromSlide.elements];
27662
+ //
27663
+ // The list is FLATTENED the same way the matcher flattens it (see
27664
+ // `morph-flatten`): a group holding a `!!`-named shape is decomposed into
27665
+ // its children in absolute coordinates, and the animations are keyed by
27666
+ // those children's ids. Painting the undecomposed group here instead would
27667
+ // paint the children twice over - once inside the group, once as their own
27668
+ // ghosts - and leave the group itself without an animation.
27669
+ const outgoingElements = flattenMorphElements(fromSlide.elements);
27382
27670
  const outgoingIds = new Set(outgoingElements.map((element) => element.id));
27383
27671
  const incomingAnimations = new Map();
27384
27672
  const outgoingAnimations = new Map();
@@ -32162,11 +32450,28 @@ const INSTANT = {
32162
32450
  */
32163
32451
  const DEFAULT_TRANSITION_DURATION_MS$1 = 1000;
32164
32452
  /**
32165
- * Default Morph duration (ms). PowerPoint's Morph defaults to 2.00s and does
32166
- * not honour the legacy `spd` speed for it; an authored override arrives as
32167
- * `p14:dur` and lands in `durationMs`, which always wins over this.
32453
+ * Default Morph duration (ms) for a transition that declares NEITHER an
32454
+ * explicit `p14:dur` (which lands in `durationMs` and always wins) NOR a legacy
32455
+ * `spd` speed (see {@link TRANSITION_SPEED_DURATION_MS}). Applying Morph in the
32456
+ * PowerPoint UI writes an explicit duration, so this only covers decks that
32457
+ * declare nothing at all.
32168
32458
  */
32169
32459
  const DEFAULT_MORPH_DURATION_MS = 2000;
32460
+ /**
32461
+ * Duration (ms) for each legacy `p:transition/@spd` speed.
32462
+ *
32463
+ * Measured against PowerPoint itself: the issue #131 deck's morph slides carry
32464
+ * `spd="slow"` and no `p14:dur`, and PowerPoint reports
32465
+ * `SlideShowTransition.Duration = 1.0`. Re-authoring that attribute and
32466
+ * re-reading it through COM gives fast=0.5s, med=0.75s, slow=1.0s - and the
32467
+ * same values for Morph as for every other effect, contradicting the earlier
32468
+ * assumption that Morph ignores `spd`.
32469
+ */
32470
+ const TRANSITION_SPEED_DURATION_MS = {
32471
+ fast: 500,
32472
+ med: 750,
32473
+ slow: 1000,
32474
+ };
32170
32475
  /** Easing applied to every transition animation. */
32171
32476
  const EASE = 'ease-in-out';
32172
32477
 
@@ -33592,10 +33897,15 @@ function resolveTransitionDurationMs(transition) {
33592
33897
  if (typeof transition.durationMs === 'number' && transition.durationMs > 0) {
33593
33898
  return transition.durationMs;
33594
33899
  }
33595
- // PowerPoint's Morph defaults to 2.00s and IGNORES the legacy `spd`
33596
- // attribute for it (the real override lives in `p14:dur`, which core parses
33597
- // into `durationMs` when present). Playing morphs at the generic 1s default
33598
- // made every dissolve feel abrupt next to PowerPoint (issue #131).
33900
+ // The legacy `spd` speed is the next authority, for EVERY effect including
33901
+ // Morph. Verified against PowerPoint via COM (see
33902
+ // `TRANSITION_SPEED_DURATION_MS`): the issue #131 deck's morphs declare
33903
+ // `spd="slow"` and no `p14:dur`, and PowerPoint plays them at 1.0s - we were
33904
+ // playing them at 2.0s, so every transition in that deck ran at half speed.
33905
+ const speedMs = transition.speed ? TRANSITION_SPEED_DURATION_MS[transition.speed] : undefined;
33906
+ if (typeof speedMs === 'number') {
33907
+ return speedMs;
33908
+ }
33599
33909
  if (transition.type === 'morph') {
33600
33910
  return DEFAULT_MORPH_DURATION_MS;
33601
33911
  }
@@ -52739,7 +53049,7 @@ function createLocalStorageBackend(namespace) {
52739
53049
  /** Try IndexedDB first; fall back to localStorage on any failure. */
52740
53050
  async function resolveBackend(dbName, namespace) {
52741
53051
  try {
52742
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-Cp9Q8WVA.mjs');
53052
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BfgImFmE.mjs');
52743
53053
  const db = await openChatDb(dbName);
52744
53054
  return createIdbBackend(db);
52745
53055
  }
@@ -68827,6 +69137,30 @@ class ElementRendererComponent {
68827
69137
  // paragraph, so only its first line got a bullet and every authored
68828
69138
  // blank line vanished (issue #131). Mirrors shared `buildParagraphs`.
68829
69139
  if (seg.isParagraphBreak || (seg.text === '\n' && !seg.isLineBreak)) {
69140
+ // An EMPTY paragraph (`paraStarted` still false) has no run to carry
69141
+ // its authored size or spacing: both ride this TERMINATING separator,
69142
+ // where core stamps the paragraph's `a:endParaRPr sz`. Read them off
69143
+ // it, or the blank line lays out on the body default and the error
69144
+ // accumulates down the panel (issue #131: Angular alone drifted
69145
+ // ~7px by the last heading of slide 13). Mirrors shared
69146
+ // `buildParagraphs`.
69147
+ if (!paraStarted) {
69148
+ const closing = out[out.length - 1];
69149
+ const endParaSize = seg.style?.fontSize;
69150
+ if (typeof endParaSize === 'number' && endParaSize > 0) {
69151
+ closing.strutFontSizePx = endParaSize;
69152
+ }
69153
+ const endSpacing = resolveParagraphSpacing(seg.paragraphProperties);
69154
+ if (endSpacing.lineHeight !== undefined) {
69155
+ closing.lineHeight = endSpacing.lineHeight;
69156
+ }
69157
+ if (endSpacing.spaceBeforePx !== undefined) {
69158
+ closing.spaceBeforePx = endSpacing.spaceBeforePx;
69159
+ }
69160
+ if (endSpacing.spaceAfterPx !== undefined) {
69161
+ closing.spaceAfterPx = endSpacing.spaceAfterPx;
69162
+ }
69163
+ }
68830
69164
  out.push({ runs: [], bulletStyle: {}, indentPx: 0 });
68831
69165
  paraStarted = false;
68832
69166
  continue;
@@ -85377,7 +85711,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.8", ngImpor
85377
85711
  }], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
85378
85712
 
85379
85713
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
85380
- const PPTX_ANGULAR_VIEWER_VERSION = "2.6.3";
85714
+ const PPTX_ANGULAR_VIEWER_VERSION = "2.6.6";
85381
85715
 
85382
85716
  /**
85383
85717
  * account-page.component.ts: File > Account content.
@@ -114231,4 +114565,4 @@ function cn(...values) {
114231
114565
  */
114232
114566
 
114233
114567
  export { DATA_TABLE_KEY_W as $, ALIGN_OPTIONS as A, BroadcastDialogComponent as B, CHART_EDITOR_STYLES as C, ChartAxisOptionsComponent as D, ChartAxisStyleOptionsComponent as E, ChartComboTypeOptionsComponent as F, ChartDataEditorComponent as G, ChartDataLabelOptionsComponent as H, ChartDatapointOptionsComponent as I, ChartDisplayOptionsComponent as J, ChartElementViewComponent as K, ChartErrorBarOptionsComponent as L, ChartMarkerOptionsComponent as M, ChartPartSelectionService as N, ChartPrimitivesComponent as O, ChartRendererComponent as P, ChartTrendlineOptionsComponent as Q, CollaborationCursorsComponent as R, CollaborationService as S, ColorChangedImageComponent as T, CommentsPanelComponent as U, CommentsService as V, ComparePanelComponent as W, ConnectorRendererComponent as X, ConnectorTextOverlayComponent as Y, CustomShowsComponent as Z, DATA_TABLE_HEADER_H as _, AUDIENCE_HASH as a, MIN_ZOOM_SCALE as a$, DATA_TABLE_PADDING as a0, DATA_TABLE_ROW_H as a1, DEFAULT_BOUNDS as a2, DEFAULT_BROADCAST_SERVER_URL as a3, DEFAULT_CANVAS_HEIGHT as a4, DEFAULT_CANVAS_WIDTH as a5, DEFAULT_COLOR_SCHEME as a6, DEFAULT_FILL_COLOR as a7, DEFAULT_LAYOUT as a8, DEFAULT_PALETTE$1 as a9, ExportProgressModalComponent as aA, ExportService as aB, FieldContextService as aC, FindBarComponent as aD, FindReplaceBarComponent as aE, FollowModeBarComponent as aF, FontEmbeddingListComponent as aG, FontEmbeddingPanelComponent as aH, GALLERY_THEME_PRESETS as aI, GradientPickerComponent as aJ, HANDOUT_OPTIONS as aK, HeaderFooterDialogComponent as aL, HyperlinkDialogComponent as aM, ImagePropertiesPanelComponent as aN, InkDrawingService as aO, InkRendererComponent as aP, InsertSmartArtDialogComponent as aQ, InspectorPaneHeaderComponent as aR, InspectorPanelComponent as aS, IsMobileService as aT, KeepAnnotationsDialogComponent as aU, LOCALE_CATALOG as aV, LONG_PRESS_DURATION_MS as aW, LONG_PRESS_MOVE_TOLERANCE_PX as aX, LoadContentService as aY, LocalPresencePublisher as aZ, MAX_ZOOM_SCALE as a_, DEFAULT_PRINT_SETTINGS as aa, DEFAULT_SLIDE_BACKGROUND as ab, DEFAULT_STROKE_COLOR as ac, DEFAULT_STYLE as ad, DEFAULT_TABLE_ROW_HEIGHT as ae, DEFAULT_TEXT_COLOR$1 as af, DEFAULT_VIEWER_PROFILE as ag, DIRECTIONAL_PRESETS as ah, DIRECTION_OPTIONS as ai, DocumentPropertiesCardComponent as aj, EMBEDDED_FONTS_STYLE_ID as ak, EMPHASIS_PRESETS as al, ENTRANCE_PRESETS as am, TEMPLATES as an, EXIT_PRESETS as ao, EditorContextMenuComponent as ap, EditorHistory as aq, EditorStateService as ar, EditorToolbarComponent as as, EffectsPanelComponent as at, ElementRendererComponent as au, EmbeddedFontsService as av, EncryptedFileDialogComponent as aw, EquationEditorDialogComponent as ax, EquationRendererComponent as ay, EquationTemplateGalleryComponent as az, AUDIENCE_NONCE_KEY as b, SLIDE_PX_PER_INCH as b$, MediaPreviewComponent as b0, MediaPropertiesPanelComponent as b1, MediaRendererComponent as b2, MediaTrimTimelineComponent as b3, MobileBottomBarComponent as b4, MobileMenuSheetComponent as b5, MobilePresenterViewComponent as b6, MobileSheetComponent as b7, MobileSlidesSheetComponent as b8, MobileToolbarComponent as b9, RESIZE_HANDLES as bA, RULER_THICKNESS as bB, RemoteSelectionOverlayComponent as bC, RibbonAnimationsSectionComponent as bD, RibbonArrangeSectionComponent as bE, RibbonColorPopoverComponent as bF, RibbonComponent as bG, RibbonDesignSectionComponent as bH, RibbonDrawSectionComponent as bI, RibbonDrawingGroupComponent as bJ, RibbonEditingSectionComponent as bK, RibbonFileSectionComponent as bL, RibbonFontControlsComponent as bM, RibbonHomeSectionComponent as bN, RibbonInsertFieldsComponent as bO, RibbonInsertSectionComponent as bP, RibbonParagraphControlsComponent as bQ, RibbonPrimaryRowComponent as bR, RibbonReviewSectionComponent as bS, RibbonSlideshowSectionComponent as bT, RibbonTransitionsSectionComponent as bU, RibbonViewSectionComponent as bV, RulerGuidesService as bW, SEQUENCE_OPTIONS as bX, SEVERITY_GROUPS as bY, SEVERITY_LABELS as bZ, SHORTCUT_REFERENCE_ITEMS as b_, ModalDialogComponent as ba, Model3DRendererComponent as bb, NotesHandoutCardComponent as bc, NotesPanelComponent as bd, NotesToolbarComponent as be, OleRendererComponent as bf, POWER_POINT_VIEWER_PROVIDERS as bg, PRESENTER_CHANNEL_NAME as bh, PRESENTER_MSG_ORIGIN as bi, PasswordProtectionDialogComponent as bj, PasswordStrengthMeterComponent as bk, PowerPointViewerComponent as bl, PresentationAnnotationOverlayComponent as bm, PresentationAnnotationsService as bn, PresentationOverlayComponent as bo, PresentationPropertiesPanelComponent as bp, PresentationSettingsCardComponent as bq, PresentationSubtitleBarComponent as br, PresentationTransitionOverlayComponent as bs, PresenterViewComponent as bt, PresenterWindowService as bu, PrintDialogComponent as bv, PrintService as bw, PrintSettingsPanelComponent as bx, PropertiesDialogComponent as by, REPEAT_MODE_OPTIONS as bz, AVATAR_COLOR_SWATCHES as c, ViewerDocumentPropertiesService as c$, SLIDE_TRANSITION_KEYFRAMES as c0, DEFAULT_PALETTE as c1, PALETTES$1 as c2, SMART_ART_COLOR_SCHEMES as c3, SMART_ART_STYLE_OPTIONS as c4, SUB_ITEM_LABEL as c5, SVG_WARP_PRESETS as c6, SWIPE_MAX_VERTICAL_PX as c7, SWIPE_THRESHOLD_PX as c8, SelectionPaneComponent as c9, TABLE_STRUCTURE_TOGGLES as cA, TEXT_DIRECTION_OPTIONS$1 as cB, THEME_CATALOG as cC, TIMING_CURVE_OPTIONS as cD, TRIGGER_OPTIONS as cE, TYPE_LABELS as cF, TableCellAdvancedFillComponent as cG, TableCellFormattingComponent as cH, TableDataEditorComponent as cI, TablePropertiesComponent as cJ, TableRendererComponent as cK, TableResizeOverlayComponent as cL, TableSelectionService as cM, TextAdvancedPanelComponent as cN, ThemeEditorFieldsComponent as cO, ThemeGalleryComponent as cP, ThemeSelectorCardComponent as cQ, TitleBarComponent as cR, VALIGN_OPTIONS as cS, VIEWER_THEME as cT, VersionHistoryPanelComponent as cU, ViewerCanvasEditingService as cV, ViewerCollabCursorService as cW, ViewerCollaborationSessionService as cX, ViewerCompareService as cY, ViewerCustomShowsService as cZ, ViewerDialogsService as c_, SetUpSlideShowDialogComponent as ca, SettingsAppearanceTabComponent as cb, SettingsDialogComponent as cc, SettingsLanguageTabComponent as cd, ShareDialogComponent as ce, ShortcutPanelComponent as cf, ShowOptionsFieldsetComponent as cg, ShowSlidesFieldsetComponent as ch, SignatureStrippedDialogComponent as ci, SignaturesPanelComponent as cj, SignaturesService as ck, SlideCanvasComponent as cl, SlideDefaultInspectorComponent as cm, SlideDiffChangesComponent as cn, SlideDiffRowComponent as co, SlideDiffThumbnailsComponent as cp, SlideSizeCardComponent as cq, SlideSorterOverlayComponent as cr, SlideThemeOverridePanelComponent as cs, SlidesPanelComponent as ct, SmartArt3DRendererComponent as cu, SmartArt3DService as cv, SmartArtPreviewComponent as cw, SmartArtPropertiesComponent as cx, SmartArtRendererComponent as cy, StatusBarComponent as cz, AccessibilityPanelComponent as d, buildFallbackViewModel as d$, ViewerExportService as d0, ViewerExtraDialogsComponent as d1, ViewerFileIOService as d2, ViewerFindReplaceService as d3, ViewerFormatPainterService as d4, ViewerInspectorPanelService as d5, ViewerKeyboardService as d6, ViewerMobileSheetService as d7, ViewerPresentationModeService as d8, ViewerThemeGalleryService as d9, asMediaElement as dA, assignUserColor as dB, attachTouchGestures as dC, beginNodeEdit as dD, boolFromEvent as dE, bringForward as dF, bringToFront as dG, buildBarActions as dH, buildBroadcastConfig as dI, buildBroadcastViewerUrl as dJ, buildCategoryLabels as dK, buildCellParagraphs as dL, buildChartViewModel as dM, buildChatLogExport as dN, buildChatLogMarkdown as dO, buildChromeStyle as dP, buildClearHyperlinkPatch as dQ, buildClickGroups as dR, buildColStyles as dS, buildCollaborationConfig as dT, buildComboViewModel as dU, buildCssGradientFromShapeStyle as dV, buildDuotoneFilter as dW, buildDuotoneFilterId as dX, buildEmbeddedFontStyles as dY, buildEquationElement as dZ, buildEquationSegment as d_, ViewerTouchGesturesService as da, ViewerZoomService as db, WEBM_MIME_CANDIDATES as dc, WriteBackScheduler as dd, ZoomNavigationService as de, ZoomRendererComponent as df, ZoomTargetService as dg, addCategory as dh, addCommentToList as di, addGradientStopPatch as dj, addItem as dk, addSeries as dl, addSubItem as dm, advanceStep as dn, aiToggleVisible as dp, alignPatch as dq, animationFor as dr, annotationMapToInkInserts as ds, applyAcceptedDiff as dt, applyAnimationPreset as du, applyFindReplacements as dv, applyFormatToElement as dw, applyMove as dx, applyResize as dy, applyTableStylePreset as dz, AccessibilityService as e, computeDataTablePrimitives as e$, buildFontFaceRule as e0, buildGradientFillCss as e1, buildGridlinesAndLabels as e2, buildHyperlinkPatch as e3, buildInkContainerStyle as e4, buildInkStrokes as e5, buildLegend as e6, buildModel3DContainerStyle as e7, buildModel3DViewModel as e8, buildOleActionModel as e9, cellStyleToStyleMap as eA, cellTdStyle as eB, changeCountLabel as eC, changeIcon as eD, characterSpacingPatch as eE, checkFontAvailable as eF, clampCursorPosition as eG, clampGifDimensions as eH, clampIndex as eI, clampNotesFontSize as eJ, clampScale as eK, clampStep as eL, clearAllLocalViewerData as eM, clearAudienceContent as eN, cn as eO, collectAccessibilityIssues as eP, collectElementText as eQ, collectSlideText as eR, collectStoredChats as eS, collectUsedFontFamilies as eT, columnWidthStyle as eU, commitNodeText as eV, computeAlign as eW, computeAxisTitlePrimitives as eX, computeBarRects as eY, computeBubbleRadius as eZ, computeCornerHandle as e_, buildOleInfoRows as ea, buildPatternFillCss as eb, buildPrintHtmlDocument as ec, buildPropertiesPatch as ed, buildRegionMapViewModel as ee, buildSaveSlides as ef, buildShareUrl as eg, buildSmartArtInsertElement as eh, buildSmartArtNodes as ei, buildStockViewModel as ej, buildSurfaceViewModel as ek, buildTableViewModel as el, buildTreemapViewModel as em, buildTrimFragment as en, buildWaterfallViewModel as eo, buildZeroLine as ep, buildZoomContainerStyle as eq, buildZoomViewModel as er, bulletIndentPx as es, canAddTopLevelNode as et, canRemoveTopLevelNode as eu, canStartBroadcast as ev, canStartShare as ew, canUseClipboard as ex, captionDisplayText as ey, cellRunStyle as ez, AccountPageComponent as f, encodeGif as f$, computeDistribute as f0, computeDrawingViewBox as f1, computeErrorBarPrimitives as f2, computeFocusTargets as f3, computeHandleBoxes as f4, computeHandoutLayout as f5, computeIsMobile as f6, computeIsTablet as f7, computeLinePoints as f8, computeLinearRegression as f9, createWebsocketBundle as fA, cssObjectToStyleMap as fB, currentColorScheme as fC, currentLayout as fD, currentStyle as fE, defaultCssVars as fF, defaultRadius as fG, defaultThemeColors as fH, deleteElementsByIds as fI, deleteVersion as fJ, demoteNode as fK, deriveModel3DBlobUrl as fL, derivePresenceList as fM, describeSmartArtBounds as fN, disableGlowPatch as fO, disableInnerShadowPatch as fP, disableOuterShadowPatch as fQ, disableReflectionPatch as fR, disableSoftEdgePatch as fS, duplicateElementById as fT, durationOf as fU, effectsStateOf as fV, enableGlowPatch as fW, enableInnerShadowPatch as fX, enableOuterShadowPatch as fY, enableReflectionPatch as fZ, enableSoftEdgePatch as f_, computePageCount as fa, computePieLayout as fb, computePieSlicePath as fc, computePieSlices as fd, computePlotLayout as fe, computeRSquared as ff, computeRadarPoints as fg, computeScatterDots as fh, computeSelectionBoxes as fi, computeSingleSelected as fj, computeSlideIndices as fk, computeSnap as fl, computeStackedBarRects as fm, computeStackedValueRange as fn, computeTextLines as fo, computeTimerProgress as fp, computeTrendlinePrimitives as fq, computeValueRange as fr, convertOmmlToMathMl as fs, copyFormatFromElement as ft, countAccessibilityIssues as fu, countAnnotationStrokes as fv, createAngularAiBridge as fw, createCustomShow as fx, createSwipeDismissDrag as fy, createWebrtcBundle as fz, ActionSettingsPanelComponent as g, hasAnimation as g$, estimatePageCount as g0, evenColumnWidths as g1, evenRowHeights as g2, exitPresentationFullscreen as g3, exportAiChatLogs as g4, extractPathPoints as g5, eyedropperAvailable as g6, fillColorOf as g7, findInSlides as g8, findOwningSlideIndex as g9, getOleBadgeLabel as gA, getOleDisplayName as gB, getOleDownloadFileName as gC, getOleTypeColor as gD, getOleTypeLabel as gE, getPasswordStrength as gF, getPatternSvg as gG, getPlaceholderStyle as gH, getVersions as gI, getResolvedShapeClipPath as gJ, getResolvedShapeClipPathFor as gK, getShapeFillStrokeStyle as gL, getSlideBackgroundStyle as gM, getSlideTransitionAnimations as gN, getSmartArtNodeBounds as gO, getSpeechRecognitionCtor as gP, getTextBlockStyle as gQ, getTextWarp as gR, getTouchDistance as gS, getWarpCategory as gT, getWarpPath as gU, gradientStateFromStyle as gV, gradientStateOf as gW, gradientStatePatch as gX, gridColumns as gY, groupElements as gZ, groupIssuesBySeverity as g_, findSlideIndexByElementId as ga, fitPolynomial as gb, fitZoom as gc, focusTargetChips as gd, fontMimeForFormat as ge, fontSizeOf as gf, formatAutoNumber as gg, formatAxisValue as gh, formatBytes as gi, formatCursorLabel as gj, formatElapsed as gk, formatFileSize as gl, formatPropertyDate as gm, formatTime as gn, fpsToFrameIntervalMs as go, generateBroadcastRoomId as gp, generateCommentId as gq, generateCustomShowId as gr, generatePressureCircles as gs, generateRulerTicks as gt, getClrChangeParams as gu, getContainerStyle as gv, getDuotoneFilterDef as gw, getImageSrc as gx, getLocalStorageUsageSummary as gy, getOleAriaLabel as gz, AdvancedChartEditorComponent as h, normalizeValue as h$, hasCopyableFormat as h0, hasExistingLink as h1, hasExitedFullscreen as h2, hasGradientFill as h3, hasPressureVariation as h4, hasVisibleSlideAfter as h5, headerLabel as h6, inkViewBox as h7, insertColumn as h8, insertRow as h9, mergeDown as hA, mergeRight as hB, mergeSelection as hC, moveElementBy as hD, moveNodeDown as hE, moveNodeUp as hF, msToFrameDelayCs as hG, narrowToCircle as hH, narrowToPolygon as hI, narrowToRect as hJ, newChartElement as hK, newEquationElement as hL, newPresetShapeElement as hM, newShapeElement as hN, newSmartArtElement as hO, newTableElement as hP, newTextElement as hQ, nextVisibleIndex as hR, nodeBold as hS, nodeEditBox as hT, nodeFillColor as hU, nodeFontColor as hV, nodeIdFromKey as hW, nodeItalic as hX, nodeStyle as hY, normalizeFontFormat as hZ, normalizeSlidesPerPage as h_, interpolateWidth as ha, isAudienceTab as hb, isBold as hc, isBrowserOpenableMime as hd, isChildNode as he, isElementInteractive as hf, isInjectableUrl as hg, isItalic as hh, isPpactionUrl as hi, isPresenterMessage as hj, isSigned as hk, isTextElement as hl, isTwoTableFocus as hm, isUnderline as hn, isUrlSafe as ho, isValidRoomId as hp, isViewportBackgroundPressTarget as hq, isZoomActivationKey as hr, issueTrackKey as hs, issueTypeLabel as ht, keyToLabel as hu, latexToMathml as hv, linePointsToSvgString as hw, lineSpacingPatch as hx, loadAudienceContent as hy, mergeCaptionResults as hz, AiChangeOverlayComponent as i, revealedElementStyles as i$, numFromEvent as i0, ommlToMathml as i1, ooxmlDashToCssBorderStyle as i2, openNativeEyeDropper as i3, overallStatus as i4, paletteColor as i5, parseAudienceNonce as i6, parseNodeTextarea as i7, partitionSlides as i8, patchChartData as i9, removeCommentFromList as iA, removeElementAnimation as iB, removeGradientStopPatch as iC, removeNode as iD, removeRow as iE, removeSeries as iF, renderToCanvas as iG, reorderAnimationDown as iH, reorderAnimationUp as iI, replaceInSlides as iJ, replaceMatch as iK, requestPresentationFullscreen as iL, resizeElement as iM, resolveCaptionTracks as iN, resolveChartKind as iO, resolveFontVariant as iP, resolveHyperlinkHref as iQ, resolveInteractiveElementId as iR, resolveMediaSrc as iS, resolveOleType as iT, resolveParagraphBullet as iU, resolvePresenterNotes as iV, resolveProfileInitial as iW, resolveRegionCode as iX, resolvePalette as iY, resolveThemeCatalogEntry as iZ, resolveTransitionDuration as i_, patchChartStyle as ia, patchTableData as ib, patchTextStyle as ic, pendingElementStyles as id, pickColorByClickFallback as ie, pickSupportedMimeType as ig, planGifFrames as ih, planVideoSegments as ii, pointsToSvgPathD as ij, presenceToCursors as ik, presetByLayout as il, presetsForCategory as im, pressuresToWidths as io, prevVisibleIndex as ip, projectDrawingShapes as iq, promoteNode as ir, provideViewerTheme as is, radarAngle as it, radarRingPoints as iu, recordWebm as iv, redistributeColumnWidth as iw, removeAnimation as ix, removeCategory as iy, removeColumn as iz, AiChatPanelComponent as j, signatureCountLabel as j$, routeOrthogonalConnector as j0, rowStyle as j1, sampleColorFromSlide as j2, sanitizeColor as j3, sanitizeSlideIndex as j4, sanitizeUserName as j5, saveViewerProfile as j6, scanAvailableFonts as j7, searchSlides as j8, seedBroadcastFields as j9, setElementPosition as jA, setGridlineStyle as jB, setLayout as jC, setLegend as jD, setNodeStyle as jE, setNodeText as jF, setRepeatCount as jG, setRepeatMode as jH, setSequence as jI, setSeriesChartType as jJ, setSeriesColor as jK, setSeriesErrorBars as jL, setSeriesMarker as jM, setSeriesName as jN, setSeriesTrendline as jO, setSeriesValue as jP, setStyle as jQ, setTimingCurve as jR, setTitle as jS, setTrigger as jT, setTriggerShapeId as jU, shapeStylePatch as jV, sheetAfterNavigate as jW, shouldBlockClickAdvance as jX, shouldUseSvgWarp as jY, showDirectionPicker as jZ, showsTemplateAffordance as j_, seedHyperlinkDraft as ja, seedPropertiesDraft as jb, seedShareFields as jc, segmentFrameCount as jd, selectValue$2 as je, sendBackward as jf, sendToBack as jg, sequentialColorScale as jh, serializeWriteBack as ji, seriesColor as jj, setAnimationEmphasis as jk, setAnimationEntrance as jl, setAnimationExit as jm, setAxis as jn, setAxisLogScale as jo, setAxisTitleStyle as jp, setCategoryLabel as jq, setCellText as jr, setColorScheme as js, setDataLabels as jt, setDataPointExplosion as ju, setDataPointFill as jv, setDataPointLabel as jw, setDelay as jx, setDirection as jy, setDuration as jz, AiChatService as k, signatureKey as k0, signatureTimestamp as k1, signerName as k2, statusLabel as k3, slideNumberOf as k4, smartArtNodes as k5, paletteColour as k6, snapToGridStep as k7, splitCursorCell as k8, splitMergedCell as k9, updateElementById as kA, updateGlowPatch as kB, updateGradientStopPatch as kC, updateInnerShadowPatch as kD, updateOuterShadowPatch as kE, updateReflectionPatch as kF, vAlignPatch as kG, validatePassword as kH, validatePrintSettings as kI, validateRoomId as kJ, valueToY as kK, vermilionDarkColors as kL, vermilionDarkTheme as kM, vermilionLightColors as kN, vermilionLightTheme as kO, vermilionRadius as kP, waypointsToPathD as kQ, worstStatus as kR, zoomTargetSlideIndex as kS, statusKind as ka, statusLabel$1 as kb, storeAudienceContent as kc, stringFromEvent$5 as kd, strokeColorOf as ke, strokeToInkElement as kf, styleShadowFilter as kg, textAdvancedPatch as kh, textAdvancedStateFromStyle as ki, textAdvancedStateOf as kj, textColorOf as kk, textDirectionPatch as kl, textStyleOf as km, textStylePatch as kn, themeStyle as ko, themeToCssVars as kp, thumbnailHeight as kq, thumbnailZoom as kr, toggleCommentResolvedInList as ks, toggleNodeBold as kt, toggleNodeItalic as ku, toggleSheet as kv, topLevelNodeCount as kw, transformSelectedTextCase as kx, translationsEn as ky, ungroupElements as kz, AiComposerComponent as l, AiFocusBarComponent as m, AiFocusHighlightOverlayComponent as n, AiMessageListComponent as o, AiPanelStore as p, AiProposalCardComponent as q, AiSettingsSectionComponent as r, AiToolCallCardComponent as s, toChatSummary as t, AnimationAuthorPanelComponent as u, AnimationPanelComponent as v, AnimationPlaybackService as w, AutosaveService as x, CURSOR_PALETTE as y, CanvasFitService as z };
114234
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-B080JvFb.mjs.map
114568
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-CuYqPeQk.mjs.map