@bendyline/squisq 2.13.14 → 2.13.16
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-BhvotZx_.d.ts → Doc-DLfTam0R.d.ts} +82 -6
- package/dist/{ImageEditDoc-D8hYio6b.d.ts → ImageEditDoc-DdSHb6sj.d.ts} +1 -1
- package/dist/{chunk-YQQWE4HG.js → chunk-33CAD575.js} +200 -262
- package/dist/{chunk-L7QZORLB.js → chunk-37RLFDIT.js} +11 -4
- package/dist/chunk-4R3YZTPX.js +42 -0
- package/dist/{chunk-DBVCSVNV.js → chunk-A4ZFYGU6.js} +13 -38
- package/dist/{chunk-CTT4XAGO.js → chunk-BG2OYBGC.js} +2534 -737
- package/dist/{chunk-2SRF5III.js → chunk-BVL3F64S.js} +1 -1
- package/dist/chunk-C7DKMO4H.js +88 -0
- package/dist/{chunk-SGNWO7OF.js → chunk-MA7XUCSQ.js} +517 -30
- package/dist/{chunk-JSGIWW35.js → chunk-MTIR5PWF.js} +1 -1
- package/dist/{chunk-C4SB3NN4.js → chunk-NBDF6SQ5.js} +22 -2
- package/dist/chunk-TOPEP5B7.js +515 -0
- package/dist/{chunk-OIQ2GO2O.js → chunk-TXN23SG2.js} +1 -1
- package/dist/{chunk-7MS26OXD.js → chunk-UDPPWYYM.js} +6 -0
- package/dist/{chunk-J2G6EOEJ.js → chunk-XY5Z23C4.js} +75 -16
- package/dist/{chunk-5DFFVW75.js → chunk-Z73DG6IL.js} +1 -1
- package/dist/doc/index.d.ts +412 -26
- package/dist/doc/index.js +66 -11
- 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 +9 -9
- package/dist/index.js +147 -29
- package/dist/jsonForm/index.d.ts +1 -1
- package/dist/jsonForm/index.js +5 -4
- package/dist/markdown/index.js +3 -3
- package/dist/{materializePageSection-CWxou4mX.d.ts → materializePageSection-HIoRYiZu.d.ts} +121 -8
- package/dist/mediaEdit/index.d.ts +154 -3
- package/dist/mediaEdit/index.js +241 -2
- package/dist/narration/index.d.ts +1 -1
- package/dist/narration/index.js +7 -5
- package/dist/recommend/index.d.ts +129 -2
- package/dist/recommend/index.js +13 -4
- package/dist/schemas/index.d.ts +26 -7
- package/dist/schemas/index.js +14 -8
- package/dist/{themeLibrary-BIYE6aLw.d.ts → themeLibrary-B2K-aAOy.d.ts} +1 -1
- package/dist/timing/index.d.ts +66 -2
- package/dist/timing/index.js +12 -0
- package/dist/transform/index.d.ts +173 -16
- package/dist/transform/index.js +58 -17
- package/package.json +1 -1
- package/dist/chunk-FCB6JLWB.js +0 -125
|
@@ -1,14 +1,24 @@
|
|
|
1
1
|
import {
|
|
2
|
+
AUTHORED_PRESENTATION_LAYOUT,
|
|
3
|
+
PRESENTATION_KEY,
|
|
4
|
+
PRESENTATION_LAYOUTS,
|
|
5
|
+
PRESENTATION_LIMITS,
|
|
2
6
|
buildNarrationScript,
|
|
3
7
|
buildSourceText,
|
|
4
8
|
coerceTemplateParams,
|
|
5
9
|
conceptBuildStepTexts,
|
|
10
|
+
conceptTemplate,
|
|
6
11
|
flattenRenderableBlocks,
|
|
7
12
|
getPinnedBlockMeta,
|
|
8
|
-
markdownToDoc
|
|
9
|
-
|
|
13
|
+
markdownToDoc,
|
|
14
|
+
parsePresentationPlan,
|
|
15
|
+
presentationBeatExtras,
|
|
16
|
+
presentationLayoutFits,
|
|
17
|
+
presentationStat
|
|
18
|
+
} from "./chunk-BG2OYBGC.js";
|
|
10
19
|
import {
|
|
11
20
|
deriveTemplateInputs,
|
|
21
|
+
extractConceptItems,
|
|
12
22
|
extractEmbeddedVideos,
|
|
13
23
|
extractImages,
|
|
14
24
|
isAsciiDiagramFence,
|
|
@@ -20,8 +30,9 @@ import {
|
|
|
20
30
|
isPictureParagraph,
|
|
21
31
|
isStandaloneHtmlVideo,
|
|
22
32
|
isTreeFence,
|
|
23
|
-
matchNumberHighlight
|
|
24
|
-
|
|
33
|
+
matchNumberHighlight,
|
|
34
|
+
shapeIsStated
|
|
35
|
+
} from "./chunk-MA7XUCSQ.js";
|
|
25
36
|
import {
|
|
26
37
|
extractContent,
|
|
27
38
|
mapElementToBlock,
|
|
@@ -34,10 +45,11 @@ import {
|
|
|
34
45
|
} from "./chunk-JNUNNQ74.js";
|
|
35
46
|
import {
|
|
36
47
|
parseMarkdown
|
|
37
|
-
} from "./chunk-
|
|
48
|
+
} from "./chunk-NBDF6SQ5.js";
|
|
38
49
|
import {
|
|
39
|
-
isContainerTemplate
|
|
40
|
-
|
|
50
|
+
isContainerTemplate,
|
|
51
|
+
resolveTemplateName
|
|
52
|
+
} from "./chunk-UDPPWYYM.js";
|
|
41
53
|
import {
|
|
42
54
|
extractPlainText,
|
|
43
55
|
findBlockVideoEmbed,
|
|
@@ -59,142 +71,6 @@ import {
|
|
|
59
71
|
hashString
|
|
60
72
|
} from "./chunk-XRW6P7IF.js";
|
|
61
73
|
|
|
62
|
-
// src/transform/presentationPlan.ts
|
|
63
|
-
var PRESENTATION_KEY = "squisq-presentation";
|
|
64
|
-
var PRESENTATION_LAYOUTS = [
|
|
65
|
-
"title",
|
|
66
|
-
"divider",
|
|
67
|
-
"statement",
|
|
68
|
-
"emphasis",
|
|
69
|
-
"quote",
|
|
70
|
-
"stat",
|
|
71
|
-
"definition",
|
|
72
|
-
"list",
|
|
73
|
-
"comparison",
|
|
74
|
-
"steps",
|
|
75
|
-
"image",
|
|
76
|
-
"cards",
|
|
77
|
-
"process",
|
|
78
|
-
"cycle",
|
|
79
|
-
"layers"
|
|
80
|
-
];
|
|
81
|
-
var AUTHORED_PRESENTATION_LAYOUT = "authored";
|
|
82
|
-
var EMPHASIS_CHARACTERS = 60;
|
|
83
|
-
var spaced = (text3) => text3.replace(/\s+/gu, " ").trim();
|
|
84
|
-
function presentationStat(headline, points) {
|
|
85
|
-
for (const [index, line] of [headline, ...points].entries()) {
|
|
86
|
-
const match = matchNumberHighlight(line);
|
|
87
|
-
if (match) return { match, line, index: index - 1 };
|
|
88
|
-
}
|
|
89
|
-
return null;
|
|
90
|
-
}
|
|
91
|
-
function presentationLayoutFits(layout, headline, points, passage) {
|
|
92
|
-
switch (layout) {
|
|
93
|
-
case "list":
|
|
94
|
-
case "steps":
|
|
95
|
-
case "cards":
|
|
96
|
-
case "process":
|
|
97
|
-
return points.length >= 2;
|
|
98
|
-
case "cycle":
|
|
99
|
-
case "layers":
|
|
100
|
-
return points.length >= 3;
|
|
101
|
-
case "comparison":
|
|
102
|
-
return points.length === 2;
|
|
103
|
-
case "definition":
|
|
104
|
-
return points.length >= 1;
|
|
105
|
-
case "stat":
|
|
106
|
-
return presentationStat(headline, points) !== null;
|
|
107
|
-
case "emphasis":
|
|
108
|
-
return headline.length <= EMPHASIS_CHARACTERS;
|
|
109
|
-
case "quote":
|
|
110
|
-
return spaced(passage).includes(spaced(headline));
|
|
111
|
-
default:
|
|
112
|
-
return true;
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
var PRESENTATION_LIMITS = {
|
|
116
|
-
sourceCharacters: 4e4,
|
|
117
|
-
beats: 80,
|
|
118
|
-
serializedCharacters: 16e4,
|
|
119
|
-
mediaPerBeat: 4
|
|
120
|
-
};
|
|
121
|
-
function record(value) {
|
|
122
|
-
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
123
|
-
}
|
|
124
|
-
function keys(value, required, optional = []) {
|
|
125
|
-
return required.every((key) => Object.prototype.hasOwnProperty.call(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
|
|
126
|
-
}
|
|
127
|
-
function text(value, max) {
|
|
128
|
-
return typeof value === "string" && value.trim().length > 0 && value.length <= max && !Array.from(value).some((character) => {
|
|
129
|
-
const code = character.charCodeAt(0);
|
|
130
|
-
return code < 32 && code !== 9 && code !== 10 && code !== 13;
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
function parsePresentationPlan(input) {
|
|
134
|
-
let value = input;
|
|
135
|
-
if (typeof value === "string") {
|
|
136
|
-
if (value.length > PRESENTATION_LIMITS.serializedCharacters) return null;
|
|
137
|
-
try {
|
|
138
|
-
value = JSON.parse(value);
|
|
139
|
-
} catch {
|
|
140
|
-
return null;
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
if (!record(value) || !keys(value, ["version", "sourceText", "origin", "beats"]) || value.version !== 1 || !text(value.sourceText, PRESENTATION_LIMITS.sourceCharacters) || typeof value.origin !== "string" || !["automatic", "ai"].includes(value.origin) || !Array.isArray(value.beats) || !value.beats.length || value.beats.length > PRESENTATION_LIMITS.beats)
|
|
144
|
-
return null;
|
|
145
|
-
const beats = [];
|
|
146
|
-
const ids = /* @__PURE__ */ new Set();
|
|
147
|
-
let end = 0;
|
|
148
|
-
for (const beat of value.beats) {
|
|
149
|
-
if (!record(beat) || !keys(
|
|
150
|
-
beat,
|
|
151
|
-
["id", "sourceStart", "sourceEnd", "layout", "headline", "points"],
|
|
152
|
-
["imageSrc", "media", "hidden"]
|
|
153
|
-
) || "hidden" in beat && beat.hidden !== true || !text(beat.id, 80) || ids.has(beat.id) || !Number.isInteger(beat.sourceStart) || !Number.isInteger(beat.sourceEnd) || typeof beat.sourceStart !== "number" || typeof beat.sourceEnd !== "number" || beat.sourceStart < end || beat.sourceEnd <= beat.sourceStart || beat.sourceEnd > value.sourceText.length || value.sourceText.slice(end, beat.sourceStart).trim() || !text(beat.headline, 110) || !Array.isArray(beat.points) || beat.points.length > 4 || !beat.points.every((point) => text(point, 180)))
|
|
154
|
-
return null;
|
|
155
|
-
if (beat.layout === AUTHORED_PRESENTATION_LAYOUT) {
|
|
156
|
-
if (beat.points.length || "media" in beat) return null;
|
|
157
|
-
} else if (!PRESENTATION_LAYOUTS.includes(beat.layout) || !presentationLayoutFits(
|
|
158
|
-
beat.layout,
|
|
159
|
-
beat.headline,
|
|
160
|
-
beat.points,
|
|
161
|
-
value.sourceText.slice(beat.sourceStart, beat.sourceEnd)
|
|
162
|
-
))
|
|
163
|
-
return null;
|
|
164
|
-
if (beat.layout === "image" ? !text(beat.imageSrc, 2048) : "imageSrc" in beat) return null;
|
|
165
|
-
if ("media" in beat && (!Array.isArray(beat.media) || !beat.media.length || beat.media.length > PRESENTATION_LIMITS.mediaPerBeat || new Set(beat.media).size !== beat.media.length || !beat.media.every((ref) => text(ref, 1100))))
|
|
166
|
-
return null;
|
|
167
|
-
ids.add(beat.id);
|
|
168
|
-
end = beat.sourceEnd;
|
|
169
|
-
beats.push({
|
|
170
|
-
id: beat.id,
|
|
171
|
-
sourceStart: beat.sourceStart,
|
|
172
|
-
sourceEnd: beat.sourceEnd,
|
|
173
|
-
layout: beat.layout,
|
|
174
|
-
headline: beat.headline,
|
|
175
|
-
points: [...beat.points],
|
|
176
|
-
...beat.layout === "image" ? { imageSrc: beat.imageSrc } : {},
|
|
177
|
-
..."media" in beat ? { media: [...beat.media] } : {},
|
|
178
|
-
...beat.hidden === true ? { hidden: true } : {}
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
if (value.sourceText.slice(end).trim()) return null;
|
|
182
|
-
return {
|
|
183
|
-
version: 1,
|
|
184
|
-
sourceText: value.sourceText,
|
|
185
|
-
origin: value.origin,
|
|
186
|
-
beats
|
|
187
|
-
};
|
|
188
|
-
}
|
|
189
|
-
function serializePresentationPlan(plan) {
|
|
190
|
-
const parsed = parsePresentationPlan(plan);
|
|
191
|
-
if (!parsed) throw new Error("The presentation plan is invalid.");
|
|
192
|
-
const result = JSON.stringify(parsed);
|
|
193
|
-
if (result.length > PRESENTATION_LIMITS.serializedCharacters)
|
|
194
|
-
throw new Error("The presentation plan is too large.");
|
|
195
|
-
return result;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
74
|
// src/transform/presentationHints.ts
|
|
199
75
|
var PRESENTATION_HINTS_KEY = "squisq-presentation-hints";
|
|
200
76
|
var DYNAMIC_PRESENTATION_STYLE = "dynamic-slides";
|
|
@@ -204,13 +80,13 @@ function presentationPassageKey(passage) {
|
|
|
204
80
|
function defaultPresentationHints() {
|
|
205
81
|
return { version: 1, density: "balanced", inbetweens: true, blocks: [] };
|
|
206
82
|
}
|
|
207
|
-
function
|
|
83
|
+
function record(value) {
|
|
208
84
|
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
209
85
|
}
|
|
210
86
|
function exact(value, required, optional = []) {
|
|
211
87
|
return required.every((key) => Object.prototype.hasOwnProperty.call(value, key)) && Object.keys(value).every((key) => required.includes(key) || optional.includes(key));
|
|
212
88
|
}
|
|
213
|
-
function
|
|
89
|
+
function text(value, max) {
|
|
214
90
|
return typeof value === "string" && !!value.trim() && value.length <= max && [...value].every((char) => char.charCodeAt(0) >= 32 || ["\n", "\r", " "].includes(char));
|
|
215
91
|
}
|
|
216
92
|
function parsePresentationHints(input) {
|
|
@@ -223,12 +99,12 @@ function parsePresentationHints(input) {
|
|
|
223
99
|
return null;
|
|
224
100
|
}
|
|
225
101
|
}
|
|
226
|
-
if (!
|
|
102
|
+
if (!record(value) || !exact(value, ["version", "density", "inbetweens", "blocks"]) || value.version !== 1 || !["concise", "balanced", "detailed", "section"].includes(String(value.density)) || typeof value.inbetweens !== "boolean" || !Array.isArray(value.blocks) || value.blocks.length > 80)
|
|
227
103
|
return null;
|
|
228
104
|
const ids = /* @__PURE__ */ new Set();
|
|
229
105
|
const blocks = [];
|
|
230
106
|
for (const entry of value.blocks) {
|
|
231
|
-
if (!
|
|
107
|
+
if (!record(entry) || !exact(entry, ["blockId"], ["layout", "inbetweens", "wording", "ai", "build", "hidden"]) || !text(entry.blockId, 1024) || ids.has(entry.blockId) || entry.layout !== void 0 && entry.layout !== AUTHORED_PRESENTATION_LAYOUT && !PRESENTATION_LAYOUTS.includes(entry.layout) || entry.inbetweens !== void 0 && typeof entry.inbetweens !== "boolean" || entry.hidden !== void 0 && (!Array.isArray(entry.hidden) || !entry.hidden.length || entry.hidden.length > 80 || new Set(entry.hidden).size !== entry.hidden.length || !entry.hidden.every(
|
|
232
108
|
(key) => typeof key === "string" && /^[0-9a-z]{1,7}-[0-9a-z]{1,4}$/u.test(key)
|
|
233
109
|
)))
|
|
234
110
|
return null;
|
|
@@ -245,7 +121,10 @@ function parsePresentationHints(input) {
|
|
|
245
121
|
if (!Array.isArray(entry.ai) || entry.ai.length > 80) return null;
|
|
246
122
|
hint.ai = [];
|
|
247
123
|
for (const item of entry.ai) {
|
|
248
|
-
if (!
|
|
124
|
+
if (!record(item) || !exact(item, ["source", "layout", "headline", "points"], ["center", "xAxis", "yAxis"]) || !text(item.source, 4e3) || !PRESENTATION_LAYOUTS.includes(item.layout) || !text(item.headline, 110) || !Array.isArray(item.points) || item.points.length > PRESENTATION_LIMITS.points || !item.points.every((point) => text(point, 180)) || // An extra is saved only on the layout that draws it, as it will be set.
|
|
125
|
+
["center", "xAxis", "yAxis"].some(
|
|
126
|
+
(key) => key in item && item[key] !== presentationBeatExtras(String(item.layout), item)[key]
|
|
127
|
+
) || !presentationLayoutFits(
|
|
249
128
|
item.layout,
|
|
250
129
|
item.headline,
|
|
251
130
|
item.points,
|
|
@@ -256,13 +135,14 @@ function parsePresentationHints(input) {
|
|
|
256
135
|
source: item.source,
|
|
257
136
|
layout: item.layout,
|
|
258
137
|
headline: item.headline,
|
|
259
|
-
points: [...item.points]
|
|
138
|
+
points: [...item.points],
|
|
139
|
+
...presentationBeatExtras(String(item.layout), item)
|
|
260
140
|
});
|
|
261
141
|
}
|
|
262
142
|
}
|
|
263
143
|
if (entry.wording !== void 0) {
|
|
264
144
|
const wording = entry.wording;
|
|
265
|
-
if (!
|
|
145
|
+
if (!record(wording) || !exact(wording, ["source"], ["headline", "points"]) || !text(wording.source, 4e4) || wording.headline === void 0 && wording.points === void 0 || wording.headline !== void 0 && !text(wording.headline, 110) || wording.points !== void 0 && (!Array.isArray(wording.points) || wording.points.length > PRESENTATION_LIMITS.points || !wording.points.every((point) => text(point, 180))))
|
|
266
146
|
return null;
|
|
267
147
|
hint.wording = {
|
|
268
148
|
source: wording.source,
|
|
@@ -589,13 +469,13 @@ function maskNonProse(stripped, contents) {
|
|
|
589
469
|
let masked = stripped;
|
|
590
470
|
let cursor = 0;
|
|
591
471
|
for (const node of contents) {
|
|
592
|
-
const
|
|
593
|
-
if (!
|
|
594
|
-
const at = stripped.indexOf(
|
|
472
|
+
const text2 = stripMarkdown(extractPlainText(node));
|
|
473
|
+
if (!text2) continue;
|
|
474
|
+
const at = stripped.indexOf(text2, cursor);
|
|
595
475
|
if (at < 0) continue;
|
|
596
|
-
cursor = at +
|
|
476
|
+
cursor = at + text2.length;
|
|
597
477
|
if (PROSE_NODE_TYPES.has(node.type)) continue;
|
|
598
|
-
masked = masked.slice(0, at) +
|
|
478
|
+
masked = masked.slice(0, at) + text2.replace(/\S/g, " ") + masked.slice(cursor);
|
|
599
479
|
}
|
|
600
480
|
return masked;
|
|
601
481
|
}
|
|
@@ -897,8 +777,8 @@ var PROSE_KEYS = /* @__PURE__ */ new Set([
|
|
|
897
777
|
"quote",
|
|
898
778
|
"text"
|
|
899
779
|
]);
|
|
900
|
-
function briefText(
|
|
901
|
-
const normalized =
|
|
780
|
+
function briefText(text2) {
|
|
781
|
+
const normalized = text2.replace(/\s+/g, " ").trim();
|
|
902
782
|
const sentence = normalized.match(/^.*?[.!?](?:["'”’])?(?=\s|$)/)?.[0] ?? normalized;
|
|
903
783
|
const words = sentence.split(/\s+/).filter(Boolean);
|
|
904
784
|
let brief = words.slice(0, 24).join(" ");
|
|
@@ -959,11 +839,11 @@ function extractFeatureContents(contents, keepData = false) {
|
|
|
959
839
|
for (const node of contents ?? []) visit(node);
|
|
960
840
|
return features;
|
|
961
841
|
}
|
|
962
|
-
function withoutProse(
|
|
963
|
-
return
|
|
842
|
+
function withoutProse(record2) {
|
|
843
|
+
return record2 && Object.fromEntries(Object.entries(record2).filter(([key]) => !PROSE_KEYS.has(key)));
|
|
964
844
|
}
|
|
965
845
|
function typedMediaContents(block, bodyMedia) {
|
|
966
|
-
const
|
|
846
|
+
const record2 = {
|
|
967
847
|
...block,
|
|
968
848
|
...block.templateData,
|
|
969
849
|
...coerceTemplateParams(block.template ?? "", block.templateOverrides ?? {}).input
|
|
@@ -979,23 +859,23 @@ function typedMediaContents(block, bodyMedia) {
|
|
|
979
859
|
});
|
|
980
860
|
}
|
|
981
861
|
};
|
|
982
|
-
addImage(
|
|
862
|
+
addImage(record2.imageSrc, record2.imageAlt);
|
|
983
863
|
for (const key of ["accentImage", "backgroundImage"]) {
|
|
984
|
-
const image =
|
|
864
|
+
const image = record2[key];
|
|
985
865
|
if (image && typeof image === "object") {
|
|
986
866
|
const data = image;
|
|
987
867
|
addImage(data.src, data.alt);
|
|
988
868
|
}
|
|
989
869
|
}
|
|
990
|
-
if (Array.isArray(
|
|
991
|
-
for (const image of
|
|
870
|
+
if (Array.isArray(record2.images)) {
|
|
871
|
+
for (const image of record2.images) {
|
|
992
872
|
if (image && typeof image === "object") {
|
|
993
873
|
const data = image;
|
|
994
874
|
addImage(data.src, data.alt);
|
|
995
875
|
}
|
|
996
876
|
}
|
|
997
877
|
}
|
|
998
|
-
if (typeof
|
|
878
|
+
if (typeof record2.videoSrc === "string" && record2.videoSrc) {
|
|
999
879
|
const htmlChildren = [
|
|
1000
880
|
{
|
|
1001
881
|
type: "htmlElement",
|
|
@@ -1003,8 +883,8 @@ function typedMediaContents(block, bodyMedia) {
|
|
|
1003
883
|
selfClosing: false,
|
|
1004
884
|
children: [],
|
|
1005
885
|
attributes: {
|
|
1006
|
-
src:
|
|
1007
|
-
...typeof
|
|
886
|
+
src: record2.videoSrc,
|
|
887
|
+
...typeof record2.posterSrc === "string" ? { poster: record2.posterSrc } : {}
|
|
1008
888
|
}
|
|
1009
889
|
}
|
|
1010
890
|
];
|
|
@@ -1636,21 +1516,21 @@ function standaloneImagePool(images, content) {
|
|
|
1636
1516
|
...available.filter((image) => accents.has(image.src))
|
|
1637
1517
|
];
|
|
1638
1518
|
}
|
|
1639
|
-
function chunkNarration(
|
|
1640
|
-
if (count <= 1) return [
|
|
1519
|
+
function chunkNarration(text2, count) {
|
|
1520
|
+
if (count <= 1) return [text2];
|
|
1641
1521
|
const sentences = [];
|
|
1642
1522
|
const boundary = /[.!?]["'’”)\]]*\s+/g;
|
|
1643
1523
|
let start = 0;
|
|
1644
1524
|
let match;
|
|
1645
|
-
while ((match = boundary.exec(
|
|
1525
|
+
while ((match = boundary.exec(text2)) !== null) {
|
|
1646
1526
|
const end = match.index + match[0].length;
|
|
1647
|
-
const sentence =
|
|
1527
|
+
const sentence = text2.slice(start, end).trim();
|
|
1648
1528
|
if (sentence) sentences.push(sentence);
|
|
1649
1529
|
start = end;
|
|
1650
1530
|
}
|
|
1651
|
-
const tail =
|
|
1531
|
+
const tail = text2.slice(start).trim();
|
|
1652
1532
|
if (tail) sentences.push(tail);
|
|
1653
|
-
if (sentences.length < 2) return [
|
|
1533
|
+
if (sentences.length < 2) return [text2];
|
|
1654
1534
|
const chunkCount = Math.min(count, sentences.length);
|
|
1655
1535
|
const words = sentences.map((sentence) => sentence.split(/\s+/).length);
|
|
1656
1536
|
const totalWords = words.reduce((sum, n) => sum + n, 0);
|
|
@@ -1721,6 +1601,51 @@ function videoBlock(video, index, segmentId, duration) {
|
|
|
1721
1601
|
};
|
|
1722
1602
|
}
|
|
1723
1603
|
|
|
1604
|
+
// src/transform/conceptReveal.ts
|
|
1605
|
+
function stems(text2) {
|
|
1606
|
+
return (text2.toLowerCase().match(/[\p{L}\p{N}][\p{L}\p{N}'-]*/gu) ?? []).filter((word) => word.length >= 4).map((word) => word.slice(0, 5));
|
|
1607
|
+
}
|
|
1608
|
+
function matchPointsToSentences(points, sourceText, start, end) {
|
|
1609
|
+
const passage = sourceText.slice(start, end);
|
|
1610
|
+
const sentences = [...passage.matchAll(/[^.!?\n]+[.!?]*/gu)].map((match) => ({
|
|
1611
|
+
offset: start + match.index,
|
|
1612
|
+
words: new Set(stems(match[0]))
|
|
1613
|
+
}));
|
|
1614
|
+
let last = -1;
|
|
1615
|
+
const offsets = [];
|
|
1616
|
+
for (const point of points) {
|
|
1617
|
+
const words = stems(point);
|
|
1618
|
+
let best;
|
|
1619
|
+
for (const sentence of sentences) {
|
|
1620
|
+
const shared = words.filter((word) => sentence.words.has(word)).length;
|
|
1621
|
+
if (shared > (best?.shared ?? 1)) best = { offset: sentence.offset, shared };
|
|
1622
|
+
}
|
|
1623
|
+
if (!best || best.offset < last) return void 0;
|
|
1624
|
+
offsets.push(last = best.offset);
|
|
1625
|
+
}
|
|
1626
|
+
return offsets;
|
|
1627
|
+
}
|
|
1628
|
+
function conceptBuildSpec() {
|
|
1629
|
+
return { mode: "items", effect: "fadeInUp", previous: "keep" };
|
|
1630
|
+
}
|
|
1631
|
+
function conceptRevealTiming(template, items, itemTimes, start, end) {
|
|
1632
|
+
const build = conceptBuildSpec();
|
|
1633
|
+
const steps = conceptBuildStepTexts(template, items);
|
|
1634
|
+
if (!itemTimes || itemTimes.length !== steps.length) return { build };
|
|
1635
|
+
const lead = Math.min(0.5, (end - start) / 8);
|
|
1636
|
+
const starts = itemTimes.map(
|
|
1637
|
+
(time) => Math.min(Math.max(0, end - start - 0.1), Math.max(lead, time - start))
|
|
1638
|
+
);
|
|
1639
|
+
starts[0] = Math.min(starts[0], Math.max(lead, Math.min(1, (end - start) / 6)));
|
|
1640
|
+
return {
|
|
1641
|
+
build,
|
|
1642
|
+
buildTiming: {
|
|
1643
|
+
sourceText: buildSourceText(steps.map((text2, index) => ({ id: `build-${index}`, text: text2 }))),
|
|
1644
|
+
starts
|
|
1645
|
+
}
|
|
1646
|
+
};
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1724
1649
|
// src/transform/presentationMedia.ts
|
|
1725
1650
|
function presentationBlockImages(doc) {
|
|
1726
1651
|
const own = /* @__PURE__ */ new Map();
|
|
@@ -1810,6 +1735,7 @@ function presentationMediaNode(item, elapsed) {
|
|
|
1810
1735
|
|
|
1811
1736
|
// src/transform/presentationPlanner.ts
|
|
1812
1737
|
var SENTENCE_END = /[.!?][”"')\]]?$/u;
|
|
1738
|
+
var ABBREVIATION = /(?:^|[\s(“"‘'])(?:\p{Lu}|(?:\p{Lu}\.)+\p{Lu}|Mr|Mrs|Ms|Mx|Dr|Prof|Sr|Jr|St|Mt|Ft|Gen|Col|Lt|Capt|Sgt|Cmdr|Adm|Gov|Sen|Rep|Rev|Hon|vs|etc|e\.g|i\.e|cf|ca|approx|est|No|Fig|Inc|Ltd|Co|Corp)\.$/u;
|
|
1813
1739
|
var SENTENCE_START = /^[\p{Lu}\p{N}"“‘'([]/u;
|
|
1814
1740
|
var SEQUENCE_CUE = /^(?:(?:first|second|third|fourth)(?:ly)?|then|next|after\b|afterwards|at that point|eventually|finally|lastly)\b|^\d+[.)]\s/iu;
|
|
1815
1741
|
var ORDINAL_OPENER = /^(?:(?:first|second|third|fourth)(?:ly)?|then|next|after that|afterwards|finally|lastly),?\s+/iu;
|
|
@@ -1817,19 +1743,19 @@ function stagePoint(sentence) {
|
|
|
1817
1743
|
const rest = sentence.replace(ORDINAL_OPENER, "");
|
|
1818
1744
|
return pointText(rest === sentence ? sentence : `${rest[0].toUpperCase()}${rest.slice(1)}`);
|
|
1819
1745
|
}
|
|
1820
|
-
var CYCLE_CUE = /\b(?:cycles?|cyclical|repeats?|over and over|again and again|loop)\b/iu;
|
|
1821
1746
|
var DEFINES = /^(?:the |an? )?((?:[\p{Lu}][\p{L}'’-]*|[\p{Ll}][\p{L}'’-]*)(?: [\p{L}'’()-]+){0,3}?) (?:is|are|was|were) (?:an? |the )?(.{12,})$/u;
|
|
1822
1747
|
var PRONOUN = /^(?:it|its|this|that|these|those|there|they|their|he|his|she|her|we|our|you|your|i|my|which|one|each|some|to|so|but|and|or)$/iu;
|
|
1823
1748
|
function labelledPoint(sentence) {
|
|
1824
1749
|
const match = sentence.replace(/\s+/gu, " ").trim().match(DEFINES);
|
|
1825
|
-
|
|
1750
|
+
const clauses = match && /[,;]\s+(?:and\s+)?[^,;]*?\s(?:is|are|was|were)\s/u.test(match[2]);
|
|
1751
|
+
if (match && !clauses && !PRONOUN.test(match[1].split(" ")[0])) {
|
|
1826
1752
|
const label = match[1];
|
|
1827
1753
|
return clip(`${label[0].toUpperCase()}${label.slice(1)}: ${match[2]}`, Infinity, 160);
|
|
1828
1754
|
}
|
|
1829
1755
|
return clip(sentence, Infinity, 160);
|
|
1830
1756
|
}
|
|
1831
|
-
function clip(
|
|
1832
|
-
const clean =
|
|
1757
|
+
function clip(text2, words, characters) {
|
|
1758
|
+
const clean = text2.replace(/\s+/gu, " ").trim();
|
|
1833
1759
|
const parts = clean.split(" ");
|
|
1834
1760
|
let result = parts.length > words ? parts.slice(0, words).join(" ") : clean;
|
|
1835
1761
|
if (result.length > characters - 1) {
|
|
@@ -1839,13 +1765,14 @@ function clip(text3, words, characters) {
|
|
|
1839
1765
|
}
|
|
1840
1766
|
return result === clean ? clean : result.replace(/[\s,;:–—-]+$/u, "") + "\u2026";
|
|
1841
1767
|
}
|
|
1842
|
-
var headlineText = (
|
|
1843
|
-
var pointText = (
|
|
1844
|
-
var captionText = (
|
|
1768
|
+
var headlineText = (text2) => clip(text2, 12, 110);
|
|
1769
|
+
var pointText = (text2) => clip(text2, Infinity, 180);
|
|
1770
|
+
var captionText = (text2) => clip(text2, 18, 110);
|
|
1845
1771
|
var FEATURE_POINTS = 2;
|
|
1846
1772
|
var FEATURE_POINT_CHARACTERS = 100;
|
|
1847
|
-
|
|
1848
|
-
|
|
1773
|
+
var HAND_DRAWN_TEMPLATES = /* @__PURE__ */ new Set(["drawing", "layout"]);
|
|
1774
|
+
function featurePointText(text2) {
|
|
1775
|
+
const clean = text2.replace(/\s+/gu, " ").trim();
|
|
1849
1776
|
if (clean.length <= FEATURE_POINT_CHARACTERS) return clean;
|
|
1850
1777
|
const head = clean.slice(0, FEATURE_POINT_CHARACTERS);
|
|
1851
1778
|
const clause = Math.max(
|
|
@@ -1859,19 +1786,30 @@ function sentencesIn(sourceText, start, end) {
|
|
|
1859
1786
|
let cursor = 0;
|
|
1860
1787
|
const add = (to) => {
|
|
1861
1788
|
const raw = passage.slice(cursor, to);
|
|
1862
|
-
const
|
|
1863
|
-
if (!
|
|
1864
|
-
const from = start + cursor + raw.indexOf(
|
|
1865
|
-
sentences.push({ text:
|
|
1789
|
+
const text2 = raw.trim();
|
|
1790
|
+
if (!text2) return;
|
|
1791
|
+
const from = start + cursor + raw.indexOf(text2);
|
|
1792
|
+
sentences.push({ text: text2, start: from, end: from + text2.length });
|
|
1866
1793
|
};
|
|
1867
1794
|
for (const match of passage.matchAll(/(?<=[.!?][”"')\]]?)\s+(?=[\p{Lu}\p{N}"“‘'([])|\n+/gu)) {
|
|
1795
|
+
if (!match[0].includes("\n") && ABBREVIATION.test(passage.slice(cursor, match.index))) continue;
|
|
1868
1796
|
add(match.index);
|
|
1869
1797
|
cursor = match.index + match[0].length;
|
|
1870
1798
|
}
|
|
1871
1799
|
add(passage.length);
|
|
1872
1800
|
return sentences;
|
|
1873
1801
|
}
|
|
1874
|
-
var
|
|
1802
|
+
var STAT_SENTENCE_CHARACTERS = 120;
|
|
1803
|
+
var STAT_SPACING = 3;
|
|
1804
|
+
var YEAR = /^(?:1\d{3}|20\d{2})$/u;
|
|
1805
|
+
function strikingFigure(sentence) {
|
|
1806
|
+
if (sentence.length > STAT_SENTENCE_CHARACTERS) return void 0;
|
|
1807
|
+
const value = matchNumberHighlight(sentence)?.value.trim();
|
|
1808
|
+
if (!value || YEAR.test(value)) return void 0;
|
|
1809
|
+
return /[%‰$€£¥×,]|\d\s?(?:[xKMB]|million|billion|thousand|percent|times)\b/iu.test(value) || /\d{4,}/u.test(value) ? value : void 0;
|
|
1810
|
+
}
|
|
1811
|
+
var EMPHASIS_SENTENCE_CHARACTERS = 60;
|
|
1812
|
+
var comparable = (text2) => text2.toLowerCase().replace(/\s+/gu, " ").replace(/[\s….!?,;:]+$/u, "").trim();
|
|
1875
1813
|
function repeats(sentence, headline) {
|
|
1876
1814
|
const body = comparable(sentence);
|
|
1877
1815
|
const head = comparable(headline);
|
|
@@ -1879,7 +1817,7 @@ function repeats(sentence, headline) {
|
|
|
1879
1817
|
}
|
|
1880
1818
|
function chunkWords(words, limit) {
|
|
1881
1819
|
const chunks = [];
|
|
1882
|
-
const ends = (count) => SENTENCE_END.test(words[count - 1][0]) && (count >= words.length || SENTENCE_START.test(words[count][0]));
|
|
1820
|
+
const ends = (count) => SENTENCE_END.test(words[count - 1][0]) && (count >= words.length || SENTENCE_START.test(words[count][0]) && !ABBREVIATION.test(words[count - 1][0]));
|
|
1883
1821
|
let first = 0;
|
|
1884
1822
|
while (first < words.length) {
|
|
1885
1823
|
let last = Math.min(first + limit, words.length);
|
|
@@ -1889,6 +1827,8 @@ function chunkWords(words, limit) {
|
|
|
1889
1827
|
const reach = Math.min(words.length, first + Math.ceil(limit * 1.5));
|
|
1890
1828
|
for (let cursor = last + 1; cursor <= reach && !cut; cursor++) if (ends(cursor)) cut = cursor;
|
|
1891
1829
|
if (cut) last = cut;
|
|
1830
|
+
if (words.length - last < limit / 2 && words.length - first <= Math.ceil(limit * 1.5))
|
|
1831
|
+
last = words.length;
|
|
1892
1832
|
}
|
|
1893
1833
|
chunks.push([first, last]);
|
|
1894
1834
|
first = last;
|
|
@@ -1913,11 +1853,11 @@ function featureSpans(sourceText, from, to, items) {
|
|
|
1913
1853
|
let cursor = from;
|
|
1914
1854
|
for (const item of items) {
|
|
1915
1855
|
if (item.kind === "image") continue;
|
|
1916
|
-
const
|
|
1917
|
-
const at =
|
|
1918
|
-
if (at < 0 || at +
|
|
1919
|
-
spans.push([at, at +
|
|
1920
|
-
cursor = at +
|
|
1856
|
+
const text2 = extractPlainText(item.node).trim();
|
|
1857
|
+
const at = text2 ? sourceText.indexOf(text2, cursor) : -1;
|
|
1858
|
+
if (at < 0 || at + text2.length > to) continue;
|
|
1859
|
+
spans.push([at, at + text2.length]);
|
|
1860
|
+
cursor = at + text2.length;
|
|
1921
1861
|
}
|
|
1922
1862
|
return spans;
|
|
1923
1863
|
}
|
|
@@ -1938,7 +1878,14 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
1938
1878
|
doc,
|
|
1939
1879
|
script.blocks.map((block) => block.blockId)
|
|
1940
1880
|
);
|
|
1881
|
+
const drawnLists = new Set(
|
|
1882
|
+
flattenRenderableBlocks(doc.blocks).filter(
|
|
1883
|
+
(block) => !!conceptTemplate(block.template ?? "") && block.contents?.length === 1 && block.contents[0].type === "list" || !block.autoTemplate && HAND_DRAWN_TEMPLATES.has(resolveTemplateName(block.template ?? "")) && !!block.children?.length
|
|
1884
|
+
).map((block) => block.id)
|
|
1885
|
+
);
|
|
1941
1886
|
const beats = [];
|
|
1887
|
+
let lastStat = -Infinity;
|
|
1888
|
+
let lastEmphasis = -Infinity;
|
|
1942
1889
|
const supportingOpeners = /* @__PURE__ */ new Set();
|
|
1943
1890
|
const quotes = /* @__PURE__ */ new Map();
|
|
1944
1891
|
const perSection = hints.density === "section";
|
|
@@ -1951,7 +1898,7 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
1951
1898
|
const inbetweens = !perSection && (hint?.inbetweens ?? hints.inbetweens);
|
|
1952
1899
|
const heading = block.heading?.trim();
|
|
1953
1900
|
const headingEnd = block.charStart + (heading?.length ?? 0);
|
|
1954
|
-
if (hint?.layout === AUTHORED_PRESENTATION_LAYOUT) {
|
|
1901
|
+
if (hint?.layout === AUTHORED_PRESENTATION_LAYOUT || hint?.layout === void 0 && !wording && drawnLists.has(block.blockId)) {
|
|
1955
1902
|
if (!words.length) continue;
|
|
1956
1903
|
const start = block.charStart + words[0].index;
|
|
1957
1904
|
const last = words[words.length - 1];
|
|
@@ -2034,13 +1981,23 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
2034
1981
|
const cardPoints = shown.slice(0, 4).map((item) => labelledPoint(item.text));
|
|
2035
1982
|
const custom = chunk === 0 ? wording : void 0;
|
|
2036
1983
|
if (custom?.headline) headline = custom.headline;
|
|
2037
|
-
const pointsFor = (layout2) => custom?.points ?? (["steps", "process", "cycle"].includes(layout2) ? stepPoints : layout2 === "cards" ? cardPoints : textPoints);
|
|
1984
|
+
const pointsFor = (layout2) => custom?.points ?? (["steps", "process", "cycle"].includes(layout2) ? stepPoints : layout2 === "cards" ? cardPoints : layout2 === "stat" && statPoints ? statPoints : layout2 === "emphasis" && takeaway ? [] : textPoints);
|
|
2038
1985
|
const quote = custom?.headline ? void 0 : body.find((sentence) => sentence.text.length <= 110)?.text;
|
|
2039
|
-
const headlineFor = (layout2) => layout2 === "quote" && quote ? quote : headline;
|
|
1986
|
+
const headlineFor = (layout2) => layout2 === "quote" && quote ? quote : layout2 === "emphasis" && takeaway ? headlineText(takeaway) : headline;
|
|
2040
1987
|
let layout = index === 0 ? "title" : textPoints.length >= 2 ? "cards" : "statement";
|
|
2041
|
-
if (sequence)
|
|
1988
|
+
if (sequence)
|
|
1989
|
+
layout = steps.length >= 3 && shapeIsStated("cycle", { heading, passage: prose, items: stepPoints }) ? "cycle" : "steps";
|
|
2042
1990
|
else if (textPoints.length === 2 && /\b(versus|whereas|compared|instead)\b/iu.test(prose))
|
|
2043
1991
|
layout = "comparison";
|
|
1992
|
+
const figureLine = !sequence && !custom && index > 0 && index - lastStat >= STAT_SPACING ? shown.find((sentence) => strikingFigure(sentence.text)) : void 0;
|
|
1993
|
+
const statPoints = figureLine ? [
|
|
1994
|
+
pointText(figureLine.text),
|
|
1995
|
+
...shown.filter((sentence) => sentence !== figureLine && !strikingFigure(sentence.text)).slice(0, 1).map((item) => pointText(item.text))
|
|
1996
|
+
] : void 0;
|
|
1997
|
+
if (statPoints && !matchNumberHighlight(headline) && presentationLayoutFits("stat", headline, statPoints, passage))
|
|
1998
|
+
layout = "stat";
|
|
1999
|
+
const takeaway = layout === "statement" && !!heading && chunk > 0 && index - lastEmphasis >= 2 && shown.length === 1 && shown[0].text.length <= EMPHASIS_SENTENCE_CHARACTERS ? shown[0].text : void 0;
|
|
2000
|
+
if (takeaway) layout = "emphasis";
|
|
2044
2001
|
if (image) layout = "image";
|
|
2045
2002
|
if (preferred && (preferred === "image" ? !!image : presentationLayoutFits(
|
|
2046
2003
|
preferred,
|
|
@@ -2059,6 +2016,8 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
2059
2016
|
...layout === "image" && image?.src ? { imageSrc: image.src } : {}
|
|
2060
2017
|
};
|
|
2061
2018
|
if (quote) quotes.set(beat.id, quote);
|
|
2019
|
+
if (beat.layout === "stat") lastStat = index;
|
|
2020
|
+
if (beat.layout === "emphasis") lastEmphasis = index;
|
|
2062
2021
|
let split;
|
|
2063
2022
|
if (inbetweens && !custom?.points && layout === "steps" && sequence) {
|
|
2064
2023
|
if (shown.some((sentence) => sentence.end <= steps[0].start)) split = steps[0].start;
|
|
@@ -2132,6 +2091,7 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
2132
2091
|
beat.headline = cached.headline;
|
|
2133
2092
|
beat.points = [...cached.points];
|
|
2134
2093
|
beat.layout = cached.layout;
|
|
2094
|
+
Object.assign(beat, presentationBeatExtras(cached.layout, cached));
|
|
2135
2095
|
suggested.add(beat.id);
|
|
2136
2096
|
origin = "ai";
|
|
2137
2097
|
}
|
|
@@ -2173,9 +2133,13 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
2173
2133
|
if (refs.length) beat.media = refs;
|
|
2174
2134
|
});
|
|
2175
2135
|
}
|
|
2136
|
+
const mediaKinds = new Map(
|
|
2137
|
+
[...sectionMedia.values()].flatMap((items) => items.map((item) => [item.ref, item.kind]))
|
|
2138
|
+
);
|
|
2176
2139
|
for (const beat of beats) {
|
|
2177
2140
|
if (!beat.media) continue;
|
|
2178
|
-
|
|
2141
|
+
const drawn = !!conceptTemplate(beat.layout) && !beat.media.some((ref) => mediaKinds.get(ref) === "table");
|
|
2142
|
+
if (!worded.has(beat.id) && !drawn) {
|
|
2179
2143
|
const points = beat.points.slice(0, FEATURE_POINTS);
|
|
2180
2144
|
beat.points = suggested.has(beat.id) ? points : points.map(featurePointText);
|
|
2181
2145
|
}
|
|
@@ -2189,56 +2153,14 @@ function createPresentationPlan(doc, hints = defaultPresentationHints()) {
|
|
|
2189
2153
|
))
|
|
2190
2154
|
beat.layout = "statement";
|
|
2191
2155
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2195
|
-
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
return CONCEPT_TEMPLATES.find((name) => name === template);
|
|
2199
|
-
}
|
|
2200
|
-
function stems(text3) {
|
|
2201
|
-
return (text3.toLowerCase().match(/[\p{L}\p{N}][\p{L}\p{N}'-]*/gu) ?? []).filter((word) => word.length >= 4).map((word) => word.slice(0, 5));
|
|
2202
|
-
}
|
|
2203
|
-
function matchPointsToSentences(points, sourceText, start, end) {
|
|
2204
|
-
const passage = sourceText.slice(start, end);
|
|
2205
|
-
const sentences = [...passage.matchAll(/[^.!?\n]+[.!?]*/gu)].map((match) => ({
|
|
2206
|
-
offset: start + match.index,
|
|
2207
|
-
words: new Set(stems(match[0]))
|
|
2208
|
-
}));
|
|
2209
|
-
let last = -1;
|
|
2210
|
-
const offsets = [];
|
|
2211
|
-
for (const point of points) {
|
|
2212
|
-
const words = stems(point);
|
|
2213
|
-
let best;
|
|
2214
|
-
for (const sentence of sentences) {
|
|
2215
|
-
const shared = words.filter((word) => sentence.words.has(word)).length;
|
|
2216
|
-
if (shared > (best?.shared ?? 1)) best = { offset: sentence.offset, shared };
|
|
2217
|
-
}
|
|
2218
|
-
if (!best || best.offset < last) return void 0;
|
|
2219
|
-
offsets.push(last = best.offset);
|
|
2156
|
+
for (const beat of beats) {
|
|
2157
|
+
const extras = presentationBeatExtras(beat.layout, beat);
|
|
2158
|
+
delete beat.center;
|
|
2159
|
+
delete beat.xAxis;
|
|
2160
|
+
delete beat.yAxis;
|
|
2161
|
+
Object.assign(beat, extras);
|
|
2220
2162
|
}
|
|
2221
|
-
return
|
|
2222
|
-
}
|
|
2223
|
-
function conceptBuildSpec() {
|
|
2224
|
-
return { mode: "items", effect: "fadeInUp", previous: "keep" };
|
|
2225
|
-
}
|
|
2226
|
-
function conceptRevealTiming(template, items, itemTimes, start, end) {
|
|
2227
|
-
const build = conceptBuildSpec();
|
|
2228
|
-
const steps = conceptBuildStepTexts(template, items);
|
|
2229
|
-
if (!itemTimes || itemTimes.length !== steps.length) return { build };
|
|
2230
|
-
const lead = Math.min(0.5, (end - start) / 8);
|
|
2231
|
-
const starts = itemTimes.map(
|
|
2232
|
-
(time) => Math.min(Math.max(0, end - start - 0.1), Math.max(lead, time - start))
|
|
2233
|
-
);
|
|
2234
|
-
starts[0] = Math.min(starts[0], Math.max(lead, Math.min(1, (end - start) / 6)));
|
|
2235
|
-
return {
|
|
2236
|
-
build,
|
|
2237
|
-
buildTiming: {
|
|
2238
|
-
sourceText: buildSourceText(steps.map((text3, index) => ({ id: `build-${index}`, text: text3 }))),
|
|
2239
|
-
starts
|
|
2240
|
-
}
|
|
2241
|
-
};
|
|
2163
|
+
return { version: 1, sourceText: script.sourceText, origin, beats };
|
|
2242
2164
|
}
|
|
2243
2165
|
|
|
2244
2166
|
// src/transform/presentationCompiler.ts
|
|
@@ -2397,11 +2319,15 @@ function compilePresentationPlan(doc, plan) {
|
|
|
2397
2319
|
if (beat.layout === AUTHORED_PRESENTATION_LAYOUT) {
|
|
2398
2320
|
if (!authored) throw new Error("A section shown as authored is no longer in the document.");
|
|
2399
2321
|
const { children, media: _media, ...own } = authored;
|
|
2322
|
+
const drawn = conceptTemplate(authored.template ?? "");
|
|
2323
|
+
const given = authored.templateData?.items;
|
|
2324
|
+
const items = drawn && !build ? Array.isArray(given) ? given.map((item) => String(item ?? "")) : extractConceptItems(authored.contents) : [];
|
|
2400
2325
|
blocks.push({
|
|
2401
2326
|
...own,
|
|
2402
2327
|
...base,
|
|
2403
2328
|
...children && isContainerTemplate(authored.template) ? { children } : {},
|
|
2404
|
-
transition: authored.transition ?? base.transition
|
|
2329
|
+
transition: authored.transition ?? base.transition,
|
|
2330
|
+
...drawn && items.length ? conceptReveal(drawn, { ...beat, points: items }, start, end, script.sourceText, timeAt) : {}
|
|
2405
2331
|
});
|
|
2406
2332
|
continue;
|
|
2407
2333
|
}
|
|
@@ -2437,9 +2363,9 @@ function conceptReveal(template, beat, start, end, sourceText, timeAt) {
|
|
|
2437
2363
|
return conceptRevealTiming(template, beat.points, offsets?.map(timeAt), start, end);
|
|
2438
2364
|
}
|
|
2439
2365
|
function tableFeatureBlock(beat, layout, base, features) {
|
|
2440
|
-
const paragraph = (
|
|
2366
|
+
const paragraph = (text2) => ({
|
|
2441
2367
|
type: "paragraph",
|
|
2442
|
-
children: [{ type: "text", value:
|
|
2368
|
+
children: [{ type: "text", value: text2 }]
|
|
2443
2369
|
});
|
|
2444
2370
|
const words = ["list", "steps", "comparison"].includes(layout) && beat.points.length > 1 ? [
|
|
2445
2371
|
{
|
|
@@ -2516,6 +2442,28 @@ function visualBlock(beat, layout, base, index) {
|
|
|
2516
2442
|
return { ...base, template: "cycle", title: beat.headline, items: beat.points };
|
|
2517
2443
|
case "layers":
|
|
2518
2444
|
return { ...base, template: "layers", title: beat.headline, items: beat.points };
|
|
2445
|
+
case "stats":
|
|
2446
|
+
case "pyramid":
|
|
2447
|
+
case "funnel":
|
|
2448
|
+
case "venn":
|
|
2449
|
+
return { ...base, template: layout, title: beat.headline, items: beat.points };
|
|
2450
|
+
case "hub":
|
|
2451
|
+
return {
|
|
2452
|
+
...base,
|
|
2453
|
+
template: "hub",
|
|
2454
|
+
title: beat.headline,
|
|
2455
|
+
items: beat.points,
|
|
2456
|
+
...beat.center ? { center: beat.center } : {}
|
|
2457
|
+
};
|
|
2458
|
+
case "matrix":
|
|
2459
|
+
return {
|
|
2460
|
+
...base,
|
|
2461
|
+
template: "matrix",
|
|
2462
|
+
title: beat.headline,
|
|
2463
|
+
items: beat.points,
|
|
2464
|
+
...beat.xAxis ? { xAxis: beat.xAxis } : {},
|
|
2465
|
+
...beat.yAxis ? { yAxis: beat.yAxis } : {}
|
|
2466
|
+
};
|
|
2519
2467
|
}
|
|
2520
2468
|
}
|
|
2521
2469
|
function applySavedPresentation(doc) {
|
|
@@ -2547,14 +2495,6 @@ function applySavedPresentation(doc) {
|
|
|
2547
2495
|
}
|
|
2548
2496
|
|
|
2549
2497
|
export {
|
|
2550
|
-
PRESENTATION_KEY,
|
|
2551
|
-
PRESENTATION_LAYOUTS,
|
|
2552
|
-
AUTHORED_PRESENTATION_LAYOUT,
|
|
2553
|
-
presentationStat,
|
|
2554
|
-
presentationLayoutFits,
|
|
2555
|
-
PRESENTATION_LIMITS,
|
|
2556
|
-
parsePresentationPlan,
|
|
2557
|
-
serializePresentationPlan,
|
|
2558
2498
|
PRESENTATION_HINTS_KEY,
|
|
2559
2499
|
DYNAMIC_PRESENTATION_STYLE,
|
|
2560
2500
|
presentationPassageKey,
|
|
@@ -2573,13 +2513,11 @@ export {
|
|
|
2573
2513
|
allocateTiming,
|
|
2574
2514
|
applyTransform,
|
|
2575
2515
|
transformNarratedSegment,
|
|
2576
|
-
collectPresentationMedia,
|
|
2577
|
-
createPresentationPlan,
|
|
2578
|
-
CONCEPT_TEMPLATES,
|
|
2579
|
-
conceptTemplate,
|
|
2580
2516
|
matchPointsToSentences,
|
|
2581
2517
|
conceptBuildSpec,
|
|
2582
2518
|
conceptRevealTiming,
|
|
2519
|
+
collectPresentationMedia,
|
|
2520
|
+
createPresentationPlan,
|
|
2583
2521
|
compilePresentationPlan,
|
|
2584
2522
|
applySavedPresentation
|
|
2585
2523
|
};
|