@sightspool/sdk 0.2.1 → 0.4.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 (35) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +111 -333
  3. package/SECURITY.md +16 -0
  4. package/dist/index.cjs +159 -1080
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.d.cts +20 -41
  7. package/dist/index.d.ts +20 -41
  8. package/dist/index.js +160 -734
  9. package/dist/index.js.map +1 -1
  10. package/dist/release.json +21 -0
  11. package/dist/sdk.global.js +2 -38
  12. package/dist/sdk.global.js.map +1 -1
  13. package/dist/source.json +11 -0
  14. package/package.json +14 -12
  15. package/site/CNAME +1 -0
  16. package/site/demo.html +6 -0
  17. package/site/demo.js +27 -0
  18. package/site/index.html +74 -0
  19. package/site/release.js +20 -0
  20. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/release.json +21 -0
  21. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js +3 -0
  22. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/sdk.global.js.map +1 -0
  23. package/site/releases/0.4.0/2acf3463db7571c459ca01a4516341891bb4c2ec6265962f494ca8b553cc0e9f/source.json +11 -0
  24. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/release.json +21 -0
  25. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js +3 -0
  26. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/sdk.global.js.map +1 -0
  27. package/site/releases/0.4.0/c21bee307a5c53e3ebb49d21f0f1ef2cce06a4483fa9824122bd6897ad6ca3ac/source.json +11 -0
  28. package/site/styles.css +69 -0
  29. package/site/trust.html +36 -0
  30. package/dist/chunk-4PADVIIO.js +0 -41
  31. package/dist/chunk-4PADVIIO.js.map +0 -1
  32. package/dist/prompt-GDFYC75D.js +0 -139
  33. package/dist/prompt-GDFYC75D.js.map +0 -1
  34. package/dist/survey-CICJQ5VI.js +0 -145
  35. package/dist/survey-CICJQ5VI.js.map +0 -1
