@bendyline/squisq 2.13.2 → 2.13.3
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/dist/{Doc-CYTLtFEu.d.ts → Doc-BPhdJFS_.d.ts} +33 -2
- package/dist/{ImageEditDoc-DZ4k_O10.d.ts → ImageEditDoc-DDx-sw_S.d.ts} +1 -1
- package/dist/{chunk-YY3OQ3MI.js → chunk-5FUBK3DK.js} +234 -216
- package/dist/{chunk-HE3HQZWU.js → chunk-6NWVLLMI.js} +104 -1
- package/dist/{chunk-3A6YM375.js → chunk-D3JQMZUT.js} +8 -8
- package/dist/chunk-DOOUVVOM.js +78 -0
- package/dist/{chunk-56TW6HE6.js → chunk-F3LRTRST.js} +15 -10
- package/dist/{chunk-7ZXCS3UU.js → chunk-JFJZ4NS6.js} +2 -2
- package/dist/{chunk-2GN67Q2T.js → chunk-JOBMPMY5.js} +1 -1
- package/dist/{chunk-HGCIIXHP.js → chunk-POZCKPCO.js} +235 -4
- package/dist/{chunk-FUQYQWQR.js → chunk-VX7MPZOK.js} +5 -5
- package/dist/doc/index.d.ts +94 -14
- package/dist/doc/index.js +15 -7
- package/dist/fence/index.d.ts +1 -1
- package/dist/generate/index.d.ts +1 -1
- package/dist/imageEdit/index.d.ts +3 -3
- package/dist/index.d.ts +5 -5
- package/dist/index.js +25 -17
- package/dist/jsonForm/index.d.ts +1 -1
- package/dist/markdown/index.js +11 -12
- package/dist/{materializePageSection-CDps_xUd.d.ts → materializePageSection-DnQi-0TA.d.ts} +1 -1
- package/dist/mediaEdit/index.d.ts +2 -2
- package/dist/narration/index.d.ts +1 -1
- package/dist/narration/index.js +5 -5
- package/dist/recommend/index.js +3 -2
- package/dist/schemas/index.d.ts +4 -4
- package/dist/{themeLibrary-CMm_jh3a.d.ts → themeLibrary-DM7eSK1w.d.ts} +1 -1
- package/dist/timing/index.d.ts +1 -1
- package/dist/transform/index.d.ts +2 -2
- package/dist/transform/index.js +6 -6
- package/package.json +1 -1
- package/dist/chunk-Y25EJEZN.js +0 -178
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
extractEmbeddedVideos,
|
|
11
11
|
extractHostedVideos,
|
|
12
12
|
extractImages,
|
|
13
|
+
extractMediaFromContents,
|
|
13
14
|
extractRichListItems,
|
|
14
15
|
extractTableFromContents,
|
|
15
16
|
isEligibleAsciiFenceLang,
|
|
@@ -19,15 +20,19 @@ import {
|
|
|
19
20
|
isExplicitTimelineLang,
|
|
20
21
|
isExplicitTreeLang,
|
|
21
22
|
isMaterializedMediaNode,
|
|
23
|
+
isMediaAnnotationName,
|
|
22
24
|
isPictureFence,
|
|
25
|
+
isPictureParagraph,
|
|
23
26
|
markdownBlockSeparatorLines,
|
|
27
|
+
parseAnnotationInner,
|
|
24
28
|
parseAsciiDiagram,
|
|
25
29
|
parseAsciiTimeline,
|
|
30
|
+
parseStandaloneAnnotation,
|
|
26
31
|
pickAutoTemplate,
|
|
27
32
|
profileBlockContents,
|
|
28
33
|
renderMarkdownBlocksHtml,
|
|
29
34
|
treeToTemplateData
|
|
30
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-POZCKPCO.js";
|
|
31
36
|
import {
|
|
32
37
|
anchorPoint,
|
|
33
38
|
base64ToUtf8,
|
|
@@ -58,33 +63,25 @@ import {
|
|
|
58
63
|
validateTheme,
|
|
59
64
|
withAlpha
|
|
60
65
|
} from "./chunk-WNEH3BZP.js";
|
|
61
|
-
import {
|
|
62
|
-
mediaEditValuesFromAttributes,
|
|
63
|
-
mediaEditValuesFromParams,
|
|
64
|
-
parseMediaEdits
|
|
65
|
-
} from "./chunk-L7QZORLB.js";
|
|
66
66
|
import {
|
|
67
67
|
TABLE_FED_TEMPLATES,
|
|
68
68
|
isContainerTemplate,
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
splitKeyValueToken,
|
|
72
|
-
tokenizeAttrTokens
|
|
73
|
-
} from "./chunk-Y25EJEZN.js";
|
|
69
|
+
resolveTemplateName
|
|
70
|
+
} from "./chunk-DOOUVVOM.js";
|
|
74
71
|
import {
|
|
75
72
|
KNOWN_BLOCK_META_KEYS,
|
|
76
73
|
coerceAnnotationValues,
|
|
77
74
|
extractPlainText,
|
|
78
75
|
isSvgIslandLang,
|
|
79
76
|
isVideoEmbedUrl,
|
|
77
|
+
matchTrailingTemplateAnnotation,
|
|
80
78
|
mediaKindForUrl,
|
|
81
79
|
parseNumber,
|
|
82
80
|
parseSvgIsland,
|
|
83
|
-
parseTimeSeconds,
|
|
84
81
|
parseVideoEmbedUrl,
|
|
85
82
|
readFrontmatterThemeId,
|
|
86
83
|
walkMarkdownTree
|
|
87
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-6NWVLLMI.js";
|
|
88
85
|
import {
|
|
89
86
|
resolveBlockTransition
|
|
90
87
|
} from "./chunk-P53Z4RYC.js";
|
|
@@ -2965,6 +2962,17 @@ function rightFeature(input, context) {
|
|
|
2965
2962
|
return buildFeatureLayers(input, context, "right");
|
|
2966
2963
|
}
|
|
2967
2964
|
|
|
2965
|
+
// src/doc/templates/mediaFeatureBlock.ts
|
|
2966
|
+
function topFeature(input, context) {
|
|
2967
|
+
return contentBlock({ ...input, template: "content" }, context, { omitPictures: true });
|
|
2968
|
+
}
|
|
2969
|
+
function bottomFeature(input, context) {
|
|
2970
|
+
return contentBlock({ ...input, template: "content" }, context, { omitPictures: true });
|
|
2971
|
+
}
|
|
2972
|
+
function mediaOnly(input, context) {
|
|
2973
|
+
return contentBlock({ ...input, template: "content" }, context);
|
|
2974
|
+
}
|
|
2975
|
+
|
|
2968
2976
|
// src/doc/templates/mapBlock.ts
|
|
2969
2977
|
function mapBlock(input, context) {
|
|
2970
2978
|
const {
|
|
@@ -5524,6 +5532,30 @@ var BLOCK_MEDIA_LAYOUT_POLICIES = {
|
|
|
5524
5532
|
additionalMediaLayout: "overlay-inset",
|
|
5525
5533
|
unconsumedMedia: "retain-native-layout"
|
|
5526
5534
|
},
|
|
5535
|
+
topFeature: {
|
|
5536
|
+
summary: "Body media spans the full width across the top; the heading and complete body take a band below sized to the text. Without media it is a content slide.",
|
|
5537
|
+
noMedia: "template-default",
|
|
5538
|
+
ownership: "native-slot",
|
|
5539
|
+
nativeLayout: "feature-top",
|
|
5540
|
+
additionalMediaLayout: "overlay-inset",
|
|
5541
|
+
unconsumedMedia: "retain-native-layout"
|
|
5542
|
+
},
|
|
5543
|
+
bottomFeature: {
|
|
5544
|
+
summary: "The heading and complete body take a band across the top sized to the text; body media spans the full width below. Without media it is a content slide.",
|
|
5545
|
+
noMedia: "template-default",
|
|
5546
|
+
ownership: "native-slot",
|
|
5547
|
+
nativeLayout: "feature-bottom",
|
|
5548
|
+
additionalMediaLayout: "overlay-inset",
|
|
5549
|
+
unconsumedMedia: "retain-native-layout"
|
|
5550
|
+
},
|
|
5551
|
+
mediaOnly: {
|
|
5552
|
+
summary: "Body media fills the whole slide with no text; without media the heading and body render as a content slide.",
|
|
5553
|
+
noMedia: "template-default",
|
|
5554
|
+
ownership: "native-slot",
|
|
5555
|
+
nativeLayout: "full-frame",
|
|
5556
|
+
additionalMediaLayout: "overlay-inset",
|
|
5557
|
+
unconsumedMedia: "retain-native-layout"
|
|
5558
|
+
},
|
|
5527
5559
|
map: {
|
|
5528
5560
|
summary: "The map canvas is the primary visual; other media must not reflow its geography.",
|
|
5529
5561
|
noMedia: "intrinsic-visual",
|
|
@@ -6198,12 +6230,144 @@ function leastObstructedMediaRect(layers, viewport) {
|
|
|
6198
6230
|
return score < bestScore ? candidate : best;
|
|
6199
6231
|
});
|
|
6200
6232
|
}
|
|
6233
|
+
var MEDIA_BANDS = {
|
|
6234
|
+
"feature-top": "top",
|
|
6235
|
+
"feature-bottom": "bottom",
|
|
6236
|
+
"full-frame": "full"
|
|
6237
|
+
};
|
|
6238
|
+
var BLOCK_GAP_EM = 0.55;
|
|
6239
|
+
function textLayer(layers, id) {
|
|
6240
|
+
const layer = layers.find((candidate) => candidate.id === id);
|
|
6241
|
+
return layer?.type === "text" ? layer : void 0;
|
|
6242
|
+
}
|
|
6243
|
+
function mediaBandLayout(layers, viewport, band, aspect) {
|
|
6244
|
+
const backdrop = layers.filter((layer) => isFullViewportBackground(layer, viewport));
|
|
6245
|
+
const title = textLayer(layers, "title");
|
|
6246
|
+
const body = textLayer(layers, "body");
|
|
6247
|
+
if (band === "full" || !title && !body) {
|
|
6248
|
+
return { layers: backdrop, mediaRect: rect(viewport, 0, 0, 1, 1), framed: false };
|
|
6249
|
+
}
|
|
6250
|
+
const { width, height } = viewport;
|
|
6251
|
+
const unit = Math.min(width, height);
|
|
6252
|
+
const margin = unit * 0.045;
|
|
6253
|
+
const gap = unit * 0.03;
|
|
6254
|
+
const innerGap = title && body ? unit * 0.02 : 0;
|
|
6255
|
+
const textWidth = width - margin * 2;
|
|
6256
|
+
const maxBandHeight = height * (body ? 0.4 : 0.2);
|
|
6257
|
+
const titleLineHeight = title?.content.style.lineHeight ?? 1.15;
|
|
6258
|
+
const titleBaseSize = Math.max(
|
|
6259
|
+
title?.content.style.fontSize ?? 0,
|
|
6260
|
+
Math.round((body?.content.style.fontSize ?? 0) * 1.2)
|
|
6261
|
+
);
|
|
6262
|
+
const titleWrapWidth = title ? Math.min(
|
|
6263
|
+
textWidth * 0.86,
|
|
6264
|
+
fitWrapWidth(
|
|
6265
|
+
title.content.text,
|
|
6266
|
+
titleBaseSize,
|
|
6267
|
+
textWidth,
|
|
6268
|
+
title.content.style.fontFamily ?? ""
|
|
6269
|
+
)
|
|
6270
|
+
) : textWidth;
|
|
6271
|
+
const titleFit = title ? fitProse({
|
|
6272
|
+
text: title.content.text,
|
|
6273
|
+
baseFontSize: titleBaseSize,
|
|
6274
|
+
minFontSize: Math.min(titleBaseSize, unit * 0.03),
|
|
6275
|
+
maxWidthPx: titleWrapWidth,
|
|
6276
|
+
maxHeightPx: body ? maxBandHeight * 0.35 : maxBandHeight,
|
|
6277
|
+
lineHeight: titleLineHeight
|
|
6278
|
+
}) : void 0;
|
|
6279
|
+
const titleHeight = titleFit?.heightPx ?? 0;
|
|
6280
|
+
const bodyRoom = maxBandHeight - titleHeight - innerGap;
|
|
6281
|
+
const bodyLineHeight = body?.content.style.lineHeight ?? 1.35;
|
|
6282
|
+
const blockGaps = body ? (body.content.text.match(/\n[^\S\n]*\n/g) ?? []).length : 0;
|
|
6283
|
+
const bodyBaseSize = body?.content.style.fontSize ?? 0;
|
|
6284
|
+
const headroomLines = 1;
|
|
6285
|
+
const bodyText3 = body?.content.text.replace(/\n[^\S\n]*\n/g, "\n") ?? "";
|
|
6286
|
+
const bodyFit = body ? fitProse({
|
|
6287
|
+
text: bodyText3,
|
|
6288
|
+
baseFontSize: bodyBaseSize,
|
|
6289
|
+
minFontSize: Math.min(bodyBaseSize, unit * 0.016),
|
|
6290
|
+
// HTML wraps on real glyphs; wide ones (CJK, emoji) fill lines in
|
|
6291
|
+
// half the characters the estimate assumes, so count lines narrower.
|
|
6292
|
+
maxWidthPx: fitWrapWidth(
|
|
6293
|
+
bodyText3,
|
|
6294
|
+
bodyBaseSize,
|
|
6295
|
+
textWidth,
|
|
6296
|
+
body.content.style.fontFamily ?? ""
|
|
6297
|
+
),
|
|
6298
|
+
maxHeightPx: bodyRoom - (blockGaps * BLOCK_GAP_EM + headroomLines * bodyLineHeight) * bodyBaseSize,
|
|
6299
|
+
lineHeight: bodyLineHeight
|
|
6300
|
+
}) : void 0;
|
|
6301
|
+
const bodyHeight = bodyFit ? Math.min(
|
|
6302
|
+
bodyRoom,
|
|
6303
|
+
bodyFit.heightPx + (blockGaps * BLOCK_GAP_EM + headroomLines * bodyLineHeight) * bodyFit.fontSize
|
|
6304
|
+
) : 0;
|
|
6305
|
+
const bandHeight = titleHeight + innerGap + bodyHeight;
|
|
6306
|
+
const roomForMedia = height - margin - gap - bandHeight;
|
|
6307
|
+
const mediaHeight = aspect && Number.isFinite(aspect) && aspect > 0 ? Math.min(roomForMedia, width / aspect) : roomForMedia;
|
|
6308
|
+
const offset = (roomForMedia - mediaHeight) / 2;
|
|
6309
|
+
const mediaTop = band === "top" ? offset : margin + offset + bandHeight + gap;
|
|
6310
|
+
const bandTop = band === "top" ? mediaTop + mediaHeight + gap : margin + offset;
|
|
6311
|
+
const placed = [...backdrop];
|
|
6312
|
+
if (title && titleFit) {
|
|
6313
|
+
placed.push({
|
|
6314
|
+
...title,
|
|
6315
|
+
position: {
|
|
6316
|
+
x: margin,
|
|
6317
|
+
y: bandTop,
|
|
6318
|
+
width: titleWrapWidth,
|
|
6319
|
+
height: titleHeight,
|
|
6320
|
+
anchor: "top-left"
|
|
6321
|
+
},
|
|
6322
|
+
content: {
|
|
6323
|
+
...title.content,
|
|
6324
|
+
style: {
|
|
6325
|
+
...title.content.style,
|
|
6326
|
+
fontSize: titleFit.fontSize,
|
|
6327
|
+
lineHeight: titleLineHeight,
|
|
6328
|
+
...titleFit.maxLines ? { maxLines: titleFit.maxLines } : {}
|
|
6329
|
+
}
|
|
6330
|
+
}
|
|
6331
|
+
});
|
|
6332
|
+
}
|
|
6333
|
+
if (body && bodyFit) {
|
|
6334
|
+
placed.push({
|
|
6335
|
+
...body,
|
|
6336
|
+
position: {
|
|
6337
|
+
x: margin,
|
|
6338
|
+
y: bandTop + titleHeight + innerGap,
|
|
6339
|
+
width: textWidth,
|
|
6340
|
+
height: bodyHeight,
|
|
6341
|
+
anchor: "top-left"
|
|
6342
|
+
},
|
|
6343
|
+
content: {
|
|
6344
|
+
...body.content,
|
|
6345
|
+
style: {
|
|
6346
|
+
...body.content.style,
|
|
6347
|
+
fontSize: bodyFit.fontSize,
|
|
6348
|
+
lineHeight: bodyLineHeight,
|
|
6349
|
+
...bodyFit.maxLines ? { maxLines: bodyFit.maxLines } : {}
|
|
6350
|
+
}
|
|
6351
|
+
}
|
|
6352
|
+
});
|
|
6353
|
+
}
|
|
6354
|
+
return {
|
|
6355
|
+
layers: placed,
|
|
6356
|
+
mediaRect: { x: 0, y: mediaTop, width, height: mediaHeight },
|
|
6357
|
+
framed: false
|
|
6358
|
+
};
|
|
6359
|
+
}
|
|
6201
6360
|
function resolveSupplementalMediaLayout(layers, template, viewport, mediaCount, aspectRatios, featureOptions = {}) {
|
|
6202
6361
|
const policy = getBlockMediaLayoutPolicy(template);
|
|
6203
6362
|
const shape = mediaShape(mediaCount, aspectRatios);
|
|
6204
6363
|
const alreadyOwnsMedia = layers.some(
|
|
6205
6364
|
(layer) => layer.type === "image" || layer.type === "video" || layer.type === "videoEmbed" || layer.type === "map" || layer.type === "mermaid" || layer.type === "svg"
|
|
6206
6365
|
);
|
|
6366
|
+
const band = policy?.nativeLayout ? MEDIA_BANDS[policy.nativeLayout] : void 0;
|
|
6367
|
+
if (band && !alreadyOwnsMedia) {
|
|
6368
|
+
const aspect = mediaCount === 1 ? featureOptions.knownAspectRatios?.[0] : void 0;
|
|
6369
|
+
return mediaBandLayout(layers, viewport, band, aspect);
|
|
6370
|
+
}
|
|
6207
6371
|
if (!alreadyOwnsMedia && (policy?.nativeLayout === "feature-left" || policy?.nativeLayout === "feature-right")) {
|
|
6208
6372
|
const { position } = featureMediaSlot(
|
|
6209
6373
|
policy.nativeLayout === "feature-left" ? "left" : "right",
|
|
@@ -7802,7 +7966,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7802
7966
|
const fill = s.fill ?? defaultFill;
|
|
7803
7967
|
if (s.kind === "text") {
|
|
7804
7968
|
out.push(
|
|
7805
|
-
|
|
7969
|
+
textLayer2(
|
|
7806
7970
|
`shape-${s.id}`,
|
|
7807
7971
|
s.text ?? s.label ?? "",
|
|
7808
7972
|
x + w / 2,
|
|
@@ -7861,7 +8025,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7861
8025
|
}
|
|
7862
8026
|
if (s.label) {
|
|
7863
8027
|
out.push(
|
|
7864
|
-
|
|
8028
|
+
textLayer2(
|
|
7865
8029
|
`shape-label-${s.id}`,
|
|
7866
8030
|
s.label,
|
|
7867
8031
|
x + w / 2,
|
|
@@ -7876,7 +8040,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7876
8040
|
}
|
|
7877
8041
|
if (s.sublabel) {
|
|
7878
8042
|
out.push(
|
|
7879
|
-
|
|
8043
|
+
textLayer2(
|
|
7880
8044
|
`shape-sublabel-${s.id}`,
|
|
7881
8045
|
s.sublabel,
|
|
7882
8046
|
x + w / 2,
|
|
@@ -7891,7 +8055,7 @@ function shapeLayers(s, x, y, w, h, context, defaultStroke, defaultFill, fontAdj
|
|
|
7891
8055
|
}
|
|
7892
8056
|
return out;
|
|
7893
8057
|
}
|
|
7894
|
-
function
|
|
8058
|
+
function textLayer2(id, text, cx, cy, width, context, color, bold, fontAdj) {
|
|
7895
8059
|
return {
|
|
7896
8060
|
type: "text",
|
|
7897
8061
|
id,
|
|
@@ -8436,6 +8600,9 @@ var templateRegistry = {
|
|
|
8436
8600
|
imageWithCaption,
|
|
8437
8601
|
leftFeature,
|
|
8438
8602
|
rightFeature,
|
|
8603
|
+
topFeature,
|
|
8604
|
+
bottomFeature,
|
|
8605
|
+
mediaOnly,
|
|
8439
8606
|
map: mapBlock,
|
|
8440
8607
|
fullBleedQuote,
|
|
8441
8608
|
list: listBlock,
|
|
@@ -8754,6 +8921,9 @@ var TEMPLATE_INPUT_DESCRIPTORS = {
|
|
|
8754
8921
|
],
|
|
8755
8922
|
leftFeature: FEATURE_DESCRIPTORS(),
|
|
8756
8923
|
rightFeature: FEATURE_DESCRIPTORS(),
|
|
8924
|
+
topFeature: [{ key: "title", description: "Heading shown with the body under the media" }],
|
|
8925
|
+
bottomFeature: [{ key: "title", description: "Heading shown with the body above the media" }],
|
|
8926
|
+
mediaOnly: [{ key: "title", description: "Heading, shown only when the block has no media" }],
|
|
8757
8927
|
map: [
|
|
8758
8928
|
{
|
|
8759
8929
|
key: "center",
|
|
@@ -9450,11 +9620,13 @@ function appendRichContentLayers(layers, block, theme, viewport, mediaAspectRati
|
|
|
9450
9620
|
const timedLayers = applyEmbeddedVideoTiming(layers, block);
|
|
9451
9621
|
const items = collectRichMediaItems(timedLayers, block);
|
|
9452
9622
|
if (items.length === 0) return timedLayers;
|
|
9453
|
-
const
|
|
9623
|
+
const knownAspects = items.map((item) => {
|
|
9454
9624
|
const key = item.kind === "image" || item.kind === "video" ? item.src : item.kind === "mermaid" ? item.source : void 0;
|
|
9455
9625
|
const intrinsic = key ? mediaAspectRatios?.[key] : void 0;
|
|
9456
|
-
|
|
9626
|
+
if (intrinsic && Number.isFinite(intrinsic) && intrinsic > 0) return intrinsic;
|
|
9627
|
+
return item.kind === "video" ? void 0 : item.aspectRatio;
|
|
9457
9628
|
});
|
|
9629
|
+
const aspects = items.map((item, index) => knownAspects[index] ?? item.aspectRatio);
|
|
9458
9630
|
const layout = block.summaryLayout === "feature" ? resolveFeatureSummaryLayout(timedLayers, viewport, aspects) : resolveSupplementalMediaLayout(
|
|
9459
9631
|
timedLayers,
|
|
9460
9632
|
block.template ? resolveTemplateName(block.template) : void 0,
|
|
@@ -9463,7 +9635,8 @@ function appendRichContentLayers(layers, block, theme, viewport, mediaAspectRati
|
|
|
9463
9635
|
aspects,
|
|
9464
9636
|
{
|
|
9465
9637
|
summaryFeature: block.summaryMode === "headings-and-features" && !timedLayers.some((layer) => layer.id === "feature-body"),
|
|
9466
|
-
stackColumns: createTemplateContext(theme, 0, 1, viewport).layout.stackColumns
|
|
9638
|
+
stackColumns: createTemplateContext(theme, 0, 1, viewport).layout.stackColumns,
|
|
9639
|
+
knownAspectRatios: knownAspects
|
|
9467
9640
|
}
|
|
9468
9641
|
);
|
|
9469
9642
|
const cells = gridCells(layout.mediaRect, items.length, viewport, layout.framed);
|
|
@@ -9625,6 +9798,18 @@ var TEMPLATE_METADATA = {
|
|
|
9625
9798
|
label: "Right Feature",
|
|
9626
9799
|
description: "Image on the right, title and body text stacked on the left."
|
|
9627
9800
|
},
|
|
9801
|
+
topFeature: {
|
|
9802
|
+
label: "Top Feature",
|
|
9803
|
+
description: "Image or video across the full width at the top, title and body text below."
|
|
9804
|
+
},
|
|
9805
|
+
bottomFeature: {
|
|
9806
|
+
label: "Bottom Feature",
|
|
9807
|
+
description: "Title and body text at the top, image or video across the full width below."
|
|
9808
|
+
},
|
|
9809
|
+
mediaOnly: {
|
|
9810
|
+
label: "Media Only",
|
|
9811
|
+
description: "The image or video fills the slide, with no title, text or caption."
|
|
9812
|
+
},
|
|
9628
9813
|
map: {
|
|
9629
9814
|
label: "Map",
|
|
9630
9815
|
description: "Embeds an interactive map centered on a geographic location."
|
|
@@ -9790,6 +9975,24 @@ var TEMPLATE_AUTHORING_METADATA = {
|
|
|
9790
9975
|
safeForContentFirst: false,
|
|
9791
9976
|
placement: "heading"
|
|
9792
9977
|
},
|
|
9978
|
+
topFeature: {
|
|
9979
|
+
role: "media",
|
|
9980
|
+
bodyPolicy: "complete",
|
|
9981
|
+
safeForContentFirst: false,
|
|
9982
|
+
placement: "heading"
|
|
9983
|
+
},
|
|
9984
|
+
bottomFeature: {
|
|
9985
|
+
role: "media",
|
|
9986
|
+
bodyPolicy: "complete",
|
|
9987
|
+
safeForContentFirst: false,
|
|
9988
|
+
placement: "heading"
|
|
9989
|
+
},
|
|
9990
|
+
mediaOnly: {
|
|
9991
|
+
role: "media",
|
|
9992
|
+
bodyPolicy: "ignored",
|
|
9993
|
+
safeForContentFirst: false,
|
|
9994
|
+
placement: "heading"
|
|
9995
|
+
},
|
|
9793
9996
|
map: {
|
|
9794
9997
|
role: "spatial",
|
|
9795
9998
|
bodyPolicy: "structured",
|
|
@@ -10896,193 +11099,6 @@ function extractTableData(table) {
|
|
|
10896
11099
|
};
|
|
10897
11100
|
}
|
|
10898
11101
|
|
|
10899
|
-
// src/doc/standaloneAnnotation.ts
|
|
10900
|
-
function parseAnnotationInner(inner) {
|
|
10901
|
-
const tokens = tokenizeAttrTokens(inner.trim());
|
|
10902
|
-
const firstIsParam = tokens.length > 0 && tokens[0].indexOf("=") > 0;
|
|
10903
|
-
const template = firstIsParam || tokens.length === 0 ? void 0 : tokens[0];
|
|
10904
|
-
const startIdx = firstIsParam ? 0 : 1;
|
|
10905
|
-
const params = {};
|
|
10906
|
-
for (let i = startIdx; i < tokens.length; i++) {
|
|
10907
|
-
const kv = splitKeyValueToken(tokens[i]);
|
|
10908
|
-
if (kv) params[kv.key] = kv.value;
|
|
10909
|
-
}
|
|
10910
|
-
return { template, params };
|
|
10911
|
-
}
|
|
10912
|
-
function parseStandaloneAnnotation(node) {
|
|
10913
|
-
if (node.type !== "paragraph") return null;
|
|
10914
|
-
const children = node.children ?? [];
|
|
10915
|
-
if (children.length !== 1 || children[0].type !== "text") return null;
|
|
10916
|
-
const text = children[0].value.trim();
|
|
10917
|
-
const match = matchTrailingTemplateAnnotation(text);
|
|
10918
|
-
if (!match || match.index !== 0) return null;
|
|
10919
|
-
return parseAnnotationInner(match.inner);
|
|
10920
|
-
}
|
|
10921
|
-
|
|
10922
|
-
// src/doc/mediaAnnotations.ts
|
|
10923
|
-
var MEDIA_TEMPLATES = /* @__PURE__ */ new Set(["audio", "video", "media"]);
|
|
10924
|
-
function isMediaAnnotationName(name) {
|
|
10925
|
-
return name != null && MEDIA_TEMPLATES.has(name);
|
|
10926
|
-
}
|
|
10927
|
-
function time(raw) {
|
|
10928
|
-
if (raw == null) return null;
|
|
10929
|
-
return parseTimeSeconds(raw);
|
|
10930
|
-
}
|
|
10931
|
-
function videoPlacement(params) {
|
|
10932
|
-
const explicit = params.placement ?? params.presentation;
|
|
10933
|
-
if (explicit === "content") return "content";
|
|
10934
|
-
if (explicit === "pip" || explicit === "picture-in-picture") return "picture-in-picture";
|
|
10935
|
-
if (explicit === "overlay" || explicit === "full-frame") return "overlay";
|
|
10936
|
-
if (params.pip === "" || params.pip === "true") return "picture-in-picture";
|
|
10937
|
-
if (params.overlay === "" || params.overlay === "true") return "overlay";
|
|
10938
|
-
return void 0;
|
|
10939
|
-
}
|
|
10940
|
-
function lockToBlock(raw) {
|
|
10941
|
-
return raw !== "false" && raw !== "0";
|
|
10942
|
-
}
|
|
10943
|
-
function videoPipSize(raw) {
|
|
10944
|
-
return raw === "small" || raw === "large" ? raw : void 0;
|
|
10945
|
-
}
|
|
10946
|
-
function videoPipShape(raw) {
|
|
10947
|
-
return raw === "square" || raw === "wide" ? raw : void 0;
|
|
10948
|
-
}
|
|
10949
|
-
function videoPipPosition(raw) {
|
|
10950
|
-
return raw === "top-left" || raw === "top-right" || raw === "bottom-left" || raw === "bottom-right" ? raw : void 0;
|
|
10951
|
-
}
|
|
10952
|
-
function toMediaClip(parsed, id) {
|
|
10953
|
-
const { template, params } = parsed;
|
|
10954
|
-
if (!template || !MEDIA_TEMPLATES.has(template)) return null;
|
|
10955
|
-
const src = params.src;
|
|
10956
|
-
if (!src) return null;
|
|
10957
|
-
const kind = template === "video" ? "video" : "audio";
|
|
10958
|
-
const anchor = params.anchor === "document" || params.span === "document" ? "document" : "block";
|
|
10959
|
-
const clip = {
|
|
10960
|
-
id,
|
|
10961
|
-
src,
|
|
10962
|
-
kind,
|
|
10963
|
-
startAt: time(params.startAt ?? params.startTime) ?? 0,
|
|
10964
|
-
anchor
|
|
10965
|
-
};
|
|
10966
|
-
const placement = kind === "video" ? videoPlacement(params) : void 0;
|
|
10967
|
-
if (placement && placement !== "content") clip.placement = placement;
|
|
10968
|
-
const pipSize = videoPipSize(params.pipSize);
|
|
10969
|
-
const pipShape = videoPipShape(params.pipShape);
|
|
10970
|
-
const pipPosition = videoPipPosition(params.pipPosition);
|
|
10971
|
-
if (pipSize) clip.pipSize = pipSize;
|
|
10972
|
-
if (pipShape) clip.pipShape = pipShape;
|
|
10973
|
-
if (pipPosition) clip.pipPosition = pipPosition;
|
|
10974
|
-
if (kind === "video" && placement && placement !== "content" && params.lockToBlock != null) {
|
|
10975
|
-
const locked = lockToBlock(params.lockToBlock);
|
|
10976
|
-
clip.lockToBlock = locked;
|
|
10977
|
-
clip.anchor = locked ? "block" : "document";
|
|
10978
|
-
if (locked) clip.startAt = 0;
|
|
10979
|
-
}
|
|
10980
|
-
const clipStart = time(params.clipStart);
|
|
10981
|
-
const clipEnd = time(params.clipEnd);
|
|
10982
|
-
if (clipStart != null) clip.clipStart = clipStart;
|
|
10983
|
-
if (clipEnd != null) clip.clipEnd = clipEnd;
|
|
10984
|
-
if (clip.lockToBlock === true) delete clip.clipEnd;
|
|
10985
|
-
if (params.spillover === "true" || params.spillover === "") clip.spillover = true;
|
|
10986
|
-
const edits = parseMediaEdits(mediaEditValuesFromParams(params));
|
|
10987
|
-
if (edits) clip.edits = edits;
|
|
10988
|
-
return clip;
|
|
10989
|
-
}
|
|
10990
|
-
function firstVideoElement(children) {
|
|
10991
|
-
const visit = (nodes) => {
|
|
10992
|
-
for (const child of nodes) {
|
|
10993
|
-
if (child.type !== "htmlElement") continue;
|
|
10994
|
-
if (child.tagName === "video") return child;
|
|
10995
|
-
const nested = visit(child.children);
|
|
10996
|
-
if (nested) return nested;
|
|
10997
|
-
}
|
|
10998
|
-
return null;
|
|
10999
|
-
};
|
|
11000
|
-
return visit(children);
|
|
11001
|
-
}
|
|
11002
|
-
function standaloneHtmlVideo(node) {
|
|
11003
|
-
if (node.type === "htmlBlock") {
|
|
11004
|
-
if (!/^\s*<video\b/i.test(node.rawHtml)) return null;
|
|
11005
|
-
const element = firstVideoElement(node.htmlChildren);
|
|
11006
|
-
return element ? { element, raw: node.rawHtml.trim() } : null;
|
|
11007
|
-
}
|
|
11008
|
-
if (node.type !== "paragraph" || !node.children.every((child) => child.type === "htmlInline")) {
|
|
11009
|
-
return null;
|
|
11010
|
-
}
|
|
11011
|
-
const raw = node.children.map((child) => child.type === "htmlInline" ? child.rawHtml : "").join("");
|
|
11012
|
-
if (!/^\s*<video\b[\s\S]*<\/video>\s*$/i.test(raw)) return null;
|
|
11013
|
-
for (const child of node.children) {
|
|
11014
|
-
if (child.type !== "htmlInline") continue;
|
|
11015
|
-
const element = firstVideoElement(child.htmlChildren);
|
|
11016
|
-
if (element) return { element, raw: raw.trim() };
|
|
11017
|
-
}
|
|
11018
|
-
return null;
|
|
11019
|
-
}
|
|
11020
|
-
function htmlVideoClip(node, id) {
|
|
11021
|
-
const authored = standaloneHtmlVideo(node);
|
|
11022
|
-
if (!authored) return null;
|
|
11023
|
-
const { element } = authored;
|
|
11024
|
-
const placement = videoPlacement({
|
|
11025
|
-
placement: element.attributes["data-squisq-video-placement"] ?? ""
|
|
11026
|
-
});
|
|
11027
|
-
if (!placement || placement === "content") return null;
|
|
11028
|
-
const src = element.attributes.src;
|
|
11029
|
-
if (!src) return null;
|
|
11030
|
-
const locked = lockToBlock(element.attributes["data-squisq-video-lock-to-block"]);
|
|
11031
|
-
const clip = {
|
|
11032
|
-
id,
|
|
11033
|
-
src,
|
|
11034
|
-
kind: "video",
|
|
11035
|
-
placement,
|
|
11036
|
-
lockToBlock: locked,
|
|
11037
|
-
startAt: locked ? 0 : time(element.attributes["data-squisq-video-start-at"]) ?? 0,
|
|
11038
|
-
anchor: locked ? "block" : "document"
|
|
11039
|
-
};
|
|
11040
|
-
const pipSize = videoPipSize(element.attributes["data-squisq-video-pip-size"]);
|
|
11041
|
-
const pipShape = videoPipShape(element.attributes["data-squisq-video-pip-shape"]);
|
|
11042
|
-
const pipPosition = videoPipPosition(element.attributes["data-squisq-video-pip-position"]);
|
|
11043
|
-
if (pipSize) clip.pipSize = pipSize;
|
|
11044
|
-
if (pipShape) clip.pipShape = pipShape;
|
|
11045
|
-
if (pipPosition) clip.pipPosition = pipPosition;
|
|
11046
|
-
const clipStart = time(element.attributes["data-squisq-video-clip-start"]);
|
|
11047
|
-
const clipEnd = time(element.attributes["data-squisq-video-clip-end"]);
|
|
11048
|
-
if (clipStart != null) clip.clipStart = clipStart;
|
|
11049
|
-
if (!locked && clipEnd != null) clip.clipEnd = clipEnd;
|
|
11050
|
-
const edits = parseMediaEdits(mediaEditValuesFromAttributes("video", element.attributes));
|
|
11051
|
-
if (edits) clip.edits = edits;
|
|
11052
|
-
return clip;
|
|
11053
|
-
}
|
|
11054
|
-
function extractMediaFromContents(contents, makeId, blockId) {
|
|
11055
|
-
const media = [];
|
|
11056
|
-
const documentMedia = [];
|
|
11057
|
-
const remaining = [];
|
|
11058
|
-
let index = 0;
|
|
11059
|
-
let originalIndex = 0;
|
|
11060
|
-
for (const node of contents ?? []) {
|
|
11061
|
-
const parsed = parseStandaloneAnnotation(node);
|
|
11062
|
-
const clip = parsed ? toMediaClip(parsed, "") : htmlVideoClip(node, "");
|
|
11063
|
-
if (clip) {
|
|
11064
|
-
clip.id = makeId(clip.src, index++);
|
|
11065
|
-
const line = node.position?.start.line;
|
|
11066
|
-
if (line != null) clip.sourceLine = line;
|
|
11067
|
-
if (blockId !== void 0) {
|
|
11068
|
-
const authoredHtml = standaloneHtmlVideo(node);
|
|
11069
|
-
const rawText = node.type === "paragraph" && node.children?.[0]?.type === "text" ? node.children[0].value.trim() : authoredHtml?.raw;
|
|
11070
|
-
clip.origin = {
|
|
11071
|
-
blockId,
|
|
11072
|
-
index: originalIndex,
|
|
11073
|
-
...rawText !== void 0 ? { raw: rawText } : {},
|
|
11074
|
-
...authoredHtml ? { format: "html" } : {}
|
|
11075
|
-
};
|
|
11076
|
-
}
|
|
11077
|
-
(clip.anchor === "document" ? documentMedia : media).push(clip);
|
|
11078
|
-
} else {
|
|
11079
|
-
remaining.push(node);
|
|
11080
|
-
}
|
|
11081
|
-
originalIndex++;
|
|
11082
|
-
}
|
|
11083
|
-
return { media, documentMedia, remaining };
|
|
11084
|
-
}
|
|
11085
|
-
|
|
11086
11102
|
// src/doc/annotationBlocks.ts
|
|
11087
11103
|
function applyBlockMeta(block, m) {
|
|
11088
11104
|
if (m.build) block.build = m.build;
|
|
@@ -12084,7 +12100,7 @@ function resolveBuildTimeline(steps, spec, duration, timing) {
|
|
|
12084
12100
|
let consumed = 0;
|
|
12085
12101
|
let previous = 0;
|
|
12086
12102
|
const matched = timing?.sourceText === buildSourceText(steps) && timing.starts.length === steps.length && timing.starts.every(
|
|
12087
|
-
(
|
|
12103
|
+
(time, i) => Number.isFinite(time) && time >= 0 && (i === 0 || time >= timing.starts[i - 1])
|
|
12088
12104
|
);
|
|
12089
12105
|
const starts = steps.map((_, i) => {
|
|
12090
12106
|
const automatic = intro + Math.max(0, latest - intro) * consumed / Math.max(1, total);
|
|
@@ -12101,15 +12117,15 @@ function resolveBuildTimeline(steps, spec, duration, timing) {
|
|
|
12101
12117
|
);
|
|
12102
12118
|
return { starts, entrance, compressed: steps.length > 0 && end < steps.length * 0.8 };
|
|
12103
12119
|
}
|
|
12104
|
-
function buildCursorAtTime(timeline,
|
|
12120
|
+
function buildCursorAtTime(timeline, time) {
|
|
12105
12121
|
let revealed = 0;
|
|
12106
12122
|
for (const start of timeline.starts) {
|
|
12107
|
-
if (
|
|
12123
|
+
if (time < start) break;
|
|
12108
12124
|
revealed++;
|
|
12109
12125
|
}
|
|
12110
12126
|
return {
|
|
12111
12127
|
revealed,
|
|
12112
|
-
progress: revealed === 0 ? 0 : timeline.entrance === 0 ? 1 : Math.min(1, Math.max(0, (
|
|
12128
|
+
progress: revealed === 0 ? 0 : timeline.entrance === 0 ? 1 : Math.min(1, Math.max(0, (time - timeline.starts[revealed - 1]) / timeline.entrance))
|
|
12113
12129
|
};
|
|
12114
12130
|
}
|
|
12115
12131
|
function buildTargetState(index, steps, cursor, spec, motion = true) {
|
|
@@ -12180,13 +12196,13 @@ function resolveDocBuildTiming(doc, blocks) {
|
|
|
12180
12196
|
}
|
|
12181
12197
|
|
|
12182
12198
|
// src/doc/templates/contentBlock.ts
|
|
12183
|
-
function bodyNodes(context) {
|
|
12199
|
+
function bodyNodes(context, omitPictures) {
|
|
12184
12200
|
if (context.block?.summaryMode === "headings-and-features") return [];
|
|
12185
12201
|
return (context.block?.contents ?? []).filter(
|
|
12186
12202
|
// Mermaid source and hosted-video links are already materialized as
|
|
12187
12203
|
// visual layers (a diagram, a player). Repeating them as prose makes the
|
|
12188
12204
|
// loss-averse default noisy without preserving any additional meaning.
|
|
12189
|
-
(node) => !isMaterializedMediaNode(node)
|
|
12205
|
+
(node) => !isMaterializedMediaNode(node) && !(omitPictures && isPictureParagraph(node))
|
|
12190
12206
|
);
|
|
12191
12207
|
}
|
|
12192
12208
|
function listParagraphs(list, level = 0) {
|
|
@@ -12231,10 +12247,10 @@ function bodyFontSize(body, context) {
|
|
|
12231
12247
|
const base = body.length > 1800 ? 18 : body.length > 1100 ? 21 : body.length > 650 ? 24 : 28;
|
|
12232
12248
|
return themedFontSize(base, context, false);
|
|
12233
12249
|
}
|
|
12234
|
-
function contentBlock(input, context) {
|
|
12250
|
+
function contentBlock(input, context, options = {}) {
|
|
12235
12251
|
const { theme } = context;
|
|
12236
12252
|
const title = input.title ?? context.block?.title ?? "";
|
|
12237
|
-
const markdown = bodyNodes(context);
|
|
12253
|
+
const markdown = bodyNodes(context, options.omitPictures === true);
|
|
12238
12254
|
const paragraphs = completeBodyParagraphs(markdown);
|
|
12239
12255
|
const body = paragraphs.map(plainParagraphText).join("\n");
|
|
12240
12256
|
const builds = planContentBuilds(markdown, input.build ?? context.block?.build);
|
|
@@ -12336,6 +12352,9 @@ export {
|
|
|
12336
12352
|
imageWithCaption,
|
|
12337
12353
|
leftFeature,
|
|
12338
12354
|
rightFeature,
|
|
12355
|
+
topFeature,
|
|
12356
|
+
bottomFeature,
|
|
12357
|
+
mediaOnly,
|
|
12339
12358
|
mapBlock,
|
|
12340
12359
|
fullBleedQuote,
|
|
12341
12360
|
listBlock,
|
|
@@ -12392,7 +12411,6 @@ export {
|
|
|
12392
12411
|
parseYamlSubset,
|
|
12393
12412
|
findFirstTable,
|
|
12394
12413
|
extractTableData,
|
|
12395
|
-
parseStandaloneAnnotation,
|
|
12396
12414
|
getPinnedBlockMeta,
|
|
12397
12415
|
markdownToDoc,
|
|
12398
12416
|
flattenBlocks,
|