pptx-angular-viewer 2.17.0 → 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 +4 -0
- package/fesm2022/{pptx-angular-viewer-chat-history-idb--NbNwqbC.mjs → pptx-angular-viewer-chat-history-idb-BF1I9H0D.mjs} +2 -2
- package/fesm2022/{pptx-angular-viewer-chat-history-idb--NbNwqbC.mjs.map → pptx-angular-viewer-chat-history-idb-BF1I9H0D.mjs.map} +1 -1
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-CGh_UvBb.mjs → pptx-angular-viewer-pptx-angular-viewer-0Jy3I4UO.mjs} +1262 -144
- package/fesm2022/{pptx-angular-viewer-pptx-angular-viewer-CGh_UvBb.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 +113 -2
|
@@ -25288,6 +25288,37 @@ function getImageFitStyle(el) {
|
|
|
25288
25288
|
if (!isImageLikeElement(el)) {
|
|
25289
25289
|
return uncropped;
|
|
25290
25290
|
}
|
|
25291
|
+
const { placement, crop } = imageFitTransformParts(el);
|
|
25292
|
+
if (!placement && !crop) {
|
|
25293
|
+
return uncropped;
|
|
25294
|
+
}
|
|
25295
|
+
// Placement first, crop second: transforms compose right-to-left, so the
|
|
25296
|
+
// crop magnifies within the box the placement has already mapped onto the
|
|
25297
|
+
// fill-rect region (translate percentages resolve against the img border
|
|
25298
|
+
// box and are scaled by the preceding placement scale, which is exactly
|
|
25299
|
+
// "percent of the placed width").
|
|
25300
|
+
const transform = [placement, crop].filter(Boolean).join(' ');
|
|
25301
|
+
return {
|
|
25302
|
+
position: 'absolute',
|
|
25303
|
+
width: '100%',
|
|
25304
|
+
height: '100%',
|
|
25305
|
+
maxWidth: 'none',
|
|
25306
|
+
maxHeight: 'none',
|
|
25307
|
+
objectFit: 'fill',
|
|
25308
|
+
transformOrigin: 'top left',
|
|
25309
|
+
transform,
|
|
25310
|
+
};
|
|
25311
|
+
}
|
|
25312
|
+
/** A `translate`/`scale` pair that changes nothing, used to pad a transform. */
|
|
25313
|
+
const IDENTITY_TRANSFORM_PAIR = 'translate(0%, 0%) scale(1, 1)';
|
|
25314
|
+
/**
|
|
25315
|
+
* The two halves of a picture's fit transform: the `a:stretch/a:fillRect`
|
|
25316
|
+
* PLACEMENT and the `a:srcRect` source CROP. Either is `''` when absent.
|
|
25317
|
+
*/
|
|
25318
|
+
function imageFitTransformParts(el) {
|
|
25319
|
+
if (!isImageLikeElement(el)) {
|
|
25320
|
+
return { placement: '', crop: '' };
|
|
25321
|
+
}
|
|
25291
25322
|
// `a:stretch/a:fillRect` stretches the (cropped) image into a sub-rect of
|
|
25292
25323
|
// the FRAME; negative offsets legitimately push it past the frame edges,
|
|
25293
25324
|
// and the overflow-hidden frame clips the spill (issue #132 deck, phone
|
|
@@ -25300,52 +25331,59 @@ function getImageFitStyle(el) {
|
|
|
25300
25331
|
const frRight = el.fillRectRight ?? 0;
|
|
25301
25332
|
const frBottom = el.fillRectBottom ?? 0;
|
|
25302
25333
|
const hasFillRect = Math.abs(frLeft) + Math.abs(frTop) + Math.abs(frRight) + Math.abs(frBottom) > 0.0001;
|
|
25303
|
-
const
|
|
25334
|
+
const placement = hasFillRect
|
|
25304
25335
|
? `translate(${round2(frLeft * 100)}%, ${round2(frTop * 100)}%) scale(${round6(Math.max(0.01, 1 - frLeft - frRight))}, ${round6(Math.max(0.01, 1 - frTop - frBottom))})`
|
|
25305
25336
|
: '';
|
|
25306
25337
|
const cropLeft = clampCropValue(el.cropLeft);
|
|
25307
25338
|
const cropTop = clampCropValue(el.cropTop);
|
|
25308
25339
|
const cropRight = clampCropValue(el.cropRight);
|
|
25309
25340
|
const cropBottom = clampCropValue(el.cropBottom);
|
|
25310
|
-
|
|
25311
|
-
|
|
25312
|
-
|
|
25313
|
-
|
|
25314
|
-
|
|
25315
|
-
|
|
25316
|
-
|
|
25317
|
-
|
|
25318
|
-
|
|
25319
|
-
|
|
25320
|
-
|
|
25321
|
-
|
|
25322
|
-
|
|
25323
|
-
|
|
25324
|
-
|
|
25325
|
-
|
|
25326
|
-
|
|
25327
|
-
|
|
25328
|
-
|
|
25329
|
-
|
|
25330
|
-
|
|
25331
|
-
|
|
25332
|
-
|
|
25333
|
-
|
|
25334
|
-
|
|
25335
|
-
|
|
25336
|
-
|
|
25337
|
-
|
|
25338
|
-
|
|
25339
|
-
|
|
25340
|
-
|
|
25341
|
-
|
|
25342
|
-
|
|
25343
|
-
|
|
25344
|
-
|
|
25345
|
-
|
|
25346
|
-
|
|
25347
|
-
|
|
25348
|
-
|
|
25341
|
+
if (cropLeft + cropRight <= 0.0001 && cropTop + cropBottom <= 0.0001) {
|
|
25342
|
+
return { placement, crop: '' };
|
|
25343
|
+
}
|
|
25344
|
+
// A crop that swallows (almost) the whole source would divide by ~0
|
|
25345
|
+
// below, so the pair is rescaled to leave a 1% sliver rather than
|
|
25346
|
+
// producing Infinity.
|
|
25347
|
+
const horizontalScale = cropLeft + cropRight >= 0.99 ? 0.99 / (cropLeft + cropRight) : 1;
|
|
25348
|
+
const verticalScale = cropTop + cropBottom >= 0.99 ? 0.99 / (cropTop + cropBottom) : 1;
|
|
25349
|
+
const left = clampCropValue(cropLeft * horizontalScale);
|
|
25350
|
+
const right = clampCropValue(cropRight * horizontalScale);
|
|
25351
|
+
const top = clampCropValue(cropTop * verticalScale);
|
|
25352
|
+
const bottom = clampCropValue(cropBottom * verticalScale);
|
|
25353
|
+
const remainingWidth = Math.max(0.01, 1 - left - right);
|
|
25354
|
+
const remainingHeight = Math.max(0.01, 1 - top - bottom);
|
|
25355
|
+
const tx = Math.round((-left / remainingWidth) * 10000) / 100;
|
|
25356
|
+
const ty = Math.round((-top / remainingHeight) * 10000) / 100;
|
|
25357
|
+
const sx = Math.round((1 / remainingWidth) * 1e6) / 1e6;
|
|
25358
|
+
const sy = Math.round((1 / remainingHeight) * 1e6) / 1e6;
|
|
25359
|
+
return { placement, crop: `translate(${tx}%, ${ty}%) scale(${sx}, ${sy})` };
|
|
25360
|
+
}
|
|
25361
|
+
/**
|
|
25362
|
+
* The `<img>` `transform` that renders a picture's fill-rect placement and
|
|
25363
|
+
* source crop, as one string.
|
|
25364
|
+
*
|
|
25365
|
+
* This is the value {@link getImageFitStyle} puts on the element; it is exposed
|
|
25366
|
+
* separately so the Morph engine can animate BETWEEN two pictures' crops
|
|
25367
|
+
* without re-deriving the maths (issue #148: PowerPoint's "Scale Height" /
|
|
25368
|
+
* "Scale Width" is an `a:srcRect` crop, so a slide pair that differs only in
|
|
25369
|
+
* scale has identical frames and morphed as a hard cut).
|
|
25370
|
+
*
|
|
25371
|
+
* @param el - The picture element.
|
|
25372
|
+
* @param padToIdentity - When true, ALWAYS emits both the placement and the
|
|
25373
|
+
* crop `translate`/`scale` pair, substituting an identity pair where the
|
|
25374
|
+
* element has none. Two pictures then produce the same transform function
|
|
25375
|
+
* list, which is what lets CSS interpolate them function-by-function instead
|
|
25376
|
+
* of decomposing to a matrix (and lets an uncropped end of a pair sit at a
|
|
25377
|
+
* true identity, so the element lands exactly on its static style).
|
|
25378
|
+
* @returns The transform value; `''` only when there is nothing to apply and
|
|
25379
|
+
* `padToIdentity` is false.
|
|
25380
|
+
*/
|
|
25381
|
+
function buildImageFitTransform(el, padToIdentity = false) {
|
|
25382
|
+
const { placement, crop } = imageFitTransformParts(el);
|
|
25383
|
+
if (!padToIdentity) {
|
|
25384
|
+
return [placement, crop].filter(Boolean).join(' ');
|
|
25385
|
+
}
|
|
25386
|
+
return `${placement || IDENTITY_TRANSFORM_PAIR} ${crop || IDENTITY_TRANSFORM_PAIR}`;
|
|
25349
25387
|
}
|
|
25350
25388
|
/** Round to two decimals for stable CSS percentage output. */
|
|
25351
25389
|
function round2(value) {
|
|
@@ -33896,6 +33934,249 @@ function buildRunEffectStyle(style) {
|
|
|
33896
33934
|
return css;
|
|
33897
33935
|
}
|
|
33898
33936
|
|
|
33937
|
+
/**
|
|
33938
|
+
* Per-run advance-width compensation, so the browser breaks lines where
|
|
33939
|
+
* PowerPoint breaks them.
|
|
33940
|
+
*
|
|
33941
|
+
* PowerPoint lays text out with GDI-compatible (hinted) metrics: every glyph
|
|
33942
|
+
* advance is snapped to a whole device pixel at 576 DPI, i.e. to 1/8 point,
|
|
33943
|
+
* i.e. to 1/6 of a CSS px. The browser uses unrounded fractional advances. The
|
|
33944
|
+
* two therefore disagree by up to 1/12 px per glyph, in EITHER direction, and
|
|
33945
|
+
* the accumulated disagreement over a line is what decides a knife-edge wrap.
|
|
33946
|
+
*
|
|
33947
|
+
* Ground truth (PowerPoint COM `TextRange.BoundWidth` over the issue #131 /
|
|
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
|
+
*
|
|
33952
|
+
* That spread is the point. The first attempt at this (issue #131) applied a
|
|
33953
|
+
* flat 0.003em to every run, which is roughly the middle of the range: it
|
|
33954
|
+
* tipped genuinely-late wraps the right way but pushed every string the browser
|
|
33955
|
+
* already measured WIDER than PowerPoint over its column, so short labels that
|
|
33956
|
+
* PowerPoint keeps on one line ("Explore solution", "Secure Data Movement")
|
|
33957
|
+
* started wrapping (issue #149). No single constant can do this job; the
|
|
33958
|
+
* correction has to be derived from the actual characters.
|
|
33959
|
+
*
|
|
33960
|
+
* So: measure the run, compute the width PowerPoint would have measured, and
|
|
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.
|
|
33970
|
+
*/
|
|
33971
|
+
/**
|
|
33972
|
+
* Advance-width quantisation steps per CSS px. PowerPoint snaps each glyph
|
|
33973
|
+
* advance to an integer pixel at 576 DPI = 8 steps per point = 6 steps per px.
|
|
33974
|
+
*/
|
|
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);
|
|
33982
|
+
/** Bound the caches so a long editing session cannot grow them without limit. */
|
|
33983
|
+
const MAX_CACHE_ENTRIES = 20000;
|
|
33984
|
+
let measureContext;
|
|
33985
|
+
let trackingCache = new Map();
|
|
33986
|
+
let fontsHookInstalled = false;
|
|
33987
|
+
/**
|
|
33988
|
+
* A font that finishes loading after a run was measured invalidates that
|
|
33989
|
+
* measurement (it described the fallback face). Drop the caches so the next
|
|
33990
|
+
* render recomputes against what is now actually painted.
|
|
33991
|
+
*/
|
|
33992
|
+
function installFontLoadHook() {
|
|
33993
|
+
if (fontsHookInstalled || typeof document === 'undefined') {
|
|
33994
|
+
return;
|
|
33995
|
+
}
|
|
33996
|
+
fontsHookInstalled = true;
|
|
33997
|
+
document.fonts?.addEventListener?.('loadingdone', () => {
|
|
33998
|
+
trackingCache = new Map();
|
|
33999
|
+
});
|
|
34000
|
+
}
|
|
34001
|
+
function getMeasureContext() {
|
|
34002
|
+
if (measureContext !== undefined) {
|
|
34003
|
+
return measureContext;
|
|
34004
|
+
}
|
|
34005
|
+
if (typeof document === 'undefined') {
|
|
34006
|
+
measureContext = null;
|
|
34007
|
+
return null;
|
|
34008
|
+
}
|
|
34009
|
+
installFontLoadHook();
|
|
34010
|
+
measureContext = document.createElement('canvas').getContext('2d');
|
|
34011
|
+
return measureContext;
|
|
34012
|
+
}
|
|
34013
|
+
/** CSS shorthand for `CanvasRenderingContext2D.font`. */
|
|
34014
|
+
function toCanvasFont(font) {
|
|
34015
|
+
const size = font.fontSizePx && font.fontSizePx > 0 ? font.fontSizePx : DEFAULT_TEXT_FONT_SIZE;
|
|
34016
|
+
const family = font.fontFamily || DEFAULT_FONT_FAMILY$1;
|
|
34017
|
+
return `${font.italic ? 'italic ' : ''}${font.bold ? 'bold ' : ''}${size}px ${family}`;
|
|
34018
|
+
}
|
|
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) {
|
|
34040
|
+
ctx.font = canvasFont;
|
|
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;
|
|
34054
|
+
}
|
|
34055
|
+
return advances;
|
|
34056
|
+
}
|
|
34057
|
+
/**
|
|
34058
|
+
* The letter-spacing (in CSS px) that makes `text` render at the width
|
|
34059
|
+
* PowerPoint measured it at. `0` when there is nothing to correct, no DOM to
|
|
34060
|
+
* measure with, or the correction came out implausible.
|
|
34061
|
+
*
|
|
34062
|
+
* The divisor is the character count, not the gap count: every engine adds the
|
|
34063
|
+
* spacing after the final character too, and that trailing gap is part of the
|
|
34064
|
+
* inline box the line breaker sees. Being wrong about that convention would
|
|
34065
|
+
* cost one unit of tracking (~0.04 px), well inside the tolerance here.
|
|
34066
|
+
*
|
|
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.
|
|
34076
|
+
*/
|
|
34077
|
+
function resolveMetricTrackingPx(text, font) {
|
|
34078
|
+
if (!text) {
|
|
34079
|
+
return 0;
|
|
34080
|
+
}
|
|
34081
|
+
const canvasFont = toCanvasFont(font);
|
|
34082
|
+
const key = `${canvasFont}\u0000${text}`;
|
|
34083
|
+
const cached = trackingCache.get(key);
|
|
34084
|
+
if (cached !== undefined) {
|
|
34085
|
+
return cached;
|
|
34086
|
+
}
|
|
34087
|
+
const ctx = getMeasureContext();
|
|
34088
|
+
if (!ctx) {
|
|
34089
|
+
return 0;
|
|
34090
|
+
}
|
|
34091
|
+
const chars = [...text];
|
|
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';
|
|
34098
|
+
const natural = ctx.measureText(text).width;
|
|
34099
|
+
if (!(natural > 0)) {
|
|
34100
|
+
return 0;
|
|
34101
|
+
}
|
|
34102
|
+
powerPoint /= ADVANCE_STEPS_PER_PX;
|
|
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));
|
|
34106
|
+
if (trackingCache.size >= MAX_CACHE_ENTRIES) {
|
|
34107
|
+
trackingCache = new Map();
|
|
34108
|
+
}
|
|
34109
|
+
trackingCache.set(key, tracking);
|
|
34110
|
+
return tracking;
|
|
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
|
+
}
|
|
34165
|
+
/**
|
|
34166
|
+
* {@link resolveMetricTrackingPx} as a CSS length, or `undefined` when the run
|
|
34167
|
+
* needs no correction (so callers can leave `letter-spacing` undeclared rather
|
|
34168
|
+
* than emitting a no-op `0px`).
|
|
34169
|
+
*/
|
|
34170
|
+
function resolveMetricTracking(text, font) {
|
|
34171
|
+
const tracking = resolveMetricTrackingPx(text, font);
|
|
34172
|
+
return tracking === 0 ? undefined : `${tracking}px`;
|
|
34173
|
+
}
|
|
34174
|
+
/** Test hook: forget every measurement (also used by the font-load listener). */
|
|
34175
|
+
function resetMetricTrackingCache() {
|
|
34176
|
+
trackingCache = new Map();
|
|
34177
|
+
measureContext = undefined;
|
|
34178
|
+
}
|
|
34179
|
+
|
|
33899
34180
|
/**
|
|
33900
34181
|
* Per-run inline-style builder for rendered text runs (framework-agnostic).
|
|
33901
34182
|
*
|
|
@@ -33909,23 +34190,62 @@ const PX_PER_POINT = 96 / 72;
|
|
|
33909
34190
|
/** Super/subscript glyphs render at ~65% of the run font size (matches React). */
|
|
33910
34191
|
const BASELINE_FONT_SCALE = 0.65;
|
|
33911
34192
|
/**
|
|
33912
|
-
*
|
|
33913
|
-
* PowerPoint
|
|
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
|
+
}
|
|
34236
|
+
/**
|
|
34237
|
+
* Combine the authored `a:rPr/@spc` character spacing with the measured
|
|
34238
|
+
* PowerPoint metric compensation into one `letter-spacing`, or leave it
|
|
34239
|
+
* undeclared when neither applies.
|
|
33914
34240
|
*
|
|
33915
|
-
*
|
|
33916
|
-
*
|
|
33917
|
-
*
|
|
33918
|
-
*
|
|
33919
|
-
* onto a knife-edge line than PowerPoint and the paragraph wraps a word late.
|
|
33920
|
-
* Solving that deck's slides 5/13/14 for the tracking that reproduces every
|
|
33921
|
-
* PowerPoint break point gives the window (0.0019em, 0.0104em); 0.003em sits
|
|
33922
|
-
* inside it and matches the measured metric gap. At a 10px font this is
|
|
33923
|
-
* 0.03px per glyph: far below anything visible, but enough to tip knife-edge
|
|
33924
|
-
* fits the way PowerPoint tips them.
|
|
34241
|
+
* The compensation is derived from the run's own characters
|
|
34242
|
+
* (`resolveMetricTracking`); an earlier attempt used one flat constant for
|
|
34243
|
+
* every run and regressed short labels that PowerPoint keeps on one line
|
|
34244
|
+
* (issue #149).
|
|
33925
34245
|
*/
|
|
33926
|
-
|
|
33927
|
-
|
|
33928
|
-
|
|
34246
|
+
function resolveLetterSpacing(s, text, font) {
|
|
34247
|
+
return pieceLetterSpacing(authoredLetterSpacingPx(s), resolveMetricTrackingPx(text, font));
|
|
34248
|
+
}
|
|
33929
34249
|
/**
|
|
33930
34250
|
* Layer the "extra" run properties that neither the boolean decoration set nor
|
|
33931
34251
|
* `buildRunEffectStyle` cover: character spacing, super/subscript baseline
|
|
@@ -33933,14 +34253,10 @@ const POWERPOINT_METRIC_TRACKING = `${POWERPOINT_METRIC_TRACKING_EM}em`;
|
|
|
33933
34253
|
* and `a:rPr/@cap` caps. Mirrors React's `renderSingleSegment` span style so the
|
|
33934
34254
|
* shared builder (Vue / Angular / Svelte / Vanilla) reaches run-prop parity.
|
|
33935
34255
|
*/
|
|
33936
|
-
function applyExtraRunProps(style, s) {
|
|
33937
|
-
|
|
33938
|
-
|
|
33939
|
-
|
|
33940
|
-
style.letterSpacing = `calc(${(s.characterSpacing / 100) * PX_PER_POINT}px + ${POWERPOINT_METRIC_TRACKING})`;
|
|
33941
|
-
}
|
|
33942
|
-
else {
|
|
33943
|
-
style.letterSpacing = POWERPOINT_METRIC_TRACKING;
|
|
34256
|
+
function applyExtraRunProps(style, s, text, font) {
|
|
34257
|
+
const letterSpacing = resolveLetterSpacing(s, text, font);
|
|
34258
|
+
if (letterSpacing !== undefined) {
|
|
34259
|
+
style.letterSpacing = letterSpacing;
|
|
33944
34260
|
}
|
|
33945
34261
|
// Kerning (`a:rPr/@kern`): 0 disables kerning, any other value enables it.
|
|
33946
34262
|
if (typeof s.kerning === 'number') {
|
|
@@ -33970,15 +34286,7 @@ function applyExtraRunProps(style, s) {
|
|
|
33970
34286
|
style.fontVariantCaps = 'small-caps';
|
|
33971
34287
|
}
|
|
33972
34288
|
}
|
|
33973
|
-
|
|
33974
|
-
* Per-run inline style derived from a TextSegment's style.
|
|
33975
|
-
*
|
|
33976
|
-
* `fontScale` is the body's `a:normAutofit/@fontScale` (see
|
|
33977
|
-
* `resolveAutoFitFontScale`). It has to be applied HERE and not only on the
|
|
33978
|
-
* text body, because a run that authors its own `sz` overrides the body's
|
|
33979
|
-
* font-size, so scaling the body alone left every authored run at full size.
|
|
33980
|
-
*/
|
|
33981
|
-
function segmentStyleToCss(seg, fontScale = 1) {
|
|
34289
|
+
function segmentStyleToCss(seg, fontScale = 1, context = {}) {
|
|
33982
34290
|
const s = seg.style ?? {};
|
|
33983
34291
|
const style = {};
|
|
33984
34292
|
if (s.fontFamily) {
|
|
@@ -34028,9 +34336,28 @@ function segmentStyleToCss(seg, fontScale = 1) {
|
|
|
34028
34336
|
if (deco.length > 0) {
|
|
34029
34337
|
style.textDecoration = deco.join(' ');
|
|
34030
34338
|
}
|
|
34031
|
-
applyExtraRunProps(style, s);
|
|
34339
|
+
applyExtraRunProps(style, s, context.text ?? seg.text ?? '', resolveRunFont(style, s, context.blockFont));
|
|
34032
34340
|
return style;
|
|
34033
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,
|
|
34354
|
+
fontSizePx: typeof style.fontSize === 'string'
|
|
34355
|
+
? Number.parseFloat(style.fontSize)
|
|
34356
|
+
: blockFont?.fontSizePx,
|
|
34357
|
+
bold: Boolean(s.bold),
|
|
34358
|
+
italic: Boolean(s.italic),
|
|
34359
|
+
};
|
|
34360
|
+
}
|
|
34034
34361
|
/**
|
|
34035
34362
|
* Layer the underline-style / double-strike *variant* decoration CSS
|
|
34036
34363
|
* (`text-decoration-style` / `-thickness` / `text-underline-offset`) onto a run
|
|
@@ -34187,6 +34514,15 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
34187
34514
|
// `a:normAutofit/@fontScale`: applied to every authored run size below, since
|
|
34188
34515
|
// a run's own `sz` overrides the (already scaled) body font-size.
|
|
34189
34516
|
const fontScale = resolveAutoFitFontScale(element.textStyle);
|
|
34517
|
+
// What a run that declares no font of its own inherits from the text body.
|
|
34518
|
+
// Only used to measure the run for its PowerPoint metric compensation, so it
|
|
34519
|
+
// mirrors what `buildTextBlockStyle` declares on the block itself.
|
|
34520
|
+
const blockFont = {
|
|
34521
|
+
fontFamily: element.textStyle?.fontFamily
|
|
34522
|
+
? getSubstituteFontFamily(element.textStyle.fontFamily)
|
|
34523
|
+
: DEFAULT_FONT_FAMILY$1,
|
|
34524
|
+
fontSizePx: (element.textStyle?.fontSize || DEFAULT_TEXT_FONT_SIZE) * fontScale,
|
|
34525
|
+
};
|
|
34190
34526
|
const paragraphIndents = element.paragraphIndents;
|
|
34191
34527
|
const grouped = [
|
|
34192
34528
|
{ paraSegments: [] },
|
|
@@ -34223,7 +34559,7 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
34223
34559
|
? substituteFieldText(rawText, seg.fieldType, fieldContext)
|
|
34224
34560
|
: rawText;
|
|
34225
34561
|
if (text) {
|
|
34226
|
-
const style = segmentStyleToCss(seg, fontScale);
|
|
34562
|
+
const style = segmentStyleToCss(seg, fontScale, { text, blockFont });
|
|
34227
34563
|
applyUnderlineVariant(style, seg);
|
|
34228
34564
|
// Per-run text effects (gradient/pattern fill, outer/inner shadow,
|
|
34229
34565
|
// 3D extrusion text-shadow, blur, HSL, alpha opacity, glow,
|
|
@@ -34232,7 +34568,13 @@ function buildParagraphs(element, fieldContext, segmentOverrides) {
|
|
|
34232
34568
|
if (seg.style) {
|
|
34233
34569
|
Object.assign(style, buildRunEffectStyle(seg.style));
|
|
34234
34570
|
}
|
|
34235
|
-
|
|
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)));
|
|
34236
34578
|
}
|
|
34237
34579
|
}
|
|
34238
34580
|
// Suppress bullets for paragraphs with no visible text content.
|
|
@@ -34557,14 +34899,79 @@ function correspondingGroup(group, candidates) {
|
|
|
34557
34899
|
return sameBox(group, candidate);
|
|
34558
34900
|
});
|
|
34559
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
|
+
}
|
|
34560
34965
|
/**
|
|
34561
34966
|
* The elements of `elements` that a morph should treat as individual units,
|
|
34562
34967
|
* given the `counterpart` slide's elements at the same level of the tree.
|
|
34563
34968
|
*
|
|
34564
34969
|
* A group is replaced by its children (in document order, recursively, in
|
|
34565
|
-
* absolute coordinates) when it holds a `!!`-named descendant
|
|
34566
|
-
* holds a group it would pair with
|
|
34567
|
-
* 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.
|
|
34568
34975
|
*/
|
|
34569
34976
|
function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
|
|
34570
34977
|
const out = [];
|
|
@@ -34573,7 +34980,7 @@ function flattenMorphElements(elements, counterpart, offsetX = 0, offsetY = 0) {
|
|
|
34573
34980
|
if (children && containsMorphNamedDescendant(element)) {
|
|
34574
34981
|
const twin = correspondingGroup(element, counterpart);
|
|
34575
34982
|
const twinChildren = twin ? (groupChildren(twin) ?? []) : undefined;
|
|
34576
|
-
if (twinChildren) {
|
|
34983
|
+
if (twinChildren && childrenCorrespond(children, twinChildren)) {
|
|
34577
34984
|
out.push(...flattenMorphElements(children, twinChildren, offsetX + element.x, offsetY + element.y));
|
|
34578
34985
|
continue;
|
|
34579
34986
|
}
|
|
@@ -34887,6 +35294,20 @@ function interpolateOutline(from, to, t) {
|
|
|
34887
35294
|
// ---------------------------------------------------------------------------
|
|
34888
35295
|
/** PowerPoint's morph transition uses a specific cubic-bezier easing. */
|
|
34889
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)';
|
|
34890
35311
|
/**
|
|
34891
35312
|
* When an unmatched OUTGOING shape has finished dissolving, as a percentage of
|
|
34892
35313
|
* the morph's duration, and when it starts.
|
|
@@ -35001,6 +35422,123 @@ function generateGeometryMorphAnimation(pair, durationMs, pairIndex, steps = GEO
|
|
|
35001
35422
|
};
|
|
35002
35423
|
}
|
|
35003
35424
|
|
|
35425
|
+
/** Crop/placement insets are fractions of the source; 0.0001 is ~0.01%. */
|
|
35426
|
+
const CROP_EPSILON = 0.0001;
|
|
35427
|
+
/** The eight inset fractions that together decide what a picture paints. */
|
|
35428
|
+
function cropInsets(element) {
|
|
35429
|
+
if (!isImageLikeElement(element)) {
|
|
35430
|
+
return [0, 0, 0, 0, 0, 0, 0, 0];
|
|
35431
|
+
}
|
|
35432
|
+
return [
|
|
35433
|
+
element.cropLeft ?? 0,
|
|
35434
|
+
element.cropTop ?? 0,
|
|
35435
|
+
element.cropRight ?? 0,
|
|
35436
|
+
element.cropBottom ?? 0,
|
|
35437
|
+
element.fillRectLeft ?? 0,
|
|
35438
|
+
element.fillRectTop ?? 0,
|
|
35439
|
+
element.fillRectRight ?? 0,
|
|
35440
|
+
element.fillRectBottom ?? 0,
|
|
35441
|
+
];
|
|
35442
|
+
}
|
|
35443
|
+
/**
|
|
35444
|
+
* Whether a matched pair's pictures show a DIFFERENT region of their source.
|
|
35445
|
+
*
|
|
35446
|
+
* This is a geometry change, not an appearance change: PowerPoint zooms
|
|
35447
|
+
* smoothly between the two crops rather than dissolving one into the other, so
|
|
35448
|
+
* callers must not route it through the crossfade path.
|
|
35449
|
+
*/
|
|
35450
|
+
function morphImageCropChanged(fromElement, toElement) {
|
|
35451
|
+
if (!isImageLikeElement(fromElement) || !isImageLikeElement(toElement)) {
|
|
35452
|
+
return false;
|
|
35453
|
+
}
|
|
35454
|
+
const from = cropInsets(fromElement);
|
|
35455
|
+
const to = cropInsets(toElement);
|
|
35456
|
+
return from.some((value, index) => Math.abs(value - to[index]) > CROP_EPSILON);
|
|
35457
|
+
}
|
|
35458
|
+
/**
|
|
35459
|
+
* Keyframes that carry a picture's `<img>` from one crop to another.
|
|
35460
|
+
*
|
|
35461
|
+
* `transform-origin` is restated because the uncropped end of a pair has no
|
|
35462
|
+
* static transform at all (and therefore the CSS default origin); pinning both
|
|
35463
|
+
* frames to `top left` is what makes the two transforms describe the same
|
|
35464
|
+
* mapping. It is harmless on the final frame, where an uncropped incoming
|
|
35465
|
+
* picture sits at a pure identity transform.
|
|
35466
|
+
*/
|
|
35467
|
+
function cropKeyframes(name, fromTransform, toTransform) {
|
|
35468
|
+
return `
|
|
35469
|
+
@keyframes ${name} {
|
|
35470
|
+
\tfrom {
|
|
35471
|
+
\t\ttransform-origin: top left;
|
|
35472
|
+
\t\ttransform: ${fromTransform};
|
|
35473
|
+
\t}
|
|
35474
|
+
\tto {
|
|
35475
|
+
\t\ttransform-origin: top left;
|
|
35476
|
+
\t\ttransform: ${toTransform};
|
|
35477
|
+
\t}
|
|
35478
|
+
}`;
|
|
35479
|
+
}
|
|
35480
|
+
/**
|
|
35481
|
+
* The INCOMING half of every pair whose picture crop changed.
|
|
35482
|
+
*
|
|
35483
|
+
* Keyed by the incoming element id and targeted at its `<img>`, matching the
|
|
35484
|
+
* FLIP model the rest of the engine uses: the incoming picture is rendered at
|
|
35485
|
+
* its final crop and started at the outgoing one's.
|
|
35486
|
+
*
|
|
35487
|
+
* @param pairs - Matched pairs.
|
|
35488
|
+
* @param durationMs - Animation duration in milliseconds.
|
|
35489
|
+
* @returns One descriptor per pair whose crop actually changed.
|
|
35490
|
+
*/
|
|
35491
|
+
function generateImageCropMorphAnimations(pairs, durationMs) {
|
|
35492
|
+
const animations = [];
|
|
35493
|
+
for (let index = 0; index < pairs.length; index++) {
|
|
35494
|
+
const { fromElement, toElement } = pairs[index];
|
|
35495
|
+
if (!morphImageCropChanged(fromElement, toElement)) {
|
|
35496
|
+
continue;
|
|
35497
|
+
}
|
|
35498
|
+
const safeName = `pptx-morph-crop-${index}-${toElement.id.replace(/[^a-zA-Z0-9]/gu, '')}`;
|
|
35499
|
+
animations.push({
|
|
35500
|
+
elementId: toElement.id,
|
|
35501
|
+
target: 'image',
|
|
35502
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
35503
|
+
keyframes: cropKeyframes(safeName, buildImageFitTransform(fromElement, true), buildImageFitTransform(toElement, true)),
|
|
35504
|
+
});
|
|
35505
|
+
}
|
|
35506
|
+
return animations;
|
|
35507
|
+
}
|
|
35508
|
+
/**
|
|
35509
|
+
* The OUTGOING half: the same zoom on a ghost the overlay is painting.
|
|
35510
|
+
*
|
|
35511
|
+
* Restricted to the ghost set for the same reason the element-level ghosts are:
|
|
35512
|
+
* an outgoing shape the overlay does not paint has no node to animate, and
|
|
35513
|
+
* `buildMorphTransitionPlan` derives the overlay's element list from the
|
|
35514
|
+
* outgoing animations.
|
|
35515
|
+
*
|
|
35516
|
+
* @param pairs - Matched pairs.
|
|
35517
|
+
* @param durationMs - Animation duration in milliseconds.
|
|
35518
|
+
* @param ghostIds - Outgoing ids the overlay will paint; defaults to "all".
|
|
35519
|
+
* @returns One descriptor per painted ghost whose crop changed.
|
|
35520
|
+
*/
|
|
35521
|
+
function generateImageCropGhostAnimations(pairs, durationMs, ghostIds) {
|
|
35522
|
+
const animations = [];
|
|
35523
|
+
for (let index = 0; index < pairs.length; index++) {
|
|
35524
|
+
const { fromElement, toElement } = pairs[index];
|
|
35525
|
+
if (ghostIds && !ghostIds.has(fromElement.id)) {
|
|
35526
|
+
continue;
|
|
35527
|
+
}
|
|
35528
|
+
if (!morphImageCropChanged(fromElement, toElement)) {
|
|
35529
|
+
continue;
|
|
35530
|
+
}
|
|
35531
|
+
const safeName = `pptx-morph-crop-ghost-${index}-${fromElement.id.replace(/[^a-zA-Z0-9]/gu, '')}`;
|
|
35532
|
+
animations.push({
|
|
35533
|
+
elementId: fromElement.id,
|
|
35534
|
+
target: 'image',
|
|
35535
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
35536
|
+
keyframes: cropKeyframes(safeName, buildImageFitTransform(fromElement, true), buildImageFitTransform(toElement, true)),
|
|
35537
|
+
});
|
|
35538
|
+
}
|
|
35539
|
+
return animations;
|
|
35540
|
+
}
|
|
35541
|
+
|
|
35004
35542
|
/** Depth cap for the recursive text read; real decks never nest this far. */
|
|
35005
35543
|
const TEXT_MAX_DEPTH = 8;
|
|
35006
35544
|
/**
|
|
@@ -35319,6 +35857,122 @@ function matchMorphElementsFull(fromSlide, toSlide) {
|
|
|
35319
35857
|
return { pairs, unmatchedFrom, unmatchedTo };
|
|
35320
35858
|
}
|
|
35321
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
|
+
|
|
35322
35976
|
// ---------------------------------------------------------------------------
|
|
35323
35977
|
// Text tokenization
|
|
35324
35978
|
// ---------------------------------------------------------------------------
|
|
@@ -35748,9 +36402,15 @@ const GEOMETRY_EPSILON = 0.5;
|
|
|
35748
36402
|
* Most of a Morph deck is inert - the authoring pattern is to duplicate a slide
|
|
35749
36403
|
* and restyle one thing, so 26 of 32 pairs on this deck's transitions are
|
|
35750
36404
|
* untouched - which makes what we do with them the dominant visual effect.
|
|
36405
|
+
*
|
|
36406
|
+
* A picture's SOURCE CROP counts here even though it moves no box: PowerPoint's
|
|
36407
|
+
* "Scale Height"/"Scale Width" is an `a:srcRect` crop inside an unchanged frame,
|
|
36408
|
+
* so a picture rescaled between two slides compares equal on every other axis
|
|
36409
|
+
* and would otherwise be skipped entirely (issue #148).
|
|
35751
36410
|
*/
|
|
35752
36411
|
function isInertMorphPair(fromElement, toElement) {
|
|
35753
|
-
return (
|
|
36412
|
+
return (!morphImageCropChanged(fromElement, toElement) &&
|
|
36413
|
+
Math.abs(fromElement.x - toElement.x) <= GEOMETRY_EPSILON &&
|
|
35754
36414
|
Math.abs(fromElement.y - toElement.y) <= GEOMETRY_EPSILON &&
|
|
35755
36415
|
Math.abs(fromElement.width - toElement.width) <= GEOMETRY_EPSILON &&
|
|
35756
36416
|
Math.abs(fromElement.height - toElement.height) <= GEOMETRY_EPSILON &&
|
|
@@ -35760,19 +36420,9 @@ function isInertMorphPair(fromElement, toElement) {
|
|
|
35760
36420
|
(fromElement.opacity ?? 1) === (toElement.opacity ?? 1) &&
|
|
35761
36421
|
!morphPairNeedsCrossfade(fromElement, toElement));
|
|
35762
36422
|
}
|
|
35763
|
-
|
|
35764
|
-
|
|
35765
|
-
|
|
35766
|
-
return {
|
|
35767
|
-
left: Math.min(...boxes.map((element) => element.x)),
|
|
35768
|
-
top: Math.min(...boxes.map((element) => element.y)),
|
|
35769
|
-
right: Math.max(...boxes.map((element) => element.x + element.width)),
|
|
35770
|
-
bottom: Math.max(...boxes.map((element) => element.y + element.height)),
|
|
35771
|
-
};
|
|
35772
|
-
}
|
|
35773
|
-
function boxesOverlap(a, b) {
|
|
35774
|
-
return a.left < b.right && b.left < a.right && a.top < b.bottom && b.top < a.bottom;
|
|
35775
|
-
}
|
|
36423
|
+
// ---------------------------------------------------------------------------
|
|
36424
|
+
// Which outgoing shapes the overlay has to paint
|
|
36425
|
+
// ---------------------------------------------------------------------------
|
|
35776
36426
|
/**
|
|
35777
36427
|
* The outgoing shapes the transition overlay actually has to paint.
|
|
35778
36428
|
*
|
|
@@ -35828,12 +36478,21 @@ function resolveMorphGhostIds(outgoingElements, pairs) {
|
|
|
35828
36478
|
* box over `noFill` has nothing to hollow out, and pinning it means the new
|
|
35829
36479
|
* wording is at full strength from frame 1 while the old dissolves off it,
|
|
35830
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.
|
|
35831
36486
|
*/
|
|
35832
36487
|
function crossfadeIncomingMayFadeIn(element) {
|
|
35833
36488
|
const image = element;
|
|
35834
36489
|
if (image.imagePath || image.svgPath) {
|
|
35835
36490
|
return false;
|
|
35836
36491
|
}
|
|
36492
|
+
const children = element.children;
|
|
36493
|
+
if (children?.length) {
|
|
36494
|
+
return children.every((child) => crossfadeIncomingMayFadeIn(child));
|
|
36495
|
+
}
|
|
35837
36496
|
if (!hasShapeProperties(element)) {
|
|
35838
36497
|
return true;
|
|
35839
36498
|
}
|
|
@@ -35928,15 +36587,19 @@ function generateMorphAnimations(pairs, durationMs, _mode = 'object', ghostIds)
|
|
|
35928
36587
|
const crossfadesIn = !inert &&
|
|
35929
36588
|
morphPairNeedsCrossfade(fromElement, toElement) &&
|
|
35930
36589
|
crossfadeIncomingMayFadeIn(toElement);
|
|
35931
|
-
// 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).
|
|
35932
36593
|
const fromProps = [
|
|
35933
36594
|
`\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${fromRot}deg)${flips};`,
|
|
35934
|
-
`\t\topacity: ${inert ? 0 : crossfadesIn ? 0 : fromOpacity};`,
|
|
35935
36595
|
];
|
|
35936
36596
|
const toProps = [
|
|
35937
36597
|
`\t\ttransform: translate(0, 0) scale(1, 1) rotate(${toRot}deg)${flips};`,
|
|
35938
|
-
`\t\topacity: ${inert ? 0 : toOpacity};`,
|
|
35939
36598
|
];
|
|
36599
|
+
if (!crossfadesIn) {
|
|
36600
|
+
fromProps.push(`\t\topacity: ${inert ? 0 : fromOpacity};`);
|
|
36601
|
+
toProps.push(`\t\topacity: ${inert ? 0 : toOpacity};`);
|
|
36602
|
+
}
|
|
35940
36603
|
// Fill color interpolation
|
|
35941
36604
|
const colorInterp = buildColorInterpolationProps(fromElement, toElement);
|
|
35942
36605
|
if (colorInterp) {
|
|
@@ -35957,10 +36620,20 @@ ${fromProps.join('\n')}
|
|
|
35957
36620
|
\tto {
|
|
35958
36621
|
${toProps.join('\n')}
|
|
35959
36622
|
\t}
|
|
35960
|
-
}
|
|
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
|
+
: ''}`;
|
|
35961
36634
|
animations.push({
|
|
35962
36635
|
elementId: toElement.id,
|
|
35963
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
36636
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards${crossfadesIn ? `, ${safeName}-fade ${durationMs}ms ${MORPH_CROSSFADE_EASING} forwards` : ''}`,
|
|
35964
36637
|
keyframes,
|
|
35965
36638
|
});
|
|
35966
36639
|
}
|
|
@@ -36015,22 +36688,36 @@ function generateMorphGhostAnimations(pairs, durationMs, startIndex, ghostIds) {
|
|
|
36015
36688
|
const fromRot = fromElement.rotation ?? 0;
|
|
36016
36689
|
const toRot = shortestRotationTarget(fromRot, toElement.rotation ?? 0);
|
|
36017
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;
|
|
36018
36697
|
const keyframes = `
|
|
36019
36698
|
@keyframes ${safeName} {
|
|
36020
36699
|
\tfrom {
|
|
36021
36700
|
\t\ttransform-origin: center;
|
|
36022
|
-
\t\ttransform: translate(0, 0) scale(1, 1) rotate(${fromRot}deg)${flips}
|
|
36023
|
-
\t\topacity: ${fromElement.opacity ?? 1};
|
|
36701
|
+
\t\ttransform: translate(0, 0) scale(1, 1) rotate(${fromRot}deg)${flips};${fadesOut ? '' : `\n\t\topacity: ${opacity};`}
|
|
36024
36702
|
\t}
|
|
36025
36703
|
\tto {
|
|
36026
36704
|
\t\ttransform-origin: center;
|
|
36027
|
-
\t\ttransform: translate(${dx}px, ${dy}px) scale(${sx}, ${sy}) rotate(${toRot}deg)${flips}
|
|
36028
|
-
\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};`}
|
|
36029
36706
|
\t}
|
|
36030
|
-
}
|
|
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
|
+
: ''}`;
|
|
36031
36718
|
animations.push({
|
|
36032
36719
|
elementId: fromElement.id,
|
|
36033
|
-
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards`,
|
|
36720
|
+
animation: `${safeName} ${durationMs}ms ${MORPH_EASING} forwards${fadesOut ? `, ${safeName}-fade ${durationMs}ms ${MORPH_CROSSFADE_EASING} forwards` : ''}`,
|
|
36034
36721
|
keyframes,
|
|
36035
36722
|
});
|
|
36036
36723
|
}
|
|
@@ -36229,6 +36916,11 @@ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = 'obj
|
|
|
36229
36916
|
allAnimations.push(geo);
|
|
36230
36917
|
}
|
|
36231
36918
|
}
|
|
36919
|
+
// Picture crop morph: a pair whose `a:srcRect` changed zooms its source
|
|
36920
|
+
// region inside an otherwise unchanged frame (PowerPoint's "Scale
|
|
36921
|
+
// Height"/"Scale Width"). This rides the element's `<img>`, not its
|
|
36922
|
+
// container, so it is additive to whatever the pair does above.
|
|
36923
|
+
allAnimations.push(...generateImageCropMorphAnimations(matchResult.pairs, durationMs));
|
|
36232
36924
|
// Generate text morph animations for text-bearing matched pairs
|
|
36233
36925
|
if (mode === 'word' || mode === 'character') {
|
|
36234
36926
|
for (let i = 0; i < matchResult.pairs.length; i++) {
|
|
@@ -36242,6 +36934,9 @@ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = 'obj
|
|
|
36242
36934
|
// Outgoing half of every restyled pair's crossfade.
|
|
36243
36935
|
const ghosts = generateMorphGhostAnimations(matchResult.pairs, durationMs, pairAnims.length, ghostIds);
|
|
36244
36936
|
allAnimations.push(...ghosts);
|
|
36937
|
+
// The same zoom on the painted ghosts, so a crop change that IS crossfading
|
|
36938
|
+
// dissolves from the region the outgoing slide actually showed.
|
|
36939
|
+
allAnimations.push(...generateImageCropGhostAnimations(matchResult.pairs, durationMs, ghostIds));
|
|
36245
36940
|
// Generate fade-out for unmatched from elements
|
|
36246
36941
|
const fadeOuts = generateUnmatchedFadeOutAnimations(matchResult.unmatchedFrom, durationMs, pairAnims.length + ghosts.length);
|
|
36247
36942
|
allAnimations.push(...fadeOuts);
|
|
@@ -36251,6 +36946,21 @@ function generateFullMorphTransition(fromSlide, toSlide, durationMs, mode = 'obj
|
|
|
36251
36946
|
return allAnimations;
|
|
36252
36947
|
}
|
|
36253
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
|
+
}`;
|
|
36254
36964
|
/** Map a parsed `<p159:morph @option>` onto the engine's granularity mode. */
|
|
36255
36965
|
function morphOptionToMode(option) {
|
|
36256
36966
|
if (option === 'byWord') {
|
|
@@ -36307,15 +37017,23 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = 'object
|
|
|
36307
37017
|
const outgoingIds = new Set(flattenedOutgoing.map((element) => element.id));
|
|
36308
37018
|
const incomingAnimations = new Map();
|
|
36309
37019
|
const outgoingAnimations = new Map();
|
|
37020
|
+
const incomingImageAnimations = new Map();
|
|
37021
|
+
const outgoingImageAnimations = new Map();
|
|
36310
37022
|
const keyframes = [];
|
|
36311
37023
|
for (const animation of animations) {
|
|
36312
37024
|
keyframes.push(animation.keyframes);
|
|
36313
|
-
|
|
36314
|
-
|
|
36315
|
-
|
|
36316
|
-
|
|
36317
|
-
|
|
36318
|
-
|
|
37025
|
+
const isOutgoing = outgoingIds.has(animation.elementId);
|
|
37026
|
+
// An `image`-targeted animation rides the `<img>` inside the element, so
|
|
37027
|
+
// it goes in its own map: it shares an element id with the container
|
|
37028
|
+
// animation and would otherwise overwrite it.
|
|
37029
|
+
const target = animation.target === 'image'
|
|
37030
|
+
? isOutgoing
|
|
37031
|
+
? outgoingImageAnimations
|
|
37032
|
+
: incomingImageAnimations
|
|
37033
|
+
: isOutgoing
|
|
37034
|
+
? outgoingAnimations
|
|
37035
|
+
: incomingAnimations;
|
|
37036
|
+
target.set(animation.elementId, animation.animation);
|
|
36319
37037
|
}
|
|
36320
37038
|
// An outgoing shape with no animation is one whose ghost the engine dropped
|
|
36321
37039
|
// as redundant: its live counterpart draws the same thing along the same
|
|
@@ -36324,11 +37042,45 @@ function buildMorphTransitionPlan(fromSlide, toSlide, durationMs, mode = 'object
|
|
|
36324
37042
|
// the overlay came down). Deriving the list from the animations keeps this
|
|
36325
37043
|
// decision in one place, `resolveMorphGhostIds`.
|
|
36326
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));
|
|
36327
37075
|
return {
|
|
36328
37076
|
keyframesCss: keyframes.join('\n'),
|
|
36329
37077
|
incomingAnimations,
|
|
36330
37078
|
outgoingAnimations,
|
|
37079
|
+
incomingImageAnimations,
|
|
37080
|
+
outgoingImageAnimations,
|
|
37081
|
+
overlayIncomingAnimations,
|
|
36331
37082
|
outgoingElements,
|
|
37083
|
+
overlayIncomingElements,
|
|
36332
37084
|
durationMs,
|
|
36333
37085
|
};
|
|
36334
37086
|
}
|
|
@@ -36353,16 +37105,51 @@ function cssAttributeValue(value) {
|
|
|
36353
37105
|
* are unique to the slide being animated and need no ancestor to disambiguate.
|
|
36354
37106
|
* That is what lets a binding whose incoming slide is rendered OUTSIDE the
|
|
36355
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}).
|
|
36356
37111
|
* @returns Keyframes plus the scoped `animation` rules, ready to inject.
|
|
36357
37112
|
*/
|
|
36358
37113
|
function buildMorphScopedCss(plan, scopeAttribute, which = 'incoming') {
|
|
36359
|
-
|
|
37114
|
+
return `${plan.keyframesCss}\n${buildMorphAnimationRules(plan, scopeAttribute, which)}`;
|
|
37115
|
+
}
|
|
37116
|
+
/**
|
|
37117
|
+
* Just the `animation` rules of a plan, with no `@keyframes` block.
|
|
37118
|
+
*
|
|
37119
|
+
* For a binding that already injects {@link MorphTransitionPlan.keyframesCss}
|
|
37120
|
+
* itself and applies the element-level animations some other way (React merges
|
|
37121
|
+
* them into its per-element animation state), but still needs the descendant
|
|
37122
|
+
* rules that {@link MorphTransitionPlan.incomingImageAnimations} cannot be
|
|
37123
|
+
* expressed as an inline style for.
|
|
37124
|
+
*
|
|
37125
|
+
* @param plan - The plan to render.
|
|
37126
|
+
* @param scopeAttribute - As {@link buildMorphScopedCss}.
|
|
37127
|
+
* @param which - Which half of the transition to emit.
|
|
37128
|
+
* @param only - `'image'` emits only the `<img>` descendant rules; omit for all.
|
|
37129
|
+
* @returns The newline-joined rules (no trailing newline); `''` when there are none.
|
|
37130
|
+
*/
|
|
37131
|
+
function buildMorphAnimationRules(plan, scopeAttribute, which = 'incoming', only) {
|
|
36360
37132
|
const prefix = scopeAttribute ? `[${scopeAttribute}] ` : '';
|
|
36361
37133
|
const rules = [];
|
|
36362
|
-
|
|
36363
|
-
|
|
37134
|
+
const emit = (animations, suffix) => {
|
|
37135
|
+
for (const [elementId, animation] of animations) {
|
|
37136
|
+
rules.push(`${prefix}[data-element-id="${cssAttributeValue(elementId)}"]${suffix} { animation: ${animation}; }`);
|
|
37137
|
+
}
|
|
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.
|
|
37142
|
+
if (only !== 'image') {
|
|
37143
|
+
emit(which === 'outgoing'
|
|
37144
|
+
? plan.outgoingAnimations
|
|
37145
|
+
: which === 'lifted'
|
|
37146
|
+
? plan.overlayIncomingAnimations
|
|
37147
|
+
: plan.incomingAnimations, '');
|
|
36364
37148
|
}
|
|
36365
|
-
|
|
37149
|
+
// The picture-crop channel targets the `<img>` the element renders, which
|
|
37150
|
+
// every binding draws inside the `data-element-id` container.
|
|
37151
|
+
emit(which === 'outgoing' ? plan.outgoingImageAnimations : plan.incomingImageAnimations, ' img');
|
|
37152
|
+
return rules.join('\n');
|
|
36366
37153
|
}
|
|
36367
37154
|
|
|
36368
37155
|
/**
|
|
@@ -55467,6 +56254,20 @@ function applyMediaPlaybackAttributes(el, source) {
|
|
|
55467
56254
|
el.volume = attributes.volume;
|
|
55468
56255
|
el.playbackRate = attributes.playbackRate;
|
|
55469
56256
|
}
|
|
56257
|
+
/**
|
|
56258
|
+
* Derive a {@link MediaSurface} from the two flags a binding's renderer carries.
|
|
56259
|
+
*
|
|
56260
|
+
* "Neither interactive nor presenting" is what a STILL of a slide looks like
|
|
56261
|
+
* from inside an element renderer, and all four declarative bindings had spelt
|
|
56262
|
+
* that out by hand - twice each, once per shared media rule. Deriving it once
|
|
56263
|
+
* keeps a binding from quietly answering the two rules differently.
|
|
56264
|
+
*/
|
|
56265
|
+
function mediaSurfaceOf(input) {
|
|
56266
|
+
return {
|
|
56267
|
+
presenting: input.presenting,
|
|
56268
|
+
preview: !input.interactive && !input.presenting,
|
|
56269
|
+
};
|
|
56270
|
+
}
|
|
55470
56271
|
/**
|
|
55471
56272
|
* Whether a media element should carry the browser's native transport.
|
|
55472
56273
|
*
|
|
@@ -55485,6 +56286,115 @@ function mediaTransportVisible(surface) {
|
|
|
55485
56286
|
}
|
|
55486
56287
|
return surface.canvasTransport;
|
|
55487
56288
|
}
|
|
56289
|
+
/**
|
|
56290
|
+
* What a media element paints when it has no playable source.
|
|
56291
|
+
*
|
|
56292
|
+
* WHY this is shared (issue #147): a slide-transition overlay is a STILL of the
|
|
56293
|
+
* outgoing slide, and React's overlay renders it without the media map, so a
|
|
56294
|
+
* full-bleed background video fell back to its poster frame AND to the centred
|
|
56295
|
+
* play badge that goes with it. The badge is authoring chrome, not slide
|
|
56296
|
+
* content, so `solution-explorer.pptx` played a mystery play triangle across
|
|
56297
|
+
* the middle of every morph out of slide 2 - which is exactly what the reporter
|
|
56298
|
+
* caught at 11s. The same class of artefact was one map away in the other four:
|
|
56299
|
+
* their typed "Media" placeholder box is chrome too, and it paints on any still
|
|
56300
|
+
* whose media cannot resolve.
|
|
56301
|
+
*
|
|
56302
|
+
* The rule: a still of a slide - and the show itself - paints slide CONTENT and
|
|
56303
|
+
* nothing else. Only the authoring canvas adds the affordance that says "this
|
|
56304
|
+
* picture is a video you cannot play here".
|
|
56305
|
+
*
|
|
56306
|
+
* `badge` and `placeholder` are unions rather than booleans on purpose. As
|
|
56307
|
+
* booleans, four bindings read "paint a badge" and drew a PLAY triangle over
|
|
56308
|
+
* media the package had failed to find - the opposite of what React said in the
|
|
56309
|
+
* same spot. A union cannot be half-read.
|
|
56310
|
+
*/
|
|
56311
|
+
function mediaFallbackVisual(surface, input) {
|
|
56312
|
+
const contentOnly = surface.presenting || surface.preview;
|
|
56313
|
+
if (contentOnly) {
|
|
56314
|
+
return { poster: input.hasPoster, dimPoster: false, badge: 'none', placeholder: 'none' };
|
|
56315
|
+
}
|
|
56316
|
+
const missing = input.missing === true;
|
|
56317
|
+
// The badge is an overlay ON a poster; with no poster the placeholder box
|
|
56318
|
+
// carries the same icon itself, so exactly one of the two is ever set.
|
|
56319
|
+
if (input.hasPoster) {
|
|
56320
|
+
return {
|
|
56321
|
+
poster: true,
|
|
56322
|
+
dimPoster: missing,
|
|
56323
|
+
badge: missing ? 'missing' : 'play',
|
|
56324
|
+
placeholder: 'none',
|
|
56325
|
+
};
|
|
56326
|
+
}
|
|
56327
|
+
return {
|
|
56328
|
+
poster: false,
|
|
56329
|
+
dimPoster: false,
|
|
56330
|
+
badge: 'none',
|
|
56331
|
+
placeholder: missing ? 'missing' : 'typed',
|
|
56332
|
+
};
|
|
56333
|
+
}
|
|
56334
|
+
/**
|
|
56335
|
+
* The icons the fallback draws, as SVG path `d` strings in a 24x24 `viewBox`,
|
|
56336
|
+
* stroked with `currentColor` over `fill: none`.
|
|
56337
|
+
*
|
|
56338
|
+
* Paths rather than each binding's own `<circle>` / `<polygon>` / `<line>` mix:
|
|
56339
|
+
* one array renders identically through JSX, a Vue/Svelte `for`, an Angular
|
|
56340
|
+
* `@for` and a DOM loop, so the five icons cannot drift apart.
|
|
56341
|
+
*/
|
|
56342
|
+
const MEDIA_FALLBACK_ICONS = {
|
|
56343
|
+
play: ['M5 3 L19 12 L5 21 Z'],
|
|
56344
|
+
missing: ['M12 2 a10 10 0 1 0 0 20 a10 10 0 1 0 0-20', 'M4 4 L20 20'],
|
|
56345
|
+
audio: [
|
|
56346
|
+
'M9 18V5l12-2v13',
|
|
56347
|
+
'M6 15 a3 3 0 1 0 0 6 a3 3 0 1 0 0-6',
|
|
56348
|
+
'M18 13 a3 3 0 1 0 0 6 a3 3 0 1 0 0-6',
|
|
56349
|
+
],
|
|
56350
|
+
};
|
|
56351
|
+
/**
|
|
56352
|
+
* The icon for a resolved {@link MediaFallbackVisual}, or `[]` when the surface
|
|
56353
|
+
* asks for none. An untyped placeholder gets no icon, as React has always done:
|
|
56354
|
+
* the deck never said whether it is a clip or a track.
|
|
56355
|
+
*/
|
|
56356
|
+
function mediaFallbackIcon(visual, mediaType) {
|
|
56357
|
+
if (visual.badge === 'missing' || visual.placeholder === 'missing') {
|
|
56358
|
+
return MEDIA_FALLBACK_ICONS.missing;
|
|
56359
|
+
}
|
|
56360
|
+
if (visual.badge === 'play') {
|
|
56361
|
+
return MEDIA_FALLBACK_ICONS.play;
|
|
56362
|
+
}
|
|
56363
|
+
if (visual.placeholder === 'typed') {
|
|
56364
|
+
if (mediaType === 'audio') {
|
|
56365
|
+
return MEDIA_FALLBACK_ICONS.audio;
|
|
56366
|
+
}
|
|
56367
|
+
if (mediaType === 'video') {
|
|
56368
|
+
return MEDIA_FALLBACK_ICONS.play;
|
|
56369
|
+
}
|
|
56370
|
+
}
|
|
56371
|
+
return [];
|
|
56372
|
+
}
|
|
56373
|
+
/**
|
|
56374
|
+
* The i18n key labelling a resolved {@link MediaFallbackVisual}, or `undefined`
|
|
56375
|
+
* when it carries no label (the play badge is a bare triangle).
|
|
56376
|
+
*
|
|
56377
|
+
* Shared because the five disagreed: React hard-coded the English words "Video"
|
|
56378
|
+
* and "Audio" - untranslated, in a package that ships four locales - while the
|
|
56379
|
+
* other four labelled every unplayable element the same flat "Media", whatever
|
|
56380
|
+
* the deck said it was.
|
|
56381
|
+
*/
|
|
56382
|
+
function mediaFallbackLabelKey(visual, mediaType) {
|
|
56383
|
+
if (visual.badge === 'missing' || visual.placeholder === 'missing') {
|
|
56384
|
+
return 'pptx.media.notFound';
|
|
56385
|
+
}
|
|
56386
|
+
if (visual.placeholder !== 'typed') {
|
|
56387
|
+
return undefined;
|
|
56388
|
+
}
|
|
56389
|
+
if (mediaType === 'video') {
|
|
56390
|
+
return 'pptx.media.videoClip';
|
|
56391
|
+
}
|
|
56392
|
+
if (mediaType === 'audio') {
|
|
56393
|
+
return 'pptx.media.audioClip';
|
|
56394
|
+
}
|
|
56395
|
+
return 'pptx.elementType.media';
|
|
56396
|
+
}
|
|
56397
|
+
const MEDIA_CHROME_ATTRIBUTE = 'data-pptx-media-chrome';
|
|
55488
56398
|
|
|
55489
56399
|
/**
|
|
55490
56400
|
* Persistent audio manager: keeps "play across slides" audio alive when the
|
|
@@ -63911,7 +64821,7 @@ function createLocalStorageBackend(namespace) {
|
|
|
63911
64821
|
/** Try IndexedDB first; fall back to localStorage on any failure. */
|
|
63912
64822
|
async function resolveBackend(dbName, namespace) {
|
|
63913
64823
|
try {
|
|
63914
|
-
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');
|
|
63915
64825
|
const db = await openChatDb(dbName);
|
|
63916
64826
|
return createIdbBackend(db);
|
|
63917
64827
|
}
|
|
@@ -75917,6 +76827,26 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
75917
76827
|
* `media-render.tsx` / `media-persistent-audio.tsx`. Kept TestBed-free so the
|
|
75918
76828
|
* source resolution + media-fragment maths can be unit-tested directly.
|
|
75919
76829
|
*/
|
|
76830
|
+
/** Which surface {@link MediaRendererComponent} is painting on. */
|
|
76831
|
+
function mediaSurfaceFor(interactive, presenting) {
|
|
76832
|
+
return mediaSurfaceOf({ interactive, presenting });
|
|
76833
|
+
}
|
|
76834
|
+
/**
|
|
76835
|
+
* What the template paints when no `<video>`/`<audio>` can be mounted.
|
|
76836
|
+
*
|
|
76837
|
+
* A still of a slide - the slide-transition overlay, the presenter console's
|
|
76838
|
+
* panes, the thumbnail rail - gets the poster frame and nothing else: the play
|
|
76839
|
+
* badge and the typed placeholder box are authoring chrome, and issue #147 is
|
|
76840
|
+
* exactly that chrome riding along inside a morph. Factored out of the template
|
|
76841
|
+
* so its `@if`s can be asserted without a TestBed, as this package does
|
|
76842
|
+
* elsewhere (see `action-settings-panel.component.test.ts`).
|
|
76843
|
+
*/
|
|
76844
|
+
function mediaFallbackFor(el, hasPoster, surface) {
|
|
76845
|
+
return mediaFallbackVisual(surface, {
|
|
76846
|
+
hasPoster,
|
|
76847
|
+
missing: asMediaElement(el)?.mediaMissing === true,
|
|
76848
|
+
});
|
|
76849
|
+
}
|
|
75920
76850
|
/** Narrow a generic element to `MediaPptxElement`, or `undefined`. */
|
|
75921
76851
|
function asMediaElement(el) {
|
|
75922
76852
|
return el.type === 'media' ? el : undefined;
|
|
@@ -76109,12 +77039,35 @@ class MediaRendererComponent {
|
|
|
76109
77039
|
* for the same reason). React paints one on its canvas; that difference is
|
|
76110
77040
|
* deliberate and is the only thing the shared rule leaves to the binding.
|
|
76111
77041
|
*/
|
|
76112
|
-
showControls = computed(() => mediaTransportVisible({
|
|
76113
|
-
presenting: this.presenting(),
|
|
76114
|
-
preview: !this.interactive() && !this.presenting(),
|
|
76115
|
-
canvasTransport: false,
|
|
76116
|
-
}), /* @ts-ignore */
|
|
77042
|
+
showControls = computed(() => mediaTransportVisible({ ...this.surface(), canvasTransport: false }), /* @ts-ignore */
|
|
76117
77043
|
...(ngDevMode ? [{ debugName: "showControls" }] : /* istanbul ignore next */ []));
|
|
77044
|
+
/**
|
|
77045
|
+
* Which surface this renderer is painting on: the live show stage, a STILL of
|
|
77046
|
+
* a slide (the transition overlay, the presenter console's panes, the
|
|
77047
|
+
* thumbnail rail), or the authoring canvas.
|
|
77048
|
+
*/
|
|
77049
|
+
surface = computed(() => mediaSurfaceFor(this.interactive(), this.presenting()), /* @ts-ignore */
|
|
77050
|
+
...(ngDevMode ? [{ debugName: "surface" }] : /* istanbul ignore next */ []));
|
|
77051
|
+
/**
|
|
77052
|
+
* What to paint when no `<video>`/`<audio>` can be mounted.
|
|
77053
|
+
*
|
|
77054
|
+
* A still of a slide - the slide-transition overlay, the presenter console's
|
|
77055
|
+
* panes, the thumbnail rail - gets the poster frame and nothing else: the
|
|
77056
|
+
* play badge and the typed placeholder box are authoring chrome, and issue
|
|
77057
|
+
* #147 is exactly that chrome riding along inside a morph. Shared, so the
|
|
77058
|
+
* five bindings cannot drift on it.
|
|
77059
|
+
*/
|
|
77060
|
+
fallback = computed(() => mediaFallbackFor(this.element(), Boolean(this.poster()), this.surface()), /* @ts-ignore */
|
|
77061
|
+
...(ngDevMode ? [{ debugName: "fallback" }] : /* istanbul ignore next */ []));
|
|
77062
|
+
/** The shared icon paths and resolved label for whatever the fallback is. */
|
|
77063
|
+
fallbackIcon = computed(() => mediaFallbackIcon(this.fallback(), this.mediaKind()), /* @ts-ignore */
|
|
77064
|
+
...(ngDevMode ? [{ debugName: "fallbackIcon" }] : /* istanbul ignore next */ []));
|
|
77065
|
+
translate = inject(TranslateService);
|
|
77066
|
+
fallbackLabel = computed(() => {
|
|
77067
|
+
const key = mediaFallbackLabelKey(this.fallback(), this.mediaKind());
|
|
77068
|
+
return key === undefined ? '' : this.translate.instant(key);
|
|
77069
|
+
}, /* @ts-ignore */
|
|
77070
|
+
...(ngDevMode ? [{ debugName: "fallbackLabel" }] : /* istanbul ignore next */ []));
|
|
76118
77071
|
containerStyle = computed(() => getContainerStyle(this.element(), this.zIndex()), /* @ts-ignore */
|
|
76119
77072
|
...(ngDevMode ? [{ debugName: "containerStyle" }] : /* istanbul ignore next */ []));
|
|
76120
77073
|
/** Poster / preview frame data-URL (also used as the `<video poster>`). */
|
|
@@ -76181,22 +77134,57 @@ class MediaRendererComponent {
|
|
|
76181
77134
|
}
|
|
76182
77135
|
</video>
|
|
76183
77136
|
}
|
|
76184
|
-
} @else if (poster(); as posterSrc) {
|
|
77137
|
+
} @else if (fallback().poster && poster(); as posterSrc) {
|
|
76185
77138
|
@if (clrChangeParams(); as cc) {
|
|
76186
77139
|
<pptx-color-changed-image
|
|
76187
77140
|
[src]="posterSrc"
|
|
76188
77141
|
[clrChange]="cc"
|
|
76189
77142
|
alt=""
|
|
76190
|
-
imgClass="pptx-ng-img"
|
|
77143
|
+
[imgClass]="fallback().dimPoster ? 'pptx-ng-img pptx-ng-media-dim' : 'pptx-ng-img'"
|
|
76191
77144
|
/>
|
|
76192
77145
|
} @else {
|
|
76193
|
-
<img
|
|
77146
|
+
<img
|
|
77147
|
+
[src]="posterSrc"
|
|
77148
|
+
alt=""
|
|
77149
|
+
class="pptx-ng-img"
|
|
77150
|
+
[class.pptx-ng-media-dim]="fallback().dimPoster"
|
|
77151
|
+
/>
|
|
76194
77152
|
}
|
|
76195
|
-
|
|
76196
|
-
|
|
77153
|
+
<!-- Authoring-canvas chrome only; data-pptx-media-chrome is the neutral
|
|
77154
|
+
marker e2e/media-transition-chrome.spec.ts asserts the absence of. -->
|
|
77155
|
+
@if (fallback().badge !== 'none') {
|
|
77156
|
+
<div
|
|
77157
|
+
[attr.data-pptx-media-chrome]="fallback().badge"
|
|
77158
|
+
class="pptx-ng-media-badge"
|
|
77159
|
+
[class.pptx-ng-media-badge-missing]="fallback().badge === 'missing'"
|
|
77160
|
+
>
|
|
77161
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
77162
|
+
@for (d of fallbackIcon(); track d) {
|
|
77163
|
+
<path [attr.d]="d" />
|
|
77164
|
+
}
|
|
77165
|
+
</svg>
|
|
77166
|
+
@if (fallback().badge === 'missing') {
|
|
77167
|
+
<span>{{ fallbackLabel() }}</span>
|
|
77168
|
+
}
|
|
77169
|
+
</div>
|
|
77170
|
+
}
|
|
77171
|
+
} @else if (fallback().placeholder !== 'none') {
|
|
77172
|
+
<div
|
|
77173
|
+
class="pptx-ng-placeholder pptx-ng-media-placeholder"
|
|
77174
|
+
[attr.data-pptx-media-chrome]="fallback().placeholder"
|
|
77175
|
+
>
|
|
77176
|
+
@if (fallbackIcon().length > 0) {
|
|
77177
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
77178
|
+
@for (d of fallbackIcon(); track d) {
|
|
77179
|
+
<path [attr.d]="d" />
|
|
77180
|
+
}
|
|
77181
|
+
</svg>
|
|
77182
|
+
}
|
|
77183
|
+
<span>{{ fallbackLabel() }}</span>
|
|
77184
|
+
</div>
|
|
76197
77185
|
}
|
|
76198
77186
|
</div>
|
|
76199
|
-
`, isInline: true, styles: [".pptx-ng-media-el{display:block;pointer-events:auto}.pptx-ng-media-video{width:100%;height:100%;object-fit:contain}.pptx-ng-media-audio{width:100%}.pptx-ng-media-inert{pointer-events:none}.pptx-ng-img{width:100%;height:100%;object-fit:contain;display:block}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ColorChangedImageComponent, selector: "pptx-color-changed-image", inputs: ["src", "clrChange", "alt", "imgClass", "imgStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
77187
|
+
`, isInline: true, styles: [".pptx-ng-media-el{display:block;pointer-events:auto}.pptx-ng-media-video{width:100%;height:100%;object-fit:contain}.pptx-ng-media-audio{width:100%}.pptx-ng-media-inert{pointer-events:none}.pptx-ng-img{width:100%;height:100%;object-fit:contain;display:block}.pptx-ng-media-dim{opacity:.5}.pptx-ng-media-badge{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;font-size:10px;color:#fffc;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));pointer-events:none}.pptx-ng-media-badge svg{width:48px;height:48px}.pptx-ng-media-badge-missing{color:#fff9}.pptx-ng-media-badge-missing svg{width:32px;height:32px}.pptx-ng-media-placeholder{flex-direction:column;gap:4px;font-size:10px}.pptx-ng-media-placeholder svg{width:32px;height:32px}\n"], dependencies: [{ kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: ColorChangedImageComponent, selector: "pptx-color-changed-image", inputs: ["src", "clrChange", "alt", "imgClass", "imgStyle"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
76200
77188
|
}
|
|
76201
77189
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: MediaRendererComponent, decorators: [{
|
|
76202
77190
|
type: Component,
|
|
@@ -76241,22 +77229,57 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
76241
77229
|
}
|
|
76242
77230
|
</video>
|
|
76243
77231
|
}
|
|
76244
|
-
} @else if (poster(); as posterSrc) {
|
|
77232
|
+
} @else if (fallback().poster && poster(); as posterSrc) {
|
|
76245
77233
|
@if (clrChangeParams(); as cc) {
|
|
76246
77234
|
<pptx-color-changed-image
|
|
76247
77235
|
[src]="posterSrc"
|
|
76248
77236
|
[clrChange]="cc"
|
|
76249
77237
|
alt=""
|
|
76250
|
-
imgClass="pptx-ng-img"
|
|
77238
|
+
[imgClass]="fallback().dimPoster ? 'pptx-ng-img pptx-ng-media-dim' : 'pptx-ng-img'"
|
|
76251
77239
|
/>
|
|
76252
77240
|
} @else {
|
|
76253
|
-
<img
|
|
77241
|
+
<img
|
|
77242
|
+
[src]="posterSrc"
|
|
77243
|
+
alt=""
|
|
77244
|
+
class="pptx-ng-img"
|
|
77245
|
+
[class.pptx-ng-media-dim]="fallback().dimPoster"
|
|
77246
|
+
/>
|
|
76254
77247
|
}
|
|
76255
|
-
|
|
76256
|
-
|
|
77248
|
+
<!-- Authoring-canvas chrome only; data-pptx-media-chrome is the neutral
|
|
77249
|
+
marker e2e/media-transition-chrome.spec.ts asserts the absence of. -->
|
|
77250
|
+
@if (fallback().badge !== 'none') {
|
|
77251
|
+
<div
|
|
77252
|
+
[attr.data-pptx-media-chrome]="fallback().badge"
|
|
77253
|
+
class="pptx-ng-media-badge"
|
|
77254
|
+
[class.pptx-ng-media-badge-missing]="fallback().badge === 'missing'"
|
|
77255
|
+
>
|
|
77256
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
77257
|
+
@for (d of fallbackIcon(); track d) {
|
|
77258
|
+
<path [attr.d]="d" />
|
|
77259
|
+
}
|
|
77260
|
+
</svg>
|
|
77261
|
+
@if (fallback().badge === 'missing') {
|
|
77262
|
+
<span>{{ fallbackLabel() }}</span>
|
|
77263
|
+
}
|
|
77264
|
+
</div>
|
|
77265
|
+
}
|
|
77266
|
+
} @else if (fallback().placeholder !== 'none') {
|
|
77267
|
+
<div
|
|
77268
|
+
class="pptx-ng-placeholder pptx-ng-media-placeholder"
|
|
77269
|
+
[attr.data-pptx-media-chrome]="fallback().placeholder"
|
|
77270
|
+
>
|
|
77271
|
+
@if (fallbackIcon().length > 0) {
|
|
77272
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5">
|
|
77273
|
+
@for (d of fallbackIcon(); track d) {
|
|
77274
|
+
<path [attr.d]="d" />
|
|
77275
|
+
}
|
|
77276
|
+
</svg>
|
|
77277
|
+
}
|
|
77278
|
+
<span>{{ fallbackLabel() }}</span>
|
|
77279
|
+
</div>
|
|
76257
77280
|
}
|
|
76258
77281
|
</div>
|
|
76259
|
-
`, styles: [".pptx-ng-media-el{display:block;pointer-events:auto}.pptx-ng-media-video{width:100%;height:100%;object-fit:contain}.pptx-ng-media-audio{width:100%}.pptx-ng-media-inert{pointer-events:none}.pptx-ng-img{width:100%;height:100%;object-fit:contain;display:block}\n"] }]
|
|
77282
|
+
`, styles: [".pptx-ng-media-el{display:block;pointer-events:auto}.pptx-ng-media-video{width:100%;height:100%;object-fit:contain}.pptx-ng-media-audio{width:100%}.pptx-ng-media-inert{pointer-events:none}.pptx-ng-img{width:100%;height:100%;object-fit:contain;display:block}.pptx-ng-media-dim{opacity:.5}.pptx-ng-media-badge{position:absolute;inset:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:4px;font-size:10px;color:#fffc;filter:drop-shadow(0 1px 2px rgba(0,0,0,.5));pointer-events:none}.pptx-ng-media-badge svg{width:48px;height:48px}.pptx-ng-media-badge-missing{color:#fff9}.pptx-ng-media-badge-missing svg{width:32px;height:32px}.pptx-ng-media-placeholder{flex-direction:column;gap:4px;font-size:10px}.pptx-ng-media-placeholder svg{width:32px;height:32px}\n"] }]
|
|
76260
77283
|
}], ctorParameters: () => [], propDecorators: { element: [{ type: i0.Input, args: [{ isSignal: true, alias: "element", required: true }] }], mediaDataUrls: [{ type: i0.Input, args: [{ isSignal: true, alias: "mediaDataUrls", required: false }] }], zIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "zIndex", required: false }] }], interactive: [{ type: i0.Input, args: [{ isSignal: true, alias: "interactive", required: false }] }], marked: [{ type: i0.Input, args: [{ isSignal: true, alias: "marked", required: false }] }], presenting: [{ type: i0.Input, args: [{ isSignal: true, alias: "presenting", required: false }] }], placeholderLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholderLabel", required: false }] }], mediaElRef: [{ type: i0.ViewChild, args: ['mediaEl', { isSignal: true }] }] } });
|
|
76261
77284
|
|
|
76262
77285
|
/**
|
|
@@ -78176,8 +79199,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
78176
79199
|
* `sz` overrides the (already scaled) body font-size, so without it a
|
|
78177
79200
|
* shrink-to-fit title painted at full size.
|
|
78178
79201
|
*/
|
|
78179
|
-
function runStyleFromSegment(seg, fontScale = 1) {
|
|
78180
|
-
const style = segmentStyleToCss(seg, fontScale);
|
|
79202
|
+
function runStyleFromSegment(seg, fontScale = 1, blockFont, text) {
|
|
79203
|
+
const style = segmentStyleToCss(seg, fontScale, { text, blockFont });
|
|
78181
79204
|
const s = seg.style;
|
|
78182
79205
|
if (s) {
|
|
78183
79206
|
const isDoubleStrike = Boolean(s.strikethrough && s.strikeType === 'dblStrike');
|
|
@@ -78506,6 +79529,15 @@ class ElementRendererComponent {
|
|
|
78506
79529
|
// run's own `sz` overrides the (already scaled) body font-size. Mirrors
|
|
78507
79530
|
// shared `buildParagraphs` and React's `renderSingleSegment`.
|
|
78508
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
|
+
};
|
|
78509
79541
|
const paragraphIndents = el.paragraphIndents;
|
|
78510
79542
|
const out = [{ runs: [], bulletStyle: {}, indentPx: 0 }];
|
|
78511
79543
|
let paraStarted = false;
|
|
@@ -78624,12 +79656,20 @@ class ElementRendererComponent {
|
|
|
78624
79656
|
: rawText;
|
|
78625
79657
|
if (text) {
|
|
78626
79658
|
const href = resolveHyperlinkHref(seg.style?.hyperlink);
|
|
78627
|
-
|
|
78628
|
-
|
|
78629
|
-
|
|
78630
|
-
|
|
78631
|
-
|
|
78632
|
-
|
|
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
|
+
}
|
|
78633
79673
|
}
|
|
78634
79674
|
}
|
|
78635
79675
|
// A paragraph that already matches the body default needs no re-basing.
|
|
@@ -88600,6 +89640,25 @@ function ensureTransitionKeyframes() {
|
|
|
88600
89640
|
|
|
88601
89641
|
/** Safety margin (ms) added to the animation duration before firing complete. */
|
|
88602
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
|
+
}
|
|
88603
89662
|
/**
|
|
88604
89663
|
* PresentationTransitionOverlayComponent: plays a PowerPoint slide transition
|
|
88605
89664
|
* over the presentation stage.
|
|
@@ -88695,6 +89754,9 @@ class PresentationTransitionOverlayComponent {
|
|
|
88695
89754
|
? [
|
|
88696
89755
|
buildMorphScopedCss(plan, '', 'incoming'),
|
|
88697
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'),
|
|
88698
89760
|
].join('\n')
|
|
88699
89761
|
: null);
|
|
88700
89762
|
});
|
|
@@ -88783,6 +89845,14 @@ class PresentationTransitionOverlayComponent {
|
|
|
88783
89845
|
return { ...slide, elements: [...template, ...slide.elements] };
|
|
88784
89846
|
}, /* @ts-ignore */
|
|
88785
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 */ []));
|
|
88786
89856
|
/** Layer container style: animation + stacking relative to the stage. */
|
|
88787
89857
|
layerStyle = computed(() => {
|
|
88788
89858
|
const anims = this.animations();
|
|
@@ -88855,7 +89925,7 @@ class PresentationTransitionOverlayComponent {
|
|
|
88855
89925
|
}
|
|
88856
89926
|
}
|
|
88857
89927
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PresentationTransitionOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
88858
|
-
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: `
|
|
88859
89929
|
<div
|
|
88860
89930
|
class="pptx-ng-transition-layer"
|
|
88861
89931
|
data-pptx-transition-layer="outgoing"
|
|
@@ -88874,6 +89944,30 @@ class PresentationTransitionOverlayComponent {
|
|
|
88874
89944
|
/>
|
|
88875
89945
|
</div>
|
|
88876
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
|
+
}
|
|
88877
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 });
|
|
88878
89972
|
}
|
|
88879
89973
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImport: i0, type: PresentationTransitionOverlayComponent, decorators: [{
|
|
@@ -88897,6 +89991,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
88897
89991
|
/>
|
|
88898
89992
|
</div>
|
|
88899
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
|
+
}
|
|
88900
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"] }]
|
|
88901
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"] }] } });
|
|
88902
90020
|
|
|
@@ -95459,7 +96577,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.0", ngImpor
|
|
|
95459
96577
|
}], propDecorators: { canEdit: [{ type: i0.Input, args: [{ isSignal: true, alias: "canEdit", required: false }] }], slideIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "slideIndex", required: false }] }] } });
|
|
95460
96578
|
|
|
95461
96579
|
// Generated by scripts/inline-shared.mjs from package.json. Do not edit.
|
|
95462
|
-
const PPTX_ANGULAR_VIEWER_VERSION = "2.
|
|
96580
|
+
const PPTX_ANGULAR_VIEWER_VERSION = "2.17.1";
|
|
95463
96581
|
|
|
95464
96582
|
/**
|
|
95465
96583
|
* account-page.component.ts: File > Account content.
|
|
@@ -127396,5 +128514,5 @@ function cn(...values) {
|
|
|
127396
128514
|
* Generated bundle index. Do not edit.
|
|
127397
128515
|
*/
|
|
127398
128516
|
|
|
127399
|
-
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, pickFile 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, nextVisibleIndex as iA, nodeBold as iB, nodeEditBox as iC, nodeFillColor as iD, nodeFontColor as iE, nodeIdFromKey as iF, nodeItalic as iG, nodeStyle as iH, normalizeFontFormat as iI, normalizeSlidesPerPage as iJ, normalizeValue as iK, numFromEvent as iL, ommlToMathml as iM, ooxmlDashToCssBorderStyle as iN, openNativeEyeDropper as iO, overallStatus as iP, paletteColor as iQ, parseAudienceNonce as iR, parseNodeTextarea as iS, partitionSlides as iT, patchChartData as iU, patchChartStyle as iV, patchTableData as iW, patchTextStyle as iX, patternPresetOptions as iY, pendingElementStyles as iZ, pickColorByClickFallback as i_, lastVisibleIndex as ia, latexToMathml as ib, linePointsToSvgString as ic, lineSpacingPatch as id, loadAudienceContent as ie, loadSessionDeck as ig, mergeCaptionResults as ih, mergeDown as ii, mergeRight as ij, mergeSelection as ik, moveElementBy as il, moveNodeDown as im, moveNodeUp as io, msToFrameDelayCs as ip, narrowToCircle as iq, narrowToPolygon as ir, narrowToRect as is, newChartElement as it, newEquationElement as iu, newPresetShapeElement as iv, newShapeElement as iw, newSmartArtElement as ix, newTableElement as iy, newTextElement as iz, AdvancedChartEditorComponent as j, saveViewerProfile as j$, pickSupportedMimeType as j0, planGifFrames as j1, planVideoSegments as j2, pointsToSvgPathD as j3, presenceToCursors as j4, presentationStageStyle as j5, presenterTimerProgress as j6, presetByLayout as j7, presetsForCategory as j8, pressuresToWidths as j9, resizeElement as jA, resolveCaptionTracks as jB, resolveChartKind as jC, resolveFontVariant as jD, resolveHyperlinkHref as jE, resolveInteractiveElementId as jF, resolveMediaSrc as jG, resolveOleType as jH, resolveParagraphBullet as jI, resolvePresenterNotes as jJ, resolveProfileInitial as jK, resolveRegionCode as jL, resolveSlideAutoAdvanceMs as jM, resolvePalette as jN, resolveThemeCatalogEntry as jO, resolveTransitionDuration as jP, restoreSessionDeck as jQ, revealedElementStyles as jR, routeOrthogonalConnector as jS, rowStyle as jT, rulerDragToGuidePosition as jU, rulerHighlight as jV, rulerStripTicks as jW, sampleColorFromSlide as jX, sanitizeColor as jY, sanitizeSlideIndex as jZ, sanitizeUserName as j_, prevVisibleIndex as ja, projectDrawingShapes as jb, promoteNode as jc, provideViewerTheme as jd, radarAngle as je, radarRingPoints as jf, readAsDataUrl as jg, recordWebm as jh, redistributeColumnWidth as ji, registerCrossSlideAudio as jj, rememberSessionDeck as jk, removeAnimation as jl, removeCategory as jm, removeTableElementColumn as jn, removeCommentFromList as jo, removeElementAnimation as jp, removeGradientStopPatch as jq, removeNode as jr, removeTableElementRow as js, removeSeries as jt, renderToCanvas as ju, reorderAnimationDown as jv, reorderAnimationUp as jw, replaceInSlides as jx, replaceMatch as jy, requestPresentationFullscreen as jz, AiChangeOverlayComponent as k, smartArtNodes as k$, scanAvailableFonts as k0, searchSlides as k1, seedBroadcastFields as k2, seedHyperlinkDraft as k3, seedPropertiesDraft as k4, seedShareFields as k5, segmentFrameCount as k6, selectValue$2 as k7, sendBackward as k8, sendToBack as k9, setRepeatCount as kA, setRepeatMode as kB, setSequence as kC, setSeriesChartType as kD, setSeriesColor as kE, setSeriesErrorBars as kF, setSeriesMarker as kG, setSeriesName as kH, setSeriesTrendline as kI, setSeriesValue as kJ, setStyle as kK, setTimingCurve as kL, setTitle as kM, setTrigger as kN, setTriggerShapeId as kO, shapeStylePatch as kP, sheetAfterNavigate as kQ, shouldBlockClickAdvance as kR, shouldUseSvgWarp as kS, showDirectionPicker as kT, showsTemplateAffordance as kU, signatureCountLabel as kV, signatureKey as kW, signatureTimestamp as kX, signerName as kY, statusLabel as kZ, slideNumberOf as k_, sequentialColorScale as ka, serializeWriteBack as kb, seriesColor as kc, setAnimationEmphasis as kd, setAnimationEntrance as ke, setAnimationExit as kf, setAxis as kg, setAxisLogScale as kh, setAxisTitleStyle as ki, setCategoryLabel as kj, setCellText as kk, setColorScheme as kl, setDataLabels as km, setDataPointExplosion as kn, setDataPointFill as ko, setDataPointLabel as kp, setDataPointMarker as kq, setDelay as kr, setDirection as ks, setDuration as kt, setElementPosition as ku, setGridlineStyle as kv, setLayout as kw, setLegend as kx, setNodeStyle as ky, setNodeText as kz, AiChatPanelComponent as l, paletteColour as l0, snapToGridStep as l1, splitCursorCell as l2, splitMergedCell as l3, statusKind as l4, statusLabel$1 as l5, storeAudienceContent as l6, stringFromEvent$5 as l7, strokeColorOf as l8, strokeToInkElement as l9, updateReflectionPatch as lA, vAlignPatch as lB, validatePassword as lC, validatePrintSettings as lD, validateRoomId as lE, valueToY as lF, vermilionDarkColors as lG, vermilionDarkTheme as lH, vermilionLightColors as lI, vermilionLightTheme as lJ, vermilionRadius as lK, waypointsToPathD as lL, worstStatus as lM, zoomTargetSlideIndex as lN, strokeWidthOf as la, styleShadowFilter as lb, textAdvancedPatch as lc, textAdvancedStateFromStyle as ld, textAdvancedStateOf as le, textColorOf as lf, textDirectionPatch as lg, textStyleOf as lh, textStylePatch as li, themeStyle as lj, themeToCssVars as lk, thumbnailHeight as ll, thumbnailZoom as lm, toggleCommentResolvedInList as ln, toggleNodeBold as lo, toggleNodeItalic as lp, toggleSheet as lq, topLevelNodeCount as lr, transformSelectedTextCase as ls, translationsEn as lt, ungroupElements as lu, updateElementById as lv, updateGlowPatch as lw, updateGradientStopPatch as lx, updateInnerShadowPatch as ly, updateOuterShadowPatch 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 };
|
|
127400
|
-
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-
|
|
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 };
|
|
128518
|
+
//# sourceMappingURL=pptx-angular-viewer-pptx-angular-viewer-0Jy3I4UO.mjs.map
|