pptx-angular-viewer 3.2.0 → 3.2.2
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.
- package/CHANGELOG.md +27 -0
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-B--KpLRw.mjs → pptx-angular-viewer-chat-history-idb-Cxqxc-c6.mjs} +2 -2
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-B--KpLRw.mjs.map → pptx-angular-viewer-chat-history-idb-Cxqxc-c6.mjs.map} +1 -1
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-MUEM_FFu.mjs → pptx-angular-viewer-pptx-angular-viewer-CblBWEKg.mjs} +1298 -419
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-MUEM_FFu.mjs.map → pptx-angular-viewer-pptx-angular-viewer-CblBWEKg.mjs.map} +1 -1
- package/fesm2022/pptx-angular-viewer.mjs +1 -1
- package/package.json +2 -2
- package/pptx-angular-viewer.css +1 -1
- package/types/pptx-angular-viewer.d.ts +10 -4
- package/types/pptx-angular-viewer.d.ts.map +1 -1
|
@@ -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, ElementRef, HostListener, afterNextRender, Renderer2, ViewEncapsulation, forwardRef, untracked, Directive } from '@angular/core';
|
|
4
4
|
import { TranslateService, TranslatePipe, translate } from '@ngx-translate/core';
|
|
5
|
-
import { THEME_PRESETS, guideEmuToPx, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, chartDataChangeType, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, formatAutoNumberMarker, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, lookupPresetShape, normalizeStShapeType, evaluateGuides, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode,
|
|
5
|
+
import { THEME_PRESETS, guideEmuToPx, getShapeClipPath, getAdjustmentAwareClipPath, getShapeClipPathFromPreset, getCloudPathForRendering, MIN_ELEMENT_SIZE as MIN_ELEMENT_SIZE$1, customGeometryPathsToSvgSubpaths, evaluatePresetShape, hasShapeProperties, ooxmlGradientAngleToCssDegrees, getShapeType, isImageLikeElement, getElementTextContent, getRoundRectRadiusPx as getRoundRectRadiusPx$1, applyDrawingColorTransforms as applyDrawingColorTransforms$1, hslToRgb as hslToRgb$1, PRESET_COLOR_MAP, getSubstituteFontFamily, parsePanoseString, hasTextProperties, stripXmlOrderSuffix, orderedXmlKey, chartDataChangeType, chartDataAddSeries, chartDataRemoveSeries, chartDataAddCategory, chartDataRemoveCategory, chartDataUpdatePoint, rebuildTableStructureInRawXml, updateCellTextInRawXml, deepCloneData, cloneTemplateElementsBySlideId, cloneSlide, EMU_PER_PX as EMU_PER_PX$2, DEFAULT_SCHEME_COLOR_MAP as DEFAULT_SCHEME_COLOR_MAP$1, formatAutoNumberMarker, getLinkedTextBoxSegments, deriveSlideTitle, svgPathToPolygons, THEME_COLOR_SCHEME_KEYS, createBuiltinVariables, resolveCoordinate, lookupPresetShape, normalizeStShapeType, evaluateGuides, PptxHandler, styleStroke, strokeFor, fitFontSize, nodeTextStyle, truncate, nodeOpacity, nodeStroke, nodeFill, styleShadow, buildTree, treeWidth, treeDepth, gearPoints, flattenNodes, interpretSmartArtLayout, addSmartArtNode, removeSmartArtNode, demoteSmartArtNode, promoteSmartArtNode, reorderSmartArtNode, deobfuscateFont, detectFontFormat, createEditorId, makeStoreAwareId, reassignDescendantIds, checkMissingAltText, checkMissingSlideTitle, checkLowContrast, checkComplexTables, checkBlankSlide, checkDuplicateTitles, createChartElement, detectFileFormat, serializePptxToJson, PPTX_JSON_MIME_TYPE, PptxMarkdownConverter, ThemePresets, formatCommentTimestamp as formatCommentTimestamp$1, EncryptedFileError, decodeXmlEntities, parseSignatureXml, groupElements, ungroupElements, cloneElement, updateSmartArtNodeText, setSmartArtNodeStyle, isInkElement, parseDataUrlToBytes, isZoomElement, SvgExporter, applyThemeToData, pptxActionToElementAction, elementActionToPptxAction, setChartTitle, setChartLegend, setChartDataLabels, setChartAxis, setChartSeriesTrendline, setChartSeriesErrorBars, setChartDataPointLabel, setChartAxisLogScale, setChartAxisTitleStyle, setChartAxisGridlineStyle, setChartSeriesMarker, setChartSeriesChartType, setChartDataPointFill, setChartDataPointMarker, setChartDataPointExplosion, getOleObjectTypeLabel, addSmartArtNodeAsChild, switchSmartArtLayout, SWITCHABLE_LAYOUT_TYPES, COLOR_MAP_ALIAS_KEYS, DEFAULT_COLOR_MAP, applyThemeOverrideToSlide, TRANSITION_VALID_DIRECTIONS } from 'pptx-viewer-core';
|
|
6
6
|
import DOMPurify from 'dompurify';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
import * as mcp from 'pptx-viewer-mcp';
|
|
@@ -2331,6 +2331,36 @@ function resolveComputedFill(ss, element) {
|
|
|
2331
2331
|
return {};
|
|
2332
2332
|
}
|
|
2333
2333
|
|
|
2334
|
+
const TEXT_ORIENTATION_IDENTITY = [1, 0, 0, 1];
|
|
2335
|
+
function isTextOrientationMatrix(value) {
|
|
2336
|
+
return (Array.isArray(value) &&
|
|
2337
|
+
value.length === 4 &&
|
|
2338
|
+
value.every((entry) => typeof entry === 'number' && Number.isFinite(entry)));
|
|
2339
|
+
}
|
|
2340
|
+
function multiplyTextOrientationMatrices(left, right) {
|
|
2341
|
+
return [
|
|
2342
|
+
left[0] * right[0] + left[2] * right[1],
|
|
2343
|
+
left[1] * right[0] + left[3] * right[1],
|
|
2344
|
+
left[0] * right[2] + left[2] * right[3],
|
|
2345
|
+
left[1] * right[2] + left[3] * right[3],
|
|
2346
|
+
];
|
|
2347
|
+
}
|
|
2348
|
+
function getElementOrientationMatrix(element) {
|
|
2349
|
+
const radians = ((Number(element.rotation) || 0) * Math.PI) / 180;
|
|
2350
|
+
const cosine = Math.cos(radians);
|
|
2351
|
+
const sine = Math.sin(radians);
|
|
2352
|
+
const rotation = [cosine, sine, -sine, cosine];
|
|
2353
|
+
const flip = [
|
|
2354
|
+
element.flipHorizontal ? -1 : 1,
|
|
2355
|
+
0,
|
|
2356
|
+
0,
|
|
2357
|
+
element.flipVertical ? -1 : 1,
|
|
2358
|
+
];
|
|
2359
|
+
return multiplyTextOrientationMatrices(rotation, flip);
|
|
2360
|
+
}
|
|
2361
|
+
function textOrientationAngleScore(matrix) {
|
|
2362
|
+
return Math.abs(Math.atan2(matrix[1], matrix[0]));
|
|
2363
|
+
}
|
|
2334
2364
|
/**
|
|
2335
2365
|
* Normalizes a raw stroke dash type string to a valid `StrokeDashType` enum value.
|
|
2336
2366
|
* Performs case-insensitive matching against all OOXML dash types.
|
|
@@ -2573,12 +2603,37 @@ function getElementTransformWithoutRotation(element) {
|
|
|
2573
2603
|
*/
|
|
2574
2604
|
function getTextCompensationTransform(element) {
|
|
2575
2605
|
const transforms = [];
|
|
2576
|
-
|
|
2606
|
+
const normalizedRotation = (((Number(element.rotation) || 0) % 360) + 360) % 360;
|
|
2607
|
+
const swapFlipAxis = normalizedRotation > 90 &&
|
|
2608
|
+
normalizedRotation < 270 &&
|
|
2609
|
+
element.flipHorizontal !== element.flipVertical;
|
|
2610
|
+
const compensateHorizontal = swapFlipAxis ? element.flipVertical : element.flipHorizontal;
|
|
2611
|
+
const compensateVertical = swapFlipAxis ? element.flipHorizontal : element.flipVertical;
|
|
2612
|
+
if (compensateHorizontal) {
|
|
2577
2613
|
transforms.push('scaleX(-1)');
|
|
2578
2614
|
}
|
|
2579
|
-
if (
|
|
2615
|
+
if (compensateVertical) {
|
|
2580
2616
|
transforms.push('scaleY(-1)');
|
|
2581
2617
|
}
|
|
2618
|
+
const ancestorGroupTransform = 'textStyle' in element ? element.textStyle?.ancestorGroupTransform : undefined;
|
|
2619
|
+
if (isTextOrientationMatrix(ancestorGroupTransform)) {
|
|
2620
|
+
const localCompensation = [
|
|
2621
|
+
compensateHorizontal ? -1 : 1,
|
|
2622
|
+
0,
|
|
2623
|
+
0,
|
|
2624
|
+
compensateVertical ? -1 : 1,
|
|
2625
|
+
];
|
|
2626
|
+
const visibleTransform = multiplyTextOrientationMatrices(multiplyTextOrientationMatrices(ancestorGroupTransform, getElementOrientationMatrix(element)), localCompensation);
|
|
2627
|
+
const determinant = visibleTransform[0] * visibleTransform[3] - visibleTransform[1] * visibleTransform[2];
|
|
2628
|
+
if (determinant < -1e-6) {
|
|
2629
|
+
const horizontalCandidate = multiplyTextOrientationMatrices(visibleTransform, [-1, 0, 0, 1]);
|
|
2630
|
+
const verticalCandidate = multiplyTextOrientationMatrices(visibleTransform, [1, 0, 0, -1]);
|
|
2631
|
+
transforms.push(textOrientationAngleScore(horizontalCandidate) <=
|
|
2632
|
+
textOrientationAngleScore(verticalCandidate)
|
|
2633
|
+
? 'scaleX(-1)'
|
|
2634
|
+
: 'scaleY(-1)');
|
|
2635
|
+
}
|
|
2636
|
+
}
|
|
2582
2637
|
return transforms.length > 0 ? transforms.join(' ') : undefined;
|
|
2583
2638
|
}
|
|
2584
2639
|
/**
|
|
@@ -2958,6 +3013,7 @@ function getOuterShadowCss(style, context) {
|
|
|
2958
3013
|
if (!style?.shadowColor || style.shadowColor === 'transparent') {
|
|
2959
3014
|
return undefined;
|
|
2960
3015
|
}
|
|
3016
|
+
const usesOoxmlDefaults = style.outerShadowXml !== undefined;
|
|
2961
3017
|
let offsetX;
|
|
2962
3018
|
let offsetY;
|
|
2963
3019
|
if (typeof style.shadowAngle === 'number' && typeof style.shadowDistance === 'number') {
|
|
@@ -2972,18 +3028,30 @@ function getOuterShadowCss(style, context) {
|
|
|
2972
3028
|
offsetX =
|
|
2973
3029
|
typeof style.shadowOffsetX === 'number' && Number.isFinite(style.shadowOffsetX)
|
|
2974
3030
|
? style.shadowOffsetX
|
|
2975
|
-
:
|
|
3031
|
+
: usesOoxmlDefaults
|
|
3032
|
+
? 0
|
|
3033
|
+
: 4;
|
|
2976
3034
|
offsetY =
|
|
2977
3035
|
typeof style.shadowOffsetY === 'number' && Number.isFinite(style.shadowOffsetY)
|
|
2978
3036
|
? style.shadowOffsetY
|
|
2979
|
-
:
|
|
3037
|
+
: usesOoxmlDefaults
|
|
3038
|
+
? 0
|
|
3039
|
+
: 4;
|
|
2980
3040
|
}
|
|
2981
|
-
const
|
|
3041
|
+
const rawBlur = typeof style.shadowBlur === 'number' && Number.isFinite(style.shadowBlur)
|
|
2982
3042
|
? Math.max(0, style.shadowBlur)
|
|
2983
|
-
:
|
|
3043
|
+
: usesOoxmlDefaults
|
|
3044
|
+
? 0
|
|
3045
|
+
: 6;
|
|
3046
|
+
// DrawingML `blurRad` is a radius while CSS shadows take a Gaussian
|
|
3047
|
+
// standard deviation. Halving authored OOXML radii matches PowerPoint's
|
|
3048
|
+
// falloff; host-authored CSS-style values retain their historical meaning.
|
|
3049
|
+
const blur = usesOoxmlDefaults ? rawBlur / 2 : rawBlur;
|
|
2984
3050
|
const opacity = typeof style.shadowOpacity === 'number' && Number.isFinite(style.shadowOpacity)
|
|
2985
3051
|
? clampUnitInterval(style.shadowOpacity)
|
|
2986
|
-
:
|
|
3052
|
+
: usesOoxmlDefaults
|
|
3053
|
+
? 1
|
|
3054
|
+
: 0.35;
|
|
2987
3055
|
// Honour @sx/@sy (1000ths of a percent, 100000 = 100%) as a box-shadow
|
|
2988
3056
|
// spread: a scaled-up shadow grows outward, a scaled-down one shrinks. This
|
|
2989
3057
|
// is a best-effort mapping (box-shadow has no true scale). @kx/@ky skew and
|
|
@@ -2994,6 +3062,77 @@ function getOuterShadowCss(style, context) {
|
|
|
2994
3062
|
const geometry = `${Math.round(offsetX)}px ${Math.round(offsetY)}px ${Math.round(blur)}px`;
|
|
2995
3063
|
return spread === 0 ? `${geometry} ${color}` : `${geometry} ${spread}px ${color}`;
|
|
2996
3064
|
}
|
|
3065
|
+
/**
|
|
3066
|
+
* Build pixel-composited outer shadows for images, text and groups.
|
|
3067
|
+
*
|
|
3068
|
+
* `box-shadow` follows the rectangular element box; PowerPoint shadows the
|
|
3069
|
+
* already-composited pixels. CSS `drop-shadow()` has those semantics.
|
|
3070
|
+
*/
|
|
3071
|
+
function getCompositeOuterShadowFilterCss(style, context) {
|
|
3072
|
+
if (!style) {
|
|
3073
|
+
return undefined;
|
|
3074
|
+
}
|
|
3075
|
+
const usesOoxmlDefaults = style.outerShadowXml !== undefined;
|
|
3076
|
+
const shadows = style.shadows && style.shadows.length > 0
|
|
3077
|
+
? style.shadows
|
|
3078
|
+
: style.shadowColor && style.shadowColor !== 'transparent'
|
|
3079
|
+
? [
|
|
3080
|
+
{
|
|
3081
|
+
angle: style.shadowAngle,
|
|
3082
|
+
distance: style.shadowDistance,
|
|
3083
|
+
offsetX: style.shadowOffsetX,
|
|
3084
|
+
offsetY: style.shadowOffsetY,
|
|
3085
|
+
blur: style.shadowBlur,
|
|
3086
|
+
color: style.shadowColor,
|
|
3087
|
+
opacity: style.shadowOpacity,
|
|
3088
|
+
},
|
|
3089
|
+
]
|
|
3090
|
+
: [];
|
|
3091
|
+
const parts = [];
|
|
3092
|
+
for (const shadow of shadows) {
|
|
3093
|
+
if (!shadow.color || shadow.color === 'transparent') {
|
|
3094
|
+
continue;
|
|
3095
|
+
}
|
|
3096
|
+
let offsetX;
|
|
3097
|
+
let offsetY;
|
|
3098
|
+
if (typeof shadow.angle === 'number' && typeof shadow.distance === 'number') {
|
|
3099
|
+
const angle = style.shadowRotateWithShape === false && typeof context?.rotation === 'number'
|
|
3100
|
+
? shadow.angle - context.rotation
|
|
3101
|
+
: shadow.angle;
|
|
3102
|
+
const angleRad = (angle * Math.PI) / 180;
|
|
3103
|
+
offsetX = Math.cos(angleRad) * shadow.distance;
|
|
3104
|
+
offsetY = Math.sin(angleRad) * shadow.distance;
|
|
3105
|
+
}
|
|
3106
|
+
else {
|
|
3107
|
+
offsetX =
|
|
3108
|
+
typeof shadow.offsetX === 'number' && Number.isFinite(shadow.offsetX)
|
|
3109
|
+
? shadow.offsetX
|
|
3110
|
+
: usesOoxmlDefaults
|
|
3111
|
+
? 0
|
|
3112
|
+
: 4;
|
|
3113
|
+
offsetY =
|
|
3114
|
+
typeof shadow.offsetY === 'number' && Number.isFinite(shadow.offsetY)
|
|
3115
|
+
? shadow.offsetY
|
|
3116
|
+
: usesOoxmlDefaults
|
|
3117
|
+
? 0
|
|
3118
|
+
: 4;
|
|
3119
|
+
}
|
|
3120
|
+
const rawBlur = typeof shadow.blur === 'number' && Number.isFinite(shadow.blur)
|
|
3121
|
+
? Math.max(0, shadow.blur)
|
|
3122
|
+
: usesOoxmlDefaults
|
|
3123
|
+
? 0
|
|
3124
|
+
: 6;
|
|
3125
|
+
const blur = usesOoxmlDefaults ? rawBlur / 2 : rawBlur;
|
|
3126
|
+
const opacity = typeof shadow.opacity === 'number' && Number.isFinite(shadow.opacity)
|
|
3127
|
+
? clampUnitInterval(shadow.opacity)
|
|
3128
|
+
: usesOoxmlDefaults
|
|
3129
|
+
? 1
|
|
3130
|
+
: 0.35;
|
|
3131
|
+
const color = colorWithOpacity(normalizeHexColor(shadow.color, DEFAULT_SHADOW_COLOR), opacity);
|
|
3132
|
+
parts.push(`drop-shadow(${Math.round(offsetX)}px ${Math.round(offsetY)}px ${Math.round(blur)}px ${color})`);
|
|
3133
|
+
}
|
|
3134
|
+
return parts.length > 0 ? parts.join(' ') : undefined;
|
|
3135
|
+
}
|
|
2997
3136
|
/**
|
|
2998
3137
|
* Derive a box-shadow spread (px) from outer-shadow `@sx`/`@sy` scale factors
|
|
2999
3138
|
* (1000ths of a percent; 100000 = 100%). The spread is proportional to the
|
|
@@ -3274,7 +3413,7 @@ function getEffectFilterCss(style, elementId) {
|
|
|
3274
3413
|
// Outer glow → drop-shadow
|
|
3275
3414
|
if (style.glowColor && style.glowColor !== 'transparent' && style.glowRadius) {
|
|
3276
3415
|
const glowOpacity = typeof style.glowOpacity === 'number' ? style.glowOpacity : 0.75;
|
|
3277
|
-
const glowRad = Math.
|
|
3416
|
+
const glowRad = Math.max(0, style.glowRadius / 2);
|
|
3278
3417
|
const glowCol = colorWithOpacity(normalizeHexColor(style.glowColor, DEFAULT_GLOW_COLOR), glowOpacity);
|
|
3279
3418
|
parts.push(`drop-shadow(0 0 ${glowRad}px ${glowCol})`);
|
|
3280
3419
|
}
|
|
@@ -3479,7 +3618,16 @@ function getComputedEffectStyle(element, options = {}) {
|
|
|
3479
3618
|
// container as well would shadow the bounding RECTANGLE on top of the line.
|
|
3480
3619
|
const paintsLineEffectsItself = element.type === 'connector' ||
|
|
3481
3620
|
getShapeType('shapeType' in element ? element.shapeType : undefined) === 'connector';
|
|
3482
|
-
const
|
|
3621
|
+
const shadowsCompositePixels = element.type === 'group' ||
|
|
3622
|
+
element.type === 'text' ||
|
|
3623
|
+
element.type === 'image' ||
|
|
3624
|
+
element.type === 'picture';
|
|
3625
|
+
const compositeShadow = shadowsCompositePixels
|
|
3626
|
+
? getCompositeOuterShadowFilterCss(style, { rotation: element.rotation })
|
|
3627
|
+
: undefined;
|
|
3628
|
+
const boxShadow = shadowsCompositePixels
|
|
3629
|
+
? undefined
|
|
3630
|
+
: getBoxShadowCss(style, { includeGlow: options.includeGlowBoxShadow }, { rotation: element.rotation });
|
|
3483
3631
|
// The line-level shadow (`a:ln/a:effectLst/a:outerShdw`) is part of the same
|
|
3484
3632
|
// box-shadow channel. Only React applied it to a shape container; folding it
|
|
3485
3633
|
// in here is what carries it to the other four bindings.
|
|
@@ -3491,7 +3639,7 @@ function getComputedEffectStyle(element, options = {}) {
|
|
|
3491
3639
|
const filter = getEffectFilterCss(style, element.id);
|
|
3492
3640
|
// As above for `a:ln/a:effectLst/a:glow`, which is a `drop-shadow` filter.
|
|
3493
3641
|
const lineGlow = paintsLineEffectsItself ? undefined : getLineGlowFilterCss(style);
|
|
3494
|
-
const filterParts = [filter, lineGlow].filter((part) => part !== undefined && part !== '');
|
|
3642
|
+
const filterParts = [compositeShadow, filter, lineGlow].filter((part) => part !== undefined && part !== '');
|
|
3495
3643
|
if (filterParts.length > 0) {
|
|
3496
3644
|
result.filter = filterParts.join(' ');
|
|
3497
3645
|
}
|
|
@@ -3754,6 +3902,59 @@ function outlinePathData(clipPath, width, height) {
|
|
|
3754
3902
|
}
|
|
3755
3903
|
return rect;
|
|
3756
3904
|
}
|
|
3905
|
+
const WEDGE_CALLOUT_PRESET_NAMES = new Set([
|
|
3906
|
+
'wedgerectcallout',
|
|
3907
|
+
'wedgeroundrectcallout',
|
|
3908
|
+
'wedgeellipsecallout',
|
|
3909
|
+
]);
|
|
3910
|
+
/** Whether a preset's pointer is part of the authored outline and may extend outside its body box. */
|
|
3911
|
+
function isWedgeCalloutPresetShape(shapeType) {
|
|
3912
|
+
return typeof shapeType === 'string' && WEDGE_CALLOUT_PRESET_NAMES.has(shapeType.toLowerCase());
|
|
3913
|
+
}
|
|
3914
|
+
function clipPathPolygonPoints(clipPath, width, height) {
|
|
3915
|
+
const asPolygon = /^polygon\((.*)\)$/su.exec(clipPath.trim());
|
|
3916
|
+
if (!asPolygon) {
|
|
3917
|
+
return [];
|
|
3918
|
+
}
|
|
3919
|
+
const toPx = (token, extent) => token.endsWith('%') ? (Number.parseFloat(token) / 100) * extent : Number.parseFloat(token);
|
|
3920
|
+
return asPolygon[1]
|
|
3921
|
+
.split(',')
|
|
3922
|
+
.map((pair) => pair.trim().split(/\s+/u))
|
|
3923
|
+
.filter((parts) => parts.length === 2)
|
|
3924
|
+
.map(([rawX, rawY]) => [toPx(rawX, width), toPx(rawY, height)])
|
|
3925
|
+
.filter(([x, y]) => Number.isFinite(x) && Number.isFinite(y));
|
|
3926
|
+
}
|
|
3927
|
+
/** Resolve a preset outline into SVG path data plus any authored out-of-box bounds. */
|
|
3928
|
+
function getPresetShapeVectorGeometry(shapeType, width, height, adjustments) {
|
|
3929
|
+
const normalizedWidth = Math.max(Number.isFinite(width) ? width : 0, 1);
|
|
3930
|
+
const normalizedHeight = Math.max(Number.isFinite(height) ? height : 0, 1);
|
|
3931
|
+
const clipPath = getResolvedShapeClipPathFor(shapeType, normalizedWidth, normalizedHeight, adjustments);
|
|
3932
|
+
const d = outlinePathData(clipPath, normalizedWidth, normalizedHeight);
|
|
3933
|
+
if (!d) {
|
|
3934
|
+
return undefined;
|
|
3935
|
+
}
|
|
3936
|
+
let minX = 0;
|
|
3937
|
+
let minY = 0;
|
|
3938
|
+
let maxX = normalizedWidth;
|
|
3939
|
+
let maxY = normalizedHeight;
|
|
3940
|
+
for (const [x, y] of clipPath
|
|
3941
|
+
? clipPathPolygonPoints(clipPath, normalizedWidth, normalizedHeight)
|
|
3942
|
+
: []) {
|
|
3943
|
+
minX = Math.min(minX, x);
|
|
3944
|
+
minY = Math.min(minY, y);
|
|
3945
|
+
maxX = Math.max(maxX, x);
|
|
3946
|
+
maxY = Math.max(maxY, y);
|
|
3947
|
+
}
|
|
3948
|
+
return {
|
|
3949
|
+
d,
|
|
3950
|
+
minX,
|
|
3951
|
+
minY,
|
|
3952
|
+
maxX,
|
|
3953
|
+
maxY,
|
|
3954
|
+
viewWidth: Math.max(maxX - minX, 1),
|
|
3955
|
+
viewHeight: Math.max(maxY - minY, 1),
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3757
3958
|
/**
|
|
3758
3959
|
* The parallel strands a line is painted with. A single (`sng`) line keeps the
|
|
3759
3960
|
* outline's own width verbatim so the ordinary case is byte-identical to a
|
|
@@ -20778,6 +20979,7 @@ function getEffectKeyframes(effect) {
|
|
|
20778
20979
|
*
|
|
20779
20980
|
* @module render/animation-color
|
|
20780
20981
|
*/
|
|
20982
|
+
const HEX_COLOR = /^#?[0-9a-f]{6}$/iu;
|
|
20781
20983
|
// ==========================================================================
|
|
20782
20984
|
// Colour conversion utilities
|
|
20783
20985
|
// ==========================================================================
|
|
@@ -20948,64 +21150,178 @@ function resolveCssProperties(attrName) {
|
|
|
20948
21150
|
* Returns an empty array for text/`color`-only animations, which do not need a
|
|
20949
21151
|
* vector renderer to relinquish its painted fill / stroke.
|
|
20950
21152
|
*/
|
|
20951
|
-
function resolveColorAnimationTargets(
|
|
20952
|
-
const
|
|
21153
|
+
function resolveColorAnimationTargets(animationOrAttribute) {
|
|
21154
|
+
const attributes = typeof animationOrAttribute === 'string' || animationOrAttribute === undefined
|
|
21155
|
+
? [animationOrAttribute]
|
|
21156
|
+
: colorAnimationComponents(animationOrAttribute).map((component) => component.targetAttribute);
|
|
20953
21157
|
const targets = [];
|
|
20954
|
-
|
|
20955
|
-
|
|
20956
|
-
|
|
20957
|
-
|
|
20958
|
-
|
|
21158
|
+
for (const attribute of attributes) {
|
|
21159
|
+
const cssProperties = resolveCssProperties(attribute);
|
|
21160
|
+
if (cssProperties.includes('fill') && !targets.includes('fill')) {
|
|
21161
|
+
targets.push('fill');
|
|
21162
|
+
}
|
|
21163
|
+
if (cssProperties.includes('stroke') && !targets.includes('stroke')) {
|
|
21164
|
+
targets.push('stroke');
|
|
21165
|
+
}
|
|
20959
21166
|
}
|
|
20960
21167
|
return targets;
|
|
20961
21168
|
}
|
|
20962
|
-
/**
|
|
20963
|
-
|
|
20964
|
-
|
|
20965
|
-
|
|
20966
|
-
|
|
20967
|
-
|
|
20968
|
-
|
|
20969
|
-
|
|
20970
|
-
|
|
20971
|
-
|
|
20972
|
-
|
|
20973
|
-
|
|
20974
|
-
|
|
20975
|
-
|
|
20976
|
-
|
|
21169
|
+
/** CSS custom properties that snapshot the shape paint before animation owns it. */
|
|
21170
|
+
const ANIMATION_COLOR_BASE_PROPERTIES = {
|
|
21171
|
+
color: '--pptx-animation-color-base',
|
|
21172
|
+
fill: '--pptx-animation-fill-base',
|
|
21173
|
+
stroke: '--pptx-animation-stroke-base',
|
|
21174
|
+
};
|
|
21175
|
+
/** Return every authored sibling behaviour, or the legacy single behaviour. */
|
|
21176
|
+
function colorAnimationComponents(colorAnim) {
|
|
21177
|
+
return colorAnim.components && colorAnim.components.length > 0
|
|
21178
|
+
? colorAnim.components
|
|
21179
|
+
: [colorAnim];
|
|
21180
|
+
}
|
|
21181
|
+
/** Clamp saturation / lightness to PowerPoint's legal range. */
|
|
21182
|
+
function clampPercent$1(value) {
|
|
21183
|
+
return Math.max(0, Math.min(100, value));
|
|
21184
|
+
}
|
|
21185
|
+
/** Apply a signed OOXML HSL delta to a concrete starting colour. */
|
|
21186
|
+
function applyHslDelta(fromColor, delta, progress) {
|
|
21187
|
+
const fromRgb = hexToRgb$2(fromColor);
|
|
21188
|
+
const fromHsl = rgbToHsl(fromRgb.r, fromRgb.g, fromRgb.b);
|
|
21189
|
+
const hue = (((fromHsl.h + delta.hue * progress) % 360) + 360) % 360;
|
|
21190
|
+
const saturation = clampPercent$1(fromHsl.s + delta.saturation * progress);
|
|
21191
|
+
const lightness = clampPercent$1(fromHsl.l + delta.lightness * progress);
|
|
21192
|
+
const rgb = hslToRgb(hue, saturation, lightness);
|
|
21193
|
+
return rgbToHex$2(rgb.r, rgb.g, rgb.b);
|
|
21194
|
+
}
|
|
21195
|
+
/** Stable compact number for generated CSS (also avoids `-0`). */
|
|
21196
|
+
function cssNumber(value) {
|
|
21197
|
+
const rounded = Math.round(value * 1_000_000) / 1_000_000;
|
|
21198
|
+
return String(Object.is(rounded, -0) ? 0 : rounded);
|
|
21199
|
+
}
|
|
21200
|
+
/** The pre-animation paint snapshot appropriate for one emitted CSS property. */
|
|
21201
|
+
function baseColorForProperty(property) {
|
|
21202
|
+
if (property === 'fill' || property === 'background-color' || property === 'backgroundColor') {
|
|
21203
|
+
return `var(${ANIMATION_COLOR_BASE_PROPERTIES.fill}, currentColor)`;
|
|
21204
|
+
}
|
|
21205
|
+
if (property === 'stroke' || property === 'border-color' || property === 'borderColor') {
|
|
21206
|
+
return `var(${ANIMATION_COLOR_BASE_PROPERTIES.stroke}, currentColor)`;
|
|
21207
|
+
}
|
|
21208
|
+
return `var(${ANIMATION_COLOR_BASE_PROPERTIES.color}, currentColor)`;
|
|
21209
|
+
}
|
|
21210
|
+
/** CSS relative-colour form for a `by` HSL animation with no explicit `from`. */
|
|
21211
|
+
function relativeHslColor(property, delta, progress) {
|
|
21212
|
+
const hue = cssNumber(delta.hue * progress);
|
|
21213
|
+
const saturation = cssNumber(delta.saturation * progress);
|
|
21214
|
+
const lightness = cssNumber(delta.lightness * progress);
|
|
21215
|
+
return `hsl(from ${baseColorForProperty(property)} calc(h + ${hue}) calc(s + ${saturation}) calc(l + ${lightness}) / alpha)`;
|
|
21216
|
+
}
|
|
21217
|
+
/** Resolve an ordinary absolute/RGB-delta component at one progress stop. */
|
|
21218
|
+
function absoluteComponentColor(component, progress) {
|
|
21219
|
+
const { colorSpace, direction, fromColor, toColor, byColor } = component;
|
|
20977
21220
|
let effectiveFrom;
|
|
20978
21221
|
let effectiveTo;
|
|
20979
21222
|
if (fromColor && toColor) {
|
|
21223
|
+
if (!HEX_COLOR.test(fromColor) || !HEX_COLOR.test(toColor)) {
|
|
21224
|
+
return undefined;
|
|
21225
|
+
}
|
|
20980
21226
|
effectiveFrom = fromColor;
|
|
20981
21227
|
effectiveTo = toColor;
|
|
20982
21228
|
}
|
|
20983
21229
|
else if (fromColor && byColor) {
|
|
20984
|
-
|
|
21230
|
+
if (!HEX_COLOR.test(fromColor) || !HEX_COLOR.test(byColor)) {
|
|
21231
|
+
return undefined;
|
|
21232
|
+
}
|
|
20985
21233
|
const fromRgb = hexToRgb$2(fromColor);
|
|
20986
21234
|
const byRgb = hexToRgb$2(byColor);
|
|
20987
21235
|
effectiveFrom = fromColor;
|
|
20988
21236
|
effectiveTo = rgbToHex$2(fromRgb.r + byRgb.r, fromRgb.g + byRgb.g, fromRgb.b + byRgb.b);
|
|
20989
21237
|
}
|
|
20990
21238
|
else if (toColor) {
|
|
20991
|
-
|
|
21239
|
+
if (!HEX_COLOR.test(toColor)) {
|
|
21240
|
+
return undefined;
|
|
21241
|
+
}
|
|
20992
21242
|
effectiveFrom = '#000000';
|
|
20993
21243
|
effectiveTo = toColor;
|
|
20994
21244
|
}
|
|
20995
21245
|
else {
|
|
20996
21246
|
return undefined;
|
|
20997
21247
|
}
|
|
20998
|
-
|
|
21248
|
+
return interpolateColor(effectiveFrom, effectiveTo, progress, colorSpace, direction);
|
|
21249
|
+
}
|
|
21250
|
+
/**
|
|
21251
|
+
* Build CSS `@keyframes` for a color animation (`p:animClr`).
|
|
21252
|
+
*
|
|
21253
|
+
* Generates keyframe stops at regular intervals with interpolated colors.
|
|
21254
|
+
* The CSS property is determined from the `targetAttribute` field which is
|
|
21255
|
+
* parsed from `p:attrNameLst` (e.g. "fillcolor" → `backgroundColor`).
|
|
21256
|
+
*
|
|
21257
|
+
* @param colorAnim - Parsed color animation data
|
|
21258
|
+
* @param keyframeName - Name for the generated `@keyframes` rule
|
|
21259
|
+
* @param steps - Number of keyframe stops (default 10 for smooth interpolation)
|
|
21260
|
+
* @returns CSS `@keyframes` string, or undefined if colors are missing
|
|
21261
|
+
*/
|
|
21262
|
+
function buildColorAnimationKeyframes(colorAnim, keyframeName, steps = 10) {
|
|
21263
|
+
const components = colorAnimationComponents(colorAnim);
|
|
21264
|
+
if (!components.some((component) => component.hslDelta !== undefined ||
|
|
21265
|
+
component.toColor !== undefined ||
|
|
21266
|
+
(component.fromColor !== undefined && component.byColor !== undefined))) {
|
|
21267
|
+
return undefined;
|
|
21268
|
+
}
|
|
20999
21269
|
const lines = [];
|
|
21270
|
+
let hasDeclarations = false;
|
|
21000
21271
|
const actualSteps = Math.max(2, steps);
|
|
21001
21272
|
for (let i = 0; i <= actualSteps; i++) {
|
|
21002
21273
|
const t = i / actualSteps;
|
|
21003
21274
|
const pct = Math.round(t * 100);
|
|
21004
|
-
const
|
|
21005
|
-
const
|
|
21275
|
+
const declarations = [];
|
|
21276
|
+
for (const component of components) {
|
|
21277
|
+
const cssProperties = resolveCssProperties(component.targetAttribute);
|
|
21278
|
+
if (component.hslDelta) {
|
|
21279
|
+
if (component.fromColor && !HEX_COLOR.test(component.fromColor)) {
|
|
21280
|
+
continue;
|
|
21281
|
+
}
|
|
21282
|
+
for (const property of cssProperties) {
|
|
21283
|
+
const color = component.fromColor
|
|
21284
|
+
? applyHslDelta(component.fromColor, component.hslDelta, t)
|
|
21285
|
+
: relativeHslColor(property, component.hslDelta, t);
|
|
21286
|
+
declarations.push(`${property}: ${color};`);
|
|
21287
|
+
hasDeclarations = true;
|
|
21288
|
+
}
|
|
21289
|
+
continue;
|
|
21290
|
+
}
|
|
21291
|
+
const color = absoluteComponentColor(component, t);
|
|
21292
|
+
if (color) {
|
|
21293
|
+
declarations.push(...cssProperties.map((property) => `${property}: ${color};`));
|
|
21294
|
+
hasDeclarations = true;
|
|
21295
|
+
}
|
|
21296
|
+
}
|
|
21297
|
+
const decls = declarations.join(' ');
|
|
21006
21298
|
lines.push(`\t${pct}% { ${decls} }`);
|
|
21007
21299
|
}
|
|
21008
|
-
return `@keyframes ${keyframeName} {\n${lines.join('\n')}\n}
|
|
21300
|
+
return hasDeclarations ? `@keyframes ${keyframeName} {\n${lines.join('\n')}\n}` : undefined;
|
|
21301
|
+
}
|
|
21302
|
+
|
|
21303
|
+
/**
|
|
21304
|
+
* Build CSS custom properties only while a paint animation is active, keeping
|
|
21305
|
+
* ordinary rendering and existing style snapshots unchanged.
|
|
21306
|
+
*/
|
|
21307
|
+
function getAnimationColorBaseStyle(element, options = {}) {
|
|
21308
|
+
if (!hasShapeProperties(element) || (!options.animatesFill && !options.animatesStroke)) {
|
|
21309
|
+
return {};
|
|
21310
|
+
}
|
|
21311
|
+
const style = {};
|
|
21312
|
+
if (options.animatesFill) {
|
|
21313
|
+
const fill = getComputedFillStyle(element, options.parentGroupFill);
|
|
21314
|
+
style[ANIMATION_COLOR_BASE_PROPERTIES.fill] =
|
|
21315
|
+
fill?.backgroundColor ?? element.shapeStyle?.fillColor ?? 'currentColor';
|
|
21316
|
+
}
|
|
21317
|
+
if (options.animatesStroke) {
|
|
21318
|
+
const stroke = getComputedStrokeStyle(element);
|
|
21319
|
+
style[ANIMATION_COLOR_BASE_PROPERTIES.stroke] =
|
|
21320
|
+
stroke.borderColor ?? element.shapeStyle?.strokeColor ?? 'currentColor';
|
|
21321
|
+
}
|
|
21322
|
+
style[ANIMATION_COLOR_BASE_PROPERTIES.color] =
|
|
21323
|
+
(hasTextProperties(element) ? element.textStyle?.color : undefined) ?? 'currentColor';
|
|
21324
|
+
return style;
|
|
21009
21325
|
}
|
|
21010
21326
|
|
|
21011
21327
|
/**
|
|
@@ -21098,7 +21414,7 @@ function resolveStepBuildDescriptor(anim) {
|
|
|
21098
21414
|
// Playback-time progress helpers
|
|
21099
21415
|
// ==========================================================================
|
|
21100
21416
|
/** Clamp a value into the closed unit interval. */
|
|
21101
|
-
function clamp01$
|
|
21417
|
+
function clamp01$3(value) {
|
|
21102
21418
|
return Math.max(0, Math.min(1, value));
|
|
21103
21419
|
}
|
|
21104
21420
|
/**
|
|
@@ -21114,7 +21430,7 @@ function computeBuildProgress(timing, elapsedMs) {
|
|
|
21114
21430
|
if (timing.durationMs <= 0) {
|
|
21115
21431
|
return elapsedMs >= timing.delayMs ? 1 : 0;
|
|
21116
21432
|
}
|
|
21117
|
-
return clamp01$
|
|
21433
|
+
return clamp01$3((elapsedMs - timing.delayMs) / timing.durationMs);
|
|
21118
21434
|
}
|
|
21119
21435
|
/**
|
|
21120
21436
|
* Map a 0..1 build progress to a whole number of revealed stages given the
|
|
@@ -21129,7 +21445,7 @@ function revealedStageCount(progress, totalStages) {
|
|
|
21129
21445
|
if (totalStages <= 0) {
|
|
21130
21446
|
return 0;
|
|
21131
21447
|
}
|
|
21132
|
-
const p = clamp01$
|
|
21448
|
+
const p = clamp01$3(progress);
|
|
21133
21449
|
if (p <= 0) {
|
|
21134
21450
|
return 0;
|
|
21135
21451
|
}
|
|
@@ -21305,6 +21621,138 @@ function revealedSmartArtNodeCount(nodes, build) {
|
|
|
21305
21621
|
return revealedStageCount(build.progress, nodes.length);
|
|
21306
21622
|
}
|
|
21307
21623
|
|
|
21624
|
+
const ATTRIBUTE_KINDS = {
|
|
21625
|
+
opacity: 'opacity',
|
|
21626
|
+
ppt_h: 'scaleY',
|
|
21627
|
+
ppt_w: 'scaleX',
|
|
21628
|
+
ppt_x: 'translateX',
|
|
21629
|
+
ppt_y: 'translateY',
|
|
21630
|
+
'style.opacity': 'opacity',
|
|
21631
|
+
'style.rotation': 'rotation',
|
|
21632
|
+
};
|
|
21633
|
+
const SELF_REFERENCE_RE = /^#?ppt_([whxy])(?:([+-])(\d*\.?\d+))?$/iu;
|
|
21634
|
+
function clamp01$2(value) {
|
|
21635
|
+
return Math.max(0, Math.min(1, value));
|
|
21636
|
+
}
|
|
21637
|
+
function numericValue(keyframe) {
|
|
21638
|
+
const parsed = Number(keyframe.value);
|
|
21639
|
+
return Number.isFinite(parsed) ? parsed : undefined;
|
|
21640
|
+
}
|
|
21641
|
+
function parseSelfReference(keyframe, expectedAxis) {
|
|
21642
|
+
const token = String(keyframe.value).replaceAll(' ', '').toLowerCase();
|
|
21643
|
+
const match = SELF_REFERENCE_RE.exec(token);
|
|
21644
|
+
if (!match || match[1] !== expectedAxis) {
|
|
21645
|
+
return undefined;
|
|
21646
|
+
}
|
|
21647
|
+
const magnitude = match[3] === undefined ? 0 : Number(match[3]);
|
|
21648
|
+
if (!Number.isFinite(magnitude)) {
|
|
21649
|
+
return undefined;
|
|
21650
|
+
}
|
|
21651
|
+
return { offset: match[2] === '-' ? -magnitude : magnitude };
|
|
21652
|
+
}
|
|
21653
|
+
function parseValue(kind, keyframe) {
|
|
21654
|
+
if (kind === 'rotation') {
|
|
21655
|
+
return numericValue(keyframe);
|
|
21656
|
+
}
|
|
21657
|
+
if (kind === 'opacity') {
|
|
21658
|
+
const value = numericValue(keyframe);
|
|
21659
|
+
return value === undefined ? undefined : clamp01$2(value);
|
|
21660
|
+
}
|
|
21661
|
+
if (kind === 'scaleX' || kind === 'scaleY') {
|
|
21662
|
+
const numeric = numericValue(keyframe);
|
|
21663
|
+
if (numeric === 0) {
|
|
21664
|
+
return 0;
|
|
21665
|
+
}
|
|
21666
|
+
const axis = kind === 'scaleX' ? 'w' : 'h';
|
|
21667
|
+
const reference = parseSelfReference(keyframe, axis);
|
|
21668
|
+
return reference?.offset === 0 ? 1 : undefined;
|
|
21669
|
+
}
|
|
21670
|
+
const axis = kind === 'translateX' ? 'x' : 'y';
|
|
21671
|
+
const reference = parseSelfReference(keyframe, axis);
|
|
21672
|
+
return reference === undefined ? undefined : reference.offset * 100;
|
|
21673
|
+
}
|
|
21674
|
+
function parseComponent(component, effectDurationMs) {
|
|
21675
|
+
const kind = ATTRIBUTE_KINDS[component.attrName];
|
|
21676
|
+
if (!kind) {
|
|
21677
|
+
return undefined;
|
|
21678
|
+
}
|
|
21679
|
+
const stops = [];
|
|
21680
|
+
for (const keyframe of component.keyframes) {
|
|
21681
|
+
if (typeof keyframe.tm !== 'number' || !Number.isFinite(keyframe.tm)) {
|
|
21682
|
+
return undefined;
|
|
21683
|
+
}
|
|
21684
|
+
const value = parseValue(kind, keyframe);
|
|
21685
|
+
if (value === undefined) {
|
|
21686
|
+
return undefined;
|
|
21687
|
+
}
|
|
21688
|
+
stops.push({ progress: clamp01$2(keyframe.tm / 100000), value });
|
|
21689
|
+
}
|
|
21690
|
+
if (stops.length < 2) {
|
|
21691
|
+
return undefined;
|
|
21692
|
+
}
|
|
21693
|
+
stops.sort((left, right) => left.progress - right.progress);
|
|
21694
|
+
return {
|
|
21695
|
+
delayMs: component.delayMs ?? 0,
|
|
21696
|
+
durationMs: component.durationMs ?? effectDurationMs,
|
|
21697
|
+
kind,
|
|
21698
|
+
stops,
|
|
21699
|
+
};
|
|
21700
|
+
}
|
|
21701
|
+
function valueAt(component, progress, effectDurationMs) {
|
|
21702
|
+
const elapsedMs = progress * effectDurationMs - component.delayMs;
|
|
21703
|
+
const localProgress = clamp01$2(elapsedMs / Math.max(1, component.durationMs));
|
|
21704
|
+
const first = component.stops[0];
|
|
21705
|
+
const last = component.stops[component.stops.length - 1];
|
|
21706
|
+
if (localProgress <= first.progress) {
|
|
21707
|
+
return first.value;
|
|
21708
|
+
}
|
|
21709
|
+
if (localProgress >= last.progress) {
|
|
21710
|
+
return last.value;
|
|
21711
|
+
}
|
|
21712
|
+
for (let index = 1; index < component.stops.length; index += 1) {
|
|
21713
|
+
const right = component.stops[index];
|
|
21714
|
+
const left = component.stops[index - 1];
|
|
21715
|
+
if (localProgress <= right.progress) {
|
|
21716
|
+
const span = Math.max(Number.EPSILON, right.progress - left.progress);
|
|
21717
|
+
const ratio = (localProgress - left.progress) / span;
|
|
21718
|
+
return left.value + (right.value - left.value) * ratio;
|
|
21719
|
+
}
|
|
21720
|
+
}
|
|
21721
|
+
return last.value;
|
|
21722
|
+
}
|
|
21723
|
+
/** Build a normalized playback model for supported generic `p:anim` transforms. */
|
|
21724
|
+
function createAttributeTransformModel(anim) {
|
|
21725
|
+
const effectDurationMs = Math.max(1, anim.durationMs ?? 1000);
|
|
21726
|
+
const supportedComponents = (anim.attributeAnimations ?? []).filter((component) => ATTRIBUTE_KINDS[component.attrName] !== undefined);
|
|
21727
|
+
const components = supportedComponents.map((component) => parseComponent(component, effectDurationMs));
|
|
21728
|
+
const parsedComponents = components.filter((component) => component !== undefined);
|
|
21729
|
+
// A partial transform is worse than the preset fallback: one unrepresentable
|
|
21730
|
+
// sibling can carry the primary movement while an identity sibling still
|
|
21731
|
+
// parses, causing the incomplete dynamic keyframe to suppress that preset.
|
|
21732
|
+
if (parsedComponents.length !== supportedComponents.length) {
|
|
21733
|
+
return undefined;
|
|
21734
|
+
}
|
|
21735
|
+
if (parsedComponents.length === 0) {
|
|
21736
|
+
return undefined;
|
|
21737
|
+
}
|
|
21738
|
+
const progressSet = new Set([0, 1]);
|
|
21739
|
+
for (const component of parsedComponents) {
|
|
21740
|
+
for (const stop of component.stops) {
|
|
21741
|
+
progressSet.add(clamp01$2((component.delayMs + stop.progress * component.durationMs) / effectDurationMs));
|
|
21742
|
+
}
|
|
21743
|
+
}
|
|
21744
|
+
return {
|
|
21745
|
+
progresses: [...progressSet].sort((left, right) => left - right),
|
|
21746
|
+
stateAt(progress) {
|
|
21747
|
+
const state = {};
|
|
21748
|
+
for (const component of parsedComponents) {
|
|
21749
|
+
state[component.kind] = valueAt(component, progress, effectDurationMs);
|
|
21750
|
+
}
|
|
21751
|
+
return state;
|
|
21752
|
+
},
|
|
21753
|
+
};
|
|
21754
|
+
}
|
|
21755
|
+
|
|
21308
21756
|
/**
|
|
21309
21757
|
* `animation-motion-path`: parse an OOXML `p:animMotion/@path` string into a
|
|
21310
21758
|
* dense list of waypoints (percentages of the element box) suitable for driving
|
|
@@ -21422,214 +21870,169 @@ function parseMotionPathPoints(motionPath) {
|
|
|
21422
21870
|
}
|
|
21423
21871
|
|
|
21424
21872
|
/**
|
|
21425
|
-
*
|
|
21426
|
-
*
|
|
21427
|
-
*
|
|
21428
|
-
* behaviour (opacity or colour).
|
|
21873
|
+
* Compose authored motion, rotation, and scale behaviours into one CSS
|
|
21874
|
+
* keyframe block. OOXML permits those behaviours to share one effect wrapper,
|
|
21875
|
+
* while CSS animations that each write `transform` would overwrite each other.
|
|
21429
21876
|
*
|
|
21430
|
-
*
|
|
21431
|
-
* `animation-timeline-helpers` already handle the RELATIVE `@by` form
|
|
21432
|
-
* (`rotationBy` / `scaleByX` / `scaleByY`); this module covers the sibling
|
|
21433
|
-
* absolute form, which OOXML allows instead of (or alongside) `@by`:
|
|
21434
|
-
* ECMA-376 S19.5.7 CT_TLAnimateRotationBehavior and S19.5.8
|
|
21435
|
-
* CT_TLAnimateScaleBehavior both make `from`/`to`/`by` independently
|
|
21436
|
-
* optional. Only the relative form was ever read, so a deck that authored
|
|
21437
|
-
* "rotate from 0 to 180" (no `@by`) or "scale from 50% to 150%" produced no
|
|
21438
|
-
* rotation/scale keyframes at all and the effect silently did nothing.
|
|
21439
|
-
*
|
|
21440
|
-
* `p:tavLst` (ECMA-376 S19.5.30 CT_TLAnimVariantList) is schema-generic: a
|
|
21441
|
-
* `p:anim` node can drive ANY attribute its `p:attrNameLst/p:attrName` names,
|
|
21442
|
-
* and until the core parser surfaced that name (`PptxNativeAnimation.attrName`)
|
|
21443
|
-
* this module could only guess from the keyframe VALUE shape, which is why it
|
|
21444
|
-
* only ever recognised a numeric `[0, 1]` ramp as opacity. With the attribute
|
|
21445
|
-
* name available, {@link buildOpacityTavKeyframe} now confirms it against a
|
|
21446
|
-
* known opacity name instead of trusting the value shape alone, and
|
|
21447
|
-
* {@link buildColorTavKeyframe} covers the sibling case: a multi-stop colour
|
|
21448
|
-
* ramp on `fillcolor` / `fill.color` / `style.color` / `stroke.color`, reusing
|
|
21449
|
-
* the same attribute -> CSS-property mapping as the dedicated `p:animClr`
|
|
21450
|
-
* behaviour (`animation-color.ts`). Every other attribute name (position,
|
|
21451
|
-
* size, and anything this module cannot confirm a CSS mapping for) is left on
|
|
21452
|
-
* the caller's canned-timing fallback; see `docs/guide/limitations.md`.
|
|
21453
|
-
*
|
|
21454
|
-
* @module render/animation-timeline-absolute
|
|
21455
|
-
*/
|
|
21456
|
-
/**
|
|
21457
|
-
* Build an absolute-rotation `@keyframes` block from `rotationFrom`/
|
|
21458
|
-
* `rotationTo`, or `undefined` when the animation has no absolute rotation
|
|
21459
|
-
* (including when a relative `rotationBy` is present, which the caller
|
|
21460
|
-
* already handles and takes priority over this).
|
|
21461
|
-
*
|
|
21462
|
-
* A `from` with no `to` (or vice versa) still produces a sensible sweep: the
|
|
21463
|
-
* missing bound defaults to the other one's value so the animation is a
|
|
21464
|
-
* no-op turn rather than being dropped, matching how PowerPoint treats a
|
|
21465
|
-
* partially-specified rotation as ending at its one given angle.
|
|
21877
|
+
* @module render/animation-transform-keyframes
|
|
21466
21878
|
*/
|
|
21467
|
-
function
|
|
21468
|
-
|
|
21469
|
-
|
|
21879
|
+
function slideOffset(percent, axis) {
|
|
21880
|
+
const fallback = axis === 'w' ? '1280px' : '720px';
|
|
21881
|
+
return `calc(var(--pptx-slide-${axis}, ${fallback}) * ${(percent / 100).toFixed(4)})`;
|
|
21882
|
+
}
|
|
21883
|
+
function hasRotation(anim) {
|
|
21884
|
+
return (anim.rotationBy !== undefined ||
|
|
21885
|
+
anim.rotationFrom !== undefined ||
|
|
21886
|
+
anim.rotationTo !== undefined);
|
|
21887
|
+
}
|
|
21888
|
+
function hasScale(anim) {
|
|
21889
|
+
return (anim.scaleByX !== undefined ||
|
|
21890
|
+
anim.scaleByY !== undefined ||
|
|
21891
|
+
anim.scaleFromX !== undefined ||
|
|
21892
|
+
anim.scaleFromY !== undefined ||
|
|
21893
|
+
anim.scaleToX !== undefined ||
|
|
21894
|
+
anim.scaleToY !== undefined);
|
|
21895
|
+
}
|
|
21896
|
+
/** True when the parsed animation contains an authored transform behaviour. */
|
|
21897
|
+
function hasAuthoredTransform(anim) {
|
|
21898
|
+
return (Boolean(anim.motionPath) ||
|
|
21899
|
+
hasRotation(anim) ||
|
|
21900
|
+
hasScale(anim) ||
|
|
21901
|
+
createAttributeTransformModel(anim) !== undefined);
|
|
21902
|
+
}
|
|
21903
|
+
function rotationAt(anim, progress) {
|
|
21904
|
+
const from = anim.rotationFrom ?? 0;
|
|
21905
|
+
const to = anim.rotationTo ?? (anim.rotationBy !== undefined ? from + anim.rotationBy : from);
|
|
21906
|
+
return from + (to - from) * progress;
|
|
21907
|
+
}
|
|
21908
|
+
function scaleAt(anim, axis, progress) {
|
|
21909
|
+
const from = axis === 'x' ? (anim.scaleFromX ?? 1) : (anim.scaleFromY ?? 1);
|
|
21910
|
+
const authoredTo = axis === 'x' ? anim.scaleToX : anim.scaleToY;
|
|
21911
|
+
const by = axis === 'x' ? anim.scaleByX : anim.scaleByY;
|
|
21912
|
+
const to = authoredTo ?? (by !== undefined ? from * by : from);
|
|
21913
|
+
return from + (to - from) * progress;
|
|
21914
|
+
}
|
|
21915
|
+
function opacityAt(anim, progress) {
|
|
21916
|
+
if (anim.presetClass === 'entr') {
|
|
21917
|
+
return progress;
|
|
21918
|
+
}
|
|
21919
|
+
if (anim.presetClass === 'exit') {
|
|
21920
|
+
return 1 - progress;
|
|
21470
21921
|
}
|
|
21471
|
-
|
|
21472
|
-
|
|
21922
|
+
return undefined;
|
|
21923
|
+
}
|
|
21924
|
+
function formatNumber(value, fractionDigits = 4) {
|
|
21925
|
+
return String(Number(value.toFixed(fractionDigits)));
|
|
21926
|
+
}
|
|
21927
|
+
function tangentAngle(points, index) {
|
|
21928
|
+
const point = points[index];
|
|
21929
|
+
const next = index < points.length - 1 ? points[index + 1] : point;
|
|
21930
|
+
const previous = index > 0 ? points[index - 1] : point;
|
|
21931
|
+
const dx = index < points.length - 1 ? next.x - point.x : point.x - previous.x;
|
|
21932
|
+
const dy = index < points.length - 1 ? next.y - point.y : point.y - previous.y;
|
|
21933
|
+
return Math.atan2(dy, dx) * (180 / Math.PI);
|
|
21934
|
+
}
|
|
21935
|
+
function rotateMotionPathPoints(points, anim) {
|
|
21936
|
+
const angle = anim.motionPathRotationAngle ?? 0;
|
|
21937
|
+
if (!Number.isFinite(angle) || angle === 0) {
|
|
21938
|
+
return [...points];
|
|
21473
21939
|
}
|
|
21474
|
-
const
|
|
21475
|
-
const
|
|
21476
|
-
const
|
|
21940
|
+
const radians = (angle * Math.PI) / 180;
|
|
21941
|
+
const cosine = Math.cos(radians);
|
|
21942
|
+
const sine = Math.sin(radians);
|
|
21943
|
+
const centerX = anim.motionPathRotationCenterX ?? 0;
|
|
21944
|
+
const centerY = anim.motionPathRotationCenterY ?? 0;
|
|
21945
|
+
return points.map((point) => {
|
|
21946
|
+
const x = point.x - centerX;
|
|
21947
|
+
const y = point.y - centerY;
|
|
21948
|
+
return {
|
|
21949
|
+
x: centerX + x * cosine - y * sine,
|
|
21950
|
+
y: centerY + x * sine + y * cosine,
|
|
21951
|
+
};
|
|
21952
|
+
});
|
|
21953
|
+
}
|
|
21954
|
+
function pointAt(points, progress) {
|
|
21955
|
+
if (points.length < 2) {
|
|
21956
|
+
return { x: 0, y: 0 };
|
|
21957
|
+
}
|
|
21958
|
+
const position = progress * (points.length - 1);
|
|
21959
|
+
const leftIndex = Math.floor(position);
|
|
21960
|
+
const rightIndex = Math.min(points.length - 1, leftIndex + 1);
|
|
21961
|
+
const ratio = position - leftIndex;
|
|
21962
|
+
const left = points[leftIndex];
|
|
21963
|
+
const right = points[rightIndex];
|
|
21477
21964
|
return {
|
|
21478
|
-
|
|
21479
|
-
|
|
21965
|
+
x: left.x + (right.x - left.x) * ratio,
|
|
21966
|
+
y: left.y + (right.y - left.y) * ratio,
|
|
21480
21967
|
};
|
|
21481
21968
|
}
|
|
21482
|
-
|
|
21483
|
-
|
|
21484
|
-
|
|
21485
|
-
|
|
21486
|
-
|
|
21487
|
-
|
|
21488
|
-
* A missing `from` defaults to 1 (unscaled) and a missing `to` defaults to
|
|
21489
|
-
* the `from` value, mirroring {@link buildAbsoluteRotationKeyframe}'s
|
|
21490
|
-
* one-bound-given handling.
|
|
21491
|
-
*/
|
|
21492
|
-
function buildAbsoluteScaleKeyframe(anim, namePrefix, uid) {
|
|
21493
|
-
if (anim.scaleByX !== undefined || anim.scaleByY !== undefined) {
|
|
21494
|
-
return undefined;
|
|
21969
|
+
function keyframeName(anim, prefixes, uid, hasAttributeAnimation) {
|
|
21970
|
+
const motion = Boolean(anim.motionPath);
|
|
21971
|
+
const rotation = hasRotation(anim);
|
|
21972
|
+
const scale = hasScale(anim);
|
|
21973
|
+
if (hasAttributeAnimation || Number(motion) + Number(rotation) + Number(scale) > 1) {
|
|
21974
|
+
return `${prefixes.transform}-${uid}`;
|
|
21495
21975
|
}
|
|
21496
|
-
if (
|
|
21497
|
-
|
|
21498
|
-
anim.scaleToX === undefined &&
|
|
21499
|
-
anim.scaleToY === undefined) {
|
|
21500
|
-
return undefined;
|
|
21976
|
+
if (motion) {
|
|
21977
|
+
return `${prefixes.motion}-${uid}`;
|
|
21501
21978
|
}
|
|
21502
|
-
|
|
21503
|
-
|
|
21504
|
-
|
|
21505
|
-
|
|
21506
|
-
const name = `${namePrefix}-${uid}`;
|
|
21507
|
-
return {
|
|
21508
|
-
keyframeName: name,
|
|
21509
|
-
css: `@keyframes ${name} {\n\tfrom { transform: scale(${fromX}, ${fromY}); }\n\tto { transform: scale(${toX}, ${toY}); }\n}`,
|
|
21510
|
-
};
|
|
21511
|
-
}
|
|
21512
|
-
/** Clamp a value into the closed unit interval. */
|
|
21513
|
-
function clamp01$1(value) {
|
|
21514
|
-
return Math.max(0, Math.min(1, value));
|
|
21979
|
+
if (rotation) {
|
|
21980
|
+
return `${anim.rotationBy === undefined ? prefixes.rotationAbsolute : prefixes.rotationRelative}-${uid}`;
|
|
21981
|
+
}
|
|
21982
|
+
return `${anim.scaleByX === undefined && anim.scaleByY === undefined ? prefixes.scaleAbsolute : prefixes.scaleRelative}-${uid}`;
|
|
21515
21983
|
}
|
|
21516
|
-
/** `p:attrName` values known to name an opacity attribute. */
|
|
21517
|
-
const KNOWN_OPACITY_ATTR_NAMES = new Set(['style.opacity', 'opacity']);
|
|
21518
21984
|
/**
|
|
21519
|
-
* Build
|
|
21520
|
-
*
|
|
21521
|
-
* when the list is missing, has fewer than two usable stops, names an
|
|
21522
|
-
* attribute other than opacity, or carries a value shape this can't
|
|
21523
|
-
* confidently interpret as opacity.
|
|
21524
|
-
*
|
|
21525
|
-
* `p:tavLst` is schema-generic (ECMA-376 S19.5.30 CT_TLAnimVariantList): a
|
|
21526
|
-
* `p:anim` node can drive any numeric/string/color/bool attribute its
|
|
21527
|
-
* `p:attrNameLst` names. When the parser DID surface that name
|
|
21528
|
-
* ({@link PptxNativeAnimation.attrName}), it is trusted outright: anything
|
|
21529
|
-
* other than a known opacity name bails immediately, so e.g. a `ppt_w`
|
|
21530
|
-
* size ramp that happens to fall in `[0, 1]` is never misread as opacity.
|
|
21531
|
-
* When the name is absent (older parses, or a deck whose `p:cBhvr` omitted
|
|
21532
|
-
* `p:attrNameLst` entirely), this falls back to the original heuristic:
|
|
21533
|
-
* numeric (`flt`/`int`) stops in the `[0, 1]` fractional range on an
|
|
21534
|
-
* EMPHASIS effect, which is exactly what PowerPoint's own "Transparency"
|
|
21535
|
-
* effect (and any custom multi-stage fade) writes. Outside that shape the
|
|
21536
|
-
* caller keeps its existing (2-stop, canned) behaviour, so nothing regresses.
|
|
21985
|
+
* Build one keyframe block so simultaneous transform behaviours remain
|
|
21986
|
+
* simultaneous instead of competing for the CSS `transform` property.
|
|
21537
21987
|
*/
|
|
21538
|
-
function
|
|
21539
|
-
|
|
21988
|
+
function buildTransformKeyframes(anim, uid, prefixes) {
|
|
21989
|
+
const rotation = hasRotation(anim);
|
|
21990
|
+
const scale = hasScale(anim);
|
|
21991
|
+
const attributeModel = createAttributeTransformModel(anim);
|
|
21992
|
+
const parsedPoints = anim.motionPath
|
|
21993
|
+
? rotateMotionPathPoints(parseMotionPathPoints(anim.motionPath), anim)
|
|
21994
|
+
: [];
|
|
21995
|
+
const points = parsedPoints.length >= 2 ? parsedPoints : [];
|
|
21996
|
+
if (points.length === 0 && !rotation && !scale && !attributeModel) {
|
|
21540
21997
|
return undefined;
|
|
21541
21998
|
}
|
|
21542
|
-
|
|
21543
|
-
|
|
21999
|
+
const progressSet = new Set(attributeModel?.progresses ?? [0, 1]);
|
|
22000
|
+
for (let index = 0; index < points.length; index += 1) {
|
|
22001
|
+
progressSet.add(index / (points.length - 1));
|
|
21544
22002
|
}
|
|
21545
|
-
const
|
|
21546
|
-
|
|
21547
|
-
|
|
21548
|
-
|
|
21549
|
-
|
|
21550
|
-
|
|
21551
|
-
if (
|
|
21552
|
-
|
|
22003
|
+
const progresses = [...progressSet].sort((left, right) => left - right);
|
|
22004
|
+
const lines = progresses.map((progress) => {
|
|
22005
|
+
const point = pointAt(points, progress);
|
|
22006
|
+
const attributeState = attributeModel?.stateAt(progress);
|
|
22007
|
+
const declarations = [];
|
|
22008
|
+
const opacity = attributeState?.opacity ?? opacityAt(anim, progress);
|
|
22009
|
+
if (opacity !== undefined) {
|
|
22010
|
+
declarations.push(`opacity: ${formatNumber(opacity)};`);
|
|
21553
22011
|
}
|
|
21554
|
-
|
|
21555
|
-
|
|
22012
|
+
const transforms = [];
|
|
22013
|
+
if (points.length > 0) {
|
|
22014
|
+
transforms.push(`translate(${slideOffset(point.x, 'w')}, ${slideOffset(point.y, 'h')})`);
|
|
21556
22015
|
}
|
|
21557
|
-
|
|
21558
|
-
|
|
21559
|
-
return undefined;
|
|
22016
|
+
if (attributeState?.translateX !== undefined || attributeState?.translateY !== undefined) {
|
|
22017
|
+
transforms.push(`translate(${slideOffset(attributeState.translateX ?? 0, 'w')}, ${slideOffset(attributeState.translateY ?? 0, 'h')})`);
|
|
21560
22018
|
}
|
|
21561
|
-
|
|
21562
|
-
|
|
21563
|
-
|
|
21564
|
-
|
|
21565
|
-
|
|
21566
|
-
|
|
21567
|
-
|
|
21568
|
-
}
|
|
21569
|
-
/** `p:attrName` values known to name a colour attribute with a CSS mapping. */
|
|
21570
|
-
const KNOWN_COLOR_ATTR_NAMES = new Set([
|
|
21571
|
-
'fillcolor',
|
|
21572
|
-
'fill.color',
|
|
21573
|
-
'style.color',
|
|
21574
|
-
'stroke.color',
|
|
21575
|
-
]);
|
|
21576
|
-
/** Matches a resolved `#rrggbb` hex colour (what the core parser's `decodeKeyframeValue` emits for `a:srgbClr`). */
|
|
21577
|
-
const HEX_COLOR_RE = /^#[0-9a-f]{6}$/iu;
|
|
21578
|
-
/**
|
|
21579
|
-
* Build a multi-stop colour `@keyframes` block from a `p:tavLst` keyframe
|
|
21580
|
-
* list whose `p:attrName` names a known colour attribute (`fillcolor`,
|
|
21581
|
-
* `fill.color`, `style.color`, `stroke.color`), or `undefined` when the
|
|
21582
|
-
* attribute is unrecognised, there are fewer than two usable stops, or any
|
|
21583
|
-
* stop isn't a resolved `#rrggbb` hex colour.
|
|
21584
|
-
*
|
|
21585
|
-
* This is the sibling of {@link buildOpacityTavKeyframe} for the OTHER shape
|
|
21586
|
-
* `p:tavLst` playback can now place with confidence: a full multi-stop colour
|
|
21587
|
-
* ramp authored on a generic `p:anim` node, as opposed to the two/three-stop
|
|
21588
|
-
* `from`/`to`/`by` model the dedicated `p:animClr` behaviour uses (already
|
|
21589
|
-
* handled via {@link PptxNativeAnimation.colorAnimation}, which this
|
|
21590
|
-
* function defers to when present so an incidental `p:tavLst` on that same
|
|
21591
|
-
* node never overrides it). A scheme-colour token (`a:schemeClr`, e.g.
|
|
21592
|
-
* `"accent1"`) cannot be resolved to a CSS colour without theme context this
|
|
21593
|
-
* pure function doesn't have, so any non-hex stop also bails to the caller's
|
|
21594
|
-
* canned fallback rather than emitting invalid CSS.
|
|
21595
|
-
*
|
|
21596
|
-
* Reuses {@link resolveCssProperties} (`animation-color.ts`) for the
|
|
21597
|
-
* attribute -> CSS-property mapping, the same one `p:animClr` keyframes use,
|
|
21598
|
-
* so a `fillcolor` ramp painting an SVG shape's fill behaves identically
|
|
21599
|
-
* whichever OOXML behaviour authored it.
|
|
21600
|
-
*/
|
|
21601
|
-
function buildColorTavKeyframe(anim, namePrefix, uid) {
|
|
21602
|
-
if (anim.colorAnimation) {
|
|
21603
|
-
return undefined;
|
|
21604
|
-
}
|
|
21605
|
-
if (!anim.attrName || !KNOWN_COLOR_ATTR_NAMES.has(anim.attrName)) {
|
|
21606
|
-
return undefined;
|
|
21607
|
-
}
|
|
21608
|
-
const frames = anim.keyframes;
|
|
21609
|
-
if (!frames || frames.length < 2) {
|
|
21610
|
-
return undefined;
|
|
21611
|
-
}
|
|
21612
|
-
const stops = [];
|
|
21613
|
-
for (const kf of frames) {
|
|
21614
|
-
if (typeof kf.tm !== 'number' || !Number.isFinite(kf.tm)) {
|
|
21615
|
-
return undefined;
|
|
22019
|
+
if (rotation ||
|
|
22020
|
+
(points.length > 0 && anim.motionPathRotateAuto) ||
|
|
22021
|
+
attributeState?.rotation !== undefined) {
|
|
22022
|
+
const pointIndex = Math.round(progress * Math.max(0, points.length - 1));
|
|
22023
|
+
const pathRotation = anim.motionPathRotateAuto ? tangentAngle(points, pointIndex) : 0;
|
|
22024
|
+
const angle = pathRotation + (attributeState?.rotation ?? rotationAt(anim, progress));
|
|
22025
|
+
transforms.push(`rotate(${anim.motionPathRotateAuto ? angle.toFixed(2) : formatNumber(angle, 2)}deg)`);
|
|
21616
22026
|
}
|
|
21617
|
-
if (
|
|
21618
|
-
|
|
22027
|
+
if (scale || attributeState?.scaleX !== undefined || attributeState?.scaleY !== undefined) {
|
|
22028
|
+
transforms.push(`scale(${formatNumber(attributeState?.scaleX ?? scaleAt(anim, 'x', progress))}, ${formatNumber(attributeState?.scaleY ?? scaleAt(anim, 'y', progress))})`);
|
|
21619
22029
|
}
|
|
21620
|
-
|
|
21621
|
-
|
|
21622
|
-
return undefined;
|
|
22030
|
+
if (transforms.length > 0) {
|
|
22031
|
+
declarations.push(`transform: ${transforms.join(' ')};`);
|
|
21623
22032
|
}
|
|
21624
|
-
|
|
21625
|
-
}
|
|
21626
|
-
stops.sort((a, b) => a.pct - b.pct);
|
|
21627
|
-
const cssProperties = resolveCssProperties(anim.attrName);
|
|
21628
|
-
const name = `${namePrefix}-${uid}`;
|
|
21629
|
-
const lines = stops.map((s) => {
|
|
21630
|
-
const decls = cssProperties.map((prop) => `${prop}: ${s.color};`).join(' ');
|
|
21631
|
-
return `\t${Number(s.pct.toFixed(2))}% { ${decls} }`;
|
|
22033
|
+
return `\t${formatNumber(progress * 100, 2)}% { ${declarations.join(' ')} }`;
|
|
21632
22034
|
});
|
|
22035
|
+
const name = keyframeName(anim, prefixes, uid, attributeModel !== undefined);
|
|
21633
22036
|
return { keyframeName: name, css: `@keyframes ${name} {\n${lines.join('\n')}\n}` };
|
|
21634
22037
|
}
|
|
21635
22038
|
|
|
@@ -21733,10 +22136,22 @@ function applyFlyDirection(effect, subtype) {
|
|
|
21733
22136
|
* @param percent - Sampled coordinate in percent-of-slide units (path * 100).
|
|
21734
22137
|
* @param axis - `w` for the horizontal offset, `h` for the vertical one.
|
|
21735
22138
|
*/
|
|
21736
|
-
|
|
21737
|
-
|
|
21738
|
-
|
|
21739
|
-
|
|
22139
|
+
const FLAT_TRANSFORM_PREFIXES = {
|
|
22140
|
+
motion: 'pptx-motionPath',
|
|
22141
|
+
rotationAbsolute: 'pptx-rotateAbs',
|
|
22142
|
+
rotationRelative: 'pptx-rotateBy',
|
|
22143
|
+
scaleAbsolute: 'pptx-scaleAbs',
|
|
22144
|
+
scaleRelative: 'pptx-scaleBy',
|
|
22145
|
+
transform: 'pptx-transform',
|
|
22146
|
+
};
|
|
22147
|
+
const TIMELINE_TRANSFORM_PREFIXES = {
|
|
22148
|
+
motion: 'pptx-tl-motion',
|
|
22149
|
+
rotationAbsolute: 'pptx-tl-rotateAbs',
|
|
22150
|
+
rotationRelative: 'pptx-tl-rotate',
|
|
22151
|
+
scaleAbsolute: 'pptx-tl-scaleAbs',
|
|
22152
|
+
scaleRelative: 'pptx-tl-scale',
|
|
22153
|
+
transform: 'pptx-tl-transform',
|
|
22154
|
+
};
|
|
21740
22155
|
/**
|
|
21741
22156
|
* Build a dynamic CSS `@keyframes` block for motion path, rotation, scale, or
|
|
21742
22157
|
* colour animations that don't map to a static effect preset. Uses the
|
|
@@ -21744,49 +22159,9 @@ function slideOffset(percent, axis) {
|
|
|
21744
22159
|
* name prefixes (flat-sequence model).
|
|
21745
22160
|
*/
|
|
21746
22161
|
function buildDynamicKeyframes(anim, uid) {
|
|
21747
|
-
|
|
21748
|
-
if (
|
|
21749
|
-
|
|
21750
|
-
const points = parseMotionPathPoints(anim.motionPath);
|
|
21751
|
-
if (points.length < 2) {
|
|
21752
|
-
return undefined;
|
|
21753
|
-
}
|
|
21754
|
-
const kfLines = [];
|
|
21755
|
-
for (let i = 0; i < points.length; i++) {
|
|
21756
|
-
const pct = Math.round((i / (points.length - 1)) * 100);
|
|
21757
|
-
kfLines.push(`\t${pct}% { transform: translate(${slideOffset(points[i].x, 'w')}, ${slideOffset(points[i].y, 'h')}); }`);
|
|
21758
|
-
}
|
|
21759
|
-
return {
|
|
21760
|
-
keyframeName: name,
|
|
21761
|
-
css: `@keyframes ${name} {\n${kfLines.join('\n')}\n}`,
|
|
21762
|
-
};
|
|
21763
|
-
}
|
|
21764
|
-
// Rotation animation (relative `@by`, then absolute `from`/`to`)
|
|
21765
|
-
if (anim.rotationBy !== undefined) {
|
|
21766
|
-
const name = `pptx-rotateBy-${uid}`;
|
|
21767
|
-
const deg = anim.rotationBy;
|
|
21768
|
-
return {
|
|
21769
|
-
keyframeName: name,
|
|
21770
|
-
css: `@keyframes ${name} {\n\tfrom { transform: rotate(0deg); }\n\tto { transform: rotate(${deg}deg); }\n}`,
|
|
21771
|
-
};
|
|
21772
|
-
}
|
|
21773
|
-
const absoluteRotate = buildAbsoluteRotationKeyframe(anim, 'pptx-rotateAbs', uid);
|
|
21774
|
-
if (absoluteRotate) {
|
|
21775
|
-
return absoluteRotate;
|
|
21776
|
-
}
|
|
21777
|
-
// Scale animation (relative `@by`, then absolute `from`/`to`)
|
|
21778
|
-
if (anim.scaleByX !== undefined || anim.scaleByY !== undefined) {
|
|
21779
|
-
const name = `pptx-scaleBy-${uid}`;
|
|
21780
|
-
const sx = anim.scaleByX ?? 1;
|
|
21781
|
-
const sy = anim.scaleByY ?? 1;
|
|
21782
|
-
return {
|
|
21783
|
-
keyframeName: name,
|
|
21784
|
-
css: `@keyframes ${name} {\n\tfrom { transform: scale(1); }\n\tto { transform: scale(${sx}, ${sy}); }\n}`,
|
|
21785
|
-
};
|
|
21786
|
-
}
|
|
21787
|
-
const absoluteScale = buildAbsoluteScaleKeyframe(anim, 'pptx-scaleAbs', uid);
|
|
21788
|
-
if (absoluteScale) {
|
|
21789
|
-
return absoluteScale;
|
|
22162
|
+
const transform = buildTransformKeyframes(anim, uid, FLAT_TRANSFORM_PREFIXES);
|
|
22163
|
+
if (transform) {
|
|
22164
|
+
return transform;
|
|
21790
22165
|
}
|
|
21791
22166
|
// Color animation (p:animClr)
|
|
21792
22167
|
if (anim.colorAnimation) {
|
|
@@ -21812,59 +22187,9 @@ function buildDynamicKeyframes(anim, uid) {
|
|
|
21812
22187
|
* `pptx-tl-color-*` prefixes and supports motion-path auto-rotate.
|
|
21813
22188
|
*/
|
|
21814
22189
|
function buildDynamicKeyframe(anim, uid) {
|
|
21815
|
-
|
|
21816
|
-
|
|
21817
|
-
|
|
21818
|
-
if (points.length < 2) {
|
|
21819
|
-
return undefined;
|
|
21820
|
-
}
|
|
21821
|
-
const lines = [];
|
|
21822
|
-
for (let i = 0; i < points.length; i++) {
|
|
21823
|
-
const pct = Math.round((i / (points.length - 1)) * 100);
|
|
21824
|
-
const tx = slideOffset(points[i].x, 'w');
|
|
21825
|
-
const ty = slideOffset(points[i].y, 'h');
|
|
21826
|
-
if (anim.motionPathRotateAuto) {
|
|
21827
|
-
// Compute the tangent angle at this point using the direction
|
|
21828
|
-
// to the next point (or from the previous point for the last one).
|
|
21829
|
-
const next = i < points.length - 1 ? points[i + 1] : points[i];
|
|
21830
|
-
const prev = i > 0 ? points[i - 1] : points[i];
|
|
21831
|
-
const dx = i < points.length - 1 ? next.x - points[i].x : points[i].x - prev.x;
|
|
21832
|
-
const dy = i < points.length - 1 ? next.y - points[i].y : points[i].y - prev.y;
|
|
21833
|
-
const angleDeg = Math.atan2(dy, dx) * (180 / Math.PI);
|
|
21834
|
-
lines.push(`\t${pct}% { transform: translate(${tx}, ${ty}) rotate(${angleDeg.toFixed(2)}deg); }`);
|
|
21835
|
-
}
|
|
21836
|
-
else {
|
|
21837
|
-
lines.push(`\t${pct}% { transform: translate(${tx}, ${ty}); }`);
|
|
21838
|
-
}
|
|
21839
|
-
}
|
|
21840
|
-
return {
|
|
21841
|
-
keyframeName: name,
|
|
21842
|
-
css: `@keyframes ${name} {\n${lines.join('\n')}\n}`,
|
|
21843
|
-
};
|
|
21844
|
-
}
|
|
21845
|
-
if (anim.rotationBy !== undefined) {
|
|
21846
|
-
const name = `pptx-tl-rotate-${uid}`;
|
|
21847
|
-
return {
|
|
21848
|
-
keyframeName: name,
|
|
21849
|
-
css: `@keyframes ${name} {\n\tfrom { transform: rotate(0deg); }\n\tto { transform: rotate(${anim.rotationBy}deg); }\n}`,
|
|
21850
|
-
};
|
|
21851
|
-
}
|
|
21852
|
-
const absoluteRotate = buildAbsoluteRotationKeyframe(anim, 'pptx-tl-rotateAbs', uid);
|
|
21853
|
-
if (absoluteRotate) {
|
|
21854
|
-
return absoluteRotate;
|
|
21855
|
-
}
|
|
21856
|
-
if (anim.scaleByX !== undefined || anim.scaleByY !== undefined) {
|
|
21857
|
-
const name = `pptx-tl-scale-${uid}`;
|
|
21858
|
-
const sx = anim.scaleByX ?? 1;
|
|
21859
|
-
const sy = anim.scaleByY ?? 1;
|
|
21860
|
-
return {
|
|
21861
|
-
keyframeName: name,
|
|
21862
|
-
css: `@keyframes ${name} {\n\tfrom { transform: scale(1); }\n\tto { transform: scale(${sx}, ${sy}); }\n}`,
|
|
21863
|
-
};
|
|
21864
|
-
}
|
|
21865
|
-
const absoluteScale = buildAbsoluteScaleKeyframe(anim, 'pptx-tl-scaleAbs', uid);
|
|
21866
|
-
if (absoluteScale) {
|
|
21867
|
-
return absoluteScale;
|
|
22190
|
+
const transform = buildTransformKeyframes(anim, uid, TIMELINE_TRANSFORM_PREFIXES);
|
|
22191
|
+
if (transform) {
|
|
22192
|
+
return transform;
|
|
21868
22193
|
}
|
|
21869
22194
|
// Color animation (p:animClr)
|
|
21870
22195
|
if (anim.colorAnimation) {
|
|
@@ -21946,6 +22271,218 @@ function finalizeClickGroup(steps, options) {
|
|
|
21946
22271
|
return group;
|
|
21947
22272
|
}
|
|
21948
22273
|
|
|
22274
|
+
/**
|
|
22275
|
+
* `animation-timeline-absolute` — dynamic CSS `@keyframes` for the absolute
|
|
22276
|
+
* `from`/`to` form of `p:animRot` (ST_Angle) and `p:animScale`
|
|
22277
|
+
* (percentage), and for a `p:tavLst` ramp attached to a generic `p:anim`
|
|
22278
|
+
* behaviour (opacity or colour).
|
|
22279
|
+
*
|
|
22280
|
+
* {@link buildDynamicKeyframe} / {@link buildDynamicKeyframes} in
|
|
22281
|
+
* `animation-timeline-helpers` already handle the RELATIVE `@by` form
|
|
22282
|
+
* (`rotationBy` / `scaleByX` / `scaleByY`); this module covers the sibling
|
|
22283
|
+
* absolute form, which OOXML allows instead of (or alongside) `@by`:
|
|
22284
|
+
* ECMA-376 S19.5.7 CT_TLAnimateRotationBehavior and S19.5.8
|
|
22285
|
+
* CT_TLAnimateScaleBehavior both make `from`/`to`/`by` independently
|
|
22286
|
+
* optional. Only the relative form was ever read, so a deck that authored
|
|
22287
|
+
* "rotate from 0 to 180" (no `@by`) or "scale from 50% to 150%" produced no
|
|
22288
|
+
* rotation/scale keyframes at all and the effect silently did nothing.
|
|
22289
|
+
*
|
|
22290
|
+
* `p:tavLst` (ECMA-376 S19.5.30 CT_TLAnimVariantList) is schema-generic: a
|
|
22291
|
+
* `p:anim` node can drive ANY attribute its `p:attrNameLst/p:attrName` names,
|
|
22292
|
+
* and until the core parser surfaced that name (`PptxNativeAnimation.attrName`)
|
|
22293
|
+
* this module could only guess from the keyframe VALUE shape, which is why it
|
|
22294
|
+
* only ever recognised a numeric `[0, 1]` ramp as opacity. With the attribute
|
|
22295
|
+
* name available, {@link buildOpacityTavKeyframe} now confirms it against a
|
|
22296
|
+
* known opacity name instead of trusting the value shape alone, and
|
|
22297
|
+
* {@link buildColorTavKeyframe} covers the sibling case: a multi-stop colour
|
|
22298
|
+
* ramp on `fillcolor` / `fill.color` / `style.color` / `stroke.color`, reusing
|
|
22299
|
+
* the same attribute -> CSS-property mapping as the dedicated `p:animClr`
|
|
22300
|
+
* behaviour (`animation-color.ts`). Every other attribute name (position,
|
|
22301
|
+
* size, and anything this module cannot confirm a CSS mapping for) is left on
|
|
22302
|
+
* the caller's canned-timing fallback; see `docs/guide/limitations.md`.
|
|
22303
|
+
*
|
|
22304
|
+
* @module render/animation-timeline-absolute
|
|
22305
|
+
*/
|
|
22306
|
+
/**
|
|
22307
|
+
* Build an absolute-rotation `@keyframes` block from `rotationFrom`/
|
|
22308
|
+
* `rotationTo`, or `undefined` when the animation has no absolute rotation
|
|
22309
|
+
* (including when a relative `rotationBy` is present, which the caller
|
|
22310
|
+
* already handles and takes priority over this).
|
|
22311
|
+
*
|
|
22312
|
+
* A `from` with no `to` (or vice versa) still produces a sensible sweep: the
|
|
22313
|
+
* missing bound defaults to the other one's value so the animation is a
|
|
22314
|
+
* no-op turn rather than being dropped, matching how PowerPoint treats a
|
|
22315
|
+
* partially-specified rotation as ending at its one given angle.
|
|
22316
|
+
*/
|
|
22317
|
+
function buildAbsoluteRotationKeyframe(anim, namePrefix, uid) {
|
|
22318
|
+
if (anim.rotationBy !== undefined) {
|
|
22319
|
+
return undefined;
|
|
22320
|
+
}
|
|
22321
|
+
if (anim.rotationFrom === undefined && anim.rotationTo === undefined) {
|
|
22322
|
+
return undefined;
|
|
22323
|
+
}
|
|
22324
|
+
const from = anim.rotationFrom ?? anim.rotationTo ?? 0;
|
|
22325
|
+
const to = anim.rotationTo ?? anim.rotationFrom ?? 0;
|
|
22326
|
+
const name = `${namePrefix}-${uid}`;
|
|
22327
|
+
return {
|
|
22328
|
+
keyframeName: name,
|
|
22329
|
+
css: `@keyframes ${name} {\n\tfrom { transform: rotate(${from}deg); }\n\tto { transform: rotate(${to}deg); }\n}`,
|
|
22330
|
+
};
|
|
22331
|
+
}
|
|
22332
|
+
/**
|
|
22333
|
+
* Build an absolute-scale `@keyframes` block from `scaleFromX`/`scaleFromY`/
|
|
22334
|
+
* `scaleToX`/`scaleToY`, or `undefined` when the animation has no absolute
|
|
22335
|
+
* scale (including when a relative `scaleByX`/`scaleByY` is present, which
|
|
22336
|
+
* the caller already handles and takes priority over this).
|
|
22337
|
+
*
|
|
22338
|
+
* A missing `from` defaults to 1 (unscaled) and a missing `to` defaults to
|
|
22339
|
+
* the `from` value, mirroring {@link buildAbsoluteRotationKeyframe}'s
|
|
22340
|
+
* one-bound-given handling.
|
|
22341
|
+
*/
|
|
22342
|
+
function buildAbsoluteScaleKeyframe(anim, namePrefix, uid) {
|
|
22343
|
+
if (anim.scaleByX !== undefined || anim.scaleByY !== undefined) {
|
|
22344
|
+
return undefined;
|
|
22345
|
+
}
|
|
22346
|
+
if (anim.scaleFromX === undefined &&
|
|
22347
|
+
anim.scaleFromY === undefined &&
|
|
22348
|
+
anim.scaleToX === undefined &&
|
|
22349
|
+
anim.scaleToY === undefined) {
|
|
22350
|
+
return undefined;
|
|
22351
|
+
}
|
|
22352
|
+
const fromX = anim.scaleFromX ?? 1;
|
|
22353
|
+
const fromY = anim.scaleFromY ?? 1;
|
|
22354
|
+
const toX = anim.scaleToX ?? fromX;
|
|
22355
|
+
const toY = anim.scaleToY ?? fromY;
|
|
22356
|
+
const name = `${namePrefix}-${uid}`;
|
|
22357
|
+
return {
|
|
22358
|
+
keyframeName: name,
|
|
22359
|
+
css: `@keyframes ${name} {\n\tfrom { transform: scale(${fromX}, ${fromY}); }\n\tto { transform: scale(${toX}, ${toY}); }\n}`,
|
|
22360
|
+
};
|
|
22361
|
+
}
|
|
22362
|
+
/** Clamp a value into the closed unit interval. */
|
|
22363
|
+
function clamp01$1(value) {
|
|
22364
|
+
return Math.max(0, Math.min(1, value));
|
|
22365
|
+
}
|
|
22366
|
+
/** `p:attrName` values known to name an opacity attribute. */
|
|
22367
|
+
const KNOWN_OPACITY_ATTR_NAMES = new Set(['style.opacity', 'opacity']);
|
|
22368
|
+
/**
|
|
22369
|
+
* Build a multi-stop opacity `@keyframes` block from a `p:tavLst` keyframe
|
|
22370
|
+
* list (parsed onto {@link PptxNativeAnimation.keyframes}), or `undefined`
|
|
22371
|
+
* when the list is missing, has fewer than two usable stops, names an
|
|
22372
|
+
* attribute other than opacity, or carries a value shape this can't
|
|
22373
|
+
* confidently interpret as opacity.
|
|
22374
|
+
*
|
|
22375
|
+
* `p:tavLst` is schema-generic (ECMA-376 S19.5.30 CT_TLAnimVariantList): a
|
|
22376
|
+
* `p:anim` node can drive any numeric/string/color/bool attribute its
|
|
22377
|
+
* `p:attrNameLst` names. When the parser DID surface that name
|
|
22378
|
+
* ({@link PptxNativeAnimation.attrName}), it is trusted outright: anything
|
|
22379
|
+
* other than a known opacity name bails immediately, so e.g. a `ppt_w`
|
|
22380
|
+
* size ramp that happens to fall in `[0, 1]` is never misread as opacity.
|
|
22381
|
+
* When the name is absent (older parses, or a deck whose `p:cBhvr` omitted
|
|
22382
|
+
* `p:attrNameLst` entirely), this falls back to the original heuristic:
|
|
22383
|
+
* numeric (`flt`/`int`) stops in the `[0, 1]` fractional range on an
|
|
22384
|
+
* EMPHASIS effect, which is exactly what PowerPoint's own "Transparency"
|
|
22385
|
+
* effect (and any custom multi-stage fade) writes. Outside that shape the
|
|
22386
|
+
* caller keeps its existing (2-stop, canned) behaviour, so nothing regresses.
|
|
22387
|
+
*/
|
|
22388
|
+
function buildOpacityTavKeyframe(anim, namePrefix, uid) {
|
|
22389
|
+
if (anim.presetClass !== 'emph') {
|
|
22390
|
+
return undefined;
|
|
22391
|
+
}
|
|
22392
|
+
if (anim.attrName !== undefined && !KNOWN_OPACITY_ATTR_NAMES.has(anim.attrName)) {
|
|
22393
|
+
return undefined;
|
|
22394
|
+
}
|
|
22395
|
+
const frames = anim.keyframes;
|
|
22396
|
+
if (!frames || frames.length < 2) {
|
|
22397
|
+
return undefined;
|
|
22398
|
+
}
|
|
22399
|
+
const stops = [];
|
|
22400
|
+
for (const kf of frames) {
|
|
22401
|
+
if (typeof kf.tm !== 'number' || !Number.isFinite(kf.tm)) {
|
|
22402
|
+
return undefined;
|
|
22403
|
+
}
|
|
22404
|
+
if (kf.valueType !== 'flt' && kf.valueType !== 'int') {
|
|
22405
|
+
return undefined;
|
|
22406
|
+
}
|
|
22407
|
+
const opacity = Number(kf.value);
|
|
22408
|
+
if (!Number.isFinite(opacity) || opacity < 0 || opacity > 1) {
|
|
22409
|
+
return undefined;
|
|
22410
|
+
}
|
|
22411
|
+
// `tm` is in 1000ths of a percent of the effect's own duration (100000 = 100%).
|
|
22412
|
+
stops.push({ pct: clamp01$1(kf.tm / 100000) * 100, opacity });
|
|
22413
|
+
}
|
|
22414
|
+
stops.sort((a, b) => a.pct - b.pct);
|
|
22415
|
+
const name = `${namePrefix}-${uid}`;
|
|
22416
|
+
const lines = stops.map((s) => `\t${Number(s.pct.toFixed(2))}% { opacity: ${s.opacity}; }`);
|
|
22417
|
+
return { keyframeName: name, css: `@keyframes ${name} {\n${lines.join('\n')}\n}` };
|
|
22418
|
+
}
|
|
22419
|
+
/** `p:attrName` values known to name a colour attribute with a CSS mapping. */
|
|
22420
|
+
const KNOWN_COLOR_ATTR_NAMES = new Set([
|
|
22421
|
+
'fillcolor',
|
|
22422
|
+
'fill.color',
|
|
22423
|
+
'style.color',
|
|
22424
|
+
'stroke.color',
|
|
22425
|
+
]);
|
|
22426
|
+
/** Matches a resolved `#rrggbb` hex colour (what the core parser's `decodeKeyframeValue` emits for `a:srgbClr`). */
|
|
22427
|
+
const HEX_COLOR_RE = /^#[0-9a-f]{6}$/iu;
|
|
22428
|
+
/**
|
|
22429
|
+
* Build a multi-stop colour `@keyframes` block from a `p:tavLst` keyframe
|
|
22430
|
+
* list whose `p:attrName` names a known colour attribute (`fillcolor`,
|
|
22431
|
+
* `fill.color`, `style.color`, `stroke.color`), or `undefined` when the
|
|
22432
|
+
* attribute is unrecognised, there are fewer than two usable stops, or any
|
|
22433
|
+
* stop isn't a resolved `#rrggbb` hex colour.
|
|
22434
|
+
*
|
|
22435
|
+
* This is the sibling of {@link buildOpacityTavKeyframe} for the OTHER shape
|
|
22436
|
+
* `p:tavLst` playback can now place with confidence: a full multi-stop colour
|
|
22437
|
+
* ramp authored on a generic `p:anim` node, as opposed to the two/three-stop
|
|
22438
|
+
* `from`/`to`/`by` model the dedicated `p:animClr` behaviour uses (already
|
|
22439
|
+
* handled via {@link PptxNativeAnimation.colorAnimation}, which this
|
|
22440
|
+
* function defers to when present so an incidental `p:tavLst` on that same
|
|
22441
|
+
* node never overrides it). A scheme-colour token (`a:schemeClr`, e.g.
|
|
22442
|
+
* `"accent1"`) cannot be resolved to a CSS colour without theme context this
|
|
22443
|
+
* pure function doesn't have, so any non-hex stop also bails to the caller's
|
|
22444
|
+
* canned fallback rather than emitting invalid CSS.
|
|
22445
|
+
*
|
|
22446
|
+
* Reuses {@link resolveCssProperties} (`animation-color.ts`) for the
|
|
22447
|
+
* attribute -> CSS-property mapping, the same one `p:animClr` keyframes use,
|
|
22448
|
+
* so a `fillcolor` ramp painting an SVG shape's fill behaves identically
|
|
22449
|
+
* whichever OOXML behaviour authored it.
|
|
22450
|
+
*/
|
|
22451
|
+
function buildColorTavKeyframe(anim, namePrefix, uid) {
|
|
22452
|
+
if (anim.colorAnimation) {
|
|
22453
|
+
return undefined;
|
|
22454
|
+
}
|
|
22455
|
+
if (!anim.attrName || !KNOWN_COLOR_ATTR_NAMES.has(anim.attrName)) {
|
|
22456
|
+
return undefined;
|
|
22457
|
+
}
|
|
22458
|
+
const frames = anim.keyframes;
|
|
22459
|
+
if (!frames || frames.length < 2) {
|
|
22460
|
+
return undefined;
|
|
22461
|
+
}
|
|
22462
|
+
const stops = [];
|
|
22463
|
+
for (const kf of frames) {
|
|
22464
|
+
if (typeof kf.tm !== 'number' || !Number.isFinite(kf.tm)) {
|
|
22465
|
+
return undefined;
|
|
22466
|
+
}
|
|
22467
|
+
if (kf.valueType !== 'clr') {
|
|
22468
|
+
return undefined;
|
|
22469
|
+
}
|
|
22470
|
+
const color = String(kf.value);
|
|
22471
|
+
if (!HEX_COLOR_RE.test(color)) {
|
|
22472
|
+
return undefined;
|
|
22473
|
+
}
|
|
22474
|
+
stops.push({ pct: clamp01$1(kf.tm / 100000) * 100, color: color.toLowerCase() });
|
|
22475
|
+
}
|
|
22476
|
+
stops.sort((a, b) => a.pct - b.pct);
|
|
22477
|
+
const cssProperties = resolveCssProperties(anim.attrName);
|
|
22478
|
+
const name = `${namePrefix}-${uid}`;
|
|
22479
|
+
const lines = stops.map((s) => {
|
|
22480
|
+
const decls = cssProperties.map((prop) => `${prop}: ${s.color};`).join(' ');
|
|
22481
|
+
return `\t${Number(s.pct.toFixed(2))}% { ${decls} }`;
|
|
22482
|
+
});
|
|
22483
|
+
return { keyframeName: name, css: `@keyframes ${name} {\n${lines.join('\n')}\n}` };
|
|
22484
|
+
}
|
|
22485
|
+
|
|
21949
22486
|
/**
|
|
21950
22487
|
* `animation-fill-repeat`: pure decisions for `p:cTn/@fill`, `@repeatDur`
|
|
21951
22488
|
* and `@spd`, the three timing attributes the parse layer now surfaces on
|
|
@@ -22010,10 +22547,17 @@ function shouldHoldEndState(anim) {
|
|
|
22010
22547
|
/** Resolve all three timing decisions for one animation in a single call. */
|
|
22011
22548
|
function resolveEffectTiming(anim, baseDurationMs) {
|
|
22012
22549
|
const durationMs = applySpeedToDuration(anim.speedPct, baseDurationMs);
|
|
22013
|
-
const
|
|
22550
|
+
const authoredIterations = resolveIterationCount(anim.repeatCount, anim.repeatDurMs, durationMs);
|
|
22551
|
+
const iterationCount = anim.autoReverse && anim.repeatDurMs === undefined
|
|
22552
|
+
? authoredIterations * 2
|
|
22553
|
+
: authoredIterations;
|
|
22554
|
+
const activeDurationMs = Number.isFinite(iterationCount)
|
|
22555
|
+
? durationMs * iterationCount
|
|
22556
|
+
: durationMs;
|
|
22014
22557
|
return {
|
|
22015
22558
|
durationMs,
|
|
22016
22559
|
iterationCount,
|
|
22560
|
+
activeDurationMs,
|
|
22017
22561
|
holdEndState: shouldHoldEndState(anim),
|
|
22018
22562
|
};
|
|
22019
22563
|
}
|
|
@@ -22509,6 +23053,7 @@ function emitStaggeredPieces(anim, kind, counts, output, newClickStepPerParagrap
|
|
|
22509
23053
|
triggerDelayMs: undefined,
|
|
22510
23054
|
startConditions: undefined,
|
|
22511
23055
|
parGroupIndex: undefined,
|
|
23056
|
+
parGroupDelayMs: undefined,
|
|
22512
23057
|
}),
|
|
22513
23058
|
buildType: undefined,
|
|
22514
23059
|
iterate: undefined,
|
|
@@ -22578,6 +23123,7 @@ function expandSingleBuildAnimation(anim, buildType, counts, output) {
|
|
|
22578
23123
|
triggerDelayMs: undefined,
|
|
22579
23124
|
startConditions: undefined,
|
|
22580
23125
|
parGroupIndex: undefined,
|
|
23126
|
+
parGroupDelayMs: undefined,
|
|
22581
23127
|
buildType: undefined,
|
|
22582
23128
|
buildReverse: undefined,
|
|
22583
23129
|
buildAdvAutoMs: undefined,
|
|
@@ -22623,6 +23169,7 @@ function joinPreviousFields() {
|
|
|
22623
23169
|
triggerDelayMs: undefined,
|
|
22624
23170
|
startConditions: undefined,
|
|
22625
23171
|
parGroupIndex: undefined,
|
|
23172
|
+
parGroupDelayMs: undefined,
|
|
22626
23173
|
};
|
|
22627
23174
|
}
|
|
22628
23175
|
/** Expand a `pRg`-scoped animation into one sub-animation per named paragraph. */
|
|
@@ -23304,6 +23851,72 @@ function parseMediaCommand(commandString) {
|
|
|
23304
23851
|
return undefined;
|
|
23305
23852
|
}
|
|
23306
23853
|
|
|
23854
|
+
const COLOR_KEYFRAME = /^pptx-tl-(?:color|tavclr)-/u;
|
|
23855
|
+
const TRANSFORM_KEYFRAME = /^pptx-tl-(?:motion|rotate(?:Abs)?|scale(?:Abs)?|transform)-/u;
|
|
23856
|
+
function sameOptionalValue(left, right) {
|
|
23857
|
+
return left === right;
|
|
23858
|
+
}
|
|
23859
|
+
function hasIndependentColourAndTransform(left, right) {
|
|
23860
|
+
return ((COLOR_KEYFRAME.test(left.keyframeName) && TRANSFORM_KEYFRAME.test(right.keyframeName)) ||
|
|
23861
|
+
(TRANSFORM_KEYFRAME.test(left.keyframeName) && COLOR_KEYFRAME.test(right.keyframeName)));
|
|
23862
|
+
}
|
|
23863
|
+
/** Whether two sibling behaviours can safely share one CSS animation list. */
|
|
23864
|
+
function canComposeParallelSteps(left, right) {
|
|
23865
|
+
return (hasIndependentColourAndTransform(left, right) &&
|
|
23866
|
+
left.elementId !== '' &&
|
|
23867
|
+
left.elementId === right.elementId &&
|
|
23868
|
+
left.cssAnimation !== '' &&
|
|
23869
|
+
right.cssAnimation !== '' &&
|
|
23870
|
+
left.delayMs === right.delayMs &&
|
|
23871
|
+
left.durationMs === right.durationMs &&
|
|
23872
|
+
left.presetClass === right.presetClass &&
|
|
23873
|
+
left.fillMode === right.fillMode &&
|
|
23874
|
+
sameOptionalValue(left.holdEndState, right.holdEndState) &&
|
|
23875
|
+
sameOptionalValue(left.hideAfterEffect, right.hideAfterEffect) &&
|
|
23876
|
+
sameOptionalValue(left.pendingHideOnNextClick, right.pendingHideOnNextClick) &&
|
|
23877
|
+
sameOptionalValue(left.seqConcurrent, right.seqConcurrent) &&
|
|
23878
|
+
sameOptionalValue(left.seqNextAction, right.seqNextAction) &&
|
|
23879
|
+
sameOptionalValue(left.seqPrevAction, right.seqPrevAction) &&
|
|
23880
|
+
!left.command &&
|
|
23881
|
+
!right.command &&
|
|
23882
|
+
!left.build &&
|
|
23883
|
+
!right.build &&
|
|
23884
|
+
!left.soundPath &&
|
|
23885
|
+
!right.soundPath &&
|
|
23886
|
+
!left.stopSound &&
|
|
23887
|
+
!right.stopSound &&
|
|
23888
|
+
!left.restart &&
|
|
23889
|
+
!right.restart &&
|
|
23890
|
+
left.exclGroupId === undefined &&
|
|
23891
|
+
right.exclGroupId === undefined);
|
|
23892
|
+
}
|
|
23893
|
+
/** Compose independent CSS properties without dropping either behaviour. */
|
|
23894
|
+
function composeParallelSteps(left, right) {
|
|
23895
|
+
const colorTargets = [...new Set([...(left.colorTargets ?? []), ...(right.colorTargets ?? [])])];
|
|
23896
|
+
return {
|
|
23897
|
+
...left,
|
|
23898
|
+
cssAnimation: `${left.cssAnimation}, ${right.cssAnimation}`,
|
|
23899
|
+
colorTargets: colorTargets.length > 0 ? colorTargets : undefined,
|
|
23900
|
+
};
|
|
23901
|
+
}
|
|
23902
|
+
|
|
23903
|
+
/** Synthetic state-map suffix for a `p:spTgt/p:bg` background-only target. */
|
|
23904
|
+
const BACKGROUND_ANIMATION_ID_SUFFIX = '::pptx-bg';
|
|
23905
|
+
/**
|
|
23906
|
+
* Resolve the view-layer target for an animation.
|
|
23907
|
+
*
|
|
23908
|
+
* PowerPoint's `p:bg` target animates only the shape paint while its text stays
|
|
23909
|
+
* visible. Keeping that state under a synthetic id lets bindings paint a
|
|
23910
|
+
* separate background layer without hiding or transforming the whole element.
|
|
23911
|
+
*/
|
|
23912
|
+
function resolveAnimationTargetId(animation) {
|
|
23913
|
+
const targetId = animation.targetId ?? '';
|
|
23914
|
+
if (targetId && animation.target?.type === 'shape' && animation.target.backgroundOnly === true) {
|
|
23915
|
+
return `${targetId}${BACKGROUND_ANIMATION_ID_SUFFIX}`;
|
|
23916
|
+
}
|
|
23917
|
+
return targetId;
|
|
23918
|
+
}
|
|
23919
|
+
|
|
23307
23920
|
/**
|
|
23308
23921
|
* `animation-timeline-builder` — `buildTimeline`, which turns a flat list of
|
|
23309
23922
|
* native animations into an {@link AnimationTimeline} of click-groups (plus
|
|
@@ -23368,11 +23981,11 @@ function stepColorTargets(anim, tavColorApplied) {
|
|
|
23368
23981
|
// colour ramp on a generic `p:anim` node (see `buildColorTavKeyframe`)
|
|
23369
23982
|
// names the same kind of attribute, so it resolves paint targets the
|
|
23370
23983
|
// same way once there's no dedicated colour animation to defer to.
|
|
23371
|
-
const
|
|
23372
|
-
if (!
|
|
23984
|
+
const colorSource = anim.colorAnimation ?? (tavColorApplied ? anim.attrName : undefined);
|
|
23985
|
+
if (!colorSource) {
|
|
23373
23986
|
return undefined;
|
|
23374
23987
|
}
|
|
23375
|
-
const targets = resolveColorAnimationTargets(
|
|
23988
|
+
const targets = resolveColorAnimationTargets(colorSource);
|
|
23376
23989
|
return targets.length > 0 ? targets : undefined;
|
|
23377
23990
|
}
|
|
23378
23991
|
function fallbackEffectForClass(presetClass) {
|
|
@@ -23423,18 +24036,24 @@ function buildTimeline(nativeAnimations) {
|
|
|
23423
24036
|
entranceElementIds: new Set(),
|
|
23424
24037
|
keyframesCss: '',
|
|
23425
24038
|
interactiveSequences: new Map(),
|
|
24039
|
+
restartableInteractiveSequences: new Set(),
|
|
23426
24040
|
hoverSequences: new Map(),
|
|
23427
24041
|
};
|
|
23428
24042
|
}
|
|
23429
24043
|
// Separate interactive (onShapeClick), hover (onHover), and regular animations
|
|
23430
24044
|
const regularAnims = [];
|
|
23431
24045
|
const interactiveAnims = new Map();
|
|
24046
|
+
const restartableInteractiveSequences = new Set();
|
|
23432
24047
|
const hoverAnims = [];
|
|
23433
24048
|
for (const anim of nativeAnimations) {
|
|
23434
|
-
if (anim.trigger === 'onShapeClick' &&
|
|
24049
|
+
if ((anim.interactiveSequence === true || anim.trigger === 'onShapeClick') &&
|
|
24050
|
+
anim.triggerShapeId) {
|
|
23435
24051
|
const existing = interactiveAnims.get(anim.triggerShapeId) ?? [];
|
|
23436
24052
|
existing.push(anim);
|
|
23437
24053
|
interactiveAnims.set(anim.triggerShapeId, existing);
|
|
24054
|
+
if (anim.interactiveRestart === true) {
|
|
24055
|
+
restartableInteractiveSequences.add(anim.triggerShapeId);
|
|
24056
|
+
}
|
|
23438
24057
|
}
|
|
23439
24058
|
else if (anim.trigger === 'onHover' && anim.targetId) {
|
|
23440
24059
|
hoverAnims.push(anim);
|
|
@@ -23449,6 +24068,7 @@ function buildTimeline(nativeAnimations) {
|
|
|
23449
24068
|
const dynamicBlocks = [];
|
|
23450
24069
|
let dynamicUid = 0;
|
|
23451
24070
|
let currentGroup = [];
|
|
24071
|
+
let currentGroupLastParallelIndex;
|
|
23452
24072
|
/** Whether the current group was started by an onClick trigger. */
|
|
23453
24073
|
let currentGroupIsClick = false;
|
|
23454
24074
|
/**
|
|
@@ -23467,8 +24087,13 @@ function buildTimeline(nativeAnimations) {
|
|
|
23467
24087
|
for (const anim of regularAnims) {
|
|
23468
24088
|
const expandedSteps = expandIterateAnimation(anim);
|
|
23469
24089
|
for (const singleAnim of expandedSteps) {
|
|
23470
|
-
let
|
|
23471
|
-
|
|
24090
|
+
let dynamic = hasAuthoredTransform(singleAnim)
|
|
24091
|
+
? buildDynamicKeyframe(singleAnim, dynamicUid++)
|
|
24092
|
+
: undefined;
|
|
24093
|
+
let effect = dynamic ? undefined : resolveEffect(singleAnim);
|
|
24094
|
+
if (!effect && !dynamic) {
|
|
24095
|
+
dynamic = buildDynamicKeyframe(singleAnim, dynamicUid++);
|
|
24096
|
+
}
|
|
23472
24097
|
// A real `p:tavLst` keyframe list on an emphasis effect (e.g.
|
|
23473
24098
|
// PowerPoint's "Transparency") carries the AUTHORED opacity ramp;
|
|
23474
24099
|
// prefer it over the canned 2/3-stop static effect so a custom fade
|
|
@@ -23538,7 +24163,7 @@ function buildTimeline(nativeAnimations) {
|
|
|
23538
24163
|
// Command steps carry no element visibility semantics: an empty
|
|
23539
24164
|
// elementId keeps them from hiding/revealing a real element; the media
|
|
23540
24165
|
// target is routed via the command payload instead.
|
|
23541
|
-
const elementId = isCommand ? '' : (singleAnim
|
|
24166
|
+
const elementId = isCommand ? '' : resolveAnimationTargetId(singleAnim);
|
|
23542
24167
|
// Honour the FULL start-condition OR-set (compound / simultaneous
|
|
23543
24168
|
// triggers) rather than the collapsed single trigger. The effective
|
|
23544
24169
|
// condition drives grouping and supplies the governing start delay.
|
|
@@ -23563,7 +24188,7 @@ function buildTimeline(nativeAnimations) {
|
|
|
23563
24188
|
// Apply `@spd` / `@repeatDur` / `@fill` (animation-fill-repeat), then
|
|
23564
24189
|
// compute direction. A command step carries no timing of its own.
|
|
23565
24190
|
const timing = isCommand
|
|
23566
|
-
? { durationMs: 0, iterationCount: 1, holdEndState: false }
|
|
24191
|
+
? { durationMs: 0, iterationCount: 1, activeDurationMs: 0, holdEndState: false }
|
|
23567
24192
|
: resolveEffectTiming(singleAnim, baseDuration);
|
|
23568
24193
|
const duration = timing.durationMs;
|
|
23569
24194
|
const iterCount = timing.iterationCount;
|
|
@@ -23587,6 +24212,7 @@ function buildTimeline(nativeAnimations) {
|
|
|
23587
24212
|
clickGroups.push(group);
|
|
23588
24213
|
}
|
|
23589
24214
|
currentGroup = [];
|
|
24215
|
+
currentGroupLastParallelIndex = undefined;
|
|
23590
24216
|
currentGroupIsClick = isOnClick || isFirstAnimation;
|
|
23591
24217
|
// A group the deck marks as auto-starting plays on slide entry. This
|
|
23592
24218
|
// is how PowerPoint renders a deck whose opening effects are "With
|
|
@@ -23603,18 +24229,24 @@ function buildTimeline(nativeAnimations) {
|
|
|
23603
24229
|
currentGroupAutoStart =
|
|
23604
24230
|
singleAnim.groupAutoStart === true && !effective.requiresInteraction;
|
|
23605
24231
|
subGroupIndex = singleAnim.parGroupIndex;
|
|
23606
|
-
subGroupStartMs = 0;
|
|
24232
|
+
subGroupStartMs = singleAnim.parGroupDelayMs ?? 0;
|
|
23607
24233
|
}
|
|
23608
24234
|
// Compute delay relative to start of this click-group
|
|
23609
24235
|
const prevStep = currentGroup.length > 0 ? currentGroup[currentGroup.length - 1] : undefined;
|
|
23610
24236
|
let delayMs;
|
|
23611
|
-
if (singleAnim.parGroupIndex !== undefined
|
|
24237
|
+
if (singleAnim.parGroupIndex !== undefined) {
|
|
23612
24238
|
if (singleAnim.parGroupIndex !== subGroupIndex) {
|
|
23613
|
-
//
|
|
23614
|
-
//
|
|
24239
|
+
// Prefer the wrapper's authored absolute offset. Older or
|
|
24240
|
+
// programmatically-created entries may not carry one, so retain
|
|
24241
|
+
// the duration-based chaining fallback for those entries.
|
|
23615
24242
|
subGroupIndex = singleAnim.parGroupIndex;
|
|
23616
24243
|
subGroupStartMs =
|
|
23617
|
-
|
|
24244
|
+
singleAnim.parGroupDelayMs ??
|
|
24245
|
+
(prevStep
|
|
24246
|
+
? trigger === 'withPrevious'
|
|
24247
|
+
? prevStep.delayMs
|
|
24248
|
+
: prevStep.delayMs + prevStep.durationMs
|
|
24249
|
+
: 0);
|
|
23618
24250
|
}
|
|
23619
24251
|
// Siblings of one wrapper are simultaneous in OOXML: each `@delay` is
|
|
23620
24252
|
// an offset from the wrapper, never a chain off the previous effect.
|
|
@@ -23639,17 +24271,17 @@ function buildTimeline(nativeAnimations) {
|
|
|
23639
24271
|
// `applyAfterAnimationFromEditorList` before the timeline is built.
|
|
23640
24272
|
const afterFields = isCommand
|
|
23641
24273
|
? { cssAnimation: baseCssAnimation, holdEndState: timing.holdEndState }
|
|
23642
|
-
: resolveAfterAnimationStepFields(singleAnim, baseCssAnimation, timing.holdEndState, delayMs +
|
|
24274
|
+
: resolveAfterAnimationStepFields(singleAnim, baseCssAnimation, timing.holdEndState, delayMs + timing.activeDurationMs, `pptx-tl-dim-${dynamicUid++}`);
|
|
23643
24275
|
if (afterFields.dimKeyframeBlock) {
|
|
23644
24276
|
dynamicBlocks.push(afterFields.dimKeyframeBlock);
|
|
23645
24277
|
}
|
|
23646
|
-
|
|
24278
|
+
const step = {
|
|
23647
24279
|
elementId,
|
|
23648
24280
|
cssAnimation: afterFields.cssAnimation,
|
|
23649
24281
|
keyframeName: keyframe,
|
|
23650
24282
|
trigger,
|
|
23651
24283
|
delayMs,
|
|
23652
|
-
durationMs:
|
|
24284
|
+
durationMs: timing.activeDurationMs,
|
|
23653
24285
|
fillMode: fill,
|
|
23654
24286
|
presetClass: presetClass,
|
|
23655
24287
|
soundPath: singleAnim.soundPath,
|
|
@@ -23665,7 +24297,18 @@ function buildTimeline(nativeAnimations) {
|
|
|
23665
24297
|
seqNextAction: singleAnim.seqNextAction,
|
|
23666
24298
|
seqPrevAction: singleAnim.seqPrevAction,
|
|
23667
24299
|
exclGroupId: singleAnim.exclGroupId,
|
|
23668
|
-
}
|
|
24300
|
+
};
|
|
24301
|
+
const previousParallelStep = currentGroup[currentGroup.length - 1];
|
|
24302
|
+
if (singleAnim.parGroupIndex !== undefined &&
|
|
24303
|
+
singleAnim.parGroupIndex === currentGroupLastParallelIndex &&
|
|
24304
|
+
previousParallelStep &&
|
|
24305
|
+
canComposeParallelSteps(previousParallelStep, step)) {
|
|
24306
|
+
currentGroup[currentGroup.length - 1] = composeParallelSteps(previousParallelStep, step);
|
|
24307
|
+
}
|
|
24308
|
+
else {
|
|
24309
|
+
currentGroup.push(step);
|
|
24310
|
+
}
|
|
24311
|
+
currentGroupLastParallelIndex = singleAnim.parGroupIndex;
|
|
23669
24312
|
}
|
|
23670
24313
|
}
|
|
23671
24314
|
// Flush last group
|
|
@@ -23706,6 +24349,7 @@ function buildTimeline(nativeAnimations) {
|
|
|
23706
24349
|
entranceElementIds: entranceIds,
|
|
23707
24350
|
keyframesCss: keyframeBlocks.join('\n\n'),
|
|
23708
24351
|
interactiveSequences,
|
|
24352
|
+
restartableInteractiveSequences,
|
|
23709
24353
|
hoverSequences,
|
|
23710
24354
|
};
|
|
23711
24355
|
}
|
|
@@ -23753,9 +24397,17 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23753
24397
|
for (const [shapeId, anims] of animsByKey) {
|
|
23754
24398
|
const seqGroups = [];
|
|
23755
24399
|
let seqGroup = [];
|
|
24400
|
+
let seqGroupLastParallelIndex;
|
|
24401
|
+
let subGroupIndex;
|
|
24402
|
+
let subGroupStartMs = 0;
|
|
23756
24403
|
for (const anim of anims) {
|
|
23757
|
-
let
|
|
23758
|
-
|
|
24404
|
+
let dynamic = hasAuthoredTransform(anim)
|
|
24405
|
+
? buildDynamicKeyframe(anim, dynamicUid++)
|
|
24406
|
+
: undefined;
|
|
24407
|
+
let effect = dynamic ? undefined : resolveEffect(anim);
|
|
24408
|
+
if (!effect && !dynamic) {
|
|
24409
|
+
dynamic = buildDynamicKeyframe(anim, dynamicUid++);
|
|
24410
|
+
}
|
|
23759
24411
|
// Same authored-tavLst-over-canned-default preference as the main
|
|
23760
24412
|
// click-group loop (see the comment there for why it's gated to
|
|
23761
24413
|
// 'transparency' / unmapped emphasis effects only).
|
|
@@ -23799,7 +24451,7 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23799
24451
|
dynamicBlocks.push(dynamic.css);
|
|
23800
24452
|
}
|
|
23801
24453
|
// Command steps carry no element visibility semantics; see the main loop.
|
|
23802
|
-
const elementId = isCommand ? '' : (anim
|
|
24454
|
+
const elementId = isCommand ? '' : resolveAnimationTargetId(anim);
|
|
23803
24455
|
const seqTrigger = anim.trigger ?? 'onShapeClick';
|
|
23804
24456
|
const baseDuration = isCommand ? 0 : (anim.durationMs ?? defaultDuration(anim.presetClass));
|
|
23805
24457
|
// Same single-quantity rule as the main sequence: never sum the two.
|
|
@@ -23808,7 +24460,7 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23808
24460
|
const presetClass = isCommand ? 'emph' : (anim.presetClass ?? 'entr');
|
|
23809
24461
|
const fill = fillModeForClass(anim.presetClass);
|
|
23810
24462
|
const timing = isCommand
|
|
23811
|
-
? { durationMs: 0, iterationCount: 1, holdEndState: false }
|
|
24463
|
+
? { durationMs: 0, iterationCount: 1, activeDurationMs: 0, holdEndState: false }
|
|
23812
24464
|
: resolveEffectTiming(anim, baseDuration);
|
|
23813
24465
|
const duration = timing.durationMs;
|
|
23814
24466
|
const iterCount = timing.iterationCount;
|
|
@@ -23821,15 +24473,26 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23821
24473
|
seqGroups.push(finalizeClickGroup(seqGroup));
|
|
23822
24474
|
seqGroup = [];
|
|
23823
24475
|
}
|
|
24476
|
+
const prevStep = seqGroup.length > 0 ? seqGroup[seqGroup.length - 1] : undefined;
|
|
23824
24477
|
let delayMs;
|
|
23825
|
-
if (
|
|
23826
|
-
|
|
23827
|
-
|
|
24478
|
+
if (anim.parGroupIndex !== undefined) {
|
|
24479
|
+
if (anim.parGroupIndex !== subGroupIndex) {
|
|
24480
|
+
subGroupIndex = anim.parGroupIndex;
|
|
24481
|
+
subGroupStartMs =
|
|
24482
|
+
anim.parGroupDelayMs ??
|
|
24483
|
+
(prevStep
|
|
24484
|
+
? seqTrigger === 'withPrevious'
|
|
24485
|
+
? prevStep.delayMs
|
|
24486
|
+
: prevStep.delayMs + prevStep.durationMs
|
|
24487
|
+
: 0);
|
|
24488
|
+
}
|
|
24489
|
+
delayMs = subGroupStartMs + animDelay + triggerDelay;
|
|
24490
|
+
}
|
|
24491
|
+
else if (seqTrigger === 'withPrevious' && prevStep) {
|
|
24492
|
+
delayMs = prevStep.delayMs + animDelay + triggerDelay;
|
|
23828
24493
|
}
|
|
23829
|
-
else if ((seqTrigger === 'afterPrevious' || seqTrigger === 'afterDelay') &&
|
|
23830
|
-
|
|
23831
|
-
const prev = seqGroup[seqGroup.length - 1];
|
|
23832
|
-
delayMs = prev.delayMs + prev.durationMs + animDelay + triggerDelay;
|
|
24494
|
+
else if ((seqTrigger === 'afterPrevious' || seqTrigger === 'afterDelay') && prevStep) {
|
|
24495
|
+
delayMs = prevStep.delayMs + prevStep.durationMs + animDelay + triggerDelay;
|
|
23833
24496
|
}
|
|
23834
24497
|
else {
|
|
23835
24498
|
delayMs = animDelay + triggerDelay;
|
|
@@ -23845,17 +24508,17 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23845
24508
|
// main-sequence one.
|
|
23846
24509
|
const afterFields = isCommand
|
|
23847
24510
|
? { cssAnimation: baseCssAnimation, holdEndState: timing.holdEndState }
|
|
23848
|
-
: resolveAfterAnimationStepFields(anim, baseCssAnimation, timing.holdEndState, delayMs +
|
|
24511
|
+
: resolveAfterAnimationStepFields(anim, baseCssAnimation, timing.holdEndState, delayMs + timing.activeDurationMs, `pptx-tl-dim-${dynamicUid++}`);
|
|
23849
24512
|
if (afterFields.dimKeyframeBlock) {
|
|
23850
24513
|
dynamicBlocks.push(afterFields.dimKeyframeBlock);
|
|
23851
24514
|
}
|
|
23852
|
-
|
|
24515
|
+
const step = {
|
|
23853
24516
|
elementId,
|
|
23854
24517
|
cssAnimation: afterFields.cssAnimation,
|
|
23855
24518
|
keyframeName: keyframe,
|
|
23856
24519
|
trigger: seqTrigger,
|
|
23857
24520
|
delayMs,
|
|
23858
|
-
durationMs:
|
|
24521
|
+
durationMs: timing.activeDurationMs,
|
|
23859
24522
|
fillMode: fill,
|
|
23860
24523
|
presetClass: presetClass,
|
|
23861
24524
|
soundPath: anim.soundPath,
|
|
@@ -23871,7 +24534,18 @@ function buildSequenceGroups(animsByKey, entranceIds, neededKeyframes, dynamicBl
|
|
|
23871
24534
|
seqNextAction: anim.seqNextAction,
|
|
23872
24535
|
seqPrevAction: anim.seqPrevAction,
|
|
23873
24536
|
exclGroupId: anim.exclGroupId,
|
|
23874
|
-
}
|
|
24537
|
+
};
|
|
24538
|
+
const previousParallelStep = seqGroup[seqGroup.length - 1];
|
|
24539
|
+
if (anim.parGroupIndex !== undefined &&
|
|
24540
|
+
anim.parGroupIndex === seqGroupLastParallelIndex &&
|
|
24541
|
+
previousParallelStep &&
|
|
24542
|
+
canComposeParallelSteps(previousParallelStep, step)) {
|
|
24543
|
+
seqGroup[seqGroup.length - 1] = composeParallelSteps(previousParallelStep, step);
|
|
24544
|
+
}
|
|
24545
|
+
else {
|
|
24546
|
+
seqGroup.push(step);
|
|
24547
|
+
}
|
|
24548
|
+
seqGroupLastParallelIndex = anim.parGroupIndex;
|
|
23875
24549
|
}
|
|
23876
24550
|
if (seqGroup.length > 0) {
|
|
23877
24551
|
seqGroups.push(finalizeClickGroup(seqGroup));
|
|
@@ -24275,9 +24949,15 @@ class TimelineEngine {
|
|
|
24275
24949
|
advanceInteractive(triggerShapeId, nowMs = Date.now()) {
|
|
24276
24950
|
const groups = this.timeline.interactiveSequences.get(triggerShapeId);
|
|
24277
24951
|
const currentIdx = this.interactiveGroupIndexes.get(triggerShapeId) ?? -1;
|
|
24278
|
-
|
|
24952
|
+
let result = this.advanceSequenceGroup(groups, currentIdx, this.interactiveGroupStartedAtMs.get(triggerShapeId), nowMs);
|
|
24279
24953
|
if (result === 'exhausted') {
|
|
24280
|
-
|
|
24954
|
+
if (!this.timeline.restartableInteractiveSequences?.has(triggerShapeId)) {
|
|
24955
|
+
return null;
|
|
24956
|
+
}
|
|
24957
|
+
result = this.advanceSequenceGroup(groups, -1, undefined, nowMs);
|
|
24958
|
+
if (result === 'exhausted') {
|
|
24959
|
+
return null;
|
|
24960
|
+
}
|
|
24281
24961
|
}
|
|
24282
24962
|
if (result === 'blocked') {
|
|
24283
24963
|
return EMPTY_CLICK_GROUP;
|
|
@@ -25045,6 +25725,9 @@ function motionPathNativeAnimations(slide) {
|
|
|
25045
25725
|
delayMs: animation.delayMs ?? 0,
|
|
25046
25726
|
motionPath: animation.motionPath,
|
|
25047
25727
|
motionPathEditMode: animation.motionPathEditMode ?? 'relative',
|
|
25728
|
+
motionPathRotationAngle: animation.motionPathRotationAngle,
|
|
25729
|
+
motionPathRotationCenterX: animation.motionPathRotationCenterX,
|
|
25730
|
+
motionPathRotationCenterY: animation.motionPathRotationCenterY,
|
|
25048
25731
|
}));
|
|
25049
25732
|
}
|
|
25050
25733
|
/**
|
|
@@ -25173,8 +25856,9 @@ class PresentationAnimationController {
|
|
|
25173
25856
|
const engine = TimelineEngine.fromAnimations(expandedAnims);
|
|
25174
25857
|
const elementIds = slide.elements.map((element) => element.id);
|
|
25175
25858
|
for (const anim of expandedAnims) {
|
|
25176
|
-
|
|
25177
|
-
|
|
25859
|
+
const targetId = resolveAnimationTargetId(anim);
|
|
25860
|
+
if (targetId.includes(TEXT_BUILD_ID_SEP)) {
|
|
25861
|
+
elementIds.push(targetId);
|
|
25178
25862
|
}
|
|
25179
25863
|
}
|
|
25180
25864
|
return new PresentationAnimationController(engine, elementIds);
|
|
@@ -30212,7 +30896,7 @@ function getImageFitStyle(el) {
|
|
|
30212
30896
|
height: '100%',
|
|
30213
30897
|
objectFit: 'fill',
|
|
30214
30898
|
};
|
|
30215
|
-
if (!isImageLikeElement(el)) {
|
|
30899
|
+
if (!isImageLikeElement(el) && el.type !== 'media') {
|
|
30216
30900
|
return uncropped;
|
|
30217
30901
|
}
|
|
30218
30902
|
const { placement, crop } = imageFitTransformParts(el);
|
|
@@ -30243,7 +30927,7 @@ const IDENTITY_TRANSFORM_PAIR = 'translate(0%, 0%) scale(1, 1)';
|
|
|
30243
30927
|
* PLACEMENT and the `a:srcRect` source CROP. Either is `''` when absent.
|
|
30244
30928
|
*/
|
|
30245
30929
|
function imageFitTransformParts(el) {
|
|
30246
|
-
if (!isImageLikeElement(el)) {
|
|
30930
|
+
if (!isImageLikeElement(el) && el.type !== 'media') {
|
|
30247
30931
|
return { placement: '', crop: '' };
|
|
30248
30932
|
}
|
|
30249
30933
|
// `a:stretch/a:fillRect` stretches the (cropped) image into a sub-rect of
|
|
@@ -41221,7 +41905,13 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
41221
41905
|
const hasVisibleTextContent = paraSegments.some((seg) => seg !== markerSegment && Boolean(seg.text) && seg.text.trim().length > 0);
|
|
41222
41906
|
const bullet = hasVisibleTextContent ? bulletResult : undefined;
|
|
41223
41907
|
const indent = resolveParagraphIndent(paragraphIndents?.[paraIndex], firstSeg?.paragraphLevel);
|
|
41224
|
-
|
|
41908
|
+
// A bare negative indent without marL or a bullet is not a hanging
|
|
41909
|
+
// indent. Applying it directly sends ordinary text outside its box.
|
|
41910
|
+
const textIndentPx = indent.textIndentPx !== undefined &&
|
|
41911
|
+
(indent.textIndentPx >= 0 || indent.marginLeftPx !== undefined || bullet !== undefined)
|
|
41912
|
+
? indent.textIndentPx
|
|
41913
|
+
: undefined;
|
|
41914
|
+
const bulletStyle = buildBulletMarkerStyle(bullet, firstSeg, fontScale, textIndentPx);
|
|
41225
41915
|
const spacing = resolveParagraphSpacing({
|
|
41226
41916
|
paraProps: propsCarrier?.paragraphProperties,
|
|
41227
41917
|
bodyStyle,
|
|
@@ -41259,7 +41949,7 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
41259
41949
|
bulletPicture: bullet?.picture,
|
|
41260
41950
|
bulletStyle,
|
|
41261
41951
|
marginLeftPx: indent.marginLeftPx,
|
|
41262
|
-
textIndentPx
|
|
41952
|
+
textIndentPx,
|
|
41263
41953
|
lineHeight: spacing.lineHeight,
|
|
41264
41954
|
spaceBeforePx: spacing.spaceBeforePx,
|
|
41265
41955
|
spaceAfterPx: spacing.spaceAfterPx,
|
|
@@ -48859,6 +49549,7 @@ const COMPLEX_SLIDE_FIELDS = {
|
|
|
48859
49549
|
activeXControls: '_ax',
|
|
48860
49550
|
legacyVmlElements: '_lvml',
|
|
48861
49551
|
backgroundPattern: '_bp',
|
|
49552
|
+
backgroundImageProperties: '_bip',
|
|
48862
49553
|
modernCommentPart: '_mc',
|
|
48863
49554
|
headerFooterFlags: '_hff',
|
|
48864
49555
|
slideSynchronization: '_sync',
|
|
@@ -56984,8 +57675,53 @@ function buildPieChart3DDataForElement(element, options) {
|
|
|
56984
57675
|
*
|
|
56985
57676
|
* @module text-wrap-estimate
|
|
56986
57677
|
*/
|
|
56987
|
-
|
|
56988
|
-
|
|
57678
|
+
function estimatedGlyphAdvanceRatio(glyph) {
|
|
57679
|
+
if (/\p{Mark}/u.test(glyph)) {
|
|
57680
|
+
return 0;
|
|
57681
|
+
}
|
|
57682
|
+
if (/\s/u.test(glyph)) {
|
|
57683
|
+
return 0.33;
|
|
57684
|
+
}
|
|
57685
|
+
if (/[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Extended_Pictographic}]/u.test(glyph)) {
|
|
57686
|
+
return 1;
|
|
57687
|
+
}
|
|
57688
|
+
if (/[A-Z]/u.test(glyph)) {
|
|
57689
|
+
return 0.65;
|
|
57690
|
+
}
|
|
57691
|
+
if (/[a-z0-9]/u.test(glyph)) {
|
|
57692
|
+
return 0.55;
|
|
57693
|
+
}
|
|
57694
|
+
if (/[,.;:!?()\u005b\u005d{}'"`\-_/\\]/u.test(glyph)) {
|
|
57695
|
+
return 0.35;
|
|
57696
|
+
}
|
|
57697
|
+
return 0.6;
|
|
57698
|
+
}
|
|
57699
|
+
function estimatedTextWidth(glyphs, fontSize) {
|
|
57700
|
+
return glyphs.reduce((sum, glyph) => sum + estimatedGlyphAdvanceRatio(glyph) * fontSize, 0);
|
|
57701
|
+
}
|
|
57702
|
+
const HANGING_PUNCTUATION_RE = /^[\u3001\u3002\uff0c\uff0e\uff01\uff1f\uff1b\uff1a\u3009\u300b\u300d\u300f\u3011\u3015\u3017\u3019\u301b\uff09\uff3d\uff5d\u2019\u201d\u00bb\u203a]$/u;
|
|
57703
|
+
const BREAKABLE_GLYPH_RE = /^[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}\p{Extended_Pictographic}]$/u;
|
|
57704
|
+
function estimatedWrapUnits(text) {
|
|
57705
|
+
const units = [];
|
|
57706
|
+
let unbreakableRun = '';
|
|
57707
|
+
const flushRun = () => {
|
|
57708
|
+
if (unbreakableRun.length > 0) {
|
|
57709
|
+
units.push(unbreakableRun);
|
|
57710
|
+
unbreakableRun = '';
|
|
57711
|
+
}
|
|
57712
|
+
};
|
|
57713
|
+
for (const glyph of Array.from(text)) {
|
|
57714
|
+
if (/\s/u.test(glyph) || BREAKABLE_GLYPH_RE.test(glyph)) {
|
|
57715
|
+
flushRun();
|
|
57716
|
+
units.push(glyph);
|
|
57717
|
+
}
|
|
57718
|
+
else {
|
|
57719
|
+
unbreakableRun += glyph;
|
|
57720
|
+
}
|
|
57721
|
+
}
|
|
57722
|
+
flushRun();
|
|
57723
|
+
return units;
|
|
57724
|
+
}
|
|
56989
57725
|
/**
|
|
56990
57726
|
* Break `text` into lines that approximately fit `maxWidth`.
|
|
56991
57727
|
*
|
|
@@ -57003,8 +57739,7 @@ function wrapTextByEstimatedWidth(text, maxWidth, fontSize, options = {}) {
|
|
|
57003
57739
|
if (!text || text.trim().length === 0) {
|
|
57004
57740
|
return [];
|
|
57005
57741
|
}
|
|
57006
|
-
|
|
57007
|
-
if (charactersPerLine <= 0) {
|
|
57742
|
+
if (!(maxWidth > 0) || !(fontSize > 0)) {
|
|
57008
57743
|
return [];
|
|
57009
57744
|
}
|
|
57010
57745
|
const lines = [];
|
|
@@ -57016,20 +57751,31 @@ function wrapTextByEstimatedWidth(text, maxWidth, fontSize, options = {}) {
|
|
|
57016
57751
|
continue;
|
|
57017
57752
|
}
|
|
57018
57753
|
let current = '';
|
|
57019
|
-
|
|
57020
|
-
|
|
57021
|
-
|
|
57754
|
+
let pendingWhitespace = false;
|
|
57755
|
+
for (const unit of estimatedWrapUnits(paragraph)) {
|
|
57756
|
+
if (/^\s+$/u.test(unit)) {
|
|
57757
|
+
pendingWhitespace = current.length > 0;
|
|
57758
|
+
continue;
|
|
57022
57759
|
}
|
|
57023
|
-
|
|
57024
|
-
|
|
57760
|
+
const separator = pendingWhitespace && current.length > 0 ? ' ' : '';
|
|
57761
|
+
const candidate = `${current}${separator}${unit}`;
|
|
57762
|
+
if (current.length === 0 || estimatedTextWidth(Array.from(candidate), fontSize) <= maxWidth) {
|
|
57763
|
+
current = candidate;
|
|
57764
|
+
pendingWhitespace = false;
|
|
57765
|
+
continue;
|
|
57025
57766
|
}
|
|
57026
|
-
|
|
57027
|
-
|
|
57028
|
-
|
|
57767
|
+
if (HANGING_PUNCTUATION_RE.test(unit)) {
|
|
57768
|
+
current += unit;
|
|
57769
|
+
pendingWhitespace = false;
|
|
57770
|
+
continue;
|
|
57029
57771
|
}
|
|
57030
|
-
}
|
|
57031
|
-
if (current.length > 0) {
|
|
57032
57772
|
lines.push(current);
|
|
57773
|
+
current = unit;
|
|
57774
|
+
pendingWhitespace = false;
|
|
57775
|
+
}
|
|
57776
|
+
const completed = current.trimEnd();
|
|
57777
|
+
if (completed.length > 0) {
|
|
57778
|
+
lines.push(completed);
|
|
57033
57779
|
}
|
|
57034
57780
|
}
|
|
57035
57781
|
return lines;
|
|
@@ -57064,7 +57810,7 @@ function centeredSvgTextLines(text, fontSize, options = {}) {
|
|
|
57064
57810
|
if (lines.length === 0) {
|
|
57065
57811
|
return [{ text: '', y: centerY }];
|
|
57066
57812
|
}
|
|
57067
|
-
const lineHeight = fontSize * LINE_HEIGHT_RATIO$1;
|
|
57813
|
+
const lineHeight = options.lineHeight ?? fontSize * (options.lineHeightRatio ?? LINE_HEIGHT_RATIO$1);
|
|
57068
57814
|
const blockTop = centerY - (lines.length * lineHeight) / 2;
|
|
57069
57815
|
return lines.map((line, index) => ({
|
|
57070
57816
|
text: line,
|
|
@@ -57141,6 +57887,14 @@ function buildChromeStyle(chrome) {
|
|
|
57141
57887
|
* outline.
|
|
57142
57888
|
*/
|
|
57143
57889
|
const TEXT_WIDTH_FRACTION = 0.82;
|
|
57890
|
+
const CJK_SMARTART_TEXT_RE = /[\p{Script=Han}\p{Script=Hiragana}\p{Script=Katakana}\p{Script=Hangul}]/u;
|
|
57891
|
+
const CJK_SMARTART_LINE_HEIGHT_RATIO = 1.33;
|
|
57892
|
+
const DEFAULT_SMARTART_LINE_HEIGHT_RATIO = 1.2;
|
|
57893
|
+
function drawingTextBaseLineHeightRatio(text) {
|
|
57894
|
+
return CJK_SMARTART_TEXT_RE.test(text ?? '')
|
|
57895
|
+
? CJK_SMARTART_LINE_HEIGHT_RATIO
|
|
57896
|
+
: DEFAULT_SMARTART_LINE_HEIGHT_RATIO;
|
|
57897
|
+
}
|
|
57144
57898
|
/**
|
|
57145
57899
|
* The fill of the nearest shape painted beneath `shape`'s centre.
|
|
57146
57900
|
*
|
|
@@ -57186,17 +57940,21 @@ function computeDrawingViewBox(shapes) {
|
|
|
57186
57940
|
let maxX = -Infinity;
|
|
57187
57941
|
let maxY = -Infinity;
|
|
57188
57942
|
for (const s of shapes) {
|
|
57189
|
-
|
|
57190
|
-
|
|
57943
|
+
const shapeMinX = Math.min(s.x, s.textFrameX ?? s.x);
|
|
57944
|
+
const shapeMinY = Math.min(s.y, s.textFrameY ?? s.y);
|
|
57945
|
+
const shapeMaxX = Math.max(s.x + s.width, (s.textFrameX ?? s.x) + (s.textFrameWidth ?? s.width));
|
|
57946
|
+
const shapeMaxY = Math.max(s.y + s.height, (s.textFrameY ?? s.y) + (s.textFrameHeight ?? s.height));
|
|
57947
|
+
if (shapeMinX < minX) {
|
|
57948
|
+
minX = shapeMinX;
|
|
57191
57949
|
}
|
|
57192
|
-
if (
|
|
57193
|
-
minY =
|
|
57950
|
+
if (shapeMinY < minY) {
|
|
57951
|
+
minY = shapeMinY;
|
|
57194
57952
|
}
|
|
57195
|
-
if (
|
|
57196
|
-
maxX =
|
|
57953
|
+
if (shapeMaxX > maxX) {
|
|
57954
|
+
maxX = shapeMaxX;
|
|
57197
57955
|
}
|
|
57198
|
-
if (
|
|
57199
|
-
maxY =
|
|
57956
|
+
if (shapeMaxY > maxY) {
|
|
57957
|
+
maxY = shapeMaxY;
|
|
57200
57958
|
}
|
|
57201
57959
|
}
|
|
57202
57960
|
if (!Number.isFinite(minX)) {
|
|
@@ -57247,14 +58005,22 @@ function resolveShapeKind(shape, hasImage) {
|
|
|
57247
58005
|
if (hasImage) {
|
|
57248
58006
|
return 'image';
|
|
57249
58007
|
}
|
|
57250
|
-
// `getShapeType` folds the aliases it knows (oval -> ellipse, can -> cylinder)
|
|
57251
|
-
// but has no vocabulary for the arrow presets SmartArt process layouts use, so
|
|
57252
|
-
// those are matched on the normalised raw type.
|
|
57253
58008
|
const normalized = (shape.shapeType ?? '').trim().toLowerCase();
|
|
57254
|
-
if (normalized === '
|
|
57255
|
-
return '
|
|
58009
|
+
if (normalized === 'ellipse' || normalized === 'oval') {
|
|
58010
|
+
return 'ellipse';
|
|
57256
58011
|
}
|
|
57257
|
-
|
|
58012
|
+
const identityPresets = new Set(['rect', 'flowchartprocess', 'roundrect']);
|
|
58013
|
+
return identityPresets.has(normalized) || normalized.length === 0 ? 'rect' : 'path';
|
|
58014
|
+
}
|
|
58015
|
+
function drawingShapeTransform(shape, cx, cy) {
|
|
58016
|
+
const transforms = [];
|
|
58017
|
+
if (shape.rotation) {
|
|
58018
|
+
transforms.push(`rotate(${shape.rotation} ${cx} ${cy})`);
|
|
58019
|
+
}
|
|
58020
|
+
if (shape.flipHorizontal || shape.flipVertical) {
|
|
58021
|
+
transforms.push(`translate(${cx} ${cy}) scale(${shape.flipHorizontal ? -1 : 1} ${shape.flipVertical ? -1 : 1}) translate(${-cx} ${-cy})`);
|
|
58022
|
+
}
|
|
58023
|
+
return transforms.length > 0 ? transforms.join(' ') : undefined;
|
|
57258
58024
|
}
|
|
57259
58025
|
/**
|
|
57260
58026
|
* Project raw `PptxSmartArtDrawingShape`s into `RenderedShape` view-models,
|
|
@@ -57281,13 +58047,46 @@ function projectDrawingShapes(elementId, shapes, viewBox, palette, style) {
|
|
|
57281
58047
|
const cx = relX + shape.width / 2;
|
|
57282
58048
|
const cy = relY + shape.height / 2;
|
|
57283
58049
|
const stroke = shape.strokeColor ?? (sw > 0 ? 'rgba(255,255,255,0.3)' : 'none');
|
|
57284
|
-
const transform =
|
|
58050
|
+
const transform = drawingShapeTransform(shape, cx, cy);
|
|
58051
|
+
const presetGeometry = kind === 'path'
|
|
58052
|
+
? getPresetShapeVectorGeometry(shape.shapeType, shape.width, shape.height, shape.shapeAdjustments)
|
|
58053
|
+
: undefined;
|
|
57285
58054
|
const fontSize = shape.fontSize ?? Math.max(8, Math.min(14, shape.height * 0.2));
|
|
58055
|
+
const hasTextFrame = Number.isFinite(shape.textFrameX) &&
|
|
58056
|
+
Number.isFinite(shape.textFrameY) &&
|
|
58057
|
+
Number.isFinite(shape.textFrameWidth) &&
|
|
58058
|
+
Number.isFinite(shape.textFrameHeight) &&
|
|
58059
|
+
(shape.textFrameWidth ?? 0) > 0 &&
|
|
58060
|
+
(shape.textFrameHeight ?? 0) > 0;
|
|
58061
|
+
const textFrameX = (hasTextFrame ? shape.textFrameX : shape.x) - minX;
|
|
58062
|
+
const textFrameY = (hasTextFrame ? shape.textFrameY : shape.y) - minY;
|
|
58063
|
+
const textFrameWidth = hasTextFrame ? shape.textFrameWidth : shape.width;
|
|
58064
|
+
const textFrameHeight = hasTextFrame ? shape.textFrameHeight : shape.height;
|
|
58065
|
+
const textInsetLeft = shape.textInsetLeft ?? 0;
|
|
58066
|
+
const textInsetRight = shape.textInsetRight ?? 0;
|
|
58067
|
+
const textInsetTop = shape.textInsetTop ?? 0;
|
|
58068
|
+
const textInsetBottom = shape.textInsetBottom ?? 0;
|
|
58069
|
+
const textContentWidth = Math.max(1, textFrameWidth - textInsetLeft - textInsetRight);
|
|
58070
|
+
const textContentHeight = Math.max(1, textFrameHeight - textInsetTop - textInsetBottom);
|
|
58071
|
+
const textCenterX = textFrameX + textInsetLeft + textContentWidth / 2;
|
|
58072
|
+
const textCenterY = textFrameY + textInsetTop + textContentHeight / 2;
|
|
58073
|
+
const textWrapWidth = hasTextFrame ? textContentWidth : shape.width * TEXT_WIDTH_FRACTION;
|
|
58074
|
+
const authoredLineHeightRatio = shape.lineHeightRatio ?? 1;
|
|
58075
|
+
const lineHeightRatio = drawingTextBaseLineHeightRatio(shape.text) * authoredLineHeightRatio +
|
|
58076
|
+
(shape.lineSpacingAfterRatio ?? 0);
|
|
58077
|
+
const lineHeight = shape.lineHeight !== undefined || shape.lineSpacingAfter !== undefined
|
|
58078
|
+
? (shape.lineHeight ??
|
|
58079
|
+
fontSize * drawingTextBaseLineHeightRatio(shape.text) * authoredLineHeightRatio) +
|
|
58080
|
+
(shape.lineSpacingAfter ?? 0)
|
|
58081
|
+
: undefined;
|
|
57286
58082
|
return {
|
|
57287
58083
|
key: `${elementId}-dsp-${shape.id}-${i}`,
|
|
57288
58084
|
kind,
|
|
57289
|
-
...(
|
|
57290
|
-
? {
|
|
58085
|
+
...(presetGeometry
|
|
58086
|
+
? {
|
|
58087
|
+
pathData: presetGeometry.d,
|
|
58088
|
+
pathTransform: [transform, `translate(${relX} ${relY})`].filter(Boolean).join(' '),
|
|
58089
|
+
}
|
|
57291
58090
|
: {}),
|
|
57292
58091
|
...(gradient ? { gradient } : {}),
|
|
57293
58092
|
x: relX,
|
|
@@ -57304,14 +58103,21 @@ function projectDrawingShapes(elementId, shapes, viewBox, palette, style) {
|
|
|
57304
58103
|
imageUrl: shape.fillImageUrl,
|
|
57305
58104
|
textLines: shape.text
|
|
57306
58105
|
? centeredSvgTextLines(shape.text, fontSize, {
|
|
57307
|
-
maxWidth:
|
|
57308
|
-
centerY:
|
|
58106
|
+
maxWidth: textWrapWidth,
|
|
58107
|
+
centerY: textCenterY,
|
|
58108
|
+
lineHeight,
|
|
58109
|
+
lineHeightRatio,
|
|
57309
58110
|
})
|
|
57310
58111
|
: [],
|
|
57311
|
-
textX:
|
|
57312
|
-
textY:
|
|
58112
|
+
textX: textCenterX,
|
|
58113
|
+
textY: textCenterY,
|
|
58114
|
+
textWidth: textContentWidth,
|
|
58115
|
+
textHeight: textContentHeight,
|
|
57313
58116
|
fontColor: shape.fontColor ?? drawingShapeLabelColor(shape, shapes, i, fill),
|
|
57314
58117
|
fontSize,
|
|
58118
|
+
fontFamily: shape.fontFamily ? getSubstituteFontFamily(shape.fontFamily) : undefined,
|
|
58119
|
+
fontWeight: shape.fontWeight,
|
|
58120
|
+
fontStyle: shape.fontStyle,
|
|
57315
58121
|
};
|
|
57316
58122
|
});
|
|
57317
58123
|
}
|
|
@@ -70603,6 +71409,7 @@ function masterViewParts(document, target) {
|
|
|
70603
71409
|
elements: master.elements ?? [],
|
|
70604
71410
|
backgroundColor: master.backgroundColor,
|
|
70605
71411
|
backgroundImage: master.backgroundImage,
|
|
71412
|
+
backgroundImageProperties: master.backgroundImageProperties,
|
|
70606
71413
|
};
|
|
70607
71414
|
const layout = target.layoutIndex === null ? undefined : master.layouts?.[target.layoutIndex];
|
|
70608
71415
|
if (!layout || target.layoutIndex === null) {
|
|
@@ -70618,6 +71425,9 @@ function masterViewParts(document, target) {
|
|
|
70618
71425
|
elements: layout.elements ?? [],
|
|
70619
71426
|
backgroundColor: layout.backgroundColor ?? master.backgroundColor,
|
|
70620
71427
|
backgroundImage: layout.backgroundImage ?? master.backgroundImage,
|
|
71428
|
+
backgroundImageProperties: layout.backgroundImage
|
|
71429
|
+
? layout.backgroundImageProperties
|
|
71430
|
+
: master.backgroundImageProperties,
|
|
70621
71431
|
},
|
|
70622
71432
|
];
|
|
70623
71433
|
}
|
|
@@ -70630,6 +71440,7 @@ function auxiliaryParts(kind, part) {
|
|
|
70630
71440
|
elements: part.elements ?? [],
|
|
70631
71441
|
backgroundColor: part.backgroundColor,
|
|
70632
71442
|
backgroundImage: part.backgroundImage,
|
|
71443
|
+
backgroundImageProperties: part.backgroundImageProperties,
|
|
70633
71444
|
},
|
|
70634
71445
|
]
|
|
70635
71446
|
: [];
|
|
@@ -70658,6 +71469,7 @@ function masterViewPseudoSlide(document, target) {
|
|
|
70658
71469
|
elements: parts.flatMap((part) => [...part.elements]),
|
|
70659
71470
|
backgroundColor: primary.backgroundColor,
|
|
70660
71471
|
backgroundImage: primary.backgroundImage,
|
|
71472
|
+
backgroundImageProperties: primary.backgroundImageProperties,
|
|
70661
71473
|
};
|
|
70662
71474
|
}
|
|
70663
71475
|
/** Every element the master-view canvas is currently painting. */
|
|
@@ -75533,6 +76345,17 @@ function buildPrintHtmlDocument(options) {
|
|
|
75533
76345
|
* then write the real document into that same window once it's ready. These
|
|
75534
76346
|
* two functions are the whole fix; every binding's print handler just calls
|
|
75535
76347
|
* them at the right points instead of re-implementing this dance itself.
|
|
76348
|
+
*
|
|
76349
|
+
* `window.open` is called WITHOUT `noopener`: with it, Chrome returns `null`
|
|
76350
|
+
* from `window.open` itself even though the tab genuinely opens (confirmed
|
|
76351
|
+
* live), so every caller here reads that as "popup blocked", bails out
|
|
76352
|
+
* having already left a stray blank tab behind, and never writes the print
|
|
76353
|
+
* document into it - the exact "print opens a blank tab and does nothing"
|
|
76354
|
+
* report this file exists to prevent. `noopener` protects against a page
|
|
76355
|
+
* reaching back into ITS OPENER via `window.opener` (reverse tabnabbing),
|
|
76356
|
+
* which only matters for a window opened to a third-party URL; this window
|
|
76357
|
+
* is opened blank (`''`) and filled entirely with the app's own
|
|
76358
|
+
* document.write() output, so there is no opener relationship worth cutting.
|
|
75536
76359
|
*/
|
|
75537
76360
|
/**
|
|
75538
76361
|
* Open a blank print window right now, synchronously, still inside the
|
|
@@ -75545,7 +76368,7 @@ function buildPrintHtmlDocument(options) {
|
|
|
75545
76368
|
* in the placeholder while the real document is assembled.
|
|
75546
76369
|
*/
|
|
75547
76370
|
function openPendingPrintWindow(preparingLabel) {
|
|
75548
|
-
const printWindow = window.open('', '_blank'
|
|
76371
|
+
const printWindow = window.open('', '_blank');
|
|
75549
76372
|
if (!printWindow) {
|
|
75550
76373
|
return null;
|
|
75551
76374
|
}
|
|
@@ -75577,7 +76400,7 @@ function finishPrintWindow(printWindow, htmlDocument) {
|
|
|
75577
76400
|
* and after its `await`s respectively.
|
|
75578
76401
|
*/
|
|
75579
76402
|
function openPrintWindow(htmlDocument) {
|
|
75580
|
-
const printWindow = window.open('', '_blank'
|
|
76403
|
+
const printWindow = window.open('', '_blank');
|
|
75581
76404
|
if (!printWindow) {
|
|
75582
76405
|
return false;
|
|
75583
76406
|
}
|
|
@@ -77654,7 +78477,7 @@ function createLocalStorageBackend(namespace) {
|
|
|
77654
78477
|
/** Try IndexedDB first; fall back to localStorage on any failure. */
|
|
77655
78478
|
async function resolveBackend(dbName, namespace) {
|
|
77656
78479
|
try {
|
|
77657
|
-
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-
|
|
78480
|
+
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-Cxqxc-c6.mjs');
|
|
77658
78481
|
const db = await openChatDb(dbName);
|
|
77659
78482
|
return createIdbBackend(db);
|
|
77660
78483
|
}
|
|
@@ -86397,11 +87220,11 @@ class SmartArtRendererComponent {
|
|
|
86397
87220
|
return rebuildDrawingShapesIfCleared(data, data.layout, resolvePalette(data), data.style ?? 'flat', el.id, { width: el.width, height: el.height });
|
|
86398
87221
|
}
|
|
86399
87222
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SmartArtRendererComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
86400
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SmartArtRendererComponent, isStandalone: true, selector: "pptx-smart-art-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, animationState: { classPropertyName: "animationState", publicName: "animationState", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "nodeEditor", first: true, predicate: ["nodeEditor"], descendants: true, isSignal: true }, { propertyName: "smartartContainer", first: true, predicate: ["smartartContainer"], descendants: true, isSignal: true }, { propertyName: "styleBar", first: true, predicate: ["styleBar"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n\t#smartartContainer\n\tclass=\"pptx-ng-smartart-chrome\"\n\t[ngStyle]=\"chromeStyle()\"\n\t[attr.role]=\"a11y() ? a11y()!.role : null\"\n\t[attr.aria-label]=\"a11y()?.label ?? null\"\n\t(mousemove)=\"onMouseMove($event)\"\n\t(mouseleave)=\"onMouseLeave()\"\n>\n\t@if (isEmpty()) {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t} @else if (hasDrawingShapes()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\tdata-testid=\"smartart-drawing-shapes\"\n\t\t\t[attr.viewBox]=\"svgViewBox()\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t>\n\t\t\t@for (shape of renderedShapes(); track shape.key; let i = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"drawingShapeNodeIds()[i] ?? null\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes() && !!drawingShapeNodeIds()[i]\"\n\t\t\t\t>\n\t\t\t\t\t@if (shape.gradient) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (shape.gradient!.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"shape.gradient!.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"shape.gradient!.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"shape.gradient!.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"shape.gradient!.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"shape.gradient!.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"shape.gradient!.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"shape.gradient!.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.kind === 'image') {\n\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.href]=\"shape.imageUrl\"\n\t\t\t\t\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'ellipse') {\n\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t[attr.cx]=\"shape.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"shape.cy\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.width / 2\"\n\t\t\t\t\t\t\t[attr.ry]=\"shape.height / 2\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'polygon') {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"shape.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.textLines.length > 0) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"shape.textX\"\n\t\t\t\t\t\t\ttext-anchor=\"middle\"\n\t\t\t\t\t\t\tdominant-baseline=\"central\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fontColor\"\n\t\t\t\t\t\t\t[attr.font-size]=\"shape.fontSize\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of shape.textLines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"shape.textX\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else if (hasLayout()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\t[attr.data-testid]=\"'smartart-' + layout().family\"\n\t\t\t[attr.viewBox]=\"layout().viewBox\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t[attr.data-layout-family]=\"layout().family\"\n\t\t>\n\t\t\t@for (conn of layout().connectors; track conn.key; let ci = $index) {\n\t\t\t\t<path\n\t\t\t\t\t[attr.d]=\"layoutConnectors()[ci]!.d\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t[attr.stroke]=\"layoutConnectors()[ci]!.stroke\"\n\t\t\t\t\t[attr.stroke-width]=\"layoutConnectors()[ci]!.strokeWidth\"\n\t\t\t\t\t[attr.opacity]=\"layoutConnectors()[ci]!.opacity\"\n\t\t\t\t\t[attr.stroke-dasharray]=\"layoutConnectors()[ci]!.dash ?? null\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (node of layout().nodes; track node.key; let ni = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes()\"\n\t\t\t\t\t[attr.tabindex]=\"canEditNodes() ? 0 : null\"\n\t\t\t\t\t[attr.role]=\"canEditNodes() ? 'button' : 'img'\"\n\t\t\t\t\t[attr.aria-label]=\"nodeAriaLabel(ni) ?? node.text\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"nodeIdAt(ni)\"\n\t\t\t\t\t(dblclick)=\"onNodeDblClick($event, node, ni)\"\n\t\t\t\t\t(keydown)=\"onNodeKeydown($event, node, ni)\"\n\t\t\t\t>\n\t\t\t\t\t@if (nodeAriaLabel(ni); as title) {\n\t\t\t\t\t\t<title>{{ title }}</title>\n\t\t\t\t\t}\n\t\t\t\t\t@if (asCircle(node); as c) {\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t[attr.fill]=\"c.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"c.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"c.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"c.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asPolygon(node); as p) {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"p.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"p.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"p.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"p.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"p.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asRect(node); as r) {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"r.x\"\n\t\t\t\t\t\t\t[attr.y]=\"r.y\"\n\t\t\t\t\t\t\t[attr.width]=\"r.width\"\n\t\t\t\t\t\t\t[attr.height]=\"r.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"r.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"r.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"r.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"r.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"r.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t<!--\n\t\t\t\t\t\tNode label. Placement, colour, weight and baseline arrive\n\t\t\t\t\t\talready decided from the shared `smartArtNodeLabel`, so an\n\t\t\t\t\t\toff-centre caption (target leader, gear legend row, timeline\n\t\t\t\t\t\tcaption above / below the axis) lands beside its node.\n\t\t\t\t\t-->\n\t\t\t\t\t@if (layoutLabels()[ni]!.visible) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"layoutLabels()[ni]!.x\"\n\t\t\t\t\t\t\t[attr.text-anchor]=\"layoutLabels()[ni]!.textAnchor\"\n\t\t\t\t\t\t\t[attr.dominant-baseline]=\"layoutLabels()[ni]!.dominantBaseline\"\n\t\t\t\t\t\t\t[attr.fill]=\"layoutLabels()[ni]!.fill\"\n\t\t\t\t\t\t\t[attr.font-size]=\"layoutLabels()[ni]!.fontSize\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"layoutLabels()[ni]!.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"layoutLabels()[ni]!.fontStyle ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of layoutLabels()[ni]!.lines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"layoutLabels()[ni]!.x\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t}\n\n\t@if (canEditNodes() && hoveredNodeId() && !editState() && styleBarStyle()) {\n\t\t<div\n\t\t\t#styleBar\n\t\t\tclass=\"pptx-ng-smartart-style-bar\"\n\t\t\t[ngStyle]=\"styleBarStyle()!\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t>\n\t\t\t@for (color of palette().slice(0, 6); track color) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-smartart-swatch\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t[attr.aria-label]=\"'pptx.smartArt.setFill' | translate: { color: color }\"\n\t\t\t\t\t[style.background]=\"color\"\n\t\t\t\t\t(click)=\"handleChangeNodeStyle(hoveredNodeId()!, color)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n\n\t<!--\n\t\tInline node-text editor. Positioned in element-local px (== viewBox\n\t\tunits, since the SVG viewBox matches the element pixel size and the\n\t\tsvg fills the chrome) over the double-clicked node. Commits via the\n\t\tshared EditorStateService.updateElement path on Enter / blur.\n\t-->\n\t@if (editState(); as edit) {\n\t\t<textarea\n\t\t\t#nodeEditor\n\t\t\tclass=\"pptx-ng-smartart-node-editor\"\n\t\t\t[style.left.px]=\"edit.box.x\"\n\t\t\t[style.top.px]=\"edit.box.y\"\n\t\t\t[style.width.px]=\"edit.box.width\"\n\t\t\t[style.height.px]=\"edit.box.height\"\n\t\t\t[value]=\"edit.text\"\n\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t(dblclick)=\"$event.stopPropagation()\"\n\t\t\t(blur)=\"commitEdit($event)\"\n\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t></textarea>\n\t}\n\n\t<!-- Polite live region: announces node-text edit commits to AT. -->\n\t<span class=\"pptx-ng-sr-only\" aria-live=\"polite\" role=\"status\">{{ liveMessage() }}</span>\n</div>\n", styles: [".pptx-ng-smartart-chrome{box-sizing:border-box;overflow:hidden;position:relative}.pptx-ng-smartart-svg{width:100%;height:100%;pointer-events:none}.pptx-ng-smartart-node--editable{pointer-events:auto;cursor:text}.pptx-ng-smartart-node--editable:hover{filter:drop-shadow(0 0 2px rgba(96,165,250,.8))}.pptx-ng-smartart-node-editor{position:absolute;box-sizing:border-box;margin:0;padding:1px 2px;border:1px solid var(--pptx-inspector-active, #0078d4);border-radius:2px;background:#fff;color:#111;font-size:11px;line-height:1.1;text-align:center;resize:none;overflow:hidden;z-index:2}.pptx-ng-smartart-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fffc;pointer-events:none}.pptx-ng-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pptx-ng-smartart-style-bar{position:absolute;pointer-events:auto;display:flex;gap:6px;padding:6px 8px;background:#ffffffe6;border:1px solid var(--border, #e2e8f0);border-radius:9999px;box-shadow:0 1px 2px #0000001a}.pptx-ng-smartart-swatch{width:20px;height:20px;border-radius:50%;border:1px solid rgba(0,0,0,.1);cursor:pointer;transition:transform .1s}.pptx-ng-smartart-swatch:hover{transform:scale(1.25)}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
87223
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.3", type: SmartArtRendererComponent, isStandalone: true, selector: "pptx-smart-art-renderer", inputs: { element: { classPropertyName: "element", publicName: "element", isSignal: true, isRequired: true, transformFunction: null }, editable: { classPropertyName: "editable", publicName: "editable", isSignal: true, isRequired: false, transformFunction: null }, animationState: { classPropertyName: "animationState", publicName: "animationState", isSignal: true, isRequired: false, transformFunction: null } }, viewQueries: [{ propertyName: "nodeEditor", first: true, predicate: ["nodeEditor"], descendants: true, isSignal: true }, { propertyName: "smartartContainer", first: true, predicate: ["smartartContainer"], descendants: true, isSignal: true }, { propertyName: "styleBar", first: true, predicate: ["styleBar"], descendants: true, isSignal: true }], ngImport: i0, template: "<div\n\t#smartartContainer\n\tclass=\"pptx-ng-smartart-chrome\"\n\t[ngStyle]=\"chromeStyle()\"\n\t[attr.role]=\"a11y() ? a11y()!.role : null\"\n\t[attr.aria-label]=\"a11y()?.label ?? null\"\n\t(mousemove)=\"onMouseMove($event)\"\n\t(mouseleave)=\"onMouseLeave()\"\n>\n\t@if (isEmpty()) {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t} @else if (hasDrawingShapes()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\tdata-testid=\"smartart-drawing-shapes\"\n\t\t\t[attr.viewBox]=\"svgViewBox()\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t>\n\t\t\t@for (shape of renderedShapes(); track shape.key; let i = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"drawingShapeNodeIds()[i] ?? null\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes() && !!drawingShapeNodeIds()[i]\"\n\t\t\t\t>\n\t\t\t\t\t@if (shape.gradient) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (shape.gradient!.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"shape.gradient!.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"shape.gradient!.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"shape.gradient!.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"shape.gradient!.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"shape.gradient!.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"shape.gradient!.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"shape.gradient!.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.kind === 'image') {\n\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.href]=\"shape.imageUrl\"\n\t\t\t\t\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'ellipse') {\n\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t[attr.cx]=\"shape.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"shape.cy\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.width / 2\"\n\t\t\t\t\t\t\t[attr.ry]=\"shape.height / 2\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'path') {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"shape.pathData\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.pathTransform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.textLines.length > 0) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"shape.textX\"\n\t\t\t\t\t\t\ttext-anchor=\"middle\"\n\t\t\t\t\t\t\tdominant-baseline=\"central\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fontColor\"\n\t\t\t\t\t\t\t[attr.font-family]=\"shape.fontFamily ?? null\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"shape.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"shape.fontStyle ?? null\"\n\t\t\t\t\t\t\t[attr.font-size]=\"shape.fontSize\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of shape.textLines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"shape.textX\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else if (hasLayout()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\t[attr.data-testid]=\"'smartart-' + layout().family\"\n\t\t\t[attr.viewBox]=\"layout().viewBox\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t[attr.data-layout-family]=\"layout().family\"\n\t\t>\n\t\t\t@for (conn of layout().connectors; track conn.key; let ci = $index) {\n\t\t\t\t<path\n\t\t\t\t\t[attr.d]=\"layoutConnectors()[ci]!.d\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t[attr.stroke]=\"layoutConnectors()[ci]!.stroke\"\n\t\t\t\t\t[attr.stroke-width]=\"layoutConnectors()[ci]!.strokeWidth\"\n\t\t\t\t\t[attr.opacity]=\"layoutConnectors()[ci]!.opacity\"\n\t\t\t\t\t[attr.stroke-dasharray]=\"layoutConnectors()[ci]!.dash ?? null\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (node of layout().nodes; track node.key; let ni = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes()\"\n\t\t\t\t\t[attr.tabindex]=\"canEditNodes() ? 0 : null\"\n\t\t\t\t\t[attr.role]=\"canEditNodes() ? 'button' : 'img'\"\n\t\t\t\t\t[attr.aria-label]=\"nodeAriaLabel(ni) ?? node.text\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"nodeIdAt(ni)\"\n\t\t\t\t\t(dblclick)=\"onNodeDblClick($event, node, ni)\"\n\t\t\t\t\t(keydown)=\"onNodeKeydown($event, node, ni)\"\n\t\t\t\t>\n\t\t\t\t\t@if (nodeAriaLabel(ni); as title) {\n\t\t\t\t\t\t<title>{{ title }}</title>\n\t\t\t\t\t}\n\t\t\t\t\t@if (asCircle(node); as c) {\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t[attr.fill]=\"c.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"c.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"c.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"c.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asPolygon(node); as p) {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"p.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"p.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"p.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"p.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"p.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asRect(node); as r) {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"r.x\"\n\t\t\t\t\t\t\t[attr.y]=\"r.y\"\n\t\t\t\t\t\t\t[attr.width]=\"r.width\"\n\t\t\t\t\t\t\t[attr.height]=\"r.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"r.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"r.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"r.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"r.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"r.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t<!--\n\t\t\t\t\t\tNode label. Placement, colour, weight and baseline arrive\n\t\t\t\t\t\talready decided from the shared `smartArtNodeLabel`, so an\n\t\t\t\t\t\toff-centre caption (target leader, gear legend row, timeline\n\t\t\t\t\t\tcaption above / below the axis) lands beside its node.\n\t\t\t\t\t-->\n\t\t\t\t\t@if (layoutLabels()[ni]!.visible) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"layoutLabels()[ni]!.x\"\n\t\t\t\t\t\t\t[attr.text-anchor]=\"layoutLabels()[ni]!.textAnchor\"\n\t\t\t\t\t\t\t[attr.dominant-baseline]=\"layoutLabels()[ni]!.dominantBaseline\"\n\t\t\t\t\t\t\t[attr.fill]=\"layoutLabels()[ni]!.fill\"\n\t\t\t\t\t\t\t[attr.font-size]=\"layoutLabels()[ni]!.fontSize\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"layoutLabels()[ni]!.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"layoutLabels()[ni]!.fontStyle ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of layoutLabels()[ni]!.lines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"layoutLabels()[ni]!.x\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t}\n\n\t@if (canEditNodes() && hoveredNodeId() && !editState() && styleBarStyle()) {\n\t\t<div\n\t\t\t#styleBar\n\t\t\tclass=\"pptx-ng-smartart-style-bar\"\n\t\t\t[ngStyle]=\"styleBarStyle()!\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t>\n\t\t\t@for (color of palette().slice(0, 6); track color) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-smartart-swatch\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t[attr.aria-label]=\"'pptx.smartArt.setFill' | translate: { color: color }\"\n\t\t\t\t\t[style.background]=\"color\"\n\t\t\t\t\t(click)=\"handleChangeNodeStyle(hoveredNodeId()!, color)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n\n\t<!--\n\t\tInline node-text editor. Positioned in element-local px (== viewBox\n\t\tunits, since the SVG viewBox matches the element pixel size and the\n\t\tsvg fills the chrome) over the double-clicked node. Commits via the\n\t\tshared EditorStateService.updateElement path on Enter / blur.\n\t-->\n\t@if (editState(); as edit) {\n\t\t<textarea\n\t\t\t#nodeEditor\n\t\t\tclass=\"pptx-ng-smartart-node-editor\"\n\t\t\t[style.left.px]=\"edit.box.x\"\n\t\t\t[style.top.px]=\"edit.box.y\"\n\t\t\t[style.width.px]=\"edit.box.width\"\n\t\t\t[style.height.px]=\"edit.box.height\"\n\t\t\t[value]=\"edit.text\"\n\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t(dblclick)=\"$event.stopPropagation()\"\n\t\t\t(blur)=\"commitEdit($event)\"\n\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t></textarea>\n\t}\n\n\t<!-- Polite live region: announces node-text edit commits to AT. -->\n\t<span class=\"pptx-ng-sr-only\" aria-live=\"polite\" role=\"status\">{{ liveMessage() }}</span>\n</div>\n", styles: [".pptx-ng-smartart-chrome{box-sizing:border-box;overflow:hidden;position:relative}.pptx-ng-smartart-svg{width:100%;height:100%;pointer-events:none}.pptx-ng-smartart-node--editable{pointer-events:auto;cursor:text}.pptx-ng-smartart-node--editable:hover{filter:drop-shadow(0 0 2px rgba(96,165,250,.8))}.pptx-ng-smartart-node-editor{position:absolute;box-sizing:border-box;margin:0;padding:1px 2px;border:1px solid var(--pptx-inspector-active, #0078d4);border-radius:2px;background:#fff;color:#111;font-size:11px;line-height:1.1;text-align:center;resize:none;overflow:hidden;z-index:2}.pptx-ng-smartart-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fffc;pointer-events:none}.pptx-ng-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pptx-ng-smartart-style-bar{position:absolute;pointer-events:auto;display:flex;gap:6px;padding:6px 8px;background:#ffffffe6;border:1px solid var(--border, #e2e8f0);border-radius:9999px;box-shadow:0 1px 2px #0000001a}.pptx-ng-smartart-swatch{width:20px;height:20px;border-radius:50%;border:1px solid rgba(0,0,0,.1);cursor:pointer;transition:transform .1s}.pptx-ng-smartart-swatch:hover{transform:scale(1.25)}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
86401
87224
|
}
|
|
86402
87225
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: SmartArtRendererComponent, decorators: [{
|
|
86403
87226
|
type: Component,
|
|
86404
|
-
args: [{ selector: 'pptx-smart-art-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, TranslatePipe], template: "<div\n\t#smartartContainer\n\tclass=\"pptx-ng-smartart-chrome\"\n\t[ngStyle]=\"chromeStyle()\"\n\t[attr.role]=\"a11y() ? a11y()!.role : null\"\n\t[attr.aria-label]=\"a11y()?.label ?? null\"\n\t(mousemove)=\"onMouseMove($event)\"\n\t(mouseleave)=\"onMouseLeave()\"\n>\n\t@if (isEmpty()) {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t} @else if (hasDrawingShapes()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\tdata-testid=\"smartart-drawing-shapes\"\n\t\t\t[attr.viewBox]=\"svgViewBox()\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t>\n\t\t\t@for (shape of renderedShapes(); track shape.key; let i = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"drawingShapeNodeIds()[i] ?? null\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes() && !!drawingShapeNodeIds()[i]\"\n\t\t\t\t>\n\t\t\t\t\t@if (shape.gradient) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (shape.gradient!.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"shape.gradient!.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"shape.gradient!.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"shape.gradient!.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"shape.gradient!.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"shape.gradient!.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"shape.gradient!.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"shape.gradient!.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.kind === 'image') {\n\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.href]=\"shape.imageUrl\"\n\t\t\t\t\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'ellipse') {\n\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t[attr.cx]=\"shape.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"shape.cy\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.width / 2\"\n\t\t\t\t\t\t\t[attr.ry]=\"shape.height / 2\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'polygon') {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"shape.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.textLines.length > 0) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"shape.textX\"\n\t\t\t\t\t\t\ttext-anchor=\"middle\"\n\t\t\t\t\t\t\tdominant-baseline=\"central\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fontColor\"\n\t\t\t\t\t\t\t[attr.font-size]=\"shape.fontSize\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of shape.textLines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"shape.textX\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else if (hasLayout()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\t[attr.data-testid]=\"'smartart-' + layout().family\"\n\t\t\t[attr.viewBox]=\"layout().viewBox\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t[attr.data-layout-family]=\"layout().family\"\n\t\t>\n\t\t\t@for (conn of layout().connectors; track conn.key; let ci = $index) {\n\t\t\t\t<path\n\t\t\t\t\t[attr.d]=\"layoutConnectors()[ci]!.d\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t[attr.stroke]=\"layoutConnectors()[ci]!.stroke\"\n\t\t\t\t\t[attr.stroke-width]=\"layoutConnectors()[ci]!.strokeWidth\"\n\t\t\t\t\t[attr.opacity]=\"layoutConnectors()[ci]!.opacity\"\n\t\t\t\t\t[attr.stroke-dasharray]=\"layoutConnectors()[ci]!.dash ?? null\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (node of layout().nodes; track node.key; let ni = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes()\"\n\t\t\t\t\t[attr.tabindex]=\"canEditNodes() ? 0 : null\"\n\t\t\t\t\t[attr.role]=\"canEditNodes() ? 'button' : 'img'\"\n\t\t\t\t\t[attr.aria-label]=\"nodeAriaLabel(ni) ?? node.text\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"nodeIdAt(ni)\"\n\t\t\t\t\t(dblclick)=\"onNodeDblClick($event, node, ni)\"\n\t\t\t\t\t(keydown)=\"onNodeKeydown($event, node, ni)\"\n\t\t\t\t>\n\t\t\t\t\t@if (nodeAriaLabel(ni); as title) {\n\t\t\t\t\t\t<title>{{ title }}</title>\n\t\t\t\t\t}\n\t\t\t\t\t@if (asCircle(node); as c) {\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t[attr.fill]=\"c.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"c.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"c.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"c.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asPolygon(node); as p) {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"p.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"p.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"p.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"p.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"p.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asRect(node); as r) {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"r.x\"\n\t\t\t\t\t\t\t[attr.y]=\"r.y\"\n\t\t\t\t\t\t\t[attr.width]=\"r.width\"\n\t\t\t\t\t\t\t[attr.height]=\"r.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"r.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"r.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"r.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"r.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"r.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t<!--\n\t\t\t\t\t\tNode label. Placement, colour, weight and baseline arrive\n\t\t\t\t\t\talready decided from the shared `smartArtNodeLabel`, so an\n\t\t\t\t\t\toff-centre caption (target leader, gear legend row, timeline\n\t\t\t\t\t\tcaption above / below the axis) lands beside its node.\n\t\t\t\t\t-->\n\t\t\t\t\t@if (layoutLabels()[ni]!.visible) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"layoutLabels()[ni]!.x\"\n\t\t\t\t\t\t\t[attr.text-anchor]=\"layoutLabels()[ni]!.textAnchor\"\n\t\t\t\t\t\t\t[attr.dominant-baseline]=\"layoutLabels()[ni]!.dominantBaseline\"\n\t\t\t\t\t\t\t[attr.fill]=\"layoutLabels()[ni]!.fill\"\n\t\t\t\t\t\t\t[attr.font-size]=\"layoutLabels()[ni]!.fontSize\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"layoutLabels()[ni]!.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"layoutLabels()[ni]!.fontStyle ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of layoutLabels()[ni]!.lines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"layoutLabels()[ni]!.x\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t}\n\n\t@if (canEditNodes() && hoveredNodeId() && !editState() && styleBarStyle()) {\n\t\t<div\n\t\t\t#styleBar\n\t\t\tclass=\"pptx-ng-smartart-style-bar\"\n\t\t\t[ngStyle]=\"styleBarStyle()!\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t>\n\t\t\t@for (color of palette().slice(0, 6); track color) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-smartart-swatch\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t[attr.aria-label]=\"'pptx.smartArt.setFill' | translate: { color: color }\"\n\t\t\t\t\t[style.background]=\"color\"\n\t\t\t\t\t(click)=\"handleChangeNodeStyle(hoveredNodeId()!, color)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n\n\t<!--\n\t\tInline node-text editor. Positioned in element-local px (== viewBox\n\t\tunits, since the SVG viewBox matches the element pixel size and the\n\t\tsvg fills the chrome) over the double-clicked node. Commits via the\n\t\tshared EditorStateService.updateElement path on Enter / blur.\n\t-->\n\t@if (editState(); as edit) {\n\t\t<textarea\n\t\t\t#nodeEditor\n\t\t\tclass=\"pptx-ng-smartart-node-editor\"\n\t\t\t[style.left.px]=\"edit.box.x\"\n\t\t\t[style.top.px]=\"edit.box.y\"\n\t\t\t[style.width.px]=\"edit.box.width\"\n\t\t\t[style.height.px]=\"edit.box.height\"\n\t\t\t[value]=\"edit.text\"\n\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t(dblclick)=\"$event.stopPropagation()\"\n\t\t\t(blur)=\"commitEdit($event)\"\n\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t></textarea>\n\t}\n\n\t<!-- Polite live region: announces node-text edit commits to AT. -->\n\t<span class=\"pptx-ng-sr-only\" aria-live=\"polite\" role=\"status\">{{ liveMessage() }}</span>\n</div>\n", styles: [".pptx-ng-smartart-chrome{box-sizing:border-box;overflow:hidden;position:relative}.pptx-ng-smartart-svg{width:100%;height:100%;pointer-events:none}.pptx-ng-smartart-node--editable{pointer-events:auto;cursor:text}.pptx-ng-smartart-node--editable:hover{filter:drop-shadow(0 0 2px rgba(96,165,250,.8))}.pptx-ng-smartart-node-editor{position:absolute;box-sizing:border-box;margin:0;padding:1px 2px;border:1px solid var(--pptx-inspector-active, #0078d4);border-radius:2px;background:#fff;color:#111;font-size:11px;line-height:1.1;text-align:center;resize:none;overflow:hidden;z-index:2}.pptx-ng-smartart-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fffc;pointer-events:none}.pptx-ng-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pptx-ng-smartart-style-bar{position:absolute;pointer-events:auto;display:flex;gap:6px;padding:6px 8px;background:#ffffffe6;border:1px solid var(--border, #e2e8f0);border-radius:9999px;box-shadow:0 1px 2px #0000001a}.pptx-ng-smartart-swatch{width:20px;height:20px;border-radius:50%;border:1px solid rgba(0,0,0,.1);cursor:pointer;transition:transform .1s}.pptx-ng-smartart-swatch:hover{transform:scale(1.25)}\n"] }]
|
|
87227
|
+
args: [{ selector: 'pptx-smart-art-renderer', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [NgStyle, TranslatePipe], template: "<div\n\t#smartartContainer\n\tclass=\"pptx-ng-smartart-chrome\"\n\t[ngStyle]=\"chromeStyle()\"\n\t[attr.role]=\"a11y() ? a11y()!.role : null\"\n\t[attr.aria-label]=\"a11y()?.label ?? null\"\n\t(mousemove)=\"onMouseMove($event)\"\n\t(mouseleave)=\"onMouseLeave()\"\n>\n\t@if (isEmpty()) {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t} @else if (hasDrawingShapes()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\tdata-testid=\"smartart-drawing-shapes\"\n\t\t\t[attr.viewBox]=\"svgViewBox()\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t>\n\t\t\t@for (shape of renderedShapes(); track shape.key; let i = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"drawingShapeNodeIds()[i] ?? null\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes() && !!drawingShapeNodeIds()[i]\"\n\t\t\t\t>\n\t\t\t\t\t@if (shape.gradient) {\n\t\t\t\t\t\t<defs>\n\t\t\t\t\t\t\t@if (shape.gradient!.kind === 'radial') {\n\t\t\t\t\t\t\t\t<radialGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.cx]=\"shape.gradient!.cx\"\n\t\t\t\t\t\t\t\t\t[attr.cy]=\"shape.gradient!.cy\"\n\t\t\t\t\t\t\t\t\t[attr.r]=\"shape.gradient!.r\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</radialGradient>\n\t\t\t\t\t\t\t} @else {\n\t\t\t\t\t\t\t\t<linearGradient\n\t\t\t\t\t\t\t\t\t[attr.id]=\"shape.gradient!.id\"\n\t\t\t\t\t\t\t\t\t[attr.x1]=\"shape.gradient!.x1\"\n\t\t\t\t\t\t\t\t\t[attr.y1]=\"shape.gradient!.y1\"\n\t\t\t\t\t\t\t\t\t[attr.x2]=\"shape.gradient!.x2\"\n\t\t\t\t\t\t\t\t\t[attr.y2]=\"shape.gradient!.y2\"\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t@for (stop of shape.gradient!.stops; track $index) {\n\t\t\t\t\t\t\t\t\t\t<stop\n\t\t\t\t\t\t\t\t\t\t\t[attr.offset]=\"stop.offset\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-color]=\"stop.color\"\n\t\t\t\t\t\t\t\t\t\t\t[attr.stop-opacity]=\"stop.opacity ?? null\"\n\t\t\t\t\t\t\t\t\t\t/>\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t</linearGradient>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</defs>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.kind === 'image') {\n\t\t\t\t\t\t<image\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.href]=\"shape.imageUrl\"\n\t\t\t\t\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'ellipse') {\n\t\t\t\t\t\t<ellipse\n\t\t\t\t\t\t\t[attr.cx]=\"shape.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"shape.cy\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.width / 2\"\n\t\t\t\t\t\t\t[attr.ry]=\"shape.height / 2\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (shape.kind === 'path') {\n\t\t\t\t\t\t<path\n\t\t\t\t\t\t\t[attr.d]=\"shape.pathData\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.pathTransform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"shape.x\"\n\t\t\t\t\t\t\t[attr.y]=\"shape.y\"\n\t\t\t\t\t\t\t[attr.width]=\"shape.width\"\n\t\t\t\t\t\t\t[attr.height]=\"shape.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"shape.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"shape.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"shape.strokeWidth\"\n\t\t\t\t\t\t\t[attr.transform]=\"shape.transform ?? null\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t@if (shape.textLines.length > 0) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"shape.textX\"\n\t\t\t\t\t\t\ttext-anchor=\"middle\"\n\t\t\t\t\t\t\tdominant-baseline=\"central\"\n\t\t\t\t\t\t\t[attr.fill]=\"shape.fontColor\"\n\t\t\t\t\t\t\t[attr.font-family]=\"shape.fontFamily ?? null\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"shape.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"shape.fontStyle ?? null\"\n\t\t\t\t\t\t\t[attr.font-size]=\"shape.fontSize\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of shape.textLines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"shape.textX\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else if (hasLayout()) {\n\t\t<svg\n\t\t\tclass=\"pptx-ng-smartart-svg\"\n\t\t\t[attr.data-testid]=\"'smartart-' + layout().family\"\n\t\t\t[attr.viewBox]=\"layout().viewBox\"\n\t\t\tpreserveAspectRatio=\"xMidYMid meet\"\n\t\t\t[attr.data-layout-family]=\"layout().family\"\n\t\t>\n\t\t\t@for (conn of layout().connectors; track conn.key; let ci = $index) {\n\t\t\t\t<path\n\t\t\t\t\t[attr.d]=\"layoutConnectors()[ci]!.d\"\n\t\t\t\t\tfill=\"none\"\n\t\t\t\t\t[attr.stroke]=\"layoutConnectors()[ci]!.stroke\"\n\t\t\t\t\t[attr.stroke-width]=\"layoutConnectors()[ci]!.strokeWidth\"\n\t\t\t\t\t[attr.opacity]=\"layoutConnectors()[ci]!.opacity\"\n\t\t\t\t\t[attr.stroke-dasharray]=\"layoutConnectors()[ci]!.dash ?? null\"\n\t\t\t\t/>\n\t\t\t}\n\t\t\t@for (node of layout().nodes; track node.key; let ni = $index) {\n\t\t\t\t<g\n\t\t\t\t\t[ngStyle]=\"shadowFilter() ? { filter: shadowFilter() } : {}\"\n\t\t\t\t\t[class.pptx-ng-smartart-node--editable]=\"canEditNodes()\"\n\t\t\t\t\t[attr.tabindex]=\"canEditNodes() ? 0 : null\"\n\t\t\t\t\t[attr.role]=\"canEditNodes() ? 'button' : 'img'\"\n\t\t\t\t\t[attr.aria-label]=\"nodeAriaLabel(ni) ?? node.text\"\n\t\t\t\t\t[attr.data-smartart-node-id]=\"nodeIdAt(ni)\"\n\t\t\t\t\t(dblclick)=\"onNodeDblClick($event, node, ni)\"\n\t\t\t\t\t(keydown)=\"onNodeKeydown($event, node, ni)\"\n\t\t\t\t>\n\t\t\t\t\t@if (nodeAriaLabel(ni); as title) {\n\t\t\t\t\t\t<title>{{ title }}</title>\n\t\t\t\t\t}\n\t\t\t\t\t@if (asCircle(node); as c) {\n\t\t\t\t\t\t<circle\n\t\t\t\t\t\t\t[attr.cx]=\"c.cx\"\n\t\t\t\t\t\t\t[attr.cy]=\"c.cy\"\n\t\t\t\t\t\t\t[attr.r]=\"c.r\"\n\t\t\t\t\t\t\t[attr.fill]=\"c.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"c.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"c.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"c.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asPolygon(node); as p) {\n\t\t\t\t\t\t<polygon\n\t\t\t\t\t\t\t[attr.points]=\"p.points\"\n\t\t\t\t\t\t\t[attr.fill]=\"p.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"p.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"p.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"p.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t} @else if (asRect(node); as r) {\n\t\t\t\t\t\t<rect\n\t\t\t\t\t\t\t[attr.x]=\"r.x\"\n\t\t\t\t\t\t\t[attr.y]=\"r.y\"\n\t\t\t\t\t\t\t[attr.width]=\"r.width\"\n\t\t\t\t\t\t\t[attr.height]=\"r.height\"\n\t\t\t\t\t\t\t[attr.rx]=\"r.rx\"\n\t\t\t\t\t\t\t[attr.fill]=\"r.fill\"\n\t\t\t\t\t\t\t[attr.stroke]=\"r.stroke\"\n\t\t\t\t\t\t\t[attr.stroke-width]=\"r.strokeWidth\"\n\t\t\t\t\t\t\t[attr.opacity]=\"r.opacity\"\n\t\t\t\t\t\t/>\n\t\t\t\t\t}\n\t\t\t\t\t<!--\n\t\t\t\t\t\tNode label. Placement, colour, weight and baseline arrive\n\t\t\t\t\t\talready decided from the shared `smartArtNodeLabel`, so an\n\t\t\t\t\t\toff-centre caption (target leader, gear legend row, timeline\n\t\t\t\t\t\tcaption above / below the axis) lands beside its node.\n\t\t\t\t\t-->\n\t\t\t\t\t@if (layoutLabels()[ni]!.visible) {\n\t\t\t\t\t\t<text\n\t\t\t\t\t\t\t[attr.x]=\"layoutLabels()[ni]!.x\"\n\t\t\t\t\t\t\t[attr.text-anchor]=\"layoutLabels()[ni]!.textAnchor\"\n\t\t\t\t\t\t\t[attr.dominant-baseline]=\"layoutLabels()[ni]!.dominantBaseline\"\n\t\t\t\t\t\t\t[attr.fill]=\"layoutLabels()[ni]!.fill\"\n\t\t\t\t\t\t\t[attr.font-size]=\"layoutLabels()[ni]!.fontSize\"\n\t\t\t\t\t\t\t[attr.font-weight]=\"layoutLabels()[ni]!.fontWeight ?? null\"\n\t\t\t\t\t\t\t[attr.font-style]=\"layoutLabels()[ni]!.fontStyle ?? null\"\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t@for (line of layoutLabels()[ni]!.lines; track $index) {\n\t\t\t\t\t\t\t\t<tspan [attr.x]=\"layoutLabels()[ni]!.x\" [attr.y]=\"line.y\">\n\t\t\t\t\t\t\t\t\t{{ line.text }}\n\t\t\t\t\t\t\t\t</tspan>\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t</text>\n\t\t\t\t\t}\n\t\t\t\t</g>\n\t\t\t}\n\t\t</svg>\n\t} @else {\n\t\t<div class=\"pptx-ng-smartart-placeholder\">\n\t\t\t{{ 'pptx.smartArt.placeholder' | translate }}\n\t\t</div>\n\t}\n\n\t@if (canEditNodes() && hoveredNodeId() && !editState() && styleBarStyle()) {\n\t\t<div\n\t\t\t#styleBar\n\t\t\tclass=\"pptx-ng-smartart-style-bar\"\n\t\t\t[ngStyle]=\"styleBarStyle()!\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t>\n\t\t\t@for (color of palette().slice(0, 6); track color) {\n\t\t\t\t<button\n\t\t\t\t\ttype=\"button\"\n\t\t\t\t\tclass=\"pptx-ng-smartart-swatch\"\n\t\t\t\t\tdata-pptx-compact\n\t\t\t\t\t[attr.aria-label]=\"'pptx.smartArt.setFill' | translate: { color: color }\"\n\t\t\t\t\t[style.background]=\"color\"\n\t\t\t\t\t(click)=\"handleChangeNodeStyle(hoveredNodeId()!, color)\"\n\t\t\t\t></button>\n\t\t\t}\n\t\t</div>\n\t}\n\n\t<!--\n\t\tInline node-text editor. Positioned in element-local px (== viewBox\n\t\tunits, since the SVG viewBox matches the element pixel size and the\n\t\tsvg fills the chrome) over the double-clicked node. Commits via the\n\t\tshared EditorStateService.updateElement path on Enter / blur.\n\t-->\n\t@if (editState(); as edit) {\n\t\t<textarea\n\t\t\t#nodeEditor\n\t\t\tclass=\"pptx-ng-smartart-node-editor\"\n\t\t\t[style.left.px]=\"edit.box.x\"\n\t\t\t[style.top.px]=\"edit.box.y\"\n\t\t\t[style.width.px]=\"edit.box.width\"\n\t\t\t[style.height.px]=\"edit.box.height\"\n\t\t\t[value]=\"edit.text\"\n\t\t\t(pointerdown)=\"$event.stopPropagation()\"\n\t\t\t(mousedown)=\"$event.stopPropagation()\"\n\t\t\t(click)=\"$event.stopPropagation()\"\n\t\t\t(dblclick)=\"$event.stopPropagation()\"\n\t\t\t(blur)=\"commitEdit($event)\"\n\t\t\t(keydown)=\"onEditorKeydown($event)\"\n\t\t></textarea>\n\t}\n\n\t<!-- Polite live region: announces node-text edit commits to AT. -->\n\t<span class=\"pptx-ng-sr-only\" aria-live=\"polite\" role=\"status\">{{ liveMessage() }}</span>\n</div>\n", styles: [".pptx-ng-smartart-chrome{box-sizing:border-box;overflow:hidden;position:relative}.pptx-ng-smartart-svg{width:100%;height:100%;pointer-events:none}.pptx-ng-smartart-node--editable{pointer-events:auto;cursor:text}.pptx-ng-smartart-node--editable:hover{filter:drop-shadow(0 0 2px rgba(96,165,250,.8))}.pptx-ng-smartart-node-editor{position:absolute;box-sizing:border-box;margin:0;padding:1px 2px;border:1px solid var(--pptx-inspector-active, #0078d4);border-radius:2px;background:#fff;color:#111;font-size:11px;line-height:1.1;text-align:center;resize:none;overflow:hidden;z-index:2}.pptx-ng-smartart-placeholder{width:100%;height:100%;display:flex;align-items:center;justify-content:center;font-size:11px;color:#fffc;pointer-events:none}.pptx-ng-sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}.pptx-ng-smartart-style-bar{position:absolute;pointer-events:auto;display:flex;gap:6px;padding:6px 8px;background:#ffffffe6;border:1px solid var(--border, #e2e8f0);border-radius:9999px;box-shadow:0 1px 2px #0000001a}.pptx-ng-smartart-swatch{width:20px;height:20px;border-radius:50%;border:1px solid rgba(0,0,0,.1);cursor:pointer;transition:transform .1s}.pptx-ng-smartart-swatch:hover{transform:scale(1.25)}\n"] }]
|
|
86405
87228
|
}], ctorParameters: () => [], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], editable: [{ type: i0.Input, args: [{ isSignal: true, alias: "editable", required: false }] }], animationState: [{ type: i0.Input, args: [{ isSignal: true, alias: "animationState", required: false }] }], nodeEditor: [{ type: i0.ViewChild, args: ['nodeEditor', { isSignal: true }] }], smartartContainer: [{ type: i0.ViewChild, args: ['smartartContainer', { isSignal: true }] }], styleBar: [{ type: i0.ViewChild, args: ['styleBar', { isSignal: true }] }] } });
|
|
86406
87229
|
|
|
86407
87230
|
/**
|
|
@@ -95597,7 +96420,11 @@ class SlideCanvasComponent {
|
|
|
95597
96420
|
'padding-left': rulerOffset > 0 ? `${rulerOffset}px` : '0',
|
|
95598
96421
|
position: 'relative',
|
|
95599
96422
|
'box-sizing': 'content-box',
|
|
95600
|
-
|
|
96423
|
+
flex: 'none',
|
|
96424
|
+
// `margin: auto` on a flex item consumes all free space on both axes,
|
|
96425
|
+
// centering the slide horizontally and vertically (matching Svelte),
|
|
96426
|
+
// rather than only horizontally with a fixed top/bottom gap.
|
|
96427
|
+
margin: 'auto',
|
|
95601
96428
|
};
|
|
95602
96429
|
}, /* @ts-ignore */
|
|
95603
96430
|
...(ngDevMode ? [{ debugName: "wrapperStyle" }] : /* istanbul ignore next */ []));
|
|
@@ -109688,9 +110515,30 @@ class RibbonAnimationsSectionComponent {
|
|
|
109688
110515
|
own 420px. Uncapped, five 150px family columns claim ~800px of a
|
|
109689
110516
|
single-row ribbon and squeeze the Advanced Animation pills beside them
|
|
109690
110517
|
until their labels overlap.
|
|
110518
|
+
|
|
110519
|
+
shrink-0, not shrink: this section used to opt INTO shrinking
|
|
110520
|
+
(shrink = flex-shrink: 1) with no min-width, and overflow-hidden
|
|
110521
|
+
removes the browser's automatic min-content-size floor a flex item
|
|
110522
|
+
would otherwise get. With the ribbon row tight on space (which is the
|
|
110523
|
+
normal case once Advanced Animation and Timing claim their own
|
|
110524
|
+
content-sized width), ALL of the row's required shrinkage landed on
|
|
110525
|
+
this one section, collapsing it to ~50px wide, i.e. hard-clipping four
|
|
110526
|
+
of the five families (Arcs/Turns/Shapes/Loops), reachable by neither
|
|
110527
|
+
scroll nor sight. pptx-ribbon-animations-section renders with
|
|
110528
|
+
display: contents (see its host below), so the ribbon row's own
|
|
110529
|
+
shrink-0-on-every-child safety net (ribbon.component.ts) never reaches
|
|
110530
|
+
this section either: that rule is a real CSS child combinator, so it
|
|
110531
|
+
lands on the custom element itself, not on the elements its
|
|
110532
|
+
display: contents template promotes up into the row's flex layout.
|
|
110533
|
+
Every element promoted that way needs its own shrink-0, the same fix
|
|
110534
|
+
already applied to the View tab's Eyedropper control (see the
|
|
110535
|
+
shrink-0-on-every-child comment in pptx-angular-viewer.css). shrink-0
|
|
110536
|
+
keeps this section at its own content width (capped at max-w-420px)
|
|
110537
|
+
and lets the row's own horizontal scroll handle any total overflow,
|
|
110538
|
+
same as every other group.
|
|
109691
110539
|
-->
|
|
109692
110540
|
<section
|
|
109693
|
-
class="relative flex max-w-[420px] shrink items-start gap-1 overflow-hidden pb-3"
|
|
110541
|
+
class="relative flex max-w-[420px] shrink-0 items-start gap-1 overflow-hidden pb-3"
|
|
109694
110542
|
[attr.aria-label]="'pptx.animation.motionPath' | translate"
|
|
109695
110543
|
>
|
|
109696
110544
|
<pptx-ribbon-motion-path-gallery
|
|
@@ -109845,9 +110693,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
109845
110693
|
own 420px. Uncapped, five 150px family columns claim ~800px of a
|
|
109846
110694
|
single-row ribbon and squeeze the Advanced Animation pills beside them
|
|
109847
110695
|
until their labels overlap.
|
|
110696
|
+
|
|
110697
|
+
shrink-0, not shrink: this section used to opt INTO shrinking
|
|
110698
|
+
(shrink = flex-shrink: 1) with no min-width, and overflow-hidden
|
|
110699
|
+
removes the browser's automatic min-content-size floor a flex item
|
|
110700
|
+
would otherwise get. With the ribbon row tight on space (which is the
|
|
110701
|
+
normal case once Advanced Animation and Timing claim their own
|
|
110702
|
+
content-sized width), ALL of the row's required shrinkage landed on
|
|
110703
|
+
this one section, collapsing it to ~50px wide, i.e. hard-clipping four
|
|
110704
|
+
of the five families (Arcs/Turns/Shapes/Loops), reachable by neither
|
|
110705
|
+
scroll nor sight. pptx-ribbon-animations-section renders with
|
|
110706
|
+
display: contents (see its host below), so the ribbon row's own
|
|
110707
|
+
shrink-0-on-every-child safety net (ribbon.component.ts) never reaches
|
|
110708
|
+
this section either: that rule is a real CSS child combinator, so it
|
|
110709
|
+
lands on the custom element itself, not on the elements its
|
|
110710
|
+
display: contents template promotes up into the row's flex layout.
|
|
110711
|
+
Every element promoted that way needs its own shrink-0, the same fix
|
|
110712
|
+
already applied to the View tab's Eyedropper control (see the
|
|
110713
|
+
shrink-0-on-every-child comment in pptx-angular-viewer.css). shrink-0
|
|
110714
|
+
keeps this section at its own content width (capped at max-w-420px)
|
|
110715
|
+
and lets the row's own horizontal scroll handle any total overflow,
|
|
110716
|
+
same as every other group.
|
|
109848
110717
|
-->
|
|
109849
110718
|
<section
|
|
109850
|
-
class="relative flex max-w-[420px] shrink items-start gap-1 overflow-hidden pb-3"
|
|
110719
|
+
class="relative flex max-w-[420px] shrink-0 items-start gap-1 overflow-hidden pb-3"
|
|
109851
110720
|
[attr.aria-label]="'pptx.animation.motionPath' | translate"
|
|
109852
110721
|
>
|
|
109853
110722
|
<pptx-ribbon-motion-path-gallery
|
|
@@ -113300,7 +114169,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
113300
114169
|
}], 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 }] }] } });
|
|
113301
114170
|
|
|
113302
114171
|
// Generated by scripts/inline-shared.mjs from package.json. Do not edit.
|
|
113303
|
-
const PPTX_ANGULAR_VIEWER_VERSION = "3.
|
|
114172
|
+
const PPTX_ANGULAR_VIEWER_VERSION = "3.2.1";
|
|
113304
114173
|
|
|
113305
114174
|
/**
|
|
113306
114175
|
* account-page.component.ts: File > Account content.
|
|
@@ -115459,14 +116328,19 @@ class HeaderFooterRibbonButtonComponent {
|
|
|
115459
116328
|
}
|
|
115460
116329
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.3", ngImport: i0, type: HeaderFooterRibbonButtonComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
115461
116330
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "22.1.3", type: HeaderFooterRibbonButtonComponent, isStandalone: true, selector: "pptx-header-footer-ribbon-button", ngImport: i0, template: `
|
|
116331
|
+
<!-- pptx-rb-pill, not pptx-rb-gb: this button is standalone (not
|
|
116332
|
+
inside a .pptx-rb-grp), so it needs its own rounded/bg-muted
|
|
116333
|
+
chrome rather than the border-r/no-background style meant for a
|
|
116334
|
+
group member. No icon either, matching React/Vue's plain-text
|
|
116335
|
+
Header & Footer pill. -->
|
|
115462
116336
|
<button
|
|
115463
116337
|
type="button"
|
|
115464
|
-
class="pptx-rb-
|
|
116338
|
+
class="pptx-rb-pill"
|
|
115465
116339
|
(click)="dialogs.showHeaderFooter.set(true)"
|
|
115466
116340
|
[title]="'pptx.headerFooter.title' | translate"
|
|
115467
116341
|
[attr.aria-label]="'pptx.headerFooter.title' | translate"
|
|
115468
116342
|
>
|
|
115469
|
-
|
|
116343
|
+
{{ 'pptx.headerFooter.title' | translate }}
|
|
115470
116344
|
</button>
|
|
115471
116345
|
`, isInline: true, dependencies: [{ kind: "pipe", type: TranslatePipe, name: "translate" }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
115472
116346
|
}
|
|
@@ -115478,14 +116352,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.3", ngImpor
|
|
|
115478
116352
|
imports: [TranslatePipe],
|
|
115479
116353
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
115480
116354
|
template: `
|
|
116355
|
+
<!-- pptx-rb-pill, not pptx-rb-gb: this button is standalone (not
|
|
116356
|
+
inside a .pptx-rb-grp), so it needs its own rounded/bg-muted
|
|
116357
|
+
chrome rather than the border-r/no-background style meant for a
|
|
116358
|
+
group member. No icon either, matching React/Vue's plain-text
|
|
116359
|
+
Header & Footer pill. -->
|
|
115481
116360
|
<button
|
|
115482
116361
|
type="button"
|
|
115483
|
-
class="pptx-rb-
|
|
116362
|
+
class="pptx-rb-pill"
|
|
115484
116363
|
(click)="dialogs.showHeaderFooter.set(true)"
|
|
115485
116364
|
[title]="'pptx.headerFooter.title' | translate"
|
|
115486
116365
|
[attr.aria-label]="'pptx.headerFooter.title' | translate"
|
|
115487
116366
|
>
|
|
115488
|
-
|
|
116367
|
+
{{ 'pptx.headerFooter.title' | translate }}
|
|
115489
116368
|
</button>
|
|
115490
116369
|
`,
|
|
115491
116370
|
}]
|
|
@@ -147412,4 +148291,4 @@ function cn(...values) {
|
|
|
147412
148291
|
*/
|
|
147413
148292
|
|
|
147414
148293
|
export { ColorChangedImageComponent as $, AFTER_ANIMATION_VALUES as A, AnimationPanelComponent as B, AnimationPlaybackService as C, AutosaveRecoveryDialogComponent as D, AutosaveService as E, BroadcastDialogComponent as F, CHART_EDITOR_STYLES as G, CURSOR_PALETTE as H, CanvasFitService as I, ChartAxisOptionsComponent as J, ChartAxisStyleOptionsComponent as K, ChartComboTypeOptionsComponent as L, ChartDataEditorComponent as M, ChartDataLabelOptionsComponent as N, ChartDatapointMarkerOptionsComponent as O, ChartDatapointOptionsComponent as P, ChartDisplayOptionsComponent as Q, ChartElementViewComponent as R, ChartErrorBarOptionsComponent as S, ChartMarkerOptionsComponent as T, ChartPartSelectionService as U, ChartPrimitivesComponent as V, ChartRendererComponent as W, ChartTrendlineOptionsComponent as X, ChartTypeSelectorComponent as Y, CollaborationCursorsComponent as Z, CollaborationService as _, ALIGN_OPTIONS as a, KeepAnnotationsDialogComponent as a$, CommentMarkersOverlayComponent as a0, CommentsPanelComponent as a1, CommentsService as a2, ComparePanelComponent as a3, ConnectorRendererComponent as a4, ConnectorTextOverlayComponent as a5, CustomShowsComponent as a6, DEFAULT_BOUNDS as a7, DEFAULT_BROADCAST_SERVER_URL as a8, DEFAULT_CANVAS_HEIGHT as a9, ElementRendererComponent as aA, EmbeddedFontsService as aB, EncryptedFileDialogComponent as aC, EquationEditorDialogComponent as aD, EquationRendererComponent as aE, EquationTemplateGalleryComponent as aF, ExportProgressModalComponent as aG, ExportService as aH, FieldContextService as aI, FindBarComponent as aJ, FindReplaceBarComponent as aK, FollowModeBarComponent as aL, FontEmbeddingListComponent as aM, FontEmbeddingPanelComponent as aN, GALLERY_THEME_PRESETS as aO, GRIDLINE_COLOR$1 as aP, GradientPickerComponent as aQ, HANDOUT_OPTIONS as aR, HeaderFooterDialogComponent as aS, HyperlinkDialogComponent as aT, ImagePropertiesPanelComponent as aU, InkDrawingService as aV, InkRendererComponent as aW, InsertSmartArtDialogComponent as aX, InspectorPaneHeaderComponent as aY, InspectorPanelComponent as aZ, IsMobileService as a_, DEFAULT_CANVAS_WIDTH as aa, DEFAULT_COLOR_SCHEME as ab, DEFAULT_FILL_COLOR$1 as ac, DEFAULT_LAYOUT as ad, DEFAULT_PALETTE$1 as ae, DEFAULT_PATTERN_FILL_PRESET as af, DEFAULT_PRINT_SETTINGS as ag, DEFAULT_SLIDE_BACKGROUND as ah, DEFAULT_STROKE_COLOR as ai, DEFAULT_STYLE as aj, DEFAULT_TABLE_ROW_HEIGHT as ak, DEFAULT_TEXT_COLOR$2 as al, DEFAULT_VIEWER_PROFILE as am, DIRECTIONAL_PRESETS as an, DIRECTION_OPTIONS as ao, DocumentPropertiesCardComponent as ap, EMBEDDED_FONTS_STYLE_ID as aq, EMPHASIS_PRESETS as ar, ENTRANCE_PRESETS as as, TEMPLATES as at, EXIT_PRESETS as au, EditorContextMenuComponent as av, EditorHistory as aw, EditorStateService as ax, EditorToolbarComponent as ay, EffectsPanelComponent as az, ANIMATION_PRESET_CATEGORIES as b, RibbonDrawSectionComponent as b$, LOCALE_CATALOG as b0, LONG_PRESS_DURATION_MS as b1, LONG_PRESS_MOVE_TOLERANCE_PX as b2, LoadContentService as b3, LocalPresencePublisher as b4, MAX_ZOOM_SCALE as b5, MIN_ZOOM_SCALE as b6, MOTION_PATH_COLUMNS as b7, MediaPreviewComponent as b8, MediaPropertiesPanelComponent as b9, PresentToolbarAutoHide as bA, PresentationAnnotationOverlayComponent as bB, PresentationAnnotationsService as bC, PresentationOverlayComponent as bD, PresentationPropertiesPanelComponent as bE, PresentationSettingsCardComponent as bF, PresentationSubtitleBarComponent as bG, PresentationToolbarComponent as bH, PresentationTransitionOverlayComponent as bI, PresenterViewComponent as bJ, PresenterWindowService as bK, PrintDialogComponent as bL, PrintService as bM, PrintSettingsPanelComponent as bN, PropertiesDialogComponent as bO, REPEAT_MODE_OPTIONS as bP, RESIZE_HANDLES as bQ, RULER_FONT_SIZE as bR, RULER_THICKNESS as bS, ReadingViewOverlayComponent as bT, RemoteSelectionOverlayComponent as bU, RibbonAnimationGalleryComponent as bV, RibbonAnimationsSectionComponent as bW, RibbonArrangeSectionComponent as bX, RibbonColorPopoverComponent as bY, RibbonComponent as bZ, RibbonDesignSectionComponent as b_, MediaRendererComponent as ba, MediaTrimTimelineComponent as bb, MobileBottomBarComponent as bc, MobileMenuSheetComponent as bd, MobilePresenterViewComponent as be, MobileSheetComponent as bf, MobileSlidesSheetComponent as bg, MobileToolbarComponent as bh, ModalDialogComponent as bi, Model3DRendererComponent as bj, NotesHandoutCardComponent as bk, NotesPanelComponent as bl, NotesToolbarComponent as bm, OleRendererComponent as bn, OutlineViewOverlayComponent as bo, POWER_POINT_VIEWER_PROVIDERS as bp, PPTX_OPEN_ACCEPT as bq, PRESENTATION_OPEN_EXTENSIONS as br, PRESENTER_CHANNEL_NAME as bs, PRESENTER_MSG_ORIGIN as bt, PRESENTER_TIMER_SEGMENT_MS as bu, PX_PER_CM as bv, PX_PER_INCH as bw, PasswordProtectionDialogComponent as bx, PasswordStrengthMeterComponent as by, PowerPointViewerComponent as bz, AUDIENCE_HASH as c, THEME_CATALOG as c$, RibbonDrawingGroupComponent as c0, RibbonEditingSectionComponent as c1, RibbonFileSectionComponent as c2, RibbonFontControlsComponent as c3, RibbonHomeSectionComponent as c4, RibbonHyperlinkButtonComponent as c5, RibbonInsertFieldsComponent as c6, RibbonInsertSectionComponent as c7, RibbonMotionPathGalleryComponent as c8, RibbonParagraphControlsComponent as c9, ShortcutPanelComponent as cA, ShowOptionsFieldsetComponent as cB, ShowSlidesFieldsetComponent as cC, SignatureStrippedDialogComponent as cD, SignaturesPanelComponent as cE, SignaturesService as cF, SlideBackgroundCardComponent as cG, SlideCanvasComponent as cH, SlideDefaultInspectorComponent as cI, SlideDiffChangesComponent as cJ, SlideDiffRowComponent as cK, SlideDiffThumbnailsComponent as cL, SlideSizeCardComponent as cM, SlideSorterOverlayComponent as cN, SlideThemeOverridePanelComponent as cO, SlideTransitionCardComponent as cP, SlidesPanelComponent as cQ, SmartArt3DRendererComponent as cR, SmartArt3DService as cS, SmartArtPreviewComponent as cT, SmartArtPropertiesComponent as cU, SmartArtRendererComponent as cV, StatusBarComponent as cW, TABLE_STRUCTURE_TOGGLES as cX, TEXT_3D_BOTTOM_BEVEL_KEYS as cY, TEXT_3D_TOP_BEVEL_KEYS as cZ, TEXT_DIRECTION_OPTIONS$1 as c_, RibbonPrimaryRowComponent as ca, RibbonReviewSectionComponent as cb, RibbonShapeExtrasComponent as cc, RibbonSlideshowSectionComponent as cd, RibbonTransitionsSectionComponent as ce, RibbonViewSectionComponent as cf, RulerGuidesService as cg, SEQUENCE_OPTIONS as ch, SEVERITY_GROUPS as ci, SEVERITY_LABELS as cj, SHORTCUT_REFERENCE_ITEMS as ck, SLIDE_TRANSITION_KEYFRAMES as cl, DEFAULT_PALETTE as cm, PALETTES$1 as cn, SMART_ART_COLOR_SCHEMES as co, SMART_ART_STYLE_OPTIONS as cp, SUB_ITEM_LABEL as cq, SVG_WARP_PRESETS as cr, SWIPE_MAX_VERTICAL_PX as cs, SWIPE_THRESHOLD_PX as ct, SelectionPaneComponent as cu, SetUpSlideShowDialogComponent as cv, SettingsAppearanceTabComponent as cw, SettingsDialogComponent as cx, SettingsLanguageTabComponent as cy, ShareDialogComponent as cz, AUDIENCE_NONCE_KEY as d, applyAcceptedDiff as d$, TIMING_CURVE_OPTIONS as d0, TRIGGER_OPTIONS as d1, TYPE_LABELS as d2, TableCellAdvancedFillComponent as d3, TableCellFormattingComponent as d4, TableDataEditorComponent as d5, TablePropertiesComponent as d6, TableRendererComponent as d7, TableResizeOverlayComponent as d8, TableSelectionService as d9, ViewerFormatPainterService as dA, ViewerInspectorPanelService as dB, ViewerKeyboardService as dC, ViewerMobileSheetService as dD, ViewerPresentationModeService as dE, ViewerThemeGalleryService as dF, ViewerTouchGesturesService as dG, ViewerZoomService as dH, WEBM_MIME_CANDIDATES as dI, WriteBackScheduler as dJ, ZERO_LINE_COLOR as dK, ZoomNavigationService as dL, ZoomRendererComponent as dM, ZoomTargetService as dN, addCategory as dO, addCommentToList as dP, addGradientStopPatch as dQ, addItem as dR, addSeries as dS, addSubItem as dT, advanceStep as dU, affordanceElements as dV, aiToggleVisible as dW, alignPatch as dX, animationFor as dY, animationPresetLabelKey as dZ, annotationMapToInkInserts as d_, TagsCardComponent as da, Text3DBevelSectionComponent as db, Text3DPanelComponent as dc, TextAdvancedPanelComponent as dd, ThemeEditorFieldsComponent as de, ThemeGalleryComponent as df, ThemeSelectorCardComponent as dg, TitleBarComponent as dh, TitleBarSearchComponent as di, TransitionDirectionPickerComponent as dj, TransitionPreviewComponent as dk, VALIGN_OPTIONS as dl, VIEWER_THEME as dm, VersionHistoryPanelComponent as dn, ViewerCanvasEditingService as dp, ViewerCollabCursorService as dq, ViewerCollaborationSessionService as dr, ViewerCompareService as ds, ViewerCustomShowsService as dt, ViewerDialogsService as du, ViewerDocumentPropertiesService as dv, ViewerExportService as dw, ViewerExtraDialogsComponent as dx, ViewerFileIOService as dy, ViewerFindReplaceService as dz, AVATAR_COLOR_SWATCHES as e, buildZoomContainerStyle as e$, applyAnimationPreset as e0, applyFindReplacements as e1, applyFormatToElement as e2, applyMove as e3, applyResize as e4, asMediaElement as e5, assignUserColor as e6, attachShowVisibilityPause as e7, attachTouchGestures as e8, axisTickValues as e9, buildFontFaceRule as eA, buildGradientFillCss as eB, buildGridlinesAndLabels as eC, buildHyperlinkPatch as eD, buildInkContainerStyle as eE, buildInkStrokes as eF, buildLegend as eG, buildMarkTooltip as eH, buildModel3DContainerStyle as eI, buildModel3DViewModel as eJ, buildOleActionModel as eK, buildOleInfoRows as eL, buildPatternFillCss as eM, buildPrintHtmlDocument as eN, buildPropertiesPatch as eO, buildRegionMapViewModel as eP, buildSaveSlides as eQ, buildShareUrl as eR, buildSmartArtInsertElement as eS, buildSmartArtNodes as eT, buildStockViewModel as eU, buildSurfaceViewModel as eV, buildTableViewModel as eW, buildTreemapViewModel as eX, buildTrimFragment as eY, buildWaterfallViewModel as eZ, buildZeroLine as e_, beginNodeEdit as ea, bevelSizePatch as eb, boolFromEvent as ec, bringForward as ed, bringToFront as ee, buildBarActions as ef, buildBroadcastConfig as eg, buildBroadcastViewerUrl as eh, buildCategoryLabels as ei, buildCellParagraphs as ej, buildChartViewModel as ek, buildChatLogExport as el, buildChatLogMarkdown as em, buildChromeStyle as en, buildClearHyperlinkPatch as eo, buildClickGroups as ep, buildColStyles as eq, buildCollaborationConfig as er, buildComboViewModel as es, buildCssGradientFromShapeStyle as et, buildDuotoneFilter as eu, buildDuotoneFilterId as ev, buildEmbeddedFontStyles as ew, buildEquationElement as ex, buildEquationSegment as ey, buildFallbackViewModel as ez, AXIS_LABEL_COLOR as f, computeSingleSelected as f$, buildZoomViewModel as f0, bulletIndentPx as f1, canAddTopLevelNode as f2, canGroupSelection as f3, canRemoveTopLevelNode as f4, canSetStrokeWidth as f5, canStartBroadcast as f6, canStartShare as f7, canUngroupSelection as f8, canUseClipboard as f9, computeAxisTitlePrimitives as fA, computeBarRects as fB, computeBubbleRadius as fC, computeCornerHandle as fD, computeDistribute as fE, computeDrawingViewBox as fF, computeErrorBarPrimitives as fG, computeFocusTargets as fH, computeGridSpacingPx as fI, computeHandleBoxes as fJ, computeHandoutLayout as fK, computeIsMobile as fL, computeIsTablet as fM, computeLinePoints as fN, computeLinearRegression as fO, computePageCount as fP, computePieLayout as fQ, computePieSlicePath as fR, computePieSlices as fS, computePlotLayout as fT, computeRSquared as fU, computeRadarPoints as fV, computeResizeHandleBoxes as fW, computeRotateHandleBox as fX, computeScatterDots as fY, computeScatterXDomain as fZ, computeSelectionBoxes as f_, captionDisplayText as fa, cellRunStyle as fb, cellStyleToStyleMap as fc, cellTdStyle as fd, changeCountLabel as fe, changeIcon as ff, characterSpacingPatch as fg, chartPreserveAspectRatio as fh, checkFontAvailable as fi, clampCursorPosition as fj, clampGifDimensions as fk, clampIndex as fl, clampNotesFontSize as fm, clampScale as fn, clampStep as fo, clearAllLocalViewerData as fp, clearAudienceContent as fq, cn as fr, collectAccessibilityIssues as fs, collectElementText as ft, collectSlideText as fu, collectStoredChats as fv, collectUsedFontFamilies as fw, columnWidthStyle as fx, commitNodeText as fy, computeAlign as fz, AccessibilityPanelComponent as g, formatFileSize as g$, computeSlideIndices as g0, computeSnap as g1, computeStackedBarRects as g2, computeStackedValueRange as g3, computeTrendlinePrimitives as g4, computeValueRange as g5, convertOmmlToMathMl as g6, copyFormatFromElement as g7, countAccessibilityIssues as g8, countAnnotationStrokes as g9, enableGlowPatch as gA, enableInnerShadowPatch as gB, enableOuterShadowPatch as gC, enableReflectionPatch as gD, enableSoftEdgePatch as gE, encodeGif as gF, endShowMediaCleanup as gG, estimatePageCount as gH, exitPresentationFullscreen as gI, exportAiChatLogs as gJ, extractPathPoints as gK, eyedropperAvailable as gL, fillColorOf$1 as gM, findInSlides as gN, findOwningSlideIndex as gO, findSlideIndexByElementId as gP, firstVisibleIndex as gQ, fitPolynomial as gR, fitZoom as gS, focusTargetChips as gT, fontMimeForFormat as gU, fontSizeOf as gV, forgetSessionDeck as gW, formatAxisValue as gX, formatBytes as gY, formatCursorLabel as gZ, formatElapsed as g_, createAngularAiBridge as ga, createCustomShow as gb, createSwipeDismissDrag as gc, createWebrtcBundle as gd, createWebsocketBundle as ge, cssObjectToStyleMap as gf, currentColorScheme as gg, currentLayout as gh, currentStyle as gi, defaultCssVars as gj, defaultRadius as gk, defaultThemeColors as gl, deleteElementsByIds as gm, deleteVersion as gn, demoteNode as go, deriveModel3DBlobUrl as gp, derivePresenceList as gq, describeSmartArtBounds as gr, disableGlowPatch as gs, disableInnerShadowPatch as gt, disableOuterShadowPatch as gu, disableReflectionPatch as gv, disableSoftEdgePatch as gw, duplicateElementById as gx, durationOf as gy, effectsStateOf as gz, AccessibilityService as h, isPpactionUrl as h$, formatPropertyDate as h0, formatTime as h1, fpsToFrameIntervalMs as h2, generateBroadcastRoomId as h3, generateCommentId as h4, generateCustomShowId as h5, generatePressureCircles as h6, generateTicks as h7, getClrChangeParams as h8, getContainerStyle as h9, getWarpPath as hA, gradientStateFromStyle as hB, gradientStateOf as hC, gradientStatePatch as hD, gridColumns as hE, groupIssuesBySeverity as hF, hasAnimation as hG, hasCopyableFormat as hH, hasExistingLink as hI, hasExitedFullscreen as hJ, hasGradientFill as hK, hasPressureVariation as hL, hasVisibleSlideAfter as hM, headerLabel as hN, imageDimensions as hO, inkViewBox as hP, insertTableElementColumn as hQ, insertTableElementRow as hR, interpolateWidth as hS, isAudienceTab as hT, isBold as hU, isBrowserOpenableMime as hV, isChildNode as hW, isElementInteractive as hX, isInjectableUrl as hY, isItalic as hZ, isLegacyBinaryPresentation as h_, getDuotoneFilterDef as ha, getEffectSoundState as hb, getImageSrc as hc, getLocalStorageUsageSummary as hd, getOleAriaLabel as he, getOleBadgeLabel as hf, getOleDisplayName as hg, getOleDownloadFileName as hh, getOleTypeColor as hi, getOleTypeLabel as hj, getPasswordStrength as hk, getPatternSvg as hl, getPlaceholderStyle as hm, getVersions as hn, getResolvedShapeClipPath as ho, getResolvedShapeClipPathFor as hp, getSessionTabId as hq, getShapeFillStrokeStyle as hr, getSlideBackgroundStyle as hs, getSlideTransitionAnimations as ht, getSmartArtNodeBounds as hu, getSpeechRecognitionCtor as hv, getTextBlockStyle as hw, getTextWarp as hx, getTouchDistance as hy, getWarpCategory as hz, AccountPageComponent as i, patchChartData as i$, isPresenterMessage as i0, isSigned as i1, isSupportedPresentationFile as i2, isTextElement as i3, isTwoTableFocus as i4, isUnderline as i5, isUrlSafe as i6, isValidRoomId as i7, isViewportBackgroundPressTarget as i8, isZoomActivationKey as i9, newChartElement as iA, newEquationElement as iB, newPresetShapeElement as iC, newShapeElement as iD, newSmartArtElement as iE, newTableElement as iF, newTextElement as iG, nextVisibleIndex as iH, nodeBold as iI, nodeEditBox as iJ, nodeFillColor as iK, nodeFontColor as iL, nodeIdFromKey as iM, nodeItalic as iN, nodeStyle as iO, normalizeFontFormat as iP, normalizeSlidesPerPage as iQ, normalizeValue as iR, numFromEvent as iS, ommlToMathml as iT, ooxmlDashToCssBorderStyle as iU, openNativeEyeDropper as iV, overallStatus as iW, paletteColor as iX, parseAudienceNonce as iY, parseNodeTextarea as iZ, partitionSlides as i_, issueTrackKey as ia, issueTypeLabel as ib, keyToLabel as ic, lastVisibleIndex as id, latexToMathml as ie, layoutConnectorPaints as ig, layoutNodeLabels as ih, linePointsToSvgString as ii, lineSpacingPatch as ij, loadAudienceContent as ik, loadSessionDeck as il, mediaFallbackFor as im, mediaSurfaceFor as io, mergeCaptionResults as ip, mergeDown as iq, mergeRight as ir, mergeSelection as is, moveElementBy as it, moveNodeDown as iu, moveNodeUp as iv, msToFrameDelayCs as iw, narrowToCircle as ix, narrowToPolygon as iy, narrowToRect as iz, ActionSettingsPanelComponent as j, rulerDragToGuidePosition as j$, patchChartStyle as j0, patchTableData as j1, patchTextStyle as j2, patternPresetOptions as j3, pendingElementStyles as j4, pickColorByClickFallback as j5, pickFile as j6, pickSupportedMimeType as j7, planGifFrames as j8, planVideoSegments as j9, removeSeries as jA, renderToCanvas as jB, reorderAnimationDown as jC, reorderAnimationUp as jD, replaceInSlides as jE, replaceMatch as jF, requestPresentationFullscreen as jG, resizeElement as jH, resolveCaptionTracks as jI, resolveChartKind as jJ, resolveFontVariant as jK, resolveHyperlinkHref as jL, resolveInteractiveElementId as jM, resolveMediaSrc as jN, resolveOleType as jO, resolveParagraphBullet as jP, resolvePresenterNotes as jQ, resolveProfileInitial as jR, resolveRegionCode as jS, resolveSlideAutoAdvanceMs as jT, resolvePalette as jU, resolveThemeCatalogEntry as jV, resolveTransitionDuration as jW, restoreSessionDeck as jX, revealedElementStyles as jY, routeOrthogonalConnector as jZ, rowStyle as j_, pointsToSvgPathD as ja, presenceToCursors as jb, presentationBaseName as jc, presentationStageStyle as jd, presenterTimerProgress as je, presetByLayout as jf, presetsForCategory as jg, pressuresToWidths as jh, prevVisibleIndex as ji, projectDrawingShapes as jj, promoteNode as jk, provideViewerTheme as jl, radarAngle as jm, radarRingPoints as jn, readAsDataUrl as jo, recordWebm as jp, registerCrossSlideAudio as jq, rememberSessionDeck as jr, removeAnimation as js, removeCategory as jt, removeTableElementColumn as ju, removeCommentFromList as jv, removeElementAnimation as jw, removeGradientStopPatch as jx, removeNode as jy, removeTableElementRow as jz, AdvancedChartEditorComponent as k, sheetAfterNavigate as k$, rulerHighlight as k0, rulerStripTicks as k1, sampleColorFromSlide as k2, sanitizeColor as k3, sanitizeSlideIndex as k4, sanitizeUserName as k5, saveViewerProfile as k6, savedPresentationFileName as k7, scanAvailableFonts as k8, searchSlides as k9, setDataPointMarker as kA, setDelay as kB, setDirection as kC, setDuration as kD, setEffectSound as kE, setElementPosition as kF, setGridlineStyle as kG, setLayout as kH, setLegend as kI, setNodeStyle as kJ, setNodeText as kK, setRepeatCount as kL, setRepeatMode as kM, setSequence as kN, setSeriesChartType as kO, setSeriesColor as kP, setSeriesErrorBars as kQ, setSeriesMarker as kR, setSeriesName as kS, setSeriesTrendline as kT, setSeriesValue as kU, setStyle as kV, setTimingCurve as kW, setTitle as kX, setTrigger as kY, setTriggerShapeId as kZ, shapeStylePatch$1 as k_, seedBroadcastFields as ka, seedHyperlinkDraft as kb, seedPropertiesDraft as kc, seedShareFields as kd, segmentFrameCount as ke, selectValue$2 as kf, sendBackward as kg, sendToBack as kh, sequentialColorScale as ki, serializeWriteBack as kj, seriesColor as kk, setAfterAnimation as kl, setAfterAnimationColor as km, setAnimationEmphasis as kn, setAnimationEntrance as ko, setAnimationExit as kp, setAxis as kq, setAxisLogScale as kr, setAxisTitleStyle as ks, setCategoryLabel as kt, setCellText as ku, setColorScheme as kv, setDataLabels as kw, setDataPointExplosion as kx, setDataPointFill as ky, setDataPointLabel as kz, AiChangeOverlayComponent as l, shouldBlockClickAdvance as l0, shouldUseSvgWarp as l1, showDirectionPicker as l2, showsTemplateAffordance as l3, signatureCountLabel as l4, signatureKey as l5, signatureTimestamp as l6, signerName as l7, statusLabel as l8, slideNumberOf as l9, toggleCommentResolvedInList as lA, toggleNodeBold as lB, toggleNodeItalic as lC, toggleSheet as lD, topLevelNodeCount as lE, transformSelectedTextCase as lF, translationsEn as lG, updateElementById as lH, updateGlowPatch as lI, updateGradientStopPatch as lJ, updateInnerShadowPatch as lK, updateOuterShadowPatch as lL, updateReflectionPatch as lM, vAlignPatch as lN, validatePassword as lO, validatePrintSettings as lP, validateRoomId as lQ, valueToY as lR, vermilionDarkColors as lS, vermilionDarkTheme as lT, vermilionLightColors as lU, vermilionLightTheme as lV, vermilionRadius as lW, waypointsToPathD as lX, worstStatus as lY, zoomTargetSlideIndex as lZ, slidesWithReappliedLayout as la, smartArtNodes as lb, paletteColour as lc, snapToGridStep as ld, splitCursorCell as le, splitMergedCell as lf, statusKind as lg, statusLabel$1 as lh, storeAudienceContent as li, stringFromEvent$5 as lj, strokeColorOf as lk, strokeToInkElement as ll, strokeWidthOf as lm, styleShadowFilter as ln, surfaceColor as lo, textAdvancedPatch as lp, textAdvancedStateFromStyle as lq, textAdvancedStateOf as lr, textColorOf as ls, textDirectionPatch as lt, textStyleOf as lu, textStylePatch as lv, themeStyle as lw, themeToCssVars as lx, thumbnailHeight as ly, thumbnailZoom as lz, AiChatPanelComponent as m, AiChatService as n, AiComposerComponent as o, AiFocusBarComponent as p, AiFocusHighlightOverlayComponent as q, AiHistoryMenuComponent as r, AiHistoryService as s, toChatSummary as t, AiMessageListComponent as u, AiPanelStore as v, AiProposalCardComponent as w, AiSettingsSectionComponent as x, AiToolCallCardComponent as y, AnimationAuthorPanelComponent as z };
|
|
147415
|
-
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-
|
|
148294
|
+
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-CblBWEKg.mjs.map
|