@particle-academy/fancy-slides 0.4.0 → 0.5.1
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/README.md +9 -0
- package/dist/index.cjs +231 -114
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +109 -68
- package/dist/index.d.ts +109 -68
- package/dist/index.js +230 -116
- package/dist/index.js.map +1 -1
- package/dist/registry.d.cts +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/{types-P-9MmnGU.d.cts → types-9BbelJX1.d.cts} +10 -0
- package/dist/{types-P-9MmnGU.d.ts → types-9BbelJX1.d.ts} +10 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -94,9 +94,18 @@ element.animation = {
|
|
|
94
94
|
duration: 500, // ms
|
|
95
95
|
delay: 0, // ms
|
|
96
96
|
order: 0, // build order, ascending; ties broken by element index
|
|
97
|
+
byParagraph: false, // text only — reveal one line/bullet per click
|
|
97
98
|
};
|
|
98
99
|
```
|
|
99
100
|
|
|
101
|
+
For a **text** element you can set `byParagraph: true` to reveal it one
|
|
102
|
+
paragraph at a time (PowerPoint/Google Slides "By paragraph"). The element's
|
|
103
|
+
`content` is split on `"\n"` (a trailing empty line is dropped) and expands into
|
|
104
|
+
one build per line — the first line uses the element's own `trigger`, every
|
|
105
|
+
subsequent line reveals on a fresh click. Each markdown line renders through the
|
|
106
|
+
normal path, so a `- …` bullet line builds in as its own item. Toggle it from
|
|
107
|
+
the Build tab when a text element has an effect selected.
|
|
108
|
+
|
|
100
109
|
A slide's builds group into *click steps*: the first build and every
|
|
101
110
|
`on-click` build opens a new step; `with-prev` plays alongside that step's lead
|
|
102
111
|
and `after-prev` follows it. In `SlideViewer` / `PresenterView`, → / Space /
|
package/dist/index.cjs
CHANGED
|
@@ -74,6 +74,15 @@ function cn(...parts) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// src/utils/builds.ts
|
|
77
|
+
function splitParagraphs(content) {
|
|
78
|
+
const lines = content.split("\n");
|
|
79
|
+
if (lines.length > 1 && lines[lines.length - 1] === "") lines.pop();
|
|
80
|
+
return lines;
|
|
81
|
+
}
|
|
82
|
+
function isByParagraph(element, animation) {
|
|
83
|
+
if (!animation.byParagraph || element.type !== "text") return false;
|
|
84
|
+
return splitParagraphs(element.content).length > 1;
|
|
85
|
+
}
|
|
77
86
|
var DEFAULT_BUILD_DURATION = 500;
|
|
78
87
|
function collectBuilds(slide) {
|
|
79
88
|
if (!slide) return [];
|
|
@@ -83,12 +92,25 @@ function collectBuilds(slide) {
|
|
|
83
92
|
builds.push({ element, animation: element.animation, index });
|
|
84
93
|
}
|
|
85
94
|
});
|
|
86
|
-
|
|
95
|
+
const ordered = builds.sort((a, b) => {
|
|
87
96
|
const ao = a.animation.order ?? 0;
|
|
88
97
|
const bo = b.animation.order ?? 0;
|
|
89
98
|
if (ao !== bo) return ao - bo;
|
|
90
99
|
return a.index - b.index;
|
|
91
100
|
});
|
|
101
|
+
const expanded = [];
|
|
102
|
+
for (const build of ordered) {
|
|
103
|
+
if (isByParagraph(build.element, build.animation)) {
|
|
104
|
+
const paras = splitParagraphs(build.element.content);
|
|
105
|
+
paras.forEach((_, paraIndex) => {
|
|
106
|
+
const animation = paraIndex === 0 ? build.animation : { ...build.animation, trigger: "on-click" };
|
|
107
|
+
expanded.push({ element: build.element, animation, index: build.index, paraIndex });
|
|
108
|
+
});
|
|
109
|
+
} else {
|
|
110
|
+
expanded.push(build);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return expanded;
|
|
92
114
|
}
|
|
93
115
|
function buildSteps(slide) {
|
|
94
116
|
const builds = collectBuilds(slide);
|
|
@@ -112,7 +134,9 @@ function visibleElementIds(slide, buildStep) {
|
|
|
112
134
|
const steps = buildSteps(slide);
|
|
113
135
|
const stepOfElement = /* @__PURE__ */ new Map();
|
|
114
136
|
steps.forEach((step, i) => {
|
|
115
|
-
for (const b of step.builds)
|
|
137
|
+
for (const b of step.builds) {
|
|
138
|
+
if (!stepOfElement.has(b.element.id)) stepOfElement.set(b.element.id, i + 1);
|
|
139
|
+
}
|
|
116
140
|
});
|
|
117
141
|
for (const element of slide.elements) {
|
|
118
142
|
const revealStep = stepOfElement.get(element.id);
|
|
@@ -124,6 +148,25 @@ function visibleElementIds(slide, buildStep) {
|
|
|
124
148
|
}
|
|
125
149
|
return visible;
|
|
126
150
|
}
|
|
151
|
+
function paragraphReveals(slide, buildStep) {
|
|
152
|
+
const out = /* @__PURE__ */ new Map();
|
|
153
|
+
if (!slide) return out;
|
|
154
|
+
const steps = buildSteps(slide);
|
|
155
|
+
steps.forEach((step, i) => {
|
|
156
|
+
const stepNum = i + 1;
|
|
157
|
+
for (const b of step.builds) {
|
|
158
|
+
if (b.paraIndex === void 0) continue;
|
|
159
|
+
const fired = buildStep >= stepNum;
|
|
160
|
+
const prev = out.get(b.element.id) ?? { revealed: 0 };
|
|
161
|
+
if (fired) {
|
|
162
|
+
prev.revealed = Math.max(prev.revealed, b.paraIndex + 1);
|
|
163
|
+
if (stepNum === buildStep) prev.firingParaIndex = b.paraIndex;
|
|
164
|
+
}
|
|
165
|
+
out.set(b.element.id, prev);
|
|
166
|
+
}
|
|
167
|
+
});
|
|
168
|
+
return out;
|
|
169
|
+
}
|
|
127
170
|
function buildsForStep(slide, buildStep) {
|
|
128
171
|
const steps = buildSteps(slide);
|
|
129
172
|
const step = steps[buildStep - 1];
|
|
@@ -145,13 +188,95 @@ function stepDelays(builds) {
|
|
|
145
188
|
}
|
|
146
189
|
return delays;
|
|
147
190
|
}
|
|
191
|
+
|
|
192
|
+
// src/components/Slide/builds-style.ts
|
|
193
|
+
var DEFAULT_BUILD_DURATION2 = 500;
|
|
194
|
+
var EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
195
|
+
function buildEnterStyle(animation, effectiveDelay) {
|
|
196
|
+
const duration = animation.duration ?? DEFAULT_BUILD_DURATION2;
|
|
197
|
+
const dir = animation.direction ?? "left";
|
|
198
|
+
let name;
|
|
199
|
+
switch (animation.effect) {
|
|
200
|
+
case "fade":
|
|
201
|
+
name = "fs-build-fade";
|
|
202
|
+
break;
|
|
203
|
+
case "zoom":
|
|
204
|
+
name = "fs-build-zoom";
|
|
205
|
+
break;
|
|
206
|
+
case "fly-in":
|
|
207
|
+
name = `fs-build-fly-${dir}`;
|
|
208
|
+
break;
|
|
209
|
+
case "wipe":
|
|
210
|
+
name = `fs-build-wipe-${dir}`;
|
|
211
|
+
break;
|
|
212
|
+
default:
|
|
213
|
+
name = "fs-build-fade";
|
|
214
|
+
}
|
|
215
|
+
return {
|
|
216
|
+
animationName: name,
|
|
217
|
+
animationDuration: `${duration}ms`,
|
|
218
|
+
animationDelay: `${effectiveDelay}ms`,
|
|
219
|
+
animationTimingFunction: EASE,
|
|
220
|
+
animationFillMode: "both"
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
var BUILD_KEYFRAMES = `
|
|
224
|
+
@media (prefers-reduced-motion: reduce) {
|
|
225
|
+
.fs-build-enter { animation: none !important; }
|
|
226
|
+
}
|
|
227
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
228
|
+
@keyframes fs-build-fade {
|
|
229
|
+
from { opacity: 0; }
|
|
230
|
+
to { opacity: 1; }
|
|
231
|
+
}
|
|
232
|
+
@keyframes fs-build-zoom {
|
|
233
|
+
from { opacity: 0; transform: scale(0.8); }
|
|
234
|
+
to { opacity: 1; transform: scale(1); }
|
|
235
|
+
}
|
|
236
|
+
@keyframes fs-build-fly-left {
|
|
237
|
+
from { opacity: 0; transform: translateX(-24%); }
|
|
238
|
+
to { opacity: 1; transform: translateX(0); }
|
|
239
|
+
}
|
|
240
|
+
@keyframes fs-build-fly-right {
|
|
241
|
+
from { opacity: 0; transform: translateX(24%); }
|
|
242
|
+
to { opacity: 1; transform: translateX(0); }
|
|
243
|
+
}
|
|
244
|
+
@keyframes fs-build-fly-up {
|
|
245
|
+
from { opacity: 0; transform: translateY(24%); }
|
|
246
|
+
to { opacity: 1; transform: translateY(0); }
|
|
247
|
+
}
|
|
248
|
+
@keyframes fs-build-fly-down {
|
|
249
|
+
from { opacity: 0; transform: translateY(-24%); }
|
|
250
|
+
to { opacity: 1; transform: translateY(0); }
|
|
251
|
+
}
|
|
252
|
+
/* wipe: clip-path inset reveals from the named edge toward the opposite one.
|
|
253
|
+
inset(top right bottom left) \u2014 start fully clipped on the far side. */
|
|
254
|
+
@keyframes fs-build-wipe-left {
|
|
255
|
+
from { clip-path: inset(0 100% 0 0); }
|
|
256
|
+
to { clip-path: inset(0 0 0 0); }
|
|
257
|
+
}
|
|
258
|
+
@keyframes fs-build-wipe-right {
|
|
259
|
+
from { clip-path: inset(0 0 0 100%); }
|
|
260
|
+
to { clip-path: inset(0 0 0 0); }
|
|
261
|
+
}
|
|
262
|
+
@keyframes fs-build-wipe-up {
|
|
263
|
+
from { clip-path: inset(100% 0 0 0); }
|
|
264
|
+
to { clip-path: inset(0 0 0 0); }
|
|
265
|
+
}
|
|
266
|
+
@keyframes fs-build-wipe-down {
|
|
267
|
+
from { clip-path: inset(0 0 100% 0); }
|
|
268
|
+
to { clip-path: inset(0 0 0 0); }
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
`;
|
|
148
272
|
function TextElementRenderer({
|
|
149
273
|
element,
|
|
150
274
|
theme,
|
|
151
275
|
slideWidthPx,
|
|
152
276
|
editing = false,
|
|
153
277
|
selected = false,
|
|
154
|
-
onContentChange
|
|
278
|
+
onContentChange,
|
|
279
|
+
paraReveal
|
|
155
280
|
}) {
|
|
156
281
|
const t = resolveTheme(theme);
|
|
157
282
|
const style = element.style ?? {};
|
|
@@ -198,30 +323,53 @@ function TextElementRenderer({
|
|
|
198
323
|
}
|
|
199
324
|
);
|
|
200
325
|
}
|
|
326
|
+
const proseScope = `[data-fs-text-scope="${scopeId}"]`;
|
|
327
|
+
const doubleScope = `${proseScope}${proseScope}`;
|
|
328
|
+
const proseStyle = /* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
329
|
+
${proseScope} > div { width: 100%; height: 100%; font-size: inherit; }
|
|
330
|
+
${doubleScope} :is(p, ul, ol, li, blockquote, h1, h2, h3, h4, h5, h6, pre, code, strong, em, a) {
|
|
331
|
+
font-size: inherit;
|
|
332
|
+
}
|
|
333
|
+
${doubleScope} h1 { font-size: 1.6em; font-weight: 700; }
|
|
334
|
+
${doubleScope} h2 { font-size: 1.35em; font-weight: 700; }
|
|
335
|
+
${doubleScope} h3 { font-size: 1.15em; font-weight: 600; }
|
|
336
|
+
${proseScope} :where(p, ul, ol, h1, h2, h3, h4, h5, h6, pre, blockquote) {
|
|
337
|
+
margin: 0;
|
|
338
|
+
padding: 0;
|
|
339
|
+
}
|
|
340
|
+
${proseScope} :where(p, li) + :where(p, li, ul, ol) { margin-top: 0.4em; }
|
|
341
|
+
${proseScope} :where(ul, ol) { padding-left: 1.4em; }
|
|
342
|
+
${proseScope} :where(strong) { font-weight: ${Math.max(700, weight(style.weight) ?? 400 + 200)}; }
|
|
343
|
+
${proseScope} :where(a) { color: inherit; text-decoration: underline; }
|
|
344
|
+
${proseScope} :where(code) { font-family: ${t.fonts?.mono ?? "monospace"}; }
|
|
345
|
+
` });
|
|
346
|
+
const renderChunk = (content) => format === "plain" ? content : /* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContentRenderer, { value: content, format: format === "html" ? "html" : "markdown" });
|
|
347
|
+
if (paraReveal) {
|
|
348
|
+
const paras = splitParagraphs(element.content);
|
|
349
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-fs-text-scope": scopeId, style: css, children: [
|
|
350
|
+
proseStyle,
|
|
351
|
+
paras.map((para, i) => {
|
|
352
|
+
if (i >= paraReveal.revealed) return null;
|
|
353
|
+
const firing = i === paraReveal.firingParaIndex && !!element.animation;
|
|
354
|
+
const enter = firing ? buildEnterStyle(element.animation, element.animation.delay ?? 0) : null;
|
|
355
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
356
|
+
"div",
|
|
357
|
+
{
|
|
358
|
+
className: firing ? "fs-build-enter" : void 0,
|
|
359
|
+
style: { whiteSpace: format === "plain" ? "pre-wrap" : "normal", ...enter },
|
|
360
|
+
"data-fancy-slides-paragraph": i,
|
|
361
|
+
children: renderChunk(para)
|
|
362
|
+
},
|
|
363
|
+
i
|
|
364
|
+
);
|
|
365
|
+
})
|
|
366
|
+
] });
|
|
367
|
+
}
|
|
201
368
|
if (format === "plain") {
|
|
202
369
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { style: css, children: element.content });
|
|
203
370
|
}
|
|
204
|
-
const proseScope = `[data-fs-text-scope="${scopeId}"]`;
|
|
205
|
-
const doubleScope = `${proseScope}${proseScope}`;
|
|
206
371
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { "data-fs-text-scope": scopeId, style: css, children: [
|
|
207
|
-
|
|
208
|
-
${proseScope} > div { width: 100%; height: 100%; font-size: inherit; }
|
|
209
|
-
${doubleScope} :is(p, ul, ol, li, blockquote, h1, h2, h3, h4, h5, h6, pre, code, strong, em, a) {
|
|
210
|
-
font-size: inherit;
|
|
211
|
-
}
|
|
212
|
-
${doubleScope} h1 { font-size: 1.6em; font-weight: 700; }
|
|
213
|
-
${doubleScope} h2 { font-size: 1.35em; font-weight: 700; }
|
|
214
|
-
${doubleScope} h3 { font-size: 1.15em; font-weight: 600; }
|
|
215
|
-
${proseScope} :where(p, ul, ol, h1, h2, h3, h4, h5, h6, pre, blockquote) {
|
|
216
|
-
margin: 0;
|
|
217
|
-
padding: 0;
|
|
218
|
-
}
|
|
219
|
-
${proseScope} :where(p, li) + :where(p, li, ul, ol) { margin-top: 0.4em; }
|
|
220
|
-
${proseScope} :where(ul, ol) { padding-left: 1.4em; }
|
|
221
|
-
${proseScope} :where(strong) { font-weight: ${Math.max(700, weight(style.weight) ?? 400 + 200)}; }
|
|
222
|
-
${proseScope} :where(a) { color: inherit; text-decoration: underline; }
|
|
223
|
-
${proseScope} :where(code) { font-family: ${t.fonts?.mono ?? "monospace"}; }
|
|
224
|
-
` }),
|
|
372
|
+
proseStyle,
|
|
225
373
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.ContentRenderer, { value: element.content, format: format === "html" ? "html" : "markdown" })
|
|
226
374
|
] });
|
|
227
375
|
}
|
|
@@ -353,87 +501,6 @@ function relativeLuminance(r, g, b) {
|
|
|
353
501
|
};
|
|
354
502
|
return 0.2126 * toLinear(r) + 0.7152 * toLinear(g) + 0.0722 * toLinear(b);
|
|
355
503
|
}
|
|
356
|
-
|
|
357
|
-
// src/components/Slide/builds-style.ts
|
|
358
|
-
var DEFAULT_BUILD_DURATION2 = 500;
|
|
359
|
-
var EASE = "cubic-bezier(0.16, 1, 0.3, 1)";
|
|
360
|
-
function buildEnterStyle(animation, effectiveDelay) {
|
|
361
|
-
const duration = animation.duration ?? DEFAULT_BUILD_DURATION2;
|
|
362
|
-
const dir = animation.direction ?? "left";
|
|
363
|
-
let name;
|
|
364
|
-
switch (animation.effect) {
|
|
365
|
-
case "fade":
|
|
366
|
-
name = "fs-build-fade";
|
|
367
|
-
break;
|
|
368
|
-
case "zoom":
|
|
369
|
-
name = "fs-build-zoom";
|
|
370
|
-
break;
|
|
371
|
-
case "fly-in":
|
|
372
|
-
name = `fs-build-fly-${dir}`;
|
|
373
|
-
break;
|
|
374
|
-
case "wipe":
|
|
375
|
-
name = `fs-build-wipe-${dir}`;
|
|
376
|
-
break;
|
|
377
|
-
default:
|
|
378
|
-
name = "fs-build-fade";
|
|
379
|
-
}
|
|
380
|
-
return {
|
|
381
|
-
animationName: name,
|
|
382
|
-
animationDuration: `${duration}ms`,
|
|
383
|
-
animationDelay: `${effectiveDelay}ms`,
|
|
384
|
-
animationTimingFunction: EASE,
|
|
385
|
-
animationFillMode: "both"
|
|
386
|
-
};
|
|
387
|
-
}
|
|
388
|
-
var BUILD_KEYFRAMES = `
|
|
389
|
-
@media (prefers-reduced-motion: reduce) {
|
|
390
|
-
.fs-build-enter { animation: none !important; }
|
|
391
|
-
}
|
|
392
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
393
|
-
@keyframes fs-build-fade {
|
|
394
|
-
from { opacity: 0; }
|
|
395
|
-
to { opacity: 1; }
|
|
396
|
-
}
|
|
397
|
-
@keyframes fs-build-zoom {
|
|
398
|
-
from { opacity: 0; transform: scale(0.8); }
|
|
399
|
-
to { opacity: 1; transform: scale(1); }
|
|
400
|
-
}
|
|
401
|
-
@keyframes fs-build-fly-left {
|
|
402
|
-
from { opacity: 0; transform: translateX(-24%); }
|
|
403
|
-
to { opacity: 1; transform: translateX(0); }
|
|
404
|
-
}
|
|
405
|
-
@keyframes fs-build-fly-right {
|
|
406
|
-
from { opacity: 0; transform: translateX(24%); }
|
|
407
|
-
to { opacity: 1; transform: translateX(0); }
|
|
408
|
-
}
|
|
409
|
-
@keyframes fs-build-fly-up {
|
|
410
|
-
from { opacity: 0; transform: translateY(24%); }
|
|
411
|
-
to { opacity: 1; transform: translateY(0); }
|
|
412
|
-
}
|
|
413
|
-
@keyframes fs-build-fly-down {
|
|
414
|
-
from { opacity: 0; transform: translateY(-24%); }
|
|
415
|
-
to { opacity: 1; transform: translateY(0); }
|
|
416
|
-
}
|
|
417
|
-
/* wipe: clip-path inset reveals from the named edge toward the opposite one.
|
|
418
|
-
inset(top right bottom left) \u2014 start fully clipped on the far side. */
|
|
419
|
-
@keyframes fs-build-wipe-left {
|
|
420
|
-
from { clip-path: inset(0 100% 0 0); }
|
|
421
|
-
to { clip-path: inset(0 0 0 0); }
|
|
422
|
-
}
|
|
423
|
-
@keyframes fs-build-wipe-right {
|
|
424
|
-
from { clip-path: inset(0 0 0 100%); }
|
|
425
|
-
to { clip-path: inset(0 0 0 0); }
|
|
426
|
-
}
|
|
427
|
-
@keyframes fs-build-wipe-up {
|
|
428
|
-
from { clip-path: inset(100% 0 0 0); }
|
|
429
|
-
to { clip-path: inset(0 0 0 0); }
|
|
430
|
-
}
|
|
431
|
-
@keyframes fs-build-wipe-down {
|
|
432
|
-
from { clip-path: inset(0 0 100% 0); }
|
|
433
|
-
to { clip-path: inset(0 0 0 0); }
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
`;
|
|
437
504
|
function Slide({
|
|
438
505
|
slide,
|
|
439
506
|
theme,
|
|
@@ -490,13 +557,16 @@ function Slide({
|
|
|
490
557
|
if (steps.length === 0) return null;
|
|
491
558
|
const revealStep = /* @__PURE__ */ new Map();
|
|
492
559
|
steps.forEach((step, i) => {
|
|
493
|
-
for (const b of step.builds)
|
|
560
|
+
for (const b of step.builds) {
|
|
561
|
+
if (!revealStep.has(b.element.id)) revealStep.set(b.element.id, i + 1);
|
|
562
|
+
}
|
|
494
563
|
});
|
|
495
564
|
const driven = buildStep !== void 0;
|
|
496
565
|
const currentStep = driven ? buildStep : steps.length;
|
|
497
566
|
const firing = driven ? steps[currentStep - 1] : void 0;
|
|
498
567
|
const delays = firing ? stepDelays(firing.builds) : /* @__PURE__ */ new Map();
|
|
499
|
-
|
|
568
|
+
const paraReveals = driven ? paragraphReveals(slide, currentStep) : /* @__PURE__ */ new Map();
|
|
569
|
+
return { revealStep, currentStep, delays, paraReveals, driven };
|
|
500
570
|
}, [editing, slide, buildStep]);
|
|
501
571
|
return /* @__PURE__ */ jsxRuntime.jsx(SlideContext.Provider, { value: slideContext, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
502
572
|
"div",
|
|
@@ -522,12 +592,13 @@ function Slide({
|
|
|
522
592
|
let buildHidden = false;
|
|
523
593
|
let buildAnimation;
|
|
524
594
|
let buildDelay = 0;
|
|
595
|
+
const paraReveal = buildInfo?.paraReveals.get(element.id);
|
|
525
596
|
if (buildInfo) {
|
|
526
597
|
const step = buildInfo.revealStep.get(element.id);
|
|
527
598
|
if (step !== void 0) {
|
|
528
599
|
if (buildInfo.currentStep < step) {
|
|
529
600
|
buildHidden = true;
|
|
530
|
-
} else if (buildInfo.currentStep === step && element.animation) {
|
|
601
|
+
} else if (paraReveal) ; else if (buildInfo.currentStep === step && element.animation) {
|
|
531
602
|
buildAnimation = element.animation;
|
|
532
603
|
buildDelay = buildInfo.delays.get(element.id) ?? 0;
|
|
533
604
|
}
|
|
@@ -549,7 +620,8 @@ function Slide({
|
|
|
549
620
|
onResize: onElementResize,
|
|
550
621
|
renderElement,
|
|
551
622
|
buildAnimation,
|
|
552
|
-
buildDelay
|
|
623
|
+
buildDelay,
|
|
624
|
+
paraReveal
|
|
553
625
|
},
|
|
554
626
|
element.id
|
|
555
627
|
);
|
|
@@ -573,7 +645,8 @@ function SlideElementHost({
|
|
|
573
645
|
onResize,
|
|
574
646
|
renderElement,
|
|
575
647
|
buildAnimation,
|
|
576
|
-
buildDelay = 0
|
|
648
|
+
buildDelay = 0,
|
|
649
|
+
paraReveal
|
|
577
650
|
}) {
|
|
578
651
|
const dragRef = react.useRef(null);
|
|
579
652
|
if (element.hidden) return null;
|
|
@@ -645,7 +718,7 @@ function SlideElementHost({
|
|
|
645
718
|
touchAction: canMove ? "none" : void 0,
|
|
646
719
|
...buildAnimation ? buildEnterStyle(buildAnimation, buildDelay) : null
|
|
647
720
|
};
|
|
648
|
-
const inner = renderInner({ element, theme, slideWidthPx, editing, selected, onContentChange }) ?? renderElement?.(element, slideWidthPx);
|
|
721
|
+
const inner = renderInner({ element, theme, slideWidthPx, editing, selected, onContentChange, paraReveal }) ?? renderElement?.(element, slideWidthPx) ?? elementPlaceholder(element);
|
|
649
722
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
650
723
|
"div",
|
|
651
724
|
{
|
|
@@ -712,7 +785,7 @@ function ResizeHandles({ onStart, onMove, onEnd }) {
|
|
|
712
785
|
anchor
|
|
713
786
|
)) });
|
|
714
787
|
}
|
|
715
|
-
function renderInner({ element, theme, slideWidthPx, editing, selected, onContentChange }) {
|
|
788
|
+
function renderInner({ element, theme, slideWidthPx, editing, selected, onContentChange, paraReveal }) {
|
|
716
789
|
switch (element.type) {
|
|
717
790
|
case "text":
|
|
718
791
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -723,7 +796,8 @@ function renderInner({ element, theme, slideWidthPx, editing, selected, onConten
|
|
|
723
796
|
slideWidthPx,
|
|
724
797
|
editing,
|
|
725
798
|
selected,
|
|
726
|
-
onContentChange: onContentChange ? (c) => onContentChange(element.id, c) : void 0
|
|
799
|
+
onContentChange: onContentChange ? (c) => onContentChange(element.id, c) : void 0,
|
|
800
|
+
paraReveal
|
|
727
801
|
}
|
|
728
802
|
);
|
|
729
803
|
case "image":
|
|
@@ -739,6 +813,37 @@ function renderInner({ element, theme, slideWidthPx, editing, selected, onConten
|
|
|
739
813
|
return null;
|
|
740
814
|
}
|
|
741
815
|
}
|
|
816
|
+
function elementPlaceholder(element) {
|
|
817
|
+
if (element.type !== "chart" && element.type !== "code" && element.type !== "table" && element.type !== "embed") {
|
|
818
|
+
return null;
|
|
819
|
+
}
|
|
820
|
+
const label = element.type.charAt(0).toUpperCase() + element.type.slice(1);
|
|
821
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
822
|
+
"div",
|
|
823
|
+
{
|
|
824
|
+
style: {
|
|
825
|
+
width: "100%",
|
|
826
|
+
height: "100%",
|
|
827
|
+
display: "flex",
|
|
828
|
+
flexDirection: "column",
|
|
829
|
+
alignItems: "center",
|
|
830
|
+
justifyContent: "center",
|
|
831
|
+
gap: "0.35em",
|
|
832
|
+
textAlign: "center",
|
|
833
|
+
padding: "0.5em",
|
|
834
|
+
boxSizing: "border-box",
|
|
835
|
+
border: "1px dashed currentColor",
|
|
836
|
+
borderRadius: 8,
|
|
837
|
+
opacity: 0.55,
|
|
838
|
+
overflow: "hidden"
|
|
839
|
+
},
|
|
840
|
+
children: [
|
|
841
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontWeight: 600 }, children: label }),
|
|
842
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: "0.7em", opacity: 0.8 }, children: "Pass renderElement to render" })
|
|
843
|
+
]
|
|
844
|
+
}
|
|
845
|
+
);
|
|
846
|
+
}
|
|
742
847
|
function orderedElements(elements) {
|
|
743
848
|
return [...elements].sort((a, b) => {
|
|
744
849
|
const az = a.z ?? -1;
|
|
@@ -1897,7 +2002,7 @@ function ElementInspector({ element, onPatch, onDelete, onLockToggle, slide, onS
|
|
|
1897
2002
|
] }),
|
|
1898
2003
|
/* @__PURE__ */ jsxRuntime.jsxs(reactFancy.Tabs.Panels, { children: [
|
|
1899
2004
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tabs.Panel, { value: "style", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsx(StyleSection, { element, onPatch }) }) }),
|
|
1900
|
-
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tabs.Panel, { value: "build", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsx(AnimateSection, { animation: element.animation, onSetAnimation }) }) }),
|
|
2005
|
+
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tabs.Panel, { value: "build", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsx(AnimateSection, { animation: element.animation, onSetAnimation, isText: element.type === "text" }) }) }),
|
|
1901
2006
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tabs.Panel, { value: "layout", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsx(LayoutSection, { element, onPatch }) }) }),
|
|
1902
2007
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Tabs.Panel, { value: "advanced", children: /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Card, { padding: "md", className: "!bg-white dark:!bg-zinc-950", children: /* @__PURE__ */ jsxRuntime.jsx(AdvancedSection, { element, onPatch }) }) })
|
|
1903
2008
|
] })
|
|
@@ -2047,7 +2152,8 @@ function AdvancedSection({ element, onPatch }) {
|
|
|
2047
2152
|
var NO_ANIMATION = "none";
|
|
2048
2153
|
function AnimateSection({
|
|
2049
2154
|
animation,
|
|
2050
|
-
onSetAnimation
|
|
2155
|
+
onSetAnimation,
|
|
2156
|
+
isText
|
|
2051
2157
|
}) {
|
|
2052
2158
|
if (!onSetAnimation) {
|
|
2053
2159
|
return /* @__PURE__ */ jsxRuntime.jsx(reactFancy.Text, { size: "sm", className: "!text-zinc-500", children: "Build animations aren't wired up in this editor." });
|
|
@@ -2134,6 +2240,14 @@ function AnimateSection({
|
|
|
2134
2240
|
onChange: (e) => set({ order: parseInt(e.target.value, 10) || 0 })
|
|
2135
2241
|
}
|
|
2136
2242
|
),
|
|
2243
|
+
isText && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2244
|
+
reactFancy.Switch,
|
|
2245
|
+
{
|
|
2246
|
+
label: "Animate by paragraph (one line per click)",
|
|
2247
|
+
checked: !!animation?.byParagraph,
|
|
2248
|
+
onCheckedChange: (v) => set({ byParagraph: v })
|
|
2249
|
+
}
|
|
2250
|
+
),
|
|
2137
2251
|
/* @__PURE__ */ jsxRuntime.jsx(reactFancy.Text, { size: "xs", className: "!text-zinc-500", children: `Builds reveal in ascending order. "On click" starts a new step; "with previous" plays alongside the step's lead; "after previous" follows it. Honors prefers-reduced-motion.` })
|
|
2138
2252
|
] })
|
|
2139
2253
|
] });
|
|
@@ -2847,10 +2961,13 @@ exports.deckId = deckId;
|
|
|
2847
2961
|
exports.defaultTheme = defaultTheme;
|
|
2848
2962
|
exports.defineTheme = defineTheme;
|
|
2849
2963
|
exports.elementId = elementId;
|
|
2964
|
+
exports.isByParagraph = isByParagraph;
|
|
2850
2965
|
exports.nextId = nextId;
|
|
2966
|
+
exports.paragraphReveals = paragraphReveals;
|
|
2851
2967
|
exports.reduceDeck = reduce;
|
|
2852
2968
|
exports.resolveTheme = resolveTheme;
|
|
2853
2969
|
exports.slideId = slideId;
|
|
2970
|
+
exports.splitParagraphs = splitParagraphs;
|
|
2854
2971
|
exports.stepDelays = stepDelays;
|
|
2855
2972
|
exports.totalBuildSteps = totalBuildSteps;
|
|
2856
2973
|
exports.useDeckState = useDeckState;
|