pptx-angular-viewer 3.17.0 → 3.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,7 +2,7 @@ import { NgStyle, NgTemplateOutlet, NgClass } from '@angular/common';
2
2
  import * as i0 from '@angular/core';
3
3
  import { InjectionToken, input, output, inject, computed, ChangeDetectionStrategy, Component, signal, Injectable, DestroyRef, viewChild, effect, Injector, untracked, ElementRef, HostListener, afterNextRender, Renderer2, ViewEncapsulation, forwardRef, Directive, linkedSignal } from '@angular/core';
4
4
  import { TranslateService, TranslatePipe, translate } from '@ngx-translate/core';
5
- import { THEME_PRESETS, guideEmuToPx, evaluateCustomGeometryPathData, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, evaluateCustomGeometryPaths, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, evaluateGuides, deobfuscateFont, detectFontFormat, stripXmlOrderSuffix, orderedXmlKey, parseDataUrlToBytes, sampleFirstPixelColorFromBytes, flattenChartUserShapes, chartDataChangeType, isParetoChartData, resolveDisplayedChartTypeName, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, resolveThemeColorRef, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, DEFAULT_POWERPOINT_TABLE_STYLE_ID, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, formatAutoNumberMarker, createAutoNumberSequence, nextAutoNumber, breakAutoNumberRun, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, getPresetConnectionSites, resolveCustomGeometryToken, resolveCustomGeometryGuideContext, lookupPresetShape, normalizeStShapeType, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, createEditorId, makeStoreAwareId, reassignDescendantIds, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, THEME_COLOR_PALETTE_COLUMNS, hexToRgbChannels as hexToRgbChannels$2, rgbToHsl as rgbToHsl$1, renameSlideMaster, deleteSlideMaster, duplicateSlideMaster, insertSlideMaster, renameLayout, deleteLayout, duplicateLayout, insertLayout, detectFileFormat, cloneElement, duplicateElement, resolveModifyVerifierAlgorithmName, verifyModifyPassword, TABLE_STYLE_PART_SEQUENCE, serializePptxToJson, PPTX_JSON_MIME_TYPE, PptxMarkdownConverter, ThemePresets, formatCommentTimestamp as formatCommentTimestamp$1, EncryptedFileError, decodeXmlEntities, parseSignatureXml, groupElements, ungroupElements, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, isZoomElement, SvgExporter, applyThemeToData, reResolveElementColors, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointMarker, setChartDataPointExplosion, getOleSheetGrid, getOleDocumentParagraphs, getOleNestedDeckDetail, applyOleSheetCellEdit, applyOleDocumentParagraphEdit, applyOleNestedDeckElementTextEdit, replaceOleFile, getOleObjectTypeLabel, addSmartArtNodeAsChild, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, TRANSITION_VALID_DIRECTIONS } from 'pptx-viewer-core';
5
+ import { THEME_PRESETS, guideEmuToPx, evaluateCustomGeometryPathData, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, evaluateCustomGeometryPaths, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, evaluateGuides, deobfuscateFont, detectFontFormat, stripXmlOrderSuffix, orderedXmlKey, parseDataUrlToBytes, sampleFirstPixelColorFromBytes, flattenChartUserShapes, chartDataChangeType, isParetoChartData, resolveDisplayedChartTypeName, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, resolveThemeColorRef, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, DEFAULT_POWERPOINT_TABLE_STYLE_ID, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, formatAutoNumberMarker, createAutoNumberSequence, nextAutoNumber, breakAutoNumberRun, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, getPresetConnectionSites, getConnectorPathGeometry, resolveCustomGeometryToken, resolveCustomGeometryGuideContext, lookupPresetShape, normalizeStShapeType, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, createEditorId, makeStoreAwareId, reassignDescendantIds, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, THEME_COLOR_PALETTE_COLUMNS, hexToRgbChannels as hexToRgbChannels$2, rgbToHsl as rgbToHsl$1, renameSlideMaster, deleteSlideMaster, duplicateSlideMaster, insertSlideMaster, renameLayout, deleteLayout, duplicateLayout, insertLayout, detectFileFormat, cloneElement, duplicateElement, resolveModifyVerifierAlgorithmName, verifyModifyPassword, TABLE_STYLE_PART_SEQUENCE, serializePptxToJson, PPTX_JSON_MIME_TYPE, PptxMarkdownConverter, ThemePresets, formatCommentTimestamp as formatCommentTimestamp$1, EncryptedFileError, decodeXmlEntities, parseSignatureXml, groupElements, ungroupElements, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, isZoomElement, SvgExporter, applyThemeToData, reResolveElementColors, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointMarker, setChartDataPointExplosion, getOleSheetGrid, getOleDocumentParagraphs, getOleNestedDeckDetail, applyOleSheetCellEdit, applyOleDocumentParagraphEdit, applyOleNestedDeckElementTextEdit, replaceOleFile, getOleObjectTypeLabel, addSmartArtNodeAsChild, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, normalizeTableStyleGuid, createTableStyleEntry, addTableStyleToMap, deleteTableStyleFromMap, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, TRANSITION_VALID_DIRECTIONS } from 'pptx-viewer-core';
6
6
  import { parse } from 'opentype.js';
7
7
  import DOMPurify from 'dompurify';
8
8
  import { z } from 'zod';
@@ -51117,8 +51117,19 @@ const LOCALE_CATALOG = [
51117
51117
  { code: 'fr', label: 'French', nativeLabel: 'Français' },
51118
51118
  { code: 'es', label: 'Spanish', nativeLabel: 'Español' },
51119
51119
  { code: 'de', label: 'German', nativeLabel: 'Deutsch' },
51120
+ { code: 'zh-CN', label: 'Chinese (Simplified)', nativeLabel: '简体中文' },
51120
51121
  ];
51121
51122
 
