@mrrocket/sdk 0.4.0 → 0.9.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 (72) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/README.md +137 -8
  3. package/dist/api-client.d.ts +213 -0
  4. package/dist/api-client.js +67 -0
  5. package/dist/api-client.js.map +1 -0
  6. package/dist/api.d.ts +9 -109
  7. package/dist/api.js +7 -62
  8. package/dist/api.js.map +1 -1
  9. package/dist/browser/mrrocket-flows.js +64 -0
  10. package/dist/browser/mrrocket-messenger.js +313 -0
  11. package/dist/browser/mrrocket-push.js +1 -0
  12. package/dist/browser/mrrocket-replay.js +3 -3
  13. package/dist/browser/mrrocket-sw.js +1 -0
  14. package/dist/browser/mrrocket.js +2 -1
  15. package/dist/browser.d.ts +3 -2
  16. package/dist/browser.js +6 -1
  17. package/dist/browser.js.map +1 -1
  18. package/dist/capture.d.ts +1 -13
  19. package/dist/capture.js +1 -22
  20. package/dist/capture.js.map +1 -1
  21. package/dist/client.d.ts +36 -1
  22. package/dist/client.js +161 -6
  23. package/dist/client.js.map +1 -1
  24. package/dist/context.d.ts +10 -0
  25. package/dist/context.js.map +1 -1
  26. package/dist/core.d.ts +64 -3
  27. package/dist/core.js +54 -2
  28. package/dist/core.js.map +1 -1
  29. package/dist/feedback.d.ts +19 -4
  30. package/dist/feedback.js +655 -190
  31. package/dist/feedback.js.map +1 -1
  32. package/dist/flows-ui.d.ts +23 -0
  33. package/dist/flows-ui.js +384 -0
  34. package/dist/flows-ui.js.map +1 -0
  35. package/dist/flows-web.d.ts +19 -0
  36. package/dist/flows-web.js +42 -0
  37. package/dist/flows-web.js.map +1 -0
  38. package/dist/flows.d.ts +222 -0
  39. package/dist/flows.js +409 -0
  40. package/dist/flows.js.map +1 -0
  41. package/dist/index.d.ts +5 -2
  42. package/dist/index.js +13 -1
  43. package/dist/index.js.map +1 -1
  44. package/dist/messenger-ui.d.ts +47 -0
  45. package/dist/messenger-ui.js +583 -0
  46. package/dist/messenger-ui.js.map +1 -0
  47. package/dist/messenger.d.ts +37 -0
  48. package/dist/messenger.js +69 -0
  49. package/dist/messenger.js.map +1 -0
  50. package/dist/proxy.d.ts +34 -1
  51. package/dist/proxy.js +14 -1
  52. package/dist/proxy.js.map +1 -1
  53. package/dist/push-web.d.ts +43 -0
  54. package/dist/push-web.js +81 -0
  55. package/dist/push-web.js.map +1 -0
  56. package/dist/rage.d.ts +14 -0
  57. package/dist/rage.js +27 -0
  58. package/dist/rage.js.map +1 -0
  59. package/dist/react-native/index.d.cts +640 -3
  60. package/dist/react-native/index.d.ts +640 -3
  61. package/dist/react-native/index.js +2015 -34
  62. package/dist/react-native/index.js.map +1 -1
  63. package/dist/styles-css.d.ts +6 -0
  64. package/dist/styles-css.js +327 -0
  65. package/dist/styles-css.js.map +1 -0
  66. package/dist/styles.d.ts +1 -2
  67. package/dist/styles.js +3 -134
  68. package/dist/styles.js.map +1 -1
  69. package/dist/ui.d.ts +3 -0
  70. package/dist/ui.js +12 -0
  71. package/dist/ui.js.map +1 -1
  72. package/package.json +20 -4
