@qaiddev/quests-embed 1.0.0 → 1.0.1

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.
@@ -1 +1 @@
1
- {"version":3,"file":"qaid-quests.js","sources":["../src/styles.ts","../src/inputs.ts","../src/visibility.ts","../src/embed.ts","../src/index.ts"],"sourcesContent":["/**\n * CSS variable + style helpers for the questionnaire embed.\n *\n * Variable names match @qaiddev/thumbs-embed so a theme written for\n * one embed renders identically in the other:\n * --qaid-positive, --qaid-negative, --qaid-marker\n * --qaid-modal-width, --qaid-backdrop-opacity\n * --qaid-font-family, --qaid-font-size\n */\n\nimport shadowStyles from \"./styles-shadow.css?inline\";\n\nexport interface BuildCssVarsOptions {\n positiveColor?: string;\n negativeColor?: string;\n markerColor?: string;\n modalWidth?: number;\n backdropOpacity?: number;\n fontFamily?: string;\n fontSize?: number;\n}\n\nfunction getLuminance(r: number, g: number, b: number): number {\n const [rs, gs, bs] = [r, g, b].map((c) => {\n c = c / 255;\n return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n\nfunction parseColor(color: string): { r: number; g: number; b: number } | null {\n if (color.startsWith(\"#\")) {\n const hex = color.slice(1);\n const fullHex =\n hex.length === 3\n ? hex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\")\n : hex;\n const num = parseInt(fullHex, 16);\n return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };\n }\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n return { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) };\n }\n return null;\n}\n\nfunction getContrastTextColor(bgColor: string): string {\n const rgb = parseColor(bgColor);\n if (!rgb) return \"white\";\n return getLuminance(rgb.r, rgb.g, rgb.b) > 0.4 ? \"black\" : \"white\";\n}\n\nexport function buildCssVars(options: BuildCssVarsOptions = {}): Record<string, string> {\n const {\n positiveColor = \"#10b981\",\n negativeColor = \"#ef4444\",\n markerColor = \"#6366f1\",\n modalWidth = 480,\n backdropOpacity = 0.4,\n fontFamily = \"system-ui, -apple-system, sans-serif\",\n fontSize = 16,\n } = options;\n\n return {\n \"--qaid-positive\": positiveColor,\n \"--qaid-positive-text\": getContrastTextColor(positiveColor),\n \"--qaid-negative\": negativeColor,\n \"--qaid-marker\": markerColor,\n \"--qaid-marker-text\": getContrastTextColor(markerColor),\n \"--qaid-modal-width\": `${modalWidth}px`,\n \"--qaid-backdrop-opacity\": String(backdropOpacity),\n \"--qaid-font-family\": fontFamily,\n \"--qaid-font-size\": `${fontSize}px`,\n };\n}\n\nexport function applyCssVars(el: HTMLElement, vars: Record<string, string>): void {\n for (const [name, value] of Object.entries(vars)) {\n el.style.setProperty(name, value);\n }\n}\n\n/** CSS string injected into every shadow root */\nexport function getEmbedStyles(): string {\n return shadowStyles;\n}\n","/**\n * Input renderers for each question type.\n *\n * Each renderer returns a small object with an element to mount, a\n * focus helper, a synchronous current-value reader, and a validator.\n *\n * Per-keystroke autosave is wired by the embed: the renderer just\n * calls back into onChange whenever its underlying value changes.\n * Renderers also call onSubmit when the user presses Enter (or\n * onAutoAdvance after a discrete selection that should auto-advance).\n */\n\nimport type {\n AnswerValue,\n CurrencyQuestion,\n DateQuestion,\n MultipleChoiceQuestion,\n Question,\n RangeQuestion,\n TextQuestion,\n} from \"./types\";\n\nexport interface QuestionInput {\n element: HTMLElement;\n focus(): void;\n getValue(): AnswerValue;\n isValid(): boolean;\n}\n\nexport interface QuestionInputOptions {\n question: Question;\n initialValue: AnswerValue;\n /** Called any time the value changes (every keystroke for text). */\n onChange: (value: AnswerValue) => void;\n /** Called when the user presses Enter to advance. */\n onSubmit: () => void;\n /**\n * Called after a discrete selection that should auto-advance\n * (e.g. picking a single-choice option when autoAdvance is on).\n */\n onAutoAdvance: () => void;\n /** Whether the embed is configured to auto-advance after discrete selections */\n autoAdvance: boolean;\n}\n\nexport function createInput(options: QuestionInputOptions): QuestionInput {\n switch (options.question.type) {\n case \"text\":\n return createTextInput(options.question, options);\n case \"currency\":\n return createCurrencyInput(options.question, options);\n case \"range\":\n return createRangeInput(options.question, options);\n case \"date\":\n return createDateInput(options.question, options);\n case \"multiple-choice\":\n return createMultipleChoiceInput(options.question, options);\n }\n}\n\n// ====================================================================\n// Text\n// ====================================================================\n\nfunction createTextInput(\n q: TextQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const initial = typeof opts.initialValue === \"string\" ? opts.initialValue : \"\";\n\n let el: HTMLInputElement | HTMLTextAreaElement;\n\n if (q.multiline) {\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"qaid-q-textarea\";\n textarea.value = initial;\n if (q.placeholder) textarea.placeholder = q.placeholder;\n if (q.maxLength) textarea.maxLength = q.maxLength;\n el = textarea;\n } else {\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n input.type = q.inputType ?? \"text\";\n input.value = initial;\n if (q.placeholder) input.placeholder = q.placeholder;\n if (q.maxLength) input.maxLength = q.maxLength;\n input.setAttribute(\"autocomplete\", inputAutocomplete(q.inputType));\n el = input;\n }\n\n el.setAttribute(\"aria-label\", q.label);\n\n el.addEventListener(\"input\", () => {\n opts.onChange(el.value);\n });\n\n el.addEventListener(\"keydown\", ((e: KeyboardEvent) => {\n if (e.key !== \"Enter\") return;\n if (q.multiline) {\n // In multiline, Enter inserts newline; Cmd/Ctrl+Enter submits.\n if (e.metaKey || e.ctrlKey) {\n e.preventDefault();\n opts.onSubmit();\n }\n return;\n }\n // Single-line: Enter submits, but allow IME composition to finish first.\n if (e.isComposing) return;\n e.preventDefault();\n opts.onSubmit();\n }) as EventListener);\n\n return {\n element: el,\n focus: () => {\n el.focus();\n // Place cursor at end so user can keep typing.\n const len = el.value.length;\n try {\n el.setSelectionRange(len, len);\n } catch {\n // input types like email may not support selectionRange\n }\n },\n getValue: () => el.value,\n isValid: () => {\n if (!q.required) return true;\n const v = el.value.trim();\n if (v.length === 0) return false;\n if (q.minLength && v.length < q.minLength) return false;\n return true;\n },\n };\n}\n\nfunction inputAutocomplete(t?: TextQuestion[\"inputType\"]): string {\n switch (t) {\n case \"email\":\n return \"email\";\n case \"tel\":\n return \"tel\";\n case \"url\":\n return \"url\";\n default:\n return \"off\";\n }\n}\n\n// ====================================================================\n// Currency\n// ====================================================================\n\nfunction createCurrencyInput(\n q: CurrencyQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n wrap.className = \"qaid-q-currency\";\n\n const prefix = document.createElement(\"span\");\n prefix.className = \"qaid-q-currency-prefix\";\n prefix.textContent = currencySymbol(q.currency ?? \"USD\", q.locale);\n wrap.appendChild(prefix);\n\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n // type=\"number\" gives native numeric keyboard + min/max validation hooks.\n input.type = \"number\";\n input.inputMode = \"decimal\";\n input.step = \"0.01\";\n if (typeof q.min === \"number\") input.min = String(q.min);\n if (typeof q.max === \"number\") input.max = String(q.max);\n if (q.placeholder) input.placeholder = q.placeholder;\n if (typeof opts.initialValue === \"number\") input.value = String(opts.initialValue);\n else if (typeof opts.initialValue === \"string\" && opts.initialValue !== \"\")\n input.value = opts.initialValue;\n input.setAttribute(\"aria-label\", q.label);\n\n input.addEventListener(\"input\", () => {\n const raw = input.value;\n if (raw === \"\") {\n opts.onChange(null);\n } else {\n const num = Number(raw);\n opts.onChange(Number.isNaN(num) ? null : num);\n }\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !(e as KeyboardEvent).isComposing) {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n wrap.appendChild(input);\n\n return {\n element: wrap,\n focus: () => input.focus(),\n getValue: () => {\n if (input.value === \"\") return null;\n const num = Number(input.value);\n return Number.isNaN(num) ? null : num;\n },\n isValid: () => {\n const v = input.value === \"\" ? null : Number(input.value);\n if (q.required && (v === null || Number.isNaN(v as number))) return false;\n if (v !== null && !Number.isNaN(v as number)) {\n if (typeof q.min === \"number\" && (v as number) < q.min) return false;\n if (typeof q.max === \"number\" && (v as number) > q.max) return false;\n }\n return true;\n },\n };\n}\n\nfunction currencySymbol(currency: string, locale?: string): string {\n try {\n const fmt = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n currencyDisplay: \"narrowSymbol\",\n maximumFractionDigits: 0,\n });\n // Pull the symbol out of a formatted zero\n const parts = fmt.formatToParts(0);\n const sym = parts.find((p) => p.type === \"currency\");\n return sym?.value ?? currency;\n } catch {\n return currency;\n }\n}\n\n// ====================================================================\n// Range\n// ====================================================================\n\nfunction createRangeInput(\n q: RangeQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n wrap.className = \"qaid-q-range-wrap\";\n\n const valueDisplay = document.createElement(\"div\");\n valueDisplay.className = \"qaid-q-range-value\";\n\n const valueText = document.createElement(\"span\");\n valueDisplay.appendChild(valueText);\n\n if (q.unit) {\n const unit = document.createElement(\"span\");\n unit.className = \"qaid-q-range-unit\";\n unit.textContent = q.unit;\n valueDisplay.appendChild(unit);\n }\n\n const initial =\n typeof opts.initialValue === \"number\"\n ? opts.initialValue\n : (q.defaultValue ?? q.min);\n\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-range\";\n input.type = \"range\";\n input.min = String(q.min);\n input.max = String(q.max);\n input.step = String(q.step ?? 1);\n input.value = String(initial);\n input.setAttribute(\"aria-label\", q.label);\n input.setAttribute(\"aria-valuemin\", String(q.min));\n input.setAttribute(\"aria-valuemax\", String(q.max));\n\n const updateDisplay = () => {\n valueText.textContent = input.value;\n input.setAttribute(\"aria-valuenow\", input.value);\n };\n updateDisplay();\n\n input.addEventListener(\"input\", () => {\n updateDisplay();\n opts.onChange(Number(input.value));\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n const bounds = document.createElement(\"div\");\n bounds.className = \"qaid-q-range-bounds\";\n const lower = document.createElement(\"span\");\n lower.textContent = `${q.min}${q.unit ?? \"\"}`;\n const upper = document.createElement(\"span\");\n upper.textContent = `${q.max}${q.unit ?? \"\"}`;\n bounds.appendChild(lower);\n bounds.appendChild(upper);\n\n wrap.appendChild(valueDisplay);\n wrap.appendChild(input);\n wrap.appendChild(bounds);\n\n // Push the initial value to onChange so first interaction is recorded\n // even if the user presses Enter without dragging.\n // (Defer to the next tick so the embed has wired up its handler.)\n queueMicrotask(() => opts.onChange(Number(input.value)));\n\n return {\n element: wrap,\n focus: () => input.focus(),\n getValue: () => Number(input.value),\n isValid: () => true,\n };\n}\n\n// ====================================================================\n// Date\n// ====================================================================\n\nfunction createDateInput(q: DateQuestion, opts: QuestionInputOptions): QuestionInput {\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n input.type = \"date\";\n if (q.min) input.min = q.min;\n if (q.max) input.max = q.max;\n if (typeof opts.initialValue === \"string\") input.value = opts.initialValue;\n input.setAttribute(\"aria-label\", q.label);\n\n input.addEventListener(\"input\", () => {\n opts.onChange(input.value || null);\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !(e as KeyboardEvent).isComposing) {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n return {\n element: input,\n focus: () => input.focus(),\n getValue: () => input.value || null,\n isValid: () => {\n if (!q.required) return true;\n return input.value !== \"\";\n },\n };\n}\n\n// ====================================================================\n// Multiple choice\n// ====================================================================\n\nfunction createMultipleChoiceInput(\n q: MultipleChoiceQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n const alignment = q.imageAlignment ?? \"horizontal\";\n const hasAnyImage = q.options.some((o) => !!o.image);\n const layoutClass = hasAnyImage\n ? alignment === \"vertical\"\n ? \" qaid-q-options--image-vertical\"\n : \" qaid-q-options--image-horizontal\"\n : \"\";\n wrap.className = `qaid-q-options${layoutClass}`;\n wrap.setAttribute(\"role\", q.multiple ? \"group\" : \"radiogroup\");\n wrap.setAttribute(\"aria-label\", q.label);\n\n // Normalize initial selection to a Set for both modes\n const selected = new Set<string>();\n if (q.multiple && Array.isArray(opts.initialValue)) {\n for (const v of opts.initialValue) selected.add(v);\n } else if (!q.multiple && typeof opts.initialValue === \"string\") {\n selected.add(opts.initialValue);\n }\n\n const buttons: HTMLButtonElement[] = [];\n\n q.options.forEach((opt, idx) => {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = `qaid-q-option${q.multiple ? \" qaid-q-multi\" : \"\"}`;\n btn.dataset.value = opt.value;\n btn.setAttribute(\"role\", q.multiple ? \"checkbox\" : \"radio\");\n btn.setAttribute(\"aria-checked\", selected.has(opt.value) ? \"true\" : \"false\");\n if (selected.has(opt.value)) btn.classList.add(\"qaid-q-selected\");\n\n const marker = document.createElement(\"span\");\n marker.className = \"qaid-q-option-marker\";\n marker.setAttribute(\"aria-hidden\", \"true\");\n\n const body = document.createElement(\"span\");\n body.className = \"qaid-q-option-body\";\n\n if (opt.image) {\n const img = document.createElement(\"img\");\n img.className = \"qaid-q-option-image\";\n img.src = opt.image;\n img.alt = \"\";\n img.loading = \"lazy\";\n img.decoding = \"async\";\n body.appendChild(img);\n }\n\n const label = document.createElement(\"span\");\n label.className = \"qaid-q-option-label\";\n label.textContent = opt.label;\n body.appendChild(label);\n\n if (opt.description) {\n const desc = document.createElement(\"span\");\n desc.className = \"qaid-q-option-desc\";\n desc.textContent = opt.description;\n body.appendChild(desc);\n }\n\n btn.appendChild(marker);\n btn.appendChild(body);\n\n if (idx < 9) {\n const key = document.createElement(\"span\");\n key.className = \"qaid-q-option-key\";\n key.textContent = String(idx + 1);\n key.setAttribute(\"aria-hidden\", \"true\");\n btn.appendChild(key);\n }\n\n btn.addEventListener(\"click\", () => toggle(idx));\n\n btn.addEventListener(\"keydown\", (e) => {\n // Native button handles Space/Enter; we add arrow-key roving focus\n // and Enter-to-advance for single-choice.\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n focusOption((idx + 1) % buttons.length);\n return;\n }\n if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n focusOption((idx - 1 + buttons.length) % buttons.length);\n return;\n }\n if (!q.multiple && e.key === \"Enter\") {\n // If something is already selected, advance instead of toggling\n if (selected.size > 0) {\n e.preventDefault();\n opts.onSubmit();\n }\n }\n });\n\n buttons.push(btn);\n wrap.appendChild(btn);\n });\n\n // Number-key shortcuts (1-9) at the wrap level\n wrap.addEventListener(\"keydown\", (e) => {\n const k = e.key;\n if (k.length === 1 && k >= \"1\" && k <= \"9\") {\n const idx = parseInt(k, 10) - 1;\n if (idx < buttons.length) {\n e.preventDefault();\n toggle(idx);\n focusOption(idx);\n }\n }\n });\n\n function focusOption(idx: number): void {\n buttons[idx]?.focus();\n }\n\n function toggle(idx: number): void {\n const value = q.options[idx].value;\n if (q.multiple) {\n if (selected.has(value)) selected.delete(value);\n else selected.add(value);\n } else {\n selected.clear();\n selected.add(value);\n }\n // Update DOM state\n buttons.forEach((b) => {\n const v = b.dataset.value!;\n const on = selected.has(v);\n b.classList.toggle(\"qaid-q-selected\", on);\n b.setAttribute(\"aria-checked\", on ? \"true\" : \"false\");\n });\n opts.onChange(currentValue());\n if (!q.multiple && opts.autoAdvance) {\n // Tiny delay so the user sees the selection animation before advancing.\n setTimeout(() => opts.onAutoAdvance(), 180);\n }\n }\n\n function currentValue(): AnswerValue {\n if (q.multiple) return Array.from(selected);\n const it = selected.values().next();\n return it.done ? null : it.value;\n }\n\n return {\n element: wrap,\n focus: () => {\n // Focus the first selected option, or the first option overall.\n const firstSelected = buttons.find((b) => b.classList.contains(\"qaid-q-selected\"));\n (firstSelected ?? buttons[0])?.focus();\n },\n getValue: () => currentValue(),\n isValid: () => {\n if (!q.required) return true;\n return selected.size > 0;\n },\n };\n}\n","/**\n * Pure helpers for evaluating per-question visibility predicates.\n *\n * `getVisibleQuestions` filters a questionnaire's flat question array down\n * to those whose `visibleIf` predicate currently evaluates to true. A\n * question with no `visibleIf` is always visible.\n *\n * Predicates are evaluated against the answers map (the same shape the\n * embed maintains internally and posts on submit). They never throw — a\n * predicate referencing an unknown questionId resolves as if that\n * question is unanswered.\n */\n\nimport type {\n AnswerValue,\n Answers,\n Question,\n Questionnaire,\n VisibilityRule,\n} from \"./types\";\n\nexport function getVisibleQuestions(\n q: Questionnaire,\n answers: Answers,\n): Question[] {\n return q.questions.filter((qn) =>\n qn.visibleIf ? evaluateRule(qn.visibleIf, answers) : true,\n );\n}\n\nexport function evaluateRule(\n rule: VisibilityRule,\n answers: Answers,\n): boolean {\n if (\"allOf\" in rule) {\n // Empty allOf is vacuously true; the validator rejects empty arrays\n // at authoring time, so this branch only matters for inline /\n // unvalidated questionnaires.\n for (const r of rule.allOf) {\n if (!evaluateRule(r, answers)) return false;\n }\n return true;\n }\n if (\"anyOf\" in rule) {\n for (const r of rule.anyOf) {\n if (evaluateRule(r, answers)) return true;\n }\n return false;\n }\n\n const v = answers[rule.questionId];\n // Empty string and empty array count as \"not answered\" so a follow-up\n // doesn't flash visible the moment a text input is focused.\n const isAnswered =\n v !== null &&\n v !== undefined &&\n !(typeof v === \"string\" && v.trim() === \"\") &&\n !(Array.isArray(v) && v.length === 0);\n\n if (\"answered\" in rule) return rule.answered ? isAnswered : !isAnswered;\n\n // Value-comparison atoms against an unanswered question return false\n // — including notEquals, so a \"show this when X is not Y\" follow-up\n // doesn't reveal itself before X has been answered at all.\n if (!isAnswered) return false;\n\n if (\"equals\" in rule) return matchesAtomic(v, rule.equals);\n if (\"notEquals\" in rule) return !matchesAtomic(v, rule.notEquals);\n if (\"in\" in rule) return rule.in.some((x) => matchesAtomic(v, x));\n return false;\n}\n\nfunction matchesAtomic(\n answer: AnswerValue,\n target: string | number,\n): boolean {\n // Multi-select multiple-choice answers are arrays; treat equality as\n // \"target is one of the selected values.\"\n if (Array.isArray(answer)) return answer.some((a) => a === target);\n return answer === target;\n}\n","import type {\n Answers,\n AnswerValue,\n CreateResponseResult,\n Question,\n Questionnaire,\n QuestsConfig,\n ResolvedQuestsConfig,\n} from \"./types\";\nimport { applyCssVars, buildCssVars, getEmbedStyles } from \"./styles\";\nimport { createInput, type QuestionInput } from \"./inputs\";\nimport { getVisibleQuestions } from \"./visibility\";\n\nconst VISITOR_ID_KEY = \"qaid_visitor_id\";\n\ntype EmbedState = \"LOADING\" | \"READY\" | \"DONE\" | \"ERROR\";\n\nfunction getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_ID_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_ID_KEY, id);\n }\n return id;\n } catch {\n return crypto.randomUUID();\n }\n}\n\nconst CLOSE_ICON = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\"><path d=\"M2 2l10 10M12 2L2 12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" fill=\"none\"/></svg>`;\nconst CHECK_ICON = `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M5 12l4 4L19 7\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/></svg>`;\n\nexport class QaidQuests {\n private config: ResolvedQuestsConfig;\n private questionnaire: Questionnaire | null = null;\n private inlineQuestionnaire: Questionnaire | undefined;\n private configUrl: string | undefined;\n\n private state: EmbedState = \"LOADING\";\n private stepIndex = 0;\n // Cached subset of questionnaire.questions that are currently visible\n // given the answers so far. Recomputed on every answer change so\n // stepIndex always indexes into THIS list, not the raw question array.\n private visibleQuestions: Question[] = [];\n // Latched goToStep request when called before init finishes. Applied\n // once the questionnaire + visible list are ready.\n private pendingGoToStep: string | null = null;\n // True after the first step has rendered. Used so the focus-on-step\n // logic in renderStep() can distinguish initial mount (driven by the\n // `autoFocus` config) from subsequent step changes (always focused so\n // keyboard + screen-reader users land on the active input after Next\n // / Back).\n private hasRenderedStep = false;\n private answers: Answers = {};\n private responseId: string | number | null = null;\n private visitorId: string;\n\n // Per-question pending autosave (text/currency are debounced)\n private pendingSaveTimer: ReturnType<typeof setTimeout> | null = null;\n private pendingSaveQuestionId: string | null = null;\n private pendingSaveValue: AnswerValue = null;\n private inflightSaves = 0;\n\n // Shadow DOM\n private shadowHost: HTMLDivElement | null = null;\n private shadowRoot: ShadowRoot | null = null;\n private isUserContainer = false;\n\n // Mounted UI elements\n private rootEl: HTMLDivElement | null = null;\n private cardEl: HTMLDivElement | null = null;\n private titleEl: HTMLHeadingElement | null = null;\n private stepCounterEl: HTMLDivElement | null = null;\n private progressEl: HTMLDivElement | null = null;\n private progressFillEl: HTMLDivElement | null = null;\n private bodyEl: HTMLDivElement | null = null;\n private footerEl: HTMLDivElement | null = null;\n private savingEl: HTMLDivElement | null = null;\n private backdropEl: HTMLDivElement | null = null;\n private currentInput: QuestionInput | null = null;\n private boundKeyDown: (e: KeyboardEvent) => void;\n\n private cssVars: Record<string, string> = {};\n\n constructor(config: QuestsConfig) {\n this.config = {\n endpoint: config.endpoint,\n apiKey: config.apiKey ?? \"\",\n container: config.container ?? \"\",\n zIndex: config.zIndex ?? 50,\n colors: {\n positive: config.colors?.positive ?? \"#10b981\",\n negative: config.colors?.negative ?? \"#ef4444\",\n marker: config.colors?.marker ?? \"#6366f1\",\n },\n modalWidth: config.modalWidth ?? 480,\n backdropOpacity: config.backdropOpacity ?? 0.4,\n fontFamily: config.fontFamily ?? \"system-ui, -apple-system, sans-serif\",\n fontSize: config.fontSize ?? 16,\n css: config.css ?? \"\",\n autoAdvance: config.autoAdvance ?? false,\n saveDebounceMs: config.saveDebounceMs ?? 500,\n autoFocus: config.autoFocus ?? true,\n progressPosition: config.progressPosition ?? \"top\",\n };\n\n this.inlineQuestionnaire = config.questionnaire;\n this.configUrl = config.configUrl;\n this.visitorId = getOrCreateVisitorId();\n this.boundKeyDown = this.handleKeyDown.bind(this);\n\n this.init();\n }\n\n private async init(): Promise<void> {\n this.cssVars = buildCssVars({\n positiveColor: this.config.colors.positive,\n negativeColor: this.config.colors.negative,\n markerColor: this.config.colors.marker,\n modalWidth: this.config.modalWidth,\n backdropOpacity: this.config.backdropOpacity,\n fontFamily: this.config.fontFamily,\n fontSize: this.config.fontSize,\n });\n\n this.mountShell();\n this.renderLoading();\n\n try {\n const q = await this.loadQuestionnaire();\n if (!q || !q.questions || q.questions.length === 0) {\n throw new Error(\"Questionnaire is empty\");\n }\n this.questionnaire = q;\n this.recomputeVisible();\n // Apply any goToStep request that came in before init finished.\n if (this.pendingGoToStep) {\n const idx = this.visibleQuestions.findIndex(\n (qn) => qn.id === this.pendingGoToStep,\n );\n if (idx !== -1) this.stepIndex = idx;\n this.pendingGoToStep = null;\n }\n // Fire-and-forget create. The form is usable immediately;\n // saves will queue until the response id arrives.\n this.createResponse();\n this.state = \"READY\";\n this.renderHeader();\n this.renderStep();\n } catch (err) {\n this.state = \"ERROR\";\n this.renderError(err);\n }\n }\n\n // ------------------------------------------------------------------\n // Loading the questionnaire JSON\n // ------------------------------------------------------------------\n\n private async loadQuestionnaire(): Promise<Questionnaire> {\n if (this.inlineQuestionnaire) return this.inlineQuestionnaire;\n if (!this.configUrl) {\n throw new Error(\"No questionnaire or configUrl provided\");\n }\n const res = await fetch(this.configUrl, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) {\n throw new Error(`Failed to load questionnaire (${res.status})`);\n }\n return (await res.json()) as Questionnaire;\n }\n\n // ------------------------------------------------------------------\n // Shell (shadow host + card chrome that's stable across steps)\n // ------------------------------------------------------------------\n\n private mountShell(): void {\n this.shadowHost = document.createElement(\"div\");\n this.shadowHost.setAttribute(\"data-qaid-quests\", \"\");\n\n const userContainer = this.config.container\n ? document.querySelector<HTMLElement>(this.config.container)\n : null;\n\n if (userContainer) {\n this.shadowHost.style.display = \"block\";\n // Fill the user-supplied container vertically so the card can\n // flex/shrink-to-fit when the host has a definite height. When\n // the container is content-sized (no fixed/min height), this is\n // a no-op — the chain just grows naturally as before.\n this.shadowHost.style.height = \"100%\";\n this.shadowHost.style.minHeight = \"0\";\n userContainer.appendChild(this.shadowHost);\n this.isUserContainer = true;\n } else {\n // Modal mode: shadow host is fixed and full-viewport.\n this.shadowHost.style.position = \"fixed\";\n this.shadowHost.style.inset = \"0\";\n this.shadowHost.style.zIndex = String(this.config.zIndex);\n this.shadowHost.style.pointerEvents = \"none\";\n document.body.appendChild(this.shadowHost);\n }\n\n this.shadowRoot = this.shadowHost.attachShadow({ mode: \"open\" });\n\n const baseStyle = document.createElement(\"style\");\n baseStyle.textContent = getEmbedStyles();\n this.shadowRoot.appendChild(baseStyle);\n\n if (this.config.css) {\n const themeStyle = document.createElement(\"style\");\n themeStyle.textContent = this.config.css;\n this.shadowRoot.appendChild(themeStyle);\n }\n\n this.rootEl = document.createElement(\"div\");\n this.rootEl.className = `qaid-q-root${this.isUserContainer ? \" qaid-q-inline\" : \"\"}`;\n applyCssVars(this.rootEl, this.cssVars);\n\n if (!this.isUserContainer) {\n this.backdropEl = document.createElement(\"div\");\n this.backdropEl.className = \"qaid-q-backdrop\";\n this.backdropEl.addEventListener(\"click\", () => this.close());\n this.rootEl.appendChild(this.backdropEl);\n\n const modal = document.createElement(\"div\");\n modal.className = \"qaid-q-modal\";\n this.cardEl = document.createElement(\"div\");\n this.cardEl.className = \"qaid-q-card\";\n modal.appendChild(this.cardEl);\n this.rootEl.appendChild(modal);\n } else {\n this.cardEl = document.createElement(\"div\");\n this.cardEl.className = \"qaid-q-card\";\n this.rootEl.appendChild(this.cardEl);\n }\n\n this.shadowRoot.appendChild(this.rootEl);\n\n // Modal mode needs pointer-events on host so the modal itself is clickable.\n if (!this.isUserContainer && this.shadowHost) {\n this.shadowHost.style.pointerEvents = \"auto\";\n }\n\n document.addEventListener(\"keydown\", this.boundKeyDown);\n }\n\n private renderLoading(): void {\n if (!this.cardEl) return;\n this.cardEl.replaceChildren();\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-description\";\n msg.textContent = \"Loading…\";\n this.cardEl.appendChild(msg);\n }\n\n private renderError(err: unknown): void {\n if (!this.cardEl) return;\n this.cardEl.replaceChildren();\n const heading = document.createElement(\"h3\");\n heading.className = \"qaid-q-title\";\n heading.textContent = \"Couldn't load form\";\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-description\";\n msg.textContent = err instanceof Error ? err.message : String(err);\n this.cardEl.appendChild(heading);\n this.cardEl.appendChild(msg);\n }\n\n private renderHeader(): void {\n if (!this.cardEl || !this.questionnaire) return;\n this.cardEl.replaceChildren();\n\n const isBottom = this.config.progressPosition === \"bottom\";\n const hasTitle = !!this.questionnaire.title;\n const hasDescription = !!this.questionnaire.description;\n const hasCloseBtn = !this.isUserContainer;\n\n // These three are created up front and reused across step renders.\n // In top mode they slot into the header / above the body; in bottom\n // mode the footer in renderStep() pulls them into its own row.\n this.savingEl = document.createElement(\"div\");\n this.savingEl.className = \"qaid-q-saving\";\n const dot = document.createElement(\"span\");\n dot.className = \"qaid-q-saving-dot\";\n const savingText = document.createElement(\"span\");\n savingText.textContent = \"Saving…\";\n this.savingEl.appendChild(dot);\n this.savingEl.appendChild(savingText);\n\n this.stepCounterEl = document.createElement(\"div\");\n this.stepCounterEl.className = \"qaid-q-step-counter\";\n\n this.progressEl = document.createElement(\"div\");\n this.progressEl.className = isBottom\n ? \"qaid-q-progress qaid-q-progress--inline\"\n : \"qaid-q-progress\";\n this.progressFillEl = document.createElement(\"div\");\n this.progressFillEl.className = \"qaid-q-progress-fill\";\n this.progressEl.appendChild(this.progressFillEl);\n\n // Skip the header row entirely when there's nothing to show in it\n // — keeps the form flush at the top of inline embeds with no\n // title/description and bottom-progress.\n const showHeader = hasTitle || hasCloseBtn || !isBottom;\n if (showHeader) {\n const header = document.createElement(\"div\");\n header.className = \"qaid-q-header\";\n\n const titleWrap = document.createElement(\"div\");\n if (hasTitle) {\n this.titleEl = document.createElement(\"h2\");\n this.titleEl.className = \"qaid-q-title\";\n this.titleEl.textContent = this.questionnaire.title!;\n titleWrap.appendChild(this.titleEl);\n }\n\n const right = document.createElement(\"div\");\n right.style.display = \"flex\";\n right.style.alignItems = \"center\";\n right.style.gap = \"0.5rem\";\n\n // Saving + step counter live in the header in top mode. In bottom\n // mode the footer owns them.\n if (!isBottom) {\n right.appendChild(this.savingEl);\n right.appendChild(this.stepCounterEl);\n }\n\n if (hasCloseBtn) {\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"qaid-q-close\";\n closeBtn.setAttribute(\"aria-label\", \"Close form\");\n closeBtn.innerHTML = CLOSE_ICON;\n closeBtn.addEventListener(\"click\", () => this.close());\n right.appendChild(closeBtn);\n }\n\n header.appendChild(titleWrap);\n header.appendChild(right);\n this.cardEl.appendChild(header);\n }\n\n if (hasDescription) {\n const desc = document.createElement(\"p\");\n desc.className = \"qaid-q-description\";\n desc.textContent = this.questionnaire.description!;\n desc.style.marginTop = showHeader ? \"-0.5rem\" : \"0\";\n desc.style.marginBottom = \"0.75rem\";\n this.cardEl.appendChild(desc);\n }\n\n if (!isBottom) {\n this.cardEl.appendChild(this.progressEl);\n }\n\n this.bodyEl = document.createElement(\"div\");\n this.bodyEl.className = \"qaid-q-body\";\n this.cardEl.appendChild(this.bodyEl);\n\n this.footerEl = document.createElement(\"div\");\n this.footerEl.className = \"qaid-q-footer\";\n this.cardEl.appendChild(this.footerEl);\n }\n\n // ------------------------------------------------------------------\n // Step rendering\n // ------------------------------------------------------------------\n\n private renderStep(): void {\n if (!this.questionnaire || !this.bodyEl || !this.footerEl) return;\n\n const total = this.visibleQuestions.length;\n if (total === 0) {\n // No visible questions — should be unreachable when the validator\n // forbids visibleIf on the first question, but guard against\n // misauthored inline questionnaires that gate everything.\n void this.submit();\n return;\n }\n if (this.stepIndex >= total) {\n this.stepIndex = total - 1;\n }\n const idx = this.stepIndex;\n const question = this.visibleQuestions[idx];\n\n if (this.stepCounterEl) {\n this.stepCounterEl.textContent = `${idx + 1} / ${total}`;\n }\n if (this.progressFillEl) {\n const pct = ((idx + 1) / total) * 100;\n this.progressFillEl.style.width = `${pct}%`;\n }\n\n // Build step body\n const step = document.createElement(\"div\");\n step.className = \"qaid-q-step\";\n step.setAttribute(\"role\", \"group\");\n step.setAttribute(\"aria-labelledby\", `qaid-q-label-${idx}`);\n\n const label = document.createElement(\"label\");\n label.id = `qaid-q-label-${idx}`;\n label.className = \"qaid-q-label\";\n label.textContent = question.label;\n if (question.required) {\n const star = document.createElement(\"span\");\n star.className = \"qaid-q-required\";\n star.textContent = \"*\";\n star.setAttribute(\"aria-label\", \"required\");\n label.appendChild(star);\n }\n step.appendChild(label);\n\n if (question.description) {\n const desc = document.createElement(\"p\");\n desc.className = \"qaid-q-description\";\n desc.textContent = question.description;\n step.appendChild(desc);\n }\n\n const errorEl = document.createElement(\"p\");\n errorEl.className = \"qaid-q-error\";\n errorEl.setAttribute(\"aria-live\", \"polite\");\n\n const initialValue = this.answers[question.id] ?? null;\n const isLast = idx === total - 1;\n\n const input = createInput({\n question,\n initialValue,\n onChange: (value) => {\n this.handleAnswerChange(question, value);\n // clearing error if the user starts typing again\n if (errorEl.textContent) errorEl.textContent = \"\";\n },\n onSubmit: () => this.advance(question, errorEl),\n onAutoAdvance: () => this.advance(question, errorEl),\n autoAdvance: this.config.autoAdvance,\n });\n this.currentInput = input;\n\n step.appendChild(input.element);\n step.appendChild(errorEl);\n\n this.bodyEl.replaceChildren(step);\n\n // Footer\n this.footerEl.replaceChildren();\n const isBottomProgress = this.config.progressPosition === \"bottom\";\n\n const back =\n idx > 0\n ? (() => {\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.className = \"qaid-q-btn qaid-q-btn-secondary\";\n b.textContent = this.questionnaire!.backLabel ?? \"Back\";\n b.addEventListener(\"click\", () => this.back());\n return b;\n })()\n : null;\n\n const next = document.createElement(\"button\");\n next.type = \"button\";\n next.className = \"qaid-q-btn qaid-q-btn-primary\";\n next.textContent = isLast\n ? (this.questionnaire.submitLabel ?? \"Submit\")\n : (this.questionnaire.nextLabel ?? \"Next\");\n next.addEventListener(\"click\", () => this.advance(question, errorEl));\n\n if (isBottomProgress) {\n // Single-row footer: [back] [progress fills] [savingEl][stepCounter] [next]\n this.footerEl.classList.add(\"qaid-q-footer--inline-progress\");\n if (back) this.footerEl.appendChild(back);\n if (this.progressEl) this.footerEl.appendChild(this.progressEl);\n if (this.savingEl) this.footerEl.appendChild(this.savingEl);\n if (this.stepCounterEl) this.footerEl.appendChild(this.stepCounterEl);\n this.footerEl.appendChild(next);\n } else {\n this.footerEl.classList.remove(\"qaid-q-footer--inline-progress\");\n const left = document.createElement(\"div\");\n left.className = \"qaid-q-footer-left\";\n const right = document.createElement(\"div\");\n right.className = \"qaid-q-footer-right\";\n\n if (back) left.appendChild(back);\n\n const hint = document.createElement(\"span\");\n hint.className = \"qaid-q-hint\";\n hint.innerHTML = isLast\n ? `<kbd>Enter</kbd> to submit`\n : `<kbd>Enter</kbd> to continue`;\n right.appendChild(hint);\n right.appendChild(next);\n\n this.footerEl.appendChild(left);\n this.footerEl.appendChild(right);\n }\n\n // Focus policy:\n // - Initial render: only focus when `autoFocus` is enabled.\n // Embedded previews and \"open in page\" usages set autoFocus:false\n // to avoid yanking focus on mount.\n // - Every subsequent step (advance / back): always focus the\n // active input. The user just performed a keyboard or click\n // action expecting to interact with the next question, and\n // screen-reader users need focus to move so the new question's\n // accessible name is announced.\n const isInitialRender = !this.hasRenderedStep;\n this.hasRenderedStep = true;\n const shouldFocus = isInitialRender ? this.config.autoFocus : true;\n if (shouldFocus) {\n requestAnimationFrame(() => input.focus());\n }\n }\n\n private renderDone(): void {\n if (!this.cardEl || !this.questionnaire) return;\n this.cardEl.replaceChildren();\n\n const done = document.createElement(\"div\");\n done.className = \"qaid-q-done\";\n\n const icon = document.createElement(\"div\");\n icon.className = \"qaid-q-done-icon\";\n icon.innerHTML = CHECK_ICON;\n done.appendChild(icon);\n\n const title = document.createElement(\"h3\");\n title.className = \"qaid-q-done-title\";\n title.textContent = this.questionnaire.thankYouTitle ?? \"Thank you!\";\n done.appendChild(title);\n\n if (this.questionnaire.thankYouMessage) {\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-done-message\";\n msg.textContent = this.questionnaire.thankYouMessage;\n done.appendChild(msg);\n }\n\n if (!this.isUserContainer) {\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"qaid-q-btn qaid-q-btn-primary\";\n closeBtn.textContent = \"Close\";\n closeBtn.style.marginTop = \"1rem\";\n closeBtn.addEventListener(\"click\", () => this.close());\n done.appendChild(closeBtn);\n }\n\n this.cardEl.appendChild(done);\n }\n\n // ------------------------------------------------------------------\n // Navigation\n // ------------------------------------------------------------------\n\n private advance(question: Question, errorEl: HTMLElement): void {\n if (!this.currentInput || !this.questionnaire) return;\n if (!this.currentInput.isValid()) {\n errorEl.textContent = validationMessage(question);\n this.currentInput.focus();\n return;\n }\n // Capture latest value (e.g. range may not have fired its first change).\n // handleAnswerChange already calls recomputeVisible after recording\n // the answer, so visibleQuestions is up-to-date here.\n this.handleAnswerChange(question, this.currentInput.getValue(), { immediate: true });\n\n const last = this.stepIndex === this.visibleQuestions.length - 1;\n if (last) {\n void this.submit();\n return;\n }\n this.stepIndex++;\n this.renderStep();\n }\n\n private back(): void {\n // Flush any pending save before navigating\n this.flushPendingSave();\n if (this.stepIndex > 0) {\n this.stepIndex--;\n // Defensive: a previous answer may have been changed in a way that\n // shrinks the visible tail. Recompute and clamp.\n this.recomputeVisible();\n if (this.stepIndex >= this.visibleQuestions.length) {\n this.stepIndex = Math.max(0, this.visibleQuestions.length - 1);\n }\n this.renderStep();\n }\n }\n\n // ------------------------------------------------------------------\n // Answer handling + autosave\n // ------------------------------------------------------------------\n\n private recomputeVisible(): void {\n if (!this.questionnaire) return;\n this.visibleQuestions = getVisibleQuestions(this.questionnaire, this.answers);\n }\n\n private handleAnswerChange(\n question: Question,\n value: AnswerValue,\n opts: { immediate?: boolean } = {},\n ): void {\n this.answers[question.id] = value;\n // Visibility may flip on follow-up questions when this answer\n // changes. Recompute synchronously so advance() / back() see the\n // up-to-date list. We don't re-render here — the user is mid-edit.\n this.recomputeVisible();\n\n const debounced =\n question.type === \"text\" ||\n question.type === \"currency\" ||\n question.type === \"range\";\n\n if (opts.immediate || !debounced) {\n this.flushPendingSave();\n this.saveAnswer(question.id, value);\n return;\n }\n\n // Debounce — collapse rapid keystrokes into one PATCH.\n this.pendingSaveQuestionId = question.id;\n this.pendingSaveValue = value;\n if (this.pendingSaveTimer) clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = setTimeout(() => {\n this.flushPendingSave();\n }, this.config.saveDebounceMs);\n }\n\n private flushPendingSave(): void {\n if (this.pendingSaveTimer) {\n clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = null;\n }\n if (this.pendingSaveQuestionId !== null) {\n const id = this.pendingSaveQuestionId;\n const value = this.pendingSaveValue;\n this.pendingSaveQuestionId = null;\n this.pendingSaveValue = null;\n this.saveAnswer(id, value);\n }\n }\n\n private saveAnswer(questionId: string, value: AnswerValue): void {\n this.showSaving(true);\n this.inflightSaves++;\n void this.doSave(questionId, value).finally(() => {\n this.inflightSaves--;\n if (this.inflightSaves === 0) this.showSaving(false);\n });\n }\n\n private async doSave(questionId: string, value: AnswerValue): Promise<void> {\n // Wait for response id to be assigned before sending updates.\n // If creation is still in flight, queue tightly via microtask polling.\n let waited = 0;\n while (this.responseId === null && waited < 5000) {\n await new Promise((r) => setTimeout(r, 50));\n waited += 50;\n }\n if (this.responseId === null) return;\n\n try {\n await fetch(`${this.config.endpoint}/${this.responseId}`, {\n method: \"PATCH\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({ questionId, value }),\n });\n } catch (err) {\n console.error(\"[quests-embed] failed to save answer:\", err);\n }\n }\n\n private async createResponse(): Promise<void> {\n try {\n const res = await fetch(this.config.endpoint, {\n method: \"POST\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({\n apiKey: this.config.apiKey || undefined,\n questId: this.questionnaire?.id,\n pageUrl: window.location.href,\n visitorId: this.visitorId,\n userAgent: navigator.userAgent,\n }),\n });\n if (res.ok) {\n const data = (await res.json()) as CreateResponseResult;\n this.responseId = data.id;\n }\n } catch (err) {\n console.error(\"[quests-embed] failed to create response:\", err);\n }\n }\n\n private async submit(): Promise<void> {\n this.flushPendingSave();\n // Wait for any in-flight saves so the server sees the final state.\n while (this.inflightSaves > 0) {\n await new Promise((r) => setTimeout(r, 50));\n }\n\n if (this.responseId !== null) {\n try {\n await fetch(`${this.config.endpoint}/${this.responseId}/submit`, {\n method: \"POST\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({ answers: this.answers }),\n });\n } catch (err) {\n console.error(\"[quests-embed] failed to submit:\", err);\n }\n }\n\n this.state = \"DONE\";\n this.renderDone();\n }\n\n private jsonHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.config.apiKey) headers[\"X-API-Key\"] = this.config.apiKey;\n return headers;\n }\n\n private showSaving(visible: boolean): void {\n if (!this.savingEl) return;\n this.savingEl.classList.toggle(\"qaid-q-visible\", visible);\n }\n\n // ------------------------------------------------------------------\n // Keyboard / lifecycle\n // ------------------------------------------------------------------\n\n private handleKeyDown(e: KeyboardEvent): void {\n if (e.key === \"Escape\" && !this.isUserContainer && this.state !== \"DONE\") {\n this.close();\n }\n }\n\n private close(): void {\n this.flushPendingSave();\n this.destroy();\n }\n\n /** Destroy the embed and clean up all resources */\n public destroy(): void {\n document.removeEventListener(\"keydown\", this.boundKeyDown);\n if (this.pendingSaveTimer) {\n clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = null;\n }\n if (this.shadowHost) {\n this.shadowHost.remove();\n this.shadowHost = null;\n this.shadowRoot = null;\n }\n this.rootEl = null;\n this.cardEl = null;\n this.bodyEl = null;\n this.footerEl = null;\n this.titleEl = null;\n this.stepCounterEl = null;\n this.progressFillEl = null;\n this.savingEl = null;\n this.backdropEl = null;\n this.currentInput = null;\n }\n\n /** Read-only snapshot of current answers */\n public getAnswers(): Answers {\n return { ...this.answers };\n }\n\n /**\n * Jump to the visible question with the given id. Returns true if\n * the question is currently visible (and the embed navigated to\n * it), false if it's hidden by an unmet `visibleIf` predicate or\n * unknown. If the embed is still initializing, the request is\n * latched and applied as soon as the questionnaire is ready.\n *\n * Intended for editor previews and other host-driven step control.\n */\n public goToStep(questionId: string): boolean {\n if (this.state !== \"READY\" || !this.questionnaire) {\n this.pendingGoToStep = questionId;\n return false;\n }\n const idx = this.visibleQuestions.findIndex((q) => q.id === questionId);\n if (idx === -1) return false;\n if (idx === this.stepIndex) return true;\n this.flushPendingSave();\n this.stepIndex = idx;\n this.renderStep();\n return true;\n }\n}\n\nfunction validationMessage(q: Question): string {\n switch (q.type) {\n case \"text\":\n if (q.minLength) return `Please enter at least ${q.minLength} characters.`;\n return \"This field is required.\";\n case \"currency\":\n return \"Please enter a valid amount.\";\n case \"date\":\n return \"Please pick a date.\";\n case \"multiple-choice\":\n return q.multiple ? \"Please select at least one option.\" : \"Please select an option.\";\n case \"range\":\n return \"Please choose a value.\";\n }\n}\n","/**\n * @qaiddev/quests-embed\n *\n * Step-by-step JSON-defined form embed.\n *\n * Usage as ES module:\n * ```ts\n * import { QaidQuests } from \"@qaiddev/quests-embed\";\n *\n * new QaidQuests({\n * endpoint: \"/api/responses\",\n * configUrl: \"/forms/intake.json\",\n * container: \"#form\",\n * });\n * ```\n *\n * Usage via script tag (auto-init):\n * ```html\n * <script src=\"qaid-quests.umd.cjs\"\n * data-endpoint=\"/api/responses\"\n * data-config-url=\"/forms/intake.json\"\n * data-container=\"#form\"></script>\n * ```\n *\n * Or with a JSON config tag:\n * ```html\n * <script type=\"application/json\" data-quests-config>\n * { \"endpoint\": \"/api/responses\", \"configUrl\": \"/forms/intake.json\" }\n * </script>\n * <script src=\"qaid-quests.umd.cjs\"></script>\n * ```\n */\n\nimport { QaidQuests } from \"./embed\";\nimport type { QuestsConfig } from \"./types\";\n\nexport { QaidQuests };\nexport { getVisibleQuestions, evaluateRule } from \"./visibility\";\nexport type {\n QuestsConfig,\n ResolvedQuestsConfig,\n Questionnaire,\n Question,\n TextQuestion,\n CurrencyQuestion,\n RangeQuestion,\n DateQuestion,\n MultipleChoiceQuestion,\n MultipleChoiceOption,\n Answers,\n AnswerValue,\n VisibilityRule,\n CreateResponsePayload,\n CreateResponseResult,\n UpdateAnswerPayload,\n SubmitPayload,\n} from \"./types\";\n\nfunction findCssFromSelector(selector: string): string {\n const el = document.querySelector(selector);\n return el?.textContent?.trim() ?? \"\";\n}\n\nfunction parseJsonConfig(): Partial<QuestsConfig> | null {\n const tag = document.querySelector(\n 'script[type=\"application/json\"][data-quests-config]',\n );\n if (!tag) return null;\n const raw = tag.textContent?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<QuestsConfig> & {\n cssSelector?: string;\n };\n if (parsed.cssSelector && !parsed.css) {\n parsed.css = findCssFromSelector(parsed.cssSelector);\n delete parsed.cssSelector;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction parseDataAttributes(\n script: HTMLScriptElement,\n): Partial<QuestsConfig> | null {\n const endpoint = script.getAttribute(\"data-endpoint\");\n if (!endpoint) return null;\n\n const configUrl = script.getAttribute(\"data-config-url\");\n const apiKey = script.getAttribute(\"data-api-key\");\n const container = script.getAttribute(\"data-container\");\n const zIndex = script.getAttribute(\"data-zindex\");\n const positiveColor = script.getAttribute(\"data-positive-color\");\n const negativeColor = script.getAttribute(\"data-negative-color\");\n const markerColor = script.getAttribute(\"data-marker-color\");\n const modalWidth = script.getAttribute(\"data-modal-width\");\n const backdropOpacity = script.getAttribute(\"data-backdrop-opacity\");\n const fontFamily = script.getAttribute(\"data-font-family\");\n const fontSize = script.getAttribute(\"data-font-size\");\n const cssSelector = script.getAttribute(\"data-css-selector\");\n const autoAdvance = script.getAttribute(\"data-auto-advance\");\n const saveDebounceMs = script.getAttribute(\"data-save-debounce-ms\");\n\n return {\n endpoint,\n configUrl: configUrl ?? undefined,\n apiKey: apiKey ?? undefined,\n container: container ?? undefined,\n zIndex: zIndex ? parseInt(zIndex, 10) : undefined,\n colors: {\n positive: positiveColor ?? undefined,\n negative: negativeColor ?? undefined,\n marker: markerColor ?? undefined,\n },\n modalWidth: modalWidth ? parseInt(modalWidth, 10) : undefined,\n backdropOpacity: backdropOpacity ? parseFloat(backdropOpacity) : undefined,\n fontFamily: fontFamily ?? undefined,\n fontSize: fontSize ? parseInt(fontSize, 10) : undefined,\n css: cssSelector ? findCssFromSelector(cssSelector) : undefined,\n autoAdvance: autoAdvance === \"true\" ? true : undefined,\n saveDebounceMs: saveDebounceMs ? parseInt(saveDebounceMs, 10) : undefined,\n };\n}\n\nif (typeof document !== \"undefined\") {\n const initFromScript = (): void => {\n const script = document.currentScript as HTMLScriptElement | null;\n const jsonConfig = parseJsonConfig();\n const dataConfig = script ? parseDataAttributes(script) : null;\n const config = jsonConfig ?? dataConfig;\n if (config?.endpoint && (config.configUrl || config.questionnaire)) {\n new QaidQuests(config as QuestsConfig);\n }\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initFromScript);\n } else {\n initFromScript();\n }\n}\n"],"names":["getLuminance","r","g","b","rs","gs","bs","c","parseColor","color","hex","fullHex","num","match","getContrastTextColor","bgColor","rgb","buildCssVars","options","positiveColor","negativeColor","markerColor","modalWidth","backdropOpacity","fontFamily","fontSize","applyCssVars","el","vars","name","value","getEmbedStyles","shadowStyles","createInput","createTextInput","createCurrencyInput","createRangeInput","createDateInput","createMultipleChoiceInput","q","opts","initial","textarea","input","inputAutocomplete","e","len","v","wrap","prefix","currencySymbol","raw","currency","locale","p","valueDisplay","valueText","unit","updateDisplay","bounds","lower","upper","alignment","layoutClass","selected","buttons","opt","idx","btn","marker","body","img","label","desc","key","toggle","focusOption","k","on","currentValue","it","getVisibleQuestions","answers","qn","evaluateRule","rule","isAnswered","matchesAtomic","x","answer","target","a","VISITOR_ID_KEY","getOrCreateVisitorId","id","CLOSE_ICON","CHECK_ICON","QaidQuests","config","err","res","userContainer","baseStyle","themeStyle","modal","msg","heading","isBottom","hasTitle","hasDescription","hasCloseBtn","dot","savingText","showHeader","header","titleWrap","right","closeBtn","total","question","pct","step","star","errorEl","initialValue","isLast","isBottomProgress","back","next","left","hint","isInitialRender","done","icon","title","validationMessage","debounced","questionId","waited","data","headers","visible","findCssFromSelector","selector","parseJsonConfig","tag","parsed","parseDataAttributes","script","endpoint","configUrl","apiKey","container","zIndex","cssSelector","autoAdvance","saveDebounceMs","initFromScript","jsonConfig","dataConfig"],"mappings":"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"}
1
+ {"version":3,"file":"qaid-quests.js","sources":["../src/styles.ts","../src/inputs.ts","../src/visibility.ts","../src/embed.ts","../src/index.ts"],"sourcesContent":["/**\n * CSS variable + style helpers for the questionnaire embed.\n *\n * Variable names match @qaiddev/thumbs-embed so a theme written for\n * one embed renders identically in the other:\n * --qaid-positive, --qaid-negative, --qaid-marker\n * --qaid-modal-width, --qaid-backdrop-opacity\n * --qaid-font-family, --qaid-font-size\n */\n\nimport shadowStyles from \"./styles-shadow.css?inline\";\n\nexport interface BuildCssVarsOptions {\n positiveColor?: string;\n negativeColor?: string;\n markerColor?: string;\n modalWidth?: number;\n backdropOpacity?: number;\n fontFamily?: string;\n fontSize?: number;\n}\n\nfunction getLuminance(r: number, g: number, b: number): number {\n const [rs, gs, bs] = [r, g, b].map((c) => {\n c = c / 255;\n return c <= 0.03928 ? c / 12.92 : Math.pow((c + 0.055) / 1.055, 2.4);\n });\n return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;\n}\n\nfunction parseColor(color: string): { r: number; g: number; b: number } | null {\n if (color.startsWith(\"#\")) {\n const hex = color.slice(1);\n const fullHex =\n hex.length === 3\n ? hex\n .split(\"\")\n .map((c) => c + c)\n .join(\"\")\n : hex;\n const num = parseInt(fullHex, 16);\n return { r: (num >> 16) & 255, g: (num >> 8) & 255, b: num & 255 };\n }\n const match = color.match(/rgb\\((\\d+),\\s*(\\d+),\\s*(\\d+)\\)/);\n if (match) {\n return { r: parseInt(match[1]), g: parseInt(match[2]), b: parseInt(match[3]) };\n }\n return null;\n}\n\nfunction getContrastTextColor(bgColor: string): string {\n const rgb = parseColor(bgColor);\n if (!rgb) return \"white\";\n return getLuminance(rgb.r, rgb.g, rgb.b) > 0.4 ? \"black\" : \"white\";\n}\n\nexport function buildCssVars(options: BuildCssVarsOptions = {}): Record<string, string> {\n const {\n positiveColor = \"#10b981\",\n negativeColor = \"#ef4444\",\n markerColor = \"#6366f1\",\n modalWidth = 480,\n backdropOpacity = 0.4,\n fontFamily = \"system-ui, -apple-system, sans-serif\",\n fontSize = 16,\n } = options;\n\n return {\n \"--qaid-positive\": positiveColor,\n \"--qaid-positive-text\": getContrastTextColor(positiveColor),\n \"--qaid-negative\": negativeColor,\n \"--qaid-marker\": markerColor,\n \"--qaid-marker-text\": getContrastTextColor(markerColor),\n \"--qaid-modal-width\": `${modalWidth}px`,\n \"--qaid-backdrop-opacity\": String(backdropOpacity),\n \"--qaid-font-family\": fontFamily,\n \"--qaid-font-size\": `${fontSize}px`,\n };\n}\n\nexport function applyCssVars(el: HTMLElement, vars: Record<string, string>): void {\n for (const [name, value] of Object.entries(vars)) {\n el.style.setProperty(name, value);\n }\n}\n\n/** CSS string injected into every shadow root */\nexport function getEmbedStyles(): string {\n return shadowStyles;\n}\n","/**\n * Input renderers for each question type.\n *\n * Each renderer returns a small object with an element to mount, a\n * focus helper, a synchronous current-value reader, and a validator.\n *\n * Per-keystroke autosave is wired by the embed: the renderer just\n * calls back into onChange whenever its underlying value changes.\n * Renderers also call onSubmit when the user presses Enter (or\n * onAutoAdvance after a discrete selection that should auto-advance).\n */\n\nimport type {\n AnswerValue,\n CurrencyQuestion,\n DateQuestion,\n MultipleChoiceQuestion,\n Question,\n RangeQuestion,\n TextQuestion,\n} from \"./types\";\n\nexport interface QuestionInput {\n element: HTMLElement;\n focus(): void;\n getValue(): AnswerValue;\n isValid(): boolean;\n}\n\nexport interface QuestionInputOptions {\n question: Question;\n initialValue: AnswerValue;\n /** Called any time the value changes (every keystroke for text). */\n onChange: (value: AnswerValue) => void;\n /** Called when the user presses Enter to advance. */\n onSubmit: () => void;\n /**\n * Called after a discrete selection that should auto-advance\n * (e.g. picking a single-choice option when autoAdvance is on).\n */\n onAutoAdvance: () => void;\n /** Whether the embed is configured to auto-advance after discrete selections */\n autoAdvance: boolean;\n}\n\nexport function createInput(options: QuestionInputOptions): QuestionInput {\n switch (options.question.type) {\n case \"text\":\n return createTextInput(options.question, options);\n case \"currency\":\n return createCurrencyInput(options.question, options);\n case \"range\":\n return createRangeInput(options.question, options);\n case \"date\":\n return createDateInput(options.question, options);\n case \"multiple-choice\":\n return createMultipleChoiceInput(options.question, options);\n }\n}\n\n// ====================================================================\n// Text\n// ====================================================================\n\nfunction createTextInput(\n q: TextQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const initial = typeof opts.initialValue === \"string\" ? opts.initialValue : \"\";\n\n let el: HTMLInputElement | HTMLTextAreaElement;\n\n if (q.multiline) {\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"qaid-q-textarea\";\n textarea.value = initial;\n if (q.placeholder) textarea.placeholder = q.placeholder;\n if (q.maxLength) textarea.maxLength = q.maxLength;\n el = textarea;\n } else {\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n input.type = q.inputType ?? \"text\";\n input.value = initial;\n if (q.placeholder) input.placeholder = q.placeholder;\n if (q.maxLength) input.maxLength = q.maxLength;\n input.setAttribute(\"autocomplete\", inputAutocomplete(q.inputType));\n el = input;\n }\n\n el.setAttribute(\"aria-label\", q.label);\n\n el.addEventListener(\"input\", () => {\n opts.onChange(el.value);\n });\n\n el.addEventListener(\"keydown\", ((e: KeyboardEvent) => {\n if (e.key !== \"Enter\") return;\n if (q.multiline) {\n // In multiline, Enter inserts newline; Cmd/Ctrl+Enter submits.\n if (e.metaKey || e.ctrlKey) {\n e.preventDefault();\n opts.onSubmit();\n }\n return;\n }\n // Single-line: Enter submits, but allow IME composition to finish first.\n if (e.isComposing) return;\n e.preventDefault();\n opts.onSubmit();\n }) as EventListener);\n\n return {\n element: el,\n focus: () => {\n el.focus();\n // Place cursor at end so user can keep typing.\n const len = el.value.length;\n try {\n el.setSelectionRange(len, len);\n } catch {\n // input types like email may not support selectionRange\n }\n },\n getValue: () => el.value,\n isValid: () => {\n if (!q.required) return true;\n const v = el.value.trim();\n if (v.length === 0) return false;\n if (q.minLength && v.length < q.minLength) return false;\n return true;\n },\n };\n}\n\nfunction inputAutocomplete(t?: TextQuestion[\"inputType\"]): string {\n switch (t) {\n case \"email\":\n return \"email\";\n case \"tel\":\n return \"tel\";\n case \"url\":\n return \"url\";\n default:\n return \"off\";\n }\n}\n\n// ====================================================================\n// Currency\n// ====================================================================\n\nfunction createCurrencyInput(\n q: CurrencyQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n wrap.className = \"qaid-q-currency\";\n\n const prefix = document.createElement(\"span\");\n prefix.className = \"qaid-q-currency-prefix\";\n prefix.textContent = currencySymbol(q.currency ?? \"USD\", q.locale);\n wrap.appendChild(prefix);\n\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n // type=\"number\" gives native numeric keyboard + min/max validation hooks.\n input.type = \"number\";\n input.inputMode = \"decimal\";\n input.step = \"0.01\";\n if (typeof q.min === \"number\") input.min = String(q.min);\n if (typeof q.max === \"number\") input.max = String(q.max);\n if (q.placeholder) input.placeholder = q.placeholder;\n if (typeof opts.initialValue === \"number\") input.value = String(opts.initialValue);\n else if (typeof opts.initialValue === \"string\" && opts.initialValue !== \"\")\n input.value = opts.initialValue;\n input.setAttribute(\"aria-label\", q.label);\n\n input.addEventListener(\"input\", () => {\n const raw = input.value;\n if (raw === \"\") {\n opts.onChange(null);\n } else {\n const num = Number(raw);\n opts.onChange(Number.isNaN(num) ? null : num);\n }\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !(e as KeyboardEvent).isComposing) {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n wrap.appendChild(input);\n\n return {\n element: wrap,\n focus: () => input.focus(),\n getValue: () => {\n if (input.value === \"\") return null;\n const num = Number(input.value);\n return Number.isNaN(num) ? null : num;\n },\n isValid: () => {\n const v = input.value === \"\" ? null : Number(input.value);\n if (q.required && (v === null || Number.isNaN(v as number))) return false;\n if (v !== null && !Number.isNaN(v as number)) {\n if (typeof q.min === \"number\" && (v as number) < q.min) return false;\n if (typeof q.max === \"number\" && (v as number) > q.max) return false;\n }\n return true;\n },\n };\n}\n\nfunction currencySymbol(currency: string, locale?: string): string {\n try {\n const fmt = new Intl.NumberFormat(locale, {\n style: \"currency\",\n currency,\n currencyDisplay: \"narrowSymbol\",\n maximumFractionDigits: 0,\n });\n // Pull the symbol out of a formatted zero\n const parts = fmt.formatToParts(0);\n const sym = parts.find((p) => p.type === \"currency\");\n return sym?.value ?? currency;\n } catch {\n return currency;\n }\n}\n\n// ====================================================================\n// Range\n// ====================================================================\n\nfunction createRangeInput(\n q: RangeQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n wrap.className = \"qaid-q-range-wrap\";\n\n const valueDisplay = document.createElement(\"div\");\n valueDisplay.className = \"qaid-q-range-value\";\n\n const valueText = document.createElement(\"span\");\n valueDisplay.appendChild(valueText);\n\n if (q.unit) {\n const unit = document.createElement(\"span\");\n unit.className = \"qaid-q-range-unit\";\n unit.textContent = q.unit;\n valueDisplay.appendChild(unit);\n }\n\n const initial =\n typeof opts.initialValue === \"number\"\n ? opts.initialValue\n : (q.defaultValue ?? q.min);\n\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-range\";\n input.type = \"range\";\n input.min = String(q.min);\n input.max = String(q.max);\n input.step = String(q.step ?? 1);\n input.value = String(initial);\n input.setAttribute(\"aria-label\", q.label);\n input.setAttribute(\"aria-valuemin\", String(q.min));\n input.setAttribute(\"aria-valuemax\", String(q.max));\n\n const updateDisplay = () => {\n valueText.textContent = input.value;\n input.setAttribute(\"aria-valuenow\", input.value);\n };\n updateDisplay();\n\n input.addEventListener(\"input\", () => {\n updateDisplay();\n opts.onChange(Number(input.value));\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\") {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n const bounds = document.createElement(\"div\");\n bounds.className = \"qaid-q-range-bounds\";\n const lower = document.createElement(\"span\");\n lower.textContent = `${q.min}${q.unit ?? \"\"}`;\n const upper = document.createElement(\"span\");\n upper.textContent = `${q.max}${q.unit ?? \"\"}`;\n bounds.appendChild(lower);\n bounds.appendChild(upper);\n\n wrap.appendChild(valueDisplay);\n wrap.appendChild(input);\n wrap.appendChild(bounds);\n\n // Push the initial value to onChange so first interaction is recorded\n // even if the user presses Enter without dragging.\n // (Defer to the next tick so the embed has wired up its handler.)\n queueMicrotask(() => opts.onChange(Number(input.value)));\n\n return {\n element: wrap,\n focus: () => input.focus(),\n getValue: () => Number(input.value),\n isValid: () => true,\n };\n}\n\n// ====================================================================\n// Date\n// ====================================================================\n\nfunction createDateInput(q: DateQuestion, opts: QuestionInputOptions): QuestionInput {\n const input = document.createElement(\"input\");\n input.className = \"qaid-q-input\";\n input.type = \"date\";\n if (q.min) input.min = q.min;\n if (q.max) input.max = q.max;\n if (typeof opts.initialValue === \"string\") input.value = opts.initialValue;\n input.setAttribute(\"aria-label\", q.label);\n\n input.addEventListener(\"input\", () => {\n opts.onChange(input.value || null);\n });\n\n input.addEventListener(\"keydown\", (e) => {\n if (e.key === \"Enter\" && !(e as KeyboardEvent).isComposing) {\n e.preventDefault();\n opts.onSubmit();\n }\n });\n\n return {\n element: input,\n focus: () => input.focus(),\n getValue: () => input.value || null,\n isValid: () => {\n if (!q.required) return true;\n return input.value !== \"\";\n },\n };\n}\n\n// ====================================================================\n// Multiple choice\n// ====================================================================\n\nfunction createMultipleChoiceInput(\n q: MultipleChoiceQuestion,\n opts: QuestionInputOptions,\n): QuestionInput {\n const wrap = document.createElement(\"div\");\n const alignment = q.imageAlignment ?? \"horizontal\";\n const hasAnyImage = q.options.some((o) => !!o.image);\n const layoutClass = hasAnyImage\n ? alignment === \"vertical\"\n ? \" qaid-q-options--image-vertical\"\n : \" qaid-q-options--image-horizontal\"\n : \"\";\n wrap.className = `qaid-q-options${layoutClass}`;\n wrap.setAttribute(\"role\", q.multiple ? \"group\" : \"radiogroup\");\n wrap.setAttribute(\"aria-label\", q.label);\n\n // Normalize initial selection to a Set for both modes\n const selected = new Set<string>();\n if (q.multiple && Array.isArray(opts.initialValue)) {\n for (const v of opts.initialValue) selected.add(v);\n } else if (!q.multiple && typeof opts.initialValue === \"string\") {\n selected.add(opts.initialValue);\n }\n\n const buttons: HTMLButtonElement[] = [];\n\n q.options.forEach((opt, idx) => {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.className = `qaid-q-option${q.multiple ? \" qaid-q-multi\" : \"\"}`;\n btn.dataset.value = opt.value;\n btn.setAttribute(\"role\", q.multiple ? \"checkbox\" : \"radio\");\n btn.setAttribute(\"aria-checked\", selected.has(opt.value) ? \"true\" : \"false\");\n if (selected.has(opt.value)) btn.classList.add(\"qaid-q-selected\");\n\n const marker = document.createElement(\"span\");\n marker.className = \"qaid-q-option-marker\";\n marker.setAttribute(\"aria-hidden\", \"true\");\n\n const body = document.createElement(\"span\");\n body.className = \"qaid-q-option-body\";\n\n if (opt.image) {\n const img = document.createElement(\"img\");\n img.className = \"qaid-q-option-image\";\n img.src = opt.image;\n img.alt = \"\";\n img.loading = \"lazy\";\n img.decoding = \"async\";\n body.appendChild(img);\n }\n\n const label = document.createElement(\"span\");\n label.className = \"qaid-q-option-label\";\n label.textContent = opt.label;\n body.appendChild(label);\n\n if (opt.description) {\n const desc = document.createElement(\"span\");\n desc.className = \"qaid-q-option-desc\";\n desc.textContent = opt.description;\n body.appendChild(desc);\n }\n\n btn.appendChild(marker);\n btn.appendChild(body);\n\n if (idx < 9) {\n const key = document.createElement(\"span\");\n key.className = \"qaid-q-option-key\";\n key.textContent = String(idx + 1);\n key.setAttribute(\"aria-hidden\", \"true\");\n btn.appendChild(key);\n }\n\n btn.addEventListener(\"click\", () => toggle(idx));\n\n btn.addEventListener(\"keydown\", (e) => {\n // Native button handles Space/Enter; we add arrow-key roving focus\n // and Enter-to-advance for single-choice.\n if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") {\n e.preventDefault();\n focusOption((idx + 1) % buttons.length);\n return;\n }\n if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") {\n e.preventDefault();\n focusOption((idx - 1 + buttons.length) % buttons.length);\n return;\n }\n if (!q.multiple && e.key === \"Enter\") {\n // If something is already selected, advance instead of toggling\n if (selected.size > 0) {\n e.preventDefault();\n opts.onSubmit();\n }\n }\n });\n\n buttons.push(btn);\n wrap.appendChild(btn);\n });\n\n // Number-key shortcuts (1-9) at the wrap level\n wrap.addEventListener(\"keydown\", (e) => {\n const k = e.key;\n if (k.length === 1 && k >= \"1\" && k <= \"9\") {\n const idx = parseInt(k, 10) - 1;\n if (idx < buttons.length) {\n e.preventDefault();\n toggle(idx);\n focusOption(idx);\n }\n }\n });\n\n function focusOption(idx: number): void {\n buttons[idx]?.focus();\n }\n\n function toggle(idx: number): void {\n const value = q.options[idx].value;\n if (q.multiple) {\n if (selected.has(value)) selected.delete(value);\n else selected.add(value);\n } else {\n selected.clear();\n selected.add(value);\n }\n // Update DOM state\n buttons.forEach((b) => {\n const v = b.dataset.value!;\n const on = selected.has(v);\n b.classList.toggle(\"qaid-q-selected\", on);\n b.setAttribute(\"aria-checked\", on ? \"true\" : \"false\");\n });\n opts.onChange(currentValue());\n if (!q.multiple && opts.autoAdvance) {\n // Tiny delay so the user sees the selection animation before advancing.\n setTimeout(() => opts.onAutoAdvance(), 180);\n }\n }\n\n function currentValue(): AnswerValue {\n if (q.multiple) return Array.from(selected);\n const it = selected.values().next();\n return it.done ? null : it.value;\n }\n\n return {\n element: wrap,\n focus: () => {\n // Focus the first selected option, or the first option overall.\n const firstSelected = buttons.find((b) => b.classList.contains(\"qaid-q-selected\"));\n (firstSelected ?? buttons[0])?.focus();\n },\n getValue: () => currentValue(),\n isValid: () => {\n if (!q.required) return true;\n return selected.size > 0;\n },\n };\n}\n","/**\n * Pure helpers for evaluating per-question visibility predicates.\n *\n * `getVisibleQuestions` filters a questionnaire's flat question array down\n * to those whose `visibleIf` predicate currently evaluates to true. A\n * question with no `visibleIf` is always visible.\n *\n * Predicates are evaluated against the answers map (the same shape the\n * embed maintains internally and posts on submit). They never throw — a\n * predicate referencing an unknown questionId resolves as if that\n * question is unanswered.\n */\n\nimport type {\n AnswerValue,\n Answers,\n Question,\n Questionnaire,\n VisibilityRule,\n} from \"./types\";\n\nexport function getVisibleQuestions(\n q: Questionnaire,\n answers: Answers,\n): Question[] {\n return q.questions.filter((qn) =>\n qn.visibleIf ? evaluateRule(qn.visibleIf, answers) : true,\n );\n}\n\nexport function evaluateRule(\n rule: VisibilityRule,\n answers: Answers,\n): boolean {\n if (\"allOf\" in rule) {\n // Empty allOf is vacuously true; the validator rejects empty arrays\n // at authoring time, so this branch only matters for inline /\n // unvalidated questionnaires.\n for (const r of rule.allOf) {\n if (!evaluateRule(r, answers)) return false;\n }\n return true;\n }\n if (\"anyOf\" in rule) {\n for (const r of rule.anyOf) {\n if (evaluateRule(r, answers)) return true;\n }\n return false;\n }\n\n const v = answers[rule.questionId];\n // Empty string and empty array count as \"not answered\" so a follow-up\n // doesn't flash visible the moment a text input is focused.\n const isAnswered =\n v !== null &&\n v !== undefined &&\n !(typeof v === \"string\" && v.trim() === \"\") &&\n !(Array.isArray(v) && v.length === 0);\n\n if (\"answered\" in rule) return rule.answered ? isAnswered : !isAnswered;\n\n // Value-comparison atoms against an unanswered question return false\n // — including notEquals, so a \"show this when X is not Y\" follow-up\n // doesn't reveal itself before X has been answered at all.\n if (!isAnswered) return false;\n\n if (\"equals\" in rule) return matchesAtomic(v, rule.equals);\n if (\"notEquals\" in rule) return !matchesAtomic(v, rule.notEquals);\n if (\"in\" in rule) return rule.in.some((x) => matchesAtomic(v, x));\n return false;\n}\n\nfunction matchesAtomic(\n answer: AnswerValue,\n target: string | number,\n): boolean {\n // Multi-select multiple-choice answers are arrays; treat equality as\n // \"target is one of the selected values.\"\n if (Array.isArray(answer)) return answer.some((a) => a === target);\n return answer === target;\n}\n","import type {\n Answers,\n AnswerValue,\n CreateResponseResult,\n Question,\n Questionnaire,\n QuestsConfig,\n ResolvedQuestsConfig,\n} from \"./types\";\nimport { applyCssVars, buildCssVars, getEmbedStyles } from \"./styles\";\nimport { createInput, type QuestionInput } from \"./inputs\";\nimport { getVisibleQuestions } from \"./visibility\";\n\nconst VISITOR_ID_KEY = \"qaid_visitor_id\";\n\ntype EmbedState = \"LOADING\" | \"READY\" | \"DONE\" | \"ERROR\";\n\nfunction getOrCreateVisitorId(): string {\n try {\n let id = localStorage.getItem(VISITOR_ID_KEY);\n if (!id) {\n id = crypto.randomUUID();\n localStorage.setItem(VISITOR_ID_KEY, id);\n }\n return id;\n } catch {\n return crypto.randomUUID();\n }\n}\n\nconst CLOSE_ICON = `<svg width=\"14\" height=\"14\" viewBox=\"0 0 14 14\" aria-hidden=\"true\"><path d=\"M2 2l10 10M12 2L2 12\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" fill=\"none\"/></svg>`;\nconst CHECK_ICON = `<svg width=\"24\" height=\"24\" viewBox=\"0 0 24 24\" aria-hidden=\"true\"><path d=\"M5 12l4 4L19 7\" stroke=\"currentColor\" stroke-width=\"3\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\"/></svg>`;\n\nexport class QaidQuests {\n private config: ResolvedQuestsConfig;\n private questionnaire: Questionnaire | null = null;\n private inlineQuestionnaire: Questionnaire | undefined;\n private configUrl: string | undefined;\n\n private state: EmbedState = \"LOADING\";\n private stepIndex = 0;\n // Cached subset of questionnaire.questions that are currently visible\n // given the answers so far. Recomputed on every answer change so\n // stepIndex always indexes into THIS list, not the raw question array.\n private visibleQuestions: Question[] = [];\n // Latched goToStep request when called before init finishes. Applied\n // once the questionnaire + visible list are ready.\n private pendingGoToStep: string | null = null;\n // True after the first step has rendered. Used so the focus-on-step\n // logic in renderStep() can distinguish initial mount (driven by the\n // `autoFocus` config) from subsequent step changes (always focused so\n // keyboard + screen-reader users land on the active input after Next\n // / Back).\n private hasRenderedStep = false;\n private answers: Answers = {};\n private responseId: string | number | null = null;\n private visitorId: string;\n\n // Per-question pending autosave (text/currency are debounced)\n private pendingSaveTimer: ReturnType<typeof setTimeout> | null = null;\n private pendingSaveQuestionId: string | null = null;\n private pendingSaveValue: AnswerValue = null;\n private inflightSaves = 0;\n\n // Shadow DOM\n private shadowHost: HTMLDivElement | null = null;\n private shadowRoot: ShadowRoot | null = null;\n private isUserContainer = false;\n\n // Mounted UI elements\n private rootEl: HTMLDivElement | null = null;\n private cardEl: HTMLDivElement | null = null;\n private titleEl: HTMLHeadingElement | null = null;\n private stepCounterEl: HTMLDivElement | null = null;\n private progressEl: HTMLDivElement | null = null;\n private progressFillEl: HTMLDivElement | null = null;\n private bodyEl: HTMLDivElement | null = null;\n private footerEl: HTMLDivElement | null = null;\n private savingEl: HTMLDivElement | null = null;\n private backdropEl: HTMLDivElement | null = null;\n private currentInput: QuestionInput | null = null;\n private boundKeyDown: (e: KeyboardEvent) => void;\n\n private cssVars: Record<string, string> = {};\n\n constructor(config: QuestsConfig) {\n this.config = {\n endpoint: config.endpoint,\n apiKey: config.apiKey ?? \"\",\n container: config.container ?? \"\",\n zIndex: config.zIndex ?? 50,\n colors: {\n positive: config.colors?.positive ?? \"#10b981\",\n negative: config.colors?.negative ?? \"#ef4444\",\n marker: config.colors?.marker ?? \"#6366f1\",\n },\n modalWidth: config.modalWidth ?? 480,\n backdropOpacity: config.backdropOpacity ?? 0.4,\n fontFamily: config.fontFamily ?? \"system-ui, -apple-system, sans-serif\",\n fontSize: config.fontSize ?? 16,\n css: config.css ?? \"\",\n autoAdvance: config.autoAdvance ?? false,\n saveDebounceMs: config.saveDebounceMs ?? 500,\n autoFocus: config.autoFocus ?? true,\n animate: config.animate ?? true,\n // Don't default here — we want to fall through to the\n // questionnaire's `progressPosition` when the host didn't\n // explicitly set one. effectiveProgressPosition() handles the\n // final fallback to \"top\".\n progressPosition: config.progressPosition,\n };\n\n this.inlineQuestionnaire = config.questionnaire;\n this.configUrl = config.configUrl;\n this.visitorId = getOrCreateVisitorId();\n this.boundKeyDown = this.handleKeyDown.bind(this);\n\n this.init();\n }\n\n private async init(): Promise<void> {\n this.cssVars = buildCssVars({\n positiveColor: this.config.colors.positive,\n negativeColor: this.config.colors.negative,\n markerColor: this.config.colors.marker,\n modalWidth: this.config.modalWidth,\n backdropOpacity: this.config.backdropOpacity,\n fontFamily: this.config.fontFamily,\n fontSize: this.config.fontSize,\n });\n\n this.mountShell();\n this.renderLoading();\n\n try {\n const q = await this.loadQuestionnaire();\n if (!q || !q.questions || q.questions.length === 0) {\n throw new Error(\"Questionnaire is empty\");\n }\n this.questionnaire = q;\n this.recomputeVisible();\n // Apply any goToStep request that came in before init finished.\n if (this.pendingGoToStep) {\n const idx = this.visibleQuestions.findIndex(\n (qn) => qn.id === this.pendingGoToStep,\n );\n if (idx !== -1) this.stepIndex = idx;\n this.pendingGoToStep = null;\n }\n // Fire-and-forget create. The form is usable immediately;\n // saves will queue until the response id arrives.\n this.createResponse();\n this.state = \"READY\";\n this.renderHeader();\n this.renderStep();\n } catch (err) {\n this.state = \"ERROR\";\n this.renderError(err);\n }\n }\n\n // ------------------------------------------------------------------\n // Loading the questionnaire JSON\n // ------------------------------------------------------------------\n\n private async loadQuestionnaire(): Promise<Questionnaire> {\n if (this.inlineQuestionnaire) return this.inlineQuestionnaire;\n if (!this.configUrl) {\n throw new Error(\"No questionnaire or configUrl provided\");\n }\n const res = await fetch(this.configUrl, {\n headers: { Accept: \"application/json\" },\n });\n if (!res.ok) {\n throw new Error(`Failed to load questionnaire (${res.status})`);\n }\n return (await res.json()) as Questionnaire;\n }\n\n // ------------------------------------------------------------------\n // Shell (shadow host + card chrome that's stable across steps)\n // ------------------------------------------------------------------\n\n private mountShell(): void {\n this.shadowHost = document.createElement(\"div\");\n this.shadowHost.setAttribute(\"data-qaid-quests\", \"\");\n\n const userContainer = this.config.container\n ? document.querySelector<HTMLElement>(this.config.container)\n : null;\n\n if (userContainer) {\n this.shadowHost.style.display = \"block\";\n // Fill the user-supplied container vertically so the card can\n // flex/shrink-to-fit when the host has a definite height. When\n // the container is content-sized (no fixed/min height), this is\n // a no-op — the chain just grows naturally as before.\n this.shadowHost.style.height = \"100%\";\n this.shadowHost.style.minHeight = \"0\";\n userContainer.appendChild(this.shadowHost);\n this.isUserContainer = true;\n } else {\n // Modal mode: shadow host is fixed and full-viewport.\n this.shadowHost.style.position = \"fixed\";\n this.shadowHost.style.inset = \"0\";\n this.shadowHost.style.zIndex = String(this.config.zIndex);\n this.shadowHost.style.pointerEvents = \"none\";\n document.body.appendChild(this.shadowHost);\n }\n\n this.shadowRoot = this.shadowHost.attachShadow({ mode: \"open\" });\n\n const baseStyle = document.createElement(\"style\");\n baseStyle.textContent = getEmbedStyles();\n this.shadowRoot.appendChild(baseStyle);\n\n if (this.config.css) {\n const themeStyle = document.createElement(\"style\");\n themeStyle.textContent = this.config.css;\n this.shadowRoot.appendChild(themeStyle);\n }\n\n this.rootEl = document.createElement(\"div\");\n this.rootEl.className = [\n \"qaid-q-root\",\n this.isUserContainer ? \"qaid-q-inline\" : \"\",\n this.config.animate ? \"\" : \"qaid-q-no-motion\",\n ]\n .filter(Boolean)\n .join(\" \");\n applyCssVars(this.rootEl, this.cssVars);\n\n if (!this.isUserContainer) {\n this.backdropEl = document.createElement(\"div\");\n this.backdropEl.className = \"qaid-q-backdrop\";\n this.backdropEl.addEventListener(\"click\", () => this.close());\n this.rootEl.appendChild(this.backdropEl);\n\n const modal = document.createElement(\"div\");\n modal.className = \"qaid-q-modal\";\n this.cardEl = document.createElement(\"div\");\n this.cardEl.className = \"qaid-q-card\";\n modal.appendChild(this.cardEl);\n this.rootEl.appendChild(modal);\n } else {\n this.cardEl = document.createElement(\"div\");\n this.cardEl.className = \"qaid-q-card\";\n this.rootEl.appendChild(this.cardEl);\n }\n\n this.shadowRoot.appendChild(this.rootEl);\n\n // Modal mode needs pointer-events on host so the modal itself is clickable.\n if (!this.isUserContainer && this.shadowHost) {\n this.shadowHost.style.pointerEvents = \"auto\";\n }\n\n document.addEventListener(\"keydown\", this.boundKeyDown);\n }\n\n private renderLoading(): void {\n if (!this.cardEl) return;\n this.cardEl.replaceChildren();\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-description\";\n msg.textContent = \"Loading…\";\n this.cardEl.appendChild(msg);\n }\n\n private renderError(err: unknown): void {\n if (!this.cardEl) return;\n this.cardEl.replaceChildren();\n const heading = document.createElement(\"h3\");\n heading.className = \"qaid-q-title\";\n heading.textContent = \"Couldn't load form\";\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-description\";\n msg.textContent = err instanceof Error ? err.message : String(err);\n this.cardEl.appendChild(heading);\n this.cardEl.appendChild(msg);\n }\n\n private effectiveProgressPosition(): \"top\" | \"bottom\" {\n return (\n this.config.progressPosition ??\n this.questionnaire?.progressPosition ??\n \"top\"\n );\n }\n\n private renderHeader(): void {\n if (!this.cardEl || !this.questionnaire) return;\n this.cardEl.replaceChildren();\n\n // A single-question form has nothing meaningful to track, so we\n // suppress the progress chrome whether or not the author asked for\n // it explicitly via `hideProgress`. Branching forms with one\n // *currently visible* question still show progress because more\n // questions can appear after the gate is answered.\n const hideProgress =\n !!this.questionnaire.hideProgress ||\n this.questionnaire.questions.length <= 1;\n const isBottom =\n !hideProgress && this.effectiveProgressPosition() === \"bottom\";\n // `hideTitle` is the dashboard's \"Hide Header\" toggle — it hides\n // both the title row and the description, since they live together\n // in the shared header area.\n const headerHidden = !!this.questionnaire.hideTitle;\n const hasTitle = !!this.questionnaire.title && !headerHidden;\n const hasDescription = !!this.questionnaire.description && !headerHidden;\n const hasCloseBtn = !this.isUserContainer;\n // Only render content into the right-hand side of the header when\n // we'd actually have something to put there.\n const headerHasRightContent =\n hasCloseBtn || (!isBottom && !hideProgress);\n\n // These three are created up front and reused across step renders.\n // In top mode they slot into the header / above the body; in bottom\n // mode the footer in renderStep() pulls them into its own row.\n this.savingEl = document.createElement(\"div\");\n this.savingEl.className = \"qaid-q-saving\";\n const dot = document.createElement(\"span\");\n dot.className = \"qaid-q-saving-dot\";\n const savingText = document.createElement(\"span\");\n savingText.textContent = \"Saving…\";\n this.savingEl.appendChild(dot);\n this.savingEl.appendChild(savingText);\n\n this.stepCounterEl = document.createElement(\"div\");\n this.stepCounterEl.className = \"qaid-q-step-counter\";\n\n this.progressEl = document.createElement(\"div\");\n this.progressEl.className = isBottom\n ? \"qaid-q-progress qaid-q-progress--inline\"\n : \"qaid-q-progress\";\n this.progressFillEl = document.createElement(\"div\");\n this.progressFillEl.className = \"qaid-q-progress-fill\";\n this.progressEl.appendChild(this.progressFillEl);\n\n // Skip the header row entirely when there's nothing to show in it\n // — keeps the form flush at the top of inline embeds with no\n // title/description, hidden progress, or bottom-progress.\n const showHeader = hasTitle || headerHasRightContent;\n if (showHeader) {\n const header = document.createElement(\"div\");\n header.className = \"qaid-q-header\";\n\n const titleWrap = document.createElement(\"div\");\n if (hasTitle) {\n this.titleEl = document.createElement(\"h2\");\n this.titleEl.className = \"qaid-q-title\";\n this.titleEl.textContent = this.questionnaire.title!;\n titleWrap.appendChild(this.titleEl);\n }\n\n const right = document.createElement(\"div\");\n right.style.display = \"flex\";\n right.style.alignItems = \"center\";\n right.style.gap = \"0.5rem\";\n\n // Saving + step counter live in the header in top mode. In bottom\n // mode the footer owns them. When progress is hidden, the step\n // counter is suppressed but the saving indicator still surfaces.\n if (!isBottom) {\n right.appendChild(this.savingEl);\n if (!hideProgress) right.appendChild(this.stepCounterEl);\n }\n\n if (hasCloseBtn) {\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"qaid-q-close\";\n closeBtn.setAttribute(\"aria-label\", \"Close form\");\n closeBtn.innerHTML = CLOSE_ICON;\n closeBtn.addEventListener(\"click\", () => this.close());\n right.appendChild(closeBtn);\n }\n\n header.appendChild(titleWrap);\n header.appendChild(right);\n this.cardEl.appendChild(header);\n }\n\n if (hasDescription) {\n const desc = document.createElement(\"p\");\n desc.className = \"qaid-q-description\";\n desc.textContent = this.questionnaire.description!;\n desc.style.marginTop = showHeader ? \"-0.5rem\" : \"0\";\n desc.style.marginBottom = \"0.75rem\";\n this.cardEl.appendChild(desc);\n }\n\n if (!isBottom && !hideProgress) {\n this.cardEl.appendChild(this.progressEl);\n }\n\n this.bodyEl = document.createElement(\"div\");\n this.bodyEl.className = \"qaid-q-body\";\n this.cardEl.appendChild(this.bodyEl);\n\n this.footerEl = document.createElement(\"div\");\n this.footerEl.className = \"qaid-q-footer\";\n this.cardEl.appendChild(this.footerEl);\n }\n\n // ------------------------------------------------------------------\n // Step rendering\n // ------------------------------------------------------------------\n\n private renderStep(): void {\n if (!this.questionnaire || !this.bodyEl || !this.footerEl) return;\n\n const total = this.visibleQuestions.length;\n if (total === 0) {\n // No visible questions — should be unreachable when the validator\n // forbids visibleIf on the first question, but guard against\n // misauthored inline questionnaires that gate everything.\n void this.submit();\n return;\n }\n if (this.stepIndex >= total) {\n this.stepIndex = total - 1;\n }\n const idx = this.stepIndex;\n const question = this.visibleQuestions[idx];\n\n if (this.stepCounterEl) {\n this.stepCounterEl.textContent = `${idx + 1} / ${total}`;\n }\n if (this.progressFillEl) {\n const pct = ((idx + 1) / total) * 100;\n this.progressFillEl.style.width = `${pct}%`;\n }\n\n // Build step body\n const step = document.createElement(\"div\");\n step.className = \"qaid-q-step\";\n step.setAttribute(\"role\", \"group\");\n step.setAttribute(\"aria-labelledby\", `qaid-q-label-${idx}`);\n\n const label = document.createElement(\"label\");\n label.id = `qaid-q-label-${idx}`;\n label.className = \"qaid-q-label\";\n label.textContent = question.label;\n if (question.required) {\n const star = document.createElement(\"span\");\n star.className = \"qaid-q-required\";\n star.textContent = \"*\";\n star.setAttribute(\"aria-label\", \"required\");\n label.appendChild(star);\n }\n step.appendChild(label);\n\n if (question.description) {\n const desc = document.createElement(\"p\");\n desc.className = \"qaid-q-description\";\n desc.textContent = question.description;\n step.appendChild(desc);\n }\n\n const errorEl = document.createElement(\"p\");\n errorEl.className = \"qaid-q-error\";\n errorEl.setAttribute(\"aria-live\", \"polite\");\n\n const initialValue = this.answers[question.id] ?? null;\n const isLast = idx === total - 1;\n\n const input = createInput({\n question,\n initialValue,\n onChange: (value) => {\n this.handleAnswerChange(question, value);\n // clearing error if the user starts typing again\n if (errorEl.textContent) errorEl.textContent = \"\";\n },\n onSubmit: () => this.advance(question, errorEl),\n onAutoAdvance: () => this.advance(question, errorEl),\n autoAdvance: this.config.autoAdvance,\n });\n this.currentInput = input;\n\n step.appendChild(input.element);\n step.appendChild(errorEl);\n\n this.bodyEl.replaceChildren(step);\n\n // Footer\n this.footerEl.replaceChildren();\n const hideProgress =\n !!this.questionnaire.hideProgress ||\n this.questionnaire.questions.length <= 1;\n const isBottomProgress =\n !hideProgress && this.effectiveProgressPosition() === \"bottom\";\n\n const back =\n idx > 0\n ? (() => {\n const b = document.createElement(\"button\");\n b.type = \"button\";\n b.className = \"qaid-q-btn qaid-q-btn-secondary\";\n b.textContent = this.questionnaire!.backLabel ?? \"Back\";\n b.addEventListener(\"click\", () => this.back());\n return b;\n })()\n : null;\n\n const next = document.createElement(\"button\");\n next.type = \"button\";\n next.className = \"qaid-q-btn qaid-q-btn-primary\";\n next.textContent = isLast\n ? (this.questionnaire.submitLabel ?? \"Submit\")\n : (this.questionnaire.nextLabel ?? \"Next\");\n next.addEventListener(\"click\", () => this.advance(question, errorEl));\n\n if (isBottomProgress) {\n // Single-row footer: [back] [progress fills] [savingEl][stepCounter] [next]\n this.footerEl.classList.add(\"qaid-q-footer--inline-progress\");\n if (back) this.footerEl.appendChild(back);\n if (this.progressEl) this.footerEl.appendChild(this.progressEl);\n if (this.savingEl) this.footerEl.appendChild(this.savingEl);\n if (this.stepCounterEl) this.footerEl.appendChild(this.stepCounterEl);\n this.footerEl.appendChild(next);\n } else {\n this.footerEl.classList.remove(\"qaid-q-footer--inline-progress\");\n const left = document.createElement(\"div\");\n left.className = \"qaid-q-footer-left\";\n const right = document.createElement(\"div\");\n right.className = \"qaid-q-footer-right\";\n\n if (back) left.appendChild(back);\n\n const hint = document.createElement(\"span\");\n hint.className = \"qaid-q-hint\";\n hint.innerHTML = isLast\n ? `<kbd>Enter</kbd> to submit`\n : `<kbd>Enter</kbd> to continue`;\n right.appendChild(hint);\n right.appendChild(next);\n\n this.footerEl.appendChild(left);\n this.footerEl.appendChild(right);\n }\n\n // Focus policy:\n // - Initial render: only focus when `autoFocus` is enabled.\n // Embedded previews and \"open in page\" usages set autoFocus:false\n // to avoid yanking focus on mount.\n // - Every subsequent step (advance / back): always focus the\n // active input. The user just performed a keyboard or click\n // action expecting to interact with the next question, and\n // screen-reader users need focus to move so the new question's\n // accessible name is announced.\n const isInitialRender = !this.hasRenderedStep;\n this.hasRenderedStep = true;\n const shouldFocus = isInitialRender ? this.config.autoFocus : true;\n if (shouldFocus) {\n requestAnimationFrame(() => input.focus());\n }\n }\n\n private renderDone(): void {\n if (!this.cardEl || !this.questionnaire) return;\n this.cardEl.replaceChildren();\n\n const done = document.createElement(\"div\");\n done.className = \"qaid-q-done\";\n\n const icon = document.createElement(\"div\");\n icon.className = \"qaid-q-done-icon\";\n icon.innerHTML = CHECK_ICON;\n done.appendChild(icon);\n\n const title = document.createElement(\"h3\");\n title.className = \"qaid-q-done-title\";\n title.textContent = this.questionnaire.thankYouTitle ?? \"Thank you!\";\n done.appendChild(title);\n\n if (this.questionnaire.thankYouMessage) {\n const msg = document.createElement(\"p\");\n msg.className = \"qaid-q-done-message\";\n msg.textContent = this.questionnaire.thankYouMessage;\n done.appendChild(msg);\n }\n\n if (!this.isUserContainer) {\n const closeBtn = document.createElement(\"button\");\n closeBtn.type = \"button\";\n closeBtn.className = \"qaid-q-btn qaid-q-btn-primary\";\n closeBtn.textContent = \"Close\";\n closeBtn.style.marginTop = \"1rem\";\n closeBtn.addEventListener(\"click\", () => this.close());\n done.appendChild(closeBtn);\n }\n\n this.cardEl.appendChild(done);\n }\n\n // ------------------------------------------------------------------\n // Navigation\n // ------------------------------------------------------------------\n\n private advance(question: Question, errorEl: HTMLElement): void {\n if (!this.currentInput || !this.questionnaire) return;\n if (!this.currentInput.isValid()) {\n errorEl.textContent = validationMessage(question);\n this.currentInput.focus();\n return;\n }\n // Capture latest value (e.g. range may not have fired its first change).\n // handleAnswerChange already calls recomputeVisible after recording\n // the answer, so visibleQuestions is up-to-date here.\n this.handleAnswerChange(question, this.currentInput.getValue(), { immediate: true });\n\n const last = this.stepIndex === this.visibleQuestions.length - 1;\n if (last) {\n void this.submit();\n return;\n }\n this.stepIndex++;\n this.renderStep();\n }\n\n private back(): void {\n // Flush any pending save before navigating\n this.flushPendingSave();\n if (this.stepIndex > 0) {\n this.stepIndex--;\n // Defensive: a previous answer may have been changed in a way that\n // shrinks the visible tail. Recompute and clamp.\n this.recomputeVisible();\n if (this.stepIndex >= this.visibleQuestions.length) {\n this.stepIndex = Math.max(0, this.visibleQuestions.length - 1);\n }\n this.renderStep();\n }\n }\n\n // ------------------------------------------------------------------\n // Answer handling + autosave\n // ------------------------------------------------------------------\n\n private recomputeVisible(): void {\n if (!this.questionnaire) return;\n this.visibleQuestions = getVisibleQuestions(this.questionnaire, this.answers);\n }\n\n private handleAnswerChange(\n question: Question,\n value: AnswerValue,\n opts: { immediate?: boolean } = {},\n ): void {\n this.answers[question.id] = value;\n // Visibility may flip on follow-up questions when this answer\n // changes. Recompute synchronously so advance() / back() see the\n // up-to-date list. We don't re-render here — the user is mid-edit.\n this.recomputeVisible();\n\n const debounced =\n question.type === \"text\" ||\n question.type === \"currency\" ||\n question.type === \"range\";\n\n if (opts.immediate || !debounced) {\n this.flushPendingSave();\n this.saveAnswer(question.id, value);\n return;\n }\n\n // Debounce — collapse rapid keystrokes into one PATCH.\n this.pendingSaveQuestionId = question.id;\n this.pendingSaveValue = value;\n if (this.pendingSaveTimer) clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = setTimeout(() => {\n this.flushPendingSave();\n }, this.config.saveDebounceMs);\n }\n\n private flushPendingSave(): void {\n if (this.pendingSaveTimer) {\n clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = null;\n }\n if (this.pendingSaveQuestionId !== null) {\n const id = this.pendingSaveQuestionId;\n const value = this.pendingSaveValue;\n this.pendingSaveQuestionId = null;\n this.pendingSaveValue = null;\n this.saveAnswer(id, value);\n }\n }\n\n private saveAnswer(questionId: string, value: AnswerValue): void {\n this.showSaving(true);\n this.inflightSaves++;\n void this.doSave(questionId, value).finally(() => {\n this.inflightSaves--;\n if (this.inflightSaves === 0) this.showSaving(false);\n });\n }\n\n private async doSave(questionId: string, value: AnswerValue): Promise<void> {\n // Wait for response id to be assigned before sending updates.\n // If creation is still in flight, queue tightly via microtask polling.\n let waited = 0;\n while (this.responseId === null && waited < 5000) {\n await new Promise((r) => setTimeout(r, 50));\n waited += 50;\n }\n if (this.responseId === null) return;\n\n try {\n await fetch(`${this.config.endpoint}/${this.responseId}`, {\n method: \"PATCH\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({ questionId, value }),\n });\n } catch (err) {\n console.error(\"[quests-embed] failed to save answer:\", err);\n }\n }\n\n private async createResponse(): Promise<void> {\n try {\n const res = await fetch(this.config.endpoint, {\n method: \"POST\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({\n apiKey: this.config.apiKey || undefined,\n questId: this.questionnaire?.id,\n pageUrl: window.location.href,\n visitorId: this.visitorId,\n userAgent: navigator.userAgent,\n }),\n });\n if (res.ok) {\n const data = (await res.json()) as CreateResponseResult;\n this.responseId = data.id;\n }\n } catch (err) {\n console.error(\"[quests-embed] failed to create response:\", err);\n }\n }\n\n private async submit(): Promise<void> {\n this.flushPendingSave();\n // Wait for any in-flight saves so the server sees the final state.\n while (this.inflightSaves > 0) {\n await new Promise((r) => setTimeout(r, 50));\n }\n\n if (this.responseId !== null) {\n try {\n await fetch(`${this.config.endpoint}/${this.responseId}/submit`, {\n method: \"POST\",\n headers: this.jsonHeaders(),\n body: JSON.stringify({ answers: this.answers }),\n });\n } catch (err) {\n console.error(\"[quests-embed] failed to submit:\", err);\n }\n }\n\n this.state = \"DONE\";\n this.renderDone();\n }\n\n private jsonHeaders(): Record<string, string> {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n };\n if (this.config.apiKey) headers[\"X-API-Key\"] = this.config.apiKey;\n return headers;\n }\n\n private showSaving(visible: boolean): void {\n if (!this.savingEl) return;\n this.savingEl.classList.toggle(\"qaid-q-visible\", visible);\n }\n\n // ------------------------------------------------------------------\n // Keyboard / lifecycle\n // ------------------------------------------------------------------\n\n private handleKeyDown(e: KeyboardEvent): void {\n if (e.key === \"Escape\" && !this.isUserContainer && this.state !== \"DONE\") {\n this.close();\n }\n }\n\n private close(): void {\n this.flushPendingSave();\n this.destroy();\n }\n\n /** Destroy the embed and clean up all resources */\n public destroy(): void {\n document.removeEventListener(\"keydown\", this.boundKeyDown);\n if (this.pendingSaveTimer) {\n clearTimeout(this.pendingSaveTimer);\n this.pendingSaveTimer = null;\n }\n if (this.shadowHost) {\n this.shadowHost.remove();\n this.shadowHost = null;\n this.shadowRoot = null;\n }\n this.rootEl = null;\n this.cardEl = null;\n this.bodyEl = null;\n this.footerEl = null;\n this.titleEl = null;\n this.stepCounterEl = null;\n this.progressFillEl = null;\n this.savingEl = null;\n this.backdropEl = null;\n this.currentInput = null;\n }\n\n /** Read-only snapshot of current answers */\n public getAnswers(): Answers {\n return { ...this.answers };\n }\n\n /**\n * Jump to the visible question with the given id. Returns true if\n * the question is currently visible (and the embed navigated to\n * it), false if it's hidden by an unmet `visibleIf` predicate or\n * unknown. If the embed is still initializing, the request is\n * latched and applied as soon as the questionnaire is ready.\n *\n * Intended for editor previews and other host-driven step control.\n */\n public goToStep(questionId: string): boolean {\n if (this.state !== \"READY\" || !this.questionnaire) {\n this.pendingGoToStep = questionId;\n return false;\n }\n const idx = this.visibleQuestions.findIndex((q) => q.id === questionId);\n if (idx === -1) return false;\n if (idx === this.stepIndex) return true;\n this.flushPendingSave();\n this.stepIndex = idx;\n this.renderStep();\n return true;\n }\n}\n\nfunction validationMessage(q: Question): string {\n switch (q.type) {\n case \"text\":\n if (q.minLength) return `Please enter at least ${q.minLength} characters.`;\n return \"This field is required.\";\n case \"currency\":\n return \"Please enter a valid amount.\";\n case \"date\":\n return \"Please pick a date.\";\n case \"multiple-choice\":\n return q.multiple ? \"Please select at least one option.\" : \"Please select an option.\";\n case \"range\":\n return \"Please choose a value.\";\n }\n}\n","/**\n * @qaiddev/quests-embed\n *\n * Step-by-step JSON-defined form embed.\n *\n * Usage as ES module:\n * ```ts\n * import { QaidQuests } from \"@qaiddev/quests-embed\";\n *\n * new QaidQuests({\n * endpoint: \"/api/responses\",\n * configUrl: \"/forms/intake.json\",\n * container: \"#form\",\n * });\n * ```\n *\n * Usage via script tag (auto-init):\n * ```html\n * <script src=\"qaid-quests.umd.cjs\"\n * data-endpoint=\"/api/responses\"\n * data-config-url=\"/forms/intake.json\"\n * data-container=\"#form\"></script>\n * ```\n *\n * Or with a JSON config tag:\n * ```html\n * <script type=\"application/json\" data-quests-config>\n * { \"endpoint\": \"/api/responses\", \"configUrl\": \"/forms/intake.json\" }\n * </script>\n * <script src=\"qaid-quests.umd.cjs\"></script>\n * ```\n */\n\nimport { QaidQuests } from \"./embed\";\nimport type { QuestsConfig } from \"./types\";\n\nexport { QaidQuests };\nexport { getVisibleQuestions, evaluateRule } from \"./visibility\";\nexport type {\n QuestsConfig,\n ResolvedQuestsConfig,\n Questionnaire,\n Question,\n TextQuestion,\n CurrencyQuestion,\n RangeQuestion,\n DateQuestion,\n MultipleChoiceQuestion,\n MultipleChoiceOption,\n Answers,\n AnswerValue,\n VisibilityRule,\n CreateResponsePayload,\n CreateResponseResult,\n UpdateAnswerPayload,\n SubmitPayload,\n} from \"./types\";\n\nfunction findCssFromSelector(selector: string): string {\n const el = document.querySelector(selector);\n return el?.textContent?.trim() ?? \"\";\n}\n\nfunction parseJsonConfig(): Partial<QuestsConfig> | null {\n const tag = document.querySelector(\n 'script[type=\"application/json\"][data-quests-config]',\n );\n if (!tag) return null;\n const raw = tag.textContent?.trim();\n if (!raw) return null;\n try {\n const parsed = JSON.parse(raw) as Partial<QuestsConfig> & {\n cssSelector?: string;\n };\n if (parsed.cssSelector && !parsed.css) {\n parsed.css = findCssFromSelector(parsed.cssSelector);\n delete parsed.cssSelector;\n }\n return parsed;\n } catch {\n return null;\n }\n}\n\nfunction parseDataAttributes(\n script: HTMLScriptElement,\n): Partial<QuestsConfig> | null {\n const endpoint = script.getAttribute(\"data-endpoint\");\n if (!endpoint) return null;\n\n const configUrl = script.getAttribute(\"data-config-url\");\n const apiKey = script.getAttribute(\"data-api-key\");\n const container = script.getAttribute(\"data-container\");\n const zIndex = script.getAttribute(\"data-zindex\");\n const positiveColor = script.getAttribute(\"data-positive-color\");\n const negativeColor = script.getAttribute(\"data-negative-color\");\n const markerColor = script.getAttribute(\"data-marker-color\");\n const modalWidth = script.getAttribute(\"data-modal-width\");\n const backdropOpacity = script.getAttribute(\"data-backdrop-opacity\");\n const fontFamily = script.getAttribute(\"data-font-family\");\n const fontSize = script.getAttribute(\"data-font-size\");\n const cssSelector = script.getAttribute(\"data-css-selector\");\n const autoAdvance = script.getAttribute(\"data-auto-advance\");\n const saveDebounceMs = script.getAttribute(\"data-save-debounce-ms\");\n\n return {\n endpoint,\n configUrl: configUrl ?? undefined,\n apiKey: apiKey ?? undefined,\n container: container ?? undefined,\n zIndex: zIndex ? parseInt(zIndex, 10) : undefined,\n colors: {\n positive: positiveColor ?? undefined,\n negative: negativeColor ?? undefined,\n marker: markerColor ?? undefined,\n },\n modalWidth: modalWidth ? parseInt(modalWidth, 10) : undefined,\n backdropOpacity: backdropOpacity ? parseFloat(backdropOpacity) : undefined,\n fontFamily: fontFamily ?? undefined,\n fontSize: fontSize ? parseInt(fontSize, 10) : undefined,\n css: cssSelector ? findCssFromSelector(cssSelector) : undefined,\n autoAdvance: autoAdvance === \"true\" ? true : undefined,\n saveDebounceMs: saveDebounceMs ? parseInt(saveDebounceMs, 10) : undefined,\n };\n}\n\nif (typeof document !== \"undefined\") {\n const initFromScript = (): void => {\n const script = document.currentScript as HTMLScriptElement | null;\n const jsonConfig = parseJsonConfig();\n const dataConfig = script ? parseDataAttributes(script) : null;\n const config = jsonConfig ?? dataConfig;\n if (config?.endpoint && (config.configUrl || config.questionnaire)) {\n new QaidQuests(config as QuestsConfig);\n }\n };\n\n if (document.readyState === \"loading\") {\n document.addEventListener(\"DOMContentLoaded\", initFromScript);\n } else {\n initFromScript();\n }\n}\n"],"names":["getLuminance","r","g","b","rs","gs","bs","c","parseColor","color","hex","fullHex","num","match","getContrastTextColor","bgColor","rgb","buildCssVars","options","positiveColor","negativeColor","markerColor","modalWidth","backdropOpacity","fontFamily","fontSize","applyCssVars","el","vars","name","value","getEmbedStyles","shadowStyles","createInput","createTextInput","createCurrencyInput","createRangeInput","createDateInput","createMultipleChoiceInput","q","opts","initial","textarea","input","inputAutocomplete","e","len","v","wrap","prefix","currencySymbol","raw","currency","locale","p","valueDisplay","valueText","unit","updateDisplay","bounds","lower","upper","alignment","layoutClass","selected","buttons","opt","idx","btn","marker","body","img","label","desc","key","toggle","focusOption","k","on","currentValue","it","getVisibleQuestions","answers","qn","evaluateRule","rule","isAnswered","matchesAtomic","x","answer","target","a","VISITOR_ID_KEY","getOrCreateVisitorId","id","CLOSE_ICON","CHECK_ICON","QaidQuests","config","err","res","userContainer","baseStyle","themeStyle","modal","msg","heading","hideProgress","isBottom","headerHidden","hasTitle","hasDescription","hasCloseBtn","headerHasRightContent","dot","savingText","showHeader","header","titleWrap","right","closeBtn","total","question","pct","step","star","errorEl","initialValue","isLast","isBottomProgress","back","next","left","hint","isInitialRender","done","icon","title","validationMessage","debounced","questionId","waited","data","headers","visible","findCssFromSelector","selector","parseJsonConfig","tag","parsed","parseDataAttributes","script","endpoint","configUrl","apiKey","container","zIndex","cssSelector","autoAdvance","saveDebounceMs","initFromScript","jsonConfig","dataConfig"],"mappings":"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"}