51123
+ /** Complete action labels keep direction enums out of translated sentences. */
51124
+ const ALIGNMENT_LABEL_KEYS = {
51125
+ left: 'pptx.ribbon.alignLeft',
51126
+ center: 'pptx.ribbon.alignCenter',
51127
+ right: 'pptx.ribbon.alignRight',
51128
+ top: 'pptx.ribbon.alignTop',
51129
+ middle: 'pptx.ribbon.alignMiddle',
51130
+ bottom: 'pptx.ribbon.alignBottom',
51131
+ };
51132
+
51122
51133
  /**
51123
51134
  * slide-template-helpers.ts: element factory helpers for slide templates.
51124
51135
  *
@@ -52409,6 +52420,7 @@ function paragraphBulletKind(paragraph) {
52409
52420
  const resolved = resolveParagraphBullet(paragraph[0]);
52410
52421
  return resolved ? (resolved.isNumbered ? 'numbered' : 'bullet') : 'none';
52411
52422
  }
52423
+ /** Copy of `style` without the inert `listType` flag. */
52412
52424
  function withoutListType(style) {
52413
52425
  const next = { ...style };
52414
52426
  delete next.listType;
@@ -52425,7 +52437,7 @@ function markerText(info) {
52425
52437
  }
52426
52438
  function infoForParagraph(previous, kind, ordinal) {
52427
52439
  if (kind === 'none') {
52428
- return { ...previous, none: true };
52440
+ return { none: true };
52429
52441
  }
52430
52442
  const sameKind = previous &&
52431
52443
  (kind === 'numbered'
@@ -52510,29 +52522,46 @@ function elementSegments(element) {
52510
52522
  { text, style: { ...element.textStyle } },
52511
52523
  ]);
52512
52524
  }
52513
- function splitParagraphs(segments) {
52514
- const paragraphs = [
52515
- { segments: [] },
52516
- ];
52517
- for (const segment of segments) {
52525
+ /** Split a segment list into paragraphs, keeping each paragraph's terminator. */
52526
+ function splitBulletParagraphs(segments) {
52527
+ const paragraphs = [{ segments: [], indices: [] }];
52528
+ for (const [index, segment] of segments.entries()) {
52518
52529
  if (isParagraphSeparatorSegment(segment)) {
52519
52530
  paragraphs[paragraphs.length - 1].terminator = segment;
52520
- paragraphs.push({ segments: [] });
52531
+ paragraphs.push({ segments: [], indices: [] });
52521
52532
  }
52522
52533
  else {
52523
52534
  paragraphs[paragraphs.length - 1].segments.push(segment);
52535
+ paragraphs[paragraphs.length - 1].indices.push(index);
52524
52536
  }
52525
52537
  }
52526
52538
  return paragraphs;
52527
52539
  }
52528
- /** Existing element-wide toggle convention: use its first nonempty paragraph. */
52529
- function elementBulletKind(element) {
52530
- for (const paragraph of splitParagraphs(elementSegments(element))) {
52531
- if (paragraph.segments.length) {
52532
- return paragraphBulletKind(paragraph.segments);
52540
+ /** The segments a list operation acts on, optionally from a live inline edit. */
52541
+ function resolveBulletSegments(element, override) {
52542
+ if (override?.length) {
52543
+ return [...override];
52544
+ }
52545
+ return elementSegments(element);
52546
+ }
52547
+ /** The common list state of non-empty paragraphs, or `'mixed'`. */
52548
+ function paragraphsBulletKind(paragraphs) {
52549
+ let kind;
52550
+ for (const paragraph of paragraphs) {
52551
+ if (paragraph.segments.length === 0) {
52552
+ continue;
52553
+ }
52554
+ const current = paragraphBulletKind(paragraph.segments);
52555
+ if (kind !== undefined && kind !== current) {
52556
+ return 'mixed';
52533
52557
  }
52558
+ kind = current;
52534
52559
  }
52535
- return 'none';
52560
+ return kind ?? 'none';
52561
+ }
52562
+ /** The list state an element's ribbon buttons should show. */
52563
+ function elementBulletKind(element) {
52564
+ return paragraphsBulletKind(splitBulletParagraphs(resolveBulletSegments(element)));
52536
52565
  }
52537
52566
  /**
52538
52567
  * Explicitly set the touched paragraphs. Existing same-kind definitions survive;
@@ -52550,7 +52579,7 @@ function setElementBullets(element, kind, range) {
52550
52579
  range.endParagraph < range.startParagraph)) {
52551
52580
  return {};
52552
52581
  }
52553
- const paragraphs = splitParagraphs(elementSegments(element));
52582
+ const paragraphs = splitBulletParagraphs(elementSegments(element));
52554
52583
  if (range && range.startParagraph >= paragraphs.length) {
52555
52584
  return {};
52556
52585
  }
@@ -52599,6 +52628,293 @@ function toggleElementBullets(element, kind) {
52599
52628
  return setElementBullets(element, elementBulletKind(element) === kind ? 'none' : kind);
52600
52629
  }
52601
52630
 
52631
+ /**
52632
+ * Selection-scoped Bullets / Numbering: PowerPoint applies the ribbon's list
52633
+ * buttons to the paragraphs the text selection intersects, and to the whole
52634
+ * body when the shape (not a text range) is selected.
52635
+ *
52636
+ * `toggleSelectionBullets` is the one decision every binding's Bullets /
52637
+ * Numbering click routes through: it rewrites only the in-scope paragraphs
52638
+ * via {@link toggleParagraphBullet} and remaps the inline selection over the
52639
+ * marker segments it inserted or removed, so the binding can restore the
52640
+ * caret exactly where the user had it.
52641
+ */
52642
+ /** Whether `paragraph` holds a segment the selection covers (all of them when there is no selection). */
52643
+ function inScope(paragraph, selection) {
52644
+ if (!selection) {
52645
+ return true;
52646
+ }
52647
+ return paragraph.indices.some((index) => index >= selection.startSegIdx && index <= selection.endSegIdx);
52648
+ }
52649
+ /**
52650
+ * The list state the ribbon buttons should show for the current selection:
52651
+ * the kind shared by the paragraphs it intersects (every paragraph when there
52652
+ * is none), `'mixed'` when they disagree.
52653
+ *
52654
+ * @param segments - A fresher copy of the element's segments (a live inline
52655
+ * edit); defaults to the element's own.
52656
+ */
52657
+ function selectionBulletKind(element, selection, segments) {
52658
+ const paragraphs = splitBulletParagraphs(resolveBulletSegments(element, segments));
52659
+ return paragraphsBulletKind(paragraphs.filter((paragraph) => inScope(paragraph, selection)));
52660
+ }
52661
+ /**
52662
+ * Set every paragraph the selection intersects to `kind` (every paragraph
52663
+ * when there is no selection), returning the element patch and the selection
52664
+ * remapped onto the rewritten segments. Numbered paragraphs are counted
52665
+ * consecutively so the renderer shows "1. 2. 3.".
52666
+ */
52667
+ function setSelectionBullets(element, kind, selection, segments) {
52668
+ if (!hasTextProperties(element)) {
52669
+ return { patch: {}, newSelection: selection };
52670
+ }
52671
+ const source = resolveBulletSegments(element, segments);
52672
+ const next = [];
52673
+ /** Source index -> index in `next`, for every segment that survives. */
52674
+ const indexMap = new Map();
52675
+ let ordinal = 0;
52676
+ for (const paragraph of splitBulletParagraphs(source)) {
52677
+ const content = paragraph.indices.filter((_index, position) => !isBulletMarkerSegment(paragraph.segments[position]));
52678
+ if (paragraph.segments.length > 0 && content.length > 0 && inScope(paragraph, selection)) {
52679
+ const rewritten = toggleParagraphBullet(paragraph.segments, kind, ordinal);
52680
+ ordinal += 1;
52681
+ // `toggleParagraphBullet` keeps the content runs in order, dropping
52682
+ // any old marker and (for a list kind) placing one new marker first.
52683
+ const contentStart = next.length + (kind === 'none' ? 0 : 1);
52684
+ for (const [position, index] of content.entries()) {
52685
+ indexMap.set(index, contentStart + position);
52686
+ }
52687
+ next.push(...rewritten);
52688
+ }
52689
+ else {
52690
+ for (const [position, index] of paragraph.indices.entries()) {
52691
+ indexMap.set(index, next.length + position);
52692
+ }
52693
+ next.push(...paragraph.segments);
52694
+ }
52695
+ // A selection never starts or ends on a separator (the DOM reader skips
52696
+ // them), so terminators need no entry in the map.
52697
+ if (paragraph.terminator) {
52698
+ next.push(paragraph.terminator);
52699
+ }
52700
+ }
52701
+ const textStyle = withoutListType(element.textStyle);
52702
+ const newSelection = selection
52703
+ ? {
52704
+ startSegIdx: indexMap.get(selection.startSegIdx) ?? selection.startSegIdx,
52705
+ startOffset: selection.startOffset,
52706
+ endSegIdx: indexMap.get(selection.endSegIdx) ?? selection.endSegIdx,
52707
+ endOffset: selection.endOffset,
52708
+ }
52709
+ : null;
52710
+ return { patch: { textSegments: next, textStyle }, newSelection };
52711
+ }
52712
+ /**
52713
+ * The ribbon button behaviour: pressing Bullets (or Numbering) when every
52714
+ * in-scope paragraph is already that kind turns them off; otherwise (none, the
52715
+ * other kind, or mixed) it applies that kind to all of them.
52716
+ */
52717
+ function toggleSelectionBullets(element, kind, selection, segments) {
52718
+ const current = selectionBulletKind(element, selection, segments);
52719
+ return setSelectionBullets(element, current === kind ? 'none' : kind, selection, segments);
52720
+ }
52721
+
52722
+ /**
52723
+ * Pressed state and toggle decision for the ribbon's Bold / Italic /
52724
+ * Underline / Strikethrough buttons.
52725
+ *
52726
+ * Every binding used to decide the next value as `!element.textStyle.bold`:
52727
+ * the body-level style, which knows nothing about the runs. A word that is
52728
+ * bold at run level inside a non-bold body read as "off", so clicking Bold
52729
+ * re-applied bold and the word could never be un-bolded from the ribbon.
52730
+ *
52731
+ * The state is derived from the runs the user selected (all content runs when
52732
+ * nothing is selected; the body style when there are no runs at all), as a
52733
+ * tri-state so a mixed selection is honest: PowerPoint turns a mixed or off
52734
+ * selection ON, and only an all-on selection OFF.
52735
+ */
52736
+ const TEXT_DECORATION_FLAGS = [
52737
+ 'bold',
52738
+ 'italic',
52739
+ 'underline',
52740
+ 'strikethrough',
52741
+ ];
52742
+ /** A run that carries text: not a paragraph break, not a display-only bullet marker. */
52743
+ function isContentSegment(segment) {
52744
+ return (!segment.isParagraphBreak &&
52745
+ segment.text !== '\n' &&
52746
+ segment.text.length > 0 &&
52747
+ !isBulletMarkerSegment(segment));
52748
+ }
52749
+ /**
52750
+ * The content runs a toggle acts on: those inside the selection's segment
52751
+ * range, or every content run when there is no selection.
52752
+ */
52753
+ function contentSegmentsInSelection(segments, selection) {
52754
+ if (!segments) {
52755
+ return [];
52756
+ }
52757
+ return segments.filter((segment, index) => isContentSegment(segment) &&
52758
+ (!selection || (index >= selection.startSegIdx && index <= selection.endSegIdx)));
52759
+ }
52760
+ function flagState(values) {
52761
+ if (values.every((value) => value)) {
52762
+ return 'on';
52763
+ }
52764
+ return values.some((value) => value) ? 'mixed' : 'off';
52765
+ }
52766
+ /**
52767
+ * The tri-state of each decoration over the selected runs. A run without an
52768
+ * explicit value inherits the body's, exactly as the renderer paints it. With
52769
+ * no content runs at all the body style decides.
52770
+ */
52771
+ function getSelectionTextStyleFlags(segments, selection, elementTextStyle) {
52772
+ const runs = contentSegmentsInSelection(segments, selection);
52773
+ const flags = {};
52774
+ for (const flag of TEXT_DECORATION_FLAGS) {
52775
+ const body = elementTextStyle?.[flag] ?? false;
52776
+ flags[flag] =
52777
+ runs.length === 0
52778
+ ? flagState([body])
52779
+ : flagState(runs.map((run) => run.style?.[flag] ?? body));
52780
+ }
52781
+ return flags;
52782
+ }
52783
+ /** What a click should write: only an all-on selection turns off. */
52784
+ function nextToggleValue(state) {
52785
+ return state !== 'on';
52786
+ }
52787
+ /**
52788
+ * {@link getSelectionTextStyleFlags} for an element: its runs (or `segments`,
52789
+ * a fresher copy from a live inline edit) against its body style. All off for
52790
+ * an element without text properties.
52791
+ */
52792
+ function textStyleFlagsOf(element, selection = null, segments) {
52793
+ if (!element || !hasTextProperties(element)) {
52794
+ return { bold: 'off', italic: 'off', underline: 'off', strikethrough: 'off' };
52795
+ }
52796
+ return getSelectionTextStyleFlags(segments ?? element.textSegments, selection, element.textStyle);
52797
+ }
52798
+
52799
+ /**
52800
+ * Which `TextStyle` keys belong to the text BODY and which to a RUN.
52801
+ *
52802
+ * `TextStyle` is one bag for three OOXML levels (`a:bodyPr`, `a:pPr`, `a:rPr`).
52803
+ * The block builder (`text-block-style.ts`, `text-body-layout.ts`) reads the
52804
+ * body-level keys from `element.textStyle` only; a run's style never carries
52805
+ * them anywhere the renderer looks. So when an inline selection is active and
52806
+ * a binding routes the WHOLE update through the selected runs, an Increase
52807
+ * Indent (`paragraphMarginLeft`) or a vertical-alignment change lands on run
52808
+ * styles nobody reads and nothing happens on screen.
52809
+ *
52810
+ * `splitTextStyleUpdate` partitions an update so a binding can merge the body
52811
+ * half into `element.textStyle` regardless of selection and scope only the
52812
+ * run half to the selected characters. `reconcileDecorationFlags` keeps the
52813
+ * body-level decoration honest after a run-scoped edit, so the block's CSS
52814
+ * `text-decoration` cannot keep painting underline over a run that was just
52815
+ * un-underlined.
52816
+ */
52817
+ /**
52818
+ * Keys read from `element.textStyle` only: `a:bodyPr` attributes, the text
52819
+ * warp / 3D scene, autofit, and the paragraph geometry the block builder
52820
+ * folds in as the body-wide fallback (indent, margins, spacing).
52821
+ */
52822
+ const BODY_TEXT_STYLE_KEYS = new Set([
52823
+ // autofit (`a:normAutofit` / `a:spAutoFit`)
52824
+ 'autoFit',
52825
+ 'autoFitMode',
52826
+ 'autoFitFontScale',
52827
+ 'autoFitLineSpacingReduction',
52828
+ // `a:bodyPr` anchoring, direction, rotation
52829
+ 'vAlign',
52830
+ 'anchorCenter',
52831
+ 'textDirection',
52832
+ 'textBodyRotation',
52833
+ 'upright',
52834
+ // `a:bodyPr` columns, overflow, wrap
52835
+ 'columnCount',
52836
+ 'columnSpacing',
52837
+ 'rtlColumns',
52838
+ 'hOverflow',
52839
+ 'vertOverflow',
52840
+ 'textWrap',
52841
+ // `a:bodyPr` insets
52842
+ 'bodyInsetLeft',
52843
+ 'bodyInsetTop',
52844
+ 'bodyInsetRight',
52845
+ 'bodyInsetBottom',
52846
+ // paragraph geometry the block applies body-wide
52847
+ 'paragraphMarginLeft',
52848
+ 'paragraphMarginRight',
52849
+ 'paragraphIndent',
52850
+ 'paragraphSpacingBefore',
52851
+ 'paragraphSpacingAfter',
52852
+ 'lineSpacing',
52853
+ 'lineSpacingExactPt',
52854
+ 'tabStops',
52855
+ 'defaultTabSize',
52856
+ 'eaLineBreak',
52857
+ 'latinLineBreak',
52858
+ 'fontAlignment',
52859
+ 'hangingPunctuation',
52860
+ // `a:bodyPr` flags
52861
+ 'spaceFirstLastParagraph',
52862
+ 'fromWordArt',
52863
+ 'forceAntiAlias',
52864
+ 'compatibleLineSpacing',
52865
+ // warp and 3D scene on the body
52866
+ 'textWarpPreset',
52867
+ 'textWarpAdj',
52868
+ 'textWarpAdj2',
52869
+ 'text3d',
52870
+ 'textBodyScene3d',
52871
+ 'textBodyScene3dXml',
52872
+ 'flatText',
52873
+ 'bodyPropertiesExtLstXml',
52874
+ ]);
52875
+ /** Whether `key` is read from the element body rather than a run. */
52876
+ function isBodyTextStyleKey(key) {
52877
+ return BODY_TEXT_STYLE_KEYS.has(key);
52878
+ }
52879
+ /** Partition `updates` into its body-level and run-level halves. Keys set to `undefined` (clears) are kept. */
52880
+ function splitTextStyleUpdate(updates) {
52881
+ const body = {};
52882
+ const run = {};
52883
+ for (const [key, value] of Object.entries(updates)) {
52884
+ (isBodyTextStyleKey(key) ? body : run)[key] = value;
52885
+ }
52886
+ return { body: body, run: run };
52887
+ }
52888
+ /**
52889
+ * Recompute the body-level value of each `flag` from the runs after a
52890
+ * run-scoped edit: `true` only when every content run is effectively on;
52891
+ * otherwise the body flag is dropped, and any run that was only inheriting it
52892
+ * gets it written explicitly so its own look does not change.
52893
+ */
52894
+ function reconcileDecorationFlags(segments, textStyle, flags) {
52895
+ const nextStyle = { ...(textStyle ?? {}) };
52896
+ let nextSegments = [...segments];
52897
+ for (const flag of flags) {
52898
+ const body = nextStyle[flag] ?? false;
52899
+ const content = nextSegments.filter(isContentSegment);
52900
+ if (content.length === 0) {
52901
+ continue;
52902
+ }
52903
+ if (content.every((segment) => segment.style?.[flag] ?? body)) {
52904
+ nextStyle[flag] = true;
52905
+ continue;
52906
+ }
52907
+ if (!body) {
52908
+ continue;
52909
+ }
52910
+ delete nextStyle[flag];
52911
+ nextSegments = nextSegments.map((segment) => isContentSegment(segment) && segment.style?.[flag] === undefined
52912
+ ? { ...segment, style: { ...segment.style, [flag]: true } }
52913
+ : segment);
52914
+ }
52915
+ return { textStyle: nextStyle, textSegments: nextSegments };
52916
+ }
52917
+
52602
52918
  /** Keep a runless paragraph's future body formatting in the same style edit. */
52603
52919
  function updateTextSegmentStyle(segment, updates, options = {}) {
52604
52920
  return {
@@ -52911,6 +53227,59 @@ function findTextPositionInSegment(editor, segIdx, charOffset) {
52911
53227
  return null;
52912
53228
  }
52913
53229
 
53230
+ /**
53231
+ * The one text-style update every binding applies from the ribbon, the
53232
+ * inspector and the inline editor's keyboard shortcuts.
53233
+ *
53234
+ * With an inline selection the run-level half of `updates` is scoped to the
53235
+ * selected characters (`applyStyleToSelectedSegments`) while the body-level
53236
+ * half (`text-style-scope.ts`) still reaches `element.textStyle`; the
53237
+ * decoration flags the edit touched are then reconciled so the body's CSS
53238
+ * decoration agrees with the runs. Without a selection the whole update goes
53239
+ * to the body and to every run, the behaviour all five bindings already had.
53240
+ */
53241
+ /**
53242
+ * Build the element patch for `updates`.
53243
+ *
53244
+ * @param selection - The active inline text selection, or `null` for a
53245
+ * whole-element edit.
53246
+ * @param segments - A fresher copy of the element's segments (a live inline
53247
+ * edit whose text is not yet on the model); defaults to the element's own.
53248
+ */
53249
+ function applyTextStyleUpdate(element, updates, selection, segments) {
53250
+ if (!hasTextProperties(element)) {
53251
+ return { patch: {}, newSelection: null };
53252
+ }
53253
+ const current = segments ?? element.textSegments;
53254
+ if (selection && current && current.length > 0) {
53255
+ const { body, run } = splitTextStyleUpdate(updates);
53256
+ let textStyle = { ...element.textStyle, ...body };
53257
+ let textSegments = [...current];
53258
+ let newSelection = selection;
53259
+ if (Object.keys(run).length > 0) {
53260
+ const scoped = applyStyleToSelectedSegments(textSegments, selection, run);
53261
+ textSegments = scoped.newSegments;
53262
+ newSelection = scoped.newSelection;
53263
+ }
53264
+ const touched = TEXT_DECORATION_FLAGS.filter((flag) => flag in run);
53265
+ if (touched.length > 0) {
53266
+ const reconciled = reconcileDecorationFlags(textSegments, textStyle, touched);
53267
+ textStyle = reconciled.textStyle;
53268
+ textSegments = reconciled.textSegments;
53269
+ }
53270
+ return { patch: { textStyle, textSegments }, newSelection };
53271
+ }
53272
+ const textStyle = { ...element.textStyle, ...updates };
53273
+ const textSegments = current?.map((segment) => ({
53274
+ ...segment,
53275
+ style: { ...segment.style, ...updates },
53276
+ }));
53277
+ return {
53278
+ patch: (textSegments ? { textStyle, textSegments } : { textStyle }),
53279
+ newSelection: null,
53280
+ };
53281
+ }
53282
+
52914
53283
  /** Body offsets ignore only the leading display marker of each paragraph. */
52915
53284
  function positions(segments) {
52916
53285
  let offset = 0;
@@ -52974,7 +53343,8 @@ function restoreParagraphMetadata$1(original, updated) {
52974
53343
  /** Current kind at the first selected paragraph; otherwise the element default. */
52975
53344
  function selectedParagraphBulletKind(element, selection) {
52976
53345
  if (!selection || !hasTextProperties(element) || !element.textSegments) {
52977
- return elementBulletKind(element);
53346
+ const kind = elementBulletKind(element);
53347
+ return kind === 'mixed' ? 'none' : kind;
52978
53348
  }
52979
53349
  let first = selection.startSegIdx;
52980
53350
  while (first > 0 && !isParagraphSeparatorSegment(element.textSegments[first - 1])) {
@@ -55294,12 +55664,23 @@ function buildTextBlockStyle(element, options = {}) {
55294
55664
  const bodyIndent = hasParagraphIndents ? 0 : ts?.paragraphIndent || 0;
55295
55665
  const bodyMarginLeft = hasParagraphIndents ? 0 : ts?.paragraphMarginLeft || 0;
55296
55666
  const bodyMarginRight = hasParagraphIndents ? 0 : ts?.paragraphMarginRight || 0;
55667
+ // CSS cannot let a nested run span CANCEL an ancestor's `text-decoration`:
55668
+ // the line is drawn by the decorating box and shows through descendants
55669
+ // regardless of their own `text-decoration-line`, so an element-level
55670
+ // underline/strikethrough here would bleed onto every run even when a
55671
+ // specific run's segment style says `underline: false`. Only a fallback
55672
+ // for segmentless text, exactly like `highlightColor` below: with
55673
+ // segments, each run already emits its own decoration
55674
+ // (`segmentStyleToCss` in `text-run-style.ts`).
55675
+ const hasTextSegments = (element.textSegments?.length ?? 0) > 0;
55297
55676
  const decorations = [];
55298
- if (ts?.underline || ts?.hyperlink) {
55299
- decorations.push('underline');
55300
- }
55301
- if (ts?.strikethrough) {
55302
- decorations.push('line-through');
55677
+ if (!hasTextSegments) {
55678
+ if (ts?.underline || ts?.hyperlink) {
55679
+ decorations.push('underline');
55680
+ }
55681
+ if (ts?.strikethrough) {
55682
+ decorations.push('line-through');
55683
+ }
55303
55684
  }
55304
55685
  const style = {};
55305
55686
  // Layout first: the typography below must win on any shared property (a
@@ -55330,7 +55711,7 @@ function buildTextBlockStyle(element, options = {}) {
55330
55711
  : normalizeHexColor$1(ts?.color, fallbackColor);
55331
55712
  // An element-level highlight is only a fallback for segmentless text; with
55332
55713
  // segments each run carries its own `backgroundColor`.
55333
- if ((element.textSegments?.length ?? 0) === 0 && ts?.highlightColor) {
55714
+ if (!hasTextSegments && ts?.highlightColor) {
55334
55715
  style.backgroundColor = normalizeHexColor$1(ts.highlightColor, undefined);
55335
55716
  }
55336
55717
  style.textAlign = resolveCssTextAlign(ts?.align, isRtl) ?? 'left';
@@ -55357,7 +55738,7 @@ function buildTextBlockStyle(element, options = {}) {
55357
55738
  style.fontWeight = ts?.bold ? 700 : 400;
55358
55739
  style.fontStyle = ts?.italic ? 'italic' : 'normal';
55359
55740
  style.textDecorationLine = decorations.length > 0 ? decorations.join(' ') : 'none';
55360
- if (ts?.strikethrough && ts?.strikeType === 'dblStrike') {
55741
+ if (!hasTextSegments && ts?.strikethrough && ts?.strikeType === 'dblStrike') {
55361
55742
  style.textDecorationStyle = 'double';
55362
55743
  }
55363
55744
  style.lineHeight = resolveLineHeight(ts, italic);
@@ -63601,26 +63982,16 @@ function buildDashArray(dash, strokeWidth, customDashSegments) {
63601
63982
  }
63602
63983
 
63603
63984
  /**
63604
- * Orientation-aware bend geometry for multi-segment elbow connectors
63985
+ * OOXML preset bend geometry for multi-segment elbow connectors
63605
63986
  * (`bentConnector3/4/5`, `curvedConnector3/4/5`).
63606
63987
  *
63607
63988
  * PowerPoint's elbow connectors do NOT avoid obstacles (obstacle-avoiding A*
63608
63989
  * routing lives in `connector-router.ts` and is applied separately by
63609
63990
  * `connector-path.ts`, only when a binding supplies an obstacle list; that is
63610
- * out of scope here). What they DO is pick the bend axis from the actual
63611
- * relative position of the two connection points: a connector between shapes
63612
- * that sit roughly side-by-side bends around a vertical mid-line (an
63613
- * "H-V-H" Z-shape), while one between vertically-stacked shapes bends around
63614
- * a horizontal mid-line (a "V-H-V" S-shape). The ECMA-376 `bentConnector3/4/5`
63615
- * / `curvedConnector3/4/5` preset-geometry formulas are always expressed
63616
- * against the connector's own local box (an `adj1` fraction of `w`, etc), so
63617
- * the same numeric formula is reused here for both orientations; only which
63618
- * axis plays the "primary" (adjustment-driven) role changes. This mirrors the
63619
- * segment-count differentiation `packages/core/src/core/geometry/connector-geometry.ts`
63620
- * already applies (2/3/4/5-segment paths from `adj1`/`adj2`/`adj3`), extended
63621
- * with the orientation choice so a connector between stacked shapes no longer
63622
- * renders the exact same "always exits sideways" shape as one between shapes
63623
- * side by side.
63991
+ * out of scope here). The ECMA-376 `bentConnector3/4/5` and
63992
+ * `curvedConnector3/4/5` paths are always authored horizontal-first against
63993
+ * their local box. `a:xfrm/@flipH` and `@flipV` orient that stored path; the
63994
+ * bounding-box aspect ratio does not transpose its axes.
63624
63995
  *
63625
63996
  * No framework imports.
63626
63997
  */
@@ -63668,16 +64039,10 @@ function elbowSegmentCount(lowerShapeType) {
63668
64039
  return 3;
63669
64040
  }
63670
64041
  /**
63671
- * True when the primary bend axis should run along x, i.e. the two endpoints
63672
- * differ more in x than in y. There is no explicit connection-site "side"
63673
- * (top/bottom/left/right) available at this layer (see `connector-path.ts`
63674
- * module docs), so the dominant axis of the resolved endpoints is the
63675
- * tractable, well-behaved proxy: shapes mostly side by side get a
63676
- * vertical-mid-line route, shapes mostly stacked get a horizontal-mid-line
63677
- * route. Ties favour horizontal, matching the historical (pre-fix) behaviour.
64042
+ * OOXML connector preset paths always use x as their primary bend axis.
63678
64043
  */
63679
- function isHorizontalPrimary(x1, y1, x2, y2) {
63680
- return Math.abs(x2 - x1) >= Math.abs(y2 - y1);
64044
+ function isHorizontalPrimary(_x1, _y1, _x2, _y2) {
64045
+ return true;
63681
64046
  }
63682
64047
  /** `(u, v)` -> `(x, y)`, transposed when the secondary axis is horizontal. */
63683
64048
  function axisMapper(horizontalPrimary) {
@@ -63729,7 +64094,7 @@ function curveTo(ctrl, end) {
63729
64094
  /**
63730
64095
  * Render the same `segments`-segment elbow as a smooth path: cubic Beziers
63731
64096
  * whose control points sit on the elbow's own corners, so curved connectors
63732
- * get the same orientation-aware, segment-count-aware routing as
64097
+ * get the same horizontal-first, segment-count-aware routing as
63733
64098
  * {@link elbowWaypoints} while never producing a sharp corner.
63734
64099
  *
63735
64100
  * `segments === 3` emits a single cubic Bezier through the two corner points
@@ -63904,15 +64269,13 @@ function buildConnectorGeometry(element, zIndex, routing) {
63904
64269
  const compoundWidths = getCompoundLineWidths(ss?.compoundLine, strokeWidth);
63905
64270
  const svgW = Math.max(element.width, 1);
63906
64271
  const svgH = Math.max(element.height, 1);
63907
- const x1 = element.flipHorizontal ? svgW : 0;
63908
- const y1 = element.flipVertical ? svgH : 0;
63909
- const x2 = element.flipHorizontal ? 0 : svgW;
63910
- const y2 = element.flipVertical ? 0 : svgH;
63911
64272
  const shapeType = element.shapeType;
63912
- const bend1 = connectorAdjustmentFraction(element, 'adj1', 0.5);
63913
- const bend2 = connectorAdjustmentFraction(element, 'adj2', 0.5);
63914
- const bend3 = connectorAdjustmentFraction(element, 'adj3', 0.5);
63915
- let pathD = buildConnectorPathD(shapeType, x1, y1, x2, y2, bend1, bend2, bend3);
64273
+ const coreGeometry = hasShapeProperties(element) ? getConnectorPathGeometry(element) : undefined;
64274
+ const x1 = coreGeometry?.startX ?? 0;
64275
+ const y1 = coreGeometry?.startY ?? 0;
64276
+ const x2 = coreGeometry?.endX ?? svgW;
64277
+ const y2 = coreGeometry?.endY ?? svgH;
64278
+ let pathD = connectorKind(shapeType) === 'straight' ? undefined : coreGeometry?.pathData;
63916
64279
  // Obstacle-avoiding A* routing for bent connectors. Routes in absolute slide
63917
64280
  // coordinates (so it can detour outside the connector's own bounding box;
63918
64281
  // the SVG uses `overflow: visible`), then translates waypoints back to
@@ -63982,20 +64345,16 @@ function buildConnectorGeometry(element, zIndex, routing) {
63982
64345
  *
63983
64346
  * PowerPoint's elbow connectors do not avoid obstacles (that A* routing is
63984
64347
  * applied separately by {@link buildConnectorGeometry} when a binding
63985
- * supplies an obstacle list). What they DO is pick the bend axis from the
63986
- * actual relative position of the two endpoints, and use the OOXML preset's
63987
- * full segment count and adjustment values rather than collapsing every
63988
- * `bentConnector3/4/5` (and `curvedConnector3/4/5`) into the same shape; see
63989
- * `connector-elbow-geometry.ts` for the orientation/segment-count formulas
63990
- * (mirroring `packages/core/src/core/geometry/connector-geometry.ts`'s
63991
- * per-segment-count treatment, extended with the orientation choice):
64348
+ * supplies an obstacle list). These fallback helpers keep the stored
64349
+ * horizontal-first axis and preserve each preset's segment count and
64350
+ * adjustments. The main renderer delegates to core's normative preset path
64351
+ * evaluator in {@link buildConnectorGeometry}.
63992
64352
  * - **bent**: orthogonal elbow polyline. `bentConnector2` is a single L-bend;
63993
64353
  * `bentConnector3` is a 2-bend Z routed through one adjustment (`adj1`);
63994
64354
  * `bentConnector4` is a 3-bend staircase (`adj1`, `adj2`); `bentConnector5`
63995
64355
  * is a 4-bend staircase (`adj1`, `adj2`, `adj3`).
63996
- * - **curved**: `curvedConnector2` is a quadratic Bezier; `curvedConnector3/4/5`
63997
- * are the same elbow shapes rendered as smooth cubic Beziers instead of
63998
- * sharp corners.
64356
+ * - **curved**: fallback Bezier approximations for callers that build paths
64357
+ * directly rather than through {@link buildConnectorGeometry}.
63999
64358
  *
64000
64359
  * `bend2`/`bend3` are optional so existing 6-argument call sites (which only
64001
64360
  * ever needed `bentConnector2/3` / `curvedConnector2/3`) keep compiling and
@@ -64313,26 +64672,22 @@ function fontSizeOf(el, presentationDefault) {
64313
64672
  const deckDefault = presentationDefault?.levelStyles?.[0]?.fontSize;
64314
64673
  return deckDefault === undefined ? DEFAULT_FONT_SIZE$2 : textFontSizePxToPt(deckDefault);
64315
64674
  }
64316
- /** Returns whether the element's text is bold (false when absent). */
64675
+ /**
64676
+ * Returns whether the element's text is bold: every content run effectively
64677
+ * bold (run style, else the body style), false when absent. Derived from the
64678
+ * runs, not the body alone, so a box whose runs are all bold at run level
64679
+ * reads as bold and a mixed box does not (see `selection-format-state`).
64680
+ */
64317
64681
  function isBold(el) {
64318
- if (hasTextProperties(el)) {
64319
- return el.textStyle?.bold ?? false;
64320
- }
64321
- return false;
64682
+ return textStyleFlagsOf(el).bold === 'on';
64322
64683
  }
64323
- /** Returns whether the element's text is italic (false when absent). */
64684
+ /** Returns whether the element's text is italic (see {@link isBold} for the run rule). */
64324
64685
  function isItalic(el) {
64325
- if (hasTextProperties(el)) {
64326
- return el.textStyle?.italic ?? false;
64327
- }
64328
- return false;
64686
+ return textStyleFlagsOf(el).italic === 'on';
64329
64687
  }
64330
- /** Returns whether the element's text has underline (false when absent). */
64688
+ /** Returns whether the element's text has underline (see {@link isBold} for the run rule). */
64331
64689
  function isUnderline(el) {
64332
- if (hasTextProperties(el)) {
64333
- return el.textStyle?.underline ?? false;
64334
- }
64335
- return false;
64690
+ return textStyleFlagsOf(el).underline === 'on';
64336
64691
  }
64337
64692
  /**
64338
64693
  * Builds a Partial<PptxElement> patch that merges the given changes into the
@@ -64489,6 +64844,9 @@ function remapEmptyParagraph(text, segments, terminator) {
64489
64844
  return [{ ...first, text, style: { ...insertionStyle } }];
64490
64845
  }
64491
64846
 
64847
+ function trailingWhitespace(text) {
64848
+ return text.slice(text.trimEnd().length);
64849
+ }
64492
64850
  /** Refresh only derived ordinals after existing paragraphs have moved. */
64493
64851
  function renumberRemappedParagraphs(segments) {
64494
64852
  const sequence = createAutoNumberSequence();
@@ -64515,12 +64873,33 @@ function renumberRemappedParagraphs(segments) {
64515
64873
  if (isBulletMarkerSegment(segment)) {
64516
64874
  const resolved = resolveParagraphBullet(updated);
64517
64875
  if (resolved) {
64518
- updated.text = resolved.marker + (segment.text.match(/\s+$/u)?.[0] ?? '');
64876
+ updated.text = resolved.marker + trailingWhitespace(segment.text);
64519
64877
  }
64520
64878
  }
64521
64879
  return updated;
64522
64880
  });
64523
64881
  }
64882
+ /** Returns the editor-only display marker that begins a listed paragraph. */
64883
+ function dedicatedBulletMarker(paragraphSegments) {
64884
+ const first = paragraphSegments[0];
64885
+ if (!first || !isBulletMarkerSegment(first)) {
64886
+ return undefined;
64887
+ }
64888
+ return !first.bulletInfo?.autoNumType || first.bulletInfo.paragraphIndex !== undefined
64889
+ ? first
64890
+ : undefined;
64891
+ }
64892
+ /** Updates an auto-number's derived ordinal and its display marker text. */
64893
+ function withAutoNumberIndex(first, paragraphIndex, isMarker = isBulletMarkerSegment(first)) {
64894
+ const next = { ...first, bulletInfo: { ...first.bulletInfo, paragraphIndex } };
64895
+ if (isMarker) {
64896
+ const resolved = resolveParagraphBullet(next);
64897
+ if (resolved) {
64898
+ next.text = `${resolved.marker}${trailingWhitespace(first.text)}`;
64899
+ }
64900
+ }
64901
+ return next;
64902
+ }
64524
64903
  /** Remove a display-only marker from editor text before remapping its content. */
64525
64904
  function withoutRenderedBulletPrefix(text, originalSegments, dedicatedMarker) {
64526
64905
  if (!dedicatedMarker) {
@@ -64586,8 +64965,7 @@ function continueListParagraph(segments, donorSegments) {
64586
64965
  isBulletMarkerSegment(donor)) {
64587
64966
  const resolved = resolveParagraphBullet(continued);
64588
64967
  if (resolved) {
64589
- const trailingWhitespace = donor.text.match(/\s+$/u)?.[0] ?? '';
64590
- continued.text = `${resolved.marker}${trailingWhitespace}`;
64968
+ continued.text = `${resolved.marker}${trailingWhitespace(donor.text)}`;
64591
64969
  }
64592
64970
  }
64593
64971
  return [continued, ...rest];
@@ -64913,6 +65291,25 @@ function remapTextToSegments(newText, originalSegments, elementTextStyle) {
64913
65291
  // or end-run properties reserved for an aligned original paragraph.
64914
65292
  if (!originalParagraph && precedingParagraph) {
64915
65293
  paraSegments = continueListParagraph(paraSegments, precedingParagraph);
65294
+ const donor = precedingParagraph[0];
65295
+ if (donor?.paragraphProperties?.alignment !==
65296
+ undefined &&
65297
+ paraSegments[0]) {
65298
+ paraSegments = [
65299
+ {
65300
+ ...paraSegments[0],
65301
+ paragraphLevel: donor.paragraphLevel,
65302
+ paragraphProperties: donor.paragraphProperties,
65303
+ },
65304
+ ...paraSegments.slice(1),
65305
+ ];
65306
+ }
65307
+ }
65308
+ else if (!originalParagraph && pi === 0 && paraSegments[0]) {
65309
+ const firstOriginal = originalParagraphs[0]?.segments[0];
65310
+ if (firstOriginal?.paragraphLevel !== undefined) {
65311
+ paraSegments = [{ ...paraSegments[0], paragraphLevel: firstOriginal.paragraphLevel }];
65312
+ }
64916
65313
  }
64917
65314
  output.push(...paraSegments);
64918
65315
  precedingParagraph = paraSegments;
@@ -78217,6 +78614,35 @@ function clamp$1(v, lo, hi) {
78217
78614
  return Math.max(lo, Math.min(hi, v));
78218
78615
  }
78219
78616
 
78617
+ /** Recursively add every explicit font family referenced by an element. */
78618
+ function collectFontsFromElement(element, fonts) {
78619
+ if (hasTextProperties(element)) {
78620
+ if (element.textStyle?.fontFamily) {
78621
+ fonts.add(element.textStyle.fontFamily);
78622
+ }
78623
+ for (const segment of element.textSegments ?? []) {
78624
+ if (segment.style?.fontFamily) {
78625
+ fonts.add(segment.style.fontFamily);
78626
+ }
78627
+ }
78628
+ }
78629
+ if (element.type === 'group') {
78630
+ for (const child of element.children ?? []) {
78631
+ collectFontsFromElement(child, fonts);
78632
+ }
78633
+ }
78634
+ }
78635
+ /** Collect the sorted unique font families referenced across a presentation. */
78636
+ function collectUsedFonts(slides) {
78637
+ const fonts = new Set();
78638
+ for (const slide of slides) {
78639
+ for (const element of slide.elements ?? []) {
78640
+ collectFontsFromElement(element, fonts);
78641
+ }
78642
+ }
78643
+ return [...fonts].sort();
78644
+ }
78645
+
78220
78646
  /**
78221
78647
  * google-webfonts.ts: Google Fonts webfont fallback for referenced font
78222
78648
  * families, shared by every binding.
@@ -78273,27 +78699,20 @@ const GOOGLE_WEBFONT_AXIS = 'ital,wght@0,400;0,700;1,400;1,700';
78273
78699
  /** `display=swap` so text paints with the fallback and swaps when ready. */
78274
78700
  const DISPLAY_PARAM = 'display=swap';
78275
78701
  /**
78276
- * Collect all unique font family names referenced across slide elements'
78277
- * text segments, recursing into group children.
78702
+ * Collect all unique font family names referenced across slide elements,
78703
+ * recursing into group children.
78704
+ *
78705
+ * Delegates to the same walker the Fonts inspector uses, so the element-level
78706
+ * `textStyle.fontFamily` counts too: segment-less text (a title whose face is
78707
+ * set once on the body rather than per run) used to be skipped here, so its
78708
+ * webfont was never requested and it painted in the fallback face.
78278
78709
  */
78279
78710
  function collectReferencedFontFamilies(slides) {
78280
78711
  const families = new Set();
78281
- const visit = (elements) => {
78282
- for (const el of elements) {
78283
- if (el.type === 'group') {
78284
- visit(el.children);
78285
- }
78286
- if (hasTextProperties(el) && el.textSegments) {
78287
- for (const seg of el.textSegments) {
78288
- if (seg.style.fontFamily) {
78289
- families.add(seg.style.fontFamily);
78290
- }
78291
- }
78292
- }
78293
- }
78294
- };
78295
78712
  for (const slide of slides) {
78296
- visit(slide.elements);
78713
+ for (const el of slide.elements) {
78714
+ collectFontsFromElement(el, families);
78715
+ }
78297
78716
  }
78298
78717
  return families;
78299
78718
  }
@@ -92988,35 +93407,6 @@ function computeDocumentStatistics(slides, coreProperties) {
92988
93407
  };
92989
93408
  }
92990
93409
 
92991
- /** Recursively add every explicit font family referenced by an element. */
92992
- function collectFontsFromElement(element, fonts) {
92993
- if (hasTextProperties(element)) {
92994
- if (element.textStyle?.fontFamily) {
92995
- fonts.add(element.textStyle.fontFamily);
92996
- }
92997
- for (const segment of element.textSegments ?? []) {
92998
- if (segment.style?.fontFamily) {
92999
- fonts.add(segment.style.fontFamily);
93000
- }
93001
- }
93002
- }
93003
- if (element.type === 'group') {
93004
- for (const child of element.children ?? []) {
93005
- collectFontsFromElement(child, fonts);
93006
- }
93007
- }
93008
- }
93009
- /** Collect the sorted unique font families referenced across a presentation. */
93010
- function collectUsedFonts(slides) {
93011
- const fonts = new Set();
93012
- for (const slide of slides) {
93013
- for (const element of slide.elements ?? []) {
93014
- collectFontsFromElement(element, fonts);
93015
- }
93016
- }
93017
- return [...fonts].sort();
93018
- }
93019
-
93020
93410
  function browserFontSource() {
93021
93411
  return typeof document === 'undefined' ? undefined : document.fonts;
93022
93412
  }
@@ -97602,24 +97992,41 @@ async function fetchAsDataUrl(url) {
97602
97992
  }
97603
97993
  }
97604
97994
  /**
97605
- * Matches one `url(...)` reference, as a double-quoted, single-quoted, or bare
97606
- * token. The three forms are matched as separate alternatives (rather than one
97607
- * `["']?...["']?` wrapped around a single content group) so the surrounding
97608
- * `\s*` never shares characters with the content group: a naive
97609
- * `\s*["']?([^"')]+)["']?\s*` lets whitespace be split between the leading
97610
- * `\s*` and the content group in exponentially many equivalent ways, which is
97611
- * polynomial-time (`js/polynomial-redos`) on an unclosed `url(` followed by
97612
- * many tabs/spaces. Each alternative here has a fixed, non-overlapping
97613
- * character class, so there is only one way to match.
97995
+ * Extract one `url(...)` reference without a regular expression. CSS values
97996
+ * can originate in a presentation, so a bounded linear scan avoids the
97997
+ * backtracking ambiguity that can make a permissive URL-matching pattern slow
97998
+ * on malformed input containing long whitespace runs.
97614
97999
  */
97615
- const CSS_URL_PATTERN = /url\(\s*(?:"([^"]*)"|'([^']*)'|([^"')\s]+))\s*\)/u;
97616
- /** Extract a `url(...)` reference from a CSS value; returns `null` when none is present. */
97617
98000
  function extractCssUrl(value) {
97618
- const match = CSS_URL_PATTERN.exec(value);
97619
- if (!match) {
98001
+ const start = value.indexOf('url(');
98002
+ if (start === -1) {
98003
+ return null;
98004
+ }
98005
+ const contents = value.slice(start + 'url('.length).trimStart();
98006
+ const quote = contents[0];
98007
+ if (quote === '"' || quote === "'") {
98008
+ const end = contents.indexOf(quote, 1);
98009
+ if (end === -1 ||
98010
+ !contents
98011
+ .slice(end + 1)
98012
+ .trimStart()
98013
+ .startsWith(')')) {
98014
+ return null;
98015
+ }
98016
+ return contents.slice(1, end);
98017
+ }
98018
+ const end = contents.indexOf(')');
98019
+ if (end === -1) {
97620
98020
  return null;
97621
98021
  }
97622
- return match[1] ?? match[2] ?? match[3] ?? null;
98022
+ const url = contents.slice(0, end).trimEnd();
98023
+ return url &&
98024
+ !url.includes('"') &&
98025
+ !url.includes("'") &&
98026
+ !url.includes(' ') &&
98027
+ !url.includes('\t')
98028
+ ? url
98029
+ : null;
97623
98030
  }
97624
98031
  function needsEmbedding(url) {
97625
98032
  return url.startsWith('blob:') || url.startsWith('http:') || url.startsWith('https:');
@@ -97793,6 +98200,117 @@ function calculateViewportFit(input, defaults = DEFAULTS$1) {
97793
98200
  };
97794
98201
  }
97795
98202
 
98203
+ /** Path coordinates are stored at 100x element pixels, matching the geometry engine. */
98204
+ const FREEFORM_COORD_SCALE = 100;
98205
+ /** Fewer points than this is a tap, not a drawing. */
98206
+ const FREEFORM_MIN_POINTS = 2;
98207
+ /**
98208
+ * The closing tolerance is this many stroke widths: the end point may sit up
98209
+ * to three outline widths from the start and still count as "back on it".
98210
+ */
98211
+ const FREEFORM_CLOSE_TOLERANCE_FACTOR = 3;
98212
+ /**
98213
+ * Floor for {@link freeformCloseTolerance}, in stage pixels, so a hairline
98214
+ * stroke does not demand a pixel-perfect return to its start.
98215
+ */
98216
+ const FREEFORM_CLOSE_TOLERANCE_MIN_PX = 4;
98217
+ /**
98218
+ * How close (stage px) the end of a stroke must be to its start for the path
98219
+ * to be closed: {@link FREEFORM_CLOSE_TOLERANCE_FACTOR} stroke widths, never
98220
+ * less than {@link FREEFORM_CLOSE_TOLERANCE_MIN_PX}.
98221
+ */
98222
+ function freeformCloseTolerance(strokeWidth) {
98223
+ return Math.max(FREEFORM_CLOSE_TOLERANCE_MIN_PX, strokeWidth * FREEFORM_CLOSE_TOLERANCE_FACTOR);
98224
+ }
98225
+ /**
98226
+ * Whether a stroke ends back on its start point (within `tolerance`). A
98227
+ * stroke of fewer than three points can never enclose anything, so it is
98228
+ * never closed no matter where its two ends sit.
98229
+ */
98230
+ function isFreeformStrokeClosed(points, tolerance) {
98231
+ if (points.length < 3) {
98232
+ return false;
98233
+ }
98234
+ const first = points[0];
98235
+ const last = points[points.length - 1];
98236
+ return Math.hypot(last.x - first.x, last.y - first.y) <= tolerance;
98237
+ }
98238
+ /**
98239
+ * Bounding box (padded by `strokeWidth`) plus the custom-geometry path for a
98240
+ * finished freeform stroke, or `null` for a tap (fewer than
98241
+ * {@link FREEFORM_MIN_POINTS} points).
98242
+ */
98243
+ function buildFreeformStrokeGeometry(points, strokeWidth, options = {}) {
98244
+ if (points.length < FREEFORM_MIN_POINTS) {
98245
+ return null;
98246
+ }
98247
+ let minX = Infinity;
98248
+ let minY = Infinity;
98249
+ let maxX = -Infinity;
98250
+ let maxY = -Infinity;
98251
+ for (const point of points) {
98252
+ minX = Math.min(minX, point.x);
98253
+ minY = Math.min(minY, point.y);
98254
+ maxX = Math.max(maxX, point.x);
98255
+ maxY = Math.max(maxY, point.y);
98256
+ }
98257
+ minX -= strokeWidth;
98258
+ minY -= strokeWidth;
98259
+ maxX += strokeWidth;
98260
+ maxY += strokeWidth;
98261
+ const width = Math.max(maxX - minX, 1);
98262
+ const height = Math.max(maxY - minY, 1);
98263
+ const segments = points.map((point, index) => {
98264
+ const pt = {
98265
+ x: Math.round((point.x - minX) * FREEFORM_COORD_SCALE),
98266
+ y: Math.round((point.y - minY) * FREEFORM_COORD_SCALE),
98267
+ };
98268
+ return index === 0 ? { type: 'moveTo', pt } : { type: 'lineTo', pt };
98269
+ });
98270
+ const closed = isFreeformStrokeClosed(points, options.closeTolerance ?? freeformCloseTolerance(strokeWidth));
98271
+ if (closed) {
98272
+ segments.push({ type: 'close' });
98273
+ }
98274
+ return {
98275
+ x: minX,
98276
+ y: minY,
98277
+ width,
98278
+ height,
98279
+ path: {
98280
+ width: Math.round(width * FREEFORM_COORD_SCALE),
98281
+ height: Math.round(height * FREEFORM_COORD_SCALE),
98282
+ segments,
98283
+ },
98284
+ closed,
98285
+ };
98286
+ }
98287
+ /**
98288
+ * The `shape` element the Freeform tool commits: an unfilled `custom` shape
98289
+ * outlined in the pen colour, or `null` for a tap. Path closing follows
98290
+ * {@link buildFreeformStrokeGeometry}.
98291
+ */
98292
+ function buildFreeformShapeElement(points, options) {
98293
+ const geometry = buildFreeformStrokeGeometry(points, options.width, options);
98294
+ if (!geometry) {
98295
+ return null;
98296
+ }
98297
+ return {
98298
+ id: options.id ?? createEditorId('shape'),
98299
+ type: 'shape',
98300
+ x: geometry.x,
98301
+ y: geometry.y,
98302
+ width: geometry.width,
98303
+ height: geometry.height,
98304
+ shapeType: 'custom',
98305
+ shapeStyle: {
98306
+ fillColor: 'transparent',
98307
+ strokeColor: options.color,
98308
+ strokeWidth: options.width,
98309
+ },
98310
+ customGeometryPaths: [geometry.path],
98311
+ };
98312
+ }
98313
+
97796
98314
  /**
97797
98315
  * Framework-agnostic rendering & editing helpers shared by the React, Vue, and
97798
98316
  * Angular `pptx-viewer` bindings. Pure TypeScript (no framework imports) — each
@@ -101617,27 +102135,13 @@ async function rasterizeElementTiles(element, naturalWidth, naturalHeight, doc,
101617
102135
  * canvas stitch) so the row/col grouping is written once.
101618
102136
  */
101619
102137
  function groupTilesByRow(tiles) {
101620
- const rowCount = tiles.reduce((max, t) => Math.max(max, t.row), 0) + 1;
101621
- const rows = Array.from({ length: rowCount }, () => []);
101622
- for (const tile of tiles) {
101623
- // `row`/`col` are declared as `number`, but this is a public export: a
101624
- // caller could pass a `RasterizedTile[]` built from untrusted data whose
101625
- // `row`/`col` are, at runtime, a string like `__proto__`. Indexing an
101626
- // array with that string resolves through `Array.prototype` (itself
101627
- // inherited from `Object.prototype`), so `rows[tile.row][tile.col] = tile`
101628
- // would assign onto `Array.prototype` rather than `rows`, polluting every
101629
- // array in the process. Requiring a genuine non-negative integer index
101630
- // closes that off without changing behaviour for any real tile, which is
101631
- // always produced by `computeExportTilePlan`'s integer loop counters.
101632
- if (!Number.isInteger(tile.row) ||
101633
- !Number.isInteger(tile.col) ||
101634
- tile.row < 0 ||
101635
- tile.col < 0) {
101636
- continue;
101637
- }
101638
- rows[tile.row][tile.col] = tile;
101639
- }
101640
- return rows;
102138
+ const validTiles = tiles.filter((tile) => Number.isInteger(tile.row) && Number.isInteger(tile.col) && tile.row >= 0 && tile.col >= 0);
102139
+ const rowCount = validTiles.reduce((max, tile) => Math.max(max, tile.row), 0) + 1;
102140
+ return Array.from({ length: rowCount }, (_rowIndex, row) => {
102141
+ const tilesInRow = validTiles.filter((tile) => tile.row === row);
102142
+ const colCount = tilesInRow.reduce((max, tile) => Math.max(max, tile.col), -1) + 1;
102143
+ return Array.from({ length: colCount }, (_columnIndex, col) => tilesInRow.find((tile) => tile.col === col));
102144
+ });
101641
102145
  }
101642
102146
 
101643
102147
  /**
@@ -104013,7 +104517,7 @@ function createLocalStorageBackend(namespace) {
104013
104517
  /** Try IndexedDB first; fall back to localStorage on any failure. */
104014
104518
  async function resolveBackend(dbName, namespace) {
104015
104519
  try {
104016
- const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-DjOCNjw-.mjs');
104520
+ const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BaGfTtS5.mjs');
104017
104521
  const db = await openChatDb(dbName);
104018
104522
  return createIdbBackend(db);
104019
104523
  }
@@ -110045,9 +110549,13 @@ class EditorStateService {
110045
110549
  }
110046
110550
  }
110047
110551
  // ── Align / distribute (multi-selection) ─────────────────────────────────
110048
- /** Align the selected elements within their group bounds (one history entry). */
110552
+ /**
110553
+ * Align the selected elements (one history entry): two or more against their
110554
+ * shared bounds, a lone element against the slide, as in PowerPoint.
110555
+ */
110049
110556
  alignSelected(slideIndex, mode) {
110050
- this.applyPositionMap(slideIndex, this.t('pptx.undoAction.align', { mode }), (boxes) => computeAlign(boxes, mode));
110557
+ const slideSize = this.loader?.canvasSize();
110558
+ this.applyPositionMap(slideIndex, this.t('pptx.undoAction.align', { mode }), (boxes) => computeAlign(boxes, mode, { slideSize }));
110051
110559
  }
110052
110560
  /** Evenly distribute the selected elements along an axis (one history entry). */
110053
110561
  distributeSelected(slideIndex, mode) {
@@ -110812,8 +111320,8 @@ class EditorToolbarComponent {
110812
111320
  this.slideIndex = input.required(/* @ts-ignore */
110813
111321
  ...(ngDevMode ? [{ debugName: "slideIndex" }] : /* istanbul ignore next */ []));
110814
111322
  this.editor = inject(EditorStateService);
110815
- /** Align needs ≥2 selected elements; distribute needs ≥3. */
110816
- this.canAlign = computed(() => this.editor.selectedIds().length >= 2, /* @ts-ignore */
111323
+ /** Align needs a selection (a lone element aligns to the slide); distribute needs ≥3. */
111324
+ this.canAlign = computed(() => this.editor.selectedIds().length >= 1, /* @ts-ignore */
110817
111325
  ...(ngDevMode ? [{ debugName: "canAlign" }] : /* istanbul ignore next */ []));
110818
111326
  this.canDistribute = computed(() => this.editor.selectedIds().length >= 3, /* @ts-ignore */
110819
111327
  ...(ngDevMode ? [{ debugName: "canDistribute" }] : /* istanbul ignore next */ []));
@@ -144035,7 +144543,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.6", ngImpor
144035
144543
  }], 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 }] }] } });
144036
144544
 
144037
144545
  // Generated by scripts/inline-shared.mjs from package.json. Do not edit.
144038
- const PPTX_ANGULAR_VIEWER_VERSION = "3.16.7";
144546
+ const PPTX_ANGULAR_VIEWER_VERSION = "3.17.1";
144039
144547
 
144040
144548
  /**
144041
144549
  * account-page.component.ts: File > Account content.
@@ -182558,4 +183066,4 @@ function cn(...values) {
182558
183066
  */
182559
183067
 
182560
183068
  export { CollaborationService as $, AFTER_ANIMATION_VALUES as A, AnimationAuthorPanelComponent as B, AnimationPanelComponent as C, AnimationPlaybackService as D, AutosaveRecoveryDialogComponent as E, AutosaveService as F, BroadcastDialogComponent as G, CHART_EDITOR_STYLES as H, CURSOR_PALETTE as I, CanvasFitService as J, ChartAxisOptionsComponent as K, ChartAxisStyleOptionsComponent as L, ChartComboTypeOptionsComponent as M, ChartDataEditorComponent as N, ChartDataLabelOptionsComponent as O, ChartDatapointMarkerOptionsComponent as P, ChartDatapointOptionsComponent as Q, ChartDisplayOptionsComponent as R, ChartElementViewComponent as S, ChartErrorBarOptionsComponent as T, ChartMarkerOptionsComponent as U, ChartPartSelectionService as V, ChartPrimitivesComponent as W, ChartRendererComponent as X, ChartTrendlineOptionsComponent as Y, ChartTypeSelectorComponent as Z, CollaborationCursorsComponent as _, ALIGN_OPTIONS as a, InsertSmartArtDialogComponent as a$, ColorChangedImageComponent as a0, CommentMarkersOverlayComponent as a1, CommentsPanelComponent as a2, CommentsService as a3, ComparePanelComponent as a4, ConnectorRendererComponent as a5, ConnectorTextOverlayComponent as a6, CustomShowsComponent as a7, DEFAULT_BOUNDS as a8, DEFAULT_BROADCAST_SERVER_URL as a9, EditorToolbarComponent as aA, EffectsPanelComponent as aB, ElementRendererComponent as aC, EmbeddedFontsService as aD, EncryptedFileDialogComponent as aE, EquationEditorDialogComponent as aF, EquationRendererComponent as aG, EquationTemplateGalleryComponent as aH, ExportProgressModalComponent as aI, ExportService as aJ, FieldContextService as aK, FindBarComponent as aL, FindReplaceBarComponent as aM, FollowModeBarComponent as aN, FontEmbeddingListComponent as aO, FontEmbeddingPanelComponent as aP, GALLERY_THEME_PRESETS as aQ, GOOGLE_WEBFONTS_LINK_ID as aR, GRIDLINE_COLOR$1 as aS, GoogleWebfontsService as aT, GradientPickerComponent as aU, HANDOUT_OPTIONS as aV, HeaderFooterDialogComponent as aW, HyperlinkDialogComponent as aX, ImagePropertiesPanelComponent as aY, InkDrawingService as aZ, InkRendererComponent as a_, DEFAULT_CANVAS_HEIGHT as aa, DEFAULT_CANVAS_WIDTH as ab, DEFAULT_COLOR_SCHEME as ac, DEFAULT_FILL_COLOR$1 as ad, DEFAULT_LAYOUT as ae, DEFAULT_PALETTE$1 as af, DEFAULT_PATTERN_FILL_PRESET as ag, DEFAULT_PRINT_SETTINGS as ah, DEFAULT_SLIDE_BACKGROUND as ai, DEFAULT_STROKE_COLOR as aj, DEFAULT_STYLE as ak, DEFAULT_TABLE_ROW_HEIGHT as al, DEFAULT_TEXT_COLOR$2 as am, DEFAULT_VIEWER_PROFILE as an, DIRECTIONAL_PRESETS as ao, DIRECTION_OPTIONS as ap, DocumentPropertiesCardComponent as aq, EFFECT_SOUND_CATALOGUE as ar, EMBEDDED_FONTS_STYLE_ID as as, EMPHASIS_PRESETS as at, ENTRANCE_PRESETS as au, TEMPLATES as av, EXIT_PRESETS as aw, EditorContextMenuComponent as ax, EditorHistory as ay, EditorStateService as az, ANIMATION_PRESET_CATEGORIES as b, RibbonArrangeSectionComponent as b$, InspectorPaneHeaderComponent as b0, InspectorPanelComponent as b1, IsMobileService as b2, KeepAnnotationsDialogComponent as b3, LOCALE_CATALOG as b4, LONG_PRESS_DURATION_MS as b5, LONG_PRESS_MOVE_TOLERANCE_PX as b6, LoadContentService as b7, LocalPresencePublisher as b8, MAX_ZOOM_SCALE as b9, PX_PER_INCH as bA, PasswordProtectionDialogComponent as bB, PasswordStrengthMeterComponent as bC, PowerPointViewerComponent as bD, PresentToolbarAutoHide as bE, PresentationAnnotationOverlayComponent as bF, PresentationAnnotationsService as bG, PresentationOverlayComponent as bH, PresentationPropertiesPanelComponent as bI, PresentationSettingsCardComponent as bJ, PresentationSubtitleBarComponent as bK, PresentationToolbarComponent as bL, PresentationTransitionOverlayComponent as bM, PresenterViewComponent as bN, PresenterWindowService as bO, PrintDialogComponent as bP, PrintService as bQ, PrintSettingsPanelComponent as bR, PropertiesDialogComponent as bS, REPEAT_MODE_OPTIONS as bT, RESIZE_HANDLES as bU, RULER_FONT_SIZE as bV, RULER_THICKNESS as bW, ReadingViewOverlayComponent as bX, RemoteSelectionOverlayComponent as bY, RibbonAnimationGalleryComponent as bZ, RibbonAnimationsSectionComponent as b_, MIN_ZOOM_SCALE as ba, MOTION_PATH_COLUMNS as bb, MediaPreviewComponent as bc, MediaPropertiesPanelComponent as bd, MediaRendererComponent as be, MediaTrimTimelineComponent as bf, MobileBottomBarComponent as bg, MobileMenuSheetComponent as bh, MobilePresenterViewComponent as bi, MobileSheetComponent as bj, MobileSlidesSheetComponent as bk, MobileToolbarComponent as bl, ModalDialogComponent as bm, Model3DRendererComponent as bn, NotesHandoutCardComponent as bo, NotesPanelComponent as bp, NotesToolbarComponent as bq, OleRendererComponent as br, OutlineViewOverlayComponent as bs, POWER_POINT_VIEWER_PROVIDERS as bt, PPTX_OPEN_ACCEPT as bu, PRESENTATION_OPEN_EXTENSIONS as bv, PRESENTER_CHANNEL_NAME as bw, PRESENTER_MSG_ORIGIN as bx, PRESENTER_TIMER_SEGMENT_MS as by, PX_PER_CM as bz, AUDIENCE_HASH as c, TABLE_STRUCTURE_TOGGLES as c$, RibbonColorPopoverComponent as c0, RibbonComponent as c1, RibbonDesignSectionComponent as c2, RibbonDrawSectionComponent as c3, RibbonDrawingGroupComponent as c4, RibbonEditingSectionComponent as c5, RibbonFileSectionComponent as c6, RibbonFontControlsComponent as c7, RibbonHomeSectionComponent as c8, RibbonHyperlinkButtonComponent as c9, SettingsAppearanceTabComponent as cA, SettingsDialogComponent as cB, SettingsLanguageTabComponent as cC, ShareDialogComponent as cD, ShortcutPanelComponent as cE, ShowOptionsFieldsetComponent as cF, ShowSlidesFieldsetComponent as cG, SignatureStrippedDialogComponent as cH, SignaturesPanelComponent as cI, SignaturesService as cJ, SlideBackgroundCardComponent 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, SlideTransitionCardComponent as cT, SlidesPanelComponent as cU, SmartArt3DRendererComponent as cV, SmartArt3DService as cW, SmartArtPreviewComponent as cX, SmartArtPropertiesComponent as cY, SmartArtRendererComponent as cZ, StatusBarComponent as c_, RibbonInsertFieldsComponent as ca, RibbonInsertSectionComponent as cb, RibbonMotionPathGalleryComponent as cc, RibbonParagraphControlsComponent as cd, RibbonPrimaryRowComponent as ce, RibbonReviewSectionComponent as cf, RibbonShapeExtrasComponent as cg, RibbonSlideshowSectionComponent as ch, RibbonTransitionsSectionComponent as ci, RibbonViewSectionComponent as cj, RulerGuidesService as ck, SEQUENCE_OPTIONS as cl, SEVERITY_GROUPS as cm, SEVERITY_LABELS as cn, SHORTCUT_REFERENCE_ITEMS as co, SLIDE_TRANSITION_KEYFRAMES as cp, DEFAULT_PALETTE as cq, PALETTES$1 as cr, SMART_ART_COLOR_SCHEMES as cs, SMART_ART_STYLE_OPTIONS as ct, SUB_ITEM_LABEL as cu, SVG_WARP_PRESETS as cv, SWIPE_MAX_VERTICAL_PX as cw, SWIPE_THRESHOLD_PX as cx, SelectionPaneComponent as cy, SetUpSlideShowDialogComponent as cz, AUDIENCE_NONCE_KEY as d, alignPatch as d$, TEXT_3D_BOTTOM_BEVEL_KEYS as d0, TEXT_3D_TOP_BEVEL_KEYS as d1, TEXT_DIRECTION_OPTIONS$1 as d2, THEME_CATALOG as d3, TIMING_CURVE_OPTIONS as d4, TRIGGER_OPTIONS as d5, TYPE_LABELS as d6, TableCellAdvancedFillComponent as d7, TableCellFormattingComponent as d8, TableDataEditorComponent as d9, ViewerExportService as dA, ViewerExtraDialogsComponent as dB, ViewerFileIOService as dC, ViewerFindReplaceService as dD, ViewerFormatPainterService as dE, ViewerInspectorPanelService as dF, ViewerKeyboardService as dG, ViewerMobileSheetService as dH, ViewerPresentationModeService as dI, ViewerThemeGalleryService as dJ, ViewerTouchGesturesService as dK, ViewerZoomService as dL, WEBM_MIME_CANDIDATES as dM, WriteBackScheduler as dN, ZERO_LINE_COLOR as dO, ZoomNavigationService as dP, ZoomRendererComponent as dQ, ZoomTargetService as dR, addCategory as dS, addCommentToList as dT, addGradientStopPatch as dU, addItem as dV, addSeries as dW, addSubItem as dX, advanceStep as dY, affordanceElements as dZ, aiToggleVisible as d_, TablePropertiesComponent as da, TableRendererComponent as db, TableResizeOverlayComponent as dc, TableSelectionService as dd, TagsCardComponent as de, Text3DBevelSectionComponent as df, Text3DPanelComponent as dg, TextAdvancedPanelComponent as dh, ThemeEditorFieldsComponent as di, ThemeGalleryComponent as dj, ThemeSelectorCardComponent as dk, TitleBarComponent as dl, TitleBarSearchComponent as dm, TransitionDirectionPickerComponent as dn, TransitionPreviewComponent as dp, VALIGN_OPTIONS as dq, VIEWER_THEME as dr, VersionHistoryPanelComponent as ds, ViewerCanvasEditingService as dt, ViewerCollabCursorService as du, ViewerCollaborationSessionService as dv, ViewerCompareService as dw, ViewerCustomShowsService as dx, ViewerDialogsService as dy, ViewerDocumentPropertiesService as dz, AVATAR_COLOR_SWATCHES as e, buildSmartArtNodes as e$, animationFor as e0, animationPresetLabelKey as e1, annotationMapToInkInserts as e2, applyAcceptedDiff as e3, applyAnimationPreset as e4, applyFindReplacements as e5, applyFormatToElement as e6, applyMove as e7, applyResize as e8, asMediaElement as e9, buildDuotoneFilterId as eA, buildEmbeddedFontStyles as eB, buildEquationElement as eC, buildEquationSegment as eD, buildFallbackViewModel as eE, buildFontFaceRule as eF, buildGradientFillCss as eG, buildGridlinesAndLabels as eH, buildHyperlinkPatch as eI, buildInkContainerStyle as eJ, buildInkStrokes as eK, buildLegend as eL, buildLiveInkStrokeView as eM, buildMarkTooltip as eN, buildModel3DContainerStyle as eO, buildModel3DViewModel as eP, buildOleActionModel as eQ, buildOleInfoRows as eR, buildPatternFillCss as eS, buildPieViewModel as eT, buildPrintHtmlDocument as eU, buildPropertiesPatch as eV, buildRadarViewModel as eW, buildRegionMapViewModel as eX, buildSaveSlides as eY, buildShareUrl as eZ, buildSmartArtInsertElement as e_, assignUserColor as ea, attachShowVisibilityPause as eb, attachTouchGestures as ec, axisTickValues as ed, beginDrawingNodeEdit as ee, beginNodeEdit as ef, bevelSizePatch as eg, boolFromEvent as eh, bringForward as ei, bringToFront as ej, buildBarActions as ek, buildBroadcastConfig as el, buildBroadcastViewerUrl as em, buildCategoryLabels as en, buildCellParagraphs as eo, buildChartViewModel as ep, buildChatLogExport as eq, buildChatLogMarkdown as er, buildChromeStyle as es, buildClearHyperlinkPatch as et, buildClickGroups as eu, buildColStyles as ev, buildCollaborationConfig as ew, buildComboViewModel as ex, buildCssGradientFromShapeStyle as ey, buildDuotoneFilter as ez, AXIS_LABEL_COLOR as f, computePieSlices as f$, buildStockViewModel as f0, buildSurfaceViewModel as f1, buildTableViewModel as f2, buildTreemapViewModel as f3, buildTrimFragment as f4, buildWaterfallViewModel as f5, buildZeroLine as f6, buildZoomContainerStyle as f7, buildZoomViewModel as f8, bulletIndentPx as f9, cn as fA, collectAccessibilityIssues as fB, collectElementText as fC, collectSlideText as fD, collectStoredChats as fE, collectUsedFontFamilies as fF, columnWidthStyle as fG, commitNodeText as fH, computeAlign as fI, computeAxisTitlePrimitives as fJ, computeBarRects as fK, computeBubbleRadius as fL, computeCornerHandle as fM, computeDistribute as fN, computeDrawingViewBox as fO, computeErrorBarPrimitives as fP, computeFocusTargets as fQ, computeGridSpacingPx as fR, computeHandleBoxes as fS, computeHandoutLayout as fT, computeIsMobile as fU, computeIsTablet as fV, computeLinePoints as fW, computeLinearRegression as fX, computePageCount as fY, computePieLayout as fZ, computePieSlicePath as f_, canAddTopLevelNode as fa, canEditSmartArtNodes as fb, canGroupSelection as fc, canRemoveTopLevelNode as fd, canSetStrokeWidth as fe, canStartBroadcast as ff, canStartShare as fg, canUngroupSelection as fh, canUseClipboard as fi, captionDisplayText as fj, cellRunStyle as fk, cellStyleToStyleMap as fl, cellTdStyle as fm, changeCountLabel as fn, changeIcon as fo, characterSpacingPatch as fp, chartPreserveAspectRatio as fq, checkFontAvailable as fr, clampCursorPosition as fs, clampGifDimensions as ft, clampIndex as fu, clampNotesFontSize as fv, clampScale as fw, clampStep as fx, clearAllLocalViewerData as fy, clearAudienceContent as fz, AccessibilityPanelComponent as g, fitZoom as g$, computePlotLayout as g0, computeRSquared as g1, computeRadarPoints as g2, computeResizeHandleBoxes as g3, computeRotateHandleBox as g4, computeScatterDots as g5, computeScatterXDomain as g6, computeSelectionBoxes as g7, computeSingleSelected as g8, computeSlideIndices as g9, describeSmartArtBounds as gA, disableGlowPatch as gB, disableInnerShadowPatch as gC, disableOuterShadowPatch as gD, disableReflectionPatch as gE, disableSoftEdgePatch as gF, duplicateElementById as gG, durationOf as gH, effectsStateOf as gI, enableGlowPatch as gJ, enableInnerShadowPatch as gK, enableOuterShadowPatch as gL, enableReflectionPatch as gM, enableSoftEdgePatch as gN, encodeGif as gO, endShowMediaCleanup as gP, estimatePageCount as gQ, exitPresentationFullscreen as gR, exportAiChatLogs as gS, extractPathPoints as gT, eyedropperAvailable as gU, fillColorOf$1 as gV, findInSlides as gW, findOwningSlideIndex as gX, findSlideIndexByElementId as gY, firstVisibleIndex as gZ, fitPolynomial as g_, computeSnap as ga, computeStackedBarRects as gb, computeStackedValueRange as gc, computeTrendlinePrimitives as gd, computeValueRange as ge, convertOmmlToMathMl as gf, copyFormatFromElement as gg, countAccessibilityIssues as gh, countAnnotationStrokes as gi, createAngularAiBridge as gj, createCustomShow as gk, createSwipeDismissDrag as gl, createWebrtcBundle as gm, createWebsocketBundle as gn, cssObjectToStyleMap as go, currentColorScheme as gp, currentLayout as gq, currentStyle as gr, defaultCssVars as gs, defaultRadius as gt, defaultThemeColors as gu, deleteElementsByIds as gv, deleteVersion as gw, demoteNode as gx, deriveModel3DBlobUrl as gy, derivePresenceList as gz, AccessibilityService as h, insertTableElementColumn as h$, focusTargetChips as h0, fontMimeForFormat as h1, fontSizeOf as h2, forgetSessionDeck as h3, formatAxisValue as h4, formatBytes as h5, formatCursorLabel as h6, formatElapsed as h7, formatFileSize as h8, formatPropertyDate as h9, getSessionTabId as hA, getShapeFillStrokeStyle as hB, getSlideBackgroundStyle as hC, getSlideTransitionAnimations as hD, getSmartArtNodeBounds as hE, getSpeechRecognitionCtor as hF, getTextBlockStyle as hG, getTextWarp as hH, getTouchDistance as hI, getWarpCategory as hJ, getWarpPath as hK, gradientStateFromStyle as hL, gradientStateOf as hM, gradientStatePatch as hN, gradientStopColorCommitPatch as hO, gridColumns as hP, groupIssuesBySeverity as hQ, hasAnimation as hR, hasCopyableFormat as hS, hasExistingLink as hT, hasExitedFullscreen as hU, hasGradientFill as hV, hasPressureVariation as hW, hasVisibleSlideAfter as hX, headerLabel as hY, imageDimensions as hZ, inkViewBox as h_, formatTime as ha, fpsToFrameIntervalMs as hb, generateBroadcastRoomId as hc, generateCommentId as hd, generateCustomShowId as he, generatePressureCircles as hf, generateTicks as hg, getClrChangeParams as hh, getContainerStyle as hi, getDuotoneFilterDef as hj, getEffectSoundAsset as hk, getEffectSoundState as hl, getImageSrc as hm, getLocalStorageUsageSummary as hn, getOleAriaLabel as ho, getOleBadgeLabel as hp, getOleDisplayName as hq, getOleDownloadFileName as hr, getOleTypeColor as hs, getOleTypeLabel as ht, getPasswordStrength as hu, getPatternSvg as hv, getPlaceholderStyle as hw, getVersions as hx, getResolvedShapeClipPath as hy, getResolvedShapeClipPathFor as hz, AccessibilityTextPanelComponent as i, normalizeFontFormat as i$, insertTableElementRow as i0, interpolateWidth as i1, isAudienceTab as i2, isBold as i3, isBrowserOpenableMime as i4, isChildNode as i5, isElementInteractive as i6, isInjectableUrl as i7, isItalic as i8, isLegacyBinaryPresentation as i9, mergeCaptionResults as iA, mergeDown as iB, mergeRight as iC, mergeSelection as iD, mergeTablesDirective as iE, moveElementBy as iF, moveNodeDown as iG, moveNodeUp as iH, msToFrameDelayCs as iI, narrowToCircle as iJ, narrowToPolygon as iK, narrowToRect as iL, newChartElement as iM, newEquationElement as iN, newPresetShapeElement as iO, newShapeElement as iP, newSmartArtElement as iQ, newTableElement as iR, newTextElement as iS, nextVisibleIndex as iT, nodeBold as iU, nodeEditBox as iV, nodeFillColor as iW, nodeFontColor as iX, nodeIdFromKey as iY, nodeItalic as iZ, nodeStyle as i_, isPpactionUrl as ia, isPresenterMessage as ib, isSigned as ic, isSupportedPresentationFile as id, isTextElement as ie, isTwoTableFocus as ig, isUnderline as ih, isUrlSafe as ii, isValidRoomId as ij, isViewportBackgroundPressTarget as ik, isZoomActivationKey as il, issueTrackKey as im, issueTypeLabel as io, keyToLabel as ip, lastVisibleIndex as iq, latexToMathml as ir, layoutConnectorPaints as is, layoutNodeLabels as it, linePointsToSvgString as iu, lineSpacingPatch as iv, loadAudienceContent as iw, loadSessionDeck as ix, mediaFallbackFor as iy, mediaSurfaceFor as iz, AccountPageComponent as j, resolveOleType as j$, normalizeSlidesPerPage as j0, normalizeValue as j1, numFromEvent as j2, ommlToMathml as j3, ooxmlDashToCssBorderStyle as j4, openNativeEyeDropper as j5, overallStatus as j6, paletteColor as j7, parseAudienceNonce as j8, parseNodeTextarea as j9, radarRingPoints as jA, readAsDataUrl as jB, recordWebm as jC, registerCrossSlideAudio as jD, rememberSessionDeck as jE, removeAnimation as jF, removeCategory as jG, removeTableElementColumn as jH, removeCommentFromList as jI, removeElementAnimation as jJ, removeGradientStopPatch as jK, removeNode as jL, removeTableElementRow as jM, removeSeries as jN, renderToCanvas as jO, reorderAnimationDown as jP, reorderAnimationUp as jQ, replaceInSlides as jR, replaceMatch as jS, requestPresentationFullscreen as jT, resizeElement as jU, resolveCaptionTracks as jV, resolveChartKind as jW, resolveFontVariant as jX, resolveHyperlinkHref as jY, resolveInteractiveElementId as jZ, resolveMediaSrc as j_, partitionSlides as ja, patchChartData as jb, patchChartStyle as jc, patchTableData as jd, patchTextStyle as je, patternPresetOptions as jf, pendingElementStyles as jg, pickColorByClickFallback as jh, pickFile as ji, pickSupportedMimeType as jj, planGifFrames as jk, planVideoSegments as jl, pointFromPointerEvent as jm, pointsToSvgPathD as jn, presenceToCursors as jo, presentationBaseName as jp, presentationStageStyle as jq, presenterTimerProgress as jr, presetByLayout as js, presetsForCategory as jt, pressuresToWidths as ju, prevVisibleIndex as jv, projectDrawingShapes as jw, promoteNode as jx, provideViewerTheme as jy, radarAngle as jz, ActionSettingsPanelComponent as k, setRepeatMode as k$, resolveParagraphBullet as k0, resolvePresenterNotes as k1, resolveProfileInitial as k2, resolveRegionCode as k3, resolveRibbonCanGroup as k4, resolveSlideAutoAdvanceMs as k5, resolvePalette as k6, resolveThemeCatalogEntry as k7, resolveTransitionDuration as k8, restoreSessionDeck as k9, setAfterAnimationColor as kA, setAnimationEmphasis as kB, setAnimationEntrance as kC, setAnimationExit as kD, setAxis as kE, setAxisLogScale as kF, setAxisTitleStyle as kG, setCategoryLabel as kH, setCellText as kI, setColorScheme as kJ, setDataLabels as kK, setDataPointExplosion as kL, setDataPointFill as kM, setDataPointLabel as kN, setDataPointMarker as kO, setDelay as kP, setDirection as kQ, setDuration as kR, setEffectSound as kS, setEffectStockSound as kT, setElementPosition as kU, setGridlineStyle as kV, setLayout as kW, setLegend as kX, setNodeStyle as kY, setNodeText as kZ, setRepeatCount as k_, revealedElementStyles as ka, routeOrthogonalConnector as kb, rowStyle as kc, rulerDragToGuidePosition as kd, rulerHighlight as ke, rulerStripTicks as kf, sampleColorFromSlide as kg, sanitizeColor as kh, sanitizeSlideIndex as ki, sanitizeUserName as kj, saveViewerProfile as kk, savedPresentationFileName as kl, scanAvailableFonts as km, searchSlides as kn, seedBroadcastFields as ko, seedHyperlinkDraft as kp, seedPropertiesDraft as kq, seedShareFields as kr, segmentFrameCount as ks, selectValue$3 as kt, sendBackward as ku, sendToBack as kv, sequentialColorScale as kw, serializeWriteBack as kx, seriesColor as ky, setAfterAnimation as kz, AdvancedChartEditorComponent as l, updateOuterShadowPatch as l$, setSequence as l0, setSeriesChartType as l1, setSeriesColor as l2, setSeriesErrorBars as l3, setSeriesMarker as l4, setSeriesName as l5, setSeriesTrendline as l6, setSeriesValue as l7, setStyle as l8, setTimingCurve as l9, strokeToInkElement as lA, strokeWidthOf as lB, styleShadowFilter as lC, surfaceColor as lD, textAdvancedPatch as lE, textAdvancedStateFromStyle as lF, textAdvancedStateOf as lG, textColorOf as lH, textDirectionPatch as lI, textFontSizePatch as lJ, textStyleOf as lK, textStylePatch as lL, themeStyle as lM, themeToCssVars as lN, thumbnailHeight as lO, thumbnailZoom as lP, toggleCommentResolvedInList as lQ, toggleNodeBold as lR, toggleNodeItalic as lS, toggleSheet as lT, topLevelNodeCount as lU, transformSelectedTextCase as lV, translationsEn as lW, updateElementById as lX, updateGlowPatch as lY, updateGradientStopPatch as lZ, updateInnerShadowPatch as l_, setTitle as la, setTrigger as lb, setTriggerShapeId as lc, shapeStylePatch$1 as ld, sheetAfterNavigate as le, shouldBlockClickAdvance as lf, shouldUseSvgWarp as lg, showDirectionPicker as lh, showsTemplateAffordance as li, signatureCountLabel as lj, signatureKey as lk, signatureTimestamp as ll, signerName as lm, statusLabel as ln, slideNumberOf as lo, slidesWithReappliedLayout as lp, smartArtNodes as lq, paletteColour as lr, snapToGridStep as ls, splitCursorCell as lt, splitMergedCell as lu, statusKind as lv, statusLabel$1 as lw, storeAudienceContent as lx, stringFromEvent$5 as ly, strokeColorOf as lz, AiChangeOverlayComponent as m, updateReflectionPatch as m0, vAlignPatch as m1, validatePassword as m2, validatePrintSettings as m3, validateRoomId as m4, valueToY as m5, vermilionDarkColors as m6, vermilionDarkTheme as m7, vermilionLightColors as m8, vermilionLightTheme as m9, vermilionRadius as ma, waypointsToPathD as mb, withManualLayouts as mc, worstStatus as md, zoomTargetSlideIndex as me, 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 };
182561
- //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-CY2-kaW3.mjs.map
183069
+ //# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-B3FNZYVL.mjs.map