@mrrocket/sdk 0.17.0 → 0.18.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 (43) hide show
  1. package/CHANGELOG.md +7 -1
  2. package/dist/browser/mrrocket-flows.js +9 -2
  3. package/dist/browser/mrrocket-messenger.js +3 -3
  4. package/dist/browser/mrrocket.js +1 -1
  5. package/dist/browser.d.ts +1 -1
  6. package/dist/browser.js +2 -1
  7. package/dist/browser.js.map +1 -1
  8. package/dist/client.d.ts +23 -3
  9. package/dist/client.js +15 -1
  10. package/dist/client.js.map +1 -1
  11. package/dist/context.d.ts +3 -1
  12. package/dist/context.js.map +1 -1
  13. package/dist/core.d.ts +3 -1
  14. package/dist/core.js +1 -1
  15. package/dist/core.js.map +1 -1
  16. package/dist/finish-web.d.ts +18 -0
  17. package/dist/finish-web.js +139 -0
  18. package/dist/finish-web.js.map +1 -0
  19. package/dist/flows-ui.d.ts +1 -10
  20. package/dist/flows-ui.js +105 -6
  21. package/dist/flows-ui.js.map +1 -1
  22. package/dist/flows-web.d.ts +8 -1
  23. package/dist/flows-web.js +8 -0
  24. package/dist/flows-web.js.map +1 -1
  25. package/dist/flows.d.ts +159 -7
  26. package/dist/flows.js +240 -28
  27. package/dist/flows.js.map +1 -1
  28. package/dist/icons.d.ts +24 -0
  29. package/dist/icons.js +61 -0
  30. package/dist/icons.js.map +1 -0
  31. package/dist/index.d.ts +4 -2
  32. package/dist/index.js +5 -0
  33. package/dist/index.js.map +1 -1
  34. package/dist/messenger-ui.js +78 -53
  35. package/dist/messenger-ui.js.map +1 -1
  36. package/dist/onboarding-state.d.ts +23 -0
  37. package/dist/onboarding-state.js +43 -0
  38. package/dist/onboarding-state.js.map +1 -0
  39. package/dist/react-native/index.d.cts +177 -15
  40. package/dist/react-native/index.d.ts +177 -15
  41. package/dist/react-native/index.js +776 -270
  42. package/dist/react-native/index.js.map +1 -1
  43. package/package.json +1 -1
