@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
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/flows-ui.ts"],"sourcesContent":["/**\n * The web renderer of the cancel flow, onboarding and in-app messages (flows.ts): plain DOM, no React, so the Next.js\n * provider and the script tag share it. Both load it only when something is about to show (a dynamic import, and\n * `sdk-flows.js` for the script tag), so pages that show nothing never download it.\n *\n * Themeable three ways: `theme` (\"light\", \"dark\", \"auto\") and `accent` from the SDK's options, and CSS variables on\n * `.ckf-root` in the site's own stylesheet (`--ckf-accent`, `--ckf-bg`, `--ckf-fg`, `--ckf-muted`, `--ckf-line`,\n * `--ckf-radius`, `--ckf-font`). Every text is set with textContent; nothing from the server is parsed as HTML.\n */\nimport { type FlowView, type FlowsController, type OnboardingStep, type TourPlacement, discounted, mediaOf, money, offerButton, videoEmbed } from \"./flows\";\nimport type { PaywallHost } from \"./paywall\";\n\nexport interface FlowsTheme {\n theme?: \"light\" | \"dark\" | \"auto\";\n /** The main color of buttons and highlights, like \"#3f76ff\". */\n accent?: string;\n /** An extra class on the root, for the site's own CSS. */\n className?: string;\n}\n\nconst STYLE_ID = \"ckf-styles\";\n\nexport 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:\"✓\";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`;\n\ntype Attrs = Record<string, string | boolean | undefined | ((e: Event) => void)>;\n\n/** A small element builder: attributes, `on*` handlers and children (strings become text, never HTML). */\nconst h = (tag: string, attrs: Attrs = {}, ...children: (Node | string | false | null | undefined)[]) => {\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined || v === false) continue;\n if (typeof v === \"function\") el.addEventListener(k.slice(2).toLowerCase(), v);\n else if (k === \"className\") el.className = String(v);\n else el.setAttribute(k, v === true ? \"\" : v);\n }\n for (const c of children) if (c || c === \"\") el.append(typeof c === \"string\" ? document.createTextNode(c) : c);\n return el;\n};\n\nconst button = (label: string, kind: \"primary\" | \"danger\" | \"secondary\" | \"quiet\", onClick: () => void, opts: { disabled?: boolean; id?: string } = {}) =>\n h(\n \"button\",\n {\n type: \"button\",\n className: `ckf-btn${kind === \"secondary\" ? \"\" : ` ckf-${kind}`}`,\n disabled: !!opts.disabled,\n \"data-ckf-id\": opts.id,\n onClick: () => onClick(),\n },\n label,\n );\n\nconst closeButton = (label: string, onClick: () => void) =>\n h(\"button\", { type: \"button\", className: \"ckf-x\", \"aria-label\": label, \"data-ckf-id\": \"x\", onClick: () => onClick() }, \"×\");\n\nconst dots = (step: number, steps: number) =>\n steps > 1\n ? h(\n \"span\",\n { className: \"ckf-dots\", role: \"img\", \"aria-label\": `Step ${step} of ${steps}` },\n ...Array.from({ length: steps }, (_, i) => h(\"span\", { className: \"ckf-dot\", \"data-on\": i < step })),\n )\n : h(\"span\");\n\n/** A key that changes when the screen (not just its state) changes: then focus moves to the new screen. */\nconst screenKey = (v: FlowView) =>\n v.type === \"cancel\" ? `c:${v.screen}:${v.round ?? 1}` : v.type === \"step\" ? `s:${v.step.id}` : v.type === \"checklist\" ? `l:${v.flow.id}` : `m:${v.message.id}`;\n\n/**\n * Draws the controller's view into the page until the returned function is called. One root element under <body>;\n * nothing is drawn while there is nothing to show.\n */\n/** The stylesheet once, and a themed root element under <body>. */\nconst rootFor = (theme: FlowsTheme) => {\n if (!document.getElementById(STYLE_ID)) {\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = FLOWS_CSS;\n document.head.appendChild(style);\n }\n const root = h(\"div\", { className: `ckf-root${theme.className ? ` ${theme.className}` : \"\"}`, \"data-theme\": theme.theme ?? \"auto\" });\n if (theme.accent) root.style.setProperty(\"--ckf-accent\", theme.accent);\n document.body.appendChild(root);\n return root;\n};\n\nexport const mountFlows = (ctl: FlowsController, theme: FlowsTheme = {}): (() => void) => {\n if (typeof document === \"undefined\") return () => {};\n const root = rootFor(theme);\n\n let lastKey = \"\";\n let returnFocus: HTMLElement | null = null;\n let comment = \"\";\n let placed: { float: HTMLElement; ring: HTMLElement; target: HTMLElement; side?: TourPlacement } | null = null;\n\n // ---------- Cancel flow ----------\n\n const cancelCard = (v: Extract<FlowView, { type: \"cancel\" }>) => {\n const titleId = \"ckf-title\";\n const busy = v.busy;\n const body: (Node | false)[] = [];\n if (v.screen === \"survey\") {\n body.push(\n h(\"h2\", { className: \"ckf-h\", id: titleId }, v.flow.question || \"Why are you leaving?\"),\n h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-labelledby\": titleId },\n ...v.flow.reasons.map((r) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt\",\n \"aria-checked\": String(v.reason === r.id),\n \"data-ckf-id\": `r:${r.id}`,\n onClick: () => ctl.cancel.pick(r.id),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n r.label,\n ),\n ),\n ),\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(\"Continue\", \"primary\", ctl.cancel.next, { disabled: !v.reason, id: \"go\" }),\n button(\"Never mind, keep my plan\", \"quiet\", ctl.cancel.close),\n ),\n );\n } else if (v.screen === \"followup\" && v.followUp) {\n const f = v.followUp;\n let field: Node;\n if (f.answers.length)\n field = h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-labelledby\": titleId },\n ...f.answers.map((a, i) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt\",\n \"aria-checked\": String(v.answer === a),\n \"data-ckf-id\": `a:${i}`,\n onClick: () => ctl.cancel.answer(a),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n a,\n ),\n ),\n );\n else {\n const text = h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"Your answer (optional)\",\n \"aria-labelledby\": titleId,\n maxlength: \"500\",\n \"data-ckf-id\": \"answer\",\n onInput: (e) => ctl.cancel.answer((e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement;\n text.value = v.answer ?? \"\";\n field = text;\n }\n const label = v.flow.reasons.find((r) => r.id === v.reason)?.label;\n body.push(\n label ? h(\"p\", { className: \"ckf-small\" }, `You said: ${label}`) : false,\n h(\"h2\", { className: \"ckf-h\", id: titleId }, f.question),\n field,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(\"Continue\", \"primary\", ctl.cancel.next, { id: \"go\" }),\n button(\"Never mind, keep my plan\", \"quiet\", ctl.cancel.close),\n ),\n );\n } else if (v.screen === \"offer\" && v.offer) {\n const o = v.offer;\n const label = v.flow.reasons.find((r) => r.id === v.reason)?.label;\n let detail: Node | false = false;\n if (o.kind === \"discount\" && o.percent)\n detail = v.price\n ? h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", { className: \"ckf-big\" }, money(discounted(v.price.amount, o.percent), v.price.currency)),\n h(\"span\", { className: \"ckf-strike\" }, money(v.price.amount, v.price.currency)),\n h(\n \"span\",\n { className: \"ckf-small\" },\n `/${v.price.interval ?? \"month\"}${o.months ? ` for ${o.months} ${o.months === 1 ? \"month\" : \"months\"}` : \"\"}`,\n ),\n )\n : h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", { className: \"ckf-big\" }, `${o.percent}% off`),\n o.months ? h(\"span\", { className: \"ckf-small\" }, `for ${o.months} ${o.months === 1 ? \"month\" : \"months\"}`) : false,\n );\n if (o.kind === \"pause\" && o.months)\n detail = h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", {}, `Pause for up to ${o.months} ${o.months === 1 ? \"month\" : \"months\"}. Your data stays.`),\n );\n if (o.kind === \"downgrade\" && o.planName) detail = h(\"div\", { className: \"ckf-box\" }, h(\"b\", {}, o.planName));\n const text =\n o.kind === \"contact\"\n ? (h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"What would make you stay?\",\n \"aria-label\": \"Your message\",\n maxlength: \"500\",\n \"data-ckf-id\": \"comment\",\n onInput: (e) => (comment = (e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement)\n : null;\n if (text) text.value = comment;\n body.push(\n label ? h(\"p\", { className: \"ckf-small\" }, `You said: ${label}`) : false,\n h(\"h2\", { className: \"ckf-h\", id: titleId }, o.headline),\n detail,\n text ?? false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(busy ? \"One moment…\" : offerButton(o), \"primary\", () => ctl.cancel.accept(comment), { disabled: busy, id: \"go\" }),\n button(\"No thanks, continue cancelling\", \"quiet\", ctl.cancel.decline, { disabled: busy }),\n ),\n );\n } else {\n const plain = v.steps === 1;\n const text = plain\n ? null\n : (h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"Anything else we should know? (optional)\",\n \"aria-label\": \"Anything else we should know? (optional)\",\n maxlength: \"500\",\n \"data-ckf-id\": \"comment\",\n onInput: (e) => (comment = (e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement);\n if (text) text.value = comment;\n body.push(\n h(\"h2\", { className: \"ckf-h\", id: titleId }, v.flow.confirm.title),\n v.flow.confirm.body ? h(\"p\", { className: \"ckf-p\" }, v.flow.confirm.body) : false,\n text ?? false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(busy ? \"One moment…\" : v.flow.confirm.button, \"danger\", () => ctl.cancel.confirm(comment), { disabled: busy, id: \"go\" }),\n button(\"Keep my plan\", \"secondary\", ctl.cancel.close, { disabled: busy }),\n ),\n );\n }\n return h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && !busy && ctl.cancel.close() },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": titleId },\n h(\"div\", { className: \"ckf-top\" }, dots(v.step, v.steps), closeButton(\"Close\", ctl.cancel.close)),\n ...body,\n v.error ? h(\"p\", { className: \"ckf-err\", role: \"alert\" }, v.error) : false,\n ),\n );\n };\n\n // ---------- Onboarding ----------\n\n /** 0.17.0: the step's picture or video above its text; a video link plays in its privacy-friendly player. */\n const media = (s: OnboardingStep) => {\n const m = mediaOf(s);\n if (!m) return false;\n if (m.kind === \"image\") return h(\"img\", { className: \"ckf-media\", src: m.url, alt: m.alt ?? \"\", onLoad: () => follow() });\n const v = videoEmbed(m.url)!;\n return v.kind === \"iframe\"\n ? h(\n \"div\",\n { className: \"ckf-video\" },\n h(\"iframe\", { src: v.src, title: m.alt || \"Video\", allow: \"fullscreen; picture-in-picture\", allowfullscreen: true, loading: \"lazy\", referrerpolicy: \"strict-origin-when-cross-origin\" }),\n )\n : h(\"video\", { className: \"ckf-media\", src: v.src, controls: true, playsinline: true, preload: \"metadata\", \"aria-label\": m.alt || undefined, onLoadedmetadata: () => follow() });\n };\n\n const stepCard = (v: Extract<FlowView, { type: \"step\" }>) => {\n const s = v.step;\n const card = h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": s.kind === \"modal\" ? \"true\" : undefined, \"aria-labelledby\": \"ckf-title\" },\n h(\n \"div\",\n { className: \"ckf-top\" },\n v.total > 1 ? h(\"p\", { className: \"ckf-small\" }, `Step ${v.index + 1} of ${v.total}`) : h(\"span\"),\n closeButton(\"Close the tour\", ctl.onboarding.dismiss),\n ),\n media(s),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, s.title),\n s.body ? h(\"p\", { className: \"ckf-p\" }, s.body) : false,\n h(\"div\", { className: \"ckf-row\" }, button(s.button || (v.last ? \"Done\" : \"Next\"), \"primary\", ctl.onboarding.next, { id: \"go\" })),\n );\n if (s.kind === \"modal\") return h(\"div\", { className: \"ckf-scrim\" }, card);\n const target = s.target ? findTarget(s.target) : null;\n const float = h(\"div\", { className: \"ckf-float\" }, card);\n if (target) {\n const ring = h(\"div\", { className: \"ckf-ring\", \"aria-hidden\": \"true\" });\n float.append(h(\"span\", { className: \"ckf-arrow\", \"aria-hidden\": \"true\" }));\n placed = { float, ring, target, side: s.placement };\n place(float, ring, target, s.placement);\n return h(\"div\", {}, ring, float);\n }\n return float;\n };\n\n /**\n * The element a tour step points at: a CSS selector (`#new-project`, `.toolbar button`, picked on the site in\n * MRRocket), or a plain name for `data-ck-target=\"…\"`. A selector that does not parse falls back to the name.\n */\n const findTarget = (t: string): HTMLElement | null => {\n const named = () => document.querySelector<HTMLElement>(`[data-ck-target=\"${CSS.escape(t)}\"]`);\n if (!/^[#.[]|[\\s>:=]/.test(t)) return named();\n return safeQuery(t) ?? named();\n };\n const safeQuery = (sel: string) => {\n try {\n return document.querySelector<HTMLElement>(sel);\n } catch {\n return null;\n }\n };\n\n /**\n * Puts a tour card next to the element it points at, on the step's side (0.17.0) or, on \"auto\", below it and above\n * when there is no room. A side without room flips to the opposite one, then to any side with room.\n */\n const place = (float: HTMLElement, ring: HTMLElement, target: HTMLElement, side: TourPlacement = \"auto\") => {\n const r = target.getBoundingClientRect();\n Object.assign(ring.style, { left: `${r.left - 4}px`, top: `${r.top - 4}px`, width: `${r.width + 8}px`, height: `${r.height + 8}px` });\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const w = Math.min(340, vw - 24);\n const ht = float.offsetHeight || 200;\n const gap = 14;\n const room: Record<string, boolean> = {\n bottom: vh - r.bottom - gap - 12 >= ht,\n top: r.top - gap - 12 >= ht,\n right: vw - r.right - gap - 12 >= w,\n left: r.left - gap - 12 >= w,\n };\n const flip: Record<string, string> = { top: \"bottom\", bottom: \"top\", left: \"right\", right: \"left\" };\n const order = side === \"auto\" || !flip[side] ? [\"bottom\", \"top\"] : [side, flip[side], \"bottom\", \"top\", \"right\", \"left\"];\n const s = order.find((x) => room[x]) ?? (side !== \"auto\" && flip[side] ? side : r.top > vh - r.bottom ? \"top\" : \"bottom\");\n const clamp = (v: number, hi: number) => Math.max(12, Math.min(v, hi - 12));\n const across = s === \"top\" || s === \"bottom\";\n // \"auto\" keeps the card's left edge at the element's, as before 0.17.0; a chosen side centres it.\n const left = across ? clamp(side === \"auto\" ? r.left : r.left + r.width / 2 - w / 2, vw - w) : s === \"right\" ? r.right + gap : r.left - gap - w;\n const top = across ? (s === \"bottom\" ? r.bottom + gap : r.top - gap - ht) : clamp(r.top + r.height / 2 - ht / 2, vh - ht);\n Object.assign(float.style, { left: `${left}px`, top: `${top}px`, right: \"auto\", bottom: \"auto\", width: `${w}px` });\n float.setAttribute(\"data-side\", s);\n // The arrow points at the element's middle, kept off the card's rounded corners.\n const at = across ? r.left + r.width / 2 - left : r.top + r.height / 2 - top;\n float.style.setProperty(\"--ckf-ap\", `${Math.max(18, Math.min(at, (across ? w : ht) - 18))}px`);\n };\n\n const checklist = (v: Extract<FlowView, { type: \"checklist\" }>) => {\n const done = v.items.filter((i) => i.done).length;\n return h(\n \"div\",\n { className: \"ckf-float\" },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"region\", \"aria-labelledby\": \"ckf-title\" },\n h(\n \"div\",\n { className: \"ckf-top\" },\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, v.flow.name),\n closeButton(\"Hide the checklist\", ctl.onboarding.dismiss),\n ),\n h(\"p\", { className: \"ckf-small\" }, `${done} of ${v.items.length} done`),\n h(\n \"div\",\n { className: \"ckf-bar\", role: \"progressbar\", \"aria-valuemin\": \"0\", \"aria-valuemax\": String(v.items.length), \"aria-valuenow\": String(done) },\n h(\"i\", { style: `width:${(done / v.items.length) * 100}%` } as Attrs),\n ),\n h(\n \"div\",\n { className: \"ckf-opts\" },\n ...v.items.map(({ step, done: d, tour }) => {\n const inner = [\n h(\"span\", { className: \"ckf-tick\", \"aria-hidden\": \"true\" }, d ? \"✓\" : \"\"),\n h(\"span\", {}, h(\"b\", {}, step.title), step.body ? h(\"span\", { className: \"ckf-small\" }, step.body) : false),\n ];\n // 0.17.0: an item that starts a tour opens it; finishing the tour ticks it (unless an event does).\n if (!d && tour)\n return h(\n \"button\",\n {\n type: \"button\",\n className: \"ckf-check\",\n \"aria-label\": `Start “${step.title}”`,\n \"data-ckf-id\": `t:${step.id}`,\n onClick: () => ctl.onboarding.startTour(step.id),\n },\n ...inner,\n h(\"span\", { className: \"ckf-go\", \"aria-hidden\": \"true\" }, \"›\"),\n );\n // An item with an event ticks itself when the app records it; the others are ticked by hand.\n return d || step.event\n ? h(\"div\", { className: \"ckf-check\", \"data-done\": d, role: \"listitem\" }, ...inner)\n : h(\n \"button\",\n {\n type: \"button\",\n className: \"ckf-check\",\n \"aria-label\": `Mark “${step.title}” done`,\n \"data-ckf-id\": `i:${step.id}`,\n onClick: () => ctl.onboarding.check(step.id),\n },\n ...inner,\n );\n }),\n ),\n ),\n );\n };\n\n // ---------- Messages ----------\n\n const message = (v: Extract<FlowView, { type: \"message\" }>) => {\n const m = v.message;\n const action = m.button ? button(m.button, \"primary\", ctl.message.click, { id: \"go\" }) : false;\n if (m.style === \"banner\")\n return h(\n \"div\",\n { className: \"ckf-banner\", role: \"status\" },\n h(\"span\", {}, h(\"b\", {}, m.title), m.body ? h(\"span\", { className: \"ckf-small\" }, m.body) : false),\n action,\n closeButton(\"Dismiss\", ctl.message.dismiss),\n );\n return h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && ctl.message.dismiss() },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"ckf-title\" },\n h(\"div\", { className: \"ckf-top\" }, h(\"span\"), closeButton(\"Dismiss\", ctl.message.dismiss)),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, m.title),\n m.body ? h(\"p\", { className: \"ckf-p\" }, m.body) : false,\n action ? h(\"div\", { className: \"ckf-row\" }, action) : false,\n ),\n );\n };\n\n // ---------- Drawing ----------\n\n const draw = () => {\n const v = ctl.view();\n const key = v ? screenKey(v) : \"\";\n const focused = (document.activeElement as HTMLElement | null)?.closest?.(\".ckf-root\") ? document.activeElement?.getAttribute(\"data-ckf-id\") : null;\n if (key && !lastKey && document.activeElement instanceof HTMLElement && !document.activeElement.closest(\".ckf-root\"))\n returnFocus = document.activeElement;\n if (key !== lastKey && !key.startsWith(\"c:\")) comment = \"\";\n if (!key) comment = \"\";\n placed = null;\n root.replaceChildren(\n ...(v ? [v.type === \"cancel\" ? cancelCard(v) : v.type === \"step\" ? stepCard(v) : v.type === \"checklist\" ? checklist(v) : message(v)] : []),\n );\n // Placed again now that the card is in the page and has its real height.\n follow();\n if (key !== lastKey) {\n // A new screen: focus its first control (a dialog's), so keyboard and screen reader users land in it.\n const modal = root.querySelector<HTMLElement>(\"[aria-modal=true]\");\n const first = modal?.querySelector<HTMLElement>(\"[role=radio], [data-ckf-id=go], textarea\") ?? null;\n first?.focus();\n if (!key && returnFocus) {\n returnFocus.focus();\n returnFocus = null;\n }\n } else if (focused) root.querySelector<HTMLElement>(`[data-ckf-id=\"${CSS.escape(focused)}\"]`)?.focus();\n lastKey = key;\n };\n\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n const v = ctl.view();\n if (v?.type === \"cancel\") ctl.cancel.close();\n else if (v?.type === \"message\") ctl.message.dismiss();\n else if (v?.type === \"step\" && v.step.kind === \"modal\") ctl.onboarding.dismiss();\n };\n // A tour card follows its element when the page scrolls or resizes.\n function follow() {\n if (placed) place(placed.float, placed.ring, placed.target, placed.side);\n }\n document.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"resize\", follow);\n window.addEventListener(\"scroll\", follow, { passive: true, capture: true });\n const off = ctl.subscribe(draw);\n draw();\n return () => {\n off();\n document.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"resize\", follow);\n window.removeEventListener(\"scroll\", follow, { capture: true });\n root.remove();\n };\n};\n\n/**\n * Draws an open paywall (paywall.ts) page by page until the returned function is called: the dots, the page's title and\n * text, its benefits, quotes or plans, Back and the button. Closes on Escape and on a click beside the card.\n */\nexport const mountPaywall = (host: PaywallHost, theme: FlowsTheme = {}): (() => void) => {\n if (typeof document === \"undefined\") return () => {};\n const root = rootFor(theme);\n let lastKey = \"\";\n let returnFocus: HTMLElement | null = null;\n const draw = () => {\n const v = host.view();\n const key = v ? `${v.paywall.id}:${v.index}` : \"\";\n if (key && !lastKey && document.activeElement instanceof HTMLElement) returnFocus = document.activeElement;\n if (!v) {\n root.replaceChildren();\n root.removeAttribute(\"data-still\");\n if (lastKey) returnFocus?.focus();\n lastKey = \"\";\n return;\n }\n // Fades in when it opens, not again on every page or plan.\n if (lastKey) root.setAttribute(\"data-still\", \"\");\n const p = v.page;\n const plans =\n p.kind === \"plans\"\n ? h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-label\": \"Plans\" },\n ...v.plans.map((plan) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt ckf-plan\",\n \"aria-checked\": String(v.plan === plan.id),\n \"data-ckf-id\": `p:${plan.id}`,\n onClick: () => host.pick(plan.id),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n h(\"span\", {}, plan.name, plan.note ? h(\"span\", { className: \"ckf-small\" }, plan.note) : false),\n h(\"b\", {}, plan.price),\n ),\n ),\n )\n : false;\n root.replaceChildren(\n h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && host.close() },\n h(\n \"div\",\n { className: \"ckf-card ckf-pw\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"ckf-title\" },\n h(\"div\", { className: \"ckf-top\" }, dots(v.index + 1, v.total), closeButton(\"Close\", host.close)),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, p.title),\n p.body ? h(\"p\", { className: \"ckf-p\" }, p.body) : false,\n p.kind === \"benefits\" && p.items?.length ? h(\"div\", { className: \"ckf-opts\" }, ...p.items.map((i) => h(\"p\", { className: \"ckf-li\" }, i))) : false,\n p.kind === \"proof\" && p.quotes?.length\n ? h(\"div\", { className: \"ckf-opts\" }, ...p.quotes.map((q) => h(\"blockquote\", { className: \"ckf-quote\" }, q.text, q.by ? h(\"cite\", {}, q.by) : false)))\n : false,\n plans,\n v.error ? h(\"p\", { className: \"ckf-err\", role: \"alert\" }, v.error) : false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(v.busy ? \"One moment…\" : p.button || \"Continue\", \"primary\", host.next, {\n disabled: v.busy || (p.kind === \"plans\" && !v.plan),\n id: \"go\",\n }),\n v.index ? button(\"Back\", \"quiet\", host.back, { disabled: v.busy }) : false,\n ),\n ),\n ),\n );\n if (key !== lastKey) root.querySelector<HTMLElement>(\"[data-ckf-id=go]\")?.focus();\n lastKey = key;\n };\n const onKey = (e: KeyboardEvent) => {\n if (!host.view()) return;\n if (e.key === \"Escape\") host.close();\n };\n document.addEventListener(\"keydown\", onKey);\n const off = host.subscribe(draw);\n draw();\n return () => {\n off();\n document.removeEventListener(\"keydown\", onKey);\n root.remove();\n };\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/flows-ui.ts"],"sourcesContent":["/**\n * The web renderer of the cancel flow, onboarding and in-app messages (flows.ts): plain DOM, no React, so the Next.js\n * provider and the script tag share it. Both load it only when something is about to show (a dynamic import, and\n * `sdk-flows.js` for the script tag), so pages that show nothing never download it.\n *\n * Themeable three ways: `theme` (\"light\", \"dark\", \"auto\") and `accent` from the SDK's options, and CSS variables on\n * `.ckf-root` in the site's own stylesheet (`--ckf-accent`, `--ckf-bg`, `--ckf-fg`, `--ckf-muted`, `--ckf-line`,\n * `--ckf-radius`, `--ckf-font`). Every text is set with textContent; nothing from the server is parsed as HTML.\n */\nimport { playFinish } from \"./finish-web\";\nimport { type FlowIcon, type FlowView, type FlowsController, type OnboardingStep, type TourPlacement, answerOk, discounted, mediaOf, money, offerButton, videoEmbed } from \"./flows\";\nimport { FLOW_ICONS, iconOf } from \"./icons\";\nimport type { PaywallHost } from \"./paywall\";\n\nexport interface FlowsTheme {\n theme?: \"light\" | \"dark\" | \"auto\";\n /** The main color of buttons and highlights, like \"#3f76ff\". */\n accent?: string;\n /** An extra class on the root, for the site's own CSS. */\n className?: string;\n}\n\nconst STYLE_ID = \"ckf-styles\";\n\nexport 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:\"✓\";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`;\n\ntype Attrs = Record<string, string | boolean | undefined | ((e: Event) => void)>;\n\n/** A small element builder: attributes, `on*` handlers and children (strings become text, never HTML). */\nconst h = (tag: string, attrs: Attrs = {}, ...children: (Node | string | false | null | undefined)[]) => {\n const el = document.createElement(tag);\n for (const [k, v] of Object.entries(attrs)) {\n if (v === undefined || v === false) continue;\n if (typeof v === \"function\") el.addEventListener(k.slice(2).toLowerCase(), v);\n else if (k === \"className\") el.className = String(v);\n else el.setAttribute(k, v === true ? \"\" : v);\n }\n for (const c of children) if (c || c === \"\") el.append(typeof c === \"string\" ? document.createTextNode(c) : c);\n return el;\n};\n\nconst button = (label: string, kind: \"primary\" | \"danger\" | \"secondary\" | \"quiet\", onClick: () => void, opts: { disabled?: boolean; id?: string } = {}) =>\n h(\n \"button\",\n {\n type: \"button\",\n className: `ckf-btn${kind === \"secondary\" ? \"\" : ` ckf-${kind}`}`,\n disabled: !!opts.disabled,\n \"data-ckf-id\": opts.id,\n onClick: () => onClick(),\n },\n label,\n );\n\nconst closeButton = (label: string, onClick: () => void) =>\n h(\"button\", { type: \"button\", className: \"ckf-x\", \"aria-label\": label, \"data-ckf-id\": \"x\", onClick: () => onClick() }, \"×\");\n\nconst dots = (step: number, steps: number) =>\n steps > 1\n ? h(\n \"span\",\n { className: \"ckf-dots\", role: \"img\", \"aria-label\": `Step ${step} of ${steps}` },\n ...Array.from({ length: steps }, (_, i) => h(\"span\", { className: \"ckf-dot\", \"data-on\": i < step })),\n )\n : h(\"span\");\n\n/** A key that changes when the screen (not just its state) changes: then focus moves to the new screen. */\nconst screenKey = (v: FlowView) =>\n v.type === \"cancel\" ? `c:${v.screen}:${v.round ?? 1}` : v.type === \"step\" ? `s:${v.step.id}` : v.type === \"checklist\" ? `l:${v.flow.id}` : `m:${v.message.id}`;\n\n/**\n * Draws the controller's view into the page until the returned function is called. One root element under <body>;\n * nothing is drawn while there is nothing to show.\n */\n/** The stylesheet once, and a themed root element under <body>. */\nconst rootFor = (theme: FlowsTheme) => {\n if (!document.getElementById(STYLE_ID)) {\n const style = document.createElement(\"style\");\n style.id = STYLE_ID;\n style.textContent = FLOWS_CSS;\n document.head.appendChild(style);\n }\n const root = h(\"div\", { className: `ckf-root${theme.className ? ` ${theme.className}` : \"\"}`, \"data-theme\": theme.theme ?? \"auto\" });\n if (theme.accent) root.style.setProperty(\"--ckf-accent\", theme.accent);\n document.body.appendChild(root);\n return root;\n};\n\n/** 0.18.0: an icon (a built-in line icon, an emoji or a picture) in a box of `className`; false when there is none. */\nconst iconEl = (icon: FlowIcon | undefined, className: string): HTMLElement | false => {\n const i = iconOf(icon);\n if (!i) return false;\n const box = h(\"span\", { className, \"aria-hidden\": \"true\" });\n if (i.kind === \"emoji\") box.textContent = i.value;\n else if (i.kind === \"image\") box.append(h(\"img\", { src: i.url, alt: \"\" }));\n else {\n const ns = \"http://www.w3.org/2000/svg\";\n const svg = document.createElementNS(ns, \"svg\");\n 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\" }))\n svg.setAttribute(k, v);\n for (const d of FLOW_ICONS[i.name].paths) {\n const p = document.createElementNS(ns, \"path\");\n p.setAttribute(\"d\", d);\n svg.append(p);\n }\n box.append(svg);\n }\n return box;\n};\n\nexport const mountFlows = (ctl: FlowsController, theme: FlowsTheme = {}): (() => void) => {\n if (typeof document === \"undefined\") return () => {};\n const root = rootFor(theme);\n /** 0.18.0: the finish animation last played, so each plays once. */\n let played = \"\";\n\n let lastKey = \"\";\n let returnFocus: HTMLElement | null = null;\n let comment = \"\";\n let placed: { float: HTMLElement; ring: HTMLElement; target: HTMLElement; side?: TourPlacement } | null = null;\n\n // ---------- Cancel flow ----------\n\n const cancelCard = (v: Extract<FlowView, { type: \"cancel\" }>) => {\n const titleId = \"ckf-title\";\n const busy = v.busy;\n const body: (Node | false)[] = [];\n if (v.screen === \"survey\") {\n body.push(\n h(\"h2\", { className: \"ckf-h\", id: titleId }, v.flow.question || \"Why are you leaving?\"),\n h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-labelledby\": titleId },\n ...v.flow.reasons.map((r) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt\",\n \"aria-checked\": String(v.reason === r.id),\n \"data-ckf-id\": `r:${r.id}`,\n onClick: () => ctl.cancel.pick(r.id),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n r.label,\n ),\n ),\n ),\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(\"Continue\", \"primary\", ctl.cancel.next, { disabled: !v.reason, id: \"go\" }),\n button(\"Never mind, keep my plan\", \"quiet\", ctl.cancel.close),\n ),\n );\n } else if (v.screen === \"followup\" && v.followUp) {\n const f = v.followUp;\n let field: Node;\n if (f.answers.length)\n field = h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-labelledby\": titleId },\n ...f.answers.map((a, i) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt\",\n \"aria-checked\": String(v.answer === a),\n \"data-ckf-id\": `a:${i}`,\n onClick: () => ctl.cancel.answer(a),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n a,\n ),\n ),\n );\n else {\n const text = h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"Your answer (optional)\",\n \"aria-labelledby\": titleId,\n maxlength: \"500\",\n \"data-ckf-id\": \"answer\",\n onInput: (e) => ctl.cancel.answer((e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement;\n text.value = v.answer ?? \"\";\n field = text;\n }\n const label = v.flow.reasons.find((r) => r.id === v.reason)?.label;\n body.push(\n label ? h(\"p\", { className: \"ckf-small\" }, `You said: ${label}`) : false,\n h(\"h2\", { className: \"ckf-h\", id: titleId }, f.question),\n field,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(\"Continue\", \"primary\", ctl.cancel.next, { id: \"go\" }),\n button(\"Never mind, keep my plan\", \"quiet\", ctl.cancel.close),\n ),\n );\n } else if (v.screen === \"offer\" && v.offer) {\n const o = v.offer;\n const label = v.flow.reasons.find((r) => r.id === v.reason)?.label;\n let detail: Node | false = false;\n if (o.kind === \"discount\" && o.percent)\n detail = v.price\n ? h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", { className: \"ckf-big\" }, money(discounted(v.price.amount, o.percent), v.price.currency)),\n h(\"span\", { className: \"ckf-strike\" }, money(v.price.amount, v.price.currency)),\n h(\n \"span\",\n { className: \"ckf-small\" },\n `/${v.price.interval ?? \"month\"}${o.months ? ` for ${o.months} ${o.months === 1 ? \"month\" : \"months\"}` : \"\"}`,\n ),\n )\n : h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", { className: \"ckf-big\" }, `${o.percent}% off`),\n o.months ? h(\"span\", { className: \"ckf-small\" }, `for ${o.months} ${o.months === 1 ? \"month\" : \"months\"}`) : false,\n );\n if (o.kind === \"pause\" && o.months)\n detail = h(\n \"div\",\n { className: \"ckf-box\" },\n h(\"span\", {}, `Pause for up to ${o.months} ${o.months === 1 ? \"month\" : \"months\"}. Your data stays.`),\n );\n if (o.kind === \"downgrade\" && o.planName) detail = h(\"div\", { className: \"ckf-box\" }, h(\"b\", {}, o.planName));\n const text =\n o.kind === \"contact\"\n ? (h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"What would make you stay?\",\n \"aria-label\": \"Your message\",\n maxlength: \"500\",\n \"data-ckf-id\": \"comment\",\n onInput: (e) => (comment = (e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement)\n : null;\n if (text) text.value = comment;\n body.push(\n label ? h(\"p\", { className: \"ckf-small\" }, `You said: ${label}`) : false,\n h(\"h2\", { className: \"ckf-h\", id: titleId }, o.headline),\n detail,\n text ?? false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(busy ? \"One moment…\" : offerButton(o), \"primary\", () => ctl.cancel.accept(comment), { disabled: busy, id: \"go\" }),\n button(\"No thanks, continue cancelling\", \"quiet\", ctl.cancel.decline, { disabled: busy }),\n ),\n );\n } else {\n const plain = v.steps === 1;\n const text = plain\n ? null\n : (h(\"textarea\", {\n className: \"ckf-text\",\n placeholder: \"Anything else we should know? (optional)\",\n \"aria-label\": \"Anything else we should know? (optional)\",\n maxlength: \"500\",\n \"data-ckf-id\": \"comment\",\n onInput: (e) => (comment = (e.target as HTMLTextAreaElement).value),\n }) as HTMLTextAreaElement);\n if (text) text.value = comment;\n body.push(\n h(\"h2\", { className: \"ckf-h\", id: titleId }, v.flow.confirm.title),\n v.flow.confirm.body ? h(\"p\", { className: \"ckf-p\" }, v.flow.confirm.body) : false,\n text ?? false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(busy ? \"One moment…\" : v.flow.confirm.button, \"danger\", () => ctl.cancel.confirm(comment), { disabled: busy, id: \"go\" }),\n button(\"Keep my plan\", \"secondary\", ctl.cancel.close, { disabled: busy }),\n ),\n );\n }\n return h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && !busy && ctl.cancel.close() },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": titleId },\n h(\"div\", { className: \"ckf-top\" }, dots(v.step, v.steps), closeButton(\"Close\", ctl.cancel.close)),\n ...body,\n v.error ? h(\"p\", { className: \"ckf-err\", role: \"alert\" }, v.error) : false,\n ),\n );\n };\n\n // ---------- Onboarding ----------\n\n /** 0.17.0: the step's picture or video above its text; a video link plays in its privacy-friendly player. */\n const media = (s: OnboardingStep) => {\n const m = mediaOf(s);\n if (!m) return false;\n if (m.kind === \"image\") return h(\"img\", { className: \"ckf-media\", src: m.url, alt: m.alt ?? \"\", onLoad: () => follow() });\n const v = videoEmbed(m.url)!;\n return v.kind === \"iframe\"\n ? h(\n \"div\",\n { className: \"ckf-video\" },\n h(\"iframe\", { src: v.src, title: m.alt || \"Video\", allow: \"fullscreen; picture-in-picture\", allowfullscreen: true, loading: \"lazy\", referrerpolicy: \"strict-origin-when-cross-origin\" }),\n )\n : h(\"video\", { className: \"ckf-media\", src: v.src, controls: true, playsinline: true, preload: \"metadata\", \"aria-label\": m.alt || undefined, onLoadedmetadata: () => follow() });\n };\n\n /** 0.18.0: one question of a Questions item: a slide with dots, the options or a text field, Back and Continue. */\n const questionCard = (v: Extract<FlowView, { type: \"step\" }>) => {\n const s = v.step;\n const q = s.question;\n const titleId = \"ckf-title\";\n const ok = answerOk(q, v.answer);\n let field: Node | false = false;\n if (q?.type === \"choice\")\n field = h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-labelledby\": titleId },\n ...(q.options ?? []).map((o) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt\",\n \"aria-checked\": String(v.answer === o.id),\n \"data-ckf-id\": `q:${o.id}`,\n onClick: () => ctl.onboarding.answer(o.id),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n o.label,\n ),\n ),\n );\n else if (q) {\n const input = h(\"input\", {\n type: \"text\",\n className: \"ckf-input\",\n placeholder: q.placeholder || \"Your answer\",\n \"aria-labelledby\": titleId,\n maxlength: \"500\",\n \"data-ckf-id\": \"answer\",\n onInput: (e) => ctl.onboarding.answer((e.target as HTMLInputElement).value),\n onKeydown: (e) => (e as KeyboardEvent).key === \"Enter\" && ctl.onboarding.next(),\n }) as HTMLInputElement;\n input.value = v.answer ?? \"\";\n field = input;\n }\n return h(\n \"div\",\n { className: \"ckf-scrim\" },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": titleId },\n h(\"div\", { className: \"ckf-top\" }, dots(v.index + 1, v.total), closeButton(\"Close\", ctl.onboarding.dismiss)),\n v.index === 0 ? iconEl(v.flow.icon, \"ckf-hic\") : false,\n h(\"h2\", { className: \"ckf-h\", id: titleId }, s.title),\n s.body ? h(\"p\", { className: \"ckf-p\" }, s.body) : false,\n field,\n h(\n \"div\",\n { className: \"ckf-row\" },\n v.back ? button(\"Back\", \"quiet\", ctl.onboarding.back) : false,\n button(s.button || (v.last ? \"Done\" : \"Continue\"), \"primary\", ctl.onboarding.next, { disabled: !ok, id: \"go\" }),\n ),\n ),\n );\n };\n\n const stepCard = (v: Extract<FlowView, { type: \"step\" }>) => {\n const s = v.step;\n if (s.kind === \"question\") return questionCard(v);\n const card = h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": s.kind === \"modal\" ? \"true\" : undefined, \"aria-labelledby\": \"ckf-title\" },\n h(\n \"div\",\n { className: \"ckf-top\" },\n v.total > 1 ? h(\"p\", { className: \"ckf-small\" }, `Step ${v.index + 1} of ${v.total}`) : h(\"span\"),\n closeButton(\"Close the tour\", ctl.onboarding.dismiss),\n ),\n s.kind === \"modal\" ? iconEl(v.flow.icon, \"ckf-hic\") : false,\n media(s),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, s.title),\n s.body ? h(\"p\", { className: \"ckf-p\" }, s.body) : false,\n h(\"div\", { className: \"ckf-row\" }, button(s.button || (v.last ? \"Done\" : \"Next\"), \"primary\", ctl.onboarding.next, { id: \"go\" })),\n );\n if (s.kind === \"modal\") return h(\"div\", { className: \"ckf-scrim\" }, card);\n const target = s.target ? findTarget(s.target) : null;\n const float = h(\"div\", { className: \"ckf-float\" }, card);\n if (target) {\n const ring = h(\"div\", { className: \"ckf-ring\", \"aria-hidden\": \"true\" });\n float.append(h(\"span\", { className: \"ckf-arrow\", \"aria-hidden\": \"true\" }));\n placed = { float, ring, target, side: s.placement };\n place(float, ring, target, s.placement);\n return h(\"div\", {}, ring, float);\n }\n return float;\n };\n\n /**\n * The element a tour step points at: a CSS selector (`#new-project`, `.toolbar button`, picked on the site in\n * MRRocket), or a plain name for `data-ck-target=\"…\"`. A selector that does not parse falls back to the name.\n */\n const findTarget = (t: string): HTMLElement | null => {\n const named = () => document.querySelector<HTMLElement>(`[data-ck-target=\"${CSS.escape(t)}\"]`);\n if (!/^[#.[]|[\\s>:=]/.test(t)) return named();\n return safeQuery(t) ?? named();\n };\n const safeQuery = (sel: string) => {\n try {\n return document.querySelector<HTMLElement>(sel);\n } catch {\n return null;\n }\n };\n\n /**\n * Puts a tour card next to the element it points at, on the step's side (0.17.0) or, on \"auto\", below it and above\n * when there is no room. A side without room flips to the opposite one, then to any side with room.\n */\n const place = (float: HTMLElement, ring: HTMLElement, target: HTMLElement, side: TourPlacement = \"auto\") => {\n const r = target.getBoundingClientRect();\n Object.assign(ring.style, { left: `${r.left - 4}px`, top: `${r.top - 4}px`, width: `${r.width + 8}px`, height: `${r.height + 8}px` });\n const vw = window.innerWidth;\n const vh = window.innerHeight;\n const w = Math.min(340, vw - 24);\n const ht = float.offsetHeight || 200;\n const gap = 14;\n const room: Record<string, boolean> = {\n bottom: vh - r.bottom - gap - 12 >= ht,\n top: r.top - gap - 12 >= ht,\n right: vw - r.right - gap - 12 >= w,\n left: r.left - gap - 12 >= w,\n };\n const flip: Record<string, string> = { top: \"bottom\", bottom: \"top\", left: \"right\", right: \"left\" };\n const order = side === \"auto\" || !flip[side] ? [\"bottom\", \"top\"] : [side, flip[side], \"bottom\", \"top\", \"right\", \"left\"];\n const s = order.find((x) => room[x]) ?? (side !== \"auto\" && flip[side] ? side : r.top > vh - r.bottom ? \"top\" : \"bottom\");\n const clamp = (v: number, hi: number) => Math.max(12, Math.min(v, hi - 12));\n const across = s === \"top\" || s === \"bottom\";\n // \"auto\" keeps the card's left edge at the element's, as before 0.17.0; a chosen side centres it.\n const left = across ? clamp(side === \"auto\" ? r.left : r.left + r.width / 2 - w / 2, vw - w) : s === \"right\" ? r.right + gap : r.left - gap - w;\n const top = across ? (s === \"bottom\" ? r.bottom + gap : r.top - gap - ht) : clamp(r.top + r.height / 2 - ht / 2, vh - ht);\n Object.assign(float.style, { left: `${left}px`, top: `${top}px`, right: \"auto\", bottom: \"auto\", width: `${w}px` });\n float.setAttribute(\"data-side\", s);\n // The arrow points at the element's middle, kept off the card's rounded corners.\n const at = across ? r.left + r.width / 2 - left : r.top + r.height / 2 - top;\n float.style.setProperty(\"--ckf-ap\", `${Math.max(18, Math.min(at, (across ? w : ht) - 18))}px`);\n };\n\n const checklist = (v: Extract<FlowView, { type: \"checklist\" }>) => {\n const done = v.items.filter((i) => i.done).length;\n return h(\n \"div\",\n { className: \"ckf-float\" },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"region\", \"aria-labelledby\": \"ckf-title\" },\n h(\n \"div\",\n { className: \"ckf-top\" },\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, v.flow.name),\n closeButton(\"Hide the checklist\", ctl.onboarding.dismiss),\n ),\n h(\"p\", { className: \"ckf-small\" }, `${done} of ${v.items.length} done`),\n h(\n \"div\",\n { className: \"ckf-bar\", role: \"progressbar\", \"aria-valuemin\": \"0\", \"aria-valuemax\": String(v.items.length), \"aria-valuenow\": String(done) },\n h(\"i\", { style: `width:${(done / v.items.length) * 100}%` } as Attrs),\n ),\n h(\n \"div\",\n { className: \"ckf-opts\" },\n ...v.items.map(({ step, done: d, opens }) => {\n const inner: (Node | false)[] = [\n h(\"span\", { className: \"ckf-tick\", \"aria-hidden\": \"true\" }, d ? \"✓\" : \"\"),\n iconEl(step.icon, \"ckf-ic\"),\n h(\"span\", {}, h(\"b\", {}, step.title), step.body ? h(\"span\", { className: \"ckf-small\" }, step.body) : false),\n ];\n // 0.17.0/0.18.0: a task that opens something (a tour, a modal, a page, the app's code) does it;\n // a finished tour or modal ticks it, a page or the app's code once opened (unless an event does).\n if (!d && opens)\n return h(\n \"button\",\n {\n type: \"button\",\n className: \"ckf-check\",\n \"aria-label\": `Start “${step.title}”`,\n \"data-ckf-id\": `t:${step.id}`,\n onClick: () => ctl.onboarding.open(step.id),\n },\n ...inner,\n h(\"span\", { className: \"ckf-go\", \"aria-hidden\": \"true\" }, \"›\"),\n );\n // An item with an event ticks itself when the app records it; the others are ticked by hand.\n return d || step.event\n ? h(\"div\", { className: \"ckf-check\", \"data-done\": d, role: \"listitem\" }, ...inner)\n : h(\n \"button\",\n {\n type: \"button\",\n className: \"ckf-check\",\n \"aria-label\": `Mark “${step.title}” done`,\n \"data-ckf-id\": `i:${step.id}`,\n onClick: () => ctl.onboarding.check(step.id),\n },\n ...inner,\n );\n }),\n ),\n ),\n );\n };\n\n // ---------- Messages ----------\n\n const message = (v: Extract<FlowView, { type: \"message\" }>) => {\n const m = v.message;\n const action = m.button ? button(m.button, \"primary\", ctl.message.click, { id: \"go\" }) : false;\n if (m.style === \"banner\")\n return h(\n \"div\",\n { className: \"ckf-banner\", role: \"status\" },\n h(\"span\", {}, h(\"b\", {}, m.title), m.body ? h(\"span\", { className: \"ckf-small\" }, m.body) : false),\n action,\n closeButton(\"Dismiss\", ctl.message.dismiss),\n );\n return h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && ctl.message.dismiss() },\n h(\n \"div\",\n { className: \"ckf-card\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"ckf-title\" },\n h(\"div\", { className: \"ckf-top\" }, h(\"span\"), closeButton(\"Dismiss\", ctl.message.dismiss)),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, m.title),\n m.body ? h(\"p\", { className: \"ckf-p\" }, m.body) : false,\n action ? h(\"div\", { className: \"ckf-row\" }, action) : false,\n ),\n );\n };\n\n // ---------- Drawing ----------\n\n const draw = () => {\n const v = ctl.view();\n // 0.18.0: the product's brand color from MRRocket, unless the site set an accent of its own.\n const accent = theme.accent ?? ctl.accent?.();\n if (accent) root.style.setProperty(\"--ckf-accent\", accent);\n // 0.18.0: someone just finished a checklist, a tour or the questions.\n const fin = ctl.finale?.();\n if (fin && fin.key !== played) {\n played = fin.key;\n playFinish(fin.kind, { accent });\n }\n const key = v ? screenKey(v) : \"\";\n const focused = (document.activeElement as HTMLElement | null)?.closest?.(\".ckf-root\") ? document.activeElement?.getAttribute(\"data-ckf-id\") : null;\n if (key && !lastKey && document.activeElement instanceof HTMLElement && !document.activeElement.closest(\".ckf-root\"))\n returnFocus = document.activeElement;\n if (key !== lastKey && !key.startsWith(\"c:\")) comment = \"\";\n if (!key) comment = \"\";\n placed = null;\n root.replaceChildren(\n ...(v ? [v.type === \"cancel\" ? cancelCard(v) : v.type === \"step\" ? stepCard(v) : v.type === \"checklist\" ? checklist(v) : message(v)] : []),\n );\n // Placed again now that the card is in the page and has its real height.\n follow();\n if (key !== lastKey) {\n // A new screen: focus its first control (a dialog's), so keyboard and screen reader users land in it.\n const modal = root.querySelector<HTMLElement>(\"[aria-modal=true]\");\n const first = modal?.querySelector<HTMLElement>(\"[role=radio], input, [data-ckf-id=go], textarea\") ?? null;\n first?.focus();\n if (!key && returnFocus) {\n returnFocus.focus();\n returnFocus = null;\n }\n } else if (focused) root.querySelector<HTMLElement>(`[data-ckf-id=\"${CSS.escape(focused)}\"]`)?.focus();\n lastKey = key;\n };\n\n const onKey = (e: KeyboardEvent) => {\n if (e.key !== \"Escape\") return;\n const v = ctl.view();\n if (v?.type === \"cancel\") ctl.cancel.close();\n else if (v?.type === \"message\") ctl.message.dismiss();\n else if (v?.type === \"step\" && (v.step.kind === \"modal\" || v.step.kind === \"question\")) ctl.onboarding.dismiss();\n };\n // A tour card follows its element when the page scrolls or resizes.\n function follow() {\n if (placed) place(placed.float, placed.ring, placed.target, placed.side);\n }\n document.addEventListener(\"keydown\", onKey);\n window.addEventListener(\"resize\", follow);\n window.addEventListener(\"scroll\", follow, { passive: true, capture: true });\n const off = ctl.subscribe(draw);\n draw();\n return () => {\n off();\n document.removeEventListener(\"keydown\", onKey);\n window.removeEventListener(\"resize\", follow);\n window.removeEventListener(\"scroll\", follow, { capture: true });\n root.remove();\n };\n};\n\n/**\n * Draws an open paywall (paywall.ts) page by page until the returned function is called: the dots, the page's title and\n * text, its benefits, quotes or plans, Back and the button. Closes on Escape and on a click beside the card.\n */\nexport const mountPaywall = (host: PaywallHost, theme: FlowsTheme = {}): (() => void) => {\n if (typeof document === \"undefined\") return () => {};\n const root = rootFor(theme);\n let lastKey = \"\";\n let returnFocus: HTMLElement | null = null;\n const draw = () => {\n const v = host.view();\n const key = v ? `${v.paywall.id}:${v.index}` : \"\";\n if (key && !lastKey && document.activeElement instanceof HTMLElement) returnFocus = document.activeElement;\n if (!v) {\n root.replaceChildren();\n root.removeAttribute(\"data-still\");\n if (lastKey) returnFocus?.focus();\n lastKey = \"\";\n return;\n }\n // Fades in when it opens, not again on every page or plan.\n if (lastKey) root.setAttribute(\"data-still\", \"\");\n const p = v.page;\n const plans =\n p.kind === \"plans\"\n ? h(\n \"div\",\n { className: \"ckf-opts\", role: \"radiogroup\", \"aria-label\": \"Plans\" },\n ...v.plans.map((plan) =>\n h(\n \"button\",\n {\n type: \"button\",\n role: \"radio\",\n className: \"ckf-opt ckf-plan\",\n \"aria-checked\": String(v.plan === plan.id),\n \"data-ckf-id\": `p:${plan.id}`,\n onClick: () => host.pick(plan.id),\n },\n h(\"span\", { className: \"ckf-radio\" }),\n h(\"span\", {}, plan.name, plan.note ? h(\"span\", { className: \"ckf-small\" }, plan.note) : false),\n h(\"b\", {}, plan.price),\n ),\n ),\n )\n : false;\n root.replaceChildren(\n h(\n \"div\",\n { className: \"ckf-scrim\", onClick: (e) => e.target === e.currentTarget && host.close() },\n h(\n \"div\",\n { className: \"ckf-card ckf-pw\", role: \"dialog\", \"aria-modal\": \"true\", \"aria-labelledby\": \"ckf-title\" },\n h(\"div\", { className: \"ckf-top\" }, dots(v.index + 1, v.total), closeButton(\"Close\", host.close)),\n h(\"h2\", { className: \"ckf-h\", id: \"ckf-title\" }, p.title),\n p.body ? h(\"p\", { className: \"ckf-p\" }, p.body) : false,\n p.kind === \"benefits\" && p.items?.length ? h(\"div\", { className: \"ckf-opts\" }, ...p.items.map((i) => h(\"p\", { className: \"ckf-li\" }, i))) : false,\n p.kind === \"proof\" && p.quotes?.length\n ? h(\"div\", { className: \"ckf-opts\" }, ...p.quotes.map((q) => h(\"blockquote\", { className: \"ckf-quote\" }, q.text, q.by ? h(\"cite\", {}, q.by) : false)))\n : false,\n plans,\n v.error ? h(\"p\", { className: \"ckf-err\", role: \"alert\" }, v.error) : false,\n h(\n \"div\",\n { className: \"ckf-btns\" },\n button(v.busy ? \"One moment…\" : p.button || \"Continue\", \"primary\", host.next, {\n disabled: v.busy || (p.kind === \"plans\" && !v.plan),\n id: \"go\",\n }),\n v.index ? button(\"Back\", \"quiet\", host.back, { disabled: v.busy }) : false,\n ),\n ),\n ),\n );\n if (key !== lastKey) root.querySelector<HTMLElement>(\"[data-ckf-id=go]\")?.focus();\n lastKey = key;\n };\n const onKey = (e: KeyboardEvent) => {\n if (!host.view()) return;\n if (e.key === \"Escape\") host.close();\n };\n document.addEventListener(\"keydown\", onKey);\n const off = host.subscribe(draw);\n draw();\n return () => {\n off();\n document.removeEventListener(\"keydown\", onKey);\n root.remove();\n };\n};\n"],"mappings":"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","names":[]}
@@ -3,7 +3,7 @@
3
3
  * person's messages and onboarding progress from `GET /api/sdk/inapp`, progress kept in localStorage only while the
4
4
  * consent is "cookies", and links opened in the same tab. Plain functions; only called in the browser.
5
5
  */
6
- import type { FlowsEnv } from "./flows.js";
6
+ import { type FlowsEnv, type OnboardingFlow } from "./flows.js";
7
7
  export interface WebFlowsOptions {
8
8
  host: string;
9
9
  apiKey: string;
@@ -15,6 +15,13 @@ export interface WebFlowsOptions {
15
15
  /** True while the consent is "cookies": progress may be kept in localStorage. */
16
16
  canStore: () => boolean;
17
17
  auto?: boolean;
18
+ /**
19
+ * 0.18.0: the app's own way to open a checklist task's page or screen (a single-page app's router). Without it a
20
+ * path or an http(s) address opens in the same tab; anything else is not opened.
21
+ */
22
+ onNavigate?: () => ((target: string) => void) | undefined;
23
+ /** 0.18.0: a checklist task that runs the app's own code. */
24
+ onTask?: () => ((taskId: string, item: OnboardingFlow) => void) | undefined;
18
25
  }
19
26
  /** Removes what the flows kept in localStorage (consent withdrawn). */
20
27
  export declare const forgetFlowsStorage: () => void;
package/dist/flows-web.js CHANGED
@@ -1,4 +1,5 @@
1
1
  // src/flows-web.ts
2
+ import { safeUrl } from "./flows.js";
2
3
  import { warnUnsigned } from "./identity.js";
3
4
  var local = {
4
5
  get: (key) => {
@@ -31,6 +32,13 @@ var webFlowsEnv = (o) => ({
31
32
  storage: () => o.canStore() ? local : null,
32
33
  openUrl: (url) => window.location.assign(url),
33
34
  path: () => window.location.pathname,
35
+ navigate: (target) => {
36
+ const own = o.onNavigate?.();
37
+ if (own) return own(target);
38
+ const url = safeUrl(target);
39
+ if (url) window.location.assign(url);
40
+ },
41
+ task: (taskId, item) => o.onTask?.()?.(taskId, item),
34
42
  fetchInApp: async (id) => {
35
43
  if (!o.apiKey) return null;
36
44
  const hash = o.userHash?.(id);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/flows-web.ts"],"sourcesContent":["/**\n * What the flows controller (flows.ts) needs in a browser, shared by the Next.js provider and the script tag: the\n * person's messages and onboarding progress from `GET /api/sdk/inapp`, progress kept in localStorage only while the\n * consent is \"cookies\", and links opened in the same tab. Plain functions; only called in the browser.\n */\nimport type { FlowsEnv, InAppState } from \"./flows\";\nimport { warnUnsigned } from \"./identity\";\n\nexport interface WebFlowsOptions {\n host: string;\n apiKey: string;\n track: FlowsEnv[\"track\"];\n /** The identify() id while tracking is allowed; undefined otherwise (no messages, no stored progress then). */\n personId: () => string | undefined;\n /** The identity hash of that person (0.16.0), when the site gave one to identify. */\n userHash?: (id: string) => string | undefined;\n /** True while the consent is \"cookies\": progress may be kept in localStorage. */\n canStore: () => boolean;\n auto?: boolean;\n}\n\nconst local = {\n get: (key: string) => {\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n set: (key: string, value: string) => {\n try {\n window.localStorage.setItem(key, value);\n } catch {\n // Private mode or full: progress stays in memory.\n }\n },\n};\n\n/** Removes what the flows kept in localStorage (consent withdrawn). */\nexport const forgetFlowsStorage = () => {\n try {\n for (let i = window.localStorage.length - 1; i >= 0; i--) {\n const key = window.localStorage.key(i);\n if (key?.startsWith(\"mrrocket:onboarding\")) window.localStorage.removeItem(key);\n }\n } catch {\n // No storage: nothing to delete.\n }\n};\n\nexport const webFlowsEnv = (o: WebFlowsOptions): FlowsEnv => ({\n track: o.track,\n personId: o.personId,\n auto: o.auto,\n storage: () => (o.canStore() ? local : null),\n openUrl: (url) => window.location.assign(url),\n path: () => window.location.pathname,\n fetchInApp: async (id) => {\n if (!o.apiKey) return null;\n const hash = o.userHash?.(id);\n const r = await fetch(`${o.host}/api/sdk/inapp?key=${encodeURIComponent(o.apiKey)}&distinctId=${encodeURIComponent(id)}${hash ? `&userHash=${hash}` : \"\"}`);\n warnUnsigned(r.status);\n return r.ok ? ((await r.json()) as InAppState) : null;\n },\n});\n"],"mappings":";AAMA,SAAS,oBAAoB;AAe7B,IAAM,QAAQ;AAAA,EACV,KAAK,CAAC,QAAgB;AAClB,QAAI;AACA,aAAO,OAAO,aAAa,QAAQ,GAAG;AAAA,IAC1C,QAAQ;AACJ,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EACA,KAAK,CAAC,KAAa,UAAkB;AACjC,QAAI;AACA,aAAO,aAAa,QAAQ,KAAK,KAAK;AAAA,IAC1C,QAAQ;AAAA,IAER;AAAA,EACJ;AACJ;AAGO,IAAM,qBAAqB,MAAM;AACpC,MAAI;AACA,aAAS,IAAI,OAAO,aAAa,SAAS,GAAG,KAAK,GAAG,KAAK;AACtD,YAAM,MAAM,OAAO,aAAa,IAAI,CAAC;AACrC,UAAI,KAAK,WAAW,qBAAqB,EAAG,QAAO,aAAa,WAAW,GAAG;AAAA,IAClF;AAAA,EACJ,QAAQ;AAAA,EAER;AACJ;AAEO,IAAM,cAAc,CAAC,OAAkC;AAAA,EAC1D,OAAO,EAAE;AAAA,EACT,UAAU,EAAE;AAAA,EACZ,MAAM,EAAE;AAAA,EACR,SAAS,MAAO,EAAE,SAAS,IAAI,QAAQ;AAAA,EACvC,SAAS,CAAC,QAAQ,OAAO,SAAS,OAAO,GAAG;AAAA,EAC5C,MAAM,MAAM,OAAO,SAAS;AAAA,EAC5B,YAAY,OAAO,OAAO;AACtB,QAAI,CAAC,EAAE,OAAQ,QAAO;AACtB,UAAM,OAAO,EAAE,WAAW,EAAE;AAC5B,UAAM,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,sBAAsB,mBAAmB,EAAE,MAAM,CAAC,eAAe,mBAAmB,EAAE,CAAC,GAAG,OAAO,aAAa,IAAI,KAAK,EAAE,EAAE;AAC1J,iBAAa,EAAE,MAAM;AACrB,WAAO,EAAE,KAAO,MAAM,EAAE,KAAK,IAAoB;AAAA,EACrD;AACJ;","names":[]}
1
+ {"version":3,"sources":["../src/flows-web.ts"],"sourcesContent":["/**\n * What the flows controller (flows.ts) needs in a browser, shared by the Next.js provider and the script tag: the\n * person's messages and onboarding progress from `GET /api/sdk/inapp`, progress kept in localStorage only while the\n * consent is \"cookies\", and links opened in the same tab. Plain functions; only called in the browser.\n */\nimport { type FlowsEnv, type InAppState, type OnboardingFlow, safeUrl } from \"./flows\";\nimport { warnUnsigned } from \"./identity\";\n\nexport interface WebFlowsOptions {\n host: string;\n apiKey: string;\n track: FlowsEnv[\"track\"];\n /** The identify() id while tracking is allowed; undefined otherwise (no messages, no stored progress then). */\n personId: () => string | undefined;\n /** The identity hash of that person (0.16.0), when the site gave one to identify. */\n userHash?: (id: string) => string | undefined;\n /** True while the consent is \"cookies\": progress may be kept in localStorage. */\n canStore: () => boolean;\n auto?: boolean;\n /**\n * 0.18.0: the app's own way to open a checklist task's page or screen (a single-page app's router). Without it a\n * path or an http(s) address opens in the same tab; anything else is not opened.\n */\n onNavigate?: () => ((target: string) => void) | undefined;\n /** 0.18.0: a checklist task that runs the app's own code. */\n onTask?: () => ((taskId: string, item: OnboardingFlow) => void) | undefined;\n}\n\nconst local = {\n get: (key: string) => {\n try {\n return window.localStorage.getItem(key);\n } catch {\n return null;\n }\n },\n set: (key: string, value: string) => {\n try {\n window.localStorage.setItem(key, value);\n } catch {\n // Private mode or full: progress stays in memory.\n }\n },\n};\n\n/** Removes what the flows kept in localStorage (consent withdrawn). */\nexport const forgetFlowsStorage = () => {\n try {\n for (let i = window.localStorage.length - 1; i >= 0; i--) {\n const key = window.localStorage.key(i);\n if (key?.startsWith(\"mrrocket:onboarding\")) window.localStorage.removeItem(key);\n }\n } catch {\n // No storage: nothing to delete.\n }\n};\n\nexport const webFlowsEnv = (o: WebFlowsOptions): FlowsEnv => ({\n track: o.track,\n personId: o.personId,\n auto: o.auto,\n storage: () => (o.canStore() ? local : null),\n openUrl: (url) => window.location.assign(url),\n path: () => window.location.pathname,\n navigate: (target) => {\n const own = o.onNavigate?.();\n if (own) return own(target);\n const url = safeUrl(target);\n if (url) window.location.assign(url);\n },\n task: (taskId, item) => o.onTask?.()?.(taskId, item),\n fetchInApp: async (id) => {\n if (!o.apiKey) return null;\n const hash = o.userHash?.(id);\n const r = await fetch(`${o.host}/api/sdk/inapp?key=${encodeURIComponent(o.apiKey)}&distinctId=${encodeURIComponent(id)}${hash ? `&userHash=${hash}` : \"\"}`);\n warnUnsigned(r.status);\n return r.ok ? ((await r.json()) as InAppState) : null;\n },\n});\n"],"mappings":";AAKA,SAA8D,eAAe;AAC7E,SAAS,oBAAoB;AAsB7B,IAAM,QAAQ;AAAA,EACV,KAAK,CAAC,QAAgB;AAClB,QAAI;AACA,aAAO,OAAO,aAAa,QAAQ,GAAG;AAAA,IAC1C,QAAQ;AACJ,aAAO;AAAA,IACX;AAAA,EACJ;AAAA,EACA,KAAK,CAAC,KAAa,UAAkB;AACjC,QAAI;AACA,aAAO,aAAa,QAAQ,KAAK,KAAK;AAAA,IAC1C,QAAQ;AAAA,IAER;AAAA,EACJ;AACJ;AAGO,IAAM,qBAAqB,MAAM;AACpC,MAAI;AACA,aAAS,IAAI,OAAO,aAAa,SAAS,GAAG,KAAK,GAAG,KAAK;AACtD,YAAM,MAAM,OAAO,aAAa,IAAI,CAAC;AACrC,UAAI,KAAK,WAAW,qBAAqB,EAAG,QAAO,aAAa,WAAW,GAAG;AAAA,IAClF;AAAA,EACJ,QAAQ;AAAA,EAER;AACJ;AAEO,IAAM,cAAc,CAAC,OAAkC;AAAA,EAC1D,OAAO,EAAE;AAAA,EACT,UAAU,EAAE;AAAA,EACZ,MAAM,EAAE;AAAA,EACR,SAAS,MAAO,EAAE,SAAS,IAAI,QAAQ;AAAA,EACvC,SAAS,CAAC,QAAQ,OAAO,SAAS,OAAO,GAAG;AAAA,EAC5C,MAAM,MAAM,OAAO,SAAS;AAAA,EAC5B,UAAU,CAAC,WAAW;AAClB,UAAM,MAAM,EAAE,aAAa;AAC3B,QAAI,IAAK,QAAO,IAAI,MAAM;AAC1B,UAAM,MAAM,QAAQ,MAAM;AAC1B,QAAI,IAAK,QAAO,SAAS,OAAO,GAAG;AAAA,EACvC;AAAA,EACA,MAAM,CAAC,QAAQ,SAAS,EAAE,SAAS,IAAI,QAAQ,IAAI;AAAA,EACnD,YAAY,OAAO,OAAO;AACtB,QAAI,CAAC,EAAE,OAAQ,QAAO;AACtB,UAAM,OAAO,EAAE,WAAW,EAAE;AAC5B,UAAM,IAAI,MAAM,MAAM,GAAG,EAAE,IAAI,sBAAsB,mBAAmB,EAAE,MAAM,CAAC,eAAe,mBAAmB,EAAE,CAAC,GAAG,OAAO,aAAa,IAAI,KAAK,EAAE,EAAE;AAC1J,iBAAa,EAAE,MAAM;AACrB,WAAO,EAAE,KAAO,MAAM,EAAE,KAAK,IAAoB;AAAA,EACrD;AACJ;","names":[]}
package/dist/flows.d.ts CHANGED
@@ -12,7 +12,9 @@
12
12
  * - `$onboarding` `{flow, step?, action: "started" | "shown" | "completed" | "dismissed"}`; since 0.11.0 a wait records
13
13
  * "shown" when the person reaches it and "completed" when it is over, a condition `{action: "answered", answer: "yes"
14
14
  * | "no"}` once it is decided; since 0.17.0 a tour a checklist task started records `{action: "started", from}` with
15
- * the checklist's id.
15
+ * the checklist's id; since 0.18.0 a question records `{kind: "question", action: "completed", question, answer,
16
+ * label}` (the question's key, the option's id or the typed text, the option's words), which MRRocket keeps on the
17
+ * contact, and a checklist task that opens something `{action: "opened", opens}`.
16
18
  * - `$inapp` `{message, journey, action: "shown" | "clicked" | "dismissed"}`; the journey moves the person on.
17
19
  */
18
20
  import type { CockpitConfig } from "./core.js";
@@ -86,7 +88,54 @@ export interface CancelFlowConfig {
86
88
  */
87
89
  offersFor: "business";
88
90
  }
89
- export type OnboardingStepKind = "tour" | "checklist" | "modal";
91
+ /** "question" (0.18.0): one question of a Questions item, a slide of its window. */
92
+ export type OnboardingStepKind = "tour" | "checklist" | "modal" | "question";
93
+ /**
94
+ * 0.18.0: what a checklist task opens. `page`: a path or address on the web, a deep link (`myapp://…`) or a screen name
95
+ * in an app, handed to the app's `onNavigate` when it passes one; `tour` / `modal`: another item of the config, after
96
+ * which the checklist comes back; `code`: the app's `onTask(taskId, item)`.
97
+ */
98
+ export type TaskOpens = {
99
+ kind: "page";
100
+ target: string;
101
+ } | {
102
+ kind: "tour";
103
+ id: string;
104
+ } | {
105
+ kind: "modal";
106
+ id: string;
107
+ } | {
108
+ kind: "code";
109
+ };
110
+ /**
111
+ * 0.18.0: a small picture beside a checklist task or above a modal's or the questions' heading: one of the SDK's own
112
+ * line icons (`FLOW_ICON_NAMES`, icons.ts), an emoji, or a picture (http(s)).
113
+ */
114
+ export type FlowIcon = {
115
+ kind: "builtin";
116
+ name: string;
117
+ } | {
118
+ kind: "emoji";
119
+ value: string;
120
+ } | {
121
+ kind: "image";
122
+ url: string;
123
+ };
124
+ /** 0.18.0: what plays when someone finishes a checklist, a tour or the questions. */
125
+ export type FinishAnimation = "none" | "confetti" | "fireworks" | "stars";
126
+ /** 0.18.0: one question of a Questions item: one choice of 2 to 6 options, or a short text. */
127
+ export interface OnboardingQuestion {
128
+ /** The answer's name on the contact (`onboarding.<key>`) and in "People who answered …". */
129
+ key: string;
130
+ type: "choice" | "text";
131
+ /** Choice: the options, in order; `id` is what is stored, `label` what people read. */
132
+ options?: {
133
+ id: string;
134
+ label: string;
135
+ }[];
136
+ /** Text: the field's hint. */
137
+ placeholder?: string;
138
+ }
90
139
  /** 0.17.0: where a tour bubble sits next to its element; "auto" (and no value) puts it below, else above, as before. */
91
140
  export type TourPlacement = "auto" | "top" | "bottom" | "left" | "right";
92
141
  /**
@@ -116,6 +165,12 @@ export interface OnboardingStep {
116
165
  url?: string;
117
166
  /** 0.17.0, checklist items: the id of a tour (another flow) the item starts; finishing the tour ticks the item. */
118
167
  startsTour?: string;
168
+ /** 0.18.0, checklist items: what the task opens (read before `startsTour`, which MRRocket still sends for a tour). */
169
+ opens?: TaskOpens;
170
+ /** 0.18.0, checklist items: the task's icon. */
171
+ icon?: FlowIcon;
172
+ /** 0.18.0, question steps: the question (the step's `title` is what people read). */
173
+ question?: OnboardingQuestion;
119
174
  }
120
175
  /** A pause in a flow (0.11.0): the next step shows this long after the one before was done. */
121
176
  export interface OnboardingWait {
@@ -148,10 +203,33 @@ export interface OnboardingFlow {
148
203
  * of the app ("/settings", "/projects/*"), or "From a checklist" (only a checklist task starts it).
149
204
  */
150
205
  trigger: string;
151
- /** 0.17.0: "signed_in" starts it on its own only for someone the app identified. */
152
- audience?: "signed_in";
206
+ /**
207
+ * 0.17.0: "signed_in" starts it on its own only for someone the app identified. 0.18.0: "answered" only for someone
208
+ * who gave `answered.option` to the question `answered.question` (its key).
209
+ */
210
+ audience?: "signed_in" | "answered";
211
+ /** 0.18.0: with `audience: "answered"`, the question's key and the option's id (or the typed text). */
212
+ answered?: {
213
+ question: string;
214
+ option: string;
215
+ };
153
216
  /** What every version shows: with `nodes`, only the in-app steps before the first wait or condition. */
154
217
  steps: OnboardingStep[];
218
+ /** 0.18.0: the icon above a modal's or the questions' heading. */
219
+ icon?: FlowIcon;
220
+ /** 0.18.0: what plays when the person finishes it (a checklist, a tour, the questions). */
221
+ finish?: FinishAnimation;
222
+ /**
223
+ * 0.18.0: "code": the app draws it itself (`useOnboarding(id)`, `mrrocket.onboarding.get(id)`); the SDK draws
224
+ * nothing for it, never starts it, and still records what the app reports. Such an item's `trigger` is
225
+ * "From your code" (older versions never start it).
226
+ */
227
+ shownBy?: "code";
228
+ /**
229
+ * 0.18.0: the item's real moment (read instead of `trigger`, see `momentOf`) when `trigger` is one older versions
230
+ * never start: "From your code", or `NEEDS_NEWER` for questions and items that follow another or ask for an answer.
231
+ */
232
+ when?: string;
155
233
  /** 0.11.0+: the whole flow with its waits and conditions. Read instead of `steps` when it is there. */
156
234
  nodes?: OnboardingNode[];
157
235
  }
@@ -183,6 +261,8 @@ export interface InAppState {
183
261
  messages: InAppMessage[];
184
262
  /** 0.11.0: the events the flows' conditions ask about that this person did (as `eventSlug`s). */
185
263
  events?: string[];
264
+ /** 0.18.0: the person's answers to onboarding questions, by the question's key (an option's id or the text). */
265
+ answers?: Record<string, string>;
186
266
  /**
187
267
  * 0.16.0: a live review request may ask this person now. The React Native client's `requestReview()` opens the
188
268
  * store's own rating dialog (expo-store-review) and reports `$review_prompt`; websites have no store dialog.
@@ -247,15 +327,22 @@ export type FlowView = {
247
327
  /** The step for the dots, 1 to `steps`. */
248
328
  step: number;
249
329
  steps: number;
250
- } | {
330
+ }
331
+ /** `answer` (0.18.0): a question's answer so far (an option's id or the typed text); `back`: an earlier question to go back to. */
332
+ | {
251
333
  type: "step";
252
334
  flow: OnboardingFlow;
253
335
  step: OnboardingStep;
254
336
  index: number;
255
337
  total: number;
256
338
  last: boolean;
339
+ answer?: string;
340
+ back?: boolean;
257
341
  }
258
- /** `tour`: the tour the item starts (0.17.0), when the config has it. */
342
+ /**
343
+ * `tour`: the tour the item starts (0.17.0), when the config has it. `opens` (0.18.0): what tapping the task opens
344
+ * (a tour or modal only when the config has it); `target` the item it opens.
345
+ */
259
346
  | {
260
347
  type: "checklist";
261
348
  flow: OnboardingFlow;
@@ -263,6 +350,8 @@ export type FlowView = {
263
350
  step: OnboardingStep;
264
351
  done: boolean;
265
352
  tour?: OnboardingFlow;
353
+ opens?: TaskOpens;
354
+ target?: OnboardingFlow;
266
355
  }[];
267
356
  } | {
268
357
  type: "message";
@@ -286,6 +375,13 @@ export interface FlowsEnv {
286
375
  auto?: boolean;
287
376
  /** The page the person is on (a path), for "Is on <page>?" conditions; without it they answer no. */
288
377
  path?: () => string | undefined;
378
+ /**
379
+ * 0.18.0: opens what a checklist task's "page or screen" names (a path, an address, a deep link, a screen name).
380
+ * The web and React Native clients pass the app's `onNavigate`, else their own default.
381
+ */
382
+ navigate?: (target: string) => void;
383
+ /** 0.18.0: a checklist task that runs the app's own code (`onTask(taskId, item)`). */
384
+ task?: (taskId: string, item: OnboardingFlow) => void;
289
385
  /** The clock, for tests. */
290
386
  now?: () => number;
291
387
  }
@@ -311,17 +407,54 @@ export interface FlowsController {
311
407
  confirm(comment?: string): void;
312
408
  close(): void;
313
409
  };
314
- /** `startTour(stepId)` (0.17.0): the tour a checklist item starts; the checklist comes back when it ends. */
410
+ /**
411
+ * `startTour(stepId)` (0.17.0): the tour a checklist item starts; the checklist comes back when it ends.
412
+ * 0.18.0: `open(stepId)` does what the task opens (a page, a tour, a modal, the app's code); `answer(value)` picks an
413
+ * option or types the text of the question on screen, `back()` returns to the question before. `item(id)` and the
414
+ * calls after it are for an item the app draws itself (`shownBy: "code"`).
415
+ */
315
416
  onboarding: {
316
417
  next(): void;
317
418
  check(stepId: string): void;
318
419
  dismiss(): void;
319
420
  startTour(stepId: string): boolean;
421
+ open(stepId: string): boolean;
422
+ answer(value: string): void;
423
+ back(): void;
424
+ item(id: string): OnboardingItemState | null;
425
+ seen(id: string): void;
426
+ complete(id: string, stepId: string): void;
427
+ dismissItem(id: string): void;
428
+ answerItem(id: string, question: string, value: string): void;
320
429
  };
321
430
  message: {
322
431
  click(): void;
323
432
  dismiss(): void;
324
433
  };
434
+ /** 0.18.0: the animation to play now that someone finished an item (a new `key` each time), or null. */
435
+ finale(): {
436
+ kind: Exclude<FinishAnimation, "none">;
437
+ key: string;
438
+ } | null;
439
+ /** 0.18.0: the product's brand color from MRRocket, for the dialogs when the app passes no accent of its own. */
440
+ accent(): string | undefined;
441
+ /** 0.18.0: the person's answers to onboarding questions, by key. */
442
+ answers(): Record<string, string>;
443
+ }
444
+ /** 0.18.0: an item the app draws itself (`shownBy: "code"`), with the person's progress. */
445
+ export interface OnboardingItemState {
446
+ item: OnboardingFlow;
447
+ /** Its steps (a tour's steps, a checklist's tasks, the questions), each with whether the person did it. */
448
+ steps: (OnboardingStep & {
449
+ done: boolean;
450
+ answer?: string;
451
+ })[];
452
+ /** Every step is done. */
453
+ done: boolean;
454
+ /** The person closed it. */
455
+ dismissed: boolean;
456
+ /** Its moment has come for this person (the trigger MRRocket set, and who it is for); your code may ignore it. */
457
+ eligible: boolean;
325
458
  }
326
459
  /** The plain confirmation, when the product has no live cancel flow (or MRRocket was not reachable). */
327
460
  export declare const PLAIN_CANCEL: CancelFlowConfig;
@@ -335,6 +468,25 @@ export declare const startsOnLoad: (trigger: string) => boolean;
335
468
  export declare const FROM_CHECKLIST = "From a checklist";
336
469
  /** 0.17.0: a trigger that is a page of the app ("/settings", "/projects/*"): the flow starts when the person opens it. */
337
470
  export declare const isPageTrigger: (trigger: string) => boolean;
471
+ /** 0.18.0: the trigger of an item the app draws itself (`shownBy: "code"`); older versions never start it. */
472
+ export declare const FROM_CODE = "From your code";
473
+ /**
474
+ * 0.18.0: the trigger MRRocket sends for an item older versions could not show right (questions, "After <item> ends",
475
+ * "People who answered …"), so they never start it; its real moment is in `when`.
476
+ */
477
+ export declare const NEEDS_NEWER = "Needs tracking code 0.18.0";
478
+ /** An item's moment: `when` (0.18.0) where MRRocket sent one, else its trigger. */
479
+ export declare const momentOf: (f: Pick<OnboardingFlow, "trigger" | "when">) => string;
480
+ /** 0.18.0: the trigger "after:<item id>": the item starts once that item ended (finished or closed). */
481
+ export declare const AFTER_PREFIX = "after:";
482
+ /** The item an "after:<id>" trigger follows, or null. */
483
+ export declare const afterOf: (trigger: string | undefined) => string | null;
484
+ /** 0.18.0: what a task opens; a 0.17.0 `startsTour` reads as opening that tour. */
485
+ export declare const opensOf: (step: Pick<OnboardingStep, "opens" | "startsTour">) => TaskOpens | undefined;
486
+ /** 0.18.0: a usable answer to a question: one of its options' ids, or a text of 1 to 500 characters. */
487
+ export declare const answerOk: (q: OnboardingQuestion | undefined, value: string | undefined) => boolean;
488
+ /** The option's words for an answer (a text answer is its own words). */
489
+ export declare const answerLabel: (q: OnboardingQuestion | undefined, value: string) => string;
338
490
  /**
339
491
  * 0.17.0: how a video link plays. YouTube, Vimeo and Loom through their players without tracking cookies
340
492
  * (youtube-nocookie.com, Vimeo's `dnt=1`), a file (mp4, webm, mov, or an upload in MRRocket) in a plain video element;