@@ -1,41 +0,0 @@
1
- // src/privacy.ts
2
- var EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}/g;
3
- var LONG_DIGITS_RE = /\d{6,}/g;
4
- var MAX_LABEL_LEN = 280;
5
- function redactText(input) {
6
- if (!input) return "";
7
- try {
8
- return String(input).replace(EMAIL_RE, "\u2039email\u203A").replace(LONG_DIGITS_RE, "\u2039num\u203A").replace(/\s+/g, " ").trim().slice(0, MAX_LABEL_LEN);
9
- } catch (e) {
10
- return "";
11
- }
12
- }
13
- var ATTACH_DISCLOSURE = "Session and account attached automatically.";
14
- var REDACTED = "\u2039redacted\u203A";
15
- var IGNORE_ATTR = "data-sightspool-ignore";
16
- function safeClosest(el, selector) {
17
- try {
18
- return typeof el.closest === "function" && el.closest(selector) != null;
19
- } catch (e) {
20
- return false;
21
- }
22
- }
23
- function isIgnoredElement(el, blockSelectors = []) {
24
- if (!el || typeof el.closest !== "function") return false;
25
- if (safeClosest(el, `[${IGNORE_ATTR}]`)) return true;
26
- for (const sel of blockSelectors) {
27
- if (sel && safeClosest(el, sel)) return true;
28
- }
29
- return false;
30
- }
31
- function matchesRedactSelector(el, redactSelectors = []) {
32
- if (!el || typeof el.closest !== "function") return false;
33
- for (const sel of redactSelectors) {
34
- if (sel && safeClosest(el, sel)) return true;
35
- }
36
- return false;
37
- }
38
-
39
- export { ATTACH_DISCLOSURE, REDACTED, isIgnoredElement, matchesRedactSelector, redactText };
40
- //# sourceMappingURL=chunk-4PADVIIO.js.map
41
- //# sourceMappingURL=chunk-4PADVIIO.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/privacy.ts"],"names":[],"mappings":";AAIA,IAAM,QAAA,GAAW,iDAAA;AACjB,IAAM,cAAA,GAAiB,SAAA;AAEhB,IAAM,aAAA,GAAgB,GAAA;AAMtB,SAAS,WAAW,KAAA,EAA0C;AACnE,EAAA,IAAI,CAAC,OAAO,OAAO,EAAA;AACnB,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,KAAK,CAAA,CAChB,QAAQ,QAAA,EAAU,mBAAS,EAC3B,OAAA,CAAQ,cAAA,EAAgB,iBAAO,CAAA,CAC/B,OAAA,CAAQ,QAAQ,GAAG,CAAA,CACnB,MAAK,CACL,KAAA,CAAM,GAAG,aAAa,CAAA;AAAA,EAC3B,CAAA,CAAA,OAAQ,CAAA,EAAA;AACN,IAAA,OAAO,EAAA;AAAA,EACT;AACF;AAQO,IAAM,iBAAA,GAAoB;AAG1B,IAAM,QAAA,GAAW;AAGjB,IAAM,WAAA,GAAc,wBAAA;AAK3B,SAAS,WAAA,CAAY,IAAe,QAAA,EAA2B;AAC7D,EAAA,IAAI;AACF,IAAA,OAAO,OAAO,EAAA,CAAG,OAAA,KAAY,cAAc,EAAA,CAAG,OAAA,CAAQ,QAAQ,CAAA,IAAK,IAAA;AAAA,EACrE,CAAA,CAAA,OAAQ,CAAA,EAAA;AAIN,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAOO,SAAS,gBAAA,CACd,EAAA,EACA,cAAA,GAAoC,EAAC,EAC5B;AACT,EAAA,IAAI,CAAC,EAAA,IAAM,OAAO,EAAA,CAAG,OAAA,KAAY,YAAY,OAAO,KAAA;AACpD,EAAA,IAAI,YAAY,EAAA,EAAI,CAAA,CAAA,EAAI,WAAW,CAAA,CAAA,CAAG,GAAG,OAAO,IAAA;AAChD,EAAA,KAAA,MAAW,OAAO,cAAA,EAAgB;AAChC,IAAA,IAAI,GAAA,IAAO,WAAA,CAAY,EAAA,EAAI,GAAG,GAAG,OAAO,IAAA;AAAA,EAC1C;AACA,EAAA,OAAO,KAAA;AACT;AAOO,SAAS,qBAAA,CACd,EAAA,EACA,eAAA,GAAqC,EAAC,EAC7B;AACT,EAAA,IAAI,CAAC,EAAA,IAAM,OAAO,EAAA,CAAG,OAAA,KAAY,YAAY,OAAO,KAAA;AACpD,EAAA,KAAA,MAAW,OAAO,eAAA,EAAiB;AACjC,IAAA,IAAI,GAAA,IAAO,WAAA,CAAY,EAAA,EAAI,GAAG,GAAG,OAAO,IAAA;AAAA,EAC1C;AACA,EAAA,OAAO,KAAA;AACT","file":"chunk-4PADVIIO.js","sourcesContent":["// Redaction — mask sensitive text before it ever leaves the page (GOV-3). The\n// pure string helpers are unit-tested; the DOM-querying part (selector masking)\n// lives in capture.ts and calls in here.\n\nconst EMAIL_RE = /[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}/g;\nconst LONG_DIGITS_RE = /\\d{6,}/g; // card / account-number-ish runs\n\nexport const MAX_LABEL_LEN = 280;\n\n/**\n * Mask PII-ish substrings in a captured label/verbatim and clamp length.\n * Conservative: emails and long digit runs become placeholders. Never throws.\n */\nexport function redactText(input: string | null | undefined): string {\n if (!input) return \"\";\n try {\n return String(input)\n .replace(EMAIL_RE, \"‹email›\")\n .replace(LONG_DIGITS_RE, \"‹num›\")\n .replace(/\\s+/g, \" \")\n .trim()\n .slice(0, MAX_LABEL_LEN);\n } catch {\n return \"\";\n }\n}\n\n/** Should a captured element's value be dropped entirely (not just masked)? */\nexport function isSensitiveInput(type: string | null | undefined): boolean {\n const t = (type ?? \"\").toLowerCase();\n return t === \"password\" || t === \"email\" || t === \"tel\" || t === \"creditcard\";\n}\n\nexport const ATTACH_DISCLOSURE = \"Session and account attached automatically.\";\n\n/** Placeholder substituted for the text of a `redact`-matched element (GOV-3). */\nexport const REDACTED = \"‹redacted›\";\n\n/** The per-element opt-out attribute: a click/input inside `[data-sightspool-ignore]` is dropped entirely. */\nexport const IGNORE_ATTR = \"data-sightspool-ignore\";\n\n/** Anything with a `.closest(selector)` — the bit of Element we depend on (kept DOM-free for unit tests). */\ntype Closeable = { closest?: (selectors: string) => unknown };\n\nfunction safeClosest(el: Closeable, selector: string): boolean {\n try {\n return typeof el.closest === \"function\" && el.closest(selector) != null;\n } catch {\n // An invalid selector (host misconfig) must never throw into capture — and must\n // never *accidentally capture* what was meant to be excluded: treat as no-match\n // for that one selector and let the others decide.\n return false;\n }\n}\n\n/**\n * Should this element's events be dropped entirely (not just masked)? True when the\n * element — or any ancestor — carries `data-sightspool-ignore` or matches one of the\n * configured `block` selectors. The host's hard privacy opt-out (GOV-3).\n */\nexport function isIgnoredElement(\n el: Closeable | null | undefined,\n blockSelectors: readonly string[] = [],\n): boolean {\n if (!el || typeof el.closest !== \"function\") return false;\n if (safeClosest(el, `[${IGNORE_ATTR}]`)) return true;\n for (const sel of blockSelectors) {\n if (sel && safeClosest(el, sel)) return true;\n }\n return false;\n}\n\n/**\n * Should this element's captured text be masked wholesale? True when the element —\n * or any ancestor — matches one of the configured `redact` selectors. (The event is\n * still recorded; only its label becomes {@link REDACTED}.)\n */\nexport function matchesRedactSelector(\n el: Closeable | null | undefined,\n redactSelectors: readonly string[] = [],\n): boolean {\n if (!el || typeof el.closest !== \"function\") return false;\n for (const sel of redactSelectors) {\n if (sel && safeClosest(el, sel)) return true;\n }\n return false;\n}\n"]}
@@ -1,139 +0,0 @@
1
- import { ATTACH_DISCLOSURE } from './chunk-4PADVIIO.js';
2
-
3
- // src/prompt.ts
4
- var STYLE = `
5
- :host { all: initial; }
6
- .wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;
7
- width: 320px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }
8
- .card { background: #fff; color: #18181b; border: 1px solid #e4e4e7; border-radius: 12px;
9
- box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }
10
- .q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; }
11
- .row { display: flex; gap: 8px; flex-wrap: wrap; }
12
- button { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;
13
- border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }
14
- button:hover { background: #f4f4f5; }
15
- button.primary { background: #18181b; color: #fff; border-color: #18181b; }
16
- .cand { display: block; width: 100%; text-align: left; margin-bottom: 6px; }
17
- .disc { font-size: 11px; color: #71717a; margin: 12px 0 0; }
18
- .x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;
19
- color: #a1a1aa; padding: 2px 6px; }
20
- input { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;
21
- border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }
22
- `;
23
- function showPrompt(opts) {
24
- return new Promise((resolve) => {
25
- if (typeof document === "undefined") {
26
- resolve({ answer: "dismissed" });
27
- return;
28
- }
29
- let settled = false;
30
- const host = document.createElement("div");
31
- const shadow = host.attachShadow({ mode: "open" });
32
- function finish(result) {
33
- if (settled) return;
34
- settled = true;
35
- try {
36
- host.remove();
37
- } catch (e) {
38
- }
39
- resolve(result);
40
- }
41
- const style = document.createElement("style");
42
- style.textContent = STYLE;
43
- shadow.appendChild(style);
44
- const wrap = document.createElement("div");
45
- wrap.className = "wrap";
46
- shadow.appendChild(wrap);
47
- function render(node) {
48
- wrap.innerHTML = "";
49
- const card = document.createElement("div");
50
- card.className = "card";
51
- card.style.position = "relative";
52
- const x = document.createElement("button");
53
- x.className = "x";
54
- x.textContent = "\xD7";
55
- x.setAttribute("aria-label", "Dismiss");
56
- x.onclick = () => finish({ answer: "dismissed" });
57
- card.appendChild(x);
58
- card.appendChild(node);
59
- const disc = document.createElement("p");
60
- disc.className = "disc";
61
- disc.textContent = ATTACH_DISCLOSURE;
62
- card.appendChild(disc);
63
- wrap.appendChild(card);
64
- }
65
- function stateA() {
66
- const node = document.createElement("div");
67
- const q = document.createElement("p");
68
- q.className = "q";
69
- q.textContent = "Were you able to do what you came here to do today?";
70
- node.appendChild(q);
71
- const row = document.createElement("div");
72
- row.className = "row";
73
- const yes = document.createElement("button");
74
- yes.className = "primary";
75
- yes.textContent = "Yes";
76
- yes.onclick = () => finish({ answer: "yes" });
77
- const no = document.createElement("button");
78
- no.textContent = "Not really";
79
- no.onclick = () => stateB();
80
- row.append(yes, no);
81
- node.appendChild(row);
82
- render(node);
83
- }
84
- function stateB() {
85
- const node = document.createElement("div");
86
- const q = document.createElement("p");
87
- q.className = "q";
88
- q.textContent = "What were you trying to do?";
89
- node.appendChild(q);
90
- for (const c of opts.candidates.slice(0, 4)) {
91
- const b = document.createElement("button");
92
- b.className = "cand";
93
- b.textContent = c;
94
- b.onclick = () => finish({ answer: "not_really", intent: c });
95
- node.appendChild(b);
96
- }
97
- const se = document.createElement("button");
98
- se.className = "cand";
99
- se.textContent = "Something else\u2026";
100
- se.onclick = () => stateText();
101
- node.appendChild(se);
102
- render(node);
103
- }
104
- function stateText() {
105
- const node = document.createElement("div");
106
- const q = document.createElement("p");
107
- q.className = "q";
108
- q.textContent = "What were you trying to do?";
109
- node.appendChild(q);
110
- const input = document.createElement("input");
111
- input.type = "text";
112
- input.placeholder = "In your own words\u2026";
113
- node.appendChild(input);
114
- const row = document.createElement("div");
115
- row.className = "row";
116
- const submit = document.createElement("button");
117
- submit.className = "primary";
118
- submit.textContent = "Send";
119
- submit.onclick = () => finish({ answer: "not_really", verbatim: input.value.trim() || void 0 });
120
- row.appendChild(submit);
121
- node.appendChild(row);
122
- render(node);
123
- try {
124
- input.focus();
125
- } catch (e) {
126
- }
127
- }
128
- try {
129
- document.body.appendChild(host);
130
- stateA();
131
- } catch (e) {
132
- finish({ answer: "dismissed" });
133
- }
134
- });
135
- }
136
-
137
- export { showPrompt };
138
- //# sourceMappingURL=prompt-GDFYC75D.js.map
139
- //# sourceMappingURL=prompt-GDFYC75D.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/prompt.ts"],"names":[],"mappings":"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","file":"prompt-GDFYC75D.js","sourcesContent":["// The prompt UI (FR-5/6, the §16.2 blend) — rendered in a shadow root so the host\n// app's CSS can't style-break it and it leaks zero styles back. This module is\n// dynamically imported by index.ts only when a trigger fires, so it splits into a\n// lazily-loaded chunk and adds nothing to the host bundle until needed.\n//\n// State A — \"Were you able to do what you came here to do today?\" [Yes][Not really]\n// State B — (after \"Not really\") top candidate goals + an always-present\n// \"Something else\" → optional free text only after that.\n\nimport type { SignalAnswer } from \"./types\";\nimport { ATTACH_DISCLOSURE } from \"./privacy\";\n\nexport type PromptResult = {\n answer: SignalAnswer;\n intent?: string; // a tapped candidate\n verbatim?: string; // free text from \"Something else\"\n};\n\nexport type PromptOptions = {\n /** Locally-derived candidate goals (FR-5 State B). May be empty → generic ask. */\n candidates: string[];\n};\n\nconst STYLE = `\n:host { all: initial; }\n.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;\n width: 320px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }\n.card { background: #fff; color: #18181b; border: 1px solid #e4e4e7; border-radius: 12px;\n box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }\n.q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; }\n.row { display: flex; gap: 8px; flex-wrap: wrap; }\nbutton { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;\n border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }\nbutton:hover { background: #f4f4f5; }\nbutton.primary { background: #18181b; color: #fff; border-color: #18181b; }\n.cand { display: block; width: 100%; text-align: left; margin-bottom: 6px; }\n.disc { font-size: 11px; color: #71717a; margin: 12px 0 0; }\n.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;\n color: #a1a1aa; padding: 2px 6px; }\ninput { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;\n border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }\n`;\n\nexport function showPrompt(opts: PromptOptions): Promise<PromptResult> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\") {\n resolve({ answer: \"dismissed\" });\n return;\n }\n\n let settled = false;\n const host = document.createElement(\"div\");\n const shadow = host.attachShadow({ mode: \"open\" });\n\n function finish(result: PromptResult) {\n if (settled) return;\n settled = true;\n try {\n host.remove();\n } catch {\n /* swallow */\n }\n resolve(result);\n }\n\n const style = document.createElement(\"style\");\n style.textContent = STYLE;\n shadow.appendChild(style);\n\n const wrap = document.createElement(\"div\");\n wrap.className = \"wrap\";\n shadow.appendChild(wrap);\n\n function render(node: HTMLElement) {\n wrap.innerHTML = \"\";\n const card = document.createElement(\"div\");\n card.className = \"card\";\n card.style.position = \"relative\";\n const x = document.createElement(\"button\");\n x.className = \"x\";\n x.textContent = \"×\";\n x.setAttribute(\"aria-label\", \"Dismiss\");\n x.onclick = () => finish({ answer: \"dismissed\" });\n card.appendChild(x);\n card.appendChild(node);\n const disc = document.createElement(\"p\");\n disc.className = \"disc\";\n disc.textContent = ATTACH_DISCLOSURE;\n card.appendChild(disc);\n wrap.appendChild(card);\n }\n\n // --- State A ---\n function stateA() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"Were you able to do what you came here to do today?\";\n node.appendChild(q);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const yes = document.createElement(\"button\");\n yes.className = \"primary\";\n yes.textContent = \"Yes\";\n yes.onclick = () => finish({ answer: \"yes\" });\n const no = document.createElement(\"button\");\n no.textContent = \"Not really\";\n no.onclick = () => stateB();\n row.append(yes, no);\n node.appendChild(row);\n render(node);\n }\n\n // --- State B ---\n function stateB() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"What were you trying to do?\";\n node.appendChild(q);\n for (const c of opts.candidates.slice(0, 4)) {\n const b = document.createElement(\"button\");\n b.className = \"cand\";\n b.textContent = c;\n b.onclick = () => finish({ answer: \"not_really\", intent: c });\n node.appendChild(b);\n }\n const se = document.createElement(\"button\");\n se.className = \"cand\";\n se.textContent = \"Something else…\";\n se.onclick = () => stateText();\n node.appendChild(se);\n render(node);\n }\n\n // --- \"Something else\" free text ---\n function stateText() {\n const node = document.createElement(\"div\");\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = \"What were you trying to do?\";\n node.appendChild(q);\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.placeholder = \"In your own words…\";\n node.appendChild(input);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const submit = document.createElement(\"button\");\n submit.className = \"primary\";\n submit.textContent = \"Send\";\n submit.onclick = () =>\n finish({ answer: \"not_really\", verbatim: input.value.trim() || undefined });\n row.appendChild(submit);\n node.appendChild(row);\n render(node);\n try {\n input.focus();\n } catch {\n /* swallow */\n }\n }\n\n try {\n document.body.appendChild(host);\n stateA();\n } catch {\n finish({ answer: \"dismissed\" });\n }\n });\n}\n"]}
@@ -1,145 +0,0 @@
1
- // src/survey.ts
2
- var STYLE = `
3
- :host { all: initial; }
4
- .wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;
5
- width: 340px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }
6
- .card { position: relative; background: #fff; color: #18181b; border: 1px solid #e4e4e7;
7
- border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }
8
- .q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; padding-right: 16px; }
9
- .row { display: flex; gap: 8px; flex-wrap: wrap; }
10
- button { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;
11
- border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }
12
- button:hover { background: #f4f4f5; }
13
- button.primary { background: #18181b; color: #fff; border-color: #18181b; }
14
- .opt { display: block; width: 100%; text-align: left; margin-bottom: 6px; }
15
- .x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;
16
- color: #a1a1aa; padding: 2px 6px; cursor: pointer; }
17
- .done { font-size: 13px; color: #18181b; margin: 0; }
18
- input { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;
19
- border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }
20
- `;
21
- var THANKS_MS = 1100;
22
- function showSurvey(config) {
23
- return new Promise((resolve) => {
24
- if (typeof document === "undefined") {
25
- resolve({ dismissed: true });
26
- return;
27
- }
28
- let settled = false;
29
- const host = document.createElement("div");
30
- const shadow = host.attachShadow({ mode: "open" });
31
- function teardown() {
32
- try {
33
- host.remove();
34
- } catch (e) {
35
- }
36
- }
37
- function finish(result, thank) {
38
- if (settled) return;
39
- settled = true;
40
- resolve(result);
41
- if (thank) {
42
- thankYou();
43
- setTimeout(teardown, THANKS_MS);
44
- } else {
45
- teardown();
46
- }
47
- }
48
- const style = document.createElement("style");
49
- style.textContent = STYLE;
50
- shadow.appendChild(style);
51
- const wrap = document.createElement("div");
52
- wrap.className = "wrap";
53
- shadow.appendChild(wrap);
54
- function card() {
55
- wrap.innerHTML = "";
56
- const c = document.createElement("div");
57
- c.className = "card";
58
- wrap.appendChild(c);
59
- return c;
60
- }
61
- function withClose(c) {
62
- const x = document.createElement("button");
63
- x.className = "x";
64
- x.textContent = "\xD7";
65
- x.setAttribute("aria-label", "Dismiss");
66
- x.onclick = () => finish({ dismissed: true }, false);
67
- c.appendChild(x);
68
- }
69
- function question() {
70
- var _a, _b, _c;
71
- const c = card();
72
- withClose(c);
73
- const q = document.createElement("p");
74
- q.className = "q";
75
- q.textContent = config.question;
76
- c.appendChild(q);
77
- for (const opt of ((_a = config.options) != null ? _a : []).slice(0, 6)) {
78
- const b = document.createElement("button");
79
- b.className = "opt";
80
- b.textContent = opt;
81
- b.onclick = () => finish({ choice: opt }, true);
82
- c.appendChild(b);
83
- }
84
- if (config.allow_text) {
85
- const se = document.createElement("button");
86
- se.className = "opt";
87
- se.textContent = ((_c = (_b = config.options) == null ? void 0 : _b.length) != null ? _c : 0) > 0 ? "Something else\u2026" : "Answer\u2026";
88
- se.onclick = freeText;
89
- c.appendChild(se);
90
- }
91
- }
92
- function freeText() {
93
- const c = card();
94
- withClose(c);
95
- const q = document.createElement("p");
96
- q.className = "q";
97
- q.textContent = config.question;
98
- c.appendChild(q);
99
- const input = document.createElement("input");
100
- input.type = "text";
101
- input.placeholder = "In your own words\u2026";
102
- c.appendChild(input);
103
- const row = document.createElement("div");
104
- row.className = "row";
105
- const send = document.createElement("button");
106
- send.className = "primary";
107
- send.textContent = "Send";
108
- const submit = () => {
109
- const text = input.value.trim();
110
- if (!text) {
111
- finish({ dismissed: true }, false);
112
- return;
113
- }
114
- finish({ text }, true);
115
- };
116
- send.onclick = submit;
117
- input.onkeydown = (e) => {
118
- if (e.key === "Enter") submit();
119
- };
120
- row.appendChild(send);
121
- c.appendChild(row);
122
- try {
123
- input.focus();
124
- } catch (e) {
125
- }
126
- }
127
- function thankYou() {
128
- const c = card();
129
- const p = document.createElement("p");
130
- p.className = "done";
131
- p.textContent = "Thanks \u2014 that helps.";
132
- c.appendChild(p);
133
- }
134
- try {
135
- document.body.appendChild(host);
136
- question();
137
- } catch (e) {
138
- finish({ dismissed: true }, false);
139
- }
140
- });
141
- }
142
-
143
- export { showSurvey };
144
- //# sourceMappingURL=survey-CICJQ5VI.js.map
145
- //# sourceMappingURL=survey-CICJQ5VI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/survey.ts"],"names":[],"mappings":"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","file":"survey-CICJQ5VI.js","sourcesContent":["// The intervention survey widget (Wave 0005 slice B — the client half). Renders a\n// human-approved one-tap survey served by /api/sdk/serve, in a shadow root so the\n// host app's CSS can't style-break it and it leaks zero styles back. Dynamically\n// imported by index.ts only when the serve endpoint actually returns something, so\n// it splits into its own lazily-loaded chunk and adds nothing to the host bundle\n// until a survey is shown. Mirrors prompt.ts (the passive ask) deliberately.\n//\n// question + [option] [option] … (tap an option → choice)\n// + \"Something else…\" → free text (only when allow_text)\n\nexport type SurveyConfig = {\n question: string;\n options?: string[];\n allow_text?: boolean;\n};\n\nexport type SurveyResult = {\n choice?: string;\n text?: string;\n dismissed?: boolean;\n};\n\nconst STYLE = `\n:host { all: initial; }\n.wrap { position: fixed; bottom: 20px; right: 20px; z-index: 2147483000;\n width: 340px; max-width: calc(100vw - 32px); font-family: system-ui, -apple-system, sans-serif; }\n.card { position: relative; background: #fff; color: #18181b; border: 1px solid #e4e4e7;\n border-radius: 12px; box-shadow: 0 10px 30px rgba(0,0,0,.12); padding: 16px; }\n.q { font-size: 14px; font-weight: 600; margin: 0 0 12px; line-height: 1.35; padding-right: 16px; }\n.row { display: flex; gap: 8px; flex-wrap: wrap; }\nbutton { font: inherit; font-size: 13px; cursor: pointer; border-radius: 8px; padding: 8px 12px;\n border: 1px solid #e4e4e7; background: #fafafa; color: #18181b; }\nbutton:hover { background: #f4f4f5; }\nbutton.primary { background: #18181b; color: #fff; border-color: #18181b; }\n.opt { display: block; width: 100%; text-align: left; margin-bottom: 6px; }\n.x { position: absolute; top: 8px; right: 10px; border: none; background: none; font-size: 16px;\n color: #a1a1aa; padding: 2px 6px; cursor: pointer; }\n.done { font-size: 13px; color: #18181b; margin: 0; }\ninput { font: inherit; font-size: 13px; width: 100%; box-sizing: border-box; padding: 8px 10px;\n border: 1px solid #e4e4e7; border-radius: 8px; margin-bottom: 8px; }\n`;\n\nconst THANKS_MS = 1100; // brief acknowledgement, then auto-close\n\nexport function showSurvey(config: SurveyConfig): Promise<SurveyResult> {\n return new Promise((resolve) => {\n if (typeof document === \"undefined\") {\n resolve({ dismissed: true });\n return;\n }\n\n let settled = false;\n const host = document.createElement(\"div\");\n const shadow = host.attachShadow({ mode: \"open\" });\n\n function teardown() {\n try {\n host.remove();\n } catch {\n /* swallow */\n }\n }\n\n // Resolve immediately (so the answer is sent without delay) but leave a short\n // \"Thanks\" on screen before removing the node.\n function finish(result: SurveyResult, thank: boolean) {\n if (settled) return;\n settled = true;\n resolve(result);\n if (thank) {\n thankYou();\n setTimeout(teardown, THANKS_MS);\n } else {\n teardown();\n }\n }\n\n const style = document.createElement(\"style\");\n style.textContent = STYLE;\n shadow.appendChild(style);\n\n const wrap = document.createElement(\"div\");\n wrap.className = \"wrap\";\n shadow.appendChild(wrap);\n\n function card(): HTMLElement {\n wrap.innerHTML = \"\";\n const c = document.createElement(\"div\");\n c.className = \"card\";\n wrap.appendChild(c);\n return c;\n }\n\n function withClose(c: HTMLElement) {\n const x = document.createElement(\"button\");\n x.className = \"x\";\n x.textContent = \"×\";\n x.setAttribute(\"aria-label\", \"Dismiss\");\n x.onclick = () => finish({ dismissed: true }, false);\n c.appendChild(x);\n }\n\n function question() {\n const c = card();\n withClose(c);\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = config.question;\n c.appendChild(q);\n\n for (const opt of (config.options ?? []).slice(0, 6)) {\n const b = document.createElement(\"button\");\n b.className = \"opt\";\n b.textContent = opt;\n b.onclick = () => finish({ choice: opt }, true);\n c.appendChild(b);\n }\n\n if (config.allow_text) {\n const se = document.createElement(\"button\");\n se.className = \"opt\";\n // If there were no options, this is the only path — label it plainly.\n se.textContent = (config.options?.length ?? 0) > 0 ? \"Something else…\" : \"Answer…\";\n se.onclick = freeText;\n c.appendChild(se);\n }\n }\n\n function freeText() {\n const c = card();\n withClose(c);\n const q = document.createElement(\"p\");\n q.className = \"q\";\n q.textContent = config.question;\n c.appendChild(q);\n const input = document.createElement(\"input\");\n input.type = \"text\";\n input.placeholder = \"In your own words…\";\n c.appendChild(input);\n const row = document.createElement(\"div\");\n row.className = \"row\";\n const send = document.createElement(\"button\");\n send.className = \"primary\";\n send.textContent = \"Send\";\n const submit = () => {\n const text = input.value.trim();\n if (!text) {\n finish({ dismissed: true }, false);\n return;\n }\n finish({ text }, true);\n };\n send.onclick = submit;\n input.onkeydown = (e) => {\n if ((e as KeyboardEvent).key === \"Enter\") submit();\n };\n row.appendChild(send);\n c.appendChild(row);\n try {\n input.focus();\n } catch {\n /* swallow */\n }\n }\n\n function thankYou() {\n const c = card();\n const p = document.createElement(\"p\");\n p.className = \"done\";\n p.textContent = \"Thanks — that helps.\";\n c.appendChild(p);\n }\n\n try {\n document.body.appendChild(host);\n question();\n } catch {\n finish({ dismissed: true }, false);\n }\n });\n}\n"]}