@@ -0,0 +1,139 @@
1
+ // src/finish-web.ts
2
+ var prefersReducedMotion = () => {
3
+ try {
4
+ return typeof matchMedia === "function" && matchMedia("(prefers-reduced-motion: reduce)").matches;
5
+ } catch {
6
+ return false;
7
+ }
8
+ };
9
+ var COLORS = ["#f59e0b", "#10b981", "#ef4444", "#8b5cf6", "#06b6d4", "#ec4899"];
10
+ var star = (c, r) => {
11
+ c.beginPath();
12
+ for (let i = 0; i < 10; i++) {
13
+ const a = Math.PI / 5 * i - Math.PI / 2;
14
+ const d = i % 2 ? r * 0.45 : r;
15
+ c[i ? "lineTo" : "moveTo"](Math.cos(a) * d, Math.sin(a) * d);
16
+ }
17
+ c.closePath();
18
+ c.fill();
19
+ };
20
+ var bitsFor = (kind, w, h, colors) => {
21
+ const rnd = (a, b) => a + Math.random() * (b - a);
22
+ const pick = () => colors[Math.floor(Math.random() * colors.length)];
23
+ const out = [];
24
+ if (kind === "confetti")
25
+ for (let i = 0; i < 110; i++) {
26
+ const left = i % 2 === 0;
27
+ out.push({
28
+ x: left ? w * 0.15 : w * 0.85,
29
+ y: h * 0.95,
30
+ vx: (left ? 1 : -1) * rnd(0.12, 0.42) * (w / 900 + 0.4),
31
+ vy: -rnd(0.75, 1.25) * (h / 900 + 0.35),
32
+ r: rnd(4, 7),
33
+ spin: rnd(-0.02, 0.02),
34
+ angle: rnd(0, Math.PI),
35
+ color: pick(),
36
+ born: rnd(0, 180),
37
+ life: rnd(1500, 2100),
38
+ shape: "rect"
39
+ });
40
+ }
41
+ else if (kind === "fireworks")
42
+ for (let b = 0; b < 4; b++) {
43
+ const cx = rnd(w * 0.2, w * 0.8);
44
+ const cy = rnd(h * 0.18, h * 0.5);
45
+ const color = pick();
46
+ for (let i = 0; i < 46; i++) {
47
+ const a = Math.PI * 2 * i / 46 + rnd(-0.05, 0.05);
48
+ const v = rnd(0.12, 0.3) * (Math.min(w, h) / 600 + 0.5);
49
+ out.push({ x: cx, y: cy, vx: Math.cos(a) * v, vy: Math.sin(a) * v, r: rnd(1.6, 2.6), spin: 0, angle: 0, color, born: b * 320, life: rnd(900, 1300), shape: "dot" });
50
+ }
51
+ }
52
+ else
53
+ for (let i = 0; i < 34; i++)
54
+ out.push({
55
+ x: rnd(w * 0.08, w * 0.92),
56
+ y: rnd(h * 0.2, h * 0.85),
57
+ vx: 0,
58
+ vy: -rnd(0.02, 0.06),
59
+ r: rnd(6, 13),
60
+ spin: rnd(-4e-3, 4e-3),
61
+ angle: rnd(0, Math.PI),
62
+ color: pick(),
63
+ born: rnd(0, 700),
64
+ life: rnd(900, 1300),
65
+ shape: "star"
66
+ });
67
+ return out;
68
+ };
69
+ var playFinish = (kind, opts = {}) => {
70
+ if (!kind || kind === "none" || typeof document === "undefined" || !opts.force && prefersReducedMotion()) return () => {
71
+ };
72
+ const canvas = document.createElement("canvas");
73
+ canvas.setAttribute("aria-hidden", "true");
74
+ const host = opts.host;
75
+ canvas.style.cssText = host ? "position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5" : "position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483003";
76
+ (host ?? document.body).appendChild(canvas);
77
+ const w = host ? host.clientWidth : window.innerWidth;
78
+ const h = host ? host.clientHeight : window.innerHeight;
79
+ const dpr = Math.min(2, window.devicePixelRatio || 1);
80
+ canvas.width = Math.max(1, Math.round(w * dpr));
81
+ canvas.height = Math.max(1, Math.round(h * dpr));
82
+ const c = canvas.getContext("2d");
83
+ if (!c) {
84
+ canvas.remove();
85
+ return () => {
86
+ };
87
+ }
88
+ const colors = opts.accent ? [opts.accent, opts.accent, ...COLORS] : COLORS;
89
+ const bits = bitsFor(kind, w, h, colors);
90
+ const end = Math.max(...bits.map((b) => b.born + b.life));
91
+ const gravity = kind === "confetti" ? 16e-4 : kind === "fireworks" ? 35e-5 : 0;
92
+ let frame = 0;
93
+ let start = 0;
94
+ let stopped = false;
95
+ const stop = () => {
96
+ if (stopped) return;
97
+ stopped = true;
98
+ cancelAnimationFrame(frame);
99
+ canvas.remove();
100
+ };
101
+ const draw = (t) => {
102
+ if (stopped) return;
103
+ if (!start) start = t;
104
+ const el = t - start;
105
+ c.setTransform(dpr, 0, 0, dpr, 0, 0);
106
+ c.clearRect(0, 0, w, h);
107
+ for (const b of bits) {
108
+ const age = el - b.born;
109
+ if (age < 0 || age > b.life) continue;
110
+ const x = b.x + b.vx * age;
111
+ const y = b.y + b.vy * age + 0.5 * gravity * age * age;
112
+ const fade = Math.min(1, (b.life - age) / 350);
113
+ c.save();
114
+ c.globalAlpha = Math.max(0, fade);
115
+ c.translate(x, y);
116
+ c.rotate(b.angle + b.spin * age);
117
+ c.fillStyle = b.color;
118
+ if (b.shape === "rect") c.fillRect(-b.r, -b.r / 2.2, b.r * 2, b.r / 1.1);
119
+ else if (b.shape === "dot") {
120
+ c.beginPath();
121
+ c.arc(0, 0, b.r, 0, Math.PI * 2);
122
+ c.fill();
123
+ } else {
124
+ const grow = Math.min(1, age / 220);
125
+ star(c, b.r * (grow < 1 ? grow : 1 - Math.max(0, (age - b.life * 0.6) / (b.life * 0.4)) * 0.6));
126
+ }
127
+ c.restore();
128
+ }
129
+ if (el < end) frame = requestAnimationFrame(draw);
130
+ else stop();
131
+ };
132
+ frame = requestAnimationFrame(draw);
133
+ return stop;
134
+ };
135
+ export {
136
+ playFinish,
137
+ prefersReducedMotion
138
+ };
139
+ //# sourceMappingURL=finish-web.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/finish-web.ts"],"sourcesContent":["/**\n * 0.18.0: the finish animation on the web (`FinishAnimation`): confetti, fireworks or stars on one canvas for about two\n * seconds, then gone. No library, no timers left behind, nothing to click through (the canvas lets every click pass).\n * Nothing plays when the visitor asks for less motion (`prefers-reduced-motion`). The flows' dialogs (flows-ui.ts) play\n * it when someone finishes a checklist, a tour or the questions; MRRocket's editor plays the same code in its preview.\n */\nimport type { FinishAnimation } from \"./flows\";\n\n/** Whether the visitor's system asks for less motion. */\nexport const prefersReducedMotion = () => {\n try {\n return typeof matchMedia === \"function\" && matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n } catch {\n return false;\n }\n};\n\nconst COLORS = [\"#f59e0b\", \"#10b981\", \"#ef4444\", \"#8b5cf6\", \"#06b6d4\", \"#ec4899\"];\n\ninterface Bit {\n x: number;\n y: number;\n vx: number;\n vy: number;\n r: number;\n spin: number;\n angle: number;\n color: string;\n /** When it appears and how long it lives, in ms from the start. */\n born: number;\n life: number;\n shape: \"rect\" | \"dot\" | \"star\";\n}\n\nconst star = (c: CanvasRenderingContext2D, r: number) => {\n c.beginPath();\n for (let i = 0; i < 10; i++) {\n const a = (Math.PI / 5) * i - Math.PI / 2;\n const d = i % 2 ? r * 0.45 : r;\n c[i ? \"lineTo\" : \"moveTo\"](Math.cos(a) * d, Math.sin(a) * d);\n }\n c.closePath();\n c.fill();\n};\n\n/** The particles of one animation on a w×h area. */\nconst bitsFor = (kind: Exclude<FinishAnimation, \"none\">, w: number, h: number, colors: string[]): Bit[] => {\n const rnd = (a: number, b: number) => a + Math.random() * (b - a);\n const pick = () => colors[Math.floor(Math.random() * colors.length)];\n const out: Bit[] = [];\n if (kind === \"confetti\")\n for (let i = 0; i < 110; i++) {\n const left = i % 2 === 0;\n out.push({\n x: left ? w * 0.15 : w * 0.85,\n y: h * 0.95,\n vx: (left ? 1 : -1) * rnd(0.12, 0.42) * (w / 900 + 0.4),\n vy: -rnd(0.75, 1.25) * (h / 900 + 0.35),\n r: rnd(4, 7),\n spin: rnd(-0.02, 0.02),\n angle: rnd(0, Math.PI),\n color: pick(),\n born: rnd(0, 180),\n life: rnd(1500, 2100),\n shape: \"rect\",\n });\n }\n else if (kind === \"fireworks\")\n for (let b = 0; b < 4; b++) {\n const cx = rnd(w * 0.2, w * 0.8);\n const cy = rnd(h * 0.18, h * 0.5);\n const color = pick();\n for (let i = 0; i < 46; i++) {\n const a = (Math.PI * 2 * i) / 46 + rnd(-0.05, 0.05);\n const v = rnd(0.12, 0.3) * (Math.min(w, h) / 600 + 0.5);\n out.push({ x: cx, y: cy, vx: Math.cos(a) * v, vy: Math.sin(a) * v, r: rnd(1.6, 2.6), spin: 0, angle: 0, color, born: b * 320, life: rnd(900, 1300), shape: \"dot\" });\n }\n }\n else\n for (let i = 0; i < 34; i++)\n out.push({\n x: rnd(w * 0.08, w * 0.92),\n y: rnd(h * 0.2, h * 0.85),\n vx: 0,\n vy: -rnd(0.02, 0.06),\n r: rnd(6, 13),\n spin: rnd(-0.004, 0.004),\n angle: rnd(0, Math.PI),\n color: pick(),\n born: rnd(0, 700),\n life: rnd(900, 1300),\n shape: \"star\",\n });\n return out;\n};\n\n/**\n * Plays `kind` over `host` (filling it; the host should be positioned) or over the whole window; answers a function\n * that stops it early. `accent` joins the colors.\n */\nexport const playFinish = (kind: FinishAnimation | undefined, opts: { accent?: string; host?: HTMLElement; force?: boolean } = {}): (() => void) => {\n if (!kind || kind === \"none\" || typeof document === \"undefined\" || (!opts.force && prefersReducedMotion())) return () => {};\n const canvas = document.createElement(\"canvas\");\n canvas.setAttribute(\"aria-hidden\", \"true\");\n const host = opts.host;\n canvas.style.cssText = host\n ? \"position:absolute;inset:0;width:100%;height:100%;pointer-events:none;z-index:5\"\n : \"position:fixed;inset:0;width:100vw;height:100vh;pointer-events:none;z-index:2147483003\";\n (host ?? document.body).appendChild(canvas);\n const w = host ? host.clientWidth : window.innerWidth;\n const h = host ? host.clientHeight : window.innerHeight;\n const dpr = Math.min(2, window.devicePixelRatio || 1);\n canvas.width = Math.max(1, Math.round(w * dpr));\n canvas.height = Math.max(1, Math.round(h * dpr));\n const c = canvas.getContext(\"2d\");\n if (!c) {\n canvas.remove();\n return () => {};\n }\n const colors = opts.accent ? [opts.accent, opts.accent, ...COLORS] : COLORS;\n const bits = bitsFor(kind, w, h, colors);\n const end = Math.max(...bits.map((b) => b.born + b.life));\n const gravity = kind === \"confetti\" ? 0.0016 : kind === \"fireworks\" ? 0.00035 : 0;\n let frame = 0;\n let start = 0;\n let stopped = false;\n const stop = () => {\n if (stopped) return;\n stopped = true;\n cancelAnimationFrame(frame);\n canvas.remove();\n };\n const draw = (t: number) => {\n if (stopped) return;\n if (!start) start = t;\n const el = t - start;\n c.setTransform(dpr, 0, 0, dpr, 0, 0);\n c.clearRect(0, 0, w, h);\n for (const b of bits) {\n const age = el - b.born;\n if (age < 0 || age > b.life) continue;\n const x = b.x + b.vx * age;\n const y = b.y + b.vy * age + 0.5 * gravity * age * age;\n const fade = Math.min(1, (b.life - age) / 350);\n c.save();\n c.globalAlpha = Math.max(0, fade);\n c.translate(x, y);\n c.rotate(b.angle + b.spin * age);\n c.fillStyle = b.color;\n if (b.shape === \"rect\") c.fillRect(-b.r, -b.r / 2.2, b.r * 2, b.r / 1.1);\n else if (b.shape === \"dot\") {\n c.beginPath();\n c.arc(0, 0, b.r, 0, Math.PI * 2);\n c.fill();\n } else {\n // A star pops in, then shrinks away.\n const grow = Math.min(1, age / 220);\n star(c, b.r * (grow < 1 ? grow : 1 - Math.max(0, (age - b.life * 0.6) / (b.life * 0.4)) * 0.6));\n }\n c.restore();\n }\n if (el < end) frame = requestAnimationFrame(draw);\n else stop();\n };\n frame = requestAnimationFrame(draw);\n return stop;\n};\n"],"mappings":"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","names":[]}
@@ -1,12 +1,3 @@
1
- /**
2
- * The web renderer of the cancel flow, onboarding and in-app messages (flows.ts): plain DOM, no React, so the Next.js
3
- * provider and the script tag share it. Both load it only when something is about to show (a dynamic import, and
4
- * `sdk-flows.js` for the script tag), so pages that show nothing never download it.
5
- *
6
- * Themeable three ways: `theme` ("light", "dark", "auto") and `accent` from the SDK's options, and CSS variables on
7
- * `.ckf-root` in the site's own stylesheet (`--ckf-accent`, `--ckf-bg`, `--ckf-fg`, `--ckf-muted`, `--ckf-line`,
8
- * `--ckf-radius`, `--ckf-font`). Every text is set with textContent; nothing from the server is parsed as HTML.
9
- */
10
1
  import { type FlowsController } from "./flows.js";
