@kadal/deck 0.0.0-stage → 0.1.0

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.
Files changed (157) hide show
  1. package/LICENSE +661 -0
  2. package/LICENSING.md +40 -0
  3. package/README.md +170 -2
  4. package/dist/_virtual/_rolldown/runtime.js +13 -0
  5. package/dist/audience/index.d.ts +14 -0
  6. package/dist/audience/index.js +680 -0
  7. package/dist/backgrounds/index.d.ts +65 -0
  8. package/dist/backgrounds/index.js +604 -0
  9. package/dist/backgrounds/shared.d.ts +7 -0
  10. package/dist/backgrounds/shared.js +89 -0
  11. package/dist/cli/bin.d.ts +1 -0
  12. package/dist/cli/bin.js +8 -0
  13. package/dist/cli/host.js +111 -0
  14. package/dist/cli/index.d.ts +4 -0
  15. package/dist/cli/index.js +140 -0
  16. package/dist/cli/login.js +56 -0
  17. package/dist/cli/publish.js +159 -0
  18. package/dist/cli/vite.js +39 -0
  19. package/dist/compiler/code-meta.d.ts +33 -0
  20. package/dist/compiler/code-meta.js +81 -0
  21. package/dist/compiler/index.d.ts +8 -0
  22. package/dist/compiler/index.js +8 -0
  23. package/dist/compiler/magic-move.d.ts +26 -0
  24. package/dist/compiler/magic-move.js +33 -0
  25. package/dist/compiler/plain-text.js +7 -0
  26. package/dist/compiler/rehype-code.d.ts +18 -0
  27. package/dist/compiler/rehype-code.js +66 -0
  28. package/dist/compiler/rehype-glossary.d.ts +35 -0
  29. package/dist/compiler/rehype-glossary.js +211 -0
  30. package/dist/compiler/slots.d.ts +3 -0
  31. package/dist/compiler/slots.js +36 -0
  32. package/dist/compiler/split.d.ts +63 -0
  33. package/dist/compiler/split.js +195 -0
  34. package/dist/components/Background.d.ts +15 -0
  35. package/dist/components/Background.js +24 -0
  36. package/dist/components/Click.d.ts +54 -0
  37. package/dist/components/Click.js +129 -0
  38. package/dist/components/Code.d.ts +27 -0
  39. package/dist/components/Code.js +124 -0
  40. package/dist/components/Motion.d.ts +25 -0
  41. package/dist/components/Motion.js +45 -0
  42. package/dist/components/Sketch.d.ts +44 -0
  43. package/dist/components/Sketch.js +141 -0
  44. package/dist/components/Term.d.ts +63 -0
  45. package/dist/components/Term.js +492 -0
  46. package/dist/components/bling.d.ts +75 -0
  47. package/dist/components/bling.js +146 -0
  48. package/dist/components/content.d.ts +232 -0
  49. package/dist/components/content.js +637 -0
  50. package/dist/components/index.d.ts +10 -0
  51. package/dist/components/index.js +88 -0
  52. package/dist/core/clicks.d.ts +45 -0
  53. package/dist/core/clicks.js +75 -0
  54. package/dist/core/hash.d.ts +33 -0
  55. package/dist/core/hash.js +49 -0
  56. package/dist/core/keyboard.d.ts +17 -0
  57. package/dist/core/keyboard.js +198 -0
  58. package/dist/core/layout.d.ts +16 -0
  59. package/dist/core/layout.js +25 -0
  60. package/dist/core/model.d.ts +259 -0
  61. package/dist/core/model.js +377 -0
  62. package/dist/core/navigation.d.ts +74 -0
  63. package/dist/core/navigation.js +244 -0
  64. package/dist/core/poster.js +30 -0
  65. package/dist/core/store.d.ts +20 -0
  66. package/dist/core/store.js +64 -0
  67. package/dist/core/touch.js +27 -0
  68. package/dist/draw/DrawingLayer.js +315 -0
  69. package/dist/draw/strokes.js +188 -0
  70. package/dist/export/index.d.ts +68 -0
  71. package/dist/export/index.js +251 -0
  72. package/dist/export/run.js +81 -0
  73. package/dist/glossary/model.d.ts +81 -0
  74. package/dist/glossary/model.js +156 -0
  75. package/dist/glossary/parse.d.ts +27 -0
  76. package/dist/glossary/parse.js +90 -0
  77. package/dist/index.d.ts +31 -0
  78. package/dist/index.js +30 -0
  79. package/dist/live/LiveProvider.d.ts +20 -0
  80. package/dist/live/LiveProvider.js +450 -0
  81. package/dist/live/analytics.d.ts +15 -0
  82. package/dist/live/analytics.js +103 -0
  83. package/dist/live/client.d.ts +51 -0
  84. package/dist/live/client.js +193 -0
  85. package/dist/live/components.d.ts +64 -0
  86. package/dist/live/components.js +471 -0
  87. package/dist/live/context.d.ts +15 -0
  88. package/dist/live/context.js +28 -0
  89. package/dist/live/index.d.ts +7 -0
  90. package/dist/live/index.js +7 -0
  91. package/dist/live/protocol.d.ts +284 -0
  92. package/dist/live/protocol.js +42 -0
  93. package/dist/live/turnstile.js +49 -0
  94. package/dist/presenter/index.d.ts +20 -0
  95. package/dist/presenter/index.js +1211 -0
  96. package/dist/react/AutoAnimate.js +92 -0
  97. package/dist/react/Backgrounds.d.ts +11 -0
  98. package/dist/react/Backgrounds.js +154 -0
  99. package/dist/react/ConfettiLayer.js +85 -0
  100. package/dist/react/Deck.d.ts +35 -0
  101. package/dist/react/Deck.js +983 -0
  102. package/dist/react/Frame.d.ts +16 -0
  103. package/dist/react/Frame.js +174 -0
  104. package/dist/react/Hints.d.ts +3 -0
  105. package/dist/react/Hints.js +201 -0
  106. package/dist/react/Lightbox.js +54 -0
  107. package/dist/react/Overview.js +93 -0
  108. package/dist/react/PrintView.js +128 -0
  109. package/dist/react/ScrollView.js +128 -0
  110. package/dist/react/SlideFrame.d.ts +51 -0
  111. package/dist/react/SlideFrame.js +323 -0
  112. package/dist/react/Stage.js +151 -0
  113. package/dist/react/ThemeMenu.d.ts +5 -0
  114. package/dist/react/ThemeMenu.js +124 -0
  115. package/dist/react/Zoom.js +23 -0
  116. package/dist/react/chrome.js +339 -0
  117. package/dist/react/context.d.ts +165 -0
  118. package/dist/react/context.js +19 -0
  119. package/dist/react/hooks.d.ts +33 -0
  120. package/dist/react/hooks.js +70 -0
  121. package/dist/react/layouts.d.ts +21 -0
  122. package/dist/react/layouts.js +104 -0
  123. package/dist/react/mdx.d.ts +4 -0
  124. package/dist/react/mdx.js +33 -0
  125. package/dist/react/terms.d.ts +6 -0
  126. package/dist/react/terms.js +66 -0
  127. package/dist/renderers/Island.d.ts +57 -0
  128. package/dist/renderers/Island.js +223 -0
  129. package/dist/renderers/contract.d.ts +173 -0
  130. package/dist/renderers/contract.js +152 -0
  131. package/dist/renderers/index.d.ts +12 -0
  132. package/dist/renderers/index.js +16 -0
  133. package/dist/renderers/react.d.ts +16 -0
  134. package/dist/renderers/react.js +32 -0
  135. package/dist/renderers/web-components.d.ts +4 -0
  136. package/dist/renderers/web-components.js +103 -0
  137. package/dist/sketch/Canvas.js +49 -0
  138. package/dist/sketch/dsl.d.ts +131 -0
  139. package/dist/sketch/dsl.js +281 -0
  140. package/dist/sketch/index.d.ts +4 -0
  141. package/dist/sketch/index.js +3 -0
  142. package/dist/sketch/palette.d.ts +21 -0
  143. package/dist/sketch/palette.js +66 -0
  144. package/dist/sketch/render.d.ts +43 -0
  145. package/dist/sketch/render.js +198 -0
  146. package/dist/themes/base.css +1704 -0
  147. package/dist/themes/bling.css +592 -0
  148. package/dist/themes/glossary.css +317 -0
  149. package/dist/themes/live.css +1557 -0
  150. package/dist/themes/minimal.css +83 -0
  151. package/dist/themes/rla.css +92 -0
  152. package/dist/themes/sketch.css +121 -0
  153. package/dist/themes/stack.css +62 -0
  154. package/dist/vite/index.d.ts +15 -0
  155. package/dist/vite/index.js +320 -0
  156. package/package.json +159 -4
  157. package/tools/verify-island.mjs +150 -0
