pptx-angular-viewer 2.17.1 → 2.17.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 +2 -0
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-hwk7tPwT.mjs → pptx-angular-viewer-chat-history-idb-BF1I9H0D.mjs} +2 -2
- package/fesm2022/{pptx-angular-viewer-chat-history-idb-hwk7tPwT.mjs.map → pptx-angular-viewer-chat-history-idb-BF1I9H0D.mjs.map} +1 -1
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-DMmyHdPM.mjs → pptx-angular-viewer-pptx-angular-viewer-0Jy3I4UO.mjs} +608 -86
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-DMmyHdPM.mjs.map → pptx-angular-viewer-pptx-angular-viewer-0Jy3I4UO.mjs.map} +1 -1
- package/fesm2022/pptx-angular-viewer.mjs +1 -1
- package/package.json +1 -1
- package/types/pptx-angular-viewer.d.ts +35 -1
|
@@ -33945,9 +33945,9 @@ function buildRunEffectStyle(style) {
|
|
|
33945
33945
|
* the accumulated disagreement over a line is what decides a knife-edge wrap.
|
|
33946
33946
|
*
|
|
33947
33947
|
* Ground truth (PowerPoint COM `TextRange.BoundWidth` over the issue #131 /
|
|
33948
|
-
* #149 deck): summing `round(advance * 6) / 6`
|
|
33949
|
-
*
|
|
33950
|
-
*
|
|
33948
|
+
* #149 deck): summing `round(advance * 6) / 6` reproduced all 78 advance-exact
|
|
33949
|
+
* measured lines to under 0.001 px, while the browser's own measurement of the
|
|
33950
|
+
* same strings ran anywhere from 1.07% narrow to 0.28% wide.
|
|
33951
33951
|
*
|
|
33952
33952
|
* That spread is the point. The first attempt at this (issue #131) applied a
|
|
33953
33953
|
* flat 0.003em to every run, which is roughly the middle of the range: it
|
|
@@ -33958,19 +33958,30 @@ function buildRunEffectStyle(style) {
|
|
|
33958
33958
|
* correction has to be derived from the actual characters.
|
|
33959
33959
|
*
|
|
33960
33960
|
* So: measure the run, compute the width PowerPoint would have measured, and
|
|
33961
|
-
* emit the letter-spacing that closes the gap.
|
|
33962
|
-
*
|
|
33963
|
-
*
|
|
33961
|
+
* emit the letter-spacing that closes the gap. Two details decide whether that
|
|
33962
|
+
* works or does damage, and both are documented where they are made -
|
|
33963
|
+
* `advancesOf` (advances come from prefix differences, never from measuring a
|
|
33964
|
+
* character alone) and the clamp in `resolveMetricTrackingPx`.
|
|
33965
|
+
*
|
|
33966
|
+
* Measured end to end in Chromium, rendered span against COM ground truth: mean
|
|
33967
|
+
* error 0.026 px, worst 0.40 px, against 0.53 px / 2.05 px uncompensated. On
|
|
33968
|
+
* shaped scripts the correction moves the text by 0.00% (Arabic, CJK) to 0.08%
|
|
33969
|
+
* (Devanagari), i.e. nothing visible.
|
|
33964
33970
|
*/
|
|
33965
33971
|
/**
|
|
33966
33972
|
* Advance-width quantisation steps per CSS px. PowerPoint snaps each glyph
|
|
33967
33973
|
* advance to an integer pixel at 576 DPI = 8 steps per point = 6 steps per px.
|
|
33968
33974
|
*/
|
|
33969
33975
|
const ADVANCE_STEPS_PER_PX = 6;
|
|
33976
|
+
/**
|
|
33977
|
+
* The most the correction can legitimately be: half a grid step. See
|
|
33978
|
+
* {@link resolveMetricTrackingPx} for why anything beyond this is a different
|
|
33979
|
+
* problem wearing a rounding error's clothes.
|
|
33980
|
+
*/
|
|
33981
|
+
const MAX_TRACKING_PX_PER_CHAR = 1 / (2 * ADVANCE_STEPS_PER_PX);
|
|
33970
33982
|
/** Bound the caches so a long editing session cannot grow them without limit. */
|
|
33971
33983
|
const MAX_CACHE_ENTRIES = 20000;
|
|
33972
33984
|
let measureContext;
|
|
33973
|
-
let advanceCache = new Map();
|
|
33974
33985
|
let trackingCache = new Map();
|
|
33975
33986
|
let fontsHookInstalled = false;
|
|
33976
33987
|
/**
|
|
@@ -33984,7 +33995,6 @@ function installFontLoadHook() {
|
|
|
33984
33995
|
}
|
|
33985
33996
|
fontsHookInstalled = true;
|
|
33986
33997
|
document.fonts?.addEventListener?.('loadingdone', () => {
|
|
33987
|
-
advanceCache = new Map();
|
|
33988
33998
|
trackingCache = new Map();
|
|
33989
33999
|
});
|
|
33990
34000
|
}
|
|
@@ -34006,19 +34016,43 @@ function toCanvasFont(font) {
|
|
|
34006
34016
|
const family = font.fontFamily || DEFAULT_FONT_FAMILY$1;
|
|
34007
34017
|
return `${font.italic ? 'italic ' : ''}${font.bold ? 'bold ' : ''}${size}px ${family}`;
|
|
34008
34018
|
}
|
|
34009
|
-
|
|
34010
|
-
|
|
34011
|
-
|
|
34012
|
-
|
|
34013
|
-
|
|
34014
|
-
|
|
34019
|
+
/**
|
|
34020
|
+
* Per-character advances measured as PREFIX DIFFERENCES, never by measuring a
|
|
34021
|
+
* character on its own.
|
|
34022
|
+
*
|
|
34023
|
+
* This is the difference between a model that works and one that mangles half
|
|
34024
|
+
* the world's scripts. A character's advance depends on its neighbours: Arabic
|
|
34025
|
+
* letters join, so an isolated glyph measures ~37% wider than the same letter
|
|
34026
|
+
* inside a word; Devanagari forms conjuncts (~66%); an emoji ZWJ sequence is
|
|
34027
|
+
* one glyph built from several code points (~33%); and even Latin kerns - the
|
|
34028
|
+
* isolated characters of "AVATAR Wave To Yak" add up 5.3% wider than the string
|
|
34029
|
+
* itself. Summing isolated advances would hand the grid model a difference that
|
|
34030
|
+
* is not a rounding error at all, and letter-spacing would then stretch the run
|
|
34031
|
+
* to "correct" it: visibly wrong text, and a worse wrap than the one this set
|
|
34032
|
+
* out to fix.
|
|
34033
|
+
*
|
|
34034
|
+
* Differencing prefixes cannot fail that way. The advances telescope, so they
|
|
34035
|
+
* sum to exactly the width the browser will paint, whatever the shaping did.
|
|
34036
|
+
* Only their DISTRIBUTION across a ligature or cluster is approximate, and the
|
|
34037
|
+
* grid correction stays bounded by half a step per character either way.
|
|
34038
|
+
*/
|
|
34039
|
+
function advancesOf(ctx, canvasFont, chars) {
|
|
34015
34040
|
ctx.font = canvasFont;
|
|
34016
|
-
|
|
34017
|
-
|
|
34018
|
-
|
|
34041
|
+
// PowerPoint's own advances are UNKERNED unless `a:rPr/@kern` turns kerning
|
|
34042
|
+
// on, and this deck's ground truth confirms it: measured with kerning the
|
|
34043
|
+
// grid model reproduced 66 of 78 COM-measured lines, without it all 78,
|
|
34044
|
+
// exactly. Chrome kerns 12 of those lines by 0.17-1.55 px.
|
|
34045
|
+
ctx.fontKerning = 'none';
|
|
34046
|
+
const advances = [];
|
|
34047
|
+
let previous = 0;
|
|
34048
|
+
let prefix = '';
|
|
34049
|
+
for (const char of chars) {
|
|
34050
|
+
prefix += char;
|
|
34051
|
+
const width = ctx.measureText(prefix).width;
|
|
34052
|
+
advances.push(width - previous);
|
|
34053
|
+
previous = width;
|
|
34019
34054
|
}
|
|
34020
|
-
|
|
34021
|
-
return width;
|
|
34055
|
+
return advances;
|
|
34022
34056
|
}
|
|
34023
34057
|
/**
|
|
34024
34058
|
* The letter-spacing (in CSS px) that makes `text` render at the width
|
|
@@ -34030,10 +34064,15 @@ function advanceOf(ctx, canvasFont, char) {
|
|
|
34030
34064
|
* inline box the line breaker sees. Being wrong about that convention would
|
|
34031
34065
|
* cost one unit of tracking (~0.04 px), well inside the tolerance here.
|
|
34032
34066
|
*
|
|
34033
|
-
* The result
|
|
34034
|
-
*
|
|
34035
|
-
*
|
|
34036
|
-
*
|
|
34067
|
+
* The result is clamped to half a grid step per character, and that bound is
|
|
34068
|
+
* the model's own definition rather than a magic number: snapping an advance to
|
|
34069
|
+
* the grid can move it by at most half a step, so a correction larger than that
|
|
34070
|
+
* is not describing rounding at all. It means the browser and PowerPoint
|
|
34071
|
+
* disagree for some other reason - kerning the run enables and PowerPoint does
|
|
34072
|
+
* not, a font that never loaded - and uniform letter-spacing is the wrong tool
|
|
34073
|
+
* for those. Clamping keeps the correction imperceptible (at most 0.083 px per
|
|
34074
|
+
* glyph) instead of visibly stretching the text to chase a difference it cannot
|
|
34075
|
+
* legitimately close.
|
|
34037
34076
|
*/
|
|
34038
34077
|
function resolveMetricTrackingPx(text, font) {
|
|
34039
34078
|
if (!text) {
|
|
@@ -34050,23 +34089,79 @@ function resolveMetricTrackingPx(text, font) {
|
|
|
34050
34089
|
return 0;
|
|
34051
34090
|
}
|
|
34052
34091
|
const chars = [...text];
|
|
34053
|
-
|
|
34092
|
+
let powerPoint = 0;
|
|
34093
|
+
for (const advance of advancesOf(ctx, canvasFont, chars)) {
|
|
34094
|
+
powerPoint += Math.round(advance * ADVANCE_STEPS_PER_PX);
|
|
34095
|
+
}
|
|
34096
|
+
// ...against the width the browser will actually PAINT, which is kerned.
|
|
34097
|
+
ctx.fontKerning = 'auto';
|
|
34054
34098
|
const natural = ctx.measureText(text).width;
|
|
34055
34099
|
if (!(natural > 0)) {
|
|
34056
34100
|
return 0;
|
|
34057
34101
|
}
|
|
34058
|
-
let powerPoint = 0;
|
|
34059
|
-
for (const char of chars) {
|
|
34060
|
-
powerPoint += Math.round(advanceOf(ctx, canvasFont, char) * ADVANCE_STEPS_PER_PX);
|
|
34061
|
-
}
|
|
34062
34102
|
powerPoint /= ADVANCE_STEPS_PER_PX;
|
|
34063
|
-
const
|
|
34103
|
+
const limit = MAX_TRACKING_PX_PER_CHAR;
|
|
34104
|
+
const raw = (powerPoint - natural) / chars.length;
|
|
34105
|
+
const tracking = Math.min(limit, Math.max(-limit, raw));
|
|
34064
34106
|
if (trackingCache.size >= MAX_CACHE_ENTRIES) {
|
|
34065
34107
|
trackingCache = new Map();
|
|
34066
34108
|
}
|
|
34067
34109
|
trackingCache.set(key, tracking);
|
|
34068
34110
|
return tracking;
|
|
34069
34111
|
}
|
|
34112
|
+
/**
|
|
34113
|
+
* True where the browser may break a line: between whitespace and a word, and
|
|
34114
|
+
* after a hyphen. Deliberately conservative - a boundary we miss costs
|
|
34115
|
+
* accuracy, a boundary we invent costs nothing, since pieces are laid out
|
|
34116
|
+
* contiguously either way.
|
|
34117
|
+
*/
|
|
34118
|
+
function isBreakBoundary(previous, next) {
|
|
34119
|
+
const previousSpace = /\s/u.test(previous);
|
|
34120
|
+
const nextSpace = /\s/u.test(next);
|
|
34121
|
+
if (previousSpace !== nextSpace) {
|
|
34122
|
+
return true;
|
|
34123
|
+
}
|
|
34124
|
+
return previous === '-' && next !== '-' && !nextSpace;
|
|
34125
|
+
}
|
|
34126
|
+
/**
|
|
34127
|
+
* Cut a run at every line-break opportunity so each piece can carry its own
|
|
34128
|
+
* tracking.
|
|
34129
|
+
*
|
|
34130
|
+
* One tracking for a whole run makes the RUN measure exactly, but a line is a
|
|
34131
|
+
* prefix of it, and the rounding error is not spread evenly through the text -
|
|
34132
|
+
* so a line can still come out up to ~0.95 px off, which is enough to move a
|
|
34133
|
+
* break (issue #149, slide 5: "operational" fitted on a line PowerPoint had
|
|
34134
|
+
* already closed). Give every word its own tracking and every whitespace gap
|
|
34135
|
+
* its own, and any line the browser assembles out of whole pieces measures
|
|
34136
|
+
* exactly what PowerPoint measured, because advances simply add up.
|
|
34137
|
+
*
|
|
34138
|
+
* A break INSIDE a piece (mid-word, or between CJK characters, which have no
|
|
34139
|
+
* spaces to cut at) falls back to that piece's average - i.e. to the run-level
|
|
34140
|
+
* behaviour, never worse.
|
|
34141
|
+
*
|
|
34142
|
+
* Returns a single piece when the run has no interior boundary, which keeps the
|
|
34143
|
+
* common case (a short label, a one-word run) at exactly one span.
|
|
34144
|
+
*/
|
|
34145
|
+
function splitRunForMetrics(text, font) {
|
|
34146
|
+
const chars = [...text];
|
|
34147
|
+
if (chars.length < 2 || !getMeasureContext()) {
|
|
34148
|
+
return [{ text, tracking: resolveMetricTrackingPx(text, font) }];
|
|
34149
|
+
}
|
|
34150
|
+
const pieces = [];
|
|
34151
|
+
let current = chars[0];
|
|
34152
|
+
for (let i = 1; i < chars.length; i++) {
|
|
34153
|
+
if (isBreakBoundary(chars[i - 1], chars[i])) {
|
|
34154
|
+
pieces.push(current);
|
|
34155
|
+
current = '';
|
|
34156
|
+
}
|
|
34157
|
+
current += chars[i];
|
|
34158
|
+
}
|
|
34159
|
+
pieces.push(current);
|
|
34160
|
+
if (pieces.length === 1) {
|
|
34161
|
+
return [{ text, tracking: resolveMetricTrackingPx(text, font) }];
|
|
34162
|
+
}
|
|
34163
|
+
return pieces.map((piece) => ({ text: piece, tracking: resolveMetricTrackingPx(piece, font) }));
|
|
34164
|
+
}
|
|
34070
34165
|
/**
|
|
34071
34166
|
* {@link resolveMetricTrackingPx} as a CSS length, or `undefined` when the run
|
|
34072
34167
|
* needs no correction (so callers can leave `letter-spacing` undeclared rather
|
|
@@ -34078,7 +34173,6 @@ function resolveMetricTracking(text, font) {
|
|
|
34078
34173
|
}
|
|
34079
34174
|
/** Test hook: forget every measurement (also used by the font-load listener). */
|
|
34080
34175
|
function resetMetricTrackingCache() {
|
|
34081
|
-
advanceCache = new Map();
|
|
34082
34176
|
trackingCache = new Map();
|
|
34083
34177
|
measureContext = undefined;
|
|
34084
34178
|
}
|
|
@@ -34095,6 +34189,50 @@ function resetMetricTrackingCache() {
|
|
|
34095
34189
|
const PX_PER_POINT = 96 / 72;
|
|
34096
34190
|
/** Super/subscript glyphs render at ~65% of the run font size (matches React). */
|
|
34097
34191
|
const BASELINE_FONT_SCALE = 0.65;
|
|
34192
|
+
/**
|
|
34193
|
+
* The authored `a:rPr/@spc` character spacing in CSS px (hundredths of a point).
|
|
34194
|
+
* The measured PowerPoint metric compensation layers on top of this, so callers
|
|
34195
|
+
* that re-derive a per-piece `letter-spacing` need the authored part on its own.
|
|
34196
|
+
*/
|
|
34197
|
+
function authoredLetterSpacingPx(style) {
|
|
34198
|
+
const spc = style?.characterSpacing;
|
|
34199
|
+
return typeof spc === 'number' && spc !== 0 ? (spc / 100) * PX_PER_POINT : 0;
|
|
34200
|
+
}
|
|
34201
|
+
/** `letter-spacing` for a run piece: authored spacing plus its own tracking. */
|
|
34202
|
+
function pieceLetterSpacing(authoredPx, tracking) {
|
|
34203
|
+
const spacing = authoredPx + tracking;
|
|
34204
|
+
return spacing === 0 ? undefined : `${spacing}px`;
|
|
34205
|
+
}
|
|
34206
|
+
/**
|
|
34207
|
+
* Split one styled run into the per-word / per-gap runs that make a LINE
|
|
34208
|
+
* measure what PowerPoint measured (see `splitRunForMetrics`).
|
|
34209
|
+
*
|
|
34210
|
+
* Every binding that renders one span per run gets exact wrapping by emitting
|
|
34211
|
+
* these instead of the single run, so this is the one place the "which pieces,
|
|
34212
|
+
* what spacing" decision lives: shared's `buildParagraphs` covers Vue, Svelte
|
|
34213
|
+
* and Vanilla, Angular's own paragraph builder calls it directly, and React
|
|
34214
|
+
* splits inside its span.
|
|
34215
|
+
*
|
|
34216
|
+
* Returns a single entry (the run unchanged) when there is nothing to split,
|
|
34217
|
+
* which is the common case for short labels and one-word runs.
|
|
34218
|
+
*/
|
|
34219
|
+
function splitStyledRun(text, style, font, authoredPx) {
|
|
34220
|
+
const pieces = splitRunForMetrics(text, font);
|
|
34221
|
+
if (pieces.length <= 1) {
|
|
34222
|
+
return [{ text, style }];
|
|
34223
|
+
}
|
|
34224
|
+
return pieces.map((piece) => {
|
|
34225
|
+
const spacing = pieceLetterSpacing(authoredPx, piece.tracking);
|
|
34226
|
+
const pieceStyle = { ...style };
|
|
34227
|
+
if (spacing === undefined) {
|
|
34228
|
+
delete pieceStyle.letterSpacing;
|
|
34229
|
+
}
|
|
34230
|
+
else {
|
|
34231
|
+
pieceStyle.letterSpacing = spacing;
|
|
34232
|
+
}
|
|
34233
|
+
return { text: piece.text, style: pieceStyle };
|
|
34234
|
+
});
|
|
34235
|
+
}
|
|
34098
34236
|
/**
|
|
34099
34237
|
* Combine the authored `a:rPr/@spc` character spacing with the measured
|
|
34100
34238
|
* PowerPoint metric compensation into one `letter-spacing`, or leave it
|
|
@@ -34106,11 +34244,7 @@ const BASELINE_FONT_SCALE = 0.65;
|
|
|
34106
34244
|
* (issue #149).
|
|
34107
34245
|
*/
|
|
34108
34246
|
function resolveLetterSpacing(s, text, font) {
|
|
34109
|
-
|
|
34110
|
-
? (s.characterSpacing / 100) * PX_PER_POINT
|
|
34111
|
-
: 0;
|
|
34112
|
-
const spacing = authored + resolveMetricTrackingPx(text, font);
|
|
34113
|
-
return spacing === 0 ? undefined : `${spacing}px`;
|
|
34247
|
+
return pieceLetterSpacing(authoredLetterSpacingPx(s), resolveMetricTrackingPx(text, font));
|
|
34114
34248
|
}
|
|
34115
34249
|
/**
|
|
34116
34250
|
* Layer the "extra" run properties that neither the boolean decoration set nor
|
|
@@ -34202,19 +34336,27 @@ function segmentStyleToCss(seg, fontScale = 1, context = {}) {
|
|
|
34202
34336
|
if (deco.length > 0) {
|
|
34203
34337
|
style.textDecoration = deco.join(' ');
|
|
34204
34338
|
}
|
|
34205
|
-
|
|
34206
|
-
|
|
34207
|
-
|
|
34208
|
-
|
|
34209
|
-
|
|
34339
|
+
applyExtraRunProps(style, s, context.text ?? seg.text ?? '', resolveRunFont(style, s, context.blockFont));
|
|
34340
|
+
return style;
|
|
34341
|
+
}
|
|
34342
|
+
/**
|
|
34343
|
+
* The font a run will actually paint with: its own declarations where it made
|
|
34344
|
+
* them, the text body's where it did not. Bold and italic are always the run's
|
|
34345
|
+
* own, because {@link segmentStyleToCss} declares both unconditionally.
|
|
34346
|
+
*
|
|
34347
|
+
* Exported so a caller that re-measures pieces of a run (see
|
|
34348
|
+
* `splitRunForMetrics`) resolves the font exactly the way the run style did,
|
|
34349
|
+
* rather than keeping a second copy of the fallback rules.
|
|
34350
|
+
*/
|
|
34351
|
+
function resolveRunFont(style, s, blockFont) {
|
|
34352
|
+
return {
|
|
34353
|
+
fontFamily: style.fontFamily ?? blockFont?.fontFamily,
|
|
34210
34354
|
fontSizePx: typeof style.fontSize === 'string'
|
|
34211
34355
|
? Number.parseFloat(style.fontSize)
|
|
34212
|
-
:
|
|
34356
|
+
: blockFont?.fontSizePx,
|
|
34213
34357
|
bold: Boolean(s.bold),
|
|
34214
34358
|
italic: Boolean(s.italic),
|
|
34215
34359
|
};
|
|
34216
|
-
applyExtraRunProps(style, s, context.text ?? seg.text ?? '', runFont);
|
|
34217
|
-
return style;
|
|
34218
34360
|
}
|
|
34219
34361
|
/**
|
|
34220
34362
|
* Layer the underline-style / double-strike *variant* decoration CSS
|
|
@@ -34426,7 +34568,13 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
34426
34568
|
if (seg.style) {
|
|
34427
34569
|
Object.assign(style, buildRunEffectStyle(seg.style));
|
|
34428
34570
|
}
|
|
34429
|
-
|
|
34571
|
+
// Each word and each gap carries its own PowerPoint metric tracking,
|
|
34572
|
+
// so a line the browser assembles out of them measures exactly what
|
|
34573
|
+
// PowerPoint measured and breaks where PowerPoint breaks (#149).
|
|
34574
|
+
// Emitting them as sibling RUNS rather than nested spans is what
|
|
34575
|
+
// gets this to Vue/Svelte/Vanilla with no binding change: they
|
|
34576
|
+
// already render one span per run.
|
|
34577
|
+
runs.push(...splitStyledRun(text, style, resolveRunFont(style, seg.style ?? {}, blockFont), authoredLetterSpacingPx(seg.style)));
|
|
34430
34578
|
}
|
|
34431
34579
|
}
|
|
34432
34580
|
// Suppress bullets for paragraphs with no visible text content.
|
|
@@ -34751,14 +34899,79 @@ function correspondingGroup(group, candidates) {
|
|
|
34751
34899
|
return sameBox(group, candidate);
|
|
34752
34900
|
});
|
|
34753
34901
|
}
|
|
34902
|
+
/** Fraction of the union two boxes must share to read as the same object. */
|
|
34903
|
+
const CHILD_OVERLAP_RATIO = 0.5;
|
|
34904
|
+
/** Intersection over union of two element boxes. */
|
|
34905
|
+
function boxOverlapRatio(a, b) {
|
|
34906
|
+
const left = Math.max(a.x, b.x);
|
|
34907
|
+
const top = Math.max(a.y, b.y);
|
|
34908
|
+
const right = Math.min(a.x + a.width, b.x + b.width);
|
|
34909
|
+
const bottom = Math.min(a.y + a.height, b.y + b.height);
|
|
34910
|
+
if (right <= left || bottom <= top) {
|
|
34911
|
+
return 0;
|
|
34912
|
+
}
|
|
34913
|
+
const intersection = (right - left) * (bottom - top);
|
|
34914
|
+
const union = a.width * a.height + b.width * b.height - intersection;
|
|
34915
|
+
return union > 0 ? intersection / union : 0;
|
|
34916
|
+
}
|
|
34917
|
+
/** Whether two group children read as the same object, restyled or nudged. */
|
|
34918
|
+
function childrenPair(a, b) {
|
|
34919
|
+
const morphName = getElementMorphName(a);
|
|
34920
|
+
if (morphName !== undefined && getElementMorphName(b) === morphName) {
|
|
34921
|
+
return true;
|
|
34922
|
+
}
|
|
34923
|
+
if (a.name && a.name === b.name) {
|
|
34924
|
+
return true;
|
|
34925
|
+
}
|
|
34926
|
+
return boxOverlapRatio(a, b) >= CHILD_OVERLAP_RATIO;
|
|
34927
|
+
}
|
|
34928
|
+
/**
|
|
34929
|
+
* Whether two paired groups hold the SAME cast of objects, one for one.
|
|
34930
|
+
*
|
|
34931
|
+
* This is what decides between animating a group's contents individually and
|
|
34932
|
+
* dissolving the whole group into its counterpart, and PowerPoint draws the
|
|
34933
|
+
* line in the same place. Measured on the issue #131 deck by exporting the real
|
|
34934
|
+
* transitions to video (`CreateVideo`, 62.5fps) and fitting every frame of the
|
|
34935
|
+
* centre panel to a blend of the first and last:
|
|
34936
|
+
*
|
|
34937
|
+
* - hub -> topic (`!!Circle` = disc + "Select Challenge", against disc +
|
|
34938
|
+
* button + three paragraphs): every frame is a clean linear blend of the
|
|
34939
|
+
* two end states, residual < 1/255, with the arriving title AND the
|
|
34940
|
+
* departing wording both following the same curve. That is one object
|
|
34941
|
+
* dissolving into another, not four shapes appearing and one leaving:
|
|
34942
|
+
* unmatched shapes hold, then fade out by 23% and in from 42%, which would
|
|
34943
|
+
* leave the middle of the transition empty (issue #146).
|
|
34944
|
+
* - topic -> topic (five children against five, same boxes): also a clean
|
|
34945
|
+
* blend, so decomposing there is harmless - each child simply crossfades
|
|
34946
|
+
* into its own counterpart.
|
|
34947
|
+
*
|
|
34948
|
+
* So a group is decomposed only when its children line up; a group that gained
|
|
34949
|
+
* or lost content dissolves as a whole.
|
|
34950
|
+
*/
|
|
34951
|
+
function childrenCorrespond(a, b) {
|
|
34952
|
+
if (a.length !== b.length || a.length === 0) {
|
|
34953
|
+
return false;
|
|
34954
|
+
}
|
|
34955
|
+
const unclaimed = b.map((child) => child);
|
|
34956
|
+
for (const child of a) {
|
|
34957
|
+
const index = unclaimed.findIndex((candidate) => childrenPair(child, candidate));
|
|
34958
|
+
if (index < 0) {
|
|
34959
|
+
return false;
|
|
34960
|
+
}
|
|
34961
|
+
unclaimed.splice(index, 1);
|
|
34962
|
+
}
|
|
34963
|
+
return true;
|
|
34964
|
+
}
|
|
34754
34965
|
/**
|
|
34755
34966
|
* The elements of `elements` that a morph should treat as individual units,
|
|
34756
34967
|
* given the `counterpart` slide's elements at the same level of the tree.
|
|
34757
34968
|
*
|
|
34758
34969
|
* A group is replaced by its children (in document order, recursively, in
|
|
34759
|
-
* absolute coordinates) when it holds a `!!`-named descendant
|
|
34760
|
-
* holds a group it would pair with
|
|
34761
|
-
* untouched. See the module comment
|
|
34970
|
+
* absolute coordinates) when it holds a `!!`-named descendant, `counterpart`
|
|
34971
|
+
* holds a group it would pair with, AND the two groups hold the same cast of
|
|
34972
|
+
* objects; everything else is passed through untouched. See the module comment
|
|
34973
|
+
* for why the first two are required and {@link childrenCorrespond} for the
|
|
34974
|
+
* third.
|
|
34762
34975
|
*/
|
|
34763
34976
|
function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
|
|
34764
34977
|
const out = [];
|
|
@@ -34767,7 +34980,7 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
|
|
|
34767
34980
|
if (children && containsMorphNamedDescendant(element)) {
|
|
34768
34981
|
const twin = correspondingGroup(element, counterpart);
|
|
34769
34982
|
const twinChildren = twin ? (groupChildren(twin) ?? []) : undefined;
|
|
34770
|
-
if (twinChildren) {
|
|
34983
|
+
if (twinChildren && childrenCorrespond(children, twinChildren)) {
|
|
34771
34984
|
out.push(...flattenMorphElements(children, twinChildren, offsetX + element.x, offsetY + element.y));
|
|
34772
34985
|
continue;
|
|
34773
34986
|
}
|
|
@@ -35081,6 +35294,20 @@ function interpolateOutline(from, to, t) {
|
|
|
35081
35294
|
// ---------------------------------------------------------------------------
|
|
35082
35295
|
/** PowerPoint's morph transition uses a specific cubic-bezier easing. */
|
|
35083
35296
|
const MORPH_EASING = 'cubic-bezier(0.4, 0, 0.2, 1)';
|
|
35297
|
+
/**
|
|
35298
|
+
* The curve a matched pair DISSOLVES on, which is not the curve it travels on.
|
|
35299
|
+
*
|
|
35300
|
+
* Measured, not guessed: the issue #131 deck's hub-to-topic morph was exported
|
|
35301
|
+
* through PowerPoint's own `CreateVideo` and every one of the 59 frames of the
|
|
35302
|
+
* arriving title fitted to a blend of the first and last frame (residual under
|
|
35303
|
+
* 1/255, so the dissolve really is a plain linear blend). The alpha runs 0.035
|
|
35304
|
+
* at 7% of the duration, 0.232 at 20%, 0.477 at 34%, 0.684 at 47%, 0.888 at 68%
|
|
35305
|
+
* and 0.988 at 88%: an ease that leans in gently and then decelerates hard.
|
|
35306
|
+
* This curve tracks those samples to an RMS of 0.004 and never differs by more
|
|
35307
|
+
* than 0.009. {@link MORPH_EASING}, which the ghost used to fade on, sits at
|
|
35308
|
+
* 0.5 where PowerPoint is already at 0.73 (issue #146).
|
|
35309
|
+
*/
|
|
35310
|
+
const MORPH_CROSSFADE_EASING = 'cubic-bezier(0.2, 0, 0.4, 1)';
|
|
35084
35311
|
/**
|
|
35085
35312
|
* When an unmatched OUTGOING shape has finished dissolving, as a percentage of
|
|
35086
35313
|
* the morph's duration, and when it starts.
|
|
@@ -35630,6 +35857,122 @@ function matchMorphElementsFull(fromSlide, toSlide) {
|
|
|
35630
35857
|
return { pairs, unmatchedFrom, unmatchedTo };
|
|
35631
35858
|
}
|
|
35632
35859
|
|
|
35860
|
+
/** The area a shape occupies over the whole morph (start box union end box). */
|
|
35861
|
+
function travelledBox(from, to) {
|
|
35862
|
+
const boxes = to ? [from, to] : [from];
|
|
35863
|
+
return {
|
|
35864
|
+
left: Math.min(...boxes.map((element) => element.x)),
|
|
35865
|
+
top: Math.min(...boxes.map((element) => element.y)),
|
|
35866
|
+
right: Math.max(...boxes.map((element) => element.x + element.width)),
|
|
35867
|
+
bottom: Math.max(...boxes.map((element) => element.y + element.height)),
|
|
35868
|
+
};
|
|
35869
|
+
}
|
|
35870
|
+
/** Whether two travelled boxes share any area. */
|
|
35871
|
+
function boxesOverlap(a, b) {
|
|
35872
|
+
return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
|
|
35873
|
+
}
|
|
35874
|
+
/**
|
|
35875
|
+
* Rank every shape of both slides in a single back-to-front order.
|
|
35876
|
+
*
|
|
35877
|
+
* A matched pair is ONE object and gets ONE rank, so "is this arrival above
|
|
35878
|
+
* that ghost?" is a plain number comparison. The two document orders are merged
|
|
35879
|
+
* the way a diff merges two revisions of a list: walking the incoming slide,
|
|
35880
|
+
* each matched shape first flushes everything the outgoing slide drew below its
|
|
35881
|
+
* counterpart, so departures keep their place relative to the shapes that
|
|
35882
|
+
* surrounded them and arrivals keep theirs.
|
|
35883
|
+
*
|
|
35884
|
+
* Both lists must already be flattened the way the matcher flattens them (see
|
|
35885
|
+
* `morph-flatten`), or the ids will not line up with `pairs`.
|
|
35886
|
+
*
|
|
35887
|
+
* @param outgoing - The outgoing slide's elements, flattened, in document order.
|
|
35888
|
+
* @param incoming - The incoming slide's elements, flattened, in document order.
|
|
35889
|
+
* @param pairs - The matched pairs.
|
|
35890
|
+
* @returns Element id -> rank; higher is nearer the viewer.
|
|
35891
|
+
*/
|
|
35892
|
+
function buildMorphMergedOrder(outgoing, incoming, pairs) {
|
|
35893
|
+
const partnerOf = new Map(pairs.map((pair) => [pair.toElement.id, pair.fromElement.id]));
|
|
35894
|
+
const outgoingIndex = new Map(outgoing.map((element, index) => [element.id, index]));
|
|
35895
|
+
const rank = new Map();
|
|
35896
|
+
let next = 0;
|
|
35897
|
+
let cursor = 0;
|
|
35898
|
+
/** Emit every outgoing shape below `limit` that has not been placed yet. */
|
|
35899
|
+
const flushOutgoingBelow = (limit) => {
|
|
35900
|
+
while (cursor < limit) {
|
|
35901
|
+
const element = outgoing[cursor];
|
|
35902
|
+
cursor += 1;
|
|
35903
|
+
if (!rank.has(element.id)) {
|
|
35904
|
+
rank.set(element.id, next);
|
|
35905
|
+
next += 1;
|
|
35906
|
+
}
|
|
35907
|
+
}
|
|
35908
|
+
};
|
|
35909
|
+
for (const element of incoming) {
|
|
35910
|
+
const partner = partnerOf.get(element.id);
|
|
35911
|
+
const partnerIndex = partner === undefined ? undefined : outgoingIndex.get(partner);
|
|
35912
|
+
if (partner === undefined || partnerIndex === undefined) {
|
|
35913
|
+
// An arrival holds its own place in the incoming slide's stack.
|
|
35914
|
+
rank.set(element.id, next);
|
|
35915
|
+
next += 1;
|
|
35916
|
+
continue;
|
|
35917
|
+
}
|
|
35918
|
+
flushOutgoingBelow(partnerIndex + 1);
|
|
35919
|
+
rank.set(element.id, rank.get(partner) ?? next);
|
|
35920
|
+
}
|
|
35921
|
+
flushOutgoingBelow(outgoing.length);
|
|
35922
|
+
return rank;
|
|
35923
|
+
}
|
|
35924
|
+
/**
|
|
35925
|
+
* The incoming shapes the overlay has to paint over its ghosts.
|
|
35926
|
+
*
|
|
35927
|
+
* An arriving shape is lifted when a ghost that HOLDS ITS OPACITY sits below it
|
|
35928
|
+
* in the merged order and covers it: on the live stage it would dissolve in
|
|
35929
|
+
* underneath something opaque and never be seen at all. Anything the ghosts are
|
|
35930
|
+
* legitimately on top of - the incoming slide's own backdrop, artwork the
|
|
35931
|
+
* persisting shapes are drawn over - keeps its place on the stage.
|
|
35932
|
+
*
|
|
35933
|
+
* A ghost that DISSOLVES is deliberately not counted, which is why the caller
|
|
35934
|
+
* passes only the holding ones. It stops hiding anything within the first
|
|
35935
|
+
* quarter of the morph, well before an arrival starts to appear at 42% (see
|
|
35936
|
+
* `MORPH_FADE_OUT_END_PERCENT` / `MORPH_FADE_IN_START_PERCENT`), so lifting for
|
|
35937
|
+
* it buys nothing and moves an animation the live stage should own: issue
|
|
35938
|
+
* #131's overview-to-topic hop dissolves the whole centre out and the arriving
|
|
35939
|
+
* group in, exactly that way.
|
|
35940
|
+
*
|
|
35941
|
+
* Only shapes with NO counterpart qualify. A matched pair already dissolves
|
|
35942
|
+
* against its own ghost, which is the whole point of the crossfade; lifting its
|
|
35943
|
+
* incoming half above that ghost would turn the dissolve back into a cut.
|
|
35944
|
+
*
|
|
35945
|
+
* @param outgoing - The outgoing slide's elements, flattened, in document order.
|
|
35946
|
+
* @param incoming - The incoming slide's elements, flattened, in document order.
|
|
35947
|
+
* @param pairs - The matched pairs.
|
|
35948
|
+
* @param holdingGhostIds - The outgoing ids the overlay paints AND keeps opaque
|
|
35949
|
+
* for the whole morph (a painted pair whose appearance did not change).
|
|
35950
|
+
* @returns The ids of the incoming elements to lift, a subset of `incoming`.
|
|
35951
|
+
*/
|
|
35952
|
+
function resolveMorphOverlayArrivals(outgoing, incoming, pairs, holdingGhostIds) {
|
|
35953
|
+
const rank = buildMorphMergedOrder(outgoing, incoming, pairs);
|
|
35954
|
+
const matched = new Set(pairs.map((pair) => pair.toElement.id));
|
|
35955
|
+
const counterpart = new Map(pairs.map((pair) => [pair.fromElement.id, pair.toElement]));
|
|
35956
|
+
const ghosts = outgoing
|
|
35957
|
+
.filter((element) => holdingGhostIds.has(element.id))
|
|
35958
|
+
.map((element) => ({
|
|
35959
|
+
rank: rank.get(element.id) ?? 0,
|
|
35960
|
+
box: travelledBox(element, counterpart.get(element.id)),
|
|
35961
|
+
}));
|
|
35962
|
+
const lifted = new Set();
|
|
35963
|
+
for (const element of incoming) {
|
|
35964
|
+
if (matched.has(element.id)) {
|
|
35965
|
+
continue;
|
|
35966
|
+
}
|
|
35967
|
+
const mine = rank.get(element.id) ?? 0;
|
|
35968
|
+
const box = travelledBox(element);
|
|
35969
|
+
if (ghosts.some((ghost) => ghost.rank < mine && boxesOverlap(ghost.box, box))) {
|
|
35970
|
+
lifted.add(element.id);
|
|
35971
|
+
}
|
|
35972
|
+
}
|
|
35973
|
+
return lifted;
|
|
35974
|
+
}
|
|
35975
|
+
|
|
35633
35976
|
// ---------------------------------------------------------------------------
|
|
35634
35977
|
// Text tokenization
|
|
35635
35978
|
// ---------------------------------------------------------------------------
|
|
@@ -36077,19 +36420,9 @@ function isInertMorphPair(fromElement, toElement) {
|
|
|
36077
36420
|
(fromElement.opacity ?? 1) === (toElement.opacity ?? 1) &&
|
|
36078
36421
|
!morphPairNeedsCrossfade(fromElement, toElement));
|
|
36079
36422
|
}
|
|
36080
|
-
|
|
36081
|
-
|
|
36082
|
-
|
|
36083
|
-
return {
|
|
36084
|
-
left: Math.min(...boxes.map((element) => element.x)),
|
|
36085
|
-
top: Math.min(...boxes.map((element) => element.y)),
|
|
36086
|
-
right: Math.max(...boxes.map((element) => element.x + element.width)),
|
|
36087
|
-
bottom: Math.max(...boxes.map((element) => element.y + element.height)),
|
|
36088
|
-
};
|
|
36089
|
-
}
|
|
36090
|
-
function boxesOverlap(a, b) {
|
|
36091
|
-
return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
|
|
36092
|
-
}
|
|
36423
|
+
// ---------------------------------------------------------------------------
|
|
36424
|
+
// Which outgoing shapes the overlay has to paint
|
|
36425
|
+
// ---------------------------------------------------------------------------
|
|
36093
36426
|
/**
|
|
36094
36427
|
* The outgoing shapes the transition overlay actually has to paint.
|
|
36095
36428
|
*
|
|
@@ -36145,12 +36478,21 @@ function resolveMorphGhostIds(outgoingElements, pairs) {
|
|
|
36145
36478
|
* box over `noFill` has nothing to hollow out, and pinning it means the new
|
|
36146
36479
|
* wording is at full strength from frame 1 while the old dissolves off it,
|
|
36147
36480
|
* which reads as the new text simply appearing rather than cross-dissolving.
|
|
36481
|
+
*
|
|
36482
|
+
* A GROUP owns no fill of its own, so the question has to be asked of its
|
|
36483
|
+
* children: the wheel deck's centre panel is a group around an opaque disc, and
|
|
36484
|
+
* fading it in while its ghost faded out turned the disc translucent for the
|
|
36485
|
+
* middle of every hub-to-topic morph.
|
|
36148
36486
|
*/
|
|
36149
36487
|
function crossfadeIncomingMayFadeIn(element) {
|
|
36150
36488
|
const image = element;
|
|
36151
36489
|
if (image.imagePath || image.svgPath) {
|
|
36152
36490
|
return false;
|
|
36153
36491
|
}
|
|
36492
|
+
const children = element.children;
|
|
36493
|
+
if (children?.length) {
|
|
36494
|
+
return children.every((child) => crossfadeIncomingMayFadeIn(child));
|
|
36495
|
+
}
|
|
36154
36496
|
if (!hasShapeProperties(element)) {
|
|
36155
36497
|
return true;
|
|
36156
36498
|
}
|
|
@@ -36245,15 +36587,19 @@ function generateMorphAnimations(pairs, durationMs, _mode = 'object', ghostIds)
|
|
|
36245
36587
|
const crossfadesIn = !inert &&
|
|
36246
36588
|
morphPairNeedsCrossfade(fromElement, toElement) &&
|
|
36247
36589
|
crossfadeIncomingMayFadeIn(toElement);
|
|
36248
|
-
// Build from/to property blocks
|
|
36590
|
+
// Build from/to property blocks. A half that dissolves IN keeps its opacity
|
|
36591
|
+
// out of this block and rides a second animation, so the journey and the
|
|
36592
|
+
// dissolve can follow their own measured curves (see the ghost half).
|
|
36249
36593
|
const fromProps = [
|
|
36250
36594
|
`\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${fromRot}deg)${flips};`,
|
|
36251
|
-
`\t\topacity: ${inert ? 0 : crossfadesIn ? 0 : fromOpacity};`,
|
|
36252
36595
|
];
|
|
36253
36596
|
const toProps = [
|
|
36254
36597
|
`\t\ttransform: translate(0, 0) scale(1, 1) rotate(${toRot}deg)${flips};`,
|
|
36255
|
-
`\t\topacity: ${inert ? 0 : toOpacity};`,
|
|
36256
36598
|
];
|
|
36599
|
+
if (!crossfadesIn) {
|
|
36600
|
+
fromProps.push(`\t\topacity: ${inert ? 0 : fromOpacity};`);
|
|
36601
|
+
toProps.push(`\t\topacity: ${inert ? 0 : toOpacity};`);
|
|
36602
|
+
}
|
|
36257
36603
|
// Fill color interpolation
|
|
36258
36604
|
const colorInterp = buildColorInterpolationProps(fromElement, toElement);
|
|
36259
36605
|
if (colorInterp) {
|
|
@@ -36274,10 +36620,20 @@ ${fromProps.join('\n')}
|
|
|
36274
36620
|
\tto {
|
|
36275
36621
|
${toProps.join('\n')}
|
|
36276
36622
|
\t}
|
|
36277
|
-
}
|
|
36623
|
+
}${crossfadesIn
|
|
36624
|
+
? `
|
|
36625
|
+
@keyframes ${safeName}-fade {
|
|
36626
|
+
\tfrom {
|
|
36627
|
+
\t\topacity: 0;
|
|
36628
|
+
\t}
|
|
36629
|
+
\tto {
|
|
36630
|
+
\t\topacity: ${toOpacity};
|
|
36631
|
+
\t}
|
|
36632
|
+
}`
|
|
36633
|
+
: ''}`;
|
|
36278
36634
|
animations.push({
|
|
36279
36635
|
elementId: toElement.id,
|
|
36280
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
36636
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards${crossfadesIn ? `, ${safeName}-fade ${durationMs}ms ${MORPH_CROSSFADE_EASING} forwards` : ''}`,
|
|
36281
36637
|
keyframes,
|
|
36282
36638
|
});
|
|
36283
36639
|
}
|
|
@@ -36332,22 +36688,36 @@ function generateMorphGhostAnimations(pairs, durationMs, startIndex, ghostIds) {
|
|
|
36332
36688
|
const fromRot = fromElement.rotation ?? 0;
|
|
36333
36689
|
const toRot = shortestRotationTarget(fromRot, toElement.rotation ?? 0);
|
|
36334
36690
|
const flips = `${fromElement.flipHorizontal ? ' scaleX(-1)' : ''}${fromElement.flipVertical ? ' scaleY(-1)' : ''}`;
|
|
36691
|
+
// A dissolve and a journey are two different curves, so when the ghost does
|
|
36692
|
+
// both they ride two animations: the transform keeps {@link MORPH_EASING},
|
|
36693
|
+
// which its live counterpart also travels on (a single easing for both
|
|
36694
|
+
// halves is what keeps them on the same path), and the opacity gets the
|
|
36695
|
+
// measured {@link MORPH_CROSSFADE_EASING}.
|
|
36696
|
+
const opacity = fromElement.opacity ?? 1;
|
|
36335
36697
|
const keyframes = `
|
|
36336
36698
|
@keyframes ${safeName} {
|
|
36337
36699
|
\tfrom {
|
|
36338
36700
|
\t\ttransform-origin: center;
|
|
36339
|
-
\t\ttransform: translate(0, 0) scale(1, 1) rotate(${fromRot}deg)${flips}
|
|
36340
|
-
\t\topacity: ${fromElement.opacity ?? 1};
|
|
36701
|
+
\t\ttransform: translate(0, 0) scale(1, 1) rotate(${fromRot}deg)${flips};${fadesOut ? '' : `\n\t\topacity: ${opacity};`}
|
|
36341
36702
|
\t}
|
|
36342
36703
|
\tto {
|
|
36343
36704
|
\t\ttransform-origin: center;
|
|
36344
|
-
\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${toRot}deg)${flips}
|
|
36345
|
-
\t\topacity: ${fadesOut ? 0 : (fromElement.opacity ?? 1)};
|
|
36705
|
+
\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${toRot}deg)${flips};${fadesOut ? '' : `\n\t\topacity: ${opacity};`}
|
|
36346
36706
|
\t}
|
|
36347
|
-
}
|
|
36707
|
+
}${fadesOut
|
|
36708
|
+
? `
|
|
36709
|
+
@keyframes ${safeName}-fade {
|
|
36710
|
+
\tfrom {
|
|
36711
|
+
\t\topacity: ${opacity};
|
|
36712
|
+
\t}
|
|
36713
|
+
\tto {
|
|
36714
|
+
\t\topacity: 0;
|
|
36715
|
+
\t}
|
|
36716
|
+
}`
|
|
36717
|
+
: ''}`;
|
|
36348
36718
|
animations.push({
|
|
36349
36719
|
elementId: fromElement.id,
|
|
36350
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
36720
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards${fadesOut ? `, ${safeName}-fade ${durationMs}ms ${MORPH_CROSSFADE_EASING} forwards` : ''}`,
|
|
36351
36721
|
keyframes,
|
|
36352
36722
|
});
|
|
36353
36723
|
}
|
|
@@ -36576,6 +36946,21 @@ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = 'obj
|
|
|
36576
36946
|
return allAnimations;
|
|
36577
36947
|
}
|
|
36578
36948
|
|
|
36949
|
+
/**
|
|
36950
|
+
* Keyframes for an incoming shape whose dissolve has been lifted into the
|
|
36951
|
+
* overlay: the copy left on the live stage holds at nothing for the whole
|
|
36952
|
+
* morph, so the two copies never composite with each other.
|
|
36953
|
+
*/
|
|
36954
|
+
const LIFTED_HIDDEN_NAME = 'pptx-morph-lifted-hidden';
|
|
36955
|
+
const LIFTED_HIDDEN_KEYFRAMES = `
|
|
36956
|
+
@keyframes ${LIFTED_HIDDEN_NAME} {
|
|
36957
|
+
\tfrom {
|
|
36958
|
+
\t\topacity: 0;
|
|
36959
|
+
\t}
|
|
36960
|
+
\tto {
|
|
36961
|
+
\t\topacity: 0;
|
|
36962
|
+
\t}
|
|
36963
|
+
}`;
|
|
36579
36964
|
/** Map a parsed `<p159:morph @option>` onto the engine's granularity mode. */
|
|
36580
36965
|
function morphOptionToMode(option) {
|
|
36581
36966
|
if (option === 'byWord') {
|
|
@@ -36657,13 +37042,45 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = 'object
|
|
|
36657
37042
|
// the overlay came down). Deriving the list from the animations keeps this
|
|
36658
37043
|
// decision in one place, `resolveMorphGhostIds`.
|
|
36659
37044
|
const outgoingElements = flattenedOutgoing.filter((element) => outgoingAnimations.has(element.id));
|
|
37045
|
+
// Everything the overlay paints hides whatever the live stage is doing
|
|
37046
|
+
// underneath, which is wrong for a shape that ARRIVES on top of a ghost:
|
|
37047
|
+
// it dissolves in where nobody can see it and appears in one frame when the
|
|
37048
|
+
// overlay is torn down (issue #146 - the wheel's centre disc is unchanged,
|
|
37049
|
+
// so its opaque ghost sat over the new title, body and button for the whole
|
|
37050
|
+
// morph). Those few move up into the overlay, above the ghosts, and the
|
|
37051
|
+
// copy on the stage is held invisible so the two never composite.
|
|
37052
|
+
//
|
|
37053
|
+
// Only a ghost that KEEPS its opacity counts. One that dissolves is out of
|
|
37054
|
+
// the way inside the first quarter, long before an arrival begins to appear,
|
|
37055
|
+
// so it hides nothing worth moving an animation for.
|
|
37056
|
+
const flattenedIncoming = flattenMorphElements(toSlide.elements, fromSlide.elements);
|
|
37057
|
+
const holdingGhostIds = new Set(match.pairs
|
|
37058
|
+
.filter((candidate) => outgoingAnimations.has(candidate.fromElement.id) &&
|
|
37059
|
+
!morphPairNeedsCrossfade(candidate.fromElement, candidate.toElement))
|
|
37060
|
+
.map((candidate) => candidate.fromElement.id));
|
|
37061
|
+
const lifted = resolveMorphOverlayArrivals(flattenedOutgoing, flattenedIncoming, match.pairs, holdingGhostIds);
|
|
37062
|
+
const overlayIncomingAnimations = new Map();
|
|
37063
|
+
for (const id of lifted) {
|
|
37064
|
+
const animation = incomingAnimations.get(id);
|
|
37065
|
+
if (animation === undefined) {
|
|
37066
|
+
continue;
|
|
37067
|
+
}
|
|
37068
|
+
overlayIncomingAnimations.set(id, animation);
|
|
37069
|
+
incomingAnimations.set(id, `${LIFTED_HIDDEN_NAME} ${durationMs}ms linear forwards`);
|
|
37070
|
+
}
|
|
37071
|
+
if (overlayIncomingAnimations.size > 0) {
|
|
37072
|
+
keyframes.push(LIFTED_HIDDEN_KEYFRAMES);
|
|
37073
|
+
}
|
|
37074
|
+
const overlayIncomingElements = flattenedIncoming.filter((element) => overlayIncomingAnimations.has(element.id));
|
|
36660
37075
|
return {
|
|
36661
37076
|
keyframesCss: keyframes.join('\n'),
|
|
36662
37077
|
incomingAnimations,
|
|
36663
37078
|
outgoingAnimations,
|
|
36664
37079
|
incomingImageAnimations,
|
|
36665
37080
|
outgoingImageAnimations,
|
|
37081
|
+
overlayIncomingAnimations,
|
|
36666
37082
|
outgoingElements,
|
|
37083
|
+
overlayIncomingElements,
|
|
36667
37084
|
durationMs,
|
|
36668
37085
|
};
|
|
36669
37086
|
}
|
|
@@ -36688,6 +37105,9 @@ function cssAttributeValue(value) {
|
|
|
36688
37105
|
* are unique to the slide being animated and need no ancestor to disambiguate.
|
|
36689
37106
|
* That is what lets a binding whose incoming slide is rendered OUTSIDE the
|
|
36690
37107
|
* overlay (Angular, React) still drive it from here.
|
|
37108
|
+
* @param which - Which half to emit: the live stage's `incoming` elements, the
|
|
37109
|
+
* overlay's `outgoing` ghosts, or the `lifted` copies the overlay paints over
|
|
37110
|
+
* those ghosts (see {@link MorphTransitionPlan.overlayIncomingElements}).
|
|
36691
37111
|
* @returns Keyframes plus the scoped `animation` rules, ready to inject.
|
|
36692
37112
|
*/
|
|
36693
37113
|
function buildMorphScopedCss(plan, scopeAttribute, which = 'incoming') {
|
|
@@ -36716,12 +37136,19 @@ function buildMorphAnimationRules(plan, scopeAttribute, which = 'incoming', only
|
|
|
36716
37136
|
rules.push(`${prefix}[data-element-id="${cssAttributeValue(elementId)}"]${suffix} { animation: ${animation}; }`);
|
|
36717
37137
|
}
|
|
36718
37138
|
};
|
|
37139
|
+
// `lifted` is the incoming half painted in the overlay rather than on the
|
|
37140
|
+
// stage, so it shares the incoming img channel and differs only in which
|
|
37141
|
+
// container animation it carries.
|
|
36719
37142
|
if (only !== 'image') {
|
|
36720
|
-
emit(which === '
|
|
37143
|
+
emit(which === 'outgoing'
|
|
37144
|
+
? plan.outgoingAnimations
|
|
37145
|
+
: which === 'lifted'
|
|
37146
|
+
? plan.overlayIncomingAnimations
|
|
37147
|
+
: plan.incomingAnimations, '');
|
|
36721
37148
|
}
|
|
36722
37149
|
// The picture-crop channel targets the `<img>` the element renders, which
|
|
36723
37150
|
// every binding draws inside the `data-element-id` container.
|
|
36724
|
-
emit(which === '
|
|
37151
|
+
emit(which === 'outgoing' ? plan.outgoingImageAnimations : plan.incomingImageAnimations, ' img');
|
|
36725
37152
|
return rules.join('\n');
|
|
36726
37153
|
}
|
|
36727
37154
|
|
|
@@ -64394,7 +64821,7 @@ function createLocalStorageBackend(namespace) {
|
|
|
64394
64821
|
/** Try IndexedDB first; fall back to localStorage on any failure. */
|
|
64395
64822
|
async function resolveBackend(dbName, namespace) {
|
|
64396
64823
|
try {
|
|
64397
|
-
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-
|
|
64824
|
+
const { openChatDb, createIdbBackend } = await import('./pptx-angular-viewer-chat-history-idb-BF1I9H0D.mjs');
|
|
64398
64825
|
const db = await openChatDb(dbName);
|
|
64399
64826
|
return createIdbBackend(db);
|
|
64400
64827
|
}
|
|
@@ -78772,8 +79199,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
78772
79199
|
* `sz` overrides the (already scaled) body font-size, so without it a
|
|
78773
79200
|
* shrink-to-fit title painted at full size.
|
|
78774
79201
|
*/
|
|
78775
|
-
function runStyleFromSegment(seg, fontScale = 1) {
|
|
78776
|
-
const style = segmentStyleToCss(seg, fontScale);
|
|
79202
|
+
function runStyleFromSegment(seg, fontScale = 1, blockFont, text) {
|
|
79203
|
+
const style = segmentStyleToCss(seg, fontScale, { text, blockFont });
|
|
78777
79204
|
const s = seg.style;
|
|
78778
79205
|
if (s) {
|
|
78779
79206
|
const isDoubleStrike = Boolean(s.strikethrough && s.strikeType === 'dblStrike');
|
|
@@ -79102,6 +79529,15 @@ class ElementRendererComponent {
|
|
|
79102
79529
|
// run's own `sz` overrides the (already scaled) body font-size. Mirrors
|
|
79103
79530
|
// shared `buildParagraphs` and React's `renderSingleSegment`.
|
|
79104
79531
|
const fontScale = resolveAutoFitFontScale(el.textStyle);
|
|
79532
|
+
// What a run that declares no font of its own inherits from the text body,
|
|
79533
|
+
// used only to measure it for the PowerPoint metric tracking. Mirrors
|
|
79534
|
+
// shared `buildParagraphs`.
|
|
79535
|
+
const blockFont = {
|
|
79536
|
+
fontFamily: el.textStyle?.fontFamily
|
|
79537
|
+
? getSubstituteFontFamily(el.textStyle.fontFamily)
|
|
79538
|
+
: DEFAULT_FONT_FAMILY$1,
|
|
79539
|
+
fontSizePx: (el.textStyle?.fontSize || DEFAULT_TEXT_FONT_SIZE) * fontScale,
|
|
79540
|
+
};
|
|
79105
79541
|
const paragraphIndents = el.paragraphIndents;
|
|
79106
79542
|
const out = [{ runs: [], bulletStyle: {}, indentPx: 0 }];
|
|
79107
79543
|
let paraStarted = false;
|
|
@@ -79220,12 +79656,20 @@ class ElementRendererComponent {
|
|
|
79220
79656
|
: rawText;
|
|
79221
79657
|
if (text) {
|
|
79222
79658
|
const href = resolveHyperlinkHref(seg.style?.hyperlink);
|
|
79223
|
-
|
|
79224
|
-
|
|
79225
|
-
|
|
79226
|
-
|
|
79227
|
-
|
|
79228
|
-
|
|
79659
|
+
const style = runStyleFromSegment(seg, fontScale, blockFont, text);
|
|
79660
|
+
// One run per word (and per gap), each carrying its own PowerPoint
|
|
79661
|
+
// metric tracking, so a LINE measures what PowerPoint measured and
|
|
79662
|
+
// breaks where PowerPoint breaks (#149). Shared decides the split;
|
|
79663
|
+
// this builder is hand-ported from `buildParagraphs` and would
|
|
79664
|
+
// otherwise silently keep the old whole-run behaviour.
|
|
79665
|
+
for (const piece of splitStyledRun(text, style, resolveRunFont(style, seg.style ?? {}, blockFont), authoredLetterSpacingPx(seg.style))) {
|
|
79666
|
+
current.runs.push({
|
|
79667
|
+
text: piece.text,
|
|
79668
|
+
style: piece.style,
|
|
79669
|
+
href,
|
|
79670
|
+
tooltip: href ? seg.style?.hyperlinkTooltip : undefined,
|
|
79671
|
+
});
|
|
79672
|
+
}
|
|
79229
79673
|
}
|
|
79230
79674
|
}
|
|
79231
79675
|
// A paragraph that already matches the body default needs no re-basing.
|
|
@@ -89196,6 +89640,25 @@ function ensureTransitionKeyframes() {
|
|
|
89196
89640
|
|
|
89197
89641
|
/** Safety margin (ms) added to the animation duration before firing complete. */
|
|
89198
89642
|
const COMPLETE_MARGIN_MS = 50;
|
|
89643
|
+
/**
|
|
89644
|
+
* The slide the overlay paints ABOVE its ghosts, or `undefined` when a morph
|
|
89645
|
+
* has nothing to lift.
|
|
89646
|
+
*
|
|
89647
|
+
* A shape arriving inside a shape that persists is drawn on the live stage,
|
|
89648
|
+
* UNDER this overlay, so the persisting shape's opaque ghost hides it for the
|
|
89649
|
+
* whole transition (issue #146). `buildMorphTransitionPlan` names those few and
|
|
89650
|
+
* holds their stage copy invisible; this wraps them as a slide the component's
|
|
89651
|
+
* own `pptx-slide-canvas` can render.
|
|
89652
|
+
*
|
|
89653
|
+
* Exported and pure so it can be unit-tested: this package renders no component
|
|
89654
|
+
* under test (see `action-settings-panel.component.test.ts`).
|
|
89655
|
+
*/
|
|
89656
|
+
function morphLiftedSlide(plan, incomingSlide) {
|
|
89657
|
+
if (!plan || !incomingSlide || plan.overlayIncomingElements.length === 0) {
|
|
89658
|
+
return undefined;
|
|
89659
|
+
}
|
|
89660
|
+
return { ...incomingSlide, elements: [...plan.overlayIncomingElements] };
|
|
89661
|
+
}
|
|
89199
89662
|
/**
|
|
89200
89663
|
* PresentationTransitionOverlayComponent: plays a PowerPoint slide transition
|
|
89201
89664
|
* over the presentation stage.
|
|
@@ -89291,6 +89754,9 @@ class PresentationTransitionOverlayComponent {
|
|
|
89291
89754
|
? [
|
|
89292
89755
|
buildMorphScopedCss(plan, '', 'incoming'),
|
|
89293
89756
|
buildMorphScopedCss(plan, 'data-pptx-morph-outgoing', 'outgoing'),
|
|
89757
|
+
// Scoped, so it outranks the unscoped `incoming` rule that holds
|
|
89758
|
+
// the stage's copy of the same element invisible.
|
|
89759
|
+
buildMorphScopedCss(plan, 'data-pptx-morph-lifted', 'lifted'),
|
|
89294
89760
|
].join('\n')
|
|
89295
89761
|
: null);
|
|
89296
89762
|
});
|
|
@@ -89379,6 +89845,14 @@ class PresentationTransitionOverlayComponent {
|
|
|
89379
89845
|
return { ...slide, elements: [...template, ...slide.elements] };
|
|
89380
89846
|
}, /* @ts-ignore */
|
|
89381
89847
|
...(ngDevMode ? [{ debugName: "layerSlide" }] : /* istanbul ignore next */ []));
|
|
89848
|
+
/**
|
|
89849
|
+
* The arriving shapes the morph has to paint over its own ghosts, or
|
|
89850
|
+
* `undefined` when there are none (issue #146). They sit on the live stage
|
|
89851
|
+
* below this overlay, where the departing layer would hide them for the whole
|
|
89852
|
+
* transition; the plan holds that copy invisible and hands them here instead.
|
|
89853
|
+
*/
|
|
89854
|
+
liftedSlide = computed(() => morphLiftedSlide(this.morphPlan(), this.incomingSlide()), /* @ts-ignore */
|
|
89855
|
+
...(ngDevMode ? [{ debugName: "liftedSlide" }] : /* istanbul ignore next */ []));
|
|
89382
89856
|
/** Layer container style: animation + stacking relative to the stage. */
|
|
89383
89857
|
layerStyle = computed(() => {
|
|
89384
89858
|
const anims = this.animations();
|
|
@@ -89451,7 +89925,7 @@ class PresentationTransitionOverlayComponent {
|
|
|
89451
89925
|
}
|
|
89452
89926
|
}
|
|
89453
89927
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PresentationTransitionOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
89454
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.
|
|
89928
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.0", type: PresentationTransitionOverlayComponent, isStandalone: true, selector: "pptx-presentation-transition-overlay", inputs: { outgoingSlide: { classPropertyName: "outgoingSlide", publicName: "outgoingSlide", isSignal: true, isRequired: true, transformFunction: null }, canvasSize: { classPropertyName: "canvasSize", publicName: "canvasSize", isSignal: true, isRequired: true, transformFunction: null }, transition: { classPropertyName: "transition", publicName: "transition", isSignal: true, isRequired: true, transformFunction: null }, templateElements: { classPropertyName: "templateElements", publicName: "templateElements", isSignal: true, isRequired: false, transformFunction: null }, mediaDataUrls: { classPropertyName: "mediaDataUrls", publicName: "mediaDataUrls", isSignal: true, isRequired: false, transformFunction: null }, durationMs: { classPropertyName: "durationMs", publicName: "durationMs", isSignal: true, isRequired: false, transformFunction: null }, zoom: { classPropertyName: "zoom", publicName: "zoom", isSignal: true, isRequired: false, transformFunction: null }, incomingSlide: { classPropertyName: "incomingSlide", publicName: "incomingSlide", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { complete: "complete" }, host: { attributes: { "data-pptx-transition-overlay": "" } }, ngImport: i0, template: `
|
|
89455
89929
|
<div
|
|
89456
89930
|
class="pptx-ng-transition-layer"
|
|
89457
89931
|
data-pptx-transition-layer="outgoing"
|
|
@@ -89470,6 +89944,30 @@ class PresentationTransitionOverlayComponent {
|
|
|
89470
89944
|
/>
|
|
89471
89945
|
</div>
|
|
89472
89946
|
</div>
|
|
89947
|
+
|
|
89948
|
+
<!-- The arriving shapes that dissolve in ABOVE a departing one. They are on
|
|
89949
|
+
the live stage below this overlay, where the departing layer hides them
|
|
89950
|
+
for the whole morph, so they are painted again here. -->
|
|
89951
|
+
@if (liftedSlide(); as lifted) {
|
|
89952
|
+
<div
|
|
89953
|
+
class="pptx-ng-transition-layer"
|
|
89954
|
+
data-pptx-transition-layer="lifted"
|
|
89955
|
+
data-pptx-morph-lifted="true"
|
|
89956
|
+
[ngStyle]="{ 'z-index': '41' }"
|
|
89957
|
+
>
|
|
89958
|
+
<div [ngStyle]="slideBoxStyle()">
|
|
89959
|
+
<pptx-slide-canvas
|
|
89960
|
+
[slide]="lifted"
|
|
89961
|
+
[canvasSize]="canvasSize()"
|
|
89962
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
89963
|
+
[zoom]="zoom()"
|
|
89964
|
+
[autoFit]="false"
|
|
89965
|
+
[interactive]="false"
|
|
89966
|
+
[transparentBackground]="true"
|
|
89967
|
+
/>
|
|
89968
|
+
</div>
|
|
89969
|
+
</div>
|
|
89970
|
+
}
|
|
89473
89971
|
`, isInline: true, styles: [":host{display:block;position:absolute;inset:0;overflow:hidden;pointer-events:none}.pptx-ng-transition-layer{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: SlideCanvasComponent, selector: "pptx-slide-canvas", inputs: ["slide", "canvasSize", "mediaDataUrls", "zoom", "editable", "showGrid", "showRulers", "rulerUnit", "showGuides", "snapToGrid", "snapToShape", "guideCommand", "spellCheck", "snapToGuides", "autoFit", "transparentBackground", "interactive", "presenting", "selectedIds", "editingId", "editTemplateMode", "templateElements", "aiHighlights", "aiActive", "aiActiveSlideIndex", "aiChangeBatch", "aiPickMode", "drawTool", "drawColor", "drawWidth"], outputs: ["elementSelect", "backgroundClick", "transformStart", "transformUpdate", "contextMenu", "textEditStart", "textCommit", "textInput", "textCancel", "textFormat", "rotateUpdate", "marqueeSelect", "inkStrokeComplete", "eraserHit", "cellCommit", "tableChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
89474
89972
|
}
|
|
89475
89973
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PresentationTransitionOverlayComponent, decorators: [{
|
|
@@ -89493,6 +89991,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
89493
89991
|
/>
|
|
89494
89992
|
</div>
|
|
89495
89993
|
</div>
|
|
89994
|
+
|
|
89995
|
+
<!-- The arriving shapes that dissolve in ABOVE a departing one. They are on
|
|
89996
|
+
the live stage below this overlay, where the departing layer hides them
|
|
89997
|
+
for the whole morph, so they are painted again here. -->
|
|
89998
|
+
@if (liftedSlide(); as lifted) {
|
|
89999
|
+
<div
|
|
90000
|
+
class="pptx-ng-transition-layer"
|
|
90001
|
+
data-pptx-transition-layer="lifted"
|
|
90002
|
+
data-pptx-morph-lifted="true"
|
|
90003
|
+
[ngStyle]="{ 'z-index': '41' }"
|
|
90004
|
+
>
|
|
90005
|
+
<div [ngStyle]="slideBoxStyle()">
|
|
90006
|
+
<pptx-slide-canvas
|
|
90007
|
+
[slide]="lifted"
|
|
90008
|
+
[canvasSize]="canvasSize()"
|
|
90009
|
+
[mediaDataUrls]="mediaDataUrls()"
|
|
90010
|
+
[zoom]="zoom()"
|
|
90011
|
+
[autoFit]="false"
|
|
90012
|
+
[interactive]="false"
|
|
90013
|
+
[transparentBackground]="true"
|
|
90014
|
+
/>
|
|
90015
|
+
</div>
|
|
90016
|
+
</div>
|
|
90017
|
+
}
|
|
89496
90018
|
`, styles: [":host{display:block;position:absolute;inset:0;overflow:hidden;pointer-events:none}.pptx-ng-transition-layer{position:absolute;inset:0;display:flex;align-items:center;justify-content:center}\n"] }]
|
|
89497
90019
|
}], ctorParameters: () => [], propDecorators: { outgoingSlide: [{ type: i0.Input, args: [{ isSignal: true, alias: "outgoingSlide", required: true }] }], canvasSize: [{ type: i0.Input, args: [{ isSignal: true, alias: "canvasSize", required: true }] }], transition: [{ type: i0.Input, args: [{ isSignal: true, alias: "transition", required: true }] }], templateElements: [{ type: i0.Input, args: [{ isSignal: true, alias: "templateElements", required: false }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], durationMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "durationMs", required: false }] }], zoom: [{ type: i0.Input, args: [{ isSignal: true, alias: "zoom", required: false }] }], incomingSlide: [{ type: i0.Input, args: [{ isSignal: true, alias: "incomingSlide", required: false }] }], complete: [{ type: i0.Output, args: ["complete"] }] } });
|
|
89498
90020
|
|
|
@@ -96055,7 +96577,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
96055
96577
|
}], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
|
|
96056
96578
|
|
|
96057
96579
|
// Generated by scripts/inline-shared.mjs from package.json. Do not edit.
|
|
96058
|
-
const PPTX_ANGULAR_VIEWER_VERSION = "2.17.
|
|
96580
|
+
const PPTX_ANGULAR_VIEWER_VERSION = "2.17.1";
|
|
96059
96581
|
|
|
96060
96582
|
/**
|
|
96061
96583
|
* account-page.component.ts: File > Account content.
|
|
@@ -127993,4 +128515,4 @@ function cn(...values) {
|
|
|
127993
128515
|
*/
|
|
127994
128516
|
|
|
127995
128517
|
export { CommentsService as $, ALIGN_OPTIONS as A, AnimationPlaybackService as B, AutosaveService as C, BroadcastDialogComponent as D, CHART_EDITOR_STYLES as E, CURSOR_PALETTE as F, CanvasFitService as G, ChartAxisOptionsComponent as H, ChartAxisStyleOptionsComponent as I, ChartComboTypeOptionsComponent as J, ChartDataEditorComponent as K, ChartDataLabelOptionsComponent as L, ChartDatapointMarkerOptionsComponent as M, ChartDatapointOptionsComponent as N, ChartDisplayOptionsComponent as O, ChartElementViewComponent as P, ChartErrorBarOptionsComponent as Q, ChartMarkerOptionsComponent as R, ChartPartSelectionService as S, ChartPrimitivesComponent as T, ChartRendererComponent as U, ChartTrendlineOptionsComponent as V, CollaborationCursorsComponent as W, CollaborationService as X, ColorChangedImageComponent as Y, CommentMarkersOverlayComponent as Z, CommentsPanelComponent as _, ANIMATION_PRESET_CATEGORIES as a, IsMobileService as a$, ComparePanelComponent as a0, ConnectorRendererComponent as a1, ConnectorTextOverlayComponent as a2, CustomShowsComponent as a3, DATA_TABLE_HEADER_H as a4, DATA_TABLE_KEY_W as a5, DATA_TABLE_PADDING as a6, DATA_TABLE_ROW_H as a7, DEFAULT_BOUNDS as a8, DEFAULT_BROADCAST_SERVER_URL as a9, EffectsPanelComponent as aA, ElementRendererComponent as aB, EmbeddedFontsService as aC, EncryptedFileDialogComponent as aD, EquationEditorDialogComponent as aE, EquationRendererComponent as aF, EquationTemplateGalleryComponent as aG, ExportProgressModalComponent as aH, ExportService as aI, FieldContextService as aJ, FindBarComponent as aK, FindReplaceBarComponent as aL, FollowModeBarComponent as aM, FontEmbeddingListComponent as aN, FontEmbeddingPanelComponent as aO, GALLERY_THEME_PRESETS as aP, GRIDLINE_COLOR as aQ, GradientPickerComponent as aR, HANDOUT_OPTIONS as aS, HeaderFooterDialogComponent as aT, HyperlinkDialogComponent as aU, ImagePropertiesPanelComponent as aV, InkDrawingService as aW, InkRendererComponent as aX, InsertSmartArtDialogComponent as aY, InspectorPaneHeaderComponent as aZ, InspectorPanelComponent as a_, DEFAULT_CANVAS_HEIGHT as aa, DEFAULT_CANVAS_WIDTH as ab, DEFAULT_COLOR_SCHEME as ac, DEFAULT_FILL_COLOR as ad, DEFAULT_LAYOUT as ae, DEFAULT_PALETTE$1 as af, DEFAULT_PATTERN_FILL_PRESET as ag, DEFAULT_PRINT_SETTINGS as ah, DEFAULT_SLIDE_BACKGROUND as ai, DEFAULT_STROKE_COLOR as aj, DEFAULT_STYLE as ak, DEFAULT_TABLE_ROW_HEIGHT as al, DEFAULT_TEXT_COLOR$1 as am, DEFAULT_VIEWER_PROFILE as an, DIRECTIONAL_PRESETS as ao, DIRECTION_OPTIONS as ap, DocumentPropertiesCardComponent as aq, EMBEDDED_FONTS_STYLE_ID as ar, EMPHASIS_PRESETS as as, ENTRANCE_PRESETS as at, TEMPLATES as au, EXIT_PRESETS as av, EditorContextMenuComponent as aw, EditorHistory as ax, EditorStateService as ay, EditorToolbarComponent as az, AUDIENCE_HASH as b, RibbonDrawingGroupComponent as b$, KeepAnnotationsDialogComponent as b0, LOCALE_CATALOG as b1, LONG_PRESS_DURATION_MS as b2, LONG_PRESS_MOVE_TOLERANCE_PX as b3, LoadContentService as b4, LocalPresencePublisher as b5, MAX_ZOOM_SCALE as b6, MIN_ZOOM_SCALE as b7, MOTION_PATH_COLUMNS as b8, MediaPreviewComponent as b9, PresentationAnnotationOverlayComponent as bA, PresentationAnnotationsService as bB, PresentationOverlayComponent as bC, PresentationPropertiesPanelComponent as bD, PresentationSettingsCardComponent as bE, PresentationSubtitleBarComponent as bF, PresentationToolbarComponent as bG, PresentationTransitionOverlayComponent as bH, PresenterViewComponent as bI, PresenterWindowService as bJ, PrintDialogComponent as bK, PrintService as bL, PrintSettingsPanelComponent as bM, PropertiesDialogComponent as bN, REPEAT_MODE_OPTIONS as bO, RESIZE_HANDLES as bP, RULER_FONT_SIZE as bQ, RULER_THICKNESS as bR, ReadingViewOverlayComponent as bS, RemoteSelectionOverlayComponent as bT, RibbonAnimationGalleryComponent as bU, RibbonAnimationsSectionComponent as bV, RibbonArrangeSectionComponent as bW, RibbonColorPopoverComponent as bX, RibbonComponent as bY, RibbonDesignSectionComponent as bZ, RibbonDrawSectionComponent as b_, MediaPropertiesPanelComponent as ba, MediaRendererComponent as bb, MediaTrimTimelineComponent as bc, MobileBottomBarComponent as bd, MobileMenuSheetComponent as be, MobilePresenterViewComponent as bf, MobileSheetComponent as bg, MobileSlidesSheetComponent as bh, MobileToolbarComponent as bi, ModalDialogComponent as bj, Model3DRendererComponent as bk, NotesHandoutCardComponent as bl, NotesPanelComponent as bm, NotesToolbarComponent as bn, OleRendererComponent as bo, OutlineViewOverlayComponent as bp, POWER_POINT_VIEWER_PROVIDERS as bq, PRESENTER_CHANNEL_NAME as br, PRESENTER_MSG_ORIGIN as bs, PRESENTER_TIMER_SEGMENT_MS as bt, PX_PER_CM as bu, PX_PER_INCH as bv, PasswordProtectionDialogComponent as bw, PasswordStrengthMeterComponent as bx, PowerPointViewerComponent as by, PresentToolbarAutoHide as bz, AUDIENCE_NONCE_KEY as c, TIMING_CURVE_OPTIONS as c$, RibbonEditingSectionComponent as c0, RibbonFileSectionComponent as c1, RibbonFontControlsComponent as c2, RibbonHomeSectionComponent as c3, RibbonHyperlinkButtonComponent as c4, RibbonInsertFieldsComponent as c5, RibbonInsertSectionComponent as c6, RibbonMotionPathGalleryComponent as c7, RibbonParagraphControlsComponent as c8, RibbonPrimaryRowComponent as c9, ShowOptionsFieldsetComponent as cA, ShowSlidesFieldsetComponent as cB, SignatureStrippedDialogComponent as cC, SignaturesPanelComponent as cD, SignaturesService as cE, SlideBackgroundCardComponent as cF, SlideCanvasComponent as cG, SlideDefaultInspectorComponent as cH, SlideDiffChangesComponent as cI, SlideDiffRowComponent as cJ, SlideDiffThumbnailsComponent as cK, SlideSizeCardComponent as cL, SlideSorterOverlayComponent as cM, SlideThemeOverridePanelComponent as cN, SlideTransitionCardComponent as cO, SlidesPanelComponent as cP, SmartArt3DRendererComponent as cQ, SmartArt3DService as cR, SmartArtPreviewComponent as cS, SmartArtPropertiesComponent as cT, SmartArtRendererComponent as cU, StatusBarComponent as cV, TABLE_STRUCTURE_TOGGLES as cW, TEXT_3D_BOTTOM_BEVEL_KEYS as cX, TEXT_3D_TOP_BEVEL_KEYS as cY, TEXT_DIRECTION_OPTIONS$1 as cZ, THEME_CATALOG as c_, RibbonReviewSectionComponent as ca, RibbonShapeExtrasComponent as cb, RibbonSlideshowSectionComponent as cc, RibbonTransitionsSectionComponent as cd, RibbonViewSectionComponent as ce, RulerGuidesService as cf, SEQUENCE_OPTIONS as cg, SEVERITY_GROUPS as ch, SEVERITY_LABELS as ci, SHORTCUT_REFERENCE_ITEMS as cj, SLIDE_TRANSITION_KEYFRAMES as ck, DEFAULT_PALETTE as cl, PALETTES$1 as cm, SMART_ART_COLOR_SCHEMES as cn, SMART_ART_STYLE_OPTIONS as co, SUB_ITEM_LABEL as cp, SVG_WARP_PRESETS as cq, SWIPE_MAX_VERTICAL_PX as cr, SWIPE_THRESHOLD_PX as cs, SelectionPaneComponent as ct, SetUpSlideShowDialogComponent as cu, SettingsAppearanceTabComponent as cv, SettingsDialogComponent as cw, SettingsLanguageTabComponent as cx, ShareDialogComponent as cy, ShortcutPanelComponent as cz, AVATAR_COLOR_SWATCHES as d, applyAnimationPreset as d$, TRIGGER_OPTIONS as d0, TYPE_LABELS as d1, TableCellAdvancedFillComponent as d2, TableCellFormattingComponent as d3, TableDataEditorComponent as d4, TablePropertiesComponent as d5, TableRendererComponent as d6, TableResizeOverlayComponent as d7, TableSelectionService as d8, TagsCardComponent as d9, ViewerInspectorPanelService as dA, ViewerKeyboardService as dB, ViewerMobileSheetService as dC, ViewerPresentationModeService as dD, ViewerThemeGalleryService as dE, ViewerTouchGesturesService as dF, ViewerZoomService as dG, WEBM_MIME_CANDIDATES as dH, WriteBackScheduler as dI, ZERO_LINE_COLOR as dJ, ZoomNavigationService as dK, ZoomRendererComponent as dL, ZoomTargetService as dM, addCategory as dN, addCommentToList as dO, addGradientStopPatch as dP, addItem as dQ, addSeries as dR, addSubItem as dS, advanceStep as dT, affordanceElements as dU, aiToggleVisible as dV, alignPatch as dW, animationFor as dX, animationPresetLabelKey as dY, annotationMapToInkInserts as dZ, applyAcceptedDiff as d_, Text3DBevelSectionComponent as da, Text3DPanelComponent as db, TextAdvancedPanelComponent as dc, ThemeEditorFieldsComponent as dd, ThemeGalleryComponent as de, ThemeSelectorCardComponent as df, TitleBarComponent as dg, TitleBarSearchComponent as dh, TransitionDirectionPickerComponent as di, TransitionPreviewComponent as dj, VALIGN_OPTIONS as dk, VIEWER_THEME as dl, VersionHistoryPanelComponent as dm, ViewerCanvasEditingService as dn, ViewerCollabCursorService as dp, ViewerCollaborationSessionService as dq, ViewerCompareService as dr, ViewerCustomShowsService as ds, ViewerDialogsService as dt, ViewerDocumentPropertiesService as du, ViewerExportService as dv, ViewerExtraDialogsComponent as dw, ViewerFileIOService as dx, ViewerFindReplaceService as dy, ViewerFormatPainterService as dz, AXIS_LABEL_COLOR as e, buildZoomViewModel as e$, applyFindReplacements as e0, applyFormatToElement as e1, applyMove as e2, applyResize as e3, applyTableStylePreset 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, buildModel3DContainerStyle as eH, buildModel3DViewModel as eI, buildOleActionModel as eJ, buildOleInfoRows as eK, buildPatternFillCss as eL, buildPrintHtmlDocument as eM, buildPropertiesPatch as eN, buildRegionMapViewModel as eO, buildSaveSlides as eP, buildShareUrl as eQ, buildSmartArtInsertElement as eR, buildSmartArtNodes as eS, buildStockViewModel as eT, buildSurfaceViewModel as eU, buildTableViewModel as eV, buildTreemapViewModel as eW, buildTrimFragment as eX, buildWaterfallViewModel as eY, buildZeroLine as eZ, buildZoomContainerStyle 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, AccessibilityPanelComponent as f, computeTextLines as f$, bulletIndentPx as f0, canAddTopLevelNode as f1, canGroupSelection as f2, canRemoveTopLevelNode as f3, canSetStrokeWidth as f4, canStartBroadcast as f5, canStartShare as f6, canUngroupSelection as f7, canUseClipboard as f8, captionDisplayText as f9, computeBubbleRadius as fA, computeCornerHandle as fB, computeDataTablePrimitives as fC, computeDistribute as fD, computeDrawingViewBox as fE, computeErrorBarPrimitives as fF, computeFocusTargets as fG, computeHandleBoxes as fH, computeHandoutLayout as fI, computeIsMobile as fJ, computeIsTablet as fK, computeLinePoints as fL, computeLinearRegression as fM, computePageCount as fN, computePieLayout as fO, computePieSlicePath as fP, computePieSlices as fQ, computePlotLayout as fR, computeRSquared as fS, computeRadarPoints as fT, computeScatterDots as fU, computeSelectionBoxes as fV, computeSingleSelected as fW, computeSlideIndices as fX, computeSnap as fY, computeStackedBarRects as fZ, computeStackedValueRange as f_, cellRunStyle as fa, cellStyleToStyleMap as fb, cellTdStyle as fc, changeCountLabel as fd, changeIcon as fe, characterSpacingPatch as ff, checkFontAvailable as fg, clampCursorPosition as fh, clampGifDimensions as fi, clampIndex as fj, clampNotesFontSize as fk, clampScale as fl, clampStep as fm, clearAllLocalViewerData as fn, clearAudienceContent as fo, cn as fp, collectAccessibilityIssues as fq, collectElementText as fr, collectSlideText as fs, collectStoredChats as ft, collectUsedFontFamilies as fu, columnWidthStyle as fv, commitNodeText as fw, computeAlign as fx, computeAxisTitlePrimitives as fy, computeBarRects as fz, AccessibilityService as g, formatPropertyDate as g$, computeTrendlinePrimitives as g0, computeValueRange as g1, convertOmmlToMathMl as g2, copyFormatFromElement as g3, countAccessibilityIssues as g4, countAnnotationStrokes as g5, createAngularAiBridge as g6, createCustomShow as g7, createSwipeDismissDrag as g8, createWebrtcBundle as g9, enableSoftEdgePatch as gA, encodeGif as gB, endShowMediaCleanup as gC, estimatePageCount as gD, evenColumnWidths as gE, evenRowHeights as gF, exitPresentationFullscreen as gG, exportAiChatLogs as gH, extractPathPoints as gI, eyedropperAvailable as gJ, fillColorOf as gK, findInSlides as gL, findOwningSlideIndex as gM, findSlideIndexByElementId as gN, firstVisibleIndex as gO, fitPolynomial as gP, fitZoom as gQ, focusTargetChips as gR, fontMimeForFormat as gS, fontSizeOf as gT, forgetSessionDeck as gU, formatAutoNumber as gV, formatAxisValue as gW, formatBytes as gX, formatCursorLabel as gY, formatElapsed as gZ, formatFileSize as g_, createWebsocketBundle as ga, cssObjectToStyleMap as gb, currentColorScheme as gc, currentLayout as gd, currentStyle as ge, defaultCssVars as gf, defaultRadius as gg, defaultThemeColors as gh, deleteElementsByIds as gi, deleteVersion as gj, demoteNode as gk, deriveModel3DBlobUrl as gl, derivePresenceList as gm, describeSmartArtBounds as gn, disableGlowPatch as go, disableInnerShadowPatch as gp, disableOuterShadowPatch as gq, disableReflectionPatch as gr, disableSoftEdgePatch as gs, duplicateElementById as gt, durationOf as gu, effectsStateOf as gv, enableGlowPatch as gw, enableInnerShadowPatch as gx, enableOuterShadowPatch as gy, enableReflectionPatch as gz, AccountPageComponent as h, isSigned as h$, formatTime as h0, fpsToFrameIntervalMs as h1, generateBroadcastRoomId as h2, generateCommentId as h3, generateCustomShowId as h4, generatePressureCircles as h5, generateTicks as h6, getClrChangeParams as h7, getContainerStyle as h8, getDuotoneFilterDef as h9, gradientStateOf as hA, gradientStatePatch as hB, gridColumns as hC, groupElements as hD, groupIssuesBySeverity as hE, hasAnimation as hF, hasCopyableFormat as hG, hasExistingLink as hH, hasExitedFullscreen as hI, hasGradientFill as hJ, hasPressureVariation as hK, hasVisibleSlideAfter as hL, headerLabel as hM, imageDimensions as hN, inkViewBox as hO, insertTableElementColumn as hP, insertTableElementRow as hQ, interpolateWidth as hR, isAudienceTab as hS, isBold as hT, isBrowserOpenableMime as hU, isChildNode as hV, isElementInteractive as hW, isInjectableUrl as hX, isItalic as hY, isPpactionUrl as hZ, isPresenterMessage as h_, getImageSrc as ha, getLocalStorageUsageSummary as hb, getOleAriaLabel as hc, getOleBadgeLabel as hd, getOleDisplayName as he, getOleDownloadFileName as hf, getOleTypeColor as hg, getOleTypeLabel as hh, getPasswordStrength as hi, getPatternSvg as hj, getPlaceholderStyle as hk, getVersions as hl, getResolvedShapeClipPath as hm, getResolvedShapeClipPathFor as hn, getSessionTabId as ho, getShapeFillStrokeStyle as hp, getSlideBackgroundStyle as hq, getSlideTransitionAnimations as hr, getSmartArtNodeBounds as hs, getSpeechRecognitionCtor as ht, getTextBlockStyle as hu, getTextWarp as hv, getTouchDistance as hw, getWarpCategory as hx, getWarpPath as hy, gradientStateFromStyle as hz, ActionSettingsPanelComponent as i, pendingElementStyles as i$, isTextElement as i0, isTwoTableFocus as i1, isUnderline as i2, isUrlSafe as i3, isValidRoomId as i4, isViewportBackgroundPressTarget as i5, isZoomActivationKey as i6, issueTrackKey as i7, issueTypeLabel as i8, keyToLabel as i9, newTableElement as iA, newTextElement as iB, nextVisibleIndex as iC, nodeBold as iD, nodeEditBox as iE, nodeFillColor as iF, nodeFontColor as iG, nodeIdFromKey as iH, nodeItalic as iI, nodeStyle as iJ, normalizeFontFormat as iK, normalizeSlidesPerPage as iL, normalizeValue as iM, numFromEvent as iN, ommlToMathml as iO, ooxmlDashToCssBorderStyle as iP, openNativeEyeDropper as iQ, overallStatus as iR, paletteColor as iS, parseAudienceNonce as iT, parseNodeTextarea as iU, partitionSlides as iV, patchChartData as iW, patchChartStyle as iX, patchTableData as iY, patchTextStyle as iZ, patternPresetOptions as i_, lastVisibleIndex as ia, latexToMathml as ib, linePointsToSvgString as ic, lineSpacingPatch as id, loadAudienceContent as ie, loadSessionDeck as ig, mediaFallbackFor as ih, mediaSurfaceFor as ii, mergeCaptionResults as ij, mergeDown as ik, mergeRight as il, mergeSelection as im, moveElementBy as io, moveNodeDown as ip, moveNodeUp as iq, msToFrameDelayCs as ir, narrowToCircle as is, narrowToPolygon as it, narrowToRect as iu, newChartElement as iv, newEquationElement as iw, newPresetShapeElement as ix, newShapeElement as iy, newSmartArtElement as iz, AdvancedChartEditorComponent as j, sanitizeSlideIndex as j$, pickColorByClickFallback as j0, pickFile as j1, pickSupportedMimeType as j2, planGifFrames as j3, planVideoSegments as j4, pointsToSvgPathD as j5, presenceToCursors as j6, presentationStageStyle as j7, presenterTimerProgress as j8, presetByLayout as j9, replaceMatch as jA, requestPresentationFullscreen as jB, resizeElement as jC, resolveCaptionTracks as jD, resolveChartKind as jE, resolveFontVariant as jF, resolveHyperlinkHref as jG, resolveInteractiveElementId as jH, resolveMediaSrc as jI, resolveOleType as jJ, resolveParagraphBullet as jK, resolvePresenterNotes as jL, resolveProfileInitial as jM, resolveRegionCode as jN, resolveSlideAutoAdvanceMs as jO, resolvePalette as jP, resolveThemeCatalogEntry as jQ, resolveTransitionDuration as jR, restoreSessionDeck as jS, revealedElementStyles as jT, routeOrthogonalConnector as jU, rowStyle as jV, rulerDragToGuidePosition as jW, rulerHighlight as jX, rulerStripTicks as jY, sampleColorFromSlide as jZ, sanitizeColor as j_, presetsForCategory as ja, pressuresToWidths as jb, prevVisibleIndex as jc, projectDrawingShapes as jd, promoteNode as je, provideViewerTheme as jf, radarAngle as jg, radarRingPoints as jh, readAsDataUrl as ji, recordWebm as jj, redistributeColumnWidth as jk, registerCrossSlideAudio as jl, rememberSessionDeck as jm, removeAnimation as jn, removeCategory as jo, removeTableElementColumn as jp, removeCommentFromList as jq, removeElementAnimation as jr, removeGradientStopPatch as js, removeNode as jt, removeTableElementRow as ju, removeSeries as jv, renderToCanvas as jw, reorderAnimationDown as jx, reorderAnimationUp as jy, replaceInSlides as jz, AiChangeOverlayComponent as k, statusLabel as k$, sanitizeUserName as k0, saveViewerProfile as k1, scanAvailableFonts as k2, searchSlides as k3, seedBroadcastFields as k4, seedHyperlinkDraft as k5, seedPropertiesDraft as k6, seedShareFields as k7, segmentFrameCount as k8, selectValue$2 as k9, setNodeStyle as kA, setNodeText as kB, setRepeatCount as kC, setRepeatMode as kD, setSequence as kE, setSeriesChartType as kF, setSeriesColor as kG, setSeriesErrorBars as kH, setSeriesMarker as kI, setSeriesName as kJ, setSeriesTrendline as kK, setSeriesValue as kL, setStyle as kM, setTimingCurve as kN, setTitle as kO, setTrigger as kP, setTriggerShapeId as kQ, shapeStylePatch as kR, sheetAfterNavigate as kS, shouldBlockClickAdvance as kT, shouldUseSvgWarp as kU, showDirectionPicker as kV, showsTemplateAffordance as kW, signatureCountLabel as kX, signatureKey as kY, signatureTimestamp as kZ, signerName as k_, sendBackward as ka, sendToBack as kb, sequentialColorScale as kc, serializeWriteBack as kd, seriesColor as ke, setAnimationEmphasis as kf, setAnimationEntrance as kg, setAnimationExit as kh, setAxis as ki, setAxisLogScale as kj, setAxisTitleStyle as kk, setCategoryLabel as kl, setCellText as km, setColorScheme as kn, setDataLabels as ko, setDataPointExplosion as kp, setDataPointFill as kq, setDataPointLabel as kr, setDataPointMarker as ks, setDelay as kt, setDirection as ku, setDuration as kv, setElementPosition as kw, setGridlineStyle as kx, setLayout as ky, setLegend as kz, AiChatPanelComponent as l, slideNumberOf as l0, smartArtNodes as l1, paletteColour as l2, snapToGridStep as l3, splitCursorCell as l4, splitMergedCell as l5, statusKind as l6, statusLabel$1 as l7, storeAudienceContent as l8, stringFromEvent$5 as l9, updateInnerShadowPatch as lA, updateOuterShadowPatch as lB, updateReflectionPatch as lC, vAlignPatch as lD, validatePassword as lE, validatePrintSettings as lF, validateRoomId as lG, valueToY as lH, vermilionDarkColors as lI, vermilionDarkTheme as lJ, vermilionLightColors as lK, vermilionLightTheme as lL, vermilionRadius as lM, waypointsToPathD as lN, worstStatus as lO, zoomTargetSlideIndex as lP, strokeColorOf as la, strokeToInkElement as lb, strokeWidthOf as lc, styleShadowFilter as ld, textAdvancedPatch as le, textAdvancedStateFromStyle as lf, textAdvancedStateOf as lg, textColorOf as lh, textDirectionPatch as li, textStyleOf as lj, textStylePatch as lk, themeStyle as ll, themeToCssVars as lm, thumbnailHeight as ln, thumbnailZoom as lo, toggleCommentResolvedInList as lp, toggleNodeBold as lq, toggleNodeItalic as lr, toggleSheet as ls, topLevelNodeCount as lt, transformSelectedTextCase as lu, translationsEn as lv, ungroupElements as lw, updateElementById as lx, updateGlowPatch as ly, updateGradientStopPatch as lz, AiChatService as m, AiComposerComponent as n, AiFocusBarComponent as o, AiFocusHighlightOverlayComponent as p, AiHistoryMenuComponent as q, AiHistoryService as r, AiMessageListComponent as s, toChatSummary as t, AiPanelStore as u, AiProposalCardComponent as v, AiSettingsSectionComponent as w, AiToolCallCardComponent as x, AnimationAuthorPanelComponent as y, AnimationPanelComponent as z };
|
|
127996
|
-
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-
|
|
128518
|
+
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-0Jy3I4UO.mjs.map
|