11
2
  import type { PaywallHost } from "./paywall.js";
12
3
  export interface FlowsTheme {
@@ -16,7 +7,7 @@ export interface FlowsTheme {
16
7
  /** An extra class on the root, for the site's own CSS. */
17
8
  className?: string;
18
9
  }
19
- export declare const FLOWS_CSS = "\n.ckf-root{--ckf-accent:#3f76ff;--ckf-accent-ink:#fff;--ckf-bg:#fff;--ckf-fg:#1c1d20;--ckf-muted:#5d6068;--ckf-soft:#f4f5f7;--ckf-line:#e4e5e8;--ckf-danger:#d92d20;--ckf-radius:14px;--ckf-font:inherit;--ckf-shadow:0 16px 40px -12px rgba(16,18,24,.28),0 0 0 1px rgba(16,18,24,.07)}\n.ckf-root[data-theme=dark]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}\n@media (prefers-color-scheme:dark){.ckf-root[data-theme=auto]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}}\n.ckf-root,.ckf-root *{box-sizing:border-box}\n.ckf-root{font-family:var(--ckf-font);font-size:14px;line-height:1.45;color:var(--ckf-fg);-webkit-font-smoothing:antialiased}\n.ckf-root :where(button,textarea){font:inherit;color:inherit;margin:0}\n.ckf-root :focus-visible{outline:2px solid var(--ckf-accent);outline-offset:2px}\n.ckf-scrim{position:fixed;inset:0;z-index:2147483002;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;padding:16px;animation:ckf-fade .15s ease-out}\n.ckf-card{position:relative;width:100%;max-width:400px;max-height:calc(100dvh - 32px);overflow-y:auto;background:var(--ckf-bg);color:var(--ckf-fg);border-radius:var(--ckf-radius);box-shadow:var(--ckf-shadow);padding:18px 20px 20px;display:flex;flex-direction:column;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-float{position:fixed;z-index:2147483001;right:20px;bottom:20px;width:340px;max-width:calc(100vw - 24px)}\n.ckf-top{display:flex;align-items:center;gap:8px;min-height:20px}\n.ckf-dots{display:flex;gap:4px}\n.ckf-dot{width:16px;height:4px;border-radius:4px;background:var(--ckf-line)}\n.ckf-dot[data-on]{background:var(--ckf-accent)}\n.ckf-x{margin-left:auto;width:28px;height:28px;border:0;border-radius:8px;background:none;color:var(--ckf-muted);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:18px;line-height:1}\n.ckf-x:hover{background:var(--ckf-soft);color:var(--ckf-fg)}\n.ckf-h{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;text-wrap:balance}\n.ckf-p{margin:0;color:var(--ckf-muted);text-wrap:pretty;white-space:pre-wrap}\n.ckf-small{margin:0;font-size:12px;color:var(--ckf-muted)}\n.ckf-opts{display:flex;flex-direction:column;gap:6px;margin:0;padding:0;list-style:none}\n.ckf-opt{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:8px 12px;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);text-align:left;cursor:pointer;font-weight:500}\n.ckf-opt:hover{background:var(--ckf-soft)}\n.ckf-opt[aria-checked=true]{border-color:var(--ckf-accent);background:color-mix(in srgb,var(--ckf-accent) 8%,var(--ckf-bg))}\n.ckf-radio{width:16px;height:16px;flex:none;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center}\n.ckf-opt[aria-checked=true] .ckf-radio{border-color:var(--ckf-accent)}\n.ckf-opt[aria-checked=true] .ckf-radio::after{content:\"\";width:8px;height:8px;border-radius:50%;background:var(--ckf-accent)}\n.ckf-box{border-radius:10px;background:var(--ckf-soft);padding:12px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}\n.ckf-big{font-size:22px;font-weight:650;font-variant-numeric:tabular-nums}\n.ckf-strike{color:var(--ckf-muted);text-decoration:line-through;font-variant-numeric:tabular-nums}\n.ckf-text{width:100%;min-height:64px;resize:vertical;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);padding:8px 10px}\n.ckf-text::placeholder{color:var(--ckf-muted)}\n.ckf-btns{display:flex;flex-direction:column;gap:6px}\n.ckf-btn{height:38px;padding:0 14px;border-radius:10px;border:1px solid var(--ckf-line);background:var(--ckf-bg);font-weight:600;cursor:pointer;transition:filter .1s linear,background-color .1s linear}\n.ckf-btn:hover{background:var(--ckf-soft)}\n.ckf-btn[disabled]{opacity:.55;cursor:not-allowed}\n.ckf-primary{background:var(--ckf-accent);border-color:var(--ckf-accent);color:var(--ckf-accent-ink)}\n.ckf-primary:hover{background:var(--ckf-accent);filter:brightness(1.07)}\n.ckf-danger{background:var(--ckf-danger);border-color:var(--ckf-danger);color:#fff}\n.ckf-danger:hover{background:var(--ckf-danger);filter:brightness(1.07)}\n.ckf-quiet{border-color:transparent;background:none;color:var(--ckf-muted);height:30px;font-weight:500}\n.ckf-quiet:hover{background:none;color:var(--ckf-fg)}\n.ckf-err{margin:0;color:var(--ckf-danger);font-size:13px;font-weight:500}\n.ckf-row{display:flex;justify-content:flex-end;gap:8px;align-items:center}\n.ckf-row .ckf-small{margin-right:auto}\n.ckf-media{display:block;width:100%;max-height:240px;object-fit:cover;border-radius:10px;background:var(--ckf-soft)}\n.ckf-video{position:relative;width:100%;aspect-ratio:16/9;border-radius:10px;overflow:hidden;background:#000}\n.ckf-video iframe{position:absolute;inset:0;width:100%;height:100%;border:0}\n.ckf-arrow{position:absolute;width:12px;height:12px;margin:-6px;background:var(--ckf-bg);transform:rotate(45deg)}\n[data-side=bottom]>.ckf-arrow{top:0;left:var(--ckf-ap)}[data-side=top]>.ckf-arrow{top:100%;left:var(--ckf-ap)}\n[data-side=right]>.ckf-arrow{left:0;top:var(--ckf-ap)}[data-side=left]>.ckf-arrow{left:100%;top:var(--ckf-ap)}\n.ckf-check .ckf-go{margin-left:auto;align-self:center;color:var(--ckf-accent);font-weight:700}\n.ckf-ring{position:fixed;z-index:2147483000;pointer-events:none;border-radius:10px;box-shadow:0 0 0 2px var(--ckf-accent),0 0 0 6px color-mix(in srgb,var(--ckf-accent) 25%,transparent);transition:all .15s ease-out}\n.ckf-check{display:flex;align-items:flex-start;gap:10px;width:100%;padding:8px 6px;border:0;border-radius:8px;background:none;text-align:left}\n.ckf-check:where(button){cursor:pointer}\n.ckf-check:where(button):hover{background:var(--ckf-soft)}\n.ckf-tick{width:18px;height:18px;flex:none;margin-top:1px;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent-ink);font-size:11px;font-weight:700}\n.ckf-check[data-done] .ckf-tick{background:var(--ckf-accent);border-color:var(--ckf-accent)}\n.ckf-check[data-done] b{color:var(--ckf-muted);text-decoration:line-through}\n.ckf-check span{display:flex;flex-direction:column;gap:2px;min-width:0}\n.ckf-bar{height:4px;border-radius:4px;background:var(--ckf-soft);overflow:hidden}\n.ckf-bar i{display:block;height:100%;background:var(--ckf-accent)}\n.ckf-banner{position:fixed;z-index:2147483001;left:50%;top:12px;transform:translateX(-50%);width:min(640px,calc(100vw - 24px));background:var(--ckf-bg);border-radius:12px;box-shadow:var(--ckf-shadow);padding:10px 10px 10px 16px;display:flex;align-items:center;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-banner>span{flex:1;min-width:0;display:flex;flex-direction:column}\n.ckf-banner .ckf-btn{height:32px}\n.ckf-pw{max-width:420px;gap:14px}\n.ckf-root[data-still] :is(.ckf-scrim,.ckf-card){animation:none}\n.ckf-li{display:flex;gap:10px;align-items:flex-start;margin:0}\n.ckf-li::before{content:\"\u2713\";flex:none;width:20px;height:20px;border-radius:50%;background:color-mix(in srgb,var(--ckf-accent) 14%,var(--ckf-bg));color:var(--ckf-accent);font-size:12px;font-weight:700;display:inline-flex;align-items:center;justify-content:center}\n.ckf-quote{margin:0;padding:12px 14px;border-radius:12px;background:var(--ckf-soft)}\n.ckf-quote cite{display:block;margin-top:6px;font-style:normal;font-size:12px;color:var(--ckf-muted)}\n.ckf-plan{justify-content:space-between;min-height:52px}\n.ckf-plan span:nth-child(2){display:flex;flex-direction:column;margin-right:auto}\n.ckf-plan b{font-variant-numeric:tabular-nums}\n@keyframes ckf-fade{from{opacity:0}}\n@keyframes ckf-in{from{opacity:0;transform:translateY(6px)}}\n.ckf-banner{animation-name:ckf-fade}\n@media (max-width:520px){.ckf-scrim{align-items:flex-end;padding:0}.ckf-scrim .ckf-card{max-width:none;border-radius:var(--ckf-radius) var(--ckf-radius) 0 0;max-height:92dvh}.ckf-float{right:12px;bottom:12px}}\n@media (prefers-reduced-motion:reduce){.ckf-root *{animation:none!important;transition:none!important}}\n";
10
+ export declare const FLOWS_CSS = "\n.ckf-root{--ckf-accent:#3f76ff;--ckf-accent-ink:#fff;--ckf-bg:#fff;--ckf-fg:#1c1d20;--ckf-muted:#5d6068;--ckf-soft:#f4f5f7;--ckf-line:#e4e5e8;--ckf-danger:#d92d20;--ckf-radius:14px;--ckf-font:inherit;--ckf-shadow:0 16px 40px -12px rgba(16,18,24,.28),0 0 0 1px rgba(16,18,24,.07)}\n.ckf-root[data-theme=dark]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}\n@media (prefers-color-scheme:dark){.ckf-root[data-theme=auto]{--ckf-bg:#17181b;--ckf-fg:#f1f2f4;--ckf-muted:#a9acb3;--ckf-soft:#232428;--ckf-line:#2e2f35;--ckf-shadow:0 16px 40px -12px rgba(0,0,0,.6),0 0 0 1px rgba(255,255,255,.08)}}\n.ckf-root,.ckf-root *{box-sizing:border-box}\n.ckf-root{font-family:var(--ckf-font);font-size:14px;line-height:1.45;color:var(--ckf-fg);-webkit-font-smoothing:antialiased}\n.ckf-root :where(button,textarea){font:inherit;color:inherit;margin:0}\n.ckf-root :focus-visible{outline:2px solid var(--ckf-accent);outline-offset:2px}\n.ckf-scrim{position:fixed;inset:0;z-index:2147483002;background:rgba(0,0,0,.4);display:flex;align-items:center;justify-content:center;padding:16px;animation:ckf-fade .15s ease-out}\n.ckf-card{position:relative;width:100%;max-width:400px;max-height:calc(100dvh - 32px);overflow-y:auto;background:var(--ckf-bg);color:var(--ckf-fg);border-radius:var(--ckf-radius);box-shadow:var(--ckf-shadow);padding:18px 20px 20px;display:flex;flex-direction:column;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-float{position:fixed;z-index:2147483001;right:20px;bottom:20px;width:340px;max-width:calc(100vw - 24px)}\n.ckf-top{display:flex;align-items:center;gap:8px;min-height:20px}\n.ckf-dots{display:flex;gap:4px}\n.ckf-dot{width:16px;height:4px;border-radius:4px;background:var(--ckf-line)}\n.ckf-dot[data-on]{background:var(--ckf-accent)}\n.ckf-x{margin-left:auto;width:28px;height:28px;border:0;border-radius:8px;background:none;color:var(--ckf-muted);cursor:pointer;display:inline-flex;align-items:center;justify-content:center;font-size:18px;line-height:1}\n.ckf-x:hover{background:var(--ckf-soft);color:var(--ckf-fg)}\n.ckf-h{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;text-wrap:balance}\n.ckf-p{margin:0;color:var(--ckf-muted);text-wrap:pretty;white-space:pre-wrap}\n.ckf-small{margin:0;font-size:12px;color:var(--ckf-muted)}\n.ckf-opts{display:flex;flex-direction:column;gap:6px;margin:0;padding:0;list-style:none}\n.ckf-opt{display:flex;align-items:center;gap:10px;width:100%;min-height:40px;padding:8px 12px;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);text-align:left;cursor:pointer;font-weight:500}\n.ckf-opt:hover{background:var(--ckf-soft)}\n.ckf-opt[aria-checked=true]{border-color:var(--ckf-accent);background:color-mix(in srgb,var(--ckf-accent) 8%,var(--ckf-bg))}\n.ckf-radio{width:16px;height:16px;flex:none;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center}\n.ckf-opt[aria-checked=true] .ckf-radio{border-color:var(--ckf-accent)}\n.ckf-opt[aria-checked=true] .ckf-radio::after{content:\"\";width:8px;height:8px;border-radius:50%;background:var(--ckf-accent)}\n.ckf-box{border-radius:10px;background:var(--ckf-soft);padding:12px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}\n.ckf-big{font-size:22px;font-weight:650;font-variant-numeric:tabular-nums}\n.ckf-strike{color:var(--ckf-muted);text-decoration:line-through;font-variant-numeric:tabular-nums}\n.ckf-text{width:100%;min-height:64px;resize:vertical;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);padding:8px 10px}\n.ckf-text::placeholder{color:var(--ckf-muted)}\n.ckf-btns{display:flex;flex-direction:column;gap:6px}\n.ckf-btn{height:38px;padding:0 14px;border-radius:10px;border:1px solid var(--ckf-line);background:var(--ckf-bg);font-weight:600;cursor:pointer;transition:filter .1s linear,background-color .1s linear}\n.ckf-btn:hover{background:var(--ckf-soft)}\n.ckf-btn[disabled]{opacity:.55;cursor:not-allowed}\n.ckf-primary{background:var(--ckf-accent);border-color:var(--ckf-accent);color:var(--ckf-accent-ink)}\n.ckf-primary:hover{background:var(--ckf-accent);filter:brightness(1.07)}\n.ckf-danger{background:var(--ckf-danger);border-color:var(--ckf-danger);color:#fff}\n.ckf-danger:hover{background:var(--ckf-danger);filter:brightness(1.07)}\n.ckf-quiet{border-color:transparent;background:none;color:var(--ckf-muted);height:30px;font-weight:500}\n.ckf-quiet:hover{background:none;color:var(--ckf-fg)}\n.ckf-err{margin:0;color:var(--ckf-danger);font-size:13px;font-weight:500}\n.ckf-row{display:flex;justify-content:flex-end;gap:8px;align-items:center}\n.ckf-row .ckf-small{margin-right:auto}\n.ckf-media{display:block;width:100%;max-height:240px;object-fit:cover;border-radius:10px;background:var(--ckf-soft)}\n.ckf-video{position:relative;width:100%;aspect-ratio:16/9;border-radius:10px;overflow:hidden;background:#000}\n.ckf-video iframe{position:absolute;inset:0;width:100%;height:100%;border:0}\n.ckf-arrow{position:absolute;width:12px;height:12px;margin:-6px;background:var(--ckf-bg);transform:rotate(45deg)}\n[data-side=bottom]>.ckf-arrow{top:0;left:var(--ckf-ap)}[data-side=top]>.ckf-arrow{top:100%;left:var(--ckf-ap)}\n[data-side=right]>.ckf-arrow{left:0;top:var(--ckf-ap)}[data-side=left]>.ckf-arrow{left:100%;top:var(--ckf-ap)}\n.ckf-check .ckf-go{margin-left:auto;align-self:center;color:var(--ckf-accent);font-weight:700}\n.ckf-ic{width:20px;height:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent);font-size:16px;line-height:1}\n.ckf-ic svg{width:20px;height:20px}.ckf-ic img{width:20px;height:20px;border-radius:5px;object-fit:cover}\n.ckf-hic{width:40px;height:40px;border-radius:12px;background:color-mix(in srgb,var(--ckf-accent) 12%,var(--ckf-bg));display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent);font-size:22px;line-height:1}\n.ckf-hic svg{width:22px;height:22px}.ckf-hic img{width:40px;height:40px;border-radius:12px;object-fit:cover}\n.ckf-input{width:100%;height:40px;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);padding:0 12px}\n.ckf-input::placeholder{color:var(--ckf-muted)}\n.ckf-ring{position:fixed;z-index:2147483000;pointer-events:none;border-radius:10px;box-shadow:0 0 0 2px var(--ckf-accent),0 0 0 6px color-mix(in srgb,var(--ckf-accent) 25%,transparent);transition:all .15s ease-out}\n.ckf-check{display:flex;align-items:flex-start;gap:10px;width:100%;padding:8px 6px;border:0;border-radius:8px;background:none;text-align:left}\n.ckf-check:where(button){cursor:pointer}\n.ckf-check:where(button):hover{background:var(--ckf-soft)}\n.ckf-tick{width:18px;height:18px;flex:none;margin-top:1px;border-radius:50%;border:1.5px solid var(--ckf-line);display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent-ink);font-size:11px;font-weight:700}\n.ckf-check[data-done] .ckf-tick{background:var(--ckf-accent);border-color:var(--ckf-accent)}\n.ckf-check[data-done] b{color:var(--ckf-muted);text-decoration:line-through}\n.ckf-check span{display:flex;flex-direction:column;gap:2px;min-width:0}\n.ckf-bar{height:4px;border-radius:4px;background:var(--ckf-soft);overflow:hidden}\n.ckf-bar i{display:block;height:100%;background:var(--ckf-accent)}\n.ckf-banner{position:fixed;z-index:2147483001;left:50%;top:12px;transform:translateX(-50%);width:min(640px,calc(100vw - 24px));background:var(--ckf-bg);border-radius:12px;box-shadow:var(--ckf-shadow);padding:10px 10px 10px 16px;display:flex;align-items:center;gap:12px;animation:ckf-in .18s ease-out}\n.ckf-banner>span{flex:1;min-width:0;display:flex;flex-direction:column}\n.ckf-banner .ckf-btn{height:32px}\n.ckf-pw{max-width:420px;gap:14px}\n.ckf-root[data-still] :is(.ckf-scrim,.ckf-card){animation:none}\n.ckf-li{display:flex;gap:10px;align-items:flex-start;margin:0}\n.ckf-li::before{content:\"\u2713\";flex:none;width:20px;height:20px;border-radius:50%;background:color-mix(in srgb,var(--ckf-accent) 14%,var(--ckf-bg));color:var(--ckf-accent);font-size:12px;font-weight:700;display:inline-flex;align-items:center;justify-content:center}\n.ckf-quote{margin:0;padding:12px 14px;border-radius:12px;background:var(--ckf-soft)}\n.ckf-quote cite{display:block;margin-top:6px;font-style:normal;font-size:12px;color:var(--ckf-muted)}\n.ckf-plan{justify-content:space-between;min-height:52px}\n.ckf-plan span:nth-child(2){display:flex;flex-direction:column;margin-right:auto}\n.ckf-plan b{font-variant-numeric:tabular-nums}\n@keyframes ckf-fade{from{opacity:0}}\n@keyframes ckf-in{from{opacity:0;transform:translateY(6px)}}\n.ckf-banner{animation-name:ckf-fade}\n@media (max-width:520px){.ckf-scrim{align-items:flex-end;padding:0}.ckf-scrim .ckf-card{max-width:none;border-radius:var(--ckf-radius) var(--ckf-radius) 0 0;max-height:92dvh}.ckf-float{right:12px;bottom:12px}}\n@media (prefers-reduced-motion:reduce){.ckf-root *{animation:none!important;transition:none!important}}\n";
20
11
  export declare const mountFlows: (ctl: FlowsController, theme?: FlowsTheme) => (() => void);
21
12
  /**
22
13
  * Draws an open paywall (paywall.ts) page by page until the returned function is called: the dots, the page's title and
package/dist/flows-ui.js CHANGED
@@ -1,5 +1,7 @@
1
1
  // src/flows-ui.ts
2
- import { discounted, mediaOf, money, offerButton, videoEmbed } from "./flows.js";
2
+ import { playFinish } from "./finish-web.js";
3
+ import { answerOk, discounted, mediaOf, money, offerButton, videoEmbed } from "./flows.js";
4
+ import { FLOW_ICONS, iconOf } from "./icons.js";
3
5
  var STYLE_ID = "ckf-styles";
4
6
  var FLOWS_CSS = `
5
7
  .ckf-root{--ckf-accent:#3f76ff;--ckf-accent-ink:#fff;--ckf-bg:#fff;--ckf-fg:#1c1d20;--ckf-muted:#5d6068;--ckf-soft:#f4f5f7;--ckf-line:#e4e5e8;--ckf-danger:#d92d20;--ckf-radius:14px;--ckf-font:inherit;--ckf-shadow:0 16px 40px -12px rgba(16,18,24,.28),0 0 0 1px rgba(16,18,24,.07)}
@@ -53,6 +55,12 @@ var FLOWS_CSS = `
53
55
  [data-side=bottom]>.ckf-arrow{top:0;left:var(--ckf-ap)}[data-side=top]>.ckf-arrow{top:100%;left:var(--ckf-ap)}
54
56
  [data-side=right]>.ckf-arrow{left:0;top:var(--ckf-ap)}[data-side=left]>.ckf-arrow{left:100%;top:var(--ckf-ap)}
55
57
  .ckf-check .ckf-go{margin-left:auto;align-self:center;color:var(--ckf-accent);font-weight:700}
58
+ .ckf-ic{width:20px;height:20px;flex:none;display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent);font-size:16px;line-height:1}
59
+ .ckf-ic svg{width:20px;height:20px}.ckf-ic img{width:20px;height:20px;border-radius:5px;object-fit:cover}
60
+ .ckf-hic{width:40px;height:40px;border-radius:12px;background:color-mix(in srgb,var(--ckf-accent) 12%,var(--ckf-bg));display:inline-flex;align-items:center;justify-content:center;color:var(--ckf-accent);font-size:22px;line-height:1}
61
+ .ckf-hic svg{width:22px;height:22px}.ckf-hic img{width:40px;height:40px;border-radius:12px;object-fit:cover}
62
+ .ckf-input{width:100%;height:40px;border:1px solid var(--ckf-line);border-radius:10px;background:var(--ckf-bg);padding:0 12px}
63
+ .ckf-input::placeholder{color:var(--ckf-muted)}
56
64
  .ckf-ring{position:fixed;z-index:2147483000;pointer-events:none;border-radius:10px;box-shadow:0 0 0 2px var(--ckf-accent),0 0 0 6px color-mix(in srgb,var(--ckf-accent) 25%,transparent);transition:all .15s ease-out}
57
65
  .ckf-check{display:flex;align-items:flex-start;gap:10px;width:100%;padding:8px 6px;border:0;border-radius:8px;background:none;text-align:left}
58
66
  .ckf-check:where(button){cursor:pointer}
@@ -122,10 +130,31 @@ var rootFor = (theme) => {
122
130
  document.body.appendChild(root);
123
131
  return root;
124
132
  };
133
+ var iconEl = (icon, className) => {
134
+ const i = iconOf(icon);
135
+ if (!i) return false;
136
+ const box = h("span", { className, "aria-hidden": "true" });
137
+ if (i.kind === "emoji") box.textContent = i.value;
138
+ else if (i.kind === "image") box.append(h("img", { src: i.url, alt: "" }));
139
+ else {
140
+ const ns = "http://www.w3.org/2000/svg";
141
+ const svg = document.createElementNS(ns, "svg");
142
+ for (const [k, v] of Object.entries({ viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", "stroke-width": "2", "stroke-linecap": "round", "stroke-linejoin": "round" }))
143
+ svg.setAttribute(k, v);
144
+ for (const d of FLOW_ICONS[i.name].paths) {
145
+ const p = document.createElementNS(ns, "path");
146
+ p.setAttribute("d", d);
147
+ svg.append(p);
148
+ }
149
+ box.append(svg);
150
+ }
151
+ return box;
152
+ };
125
153
  var mountFlows = (ctl, theme = {}) => {
126
154
  if (typeof document === "undefined") return () => {
127
155
  };
128
156
  const root = rootFor(theme);
157
+ let played = "";
129
158
  let lastKey = "";
130
159
  let returnFocus = null;
131
160
  let comment = "";
@@ -305,8 +334,69 @@ var mountFlows = (ctl, theme = {}) => {
305
334
  h("iframe", { src: v.src, title: m.alt || "Video", allow: "fullscreen; picture-in-picture", allowfullscreen: true, loading: "lazy", referrerpolicy: "strict-origin-when-cross-origin" })
306
335
  ) : h("video", { className: "ckf-media", src: v.src, controls: true, playsinline: true, preload: "metadata", "aria-label": m.alt || void 0, onLoadedmetadata: () => follow() });
307
336
  };
337
+ const questionCard = (v) => {
338
+ const s = v.step;
339
+ const q = s.question;
340
+ const titleId = "ckf-title";
341
+ const ok = answerOk(q, v.answer);
342
+ let field = false;
343
+ if (q?.type === "choice")
344
+ field = h(
345
+ "div",
346
+ { className: "ckf-opts", role: "radiogroup", "aria-labelledby": titleId },
347
+ ...(q.options ?? []).map(
348
+ (o) => h(
349
+ "button",
350
+ {
351
+ type: "button",
352
+ role: "radio",
353
+ className: "ckf-opt",
354
+ "aria-checked": String(v.answer === o.id),
355
+ "data-ckf-id": `q:${o.id}`,
356
+ onClick: () => ctl.onboarding.answer(o.id)
357
+ },
358
+ h("span", { className: "ckf-radio" }),
359
+ o.label
360
+ )
361
+ )
362
+ );
363
+ else if (q) {
364
+ const input = h("input", {
365
+ type: "text",
366
+ className: "ckf-input",
367
+ placeholder: q.placeholder || "Your answer",
368
+ "aria-labelledby": titleId,
369
+ maxlength: "500",
370
+ "data-ckf-id": "answer",
371
+ onInput: (e) => ctl.onboarding.answer(e.target.value),
372
+ onKeydown: (e) => e.key === "Enter" && ctl.onboarding.next()
373
+ });
374
+ input.value = v.answer ?? "";
375
+ field = input;
376
+ }
377
+ return h(
378
+ "div",
379
+ { className: "ckf-scrim" },
380
+ h(
381
+ "div",
382
+ { className: "ckf-card", role: "dialog", "aria-modal": "true", "aria-labelledby": titleId },
383
+ h("div", { className: "ckf-top" }, dots(v.index + 1, v.total), closeButton("Close", ctl.onboarding.dismiss)),
384
+ v.index === 0 ? iconEl(v.flow.icon, "ckf-hic") : false,
385
+ h("h2", { className: "ckf-h", id: titleId }, s.title),
386
+ s.body ? h("p", { className: "ckf-p" }, s.body) : false,
387
+ field,
388
+ h(
389
+ "div",
390
+ { className: "ckf-row" },
391
+ v.back ? button("Back", "quiet", ctl.onboarding.back) : false,
392
+ button(s.button || (v.last ? "Done" : "Continue"), "primary", ctl.onboarding.next, { disabled: !ok, id: "go" })
393
+ )
394
+ )
395
+ );
396
+ };
308
397
  const stepCard = (v) => {
309
398
  const s = v.step;
399
+ if (s.kind === "question") return questionCard(v);
310
400
  const card = h(
311
401
  "div",
312
402
  { className: "ckf-card", role: "dialog", "aria-modal": s.kind === "modal" ? "true" : void 0, "aria-labelledby": "ckf-title" },
@@ -316,6 +406,7 @@ var mountFlows = (ctl, theme = {}) => {
316
406
  v.total > 1 ? h("p", { className: "ckf-small" }, `Step ${v.index + 1} of ${v.total}`) : h("span"),
317
407
  closeButton("Close the tour", ctl.onboarding.dismiss)
318
408
  ),
409
+ s.kind === "modal" ? iconEl(v.flow.icon, "ckf-hic") : false,
319
410
  media(s),
320
411
  h("h2", { className: "ckf-h", id: "ckf-title" }, s.title),
321
412
  s.body ? h("p", { className: "ckf-p" }, s.body) : false,
@@ -394,12 +485,13 @@ var mountFlows = (ctl, theme = {}) => {
394
485
  h(
395
486
  "div",
396
487
  { className: "ckf-opts" },
397
- ...v.items.map(({ step, done: d, tour }) => {
488
+ ...v.items.map(({ step, done: d, opens }) => {
398
489
  const inner = [
399
490
  h("span", { className: "ckf-tick", "aria-hidden": "true" }, d ? "\u2713" : ""),
491
+ iconEl(step.icon, "ckf-ic"),
400
492
  h("span", {}, h("b", {}, step.title), step.body ? h("span", { className: "ckf-small" }, step.body) : false)
401
493
  ];
402
- if (!d && tour)
494
+ if (!d && opens)
403
495
  return h(
404
496
  "button",
405
497
  {
@@ -407,7 +499,7 @@ var mountFlows = (ctl, theme = {}) => {
407
499
  className: "ckf-check",
408
500
  "aria-label": `Start \u201C${step.title}\u201D`,
409
501
  "data-ckf-id": `t:${step.id}`,
410
- onClick: () => ctl.onboarding.startTour(step.id)
502
+ onClick: () => ctl.onboarding.open(step.id)
411
503
  },
412
504
  ...inner,
413
505
  h("span", { className: "ckf-go", "aria-hidden": "true" }, "\u203A")
@@ -454,6 +546,13 @@ var mountFlows = (ctl, theme = {}) => {
454
546
  };
455
547
  const draw = () => {
456
548
  const v = ctl.view();
549
+ const accent = theme.accent ?? ctl.accent?.();
550
+ if (accent) root.style.setProperty("--ckf-accent", accent);
551
+ const fin = ctl.finale?.();
552
+ if (fin && fin.key !== played) {
553
+ played = fin.key;
554
+ playFinish(fin.kind, { accent });
555
+ }
457
556
  const key = v ? screenKey(v) : "";
458
557
  const focused = document.activeElement?.closest?.(".ckf-root") ? document.activeElement?.getAttribute("data-ckf-id") : null;
459
558
  if (key && !lastKey && document.activeElement instanceof HTMLElement && !document.activeElement.closest(".ckf-root"))
@@ -467,7 +566,7 @@ var mountFlows = (ctl, theme = {}) => {
467
566
  follow();
468
567
  if (key !== lastKey) {
469
568
  const modal = root.querySelector("[aria-modal=true]");
470
- const first = modal?.querySelector("[role=radio], [data-ckf-id=go], textarea") ?? null;
569
+ const first = modal?.querySelector("[role=radio], input, [data-ckf-id=go], textarea") ?? null;
471
570
  first?.focus();
472
571
  if (!key && returnFocus) {
473
572
  returnFocus.focus();
@@ -481,7 +580,7 @@ var mountFlows = (ctl, theme = {}) => {
481
580
  const v = ctl.view();
482
581
  if (v?.type === "cancel") ctl.cancel.close();
483
582
  else if (v?.type === "message") ctl.message.dismiss();
484
- else if (v?.type === "step" && v.step.kind === "modal") ctl.onboarding.dismiss();
583
+ else if (v?.type === "step" && (v.step.kind === "modal" || v.step.kind === "question")) ctl.onboarding.dismiss();
485
584
  };
486
585
  function follow() {
487
586
  if (placed) place(placed.float, placed.ring, placed.target, placed.side);