@@ -0,0 +1,637 @@
1
+ import { useDeck, useSlide, useSlideOptional } from "../react/context.js";
2
+ import { useActions, useClick, useNav, useUi } from "../react/hooks.js";
3
+ import { burstConfetti } from "../react/ConfettiLayer.js";
4
+ import { FrameShell } from "../react/Frame.js";
5
+ import { useEffect, useMemo, useRef, useState } from "react";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ import katex from "katex";
8
+ //#region src/components/content.tsx
9
+ /** `$…$` in Markdown is rendered at build time; this is for JSX: `<Math tex="…" block />`. */
10
+ function Tex({ tex, block = false, children }) {
11
+ const source = tex ?? (typeof children === "string" ? children : "");
12
+ const html = useMemo(() => katex.renderToString(source, {
13
+ displayMode: block,
14
+ throwOnError: false
15
+ }), [source, block]);
16
+ return block ? /* @__PURE__ */ jsx("div", {
17
+ className: "deck-math",
18
+ dangerouslySetInnerHTML: { __html: html }
19
+ }) : /* @__PURE__ */ jsx("span", {
20
+ className: "deck-math",
21
+ dangerouslySetInnerHTML: { __html: html }
22
+ });
23
+ }
24
+ let mermaidPromise = null;
25
+ /** A Mermaid diagram, rendered in the browser in the deck's colour scheme. */
26
+ function Mermaid({ children, scale = 1, className }) {
27
+ const source = typeof children === "string" ? children : Array.isArray(children) ? children.join("") : "";
28
+ const scheme = useUi((s) => s.colorScheme);
29
+ const [svg, setSvg] = useState("");
30
+ const id = useMemo(() => `m${Math.random().toString(36).slice(2, 9)}`, []);
31
+ useEffect(() => {
32
+ let alive = true;
33
+ mermaidPromise ??= import("mermaid");
34
+ mermaidPromise.then(async ({ default: mermaid }) => {
35
+ mermaid.initialize({
36
+ startOnLoad: false,
37
+ theme: scheme === "dark" ? "dark" : "neutral",
38
+ securityLevel: "loose"
39
+ });
40
+ try {
41
+ const out = await mermaid.render(id, source.trim());
42
+ if (alive) setSvg(out.svg);
43
+ } catch (e) {
44
+ if (alive) setSvg(`<pre class="deck-mermaid-error">${String(e)}</pre>`);
45
+ }
46
+ });
47
+ return () => {
48
+ alive = false;
49
+ };
50
+ }, [
51
+ source,
52
+ scheme,
53
+ id
54
+ ]);
55
+ return /* @__PURE__ */ jsx("div", {
56
+ className: ["deck-mermaid", className].filter(Boolean).join(" "),
57
+ style: { zoom: scale },
58
+ dangerouslySetInnerHTML: { __html: svg }
59
+ });
60
+ }
61
+ /** Speaker notes are lifted out at compile time; anything left renders nowhere. */
62
+ function Notes(_props) {
63
+ return null;
64
+ }
65
+ /** Go to a slide by number (1-based), `h.v`, or id. */
66
+ function Link({ to, title, children, className }) {
67
+ const actions = useActions();
68
+ const go = (e) => {
69
+ e.preventDefault();
70
+ const raw = String(to);
71
+ if (/^\d+$/.test(raw)) actions.gotoFlat(Number(raw) - 1);
72
+ else if (/^\d+\.\d+$/.test(raw)) {
73
+ const [h, v] = raw.split(".").map((n) => Number(n) - 1);
74
+ actions.goto(h, v);
75
+ } else actions.gotoId(raw);
76
+ };
77
+ return /* @__PURE__ */ jsx("a", {
78
+ href: `#/${to}`,
79
+ onClick: go,
80
+ className: ["deck-link", className].filter(Boolean).join(" "),
81
+ title,
82
+ children: children ?? title ?? String(to)
83
+ });
84
+ }
85
+ /** The `a` mapping: in-deck `#/…` links navigate, external links open in a new tab. */
86
+ function Anchor({ href, children, ...rest }) {
87
+ const actions = useActions();
88
+ if (href?.startsWith("#/")) return /* @__PURE__ */ jsx("a", {
89
+ href,
90
+ ...rest,
91
+ onClick: (e) => {
92
+ e.preventDefault();
93
+ actions.gotoId(href.slice(2));
94
+ },
95
+ children
96
+ });
97
+ const external = !!href && /^https?:/.test(href);
98
+ return /* @__PURE__ */ jsx("a", {
99
+ href,
100
+ target: external ? "_blank" : void 0,
101
+ rel: external ? "noreferrer" : void 0,
102
+ ...rest,
103
+ children
104
+ });
105
+ }
106
+ /** The table of contents from every slide's title and level (`hideInToc` slides skipped). */
107
+ function Toc({ columns = 1, maxDepth = Number.POSITIVE_INFINITY, minDepth = 1, mode = "all", listClass }) {
108
+ const deck = useDeck();
109
+ const actions = useActions();
110
+ const nav = useNav((s) => ({
111
+ h: s.h,
112
+ v: s.v
113
+ }));
114
+ const entries = deck.columns.flatMap((c) => c.slides.map((s, v) => ({
115
+ h: c.h,
116
+ v,
117
+ title: s.title,
118
+ level: s.level,
119
+ hide: !!s.frontmatter.hideInToc || deck.options.get(`${c.h},${v}`)?.hideInToc
120
+ })).filter((e) => e.title && !e.hide && e.level >= minDepth && e.level <= maxDepth));
121
+ const currentFlat = entries.findIndex((e) => e.h === nav.h && e.v === nav.v);
122
+ const shown = entries.filter((e, i) => {
123
+ if (mode === "all") return true;
124
+ if (currentFlat === -1) return e.level === minDepth;
125
+ const cur = entries[currentFlat];
126
+ if (mode === "onlySiblings") return e.level <= cur.level;
127
+ if (e.level === minDepth) return true;
128
+ let j = i;
129
+ while (j >= 0 && entries[j].level > minDepth) j--;
130
+ let k = currentFlat;
131
+ while (k >= 0 && entries[k].level > minDepth) k--;
132
+ return j === k;
133
+ });
134
+ return /* @__PURE__ */ jsx("ol", {
135
+ className: ["deck-toc", listClass].filter(Boolean).join(" "),
136
+ style: { columnCount: columns },
137
+ children: shown.map((e) => /* @__PURE__ */ jsx("li", {
138
+ className: [
139
+ `level-${e.level}`,
140
+ e.h === nav.h && e.v === nav.v ? "is-current" : "",
141
+ entries.indexOf(e) < currentFlat ? "is-past" : ""
142
+ ].filter(Boolean).join(" "),
143
+ style: { marginInlineStart: `${(e.level - minDepth) * 1.2}em` },
144
+ children: /* @__PURE__ */ jsx("a", {
145
+ href: `#/${e.h}${e.v ? `/${e.v}` : ""}`,
146
+ onClick: (ev) => {
147
+ ev.preventDefault();
148
+ actions.goto(e.h, e.v);
149
+ },
150
+ children: e.title
151
+ })
152
+ }, `${e.h},${e.v}`))
153
+ });
154
+ }
155
+ /** The `img` mapping: lazy, optionally a lightbox on click (`preview`). */
156
+ function Image({ src, alt = "", preview, fit, className, ...rest }) {
157
+ const previewSrc = typeof preview === "string" ? preview : preview ? src : void 0;
158
+ return /* @__PURE__ */ jsx("img", {
159
+ src,
160
+ alt,
161
+ loading: "lazy",
162
+ decoding: "async",
163
+ className: ["deck-image", className].filter(Boolean).join(" "),
164
+ "data-preview-image": previewSrc,
165
+ "data-preview-fit": fit,
166
+ ...rest
167
+ });
168
+ }
169
+ function Video({ src, autoplay, loop, muted = true, controls = false, className, ...rest }) {
170
+ return /* @__PURE__ */ jsx("video", {
171
+ "data-src": src,
172
+ "data-autoplay": autoplay ? "" : void 0,
173
+ loop,
174
+ muted,
175
+ controls,
176
+ playsInline: true,
177
+ className: ["deck-video", className].filter(Boolean).join(" "),
178
+ ...rest
179
+ });
180
+ }
181
+ function Audio({ src, autoplay, loop, controls = true, className }) {
182
+ return /* @__PURE__ */ jsx("audio", {
183
+ "data-src": src,
184
+ "data-autoplay": autoplay ? "" : void 0,
185
+ loop,
186
+ controls,
187
+ className
188
+ });
189
+ }
190
+ /** An embedded page, loaded only while its slide is near (`preload` loads it earlier). */
191
+ function Iframe({ src, preload, className, title, poster, posterSize, scale }) {
192
+ return /* @__PURE__ */ jsx(FrameShell, {
193
+ url: src,
194
+ preload,
195
+ className,
196
+ title,
197
+ poster,
198
+ posterSize,
199
+ scale
200
+ });
201
+ }
202
+ function Youtube({ id, url, autoplay, start, className }) {
203
+ const videoId = id ?? (url ? /(?:v=|youtu\.be\/|embed\/)([\w-]{6,})/.exec(url)?.[1] ?? "" : "");
204
+ const params = new URLSearchParams({
205
+ rel: "0",
206
+ modestbranding: "1",
207
+ ...autoplay ? {
208
+ autoplay: "1",
209
+ mute: "1"
210
+ } : {},
211
+ ...start ? { start: String(start) } : {}
212
+ });
213
+ return /* @__PURE__ */ jsx(Iframe, {
214
+ src: `https://www.youtube-nocookie.com/embed/${videoId}?${params}`,
215
+ className: ["deck-youtube", className].filter(Boolean).join(" ")
216
+ });
217
+ }
218
+ function Tweet({ id, url, scale = 1 }) {
219
+ const tweetId = String(id ?? (url ? /status\/(\d+)/.exec(url)?.[1] ?? "" : ""));
220
+ const scheme = useUi((s) => s.colorScheme);
221
+ return /* @__PURE__ */ jsx("div", {
222
+ className: "deck-tweet",
223
+ style: { zoom: scale },
224
+ children: /* @__PURE__ */ jsx(Iframe, { src: `https://platform.twitter.com/embed/Tweet.html?id=${tweetId}&theme=${scheme}&dnt=true` })
225
+ });
226
+ }
227
+ /** reveal.js's `r-stack`: children stacked at the same spot, for stepping through with clicks. */
228
+ function Stack({ children, className }) {
229
+ return /* @__PURE__ */ jsx("div", {
230
+ className: ["deck-stack", className].filter(Boolean).join(" "),
231
+ children
232
+ });
233
+ }
234
+ /** reveal.js's `r-stretch`: grows to fill the slide's remaining height. */
235
+ function Stretch({ children, className }) {
236
+ return /* @__PURE__ */ jsx("div", {
237
+ className: ["deck-stretch", className].filter(Boolean).join(" "),
238
+ children
239
+ });
240
+ }
241
+ /** Columns: `<Cols cols="2fr 1fr">` or `<Cols n={3}>`, each child a column (or use `<Col>`). */
242
+ function Cols({ cols, n, gap = "2rem", children, className, align }) {
243
+ const template = cols ?? `repeat(${n ?? 2}, minmax(0, 1fr))`;
244
+ return /* @__PURE__ */ jsx("div", {
245
+ className: ["deck-cols", className].filter(Boolean).join(" "),
246
+ style: {
247
+ gridTemplateColumns: template,
248
+ gap,
249
+ alignItems: align
250
+ },
251
+ children
252
+ });
253
+ }
254
+ function Col({ children, className, span }) {
255
+ return /* @__PURE__ */ jsx("div", {
256
+ className: ["deck-col", className].filter(Boolean).join(" "),
257
+ style: span ? { gridColumn: `span ${span}` } : void 0,
258
+ children
259
+ });
260
+ }
261
+ function Grid({ cols = 3, rows, gap = "1.5rem", children, className }) {
262
+ return /* @__PURE__ */ jsx("div", {
263
+ className: ["deck-grid", className].filter(Boolean).join(" "),
264
+ style: {
265
+ gridTemplateColumns: typeof cols === "number" ? `repeat(${cols}, minmax(0, 1fr))` : cols,
266
+ gridTemplateRows: typeof rows === "number" ? `repeat(${rows}, minmax(0, 1fr))` : rows,
267
+ gap
268
+ },
269
+ children
270
+ });
271
+ }
272
+ function Center({ children, className }) {
273
+ return /* @__PURE__ */ jsx("div", {
274
+ className: ["deck-center", className].filter(Boolean).join(" "),
275
+ children
276
+ });
277
+ }
278
+ function Spacer({ size = "1rem" }) {
279
+ return /* @__PURE__ */ jsx("div", {
280
+ className: "deck-spacer",
281
+ style: { height: size }
282
+ });
283
+ }
284
+ /** reveal.js's `r-frame`. */
285
+ function Frame({ children, className }) {
286
+ return /* @__PURE__ */ jsx("div", {
287
+ className: ["deck-frame", className].filter(Boolean).join(" "),
288
+ children
289
+ });
290
+ }
291
+ /** Slidev's `<Transform>`: scale a block around an origin. */
292
+ function Transform({ scale = 1, origin = "top left", children, className }) {
293
+ return /* @__PURE__ */ jsx("div", {
294
+ className: ["deck-transform", className].filter(Boolean).join(" "),
295
+ style: {
296
+ transform: `scale(${scale})`,
297
+ transformOrigin: origin
298
+ },
299
+ children
300
+ });
301
+ }
302
+ /** Place a block at stage coordinates: `<Absolute x={100} y={200} w={400}>`. */
303
+ function Absolute({ x = 0, y = 0, w, h, rotate = 0, children, className }) {
304
+ return /* @__PURE__ */ jsx("div", {
305
+ className: ["deck-absolute", className].filter(Boolean).join(" "),
306
+ style: {
307
+ left: x,
308
+ top: y,
309
+ width: w,
310
+ height: h,
311
+ transform: rotate ? `rotate(${rotate}deg)` : void 0
312
+ },
313
+ children
314
+ });
315
+ }
316
+ /** reveal.js's `r-fit-text` and Slidev's `AutoFitText`: as big as fits, no bigger than `max`. */
317
+ function FitText({ children, max = 400, min = 12, className }) {
318
+ const outer = useRef(null);
319
+ const inner = useRef(null);
320
+ const [size, setSize] = useState(max);
321
+ useEffect(() => {
322
+ const o = outer.current;
323
+ const i = inner.current;
324
+ if (!o || !i) return;
325
+ const fit = () => {
326
+ const avail = o.clientWidth;
327
+ if (!avail) return;
328
+ let lo = min;
329
+ let hi = max;
330
+ for (let k = 0; k < 14; k++) {
331
+ const mid = (lo + hi) / 2;
332
+ i.style.fontSize = `${mid}px`;
333
+ if (i.scrollWidth <= avail) lo = mid;
334
+ else hi = mid;
335
+ }
336
+ setSize(lo);
337
+ };
338
+ fit();
339
+ const ro = new ResizeObserver(fit);
340
+ ro.observe(o);
341
+ return () => ro.disconnect();
342
+ }, [
343
+ max,
344
+ min,
345
+ children
346
+ ]);
347
+ return /* @__PURE__ */ jsx("div", {
348
+ ref: outer,
349
+ className: ["deck-fit-text", className].filter(Boolean).join(" "),
350
+ children: /* @__PURE__ */ jsx("span", {
351
+ ref: inner,
352
+ style: {
353
+ fontSize: size,
354
+ whiteSpace: "nowrap",
355
+ display: "inline-block"
356
+ },
357
+ children
358
+ })
359
+ });
360
+ }
361
+ /** Slidev's `<Arrow>`: a straight arrow in stage coordinates. */
362
+ function Arrow({ x1, y1, x2, y2, width = 2, color = "currentColor", twoWay = false, className }) {
363
+ const id = useMemo(() => `arrow${Math.random().toString(36).slice(2, 8)}`, []);
364
+ const minX = Math.min(x1, x2) - 20;
365
+ const minY = Math.min(y1, y2) - 20;
366
+ const w = Math.abs(x2 - x1) + 40;
367
+ const h = Math.abs(y2 - y1) + 40;
368
+ return /* @__PURE__ */ jsxs("svg", {
369
+ className: ["deck-arrow", className].filter(Boolean).join(" "),
370
+ style: {
371
+ position: "absolute",
372
+ left: minX,
373
+ top: minY,
374
+ width: w,
375
+ height: h,
376
+ overflow: "visible",
377
+ pointerEvents: "none"
378
+ },
379
+ viewBox: `${minX} ${minY} ${w} ${h}`,
380
+ children: [/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx("marker", {
381
+ id,
382
+ viewBox: "0 0 10 10",
383
+ refX: "9",
384
+ refY: "5",
385
+ markerWidth: 6,
386
+ markerHeight: 6,
387
+ orient: "auto-start-reverse",
388
+ children: /* @__PURE__ */ jsx("path", {
389
+ d: "M 0 0 L 10 5 L 0 10 z",
390
+ fill: color
391
+ })
392
+ }) }), /* @__PURE__ */ jsx("line", {
393
+ x1,
394
+ y1,
395
+ x2,
396
+ y2,
397
+ stroke: color,
398
+ strokeWidth: width,
399
+ markerEnd: `url(#${id})`,
400
+ markerStart: twoWay ? `url(#${id})` : void 0
401
+ })]
402
+ });
403
+ }
404
+ function Kbd({ children }) {
405
+ return /* @__PURE__ */ jsx("kbd", {
406
+ className: "deck-kbd",
407
+ children
408
+ });
409
+ }
410
+ function Badge({ children, tone = "neutral", className }) {
411
+ return /* @__PURE__ */ jsx("span", {
412
+ className: [
413
+ "deck-badge",
414
+ `tone-${tone}`,
415
+ className
416
+ ].filter(Boolean).join(" "),
417
+ children
418
+ });
419
+ }
420
+ function Callout({ kind = "info", title, children, className }) {
421
+ return /* @__PURE__ */ jsxs("aside", {
422
+ className: [
423
+ "deck-callout",
424
+ `kind-${kind}`,
425
+ className
426
+ ].filter(Boolean).join(" "),
427
+ children: [title ? /* @__PURE__ */ jsx("strong", {
428
+ className: "deck-callout-title",
429
+ children: title
430
+ }) : null, /* @__PURE__ */ jsx("div", { children })]
431
+ });
432
+ }
433
+ /** A number that counts up when its slide is shown (or at its click). */
434
+ function Counter({ value, from = 0, duration = 1500, decimals = 0, prefix = "", suffix = "", className }) {
435
+ const slide = useSlide();
436
+ const [shown, setShown] = useState(slide.preview && !slide.active ? value : from);
437
+ useEffect(() => {
438
+ if (!slide.active) {
439
+ setShown(slide.preview ? value : from);
440
+ return;
441
+ }
442
+ const start = performance.now();
443
+ let raf = 0;
444
+ const tick = (t) => {
445
+ const p = Math.min(1, (t - start) / duration);
446
+ const eased = 1 - Math.pow(1 - p, 3);
447
+ setShown(from + (value - from) * eased);
448
+ if (p < 1) raf = requestAnimationFrame(tick);
449
+ };
450
+ raf = requestAnimationFrame(tick);
451
+ return () => cancelAnimationFrame(raf);
452
+ }, [
453
+ slide.active,
454
+ slide.preview,
455
+ value,
456
+ from,
457
+ duration
458
+ ]);
459
+ return /* @__PURE__ */ jsxs("span", {
460
+ className: ["deck-counter", className].filter(Boolean).join(" "),
461
+ children: [
462
+ prefix,
463
+ shown.toLocaleString(void 0, {
464
+ minimumFractionDigits: decimals,
465
+ maximumFractionDigits: decimals
466
+ }),
467
+ suffix
468
+ ]
469
+ });
470
+ }
471
+ /** Text that types itself out when the slide is shown. */
472
+ function Typewriter({ text, speed = 35, className, cursor = true }) {
473
+ const slide = useSlide();
474
+ const [n, setN] = useState(0);
475
+ useEffect(() => {
476
+ if (!slide.active) {
477
+ setN(0);
478
+ return;
479
+ }
480
+ let i = 0;
481
+ const t = setInterval(() => {
482
+ i++;
483
+ setN(i);
484
+ if (i >= text.length) clearInterval(t);
485
+ }, speed);
486
+ return () => clearInterval(t);
487
+ }, [
488
+ slide.active,
489
+ text,
490
+ speed
491
+ ]);
492
+ return /* @__PURE__ */ jsxs("span", {
493
+ className: ["deck-typewriter", className].filter(Boolean).join(" "),
494
+ children: [text.slice(0, n), cursor && n < text.length ? /* @__PURE__ */ jsx("span", {
495
+ className: "deck-typewriter-cursor",
496
+ children: "▍"
497
+ }) : null]
498
+ });
499
+ }
500
+ const GLYPHS = "!<>-_\\/[]{}—=+*^?#________";
501
+ /** Text that resolves out of noise, glyph by glyph — the RLA deck's `EncryptedText`. */
502
+ function Encrypted({ text, speed = 30, delay = 0, className }) {
503
+ const slide = useSlide();
504
+ const [out, setOut] = useState(text);
505
+ useEffect(() => {
506
+ if (!slide.active) {
507
+ setOut(text.replace(/\S/g, () => GLYPHS[Math.floor(Math.random() * 26)]));
508
+ return;
509
+ }
510
+ let frame = 0;
511
+ const perChar = 3;
512
+ const total = text.length * perChar + 10;
513
+ let raf = 0;
514
+ const start = performance.now() + delay;
515
+ const tick = (t) => {
516
+ if (t < start) {
517
+ raf = requestAnimationFrame(tick);
518
+ return;
519
+ }
520
+ frame++;
521
+ const resolved = Math.floor(frame / perChar);
522
+ setOut(text.split("").map((ch, i) => ch === " " ? " " : i < resolved ? ch : GLYPHS[Math.floor(Math.random() * 26)]).join(""));
523
+ if (frame < total) raf = setTimeout(() => requestAnimationFrame(tick), speed);
524
+ };
525
+ raf = requestAnimationFrame(tick);
526
+ return () => {
527
+ cancelAnimationFrame(raf);
528
+ clearTimeout(raf);
529
+ };
530
+ }, [
531
+ slide.active,
532
+ text,
533
+ speed,
534
+ delay
535
+ ]);
536
+ return /* @__PURE__ */ jsx("span", {
537
+ className: ["deck-encrypted", className].filter(Boolean).join(" "),
538
+ children: out
539
+ });
540
+ }
541
+ /** A countdown or stopwatch that starts when its slide is shown. */
542
+ function Timer({ seconds, className }) {
543
+ const slide = useSlide();
544
+ const [elapsed, setElapsed] = useState(0);
545
+ useEffect(() => {
546
+ if (!slide.active) {
547
+ setElapsed(0);
548
+ return;
549
+ }
550
+ const start = Date.now();
551
+ const t = setInterval(() => setElapsed((Date.now() - start) / 1e3), 250);
552
+ return () => clearInterval(t);
553
+ }, [slide.active]);
554
+ const value = seconds !== void 0 ? Math.max(0, seconds - elapsed) : elapsed;
555
+ const m = Math.floor(value / 60);
556
+ const s = Math.floor(value % 60);
557
+ return /* @__PURE__ */ jsxs("span", {
558
+ className: [
559
+ "deck-timer",
560
+ seconds !== void 0 && value === 0 ? "is-done" : "",
561
+ className
562
+ ].filter(Boolean).join(" "),
563
+ children: [
564
+ m,
565
+ ":",
566
+ String(s).padStart(2, "0")
567
+ ]
568
+ });
569
+ }
570
+ /** A hand-drawn mark around inline content, drawn on its click: underline, circle, box, highlight. */
571
+ function Mark({ type = "underline", color = "var(--deck-accent)", at, children, className }) {
572
+ const { shown } = useClick({ at });
573
+ return /* @__PURE__ */ jsx("span", {
574
+ className: [
575
+ "deck-mark",
576
+ `type-${type}`,
577
+ shown ? "is-on" : "",
578
+ className
579
+ ].filter(Boolean).join(" "),
580
+ style: { "--mark-color": color },
581
+ children
582
+ });
583
+ }
584
+ /** A quick burst of confetti when the slide (or its click) arrives. */
585
+ function Confetti({ at, count = 140, duration = 2200 }) {
586
+ const { shown, current } = useClick(at !== void 0 ? { at } : { at: "+0" });
587
+ const slide = useSlideOptional();
588
+ const canvas = useRef(null);
589
+ const fire = at !== void 0 ? shown && current : !!slide?.active;
590
+ useEffect(() => {
591
+ const c = canvas.current;
592
+ if (!c || !fire) return;
593
+ return burstConfetti(c, {
594
+ count,
595
+ duration
596
+ });
597
+ }, [
598
+ fire,
599
+ count,
600
+ duration
601
+ ]);
602
+ return /* @__PURE__ */ jsx("canvas", {
603
+ ref: canvas,
604
+ className: "deck-confetti",
605
+ "aria-hidden": true
606
+ });
607
+ }
608
+ /** A QR code, rendered locally. */
609
+ function Qr({ value, size = 240, className }) {
610
+ const [src, setSrc] = useState("");
611
+ useEffect(() => {
612
+ let alive = true;
613
+ import("qrcode").then(({ default: QRCode }) => QRCode.toDataURL(value, {
614
+ width: size,
615
+ margin: 1,
616
+ errorCorrectionLevel: "M"
617
+ })).then((url) => alive && setSrc(url)).catch(() => {});
618
+ return () => {
619
+ alive = false;
620
+ };
621
+ }, [value, size]);
622
+ return src ? /* @__PURE__ */ jsx("img", {
623
+ src,
624
+ width: size,
625
+ height: size,
626
+ alt: `QR code for ${value}`,
627
+ className: ["deck-qr", className].filter(Boolean).join(" ")
628
+ }) : /* @__PURE__ */ jsx("div", {
629
+ className: "deck-qr",
630
+ style: {
631
+ width: size,
632
+ height: size
633
+ }
634
+ });
635
+ }
636
+ //#endregion
637
+ export { Absolute, Anchor, Arrow, Audio, Badge, Callout, Center, Col, Cols, Confetti, Counter, Encrypted, FitText, Frame, Grid, Iframe, Image, Kbd, Link, Mark, Mermaid, Notes, Qr, Spacer, Stack, Stretch, Tex, Timer, Toc, Transform, Tweet, Typewriter, Video, Youtube };
@@ -0,0 +1,10 @@
1
+ import { After, Click, Clicks, Fragment, Li, Ol, Ul } from "./Click.js";
2
+ import { Code, MagicMove } from "./Code.js";
3
+ import { Absolute, Anchor, Arrow, Audio, Badge, Callout, Center, Col, Cols, Confetti, Counter, Encrypted, FitText, Frame, Grid, Iframe, Image, Kbd, Link, Mark, Mermaid, Notes, Qr, Spacer, Stack, Stretch, Tex, Timer, Toc, Transform, Tweet, Typewriter, Video, Youtube } from "./content.js";
4
+ import { Motion } from "./Motion.js";
5
+ import { Term, TermProps, TermReadout, Terms } from "./Term.js";
6
+ import { Sketch, SketchProps, SketchStep } from "./Sketch.js";
7
+ import { Background } from "./Background.js";
8
+ import { Leaderboard, Pace, Poll, Presence, QrJoin, Questions, Quiz, Reactions, WordCloud } from "../live/components.js";
9
+ import { Blob, Chip, Divider, Glass, Glow, GradientText, Halo, Icon, Ribbon, Shimmer, Tilt } from "./bling.js";
10
+ export { Absolute, After, Anchor, Arrow, Audio, Background, Badge, Blob, Callout, Center, Chip, Click, Clicks, Code, Col, Cols, Confetti, Counter, Divider, Encrypted, FitText, Fragment, Frame, Glass, Glow, GradientText, Grid, Halo, Icon, Iframe, Image, Kbd, Leaderboard, Li, Link, MagicMove, Mark, Tex as Math, Mermaid, Motion, Notes, Ol, Pace, Poll, Presence, Qr, QrJoin, Questions, Quiz, Reactions, Ribbon, Shimmer, Sketch, type SketchProps, type SketchStep, Spacer, Stack, Stretch, Term, type TermProps, TermReadout, Terms, Tex, Tilt, Timer, Toc, Transform, Tweet, Typewriter, Ul, Video, WordCloud, Youtube, Li as li, Ol as ol, Ul as ul };