package/dist/api.d.ts CHANGED
@@ -1,113 +1,13 @@
1
- export type PostStatus = "review" | "planned" | "progress" | "shipped";
2
- export declare const STATUS_LABEL: Record<PostStatus, string>;
3
- export interface FeedbackBoardInfo {
4
- id: string;
5
- label: string;
6
- }
7
- export interface FeedbackPost {
8
- id: string;
9
- title: string;
10
- body: string;
11
- board: string;
12
- status: PostStatus;
13
- votes: number;
14
- comments: number;
15
- voted: boolean;
16
- createdAt: string;
17
- }
18
- export interface FeedbackList {
19
- boards: FeedbackBoardInfo[];
20
- posts: FeedbackPost[];
21
- }
22
- export interface FeedbackRoadmap {
23
- columns: {
24
- planned: FeedbackPost[];
25
- progress: FeedbackPost[];
26
- shipped: FeedbackPost[];
27
- };
28
- }
29
- export interface ChangelogEntry {
30
- id: string;
31
- title: string;
32
- body: string;
33
- publishedAt: string;
34
- }
35
- export interface FeedbackComment {
36
- id: string;
37
- body: string;
38
- author: string;
39
- isTeam: boolean;
40
- postedAt: string;
41
- }
42
- export type SurveyQuestionKind = "nps" | "rating" | "single" | "multi" | "text";
43
- export interface SurveyQuestion {
44
- key: string;
45
- kind: SurveyQuestionKind;
46
- title: string;
47
- description?: string;
48
- required: boolean;
49
- options?: string[];
50
- scale?: number;
51
- low?: string;
52
- high?: string;
53
- placeholder?: string;
54
- }
55
- export interface SurveyDefinition {
56
- id: string;
57
- name: string;
58
- type: string;
59
- thanks: string;
60
- questions: SurveyQuestion[];
61
- }
62
- export type SurveyAnswer = number | string | string[];
63
- export declare class ApiError extends Error {
64
- status: number;
65
- constructor(message: string, status: number);
66
- }
67
- interface Conn {
68
- host: string;
69
- apiKey: string;
1
+ import { type Api } from "./api-client.js";
2
+ export * from "./api-client.js";
3
+ /** Who writes: the provider's visitor, or the name and email a visitor gave the board (see useBoardIdentity). */
4
+ export interface Writer {
70
5
  distinctId: string;
71
6
  user?: {
72
- id: string;
73
- [key: string]: unknown;
7
+ id?: string;
8
+ name?: string;
9
+ email?: string;
74
10
  };
75
11
  }
76
- /** The small fetch client behind the widgets. Every read takes an AbortSignal so unmounting cancels it. */
77
- export declare const createApi: (c: Conn) => {
78
- list: (o: {
79
- board?: string;
80
- sort?: "top" | "new";
81
- q?: string;
82
- }, signal?: AbortSignal) => Promise<FeedbackList>;
83
- roadmap: (signal?: AbortSignal) => Promise<FeedbackRoadmap>;
84
- changelog: (signal?: AbortSignal) => Promise<{
85
- entries: ChangelogEntry[];
86
- }>;
87
- submit: (p: {
88
- title: string;
89
- body?: string;
90
- board: string;
91
- }) => Promise<FeedbackPost>;
92
- vote: (id: string) => Promise<{
93
- voted: boolean;
94
- votes: number;
95
- }>;
96
- comments: (id: string, signal?: AbortSignal) => Promise<{
97
- comments: FeedbackComment[];
98
- }>;
99
- comment: (id: string, body: string) => Promise<FeedbackComment>;
100
- survey: (url: string, signal?: AbortSignal) => Promise<{
101
- survey: SurveyDefinition | null;
102
- }>;
103
- seen: (id: string) => Promise<unknown>;
104
- respond: (id: string, r: {
105
- answers: Record<string, SurveyAnswer>;
106
- completed: boolean;
107
- seconds: number;
108
- }) => Promise<unknown>;
109
- };
110
- export type Api = ReturnType<typeof createApi>;
111
- /** The client for the provider's key, host and visitor. */
112
- export declare const useApi: () => Api;
113
- export {};
12
+ /** The client for the provider's key, host and visitor, or for `as` when given. */
13
+ export declare const useApi: (as?: Writer | null) => Api;
package/dist/api.js CHANGED
@@ -1,71 +1,16 @@
1
1
  // src/api.ts
2
2
  import { useMemo } from "react";
3
+ import { createApi } from "./api-client.js";
3
4
  import { useCtx } from "./context.js";
4
- var STATUS_LABEL = {
5
- review: "Under review",
6
- planned: "Planned",
7
- progress: "In progress",
8
- shipped: "Shipped"
9
- };
10
- var ApiError = class extends Error {
11
- status;
12
- constructor(message, status) {
13
- super(message);
14
- this.status = status;
15
- }
16
- };
17
- var qs = (params) => {
18
- const p = new URLSearchParams();
19
- for (const [k, v] of Object.entries(params)) if (v) p.set(k, v);
20
- return p.toString();
21
- };
22
- var call = async (url, init, signal) => {
23
- let res;
24
- try {
25
- res = await fetch(url, {
26
- ...init,
27
- signal,
28
- headers: init?.body ? { "content-type": "application/json" } : void 0
29
- });
30
- } catch (e) {
31
- if (e.name === "AbortError") throw e;
32
- throw new ApiError("Could not reach the server. Check your connection and try again.", 0);
33
- }
34
- if (!res.ok) {
35
- let detail = "";
36
- try {
37
- detail = (await res.json()).error ?? "";
38
- } catch {
39
- }
40
- throw new ApiError(detail || (res.status === 429 ? "Too many requests. Try again in a minute." : "Something went wrong. Please try again."), res.status);
41
- }
42
- return await res.json();
43
- };
44
- var createApi = (c) => {
45
- const base = `${c.host}/api/sdk`;
46
- const who = { key: c.apiKey, distinctId: c.distinctId, user: c.user };
47
- const post = (path, body, signal) => call(`${base}${path}`, { method: "POST", body: JSON.stringify({ ...who, ...body }) }, signal);
48
- return {
49
- list: (o, signal) => call(`${base}/feedback?${qs({ key: c.apiKey, distinctId: c.distinctId, board: o.board, sort: o.sort, q: o.q })}`, void 0, signal),
50
- roadmap: (signal) => call(`${base}/feedback/roadmap?${qs({ key: c.apiKey })}`, void 0, signal),
51
- changelog: (signal) => call(`${base}/feedback/changelog?${qs({ key: c.apiKey })}`, void 0, signal),
52
- submit: (p) => post("/feedback", p),
53
- vote: (id) => post(`/feedback/${encodeURIComponent(id)}/vote`, {}),
54
- comments: (id, signal) => call(`${base}/feedback/${encodeURIComponent(id)}/comments?${qs({ key: c.apiKey })}`, void 0, signal),
55
- comment: (id, body) => post(`/feedback/${encodeURIComponent(id)}/comments`, { body }),
56
- survey: (url, signal) => call(`${base}/surveys?${qs({ key: c.apiKey, distinctId: c.distinctId, url })}`, void 0, signal),
57
- seen: (id) => post(`/surveys/${encodeURIComponent(id)}/seen`, { user: void 0 }),
58
- respond: (id, r) => post(`/surveys/${encodeURIComponent(id)}/respond`, r)
59
- };
60
- };
61
- var useApi = () => {
62
- const { apiKey, host, distinctId, user } = useCtx();
5
+ export * from "./api-client.js";
6
+ var useApi = (as) => {
7
+ const ctx = useCtx();
8
+ const distinctId = as?.distinctId ?? ctx.distinctId;
9
+ const user = as ? as.user : ctx.user;
10
+ const { apiKey, host } = ctx;
63
11
  return useMemo(() => createApi({ apiKey, host, distinctId, user }), [apiKey, host, distinctId, user]);
64
12
  };
65
13
  export {
66
- ApiError,
67
- STATUS_LABEL,
68
- createApi,
69
14
  useApi
70
15
  };
71
16
  //# sourceMappingURL=api.js.map
package/dist/api.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { useCtx } from \"./context\";\n\nexport type PostStatus = \"review\" | \"planned\" | \"progress\" | \"shipped\";\n\nexport const STATUS_LABEL: Record<PostStatus, string> = {\n review: \"Under review\",\n planned: \"Planned\",\n progress: \"In progress\",\n shipped: \"Shipped\",\n};\n\nexport interface FeedbackBoardInfo {\n id: string;\n label: string;\n}\n\nexport interface FeedbackPost {\n id: string;\n title: string;\n body: string;\n board: string;\n status: PostStatus;\n votes: number;\n comments: number;\n voted: boolean;\n createdAt: string;\n}\n\nexport interface FeedbackList {\n boards: FeedbackBoardInfo[];\n posts: FeedbackPost[];\n}\n\nexport interface FeedbackRoadmap {\n columns: { planned: FeedbackPost[]; progress: FeedbackPost[]; shipped: FeedbackPost[] };\n}\n\nexport interface ChangelogEntry {\n id: string;\n title: string;\n body: string;\n publishedAt: string;\n}\n\nexport interface FeedbackComment {\n id: string;\n body: string;\n author: string;\n isTeam: boolean;\n postedAt: string;\n}\n\nexport type SurveyQuestionKind = \"nps\" | \"rating\" | \"single\" | \"multi\" | \"text\";\n\nexport interface SurveyQuestion {\n key: string;\n kind: SurveyQuestionKind;\n title: string;\n description?: string;\n required: boolean;\n options?: string[];\n scale?: number;\n low?: string;\n high?: string;\n placeholder?: string;\n}\n\nexport interface SurveyDefinition {\n id: string;\n name: string;\n type: string;\n thanks: string;\n questions: SurveyQuestion[];\n}\n\nexport type SurveyAnswer = number | string | string[];\n\nexport class ApiError extends Error {\n status: number;\n constructor(message: string, status: number) {\n super(message);\n this.status = status;\n }\n}\n\ninterface Conn {\n host: string;\n apiKey: string;\n distinctId: string;\n user?: { id: string; [key: string]: unknown };\n}\n\nconst qs = (params: Record<string, string | undefined>) => {\n const p = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v) p.set(k, v);\n return p.toString();\n};\n\nconst call = async <T>(url: string, init: RequestInit | undefined, signal?: AbortSignal): Promise<T> => {\n let res: Response;\n try {\n res = await fetch(url, {\n ...init,\n signal,\n headers: init?.body ? { \"content-type\": \"application/json\" } : undefined,\n });\n } catch (e) {\n if ((e as Error).name === \"AbortError\") throw e;\n throw new ApiError(\"Could not reach the server. Check your connection and try again.\", 0);\n }\n if (!res.ok) {\n let detail = \"\";\n try {\n detail = ((await res.json()) as { error?: string }).error ?? \"\";\n } catch {\n // Not JSON; the status is enough.\n }\n throw new ApiError(detail || (res.status === 429 ? \"Too many requests. Try again in a minute.\" : \"Something went wrong. Please try again.\"), res.status);\n }\n return (await res.json()) as T;\n};\n\n/** The small fetch client behind the widgets. Every read takes an AbortSignal so unmounting cancels it. */\nexport const createApi = (c: Conn) => {\n const base = `${c.host}/api/sdk`;\n const who = { key: c.apiKey, distinctId: c.distinctId, user: c.user };\n const post = <T>(path: string, body: Record<string, unknown>, signal?: AbortSignal) =>\n call<T>(`${base}${path}`, { method: \"POST\", body: JSON.stringify({ ...who, ...body }) }, signal);\n return {\n list: (o: { board?: string; sort?: \"top\" | \"new\"; q?: string }, signal?: AbortSignal) =>\n call<FeedbackList>(`${base}/feedback?${qs({ key: c.apiKey, distinctId: c.distinctId, board: o.board, sort: o.sort, q: o.q })}`, undefined, signal),\n roadmap: (signal?: AbortSignal) => call<FeedbackRoadmap>(`${base}/feedback/roadmap?${qs({ key: c.apiKey })}`, undefined, signal),\n changelog: (signal?: AbortSignal) => call<{ entries: ChangelogEntry[] }>(`${base}/feedback/changelog?${qs({ key: c.apiKey })}`, undefined, signal),\n submit: (p: { title: string; body?: string; board: string }) => post<FeedbackPost>(\"/feedback\", p),\n vote: (id: string) => post<{ voted: boolean; votes: number }>(`/feedback/${encodeURIComponent(id)}/vote`, {}),\n comments: (id: string, signal?: AbortSignal) =>\n call<{ comments: FeedbackComment[] }>(`${base}/feedback/${encodeURIComponent(id)}/comments?${qs({ key: c.apiKey })}`, undefined, signal),\n comment: (id: string, body: string) => post<FeedbackComment>(`/feedback/${encodeURIComponent(id)}/comments`, { body }),\n survey: (url: string, signal?: AbortSignal) =>\n call<{ survey: SurveyDefinition | null }>(`${base}/surveys?${qs({ key: c.apiKey, distinctId: c.distinctId, url })}`, undefined, signal),\n seen: (id: string) => post<unknown>(`/surveys/${encodeURIComponent(id)}/seen`, { user: undefined }),\n respond: (id: string, r: { answers: Record<string, SurveyAnswer>; completed: boolean; seconds: number }) =>\n post<unknown>(`/surveys/${encodeURIComponent(id)}/respond`, r),\n };\n};\n\nexport type Api = ReturnType<typeof createApi>;\n\n/** The client for the provider's key, host and visitor. */\nexport const useApi = (): Api => {\n const { apiKey, host, distinctId, user } = useCtx();\n return useMemo(() => createApi({ apiKey, host, distinctId, user }), [apiKey, host, distinctId, user]);\n};\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/api.ts"],"sourcesContent":["import { useMemo } from \"react\";\nimport { type Api, createApi } from \"./api-client\";\nimport { useCtx } from \"./context\";\n\nexport * from \"./api-client\";\n\n/** Who writes: the provider's visitor, or the name and email a visitor gave the board (see useBoardIdentity). */\nexport interface Writer {\n distinctId: string;\n user?: { id?: string; name?: string; email?: string };\n}\n\n/** The client for the provider's key, host and visitor, or for `as` when given. */\nexport const useApi = (as?: Writer | null): Api => {\n const ctx = useCtx();\n const distinctId = as?.distinctId ?? ctx.distinctId;\n const user = as ? as.user : ctx.user;\n const { apiKey, host } = ctx;\n return useMemo(() => createApi({ apiKey, host, distinctId, user }), [apiKey, host, distinctId, user]);\n};\n"],"mappings":";AAAA,SAAS,eAAe;AACxB,SAAmB,iBAAiB;AACpC,SAAS,cAAc;AAEvB,cAAc;AASP,IAAM,SAAS,CAAC,OAA4B;AAC/C,QAAM,MAAM,OAAO;AACnB,QAAM,aAAa,IAAI,cAAc,IAAI;AACzC,QAAM,OAAO,KAAK,GAAG,OAAO,IAAI;AAChC,QAAM,EAAE,QAAQ,KAAK,IAAI;AACzB,SAAO,QAAQ,MAAM,UAAU,EAAE,QAAQ,MAAM,YAAY,KAAK,CAAC,GAAG,CAAC,QAAQ,MAAM,YAAY,IAAI,CAAC;AACxG;","names":[]}
@@ -0,0 +1,64 @@
1
+ (function(){'use strict';var E=(n,a)=>Math.round(n*(1-a/100)*100)/100,v=(n,a)=>{try{return new Intl.NumberFormat(void 0,{style:"currency",currency:a}).format(n)}catch(p){return `${n.toFixed(2)} ${a}`}},S=n=>n.kind==="contact"?"Send to the team":n.kind==="pause"?"Pause instead":n.kind==="downgrade"?"Switch plan":"Accept offer";var O="ckf-styles",_=`
2
+ .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)}
3
+ .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)}
4
+ @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)}}
5
+ .ckf-root,.ckf-root *{box-sizing:border-box}
6
+ .ckf-root{font-family:var(--ckf-font);font-size:14px;line-height:1.45;color:var(--ckf-fg);-webkit-font-smoothing:antialiased}
7
+ .ckf-root :where(button,textarea){font:inherit;color:inherit;margin:0}
8
+ .ckf-root :focus-visible{outline:2px solid var(--ckf-accent);outline-offset:2px}
9
+ .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}
10
+ .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}
11
+ .ckf-float{position:fixed;z-index:2147483001;right:20px;bottom:20px;width:340px;max-width:calc(100vw - 24px)}
12
+ .ckf-top{display:flex;align-items:center;gap:8px;min-height:20px}
13
+ .ckf-dots{display:flex;gap:4px}
14
+ .ckf-dot{width:16px;height:4px;border-radius:4px;background:var(--ckf-line)}
15
+ .ckf-dot[data-on]{background:var(--ckf-accent)}
16
+ .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}
17
+ .ckf-x:hover{background:var(--ckf-soft);color:var(--ckf-fg)}
18
+ .ckf-h{margin:0;font-size:17px;font-weight:650;letter-spacing:-.01em;text-wrap:balance}
19
+ .ckf-p{margin:0;color:var(--ckf-muted);text-wrap:pretty;white-space:pre-wrap}
20
+ .ckf-small{margin:0;font-size:12px;color:var(--ckf-muted)}
21
+ .ckf-opts{display:flex;flex-direction:column;gap:6px;margin:0;padding:0;list-style:none}
22
+ .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}
23
+ .ckf-opt:hover{background:var(--ckf-soft)}
24
+ .ckf-opt[aria-checked=true]{border-color:var(--ckf-accent);background:color-mix(in srgb,var(--ckf-accent) 8%,var(--ckf-bg))}
25
+ .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}
26
+ .ckf-opt[aria-checked=true] .ckf-radio{border-color:var(--ckf-accent)}
27
+ .ckf-opt[aria-checked=true] .ckf-radio::after{content:"";width:8px;height:8px;border-radius:50%;background:var(--ckf-accent)}
28
+ .ckf-box{border-radius:10px;background:var(--ckf-soft);padding:12px;display:flex;align-items:baseline;gap:8px;flex-wrap:wrap}
29
+ .ckf-big{font-size:22px;font-weight:650;font-variant-numeric:tabular-nums}
30
+ .ckf-strike{color:var(--ckf-muted);text-decoration:line-through;font-variant-numeric:tabular-nums}
31
+ .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}
32
+ .ckf-text::placeholder{color:var(--ckf-muted)}
33
+ .ckf-btns{display:flex;flex-direction:column;gap:6px}
34
+ .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}
35
+ .ckf-btn:hover{background:var(--ckf-soft)}
36
+ .ckf-btn[disabled]{opacity:.55;cursor:not-allowed}
37
+ .ckf-primary{background:var(--ckf-accent);border-color:var(--ckf-accent);color:var(--ckf-accent-ink)}
38
+ .ckf-primary:hover{background:var(--ckf-accent);filter:brightness(1.07)}
39
+ .ckf-danger{background:var(--ckf-danger);border-color:var(--ckf-danger);color:#fff}
40
+ .ckf-danger:hover{background:var(--ckf-danger);filter:brightness(1.07)}
41
+ .ckf-quiet{border-color:transparent;background:none;color:var(--ckf-muted);height:30px;font-weight:500}
42
+ .ckf-quiet:hover{background:none;color:var(--ckf-fg)}
43
+ .ckf-err{margin:0;color:var(--ckf-danger);font-size:13px;font-weight:500}
44
+ .ckf-row{display:flex;justify-content:flex-end;gap:8px;align-items:center}
45
+ .ckf-row .ckf-small{margin-right:auto}
46
+ .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}
47
+ .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}
48
+ .ckf-check:where(button){cursor:pointer}
49
+ .ckf-check:where(button):hover{background:var(--ckf-soft)}
50
+ .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}
51
+ .ckf-check[data-done] .ckf-tick{background:var(--ckf-accent);border-color:var(--ckf-accent)}
52
+ .ckf-check[data-done] b{color:var(--ckf-muted);text-decoration:line-through}
53
+ .ckf-check span{display:flex;flex-direction:column;gap:2px;min-width:0}
54
+ .ckf-bar{height:4px;border-radius:4px;background:var(--ckf-soft);overflow:hidden}
55
+ .ckf-bar i{display:block;height:100%;background:var(--ckf-accent)}
56
+ .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}
57
+ .ckf-banner>span{flex:1;min-width:0;display:flex;flex-direction:column}
58
+ .ckf-banner .ckf-btn{height:32px}
59
+ @keyframes ckf-fade{from{opacity:0}}
60
+ @keyframes ckf-in{from{opacity:0;transform:translateY(6px)}}
61
+ .ckf-banner{animation-name:ckf-fade}
62
+ @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}}
63
+ @media (prefers-reduced-motion:reduce){.ckf-root *{animation:none!important;transition:none!important}}
64
+ `,e=(n,a={},...p)=>{let d=document.createElement(n);for(let[f,c]of Object.entries(a))c===void 0||c===false||(typeof c=="function"?d.addEventListener(f.slice(2).toLowerCase(),c):f==="className"?d.className=String(c):d.setAttribute(f,c===true?"":c));for(let f of p)(f||f==="")&&d.append(typeof f=="string"?document.createTextNode(f):f);return d},b=(n,a,p,d={})=>e("button",{type:"button",className:`ckf-btn${a==="secondary"?"":` ckf-${a}`}`,disabled:!!d.disabled,"data-ckf-id":d.id,onClick:()=>p()},n),w=(n,a)=>e("button",{type:"button",className:"ckf-x","aria-label":n,"data-ckf-id":"x",onClick:()=>a()},"\xD7"),H=(n,a)=>a>1?e("span",{className:"ckf-dots",role:"img","aria-label":`Step ${n} of ${a}`},...Array.from({length:a},(p,d)=>e("span",{className:"ckf-dot","data-on":d<n}))):e("span"),P=n=>n.type==="cancel"?`c:${n.screen}`:n.type==="step"?`s:${n.step.id}`:n.type==="checklist"?`l:${n.flow.id}`:`m:${n.message.id}`,L=(n,a={})=>{var $;if(typeof document=="undefined")return ()=>{};if(!document.getElementById(O)){let t=document.createElement("style");t.id=O,t.textContent=_,document.head.appendChild(t);}let p=e("div",{className:`ckf-root${a.className?` ${a.className}`:""}`,"data-theme":($=a.theme)!=null?$:"auto"});a.accent&&p.style.setProperty("--ckf-accent",a.accent),document.body.appendChild(p);let d="",f=null,c="",h=null,T=t=>{var l,u;let o="ckf-title",r=t.busy,i=[];if(t.screen==="survey")i.push(e("h2",{className:"ckf-h",id:o},t.flow.question||"Why are you leaving?"),e("div",{className:"ckf-opts",role:"radiogroup","aria-labelledby":o},...t.flow.reasons.map(s=>e("button",{type:"button",role:"radio",className:"ckf-opt","aria-checked":String(t.reason===s.id),"data-ckf-id":`r:${s.id}`,onClick:()=>n.cancel.pick(s.id)},e("span",{className:"ckf-radio"}),s.label))),e("div",{className:"ckf-btns"},b("Continue","primary",n.cancel.next,{disabled:!t.reason,id:"go"}),b("Never mind, keep my plan","quiet",n.cancel.close)));else if(t.screen==="offer"&&t.offer){let s=t.offer,m=(l=t.flow.reasons.find(y=>y.id===t.reason))==null?void 0:l.label,g=false;s.kind==="discount"&&s.percent&&(g=t.price?e("div",{className:"ckf-box"},e("span",{className:"ckf-big"},v(E(t.price.amount,s.percent),t.price.currency)),e("span",{className:"ckf-strike"},v(t.price.amount,t.price.currency)),e("span",{className:"ckf-small"},`/${(u=t.price.interval)!=null?u:"month"}${s.months?` for ${s.months} ${s.months===1?"month":"months"}`:""}`)):e("div",{className:"ckf-box"},e("span",{className:"ckf-big"},`${s.percent}% off`),s.months?e("span",{className:"ckf-small"},`for ${s.months} ${s.months===1?"month":"months"}`):false)),s.kind==="pause"&&s.months&&(g=e("div",{className:"ckf-box"},e("span",{},`Pause for up to ${s.months} ${s.months===1?"month":"months"}. Your data stays.`))),s.kind==="downgrade"&&s.planName&&(g=e("div",{className:"ckf-box"},e("b",{},s.planName)));let k=s.kind==="contact"?e("textarea",{className:"ckf-text",placeholder:"What would make you stay?","aria-label":"Your message",maxlength:"500","data-ckf-id":"comment",onInput:y=>c=y.target.value}):null;k&&(k.value=c),i.push(m?e("p",{className:"ckf-small"},`You said: ${m}`):false,e("h2",{className:"ckf-h",id:o},s.headline),g,k!=null?k:false,e("div",{className:"ckf-btns"},b(r?"One moment\u2026":S(s),"primary",()=>n.cancel.accept(c),{disabled:r,id:"go"}),b("No thanks, continue cancelling","quiet",n.cancel.decline,{disabled:r})));}else {let m=t.steps===1?null:e("textarea",{className:"ckf-text",placeholder:"Anything else we should know? (optional)","aria-label":"Anything else we should know? (optional)",maxlength:"500","data-ckf-id":"comment",onInput:g=>c=g.target.value});m&&(m.value=c),i.push(e("h2",{className:"ckf-h",id:o},t.flow.confirm.title),t.flow.confirm.body?e("p",{className:"ckf-p"},t.flow.confirm.body):false,m!=null?m:false,e("div",{className:"ckf-btns"},b(r?"One moment\u2026":t.flow.confirm.button,"danger",()=>n.cancel.confirm(c),{disabled:r,id:"go"}),b("Keep my plan","secondary",n.cancel.close,{disabled:r})));}return e("div",{className:"ckf-scrim",onClick:s=>s.target===s.currentTarget&&!r&&n.cancel.close()},e("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":o},e("div",{className:"ckf-top"},H(t.step,t.steps),w("Close",n.cancel.close)),...i,t.error?e("p",{className:"ckf-err",role:"alert"},t.error):false))},I=t=>{let o=t.step,r=e("div",{className:"ckf-card",role:"dialog","aria-modal":o.kind==="modal"?"true":void 0,"aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},t.total>1?e("p",{className:"ckf-small"},`Step ${t.index+1} of ${t.total}`):e("span"),w("Close the tour",n.onboarding.dismiss)),e("h2",{className:"ckf-h",id:"ckf-title"},o.title),o.body?e("p",{className:"ckf-p"},o.body):false,e("div",{className:"ckf-row"},b(o.button||(t.last?"Done":"Next"),"primary",n.onboarding.next,{id:"go"})));if(o.kind==="modal")return e("div",{className:"ckf-scrim"},r);let i=o.target?document.querySelector(`[data-ck-target="${CSS.escape(o.target)}"]`):null,l=e("div",{className:"ckf-float"},r);if(i){let u=e("div",{className:"ckf-ring","aria-hidden":"true"});return h={float:l,ring:u,target:i},N(l,u,i),e("div",{},u,l)}return l},N=(t,o,r)=>{let i=r.getBoundingClientRect();Object.assign(o.style,{left:`${i.left-4}px`,top:`${i.top-4}px`,width:`${i.width+8}px`,height:`${i.height+8}px`});let l=Math.min(340,window.innerWidth-24),u=Math.max(12,Math.min(i.left,window.innerWidth-l-12)),s=i.bottom+12;Object.assign(t.style,{left:`${u}px`,right:"auto",width:`${l}px`}),s+200<window.innerHeight?Object.assign(t.style,{top:`${s}px`,bottom:"auto"}):Object.assign(t.style,{top:"auto",bottom:`${Math.max(12,window.innerHeight-i.top+12)}px`});},A=t=>{let o=t.items.filter(r=>r.done).length;return e("div",{className:"ckf-float"},e("div",{className:"ckf-card",role:"region","aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},e("h2",{className:"ckf-h",id:"ckf-title"},t.flow.name),w("Hide the checklist",n.onboarding.dismiss)),e("p",{className:"ckf-small"},`${o} of ${t.items.length} done`),e("div",{className:"ckf-bar",role:"progressbar","aria-valuemin":"0","aria-valuemax":String(t.items.length),"aria-valuenow":String(o)},e("i",{style:`width:${o/t.items.length*100}%`})),e("div",{className:"ckf-opts"},...t.items.map(({step:r,done:i})=>{let l=[e("span",{className:"ckf-tick","aria-hidden":"true"},i?"\u2713":""),e("span",{},e("b",{},r.title),r.body?e("span",{className:"ckf-small"},r.body):false)];return i||r.event?e("div",{className:"ckf-check","data-done":i,role:"listitem"},...l):e("button",{type:"button",className:"ckf-check","aria-label":`Mark \u201C${r.title}\u201D done`,"data-ckf-id":`i:${r.id}`,onClick:()=>n.onboarding.check(r.id)},...l)}))))},M=t=>{let o=t.message,r=o.button?b(o.button,"primary",n.message.click,{id:"go"}):false;return o.style==="banner"?e("div",{className:"ckf-banner",role:"status"},e("span",{},e("b",{},o.title),o.body?e("span",{className:"ckf-small"},o.body):false),r,w("Dismiss",n.message.dismiss)):e("div",{className:"ckf-scrim",onClick:i=>i.target===i.currentTarget&&n.message.dismiss()},e("div",{className:"ckf-card",role:"dialog","aria-modal":"true","aria-labelledby":"ckf-title"},e("div",{className:"ckf-top"},e("span"),w("Dismiss",n.message.dismiss)),e("h2",{className:"ckf-h",id:"ckf-title"},o.title),o.body?e("p",{className:"ckf-p"},o.body):false,r?e("div",{className:"ckf-row"},r):false))},C=()=>{var i,l,u,s,m;let t=n.view(),o=t?P(t):"",r=(l=(i=document.activeElement)==null?void 0:i.closest)!=null&&l.call(i,".ckf-root")?(u=document.activeElement)==null?void 0:u.getAttribute("data-ckf-id"):null;if(o&&!d&&document.activeElement instanceof HTMLElement&&!document.activeElement.closest(".ckf-root")&&(f=document.activeElement),o!==d&&!o.startsWith("c:")&&(c=""),o||(c=""),h=null,p.replaceChildren(...t?[t.type==="cancel"?T(t):t.type==="step"?I(t):t.type==="checklist"?A(t):M(t)]:[]),o!==d){let g=p.querySelector("[aria-modal=true]"),k=(s=g==null?void 0:g.querySelector("[role=radio], [data-ckf-id=go], textarea"))!=null?s:null;k==null||k.focus(),!o&&f&&(f.focus(),f=null);}else r&&((m=p.querySelector(`[data-ckf-id="${CSS.escape(r)}"]`))==null||m.focus());d=o;},F=t=>{if(t.key!=="Escape")return;let o=n.view();(o==null?void 0:o.type)==="cancel"?n.cancel.close():(o==null?void 0:o.type)==="message"?n.message.dismiss():(o==null?void 0:o.type)==="step"&&o.step.kind==="modal"&&n.onboarding.dismiss();},x=()=>{h&&N(h.float,h.ring,h.target);};document.addEventListener("keydown",F),window.addEventListener("resize",x),window.addEventListener("scroll",x,{passive:true,capture:true});let R=n.subscribe(C);return C(),()=>{R(),document.removeEventListener("keydown",F),window.removeEventListener("resize",x),window.removeEventListener("scroll",x,{capture:true}),p.remove();}};window.__mrrocketFlows={mountFlows:L};})();