@magicx-eng/ai-autocomplete-react 0.1.41 → 0.1.42

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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/AIAutocomplete.module.css.js","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/AIAutocompleteDropdown.module.css.js","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/PillList.module.css.js","../src/components/PillList.tsx","../src/components/SuggestionGrid.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/SuggestionGrid.module.css.js","../src/components/SuggestionItem.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/SuggestionItem.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/Users/saharshv/MagicX/ai-autocomplete-react/src/appearance.css.js","../src/core/dom/cursorUtils.ts","../src/core/render/renderEditable.ts","../src/hooks/useAIAutocomplete.ts","../src/utils/buildQuery.ts","../src/utils/filtering.ts","../src/utils/modeController.ts","../src/utils/segments.ts","../src/utils/tokenManager.ts","../src/utils/auth.ts","../src/utils/telemetry.ts","../src/utils/api.ts","../src/utils/overrides.ts","../src/core/controllers/fetchController.ts","../src/core/controllers/keyboardController.ts","../src/core/controllers/pillsController.ts","../src/core/render/renderPills.ts","../src/core/render/renderDropdown.ts","../src/core/render/renderDropdownOnly.ts","../src/core/render/renderInput.ts","../src/core/state.ts","../src/core/styleInjector.ts","../src/core/AIAutocomplete.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import {\n forwardRef,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport \"./appearance.css\";\nimport { PillList } from \"./components/PillList\";\nimport {\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n setCursorOffset,\n} from \"./core/dom/cursorUtils\";\nimport { renderEditableContent } from \"./core/render/renderEditable\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type {\n AIAutocompleteHandle,\n AIAutocompleteProps,\n AppearanceMode,\n AutocompleteResult,\n} from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\nimport { ModeController } from \"./utils/modeController\";\n\nfunction resolveInitialMode(mode: AppearanceMode): \"light\" | \"dark\" {\n if (mode !== \"auto\") return mode;\n if (typeof window === \"undefined\") return \"dark\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n\nlet plaintextOnlyCache: boolean | undefined;\nfunction supportsPlaintextOnly(): boolean {\n if (plaintextOnlyCache !== undefined) return plaintextOnlyCache;\n if (typeof document === \"undefined\") return false;\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n plaintextOnlyCache = probe.contentEditable === \"plaintext-only\";\n return plaintextOnlyCache;\n}\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n className,\n apiConfig,\n columns,\n pillPlacement = \"inline\",\n mode = \"auto\",\n optionsPosition = \"below\",\n animations = true,\n dropdownTrigger,\n closeDropdownOnBlur,\n autoFocus = true,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n submitButton,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const inputRef = useRef<HTMLDivElement>(null);\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const modeControllerRef = useRef<ModeController | null>(null);\n const composingRef = useRef(false);\n const lastSeenParamIdRef = useRef<string>(\"\");\n const lastEditingIdRef = useRef<string>(\"\");\n const caretOffsetRef = useRef<number | null>(null);\n // Set in the input event handler; selectionchange suppresses post-input\n // caret-move tracking within this window so typing doesn't get treated\n // as navigation.\n const lastInputAtRef = useRef(0);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n if (modeControllerRef.current) {\n modeControllerRef.current.setMode(mode);\n } else {\n modeControllerRef.current = new ModeController(el, mode);\n }\n return () => {\n modeControllerRef.current?.destroy();\n modeControllerRef.current = null;\n };\n }, [mode]);\n\n const handleSetCursor = useCallback((offset: number) => {\n const el = inputRef.current;\n if (el) setCursorOffset(el, offset);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n newParamId,\n clearNewParamId,\n placeholderText,\n isFocused,\n isDropdownOpen,\n isLoading,\n activeIndex,\n listboxId,\n handleTextChange,\n handleKeyDown,\n setFocused,\n editingParam,\n editingAnchor,\n caretOffset,\n startEditingParam,\n handleCaretAfterInput,\n handleCaretMove,\n replaceEditingRange,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n columns,\n dropdownTrigger,\n closeDropdownOnBlur,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n source: \"full-sdk\",\n setCursor: handleSetCursor,\n });\n\n caretOffsetRef.current = caretOffset;\n\n // Auto-focus on mount once the hook's instance is ready.\n useEffect(() => {\n if (!autoFocus) return;\n const el = inputRef.current;\n if (!el) return;\n if (document.activeElement === el) {\n setFocused(true);\n } else {\n el.focus();\n }\n }, [autoFocus, setFocused]);\n\n // Shimmer auto-clear after the animation finishes.\n useEffect(() => {\n if (!newParamId) return;\n const t = window.setTimeout(() => clearNewParamId(), 650);\n return () => window.clearTimeout(t);\n }, [newParamId, clearNewParamId]);\n\n // `selectionchange` is the canonical signal for \"caret moved\" in\n // contentEditable land. Anchored inside the editor: a caret that lands\n // inside a `<strong>` triggers re-edit mode; a caret that leaves the\n // current editing region exits it.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const doc = el.ownerDocument ?? document;\n const onSelectionChange = () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return;\n const anchor = sel.anchorNode;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n const strong = startEl?.closest<HTMLElement>('strong[data-seg=\"completed\"][data-param-id]');\n const enclosing = strong?.dataset.paramId ?? null;\n if (enclosing && enclosing !== editingParam?.id) {\n startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAtRef.current < 50) return;\n handleCaretMove(getCursorOffset(el));\n };\n doc.addEventListener(\"selectionchange\", onSelectionChange);\n return () => doc.removeEventListener(\"selectionchange\", onSelectionChange);\n }, [editingParam, startEditingParam, handleCaretMove]);\n\n // Render segments imperatively into the contentEditable. useLayoutEffect\n // runs before paint so the caret is restored without a one-frame flicker.\n useLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n renderEditableContent({\n input: el,\n segments,\n newParamId,\n editingParamId: editingParam?.id ?? null,\n placeholderText: placeholderText ?? \"\",\n isFocused,\n });\n }, [segments, newParamId, editingParam, placeholderText, isFocused]);\n\n // After a fresh option selection (newParamId changed), refocus the editor\n // and place the caret at the end. Mirrors the vanilla core's `justSelected`\n // logic in renderInput.ts — clicking a dropdown option moves focus to the\n // option button, and we want to return it to the editor so typing can\n // continue immediately.\n useLayoutEffect(() => {\n const previous = lastSeenParamIdRef.current;\n const current = newParamId ?? \"\";\n lastSeenParamIdRef.current = current;\n if (!current || current === previous) return;\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n // Every promote path stamps `caretOffset` with the position right\n // after the new param's trailing space, so use it. Read via ref so the\n // effect stays gated on newParamId (not every caret-move).\n const desired = caretOffsetRef.current ?? plainTextLength(el);\n setCursorOffset(el, desired);\n }, [newParamId]);\n\n // On re-edit-mode entry, park the caret just BEFORE the bold strong so\n // typing/backspace via the `beforeinput` intercept replaces the param\n // cleanly (instead of inserting mid-letter inside the bold span).\n useLayoutEffect(() => {\n const previous = lastEditingIdRef.current;\n const current = editingParam?.id ?? \"\";\n lastEditingIdRef.current = current;\n if (!current || current === previous || editingAnchor == null) return;\n const el = inputRef.current;\n if (!el) return;\n setCursorOffset(el, editingAnchor);\n }, [editingParam, editingAnchor]);\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => inputRef.current?.focus(),\n blur: () => inputRef.current?.blur(),\n reset,\n setMode: (m) => modeControllerRef.current?.setMode(m),\n }),\n [reset],\n );\n\n const fireInput = useCallback(() => {\n if (composingRef.current) return;\n const el = inputRef.current;\n if (!el) return;\n const raw = extractPlainText(el);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const next = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n handleTextChange(next);\n }, [handleTextChange]);\n\n const handleInputEvent = useCallback(() => {\n lastInputAtRef.current = performance.now();\n fireInput();\n const el = inputRef.current;\n if (el) handleCaretAfterInput(getCursorOffset(el));\n }, [fireInput, handleCaretAfterInput]);\n\n // React's synthetic `onBeforeInput` is wired to the legacy `textInput`\n // event and doesn't reliably fire for `delete*` input types, so we\n // attach a native `beforeinput` listener directly on the editor.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const onBeforeInput = (e: Event) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n };\n el.addEventListener(\"beforeinput\", onBeforeInput);\n return () => el.removeEventListener(\"beforeinput\", onBeforeInput);\n }, [replaceEditingRange]);\n\n const handleCompositionStart = useCallback(() => {\n composingRef.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(() => {\n composingRef.current = false;\n fireInput();\n }, [fireInput]);\n\n const handlePaste = useCallback(\n (e: React.ClipboardEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = inputRef.current;\n if (!el) return;\n const text = (e.clipboardData.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!el.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n [fireInput],\n );\n\n const handleKeyDownReact = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => handleKeyDown(e),\n [handleKeyDown],\n );\n\n const canSubmit = !!segments.length || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const text = inputRef.current ? extractPlainText(inputRef.current) : \"\";\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n onSubmit({\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n }, [canSubmit, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const handleWrapperClick = useCallback((e: React.MouseEvent<HTMLDivElement>) => {\n // Clicking a pill activates it; don't steal focus away from where it lands.\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"[data-aia-pill]\")) return;\n inputRef.current?.focus();\n }, []);\n\n const showInlinePills = pillPlacement === \"inline\";\n const showDropdownPills = pillPlacement === \"dropdown\";\n const activeDescendantId = activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined;\n const ceMode = supportsPlaintextOnly() ? \"plaintext-only\" : \"true\";\n\n return (\n <div\n ref={containerRef}\n className={`magicx-aia ${styles.container} ${className ?? \"\"}`}\n data-pill-placement={pillPlacement}\n data-options-position={optionsPosition}\n data-animations={animations ? \"on\" : \"off\"}\n data-mode={resolveInitialMode(mode)}\n >\n <AIAutocompleteDropdown {...dropdownProps} showPills={showDropdownPills} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to editor focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to editor */}\n <div className={styles.inputWrapper} onClick={handleWrapperClick}>\n <div className={styles.editorArea} data-aia-editor=\"\">\n <div\n ref={inputRef}\n className={styles.input}\n data-aia-input=\"\"\n contentEditable={ceMode as unknown as boolean}\n suppressContentEditableWarning\n tabIndex={0}\n role=\"combobox\"\n aria-autocomplete=\"list\"\n aria-haspopup=\"listbox\"\n aria-controls={listboxId}\n aria-expanded={isDropdownOpen}\n aria-activedescendant={activeDescendantId}\n spellCheck\n enterKeyHint=\"send\"\n onInput={handleInputEvent}\n onKeyDown={handleKeyDownReact}\n onCompositionStart={handleCompositionStart}\n onCompositionEnd={handleCompositionEnd}\n onPaste={handlePaste}\n onFocus={() => setFocused(true)}\n onBlur={() => setFocused(false)}\n />\n {showInlinePills && (isLoading || suggestionPills.length > 0) && (\n <span className={styles.pillListContainer} data-aia-pill-list-container=\"\">\n <PillList\n pills={suggestionPills}\n activePillIndex={0}\n onSelectPill={setActivePill}\n loading={isLoading}\n />\n </span>\n )}\n </div>\n {submitButton === null ? null : submitButton === undefined ? (\n <button\n type=\"button\"\n data-aia-submit=\"\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n ) : (\n // biome-ignore lint/a11y/useKeyWithClickEvents: consumer-provided element handles its own keyboard interaction\n // biome-ignore lint/a11y/noStaticElementInteractions: transparent slot — click bubbles from consumer's element\n <span\n data-aia-submit=\"\"\n className={styles.submitSlot}\n onClick={(e) => {\n if (!canSubmit) return;\n e.stopPropagation();\n handleSubmit();\n }}\n >\n {submitButton}\n </span>\n )}\n </div>\n </div>\n );\n },\n);\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-cc65f4cc\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-cc65f4cc\";\n s.textContent = `.AIAutocomplete-module_container_KKjFU {\n position: relative;\n /* Inherits the host page's font by default. Consumers can pin a specific\n font on the library via \\`--aia-font-family: 'Custom Font'\\` without\n affecting the surrounding page. */\n font-family: var(--aia-font-family, inherit);\n container-type: inline-size;\n}\n\n.AIAutocomplete-module_inputWrapper_FLq1b {\n padding: 20px;\n border: 1px solid var(--aia-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 0px;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq {\n position: relative;\n flex: 1;\n min-width: 0;\n min-height: 38px;\n line-height: 38px;\n font-family: inherit;\n font-size: var(--aia-written-text-font-size, 19px);\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n.AIAutocomplete-module_input_IW-P- {\n display: inline;\n outline: none;\n background: transparent;\n color: var(--aia-written-text-color, var(--aia-color-text-default, #fff));\n caret-color: var(\n --aia-caret-color,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff))\n );\n font-weight: 200;\n}\n\n/* Completed params render as inline bold runs. \\`:where()\\` keeps specificity\n at (0,2,0) so consumers can override without \\`!important\\`. */\n:where(.AIAutocomplete-module_input_IW-P-) strong {\n font-weight: 500;\n letter-spacing: -0.01em;\n}\n\n/* Re-edit highlight — the editing class is written by the shared renderer\n (a global string), so target it via an attribute selector to bypass\n CSS Modules' class-name hashing. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"] {\n outline: 1.5px solid var(--aia-edit-outline, currentColor);\n outline-offset: 1px;\n border-radius: 4px;\n caret-color: transparent;\n}\n\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::selection {\n background: transparent;\n color: inherit;\n}\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::-moz-selection {\n background: transparent;\n color: inherit;\n}\n\n/* Placeholder via ::before so it doesn't enter the editable DOM. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n content: attr(data-placeholder);\n color: var(--aia-color-text-muted, #c1c4cb);\n opacity: 0.7;\n pointer-events: none;\n}\n\n/* Empty inline contentEditables have no inline box for the caret to render\n in. Switch to inline-block (min-width matches the caret line) when empty,\n so the caret stays visible while focused. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"] {\n display: inline-block;\n min-width: 1px;\n vertical-align: top;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA {\n display: inline;\n margin-left: 8px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA:empty {\n margin-left: 0;\n}\n\n.AIAutocomplete-module_submitButton_sl1Mi {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--aia-submit-bg, var(--aia-color-text-default, #fff));\n color: var(--aia-submit-color, var(--aia-color-bg-default, #000));\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.AIAutocomplete-module_submitButton_sl1Mi:hover {\n opacity: 0.85;\n}\n\n.AIAutocomplete-module_submitSlot_GhuCM {\n display: contents;\n}\n\n/* Text shimmer on newly added completed param. The shimmer span wraps the\n bold completion text inside the editor; a moving gradient clipped to the\n text shape produces the sweep effect. */\n.AIAutocomplete-module_shimmerRevealed_RR8dp {\n color: transparent;\n background: linear-gradient(\n 120deg,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,\n #b0b0b0 48%,\n #b0b0b0 52%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%\n );\n background-size: 200% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n}\n\n.AIAutocomplete-module_shimmerSweep_ARCon {\n animation: AIAutocomplete-module_textShimmer_eCLdq 650ms ease-out forwards;\n}\n\n@keyframes AIAutocomplete-module_textShimmer_eCLdq {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -50% 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"container\":\"AIAutocomplete-module_container_KKjFU\",\"inputWrapper\":\"AIAutocomplete-module_inputWrapper_FLq1b\",\"editorArea\":\"AIAutocomplete-module_editorArea_7rBWq\",\"input\":\"AIAutocomplete-module_input_IW-P-\",\"pillListContainer\":\"AIAutocomplete-module_pillListContainer_h92IA\",\"submitButton\":\"AIAutocomplete-module_submitButton_sl1Mi\",\"submitSlot\":\"AIAutocomplete-module_submitSlot_GhuCM\",\"shimmerRevealed\":\"AIAutocomplete-module_shimmerRevealed_RR8dp\",\"shimmerSweep\":\"AIAutocomplete-module_shimmerSweep_ARCon\",\"textShimmer\":\"AIAutocomplete-module_textShimmer_eCLdq\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-2eef895d\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-2eef895d\";\n s.textContent = `.AIAutocompleteDropdown-module_dropdown_yz2KC {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n max-width: 516px;\n margin-top: 6px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n container-type: inline-size;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset, /* same color as bg */\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset, /* same color as bg */\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n border-radius: 28px;\n}\n\n.AIAutocompleteDropdown-module_visible_QCoXj {\n opacity: 1;\n pointer-events: auto;\n}\n\n.AIAutocompleteDropdown-module_pillBar_pwTXe {\n padding: 27px 27px 0px 27px;\n}\n\n/* --- Fallback loading skeleton (only when no pills/options are cached) --- */\n.AIAutocompleteDropdown-module_skeletonBars_HVr9C {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 25px;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx {\n display: block;\n height: 19px;\n border-radius: 999px;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n opacity: 0.5;\n animation: AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q 1.4s ease-in-out infinite;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(2) {\n animation-delay: 150ms;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(3) {\n animation-delay: 300ms;\n}\n\n@keyframes AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q {\n 0%,\n 100% {\n opacity: 0.5;\n }\n 50% {\n opacity: 0.25;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"dropdown\":\"AIAutocompleteDropdown-module_dropdown_yz2KC\",\"visible\":\"AIAutocompleteDropdown-module_visible_QCoXj\",\"pillBar\":\"AIAutocompleteDropdown-module_pillBar_pwTXe\",\"skeletonBars\":\"AIAutocompleteDropdown-module_skeletonBars_HVr9C\",\"skeletonBar\":\"AIAutocompleteDropdown-module_skeletonBar_O3xIx\",\"aiaSkeletonPulse\":\"AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-b745b4fb\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-b745b4fb\";\n s.textContent = `.PillList-module_list_qvLqO {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.PillList-module_pill_osSyz {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 13px 13px;\n border: none;\n border-radius: 999px;\n background: rgba(49, 50, 85, 0.25);\n background: color-mix(\n in srgb,\n var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 25%,\n transparent\n );\n color: var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));\n font-family: inherit;\n font-size: var(--aia-pill-font-size, 19px);\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: PillList-module_fadeIn_Aezob 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n}\n\n.PillList-module_rounded_WvXy4 {\n border-radius: 999px;\n}\n\n/* Loading skeleton — preserves the pill's exact box (same width and height)\n and just hides the text. The pill's native background acts as the visible\n shape; the pulse provides the shimmer. */\n.PillList-module_skeleton_Lp8x6 {\n pointer-events: none;\n cursor: default;\n color: transparent;\n animation: PillList-module_skeletonPulse_xZ8Yf 1.4s ease-in-out infinite;\n}\n\n@keyframes PillList-module_skeletonPulse_xZ8Yf {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n\n.PillList-module_pill_osSyz:hover {\n filter: brightness(1.2);\n}\n\n.PillList-module_active_Oll-- {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes PillList-module_fadeIn_Aezob {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"list\":\"PillList-module_list_qvLqO\",\"pill\":\"PillList-module_pill_osSyz\",\"fadeIn\":\"PillList-module_fadeIn_Aezob\",\"rounded\":\"PillList-module_rounded_WvXy4\",\"skeleton\":\"PillList-module_skeleton_Lp8x6\",\"skeletonPulse\":\"PillList-module_skeletonPulse_xZ8Yf\",\"active\":\"PillList-module_active_Oll--\"};","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n /** Use capsule-shaped pills (fully rounded). Default: false. */\n rounded?: boolean;\n /**\n * When true, the rendered pills become non-interactive shimmering skeletons.\n * Real pills (with their text) are rendered when provided so widths/positions\n * match the previous state; when `pills` is empty, fixed-width fallback\n * placeholders are rendered instead.\n */\n loading?: boolean;\n}\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({\n pills,\n activePillIndex,\n onSelectPill,\n rounded,\n loading,\n}: PillListProps) {\n if (loading && pills.length === 0) {\n return (\n <span className={styles.list} data-aia-pill-list-loading=\"\">\n {FALLBACK_SKELETON_WIDTHS.map((w, i) => (\n <span\n key={`skel-${w}`}\n data-aia-pill-skeleton=\"\"\n className={`${styles.pill} ${rounded ? styles.rounded : \"\"} ${styles.skeleton}`}\n style={{ width: w, opacity: getPillOpacity(i) }}\n />\n ))}\n </span>\n );\n }\n\n return (\n <span className={styles.list} data-aia-pill-list-loading={loading ? \"\" : undefined}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n data-aia-pill=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n tabIndex={-1}\n contentEditable={false}\n suppressContentEditableWarning\n className={`${styles.pill} ${rounded ? styles.rounded : \"\"} ${i === activePillIndex && !loading ? styles.active : \"\"} ${loading ? styles.skeleton : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onMouseDown={(e) => e.preventDefault()}\n onClick={loading ? undefined : () => onSelectPill(i)}\n disabled={loading}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n loading?: boolean;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n loading,\n}: SuggestionGridProps) {\n const gridRef = useRef<HTMLDivElement>(null);\n const [hasBottomOverflow, setHasBottomOverflow] = useState(false);\n\n useEffect(() => {\n const el = gridRef.current;\n if (!el) return;\n\n const update = () => {\n setHasBottomOverflow(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n };\n\n el.addEventListener(\"scroll\", update, { passive: true });\n const resizeObserver = new ResizeObserver(update);\n resizeObserver.observe(el);\n\n return () => {\n el.removeEventListener(\"scroll\", update);\n resizeObserver.disconnect();\n };\n }, []);\n\n // Re-measure synchronously when the option list changes. ResizeObserver\n // misses this case (the grid hits max-height, so scrollHeight grows but the\n // observed box doesn't) and useEffect would leave a frame of stale fade.\n // biome-ignore lint/correctness/useExhaustiveDependencies: options is a trigger-only dep\n useLayoutEffect(() => {\n const el = gridRef.current;\n if (!el) return;\n setHasBottomOverflow(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n }, [options]);\n\n return (\n <div className={styles.scrollWrapper} data-fade={hasBottomOverflow ? \"\" : undefined}>\n <div ref={gridRef} className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n loading={loading}\n />\n ))}\n </div>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-d91f2b06\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-d91f2b06\";\n s.textContent = `.SuggestionGrid-module_scrollWrapper_MOqfw {\n position: relative;\n}\n\n.SuggestionGrid-module_scrollWrapper_MOqfw::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n height: 50%;\n pointer-events: none;\n opacity: 0;\n transition: opacity 150ms ease-out;\n backdrop-filter: blur(12px);\n mask-image: linear-gradient(to bottom, transparent, white);\n}\n\n.SuggestionGrid-module_scrollWrapper_MOqfw[data-fade]::after {\n opacity: 1;\n}\n\n.SuggestionGrid-module_grid_jvaPb {\n display: grid;\n grid-template-columns: minmax(0, 250px);\n /* Pack rows from the top instead of stretching to fill the grid container. */\n grid-auto-rows: min-content;\n align-content: start;\n max-width: 100cqi;\n padding: 8px 8px;\n max-height: 200px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3)) transparent;\n}\n\n@container (min-width: 516px) {\n .SuggestionGrid-module_grid_jvaPb {\n grid-template-columns: repeat(2, minmax(0, 250px));\n justify-content: start;\n }\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar {\n width: 6px;\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar-thumb {\n background: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3));\n border-radius: 3px;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"scrollWrapper\":\"SuggestionGrid-module_scrollWrapper_MOqfw\",\"grid\":\"SuggestionGrid-module_grid_jvaPb\"};","import { useEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n loading?: boolean;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n loading,\n}: SuggestionItemProps) {\n const [pressed, setPressed] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n return () => clearTimeout(timerRef.current);\n }, []);\n\n const handleSelect = () => {\n if (loading || !option.is_tappable || pressed) return;\n setPressed(true);\n onSelect(option);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setPressed(false), 500);\n };\n\n const className = [\n styles.item,\n isHighlighted && !loading ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n pressed ? styles.pressed : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n aria-selected={isHighlighted}\n className={className}\n tabIndex={loading || !option.is_tappable ? -1 : 0}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (!loading && option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={!loading && option.is_tappable ? onHighlight : undefined}\n >\n <div className={styles.streaks} />\n <div className={styles.streaksVert} />\n <span className={styles.content}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-f6bdc634\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-f6bdc634\";\n s.textContent = `.SuggestionItem-module_item_d4vpD {\n position: relative;\n overflow: visible;\n display: flex;\n /* Top-align so single-line and multi-line options in the same row share\n the same baseline at the top edge of the cell. */\n align-items: flex-start;\n font-family: inherit;\n font-size: var(--aia-option-font-size, 19px);\n line-height: 24px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n white-space: normal;\n word-break: break-word;\n opacity: 0.4;\n border-radius: 12px;\n padding: 13px 13px;\n animation: SuggestionItem-module_fadeIn_I8u35 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes SuggestionItem-module_fadeIn_I8u35 {\n from {\n opacity: 0;\n }\n}\n\n.SuggestionItem-module_content_T-Qba {\n position: relative;\n z-index: 2;\n}\n\n.SuggestionItem-module_tappable_70KcX {\n cursor: pointer;\n}\n\n.SuggestionItem-module_tappable_70KcX:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.SuggestionItem-module_nonTappable_xSZM- {\n cursor: default;\n opacity: 0.3;\n}\n\n.SuggestionItem-module_highlighted_Hb0SU {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n opacity: 0.5;\n}\n\n.SuggestionItem-module_tag_e3Fwe {\n font-size: 11px;\n margin-left: 6px;\n opacity: 0.5;\n}\n\n.SuggestionItem-module_pressed_98o-r {\n opacity: 0.8;\n color: var(--aia-color-text-default, #fff);\n background: rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n animation:\n SuggestionItem-module_glassFade_oyiSj 500ms ease forwards,\n SuggestionItem-module_tapDown_G3WGz 500ms ease forwards;\n}\n\n@keyframes SuggestionItem-module_tapDown_G3WGz {\n 0% {\n transform: scale(1);\n }\n 30% {\n transform: scale(0.97);\n }\n 100% {\n transform: scale(1);\n }\n}\n\n@keyframes SuggestionItem-module_glassFade_oyiSj {\n 0% {\n background: var(--aia-streak-glass-bg, rgba(255, 255, 255, 0.1));\n }\n 100% {\n background: transparent;\n }\n}\n\n/* Border streaks — horizontal segments */\n\n.SuggestionItem-module_streaks_d9PEB {\n position: absolute;\n inset: 0;\n z-index: 1;\n pointer-events: none;\n border-radius: inherit;\n overflow: hidden;\n}\n\n/* Bottom horizontal: 40% from right → right corner */\n.SuggestionItem-module_streaks_d9PEB::before {\n content: \"\";\n position: absolute;\n bottom: -3px;\n left: 60%;\n width: 0;\n height: 6px;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.5) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Top horizontal: 40% from left → left corner */\n.SuggestionItem-module_streaks_d9PEB::after {\n content: \"\";\n position: absolute;\n top: -3px;\n right: 60%;\n width: 0;\n height: 6px;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.5) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Border streaks — vertical segments */\n\n.SuggestionItem-module_streaksVert_ERlV1 {\n position: absolute;\n inset: 0;\n z-index: 1;\n pointer-events: none;\n border-radius: inherit;\n overflow: hidden;\n}\n\n/* Right vertical: bottom-right corner → up */\n.SuggestionItem-module_streaksVert_ERlV1::before {\n content: \"\";\n position: absolute;\n bottom: 0;\n right: -3px;\n width: 6px;\n height: 0;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.4) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Left vertical: top-left corner → down */\n.SuggestionItem-module_streaksVert_ERlV1::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: -3px;\n width: 6px;\n height: 0;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.4) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaks_d9PEB::before {\n animation: SuggestionItem-module_streakHorizRight_aboGz 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaks_d9PEB::after {\n animation: SuggestionItem-module_streakHorizLeft_BreWJ 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaksVert_ERlV1::before {\n animation: SuggestionItem-module_streakVertUp_to1GD 300ms cubic-bezier(0.3, 0, 0.2, 1) 200ms forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaksVert_ERlV1::after {\n animation: SuggestionItem-module_streakVertDown_OrcLh 300ms cubic-bezier(0.3, 0, 0.2, 1) 200ms forwards;\n}\n\n/* Horizontal: bottom center-ish → right edge */\n@keyframes SuggestionItem-module_streakHorizRight_aboGz {\n 0% {\n width: 0;\n height: 4px;\n opacity: 0;\n filter: blur(1px);\n box-shadow: 0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 15% {\n height: 4px;\n opacity: 1;\n filter: blur(1px);\n box-shadow: 0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 80% {\n width: 50%;\n height: 10px;\n opacity: 0.8;\n filter: blur(3px);\n box-shadow: 0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.1);\n }\n 100% {\n width: 50%;\n height: 12px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.03);\n }\n}\n\n/* Horizontal: top center-ish → left edge */\n@keyframes SuggestionItem-module_streakHorizLeft_BreWJ {\n 0% {\n width: 0;\n height: 4px;\n opacity: 0;\n filter: blur(1px);\n box-shadow: 0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 15% {\n height: 4px;\n opacity: 1;\n filter: blur(1px);\n box-shadow: 0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 80% {\n width: 50%;\n height: 10px;\n opacity: 0.8;\n filter: blur(3px);\n box-shadow: 0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.1);\n }\n 100% {\n width: 50%;\n height: 12px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.03);\n }\n}\n\n/* Vertical segments start matching horizontal state at 200ms handoff */\n@keyframes SuggestionItem-module_streakVertUp_to1GD {\n 0% {\n height: 0;\n width: 6px;\n opacity: 0.9;\n filter: blur(1.8px);\n box-shadow: 0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.25);\n }\n 75% {\n height: 100%;\n width: 10px;\n opacity: 0.4;\n filter: blur(3px);\n box-shadow: 0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n }\n 100% {\n height: 100%;\n width: 14px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.02);\n }\n}\n\n@keyframes SuggestionItem-module_streakVertDown_OrcLh {\n 0% {\n height: 0;\n width: 6px;\n opacity: 0.9;\n filter: blur(1.8px);\n box-shadow: 0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.25);\n }\n 75% {\n height: 100%;\n width: 10px;\n opacity: 0.4;\n filter: blur(3px);\n box-shadow: 0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n }\n 100% {\n height: 100%;\n width: 14px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.02);\n }\n}\n\n/* Loading state — preserve the row's exact dimensions. The content stays an\n inline span so the line box and padding match the non-loading state byte\n for byte. Just hide the text and apply a background as a skeleton bar; the\n pulse provides the shimmer. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] {\n cursor: default;\n animation: SuggestionItem-module_skeletonPulse_plvdD 1.4s ease-in-out infinite;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_content_T-Qba {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n border-radius: 999px;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_tag_e3Fwe {\n display: none;\n}\n\n@keyframes SuggestionItem-module_skeletonPulse_plvdD {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"item\":\"SuggestionItem-module_item_d4vpD\",\"fadeIn\":\"SuggestionItem-module_fadeIn_I8u35\",\"content\":\"SuggestionItem-module_content_T-Qba\",\"tappable\":\"SuggestionItem-module_tappable_70KcX\",\"nonTappable\":\"SuggestionItem-module_nonTappable_xSZM-\",\"highlighted\":\"SuggestionItem-module_highlighted_Hb0SU\",\"tag\":\"SuggestionItem-module_tag_e3Fwe\",\"pressed\":\"SuggestionItem-module_pressed_98o-r\",\"glassFade\":\"SuggestionItem-module_glassFade_oyiSj\",\"tapDown\":\"SuggestionItem-module_tapDown_G3WGz\",\"streaks\":\"SuggestionItem-module_streaks_d9PEB\",\"streaksVert\":\"SuggestionItem-module_streaksVert_ERlV1\",\"streakHorizRight\":\"SuggestionItem-module_streakHorizRight_aboGz\",\"streakHorizLeft\":\"SuggestionItem-module_streakHorizLeft_BreWJ\",\"streakVertUp\":\"SuggestionItem-module_streakVertUp_to1GD\",\"streakVertDown\":\"SuggestionItem-module_streakVertDown_OrcLh\",\"skeletonPulse\":\"SuggestionItem-module_skeletonPulse_plvdD\"};","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { PillList } from \"./components/PillList\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n pills,\n onPillClick,\n showPills = true,\n isLoading = false,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const options = activeSuggestion?.options ?? [];\n const showsPills = showPills && pills && pills.length > 0 && onPillClick;\n const showsOptions = options.length > 0;\n // Guarantee at least one option bar during loading — if the cached state\n // had no options, render the fallback skeleton bars regardless of whether\n // pills are present, so the dropdown never shows pills with an empty body.\n const showsFallbackSkeleton = isLoading && !showsOptions;\n const isVisible = isOpen && (showsOptions || showsPills || isLoading);\n\n return (\n <div\n id={id}\n role=\"listbox\"\n data-aia-dropdown=\"\"\n data-aia-loading={isLoading ? \"\" : undefined}\n className={`${styles.dropdown} ${isVisible ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {showPills && pills && pills.length > 0 && onPillClick && (\n <div className={styles.pillBar} data-aia-pillbar=\"\">\n <PillList\n pills={pills}\n activePillIndex={0}\n onSelectPill={onPillClick}\n rounded\n loading={isLoading}\n />\n </div>\n )}\n {showPills && (!pills || pills.length === 0) && isLoading && (\n <div className={styles.pillBar} data-aia-pillbar=\"\">\n <PillList pills={[]} activePillIndex={0} onSelectPill={() => {}} rounded loading />\n </div>\n )}\n {showsOptions && (\n <SuggestionGrid\n options={options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n loading={isLoading}\n />\n )}\n {showsFallbackSkeleton && (\n <div className={styles.skeletonBars} data-aia-skeleton-bars=\"\">\n {FALLBACK_SKELETON_BAR_WIDTHS.map((w) => (\n <span key={`bar-${w}`} className={styles.skeletonBar} style={{ width: w }} />\n ))}\n </div>\n )}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-dc8da745\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-dc8da745\";\n s.textContent = `/*\n * Built-in appearance defaults — zero specificity via :where().\n * Consumer CSS always wins without !important.\n *\n * Resolution priority (highest wins):\n * 1. Consumer CSS targeting new vars (--aia-pill-bg, etc.)\n * 2. Consumer CSS targeting legacy vars (--aia-color-*, via fallback chain)\n * 3. These built-in defaults\n */\n\n/*\n * Library-scoped box-sizing reset. The SDK's pill / option / wrapper styles\n * mix explicit dimensions with padding (e.g. .magicx-aia-pill has height:36px\n * + padding:13px) and were authored assuming \\`border-box\\`. In consumer apps\n * without a global \\`* { box-sizing: border-box }\\` reset the pill rendered\n * ~62px tall instead of 36px. Scoping the reset to \\`.magicx-aia\\` descendants\n * keeps the library self-contained without leaking onto consumer markup.\n */\n:where(.magicx-aia, .magicx-aia *, .magicx-aia *::before, .magicx-aia *::after) {\n box-sizing: border-box;\n}\n\n/* Light mode defaults (base) */\n:where(.magicx-aia),\n:where(.magicx-aia[data-mode=\"light\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #000000;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #000000;\n --aia-option-color-selected: #000000;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #000000;\n --aia-written-text-font-size: 19px;\n --aia-caret-color: var(--aia-written-text-color, #000000);\n\n --aia-submit-bg: #000000;\n --aia-submit-color: #ffffff;\n\n --aia-color-text-muted: #6b7280;\n\n --aia-skeleton-bg: rgba(189, 189, 189, 0.51);\n\n --aia-streak-rgb: 99, 102, 241;\n --aia-streak-glass-bg: rgba(99, 102, 241, 0.1);\n}\n\n/* Dark mode defaults */\n:where(.magicx-aia[data-mode=\"dark\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #ffffff;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #ffffff;\n --aia-option-color-selected: #ffffff;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #ffffff;\n --aia-written-text-font-size: 19px;\n --aia-caret-color: var(--aia-written-text-color, #ffffff);\n\n --aia-submit-bg: #ffffff;\n --aia-submit-color: #000000;\n\n --aia-color-text-muted: #c1c4cb;\n\n --aia-skeleton-bg: #333539;\n\n --aia-streak-rgb: 255, 255, 255;\n --aia-streak-glass-bg: rgba(255, 255, 255, 0.1);\n}\n\n/* optionsPosition: dropdown above the input */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 6px;\n flex-direction: column-reverse;\n}\n\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-pillbar] {\n padding: 0 27px 27px 27px;\n}\n\n/* Disable all animations when data-animations=\"off\" */\n:where(.magicx-aia[data-animations=\"off\"]) *,\n:where(.magicx-aia[data-animations=\"off\"]) *::before,\n:where(.magicx-aia[data-animations=\"off\"]) *::after {\n animation-duration: 0s !important;\n transition-duration: 0s !important;\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","/**\n * Plain-text caret utilities for contentEditable elements.\n *\n * Offsets are measured in plain-text characters that come from the editable\n * region only — subtrees inside `[contenteditable=\"false\"]` (e.g. pills)\n * contribute zero characters. Callers can think in string offsets without\n * touching DOM Ranges directly.\n */\n\nconst NON_EDITABLE_SELECTOR = '[contenteditable=\"false\"]';\n\ninterface GraphemeSegmenter {\n segment(input: string): Iterable<{ index: number; segment: string }>;\n}\n\nlet segmenter: GraphemeSegmenter | null | undefined;\nfunction getGraphemeSegmenter(): GraphemeSegmenter | null {\n if (segmenter !== undefined) return segmenter;\n // Intl.Segmenter is ES2022; lib target is ES2020. Access via globalThis to\n // avoid a hard compile dependency on the newer lib.\n const Segmenter = (globalThis as { Intl: typeof Intl & { Segmenter?: unknown } }).Intl\n .Segmenter as undefined | (new (locale?: string, options?: object) => GraphemeSegmenter);\n if (!Segmenter) {\n segmenter = null;\n return null;\n }\n try {\n segmenter = new Segmenter(undefined, { granularity: \"grapheme\" });\n } catch {\n segmenter = null;\n }\n return segmenter ?? null;\n}\n\nfunction isInsideNonEditable(node: Node, root: HTMLElement): boolean {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n.nodeType === Node.ELEMENT_NODE) {\n const el = n as HTMLElement;\n if (el.matches(NON_EDITABLE_SELECTOR)) return true;\n }\n n = n.parentNode;\n }\n return false;\n}\n\nfunction createTextWalker(root: HTMLElement): TreeWalker {\n return (root.ownerDocument ?? document).createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n return isInsideNonEditable(node, root) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;\n },\n });\n}\n\nexport function extractPlainText(root: HTMLElement): string {\n const walker = createTextWalker(root);\n let out = \"\";\n let node = walker.nextNode() as Text | null;\n while (node) {\n out += node.data;\n node = walker.nextNode() as Text | null;\n }\n return out;\n}\n\nexport function plainTextLength(root: HTMLElement): number {\n const walker = createTextWalker(root);\n let total = 0;\n let node = walker.nextNode() as Text | null;\n while (node) {\n total += node.data.length;\n node = walker.nextNode() as Text | null;\n }\n return total;\n}\n\n/**\n * Read the current caret offset (in plain-text characters) within `root`.\n * Returns null when no selection is anchored inside `root`.\n */\nexport function getCursorOffset(root: HTMLElement): number | null {\n const sel = (root.ownerDocument ?? document).getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const anchorNode = sel.anchorNode;\n const anchorOffset = sel.anchorOffset;\n if (!anchorNode || !root.contains(anchorNode)) return null;\n\n // When the anchor is the editable itself (or an element child), interpret\n // anchorOffset as a child index and sum text lengths up to that child.\n if (anchorNode.nodeType === Node.ELEMENT_NODE) {\n const el = anchorNode as Element;\n if (isInsideNonEditable(el, root) && el !== root) return null;\n let offset = 0;\n for (let i = 0; i < anchorOffset && i < el.childNodes.length; i++) {\n offset += plainTextLengthOfSubtree(el.childNodes[i], root);\n }\n // Add lengths of previous siblings + ancestors up to root.\n return offset + offsetBeforeNode(el, root);\n }\n\n if (anchorNode.nodeType !== Node.TEXT_NODE) return null;\n if (isInsideNonEditable(anchorNode, root)) return null;\n\n return offsetBeforeNode(anchorNode, root) + anchorOffset;\n}\n\nfunction plainTextLengthOfSubtree(node: Node, root: HTMLElement): number {\n if (node.nodeType === Node.TEXT_NODE) {\n return isInsideNonEditable(node, root) ? 0 : (node as Text).data.length;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return 0;\n const el = node as HTMLElement;\n if (el.matches(NON_EDITABLE_SELECTOR)) return 0;\n let total = 0;\n for (const child of Array.from(el.childNodes)) {\n total += plainTextLengthOfSubtree(child, root);\n }\n return total;\n}\n\nfunction offsetBeforeNode(target: Node, root: HTMLElement): number {\n const walker = createTextWalker(root);\n let total = 0;\n let node = walker.nextNode() as Text | null;\n while (node) {\n if (node === target) return total;\n // If target is an ancestor element of this text node, we've already passed it.\n if (target.nodeType === Node.ELEMENT_NODE && (target as Element).contains(node)) {\n return total;\n }\n total += node.data.length;\n node = walker.nextNode() as Text | null;\n }\n return total;\n}\n\n/**\n * Set the caret at the given plain-text offset within `root`.\n *\n * Boundary policy: when the offset falls at the seam between text nodes, the\n * caret is placed at the START of the *following* text node so newly typed\n * characters do not inherit a preceding `<strong>`'s bold styling. When the\n * caret would land at the trailing edge of a text node inside a `<strong>`\n * with no following text node, we use `setStartAfter(strong)` so the caret\n * sits OUTSIDE the bold subtree — otherwise a caret at the end of a strong's\n * text is still \"inside\" the strong, which would falsely trigger re-edit mode.\n */\nexport function setCursorOffset(root: HTMLElement, offset: number): void {\n const doc = root.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel) return;\n\n const clamped = Math.max(0, Math.min(offset, plainTextLength(root)));\n const walker = createTextWalker(root);\n let cumulative = 0;\n let target: Text | null = null;\n let targetOffset = 0;\n let node = walker.nextNode() as Text | null;\n let lastNode: Text | null = null;\n\n while (node) {\n const len = node.data.length;\n if (clamped < cumulative + len) {\n target = node;\n targetOffset = clamped - cumulative;\n break;\n }\n if (clamped === cumulative + len) {\n const next = walker.nextNode() as Text | null;\n if (next) {\n // Prefer the start of the following text node so the caret sits past\n // any preceding `<strong>` boundary.\n target = next;\n targetOffset = 0;\n } else {\n target = node;\n targetOffset = len;\n }\n break;\n }\n cumulative += len;\n lastNode = node;\n node = walker.nextNode() as Text | null;\n }\n\n const range = doc.createRange();\n if (target) {\n // Boundary policy: the caret must never land at the leading or trailing\n // edge of a `<strong>`'s text node — visually it sits AT the boundary\n // but the DOM anchor is still INSIDE the strong, which would falsely\n // trigger re-edit mode. Hop OUT of the strong at those boundaries.\n const strongParent = target.parentElement?.closest<HTMLElement>('strong[data-seg=\"completed\"]');\n if (strongParent && strongParent !== root && root.contains(strongParent)) {\n if (targetOffset === 0) {\n range.setStartBefore(strongParent);\n } else if (targetOffset === target.data.length) {\n range.setStartAfter(strongParent);\n } else {\n range.setStart(target, targetOffset);\n }\n } else {\n range.setStart(target, targetOffset);\n }\n } else if (lastNode) {\n range.setStart(lastNode, lastNode.data.length);\n } else {\n range.setStart(root, 0);\n }\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * True when the caret offset equals the editable's plain-text length —\n * meaning the only content to the right is non-editable (e.g. trailing pills).\n */\nexport function cursorIsAtEnd(root: HTMLElement): boolean {\n const offset = getCursorOffset(root);\n if (offset == null) return false;\n return offset >= plainTextLength(root);\n}\n\n/**\n * Step back one grapheme from a plain-text offset, falling back to one UTF-16\n * code unit when Intl.Segmenter is unavailable. Used by Backspace handling so\n * emoji and combining marks are deleted as a single user-perceived character.\n */\nexport function previousGraphemeBoundary(text: string, offset: number): number {\n if (offset <= 0) return 0;\n const seg = getGraphemeSegmenter();\n if (!seg) return offset - 1;\n const slice = text.slice(0, offset);\n let last = 0;\n for (const { index } of seg.segment(slice)) {\n if (index < offset) last = index;\n }\n return last;\n}\n","import type { Segment } from \"../../types\";\nimport { getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\n\ninterface RenderEditableArgs {\n input: HTMLElement;\n segments: Segment[];\n newParamId: string | null;\n /** When set, the matching `<strong>` is decorated with the editing class. */\n editingParamId: string | null;\n placeholderText: string;\n isFocused: boolean;\n}\n\n/**\n * Renders text segments — including bold `<strong>` runs for completed params\n * — into the contentEditable input. Pills are NOT rendered here; they live as\n * a sibling element so the editable's subtree never contains non-editable\n * children. See renderInput.ts for the pill list placement.\n *\n * Skips rebuilds when the segment key is unchanged so an in-flight shimmer\n * animation isn't interrupted by unrelated state churn.\n */\nexport function renderEditableContent(args: RenderEditableArgs) {\n const { input, segments, newParamId, editingParamId, placeholderText, isFocused } = args;\n\n const empty = segments.length === 0;\n input.dataset.aiaEmpty = empty ? \"true\" : \"false\";\n if (empty && placeholderText) {\n input.dataset.placeholder = placeholderText;\n } else {\n delete input.dataset.placeholder;\n }\n\n const segKey = segments.map((s) => `${s.type}:${s.value}`).join(\"\\0\");\n const lastSegKey = input.dataset.segKey ?? \"\";\n const lastNewParamId = input.dataset.newParamId ?? \"\";\n const lastEditingParamId = input.dataset.editingParamId ?? \"\";\n if (\n segKey === lastSegKey &&\n (newParamId ?? \"\") === lastNewParamId &&\n (editingParamId ?? \"\") === lastEditingParamId\n ) {\n return;\n }\n\n const savedOffset = isFocused ? getCursorOffset(input) : null;\n input.dataset.segKey = segKey;\n input.dataset.newParamId = newParamId ?? \"\";\n input.dataset.editingParamId = editingParamId ?? \"\";\n\n const doc = input.ownerDocument ?? document;\n const frag = doc.createDocumentFragment();\n let newLength = 0;\n for (const seg of segments) {\n newLength += seg.value.length;\n if (seg.type === \"completed\") {\n const strong = doc.createElement(\"strong\");\n strong.dataset.seg = \"completed\";\n strong.dataset.paramId = seg.param.id;\n const isNew = seg.param.id === newParamId;\n const isEditing = seg.param.id === editingParamId;\n const classes = [\"magicx-aia-segment\", \"magicx-aia-segment--completed\"];\n if (isNew) classes.push(\"magicx-aia-shimmer-revealed\", \"magicx-aia-shimmer-sweep\");\n if (isEditing) classes.push(\"magicx-aia-segment--editing\");\n strong.className = classes.join(\" \");\n strong.textContent = seg.value;\n frag.appendChild(strong);\n } else {\n frag.appendChild(doc.createTextNode(seg.value));\n }\n }\n input.replaceChildren(frag);\n input.dataset.aiaTextLength = String(newLength);\n\n if (savedOffset != null) {\n // Restore the caret to where the browser left it (clamped to the new\n // text length). Callers that need the caret at a specific position\n // (e.g. Tab-on-placeholder, edit-mode replacement) schedule their own\n // `setCursorOffset` via `queueMicrotask` after the store mutation.\n setCursorOffset(input, Math.max(0, Math.min(savedOffset, newLength)));\n }\n}\n","import {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { AIAutocomplete as CoreAIAutocomplete } from \"../core/AIAutocomplete\";\nimport type { CoreState } from \"../core/types\";\nimport type {\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n columns = 2,\n dropdownTrigger,\n closeDropdownOnBlur,\n onFocus,\n onBlur,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n source,\n setCursor,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n const instanceRef = useRef<CoreAIAutocomplete | null>(null);\n const [coreState, setCoreState] = useState<CoreState | null>(null);\n\n // Refs for callbacks to avoid stale closures\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const onFocusRef = useRef(onFocus);\n onFocusRef.current = onFocus;\n const onBlurRef = useRef(onBlur);\n onBlurRef.current = onBlur;\n const setCursorRef = useRef(setCursor);\n setCursorRef.current = setCursor;\n\n // Create, subscribe, and destroy the core instance in one mount-only effect.\n // Keeping creation out of render (and pairing it with the cleanup) is what\n // makes this StrictMode-safe — otherwise cleanup nulls the ref, render\n // re-creates, and the store subscription drives an infinite setState loop.\n // biome-ignore lint/correctness/useExhaustiveDependencies: initial-opts snapshot; later changes are synced by the update-effect below\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const instance = new CoreAIAutocomplete(document.createElement(\"div\"), {\n renderMode: \"headless\",\n apiConfig,\n optionOverrides,\n maskCompletedText,\n columns,\n dropdownTrigger,\n closeDropdownOnBlur,\n source,\n value: controlledValue,\n completedParams: controlledParams,\n onSubmit: (...args) => onSubmitRef.current?.(...args),\n onError: (...args) => onErrorRef.current?.(...args),\n onChange: (...args) => onChangeRef.current?.(...args),\n onParamsChange: (...args) => onParamsChangeRef.current?.(...args),\n onFocus: () => onFocusRef.current?.(),\n onBlur: () => onBlurRef.current?.(),\n setCursor: (offset) => setCursorRef.current?.(offset),\n });\n instanceRef.current = instance;\n setCoreState(instance.getState());\n const unsub = instance.subscribe((state) => setCoreState(state));\n return () => {\n unsub();\n instance.destroy();\n if (instanceRef.current === instance) instanceRef.current = null;\n };\n }, []);\n\n const instance = instanceRef.current;\n\n // SSR bail-out — no instance, return safe empty defaults\n // Hooks below are unconditional (React rules of hooks) but guarded internally\n const noop = useCallback(() => {}, []);\n\n // Sync controlled value\n useEffect(() => {\n if (controlledValue !== undefined) instance?.setValue(controlledValue);\n }, [controlledValue, instance]);\n\n // Sync controlled params\n useEffect(() => {\n if (controlledParams !== undefined) instance?.setCompletedParams(controlledParams);\n }, [controlledParams, instance]);\n\n // Sync apiConfig/optionOverrides/dropdownTrigger when values change\n const apiConfigJson = JSON.stringify(apiConfig ?? null);\n const prevOverridesRef = useRef(optionOverrides);\n const overridesVersion = useRef(0);\n if (optionOverrides !== prevOverridesRef.current) {\n const prev = prevOverridesRef.current;\n const next = optionOverrides;\n const prevKeys = Object.keys(prev ?? {});\n const nextKeys = Object.keys(next ?? {});\n if (\n prevKeys.length !== nextKeys.length ||\n nextKeys.some(\n (k) =>\n !(prev as Record<string, unknown>)?.[k] ||\n (next as Record<string, unknown>)[k] !== (prev as Record<string, unknown>)[k],\n )\n ) {\n overridesVersion.current++;\n }\n prevOverridesRef.current = optionOverrides;\n }\n // biome-ignore lint/correctness/useExhaustiveDependencies: overridesVersion tracks shallow changes to fn-valued optionOverrides\n useEffect(() => {\n instance?.update({ apiConfig, optionOverrides, dropdownTrigger, closeDropdownOnBlur });\n }, [apiConfigJson, overridesVersion.current, dropdownTrigger, closeDropdownOnBlur, instance]);\n\n // Handle text change from textarea\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n if (!instance) return;\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n instance.handleTextChange(newValue);\n },\n [instance],\n );\n\n // Handle keyboard\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n instance?.handleKeyDown(e.nativeEvent);\n },\n [instance],\n );\n\n const handleFocus = useCallback(() => instance?.setFocused(true), [instance]);\n const handleBlur = useCallback(() => instance?.setFocused(false), [instance]);\n\n // Tier 1 helpers — element-agnostic versions usable on a contentEditable div.\n const handleTextChange = useCallback(\n (value: string) => instance?.handleTextChange(value),\n [instance],\n );\n const handleKeyDownT1 = useCallback(\n (e: KeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => {\n if (!instance) return;\n const native = \"nativeEvent\" in e ? e.nativeEvent : e;\n instance.handleKeyDown(native);\n },\n [instance],\n );\n const setFocused = useCallback((focused: boolean) => instance?.setFocused(focused), [instance]);\n\n // Tier 1 re-edit helpers.\n const startEditingParam = useCallback(\n (paramId: string) => instance?.startEditingParam(paramId),\n [instance],\n );\n const exitEditMode = useCallback(() => instance?.exitEditMode(), [instance]);\n const handleCaretAfterInput = useCallback(\n (offset: number | null) => instance?.handleCaretAfterInput(offset),\n [instance],\n );\n const handleCaretMove = useCallback(\n (offset: number | null) => instance?.handleCaretMove(offset),\n [instance],\n );\n const replaceEditingRange = useCallback(\n (replacement: string) => instance?.replaceEditingRange(replacement) ?? false,\n [instance],\n );\n\n // Actions\n const setActivePill = useCallback((index: number) => instance?.setActivePill(index), [instance]);\n const removeLastParam = useCallback(() => instance?.removeLastParam(), [instance]);\n const clearNewParamId = useCallback(() => instance?.clearNewParamId(), [instance]);\n const reset = useCallback(() => instance?.reset(), [instance]);\n const selectOption = useCallback(\n (option: SuggestionOption) => instance?.selectOption(option),\n [instance],\n );\n const setActiveDropdownIndex = useCallback(\n (index: number) => instance?.setActiveDropdownIndex(index),\n [instance],\n );\n\n // No instance (SSR) — return safe defaults\n if (!instance) {\n return {\n completedParams: controlledParams ?? [],\n suggestionPills: [],\n setActivePill: noop,\n removeLastParam: noop,\n segments: [],\n newParamId: null,\n clearNewParamId: noop,\n suggestions: [],\n activeIndex: -1,\n isReady: false,\n isLoading: true,\n isFocused: false,\n isDropdownOpen: false,\n placeholderText: \"\",\n listboxId: \"\",\n error: null,\n handleTextChange: noop,\n handleKeyDown: noop,\n setFocused: noop,\n editingParam: null,\n editingAnchor: null,\n caretOffset: null,\n startEditingParam: noop,\n exitEditMode: noop,\n handleCaretAfterInput: noop,\n handleCaretMove: noop,\n replaceEditingRange: () => false,\n inputProps: {\n value: controlledValue ?? \"\",\n placeholder: undefined,\n onChange: noop as unknown as UseAIAutocompleteReturn[\"inputProps\"][\"onChange\"],\n onKeyDown: noop as unknown as UseAIAutocompleteReturn[\"inputProps\"][\"onKeyDown\"],\n onFocus: noop,\n onBlur: noop,\n role: \"combobox\" as const,\n \"aria-expanded\": false,\n \"aria-activedescendant\": undefined,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": \"\",\n },\n reset: noop,\n dropdownProps: {\n suggestions: [],\n activeIndex: -1,\n onSelect: noop as unknown as (option: SuggestionOption) => void,\n onHighlight: noop as unknown as (index: number) => void,\n isOpen: false,\n id: \"\",\n pills: [],\n onPillClick: noop as unknown as (index: number) => void,\n },\n };\n }\n\n // Derive current state\n const state = coreState ?? instance.getState();\n const text = controlledValue !== undefined ? controlledValue : state.text;\n const completedParams = controlledParams !== undefined ? controlledParams : state.completedParams;\n\n const actionableSuggestions = state.actionableSuggestions;\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const filteredOptions = state.filteredOptions;\n\n const activeDescendantId =\n state.activeDropdownIndex >= 0\n ? `${instance.listboxId}-option-${state.activeDropdownIndex}`\n : undefined;\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata. The options grid\n // shows the cached options regardless of the latest server response.\n const editingParam = state.editingParam;\n const dropdownPill: Suggestion | null = editingParam\n ? {\n type: editingParam.suggestionType,\n text: editingParam.suggestionPlaceholder,\n required: true,\n options: editingParam.options,\n }\n : null;\n const dropdownActivePill = dropdownPill ?? activeSuggestion;\n const dropdownPills = dropdownPill ? [dropdownPill] : actionableSuggestions;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill,\n removeLastParam,\n segments: state.segments,\n newParamId: state.newParamId,\n clearNewParamId,\n suggestions: state.suggestions,\n activeIndex: state.activeDropdownIndex,\n isReady: state.isReady,\n // UI-visible loading — suppressed during the post-select streak animation\n // and during re-edit (cached options remain visible there).\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n isFocused: state.isFocused,\n isDropdownOpen: state.isDropdownOpen,\n placeholderText: state.placeholderText,\n listboxId: instance.listboxId,\n error: state.error,\n handleTextChange,\n handleKeyDown: handleKeyDownT1,\n setFocused,\n editingParam,\n editingAnchor: state.editingAnchor,\n caretOffset: state.caretOffset,\n startEditingParam,\n exitEditMode,\n handleCaretAfterInput,\n handleCaretMove,\n replaceEditingRange,\n inputProps: {\n value: text,\n placeholder: state.placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n onFocus: handleFocus,\n onBlur: handleBlur,\n role: \"combobox\" as const,\n \"aria-expanded\": state.isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": instance.listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: dropdownActivePill ? [{ ...dropdownActivePill, options: filteredOptions }] : [],\n activeIndex: state.activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: state.isDropdownOpen,\n id: instance.listboxId,\n pills: dropdownPills,\n onPillClick: setActivePill,\n // Re-edit shows cached options for the edited param, and the streak\n // animation should finish before we swap in the skeleton.\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n },\n };\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Returns a filter base that respects the server-suggested placeholder. When\n * `filterBase` hasn't been set by a fetch yet (still 0) and `text` starts with\n * `placeholderText`, the placeholder occupies the same role as `filterBase` —\n * the user's filter query is whatever they typed past it. Returns `filterBase`\n * unchanged otherwise.\n */\nexport function effectiveFilterBase(\n text: string,\n filterBase: number,\n placeholderText: string,\n): number {\n if (filterBase > 0 || !placeholderText) return filterBase;\n if (text.toLowerCase().startsWith(placeholderText.toLowerCase())) {\n return placeholderText.length;\n }\n return filterBase;\n}\n\n/**\n * Extracts the effective filter query from the region after filterBase.\n * If the server marked the region as in_progress, the full region is used.\n * Otherwise, filtering only starts after the first space (to avoid filtering\n * mid-word when the user continues typing a word that was already in the input).\n */\nexport function extractFilterQuery(\n text: string,\n filterBase: number,\n isInProgress: boolean,\n): string {\n const rawRegion = text.slice(filterBase);\n if (isInProgress || filterBase === 0 || text[filterBase - 1] === \" \") {\n return rawRegion;\n }\n const spaceIdx = rawRegion.indexOf(\" \");\n return spaceIdx === -1 ? \"\" : rawRegion.slice(spaceIdx + 1);\n}\n\n/**\n * Finds the longest word-boundary-aligned suffix of `prefix` that matches a\n * prefix of `optionText` (case-insensitive). Returns the number of characters\n * to remove from the end of `prefix` to avoid duplication.\n */\nexport function findPrefixOverlap(prefix: string, optionText: string): number {\n // Normalize internal whitespace so words.join(\" \") roundtrips losslessly\n const trimmed = prefix.trimEnd().replace(/\\s+/g, \" \");\n if (trimmed.length === 0 || optionText.length === 0) return 0;\n\n const words = trimmed.split(\" \");\n const optionLower = optionText.toLowerCase();\n\n // Try from longest suffix (all words) to shortest (last word only)\n for (let i = 0; i < words.length; i++) {\n const candidate = words.slice(i).join(\" \");\n if (optionLower.startsWith(candidate.toLowerCase())) {\n const suffixStart = trimmed.length - candidate.length;\n return prefix.length - suffixStart;\n }\n }\n\n return 0;\n}\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption[] {\n if (!options) return [];\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption | null {\n if (!options) return null;\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { AppearanceMode } from \"../types\";\n\nexport class ModeController {\n private mediaQuery: MediaQueryList | null = null;\n\n constructor(\n private container: HTMLElement,\n private mode: AppearanceMode = \"auto\",\n ) {\n this.apply();\n }\n\n setMode(mode: AppearanceMode) {\n this.detachListener();\n this.mode = mode;\n this.apply();\n }\n\n destroy() {\n this.detachListener();\n }\n\n private apply() {\n if (this.mode === \"auto\") {\n this.mediaQuery ??= window.matchMedia(\"(prefers-color-scheme: dark)\");\n this.mediaQuery.addEventListener(\"change\", this.onSystemChange);\n this.container.dataset.mode = this.mediaQuery.matches ? \"dark\" : \"light\";\n } else {\n this.container.dataset.mode = this.mode;\n }\n }\n\n private onSystemChange = (e: MediaQueryListEvent) => {\n this.container.dataset.mode = e.matches ? \"dark\" : \"light\";\n };\n\n private detachListener() {\n this.mediaQuery?.removeEventListener(\"change\", this.onSystemChange);\n }\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import type { AccessTokenConfig } from \"../types\";\n\n/** Refresh 30 seconds before stated expiry to absorb clock drift and request latency. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport class TokenManager {\n private current: string | null = null;\n private expiresAt: number | null = null;\n private inFlightRefresh: Promise<string> | null = null;\n\n constructor(private config: AccessTokenConfig) {\n if (config.accessToken) {\n this.current = config.accessToken;\n }\n }\n\n /** Returns a valid token, refreshing if needed. Single-flight: concurrent callers share one refresh. */\n async getToken(forceRefresh = false): Promise<string> {\n if (!forceRefresh && this.current && !this.isExpired()) {\n return this.current;\n }\n if (!forceRefresh && this.inFlightRefresh) {\n return this.inFlightRefresh;\n }\n this.inFlightRefresh = this.refresh();\n try {\n return await this.inFlightRefresh;\n } finally {\n this.inFlightRefresh = null;\n }\n }\n\n private async refresh(): Promise<string> {\n const result = await this.config.getAccessToken();\n this.current = result.accessToken;\n this.expiresAt = result.expiresAt ?? null;\n return this.current;\n }\n\n private isExpired(): boolean {\n if (this.expiresAt == null) return false;\n return Date.now() >= this.expiresAt - REFRESH_SKEW_MS;\n }\n}\n","import type { AccessTokenConfig, APIConfig, APIKeyConfig } from \"../types\";\nimport { TokenManager } from \"./tokenManager\";\n\n/** Default backend origin used when apiConfig.endpoint is not set. */\nexport const DEFAULT_API_ORIGIN = \"https://api.ai-autocomplete.com\";\nexport const DEFAULT_SUGGEST_ENDPOINT = `${DEFAULT_API_ORIGIN}/api/suggest`;\n\n// Keyed by getAccessToken function reference (stable across React re-renders)\nconst tokenManagers = new WeakMap<AccessTokenConfig[\"getAccessToken\"], TokenManager>();\n\nexport function isAccessTokenConfig(config?: APIConfig): config is AccessTokenConfig {\n return config?.type === \"accessToken\";\n}\n\nexport function getApiKeyConfig(config?: APIConfig): APIKeyConfig | undefined {\n if (!config || isAccessTokenConfig(config)) return undefined;\n return config;\n}\n\nexport function getTokenManager(config: AccessTokenConfig): TokenManager {\n let manager = tokenManagers.get(config.getAccessToken);\n if (!manager) {\n manager = new TokenManager(config);\n tokenManagers.set(config.getAccessToken, manager);\n }\n return manager;\n}\n\n/**\n * Builds shared (non-auth) request headers used by every backend call.\n * Mirrors what /suggest sends so /api/telemetry/events sees the same envelope.\n */\nexport function buildHeaders(apiConfig?: APIConfig): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n ...(apiConfig?.appIdentifier && { \"X-App-Identifier\": apiConfig.appIdentifier }),\n ...apiConfig?.headers,\n };\n}\n\n/**\n * Returns the Authorization header value for an API-key config, or `null` if no\n * apiKey is set (matches /suggest's behavior of sending the request without an\n * Authorization header in that case — the warn lives in api.ts so it fires only\n * for the user-visible suggest call).\n */\nexport function buildApiKeyAuthHeader(apiConfig?: APIConfig): string | null {\n const apiKeyConfig = getApiKeyConfig(apiConfig);\n const apiKey = apiKeyConfig?.apiKey;\n if (!apiKey) return null;\n const scheme = apiKeyConfig?.authScheme ?? \"Bearer\";\n return scheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n}\n","import type { APIConfig } from \"../types\";\nimport {\n buildApiKeyAuthHeader,\n buildHeaders,\n DEFAULT_SUGGEST_ENDPOINT,\n getTokenManager,\n isAccessTokenConfig,\n} from \"./auth\";\n\nexport type TelemetrySource = \"full-sdk\" | \"headless-sdk\" | \"endpoint-direct\";\nexport type TelemetryType = \"pill\" | \"option\";\n\nexport interface TelemetryEvent {\n source: TelemetrySource;\n sessionId: string;\n type: TelemetryType;\n queryData: Record<string, unknown>;\n apiConfig?: APIConfig;\n}\n\n/**\n * Telemetry sits next to /suggest on the server, so we derive the URL by\n * rewriting the trailing `/suggest` segment. This preserves whatever origin\n * and path-prefix the consumer configured — including relative dev-proxy\n * paths like \"/api/suggest\" → \"/api/telemetry/events\" or \"/ac/api/suggest\" →\n * \"/ac/api/telemetry/events\".\n */\nfunction deriveTelemetryEndpoint(suggestEndpoint?: string): string {\n const base = suggestEndpoint ?? DEFAULT_SUGGEST_ENDPOINT;\n return base.replace(/\\/suggest(\\?|#|$)/, \"/telemetry/events$1\");\n}\n\n/**\n * Resolves Authorization header using the same logic as /suggest:\n * - accessToken mode → Bearer from TokenManager\n * - apiKey mode → Bearer/Basic from configured key\n * - neither → null (request is sent without an Authorization header, matching\n * /suggest's behavior)\n */\nasync function resolveAuthHeader(apiConfig?: APIConfig): Promise<string | null> {\n if (isAccessTokenConfig(apiConfig)) {\n const token = await getTokenManager(apiConfig).getToken();\n return `Bearer ${token}`;\n }\n return buildApiKeyAuthHeader(apiConfig);\n}\n\n/**\n * Fire-and-forget telemetry POST. Never throws; failures are swallowed so the\n * UI is never disrupted by analytics. Auth headers are constructed via the\n * same helpers used by /suggest, so credential resolution stays consistent\n * across endpoints.\n */\nexport async function sendTelemetry(event: TelemetryEvent): Promise<void> {\n try {\n const endpoint = deriveTelemetryEndpoint(event.apiConfig?.endpoint);\n const headers = buildHeaders(event.apiConfig);\n const authHeader = await resolveAuthHeader(event.apiConfig);\n if (authHeader) headers.Authorization = authHeader;\n\n const body = JSON.stringify({\n source: event.source,\n session_id: event.sessionId,\n type: event.type,\n at: new Date().toISOString(),\n query_data: event.queryData,\n });\n\n await fetch(endpoint, { method: \"POST\", headers, body });\n } catch {\n // best-effort\n }\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\nimport {\n buildApiKeyAuthHeader,\n buildHeaders,\n DEFAULT_SUGGEST_ENDPOINT,\n getTokenManager,\n isAccessTokenConfig,\n} from \"./auth\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\nlet hasWarnedMissingKey = false;\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nfunction buildRequestBody(\n rawQuery: string,\n completedParams: CompletedParamState[],\n includeText: boolean,\n sessionId: string,\n): AutocompleteRequest {\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n return {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n session_id: sessionId,\n },\n };\n}\n\nasync function doFetch(\n endpoint: string,\n headers: Record<string, string>,\n token: string,\n body: string,\n signal?: AbortSignal,\n): Promise<Response> {\n return fetch(endpoint, {\n method: \"POST\",\n headers: { ...headers, Authorization: `Bearer ${token}` },\n body,\n signal,\n });\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options: {\n sessionId: string;\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options.apiConfig;\n const includeText = !options.maskCompletedText;\n const body = buildRequestBody(rawQuery, completedParams, includeText, options.sessionId);\n const headers = buildHeaders(apiConfig);\n const endpoint = apiConfig?.endpoint ?? DEFAULT_SUGGEST_ENDPOINT;\n const jsonBody = JSON.stringify(body);\n\n // === Access token mode ===\n if (isAccessTokenConfig(apiConfig)) {\n const manager = getTokenManager(apiConfig);\n const token = await manager.getToken();\n\n let response = await doFetch(endpoint, headers, token, jsonBody, options.signal);\n\n // 401 retry: force-refresh token and retry exactly once\n if (response.status === 401) {\n const newToken = await manager.getToken(true);\n response = await doFetch(endpoint, headers, newToken, jsonBody, options.signal);\n }\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n }\n\n // === API key mode (default) ===\n const authHeader = buildApiKeyAuthHeader(apiConfig);\n if (!authHeader && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No apiKey in apiConfig. Requests will be sent without an Authorization header.\",\n );\n }\n if (authHeader) headers.Authorization = authHeader;\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: jsonBody,\n signal: options.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../../types\";\nimport { fetchSuggestions } from \"../../utils/api\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport {\n effectiveFilterBase,\n extractFilterQuery,\n filterOptions,\n findExactMatch,\n} from \"../../utils/filtering\";\nimport { applyOptionOverrides } from \"../../utils/overrides\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\nexport interface FetchAutoMatchEvent {\n active: Suggestion;\n matched: SuggestionOption;\n rawQuery: string;\n}\n\nexport interface FetchControllerCallbacks {\n onAutoMatch?: (event: FetchAutoMatchEvent) => void;\n}\n\nexport class FetchController {\n private fetchVersion = 0;\n private abortController: AbortController | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private slowDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: (() => void) | null = null;\n\n constructor(\n private store: Store<CoreState>,\n private getApiConfig: () => APIConfig | undefined,\n private getOptionOverrides: () => OptionOverrides | undefined,\n private getMaskCompletedText: () => boolean | undefined,\n private getOnError: () => ((error: Error) => void) | undefined,\n private getSessionId: () => string,\n private callbacks: FetchControllerCallbacks = {},\n ) {}\n\n start() {\n // Initial fetch\n this.doFetch(\"\", []);\n\n // Subscribe to state changes for debounced fetching\n let prevText = this.store.get().text;\n let prevParams = this.store.get().completedParams;\n this.unsubscribe = this.store.subscribe((next) => {\n if (next.text !== prevText || next.completedParams !== prevParams) {\n prevText = next.text;\n prevParams = next.completedParams;\n this.scheduleFetch();\n }\n });\n }\n\n dispose() {\n this.abortController?.abort();\n this.clearTimers();\n this.unsubscribe?.();\n }\n\n async doFetch(rawQuery: string, completed: CompletedParamState[]) {\n this.abortController?.abort();\n const controller = new AbortController();\n this.abortController = controller;\n const version = ++this.fetchVersion;\n const textAtRequest = this.store.get().text.length;\n\n this.store.set({ isLoading: true, error: null });\n\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n sessionId: this.getSessionId(),\n maskCompletedText: this.getMaskCompletedText(),\n signal: controller.signal,\n apiConfig: this.getApiConfig(),\n });\n\n if (version !== this.fetchVersion) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n this.getOptionOverrides(),\n );\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = this.store.get().text;\n let filterBase: number;\n let filterInProgress: boolean;\n\n if (lastInput?.state === \"in_progress\") {\n filterInProgress = true;\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n filterBase = inProgressIdx !== -1 ? inProgressIdx : textAtRequest;\n } else {\n filterInProgress = false;\n filterBase = textAtRequest;\n }\n\n // Check if user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n let extraParam: CompletedParamState | null = null;\n if (active) {\n const query = extractFilterQuery(currentText, filterBase, filterInProgress);\n const match = findExactMatch(active.options, query);\n if (match) {\n extraParam = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n newSuggestions = newSuggestions.filter((s) => s !== active);\n this.callbacks.onAutoMatch?.({ active, matched: match, rawQuery });\n }\n }\n\n this.store.set((s) => ({\n suggestions: newSuggestions,\n isLoading: false,\n isReady: res.data.is_ready ?? false,\n lastRawQuery: rawQuery,\n activeDropdownIndex: -1,\n filterBase,\n filterInProgress,\n ...(extraParam ? { completedParams: [...s.completedParams, extraParam] } : {}),\n }));\n } catch (err) {\n if (version === this.fetchVersion) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n this.store.set({ error: caughtError, isLoading: false });\n this.getOnError()?.(caughtError);\n }\n }\n }\n\n private scheduleFetch() {\n this.clearTimers();\n const state = this.store.get();\n\n if (state.skipNextFetch) {\n this.store.set({ skipNextFetch: false });\n return;\n }\n\n const attemptFetch = (minDiff: number): boolean => {\n const s = this.store.get();\n if (!s.text && s.completedParams.length === 0) {\n this.doFetch(\"\", []);\n return true;\n }\n\n const placeholderText = s.suggestions\n .filter((sg: Suggestion) => sg.type === \"placeholder\")\n .map((sg: Suggestion) => sg.text)\n .join(\" \");\n const effBase = effectiveFilterBase(s.text, s.filterBase, placeholderText);\n const currentQuery = extractFilterQuery(s.text, effBase, s.filterInProgress);\n const actionable = s.suggestions.filter((sg: Suggestion) => sg.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n // Mirror the filter-zone behavior for placeholder suggestions: if the user is\n // still typing a prefix of the server-provided placeholder, don't fetch yet.\n if (\n s.completedParams.length === 0 &&\n s.text.length > 0 &&\n placeholderText.length > 0 &&\n placeholderText.toLowerCase().startsWith(s.text.toLowerCase())\n ) {\n return false;\n }\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(s.text, s.completedParams);\n const isDeleting = rawQuery.length < s.lastRawQuery.length;\n const charDiff = Math.abs(rawQuery.length - s.lastRawQuery.length);\n if (isDeleting || charDiff >= minDiff) {\n this.doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n this.debounceTimer = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n }\n }, DEBOUNCE_MS);\n\n this.slowDebounceTimer = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n }\n\n private clearTimers() {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n this.debounceTimer = null;\n this.slowDebounceTimer = null;\n }\n}\n","import type { AutocompleteResult, SuggestionOption } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { cursorIsAtEnd, getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface KeyboardContext {\n columns: number;\n listboxId: string;\n getOnSubmit: () => ((result: AutocompleteResult) => void) | undefined;\n /** Optional hook invoked after onSubmit fires (used by Tier 1 to auto-reset). */\n afterSubmit?: () => void;\n selectOption: (option: SuggestionOption) => void;\n /**\n * Tier 1 only: remove a completed param at the given caret offset, returning\n * true when a param was removed. Tier 2 consumers can omit this — Backspace\n * falls back to the browser default in their own input element.\n */\n removeParamAtCaret?: (offset: number) => boolean;\n /** Tier 1 only: exit re-edit mode (Escape, arrow-key escape). */\n exitEditMode?: () => void;\n}\n\n/**\n * Returns true when the caret in the event target sits at the end of its\n * editable content. Works for both `<textarea>`/`<input>` (Tier 2 consumer\n * inputs) and our contentEditable Tier 1 editor.\n */\nfunction isCursorAtEnd(target: EventTarget | null): boolean {\n if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement) {\n return target.selectionStart != null && target.selectionStart === target.value.length;\n }\n if (target instanceof HTMLElement && target.hasAttribute(\"data-aia-input\")) {\n return cursorIsAtEnd(target);\n }\n return false;\n}\n\nfunction getEditableCaretOffset(target: EventTarget | null): number | null {\n if (target instanceof HTMLElement && target.hasAttribute(\"data-aia-input\")) {\n return getCursorOffset(target);\n }\n return null;\n}\n\nexport class KeyboardController {\n constructor(\n private store: Store<CoreState>,\n private ctx: KeyboardContext,\n ) {}\n\n handleKeyDown(e: KeyboardEvent) {\n const state = this.store.get();\n const { listboxId, getOnSubmit } = this.ctx;\n const columns = this.getEffectiveColumns();\n const onSubmit = getOnSubmit();\n const tappableIndices = this.getTappableIndices(columns);\n\n switch (e.key) {\n case \"ArrowDown\": {\n const cursorAtEnd = isCursorAtEnd(e.target);\n // While re-editing a bold param, the dropdown is showing cached\n // options for it — ArrowDown should descend into them regardless of\n // whether the caret is \"at end\" of the input.\n const inEditMode = !!state.editingParam;\n if (!cursorAtEnd && !inEditMode && state.activeDropdownIndex < 0) break;\n\n e.preventDefault();\n if (!state.isDropdownOpen && state.actionableSuggestions.length > 0) {\n this.store.set({ pillTapped: true, activeDropdownIndex: tappableIndices[0] ?? 0 });\n break;\n }\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n this.store.set({ activeDropdownIndex: tappableIndices[nextPos] });\n break;\n }\n case \"ArrowUp\": {\n if (tappableIndices.length === 0 || state.activeDropdownIndex < 0) break;\n e.preventDefault();\n if (state.activeDropdownIndex < columns) {\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n this.store.set({ activeDropdownIndex: tappableIndices[prevPos] });\n break;\n }\n case \"ArrowRight\": {\n // When a dropdown option is highlighted, arrows navigate the grid\n // only — the caret in the editor stays put. Always preventDefault so\n // a press at the rightmost column doesn't fall through to caret\n // movement.\n if (state.activeDropdownIndex >= 0) {\n e.preventDefault();\n const col = state.activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = state.activeDropdownIndex + 1;\n if (\n rightNeighbor < state.filteredOptions.length &&\n state.filteredOptions[rightNeighbor]?.is_tappable\n ) {\n this.store.set({ activeDropdownIndex: rightNeighbor });\n }\n }\n break;\n }\n // No highlight → arrow keys move the caret. In re-edit mode that\n // means collapse the highlight to the param's trailing edge and exit.\n if (state.editingParam && e.target instanceof HTMLElement && state.editingTail != null) {\n e.preventDefault();\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const tail = state.editingTail;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, tail);\n break;\n }\n const atEnd = isCursorAtEnd(e.target);\n if (atEnd && state.actionableSuggestions.length > 1) {\n e.preventDefault();\n this.pillsSetActivePill(1);\n }\n break;\n }\n case \"ArrowLeft\": {\n // When a dropdown option is highlighted, arrows navigate the grid\n // only — the caret stays put. Always preventDefault so a press at\n // the leftmost column doesn't fall through to caret movement.\n if (state.activeDropdownIndex >= 0) {\n e.preventDefault();\n if (state.activeDropdownIndex % columns > 0) {\n const leftNeighbor = state.activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && state.filteredOptions[leftNeighbor]?.is_tappable) {\n this.store.set({ activeDropdownIndex: leftNeighbor });\n }\n }\n break;\n }\n // No highlight → arrow keys move the caret.\n if (state.editingParam && e.target instanceof HTMLElement && state.editingAnchor != null) {\n e.preventDefault();\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const anchor = state.editingAnchor;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, anchor);\n break;\n }\n break;\n }\n case \"Backspace\": {\n // In re-edit mode the entire bold param is selected; the browser's\n // default Backspace handles deletion of the selected range. Skip\n // removeParamAtCaret so we don't double-handle.\n if (state.editingParam) break;\n if (!this.ctx.removeParamAtCaret) break;\n const offset = getEditableCaretOffset(e.target);\n if (offset == null) break;\n if (this.ctx.removeParamAtCaret(offset)) {\n e.preventDefault();\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable\n ) {\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (onSubmit) {\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n this.ctx.afterSubmit?.();\n }\n break;\n }\n case \"Tab\": {\n const placeholderVisible = !state.text && !!state.placeholderText;\n const hasHighlightedOption =\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable;\n\n // Placeholder visible + option highlighted → defer to selectOption,\n // which prepends the placeholder text to the option (see AIAutocomplete.selectOption).\n if (placeholderVisible && !hasHighlightedOption) {\n // Tab on a placeholder commits the suggested text as plain typed\n // text — it is NOT a completed param, so it does not render bold.\n // The placeholder suggestion is dropped so it stops showing.\n e.preventDefault();\n const filledText = state.placeholderText;\n this.store.set((s) => ({\n text: filledText,\n filterBase: filledText.length,\n suggestions: s.suggestions.filter((sg) => sg.type !== \"placeholder\"),\n }));\n // Park caret at the end of the just-filled text. queueMicrotask\n // runs AFTER the batched-render microtask so we override the\n // renderer's default caret-clamp.\n if (e.target instanceof HTMLElement) {\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n queueMicrotask(() => setCursorOffset(editor, filledText.length));\n }\n } else if (hasHighlightedOption) {\n e.preventDefault();\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (state.isDropdownOpen) {\n const firstTappableIdx = state.filteredOptions.findIndex((o) => o.is_tappable);\n if (firstTappableIdx >= 0) {\n e.preventDefault();\n this.clickOrSelect(firstTappableIdx, state.filteredOptions, listboxId);\n }\n }\n break;\n }\n case \"Escape\": {\n if (state.editingParam && e.target instanceof HTMLElement && state.editingTail != null) {\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const tail = state.editingTail;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, tail);\n }\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n }\n }\n\n private getTappableIndices(columns: number): number[] {\n const state = this.store.get();\n const tappable = state.filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }\n\n /**\n * The grid uses a container query to switch between 1 and 2 columns based on\n * width, so the prop value can disagree with what's actually rendered. Read\n * the live column count from the grid; fall back to the prop if unavailable.\n */\n private getEffectiveColumns(): number {\n const firstOption = document.getElementById(`${this.ctx.listboxId}-option-0`);\n const grid = firstOption?.parentElement;\n if (!grid) return this.ctx.columns;\n const tracks = getComputedStyle(grid).gridTemplateColumns.split(\" \").filter(Boolean).length;\n return tracks > 0 ? tracks : this.ctx.columns;\n }\n\n private clickOrSelect(index: number, options: SuggestionOption[], listboxId: string) {\n const optionEl = document.getElementById(`${listboxId}-option-${index}`);\n if (optionEl) {\n optionEl.click();\n } else {\n this.ctx.selectOption(options[index]);\n }\n }\n\n /** Delegate to pills controller logic inline (avoids circular dep) */\n private pillsSetActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n}\n","import { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface PillSelectedEvent {\n rawQuery: string;\n selectedPill: string;\n otherPills: string[];\n}\n\nexport interface PillsControllerCallbacks {\n onPillSelected?: (event: PillSelectedEvent) => void;\n}\n\nexport class PillsController {\n constructor(\n private store: Store<CoreState>,\n private callbacks: PillsControllerCallbacks = {},\n ) {}\n\n setActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n\n if (this.callbacks.onPillSelected) {\n const { rawQuery } = buildQuery(state.text, state.completedParams);\n this.callbacks.onPillSelected({\n rawQuery,\n selectedPill: moved.text,\n otherPills: rest.map((s) => s.text),\n });\n }\n\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n\n removeLastParam() {\n const state = this.store.get();\n if (state.completedParams.length === 0) return;\n this.store.set((s) => ({\n completedParams: s.completedParams.slice(0, -1),\n activeDropdownIndex: -1,\n }));\n }\n}\n","import type { Suggestion } from \"../../types\";\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function renderPills(\n container: HTMLElement,\n pills: Suggestion[],\n activePillIndex: number,\n onSelectPill: (index: number) => void,\n rounded = false,\n loading = false,\n) {\n let list = container.querySelector<HTMLElement>(\".magicx-aia-pill-list\");\n if (!list) {\n list = document.createElement(\"span\");\n list.className = \"magicx-aia-pill-list\";\n container.appendChild(list);\n }\n\n // No cached pills + loading → fallback fixed-width placeholders.\n if (loading && pills.length === 0) {\n list.setAttribute(\"data-aia-pill-list-loading\", \"\");\n list.innerHTML = \"\";\n for (let i = 0; i < FALLBACK_SKELETON_WIDTHS.length; i++) {\n const width = FALLBACK_SKELETON_WIDTHS[i];\n const span = document.createElement(\"span\");\n span.setAttribute(\"data-aia-pill-skeleton\", \"\");\n span.className = `magicx-aia-pill magicx-aia-pill--skeleton${rounded ? \" magicx-aia-pill--rounded\" : \"\"}`;\n span.style.width = `${width}px`;\n span.style.opacity = String(getPillOpacity(i));\n list.appendChild(span);\n }\n return;\n }\n\n if (loading) {\n list.setAttribute(\"data-aia-pill-list-loading\", \"\");\n } else {\n list.removeAttribute(\"data-aia-pill-list-loading\");\n }\n\n // Drop any leftover fallback placeholders before diffing the real pills.\n for (const skel of list.querySelectorAll<HTMLElement>(\"[data-aia-pill-skeleton]\")) {\n skel.remove();\n }\n\n // Diff by key (type-text)\n const existing = new Map<string, HTMLButtonElement>();\n for (const btn of list.querySelectorAll<HTMLButtonElement>(\".magicx-aia-pill\")) {\n existing.set(btn.dataset.pillKey ?? \"\", btn);\n }\n\n const used = new Set<string>();\n for (let i = 0; i < pills.length; i++) {\n const pill = pills[i];\n const key = `${pill.type}-${pill.text}`;\n used.add(key);\n\n let btn = existing.get(key);\n if (!btn || btn.tagName !== \"BUTTON\") {\n btn?.remove();\n btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.tabIndex = -1;\n btn.dataset.pillKey = key;\n btn.setAttribute(\"data-aia-pill\", \"\");\n btn.setAttribute(\"contenteditable\", \"false\");\n btn.textContent = pill.text;\n btn.addEventListener(\"mousedown\", (e) => e.preventDefault());\n }\n\n const classes = [\"magicx-aia-pill\"];\n if (rounded) classes.push(\"magicx-aia-pill--rounded\");\n if (i === activePillIndex && !loading) classes.push(\"magicx-aia-pill--active\");\n if (loading) classes.push(\"magicx-aia-pill--skeleton\");\n btn.className = classes.join(\" \");\n btn.style.width = \"\";\n btn.style.opacity = String(getPillOpacity(i));\n if (loading) {\n btn.setAttribute(\"data-aia-loading\", \"\");\n btn.disabled = true;\n btn.onclick = null;\n } else {\n btn.removeAttribute(\"data-aia-loading\");\n btn.disabled = false;\n btn.onclick = () => onSelectPill(i);\n }\n\n if (list.children[i] !== btn) {\n list.insertBefore(btn, list.children[i] ?? null);\n }\n }\n\n for (const [key, btn] of existing) {\n if (!used.has(key)) btn.remove();\n }\n}\n\nexport function clearPills(container: HTMLElement) {\n container.querySelector(\".magicx-aia-pill-list\")?.remove();\n}\n","import type { Suggestion, SuggestionOption } from \"../../types\";\nimport { renderPills } from \"./renderPills\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\ninterface DropdownState {\n suggestions: Suggestion[];\n filteredOptions: SuggestionOption[];\n activeIndex: number;\n isOpen: boolean;\n isLoading: boolean;\n listboxId: string;\n pills: Suggestion[];\n showPills: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPillClick: (index: number) => void;\n}\n\nexport function createDropdown(listboxId: string): HTMLElement {\n const dropdown = document.createElement(\"div\");\n dropdown.id = listboxId;\n dropdown.setAttribute(\"role\", \"listbox\");\n dropdown.setAttribute(\"data-aia-dropdown\", \"\");\n dropdown.className = \"magicx-aia-dropdown\";\n dropdown.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return dropdown;\n}\n\nexport function renderDropdown(dropdown: HTMLElement, state: DropdownState) {\n const {\n filteredOptions,\n activeIndex,\n isOpen,\n isLoading,\n pills,\n showPills,\n onSelect,\n onHighlight,\n onPillClick,\n } = state;\n\n const hasPills = showPills && pills.length > 0;\n const hasOptions = filteredOptions.length > 0;\n const isVisible = isOpen && (hasOptions || hasPills || isLoading);\n\n if (isVisible) {\n dropdown.classList.add(\"magicx-aia-dropdown--visible\");\n } else {\n dropdown.classList.remove(\"magicx-aia-dropdown--visible\");\n }\n\n if (isLoading) {\n dropdown.setAttribute(\"data-aia-loading\", \"\");\n } else {\n dropdown.removeAttribute(\"data-aia-loading\");\n }\n\n // --- Pill bar ---\n // Render the pill bar when we have real pills OR when loading + showPills\n // (so the bar can host the fallback placeholder pills).\n const wantsPillBar = hasPills || (isLoading && showPills);\n let pillBar = dropdown.querySelector<HTMLElement>(\".magicx-aia-pill-bar\");\n if (wantsPillBar) {\n if (!pillBar) {\n pillBar = document.createElement(\"div\");\n pillBar.className = \"magicx-aia-pill-bar\";\n pillBar.setAttribute(\"data-aia-pillbar\", \"\");\n dropdown.insertBefore(pillBar, dropdown.firstChild);\n }\n renderPills(pillBar, pills, 0, onPillClick, true, isLoading);\n } else if (pillBar) {\n pillBar.remove();\n }\n\n // --- Options grid ---\n let grid = dropdown.querySelector<HTMLElement>(\".magicx-aia-grid\");\n if (hasOptions) {\n if (!grid) {\n grid = document.createElement(\"div\");\n grid.className = \"magicx-aia-grid\";\n dropdown.appendChild(grid);\n }\n renderOptions(\n grid,\n filteredOptions,\n activeIndex,\n onSelect,\n onHighlight,\n state.listboxId,\n isLoading,\n );\n } else if (grid) {\n grid.remove();\n }\n\n // --- Fallback skeleton bars (when loading with no cached options) ---\n let skeleton = dropdown.querySelector<HTMLElement>(\".magicx-aia-skeleton-bars\");\n if (isLoading && !hasOptions) {\n if (!skeleton) {\n skeleton = document.createElement(\"div\");\n skeleton.className = \"magicx-aia-skeleton-bars\";\n skeleton.setAttribute(\"data-aia-skeleton-bars\", \"\");\n for (const width of FALLBACK_SKELETON_BAR_WIDTHS) {\n const bar = document.createElement(\"span\");\n bar.className = \"magicx-aia-skeleton-bar\";\n bar.style.width = `${width}px`;\n skeleton.appendChild(bar);\n }\n dropdown.appendChild(skeleton);\n }\n } else if (skeleton) {\n skeleton.remove();\n }\n}\n\nfunction renderOptions(\n grid: HTMLElement,\n options: SuggestionOption[],\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n loading: boolean,\n) {\n const optionsKey = options.map((o) => o.text).join(\"\\0\");\n const lastKey = grid.dataset.optionsKey ?? \"\";\n const lastLoading = grid.dataset.loading ?? \"\";\n const loadingFlag = loading ? \"1\" : \"0\";\n const listChanged = optionsKey !== lastKey || lastLoading !== loadingFlag;\n grid.dataset.optionsKey = optionsKey;\n grid.dataset.loading = loadingFlag;\n\n if (listChanged) {\n // Full rebuild — options or loading state changed.\n const fragment = document.createDocumentFragment();\n\n for (let i = 0; i < options.length; i++) {\n const option = options[i];\n const item = createOptionElement(\n option,\n i,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n loading,\n );\n fragment.appendChild(item);\n }\n\n grid.innerHTML = \"\";\n grid.appendChild(fragment);\n } else {\n // Just update highlight classes — no DOM rebuild\n const items = grid.querySelectorAll<HTMLElement>(\".magicx-aia-option\");\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const isHighlighted = i === activeIndex && !loading;\n item.setAttribute(\"aria-selected\", String(isHighlighted));\n if (isHighlighted) {\n item.classList.add(\"magicx-aia-option--highlighted\");\n } else {\n item.classList.remove(\"magicx-aia-option--highlighted\");\n }\n }\n }\n}\n\nfunction createOptionElement(\n option: SuggestionOption,\n index: number,\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n loading: boolean,\n): HTMLElement {\n const item = document.createElement(\"div\");\n item.id = `${listboxId}-option-${index}`;\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"data-aia-option\", \"\");\n if (loading) item.setAttribute(\"data-aia-loading\", \"\");\n item.setAttribute(\"aria-selected\", String(index === activeIndex && !loading));\n item.tabIndex = loading || !option.is_tappable ? -1 : 0;\n\n const classes = [\"magicx-aia-option\"];\n if (index === activeIndex && !loading) classes.push(\"magicx-aia-option--highlighted\");\n if (option.is_tappable) {\n classes.push(\"magicx-aia-option--tappable\");\n } else {\n classes.push(\"magicx-aia-option--non-tappable\");\n }\n item.className = classes.join(\" \");\n\n // Streaks\n const streaks = document.createElement(\"div\");\n streaks.className = \"magicx-aia-streaks\";\n item.appendChild(streaks);\n\n const streaksVert = document.createElement(\"div\");\n streaksVert.className = \"magicx-aia-streaks-vert\";\n item.appendChild(streaksVert);\n\n // Content\n const content = document.createElement(\"span\");\n content.className = \"magicx-aia-option-content\";\n content.textContent = option.icon ? `${option.icon} ${option.text}` : option.text;\n\n if (option.tag) {\n const tag = document.createElement(\"span\");\n tag.className = \"magicx-aia-option-tag\";\n tag.textContent = option.tag;\n content.appendChild(tag);\n }\n\n item.appendChild(content);\n\n // Events (suppressed while loading)\n if (!loading && option.is_tappable) {\n item.addEventListener(\"click\", () => {\n item.classList.add(\"magicx-aia-option--pressed\");\n onSelect(option);\n setTimeout(() => item.classList.remove(\"magicx-aia-option--pressed\"), 500);\n });\n item.addEventListener(\"mouseenter\", () => onHighlight(index));\n }\n\n return item;\n}\n","import type { SuggestionOption } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\n\ninterface DropdownOnlyRefs {\n dropdown: HTMLElement;\n}\n\ninterface DropdownOnlyOptions {\n store: Store<CoreState>;\n listboxId: string;\n selectOption: (option: SuggestionOption) => void;\n setActivePill: (index: number) => void;\n}\n\nexport function buildDropdownOnly(\n container: HTMLElement,\n opts: DropdownOnlyOptions,\n): DropdownOnlyRefs {\n const dropdown = createDropdown(opts.listboxId);\n container.appendChild(dropdown);\n return { dropdown };\n}\n\nexport function updateDropdownOnly(\n refs: DropdownOnlyRefs,\n state: CoreState,\n opts: DropdownOnlyOptions,\n) {\n renderDropdown(refs.dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n // Re-edit shows cached options, and the streak animation finishes before\n // we swap in the skeleton.\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: true, // always show pills in dropdown-only mode\n onSelect: opts.selectOption,\n onHighlight: (i) => opts.store.set({ activeDropdownIndex: i }),\n onPillClick: opts.setActivePill,\n });\n}\n","import type { AutocompleteResult, Suggestion } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { extractPlainText, getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\nimport { renderEditableContent } from \"./renderEditable\";\nimport { clearPills, renderPills } from \"./renderPills\";\n\ninterface RenderInputOptions {\n store: Store<CoreState>;\n listboxId: string;\n pillPlacement: \"inline\" | \"dropdown\" | \"hidden\";\n autoFocus?: boolean;\n onSubmit?: (result: AutocompleteResult) => void;\n /** Invoked after onSubmit fires — Tier 1 uses this to auto-reset. */\n afterSubmit?: () => void;\n submitButton?: HTMLElement | null;\n selectOption: (option: import(\"../../types\").SuggestionOption) => void;\n setActivePill: (index: number) => void;\n handleKeyDown: (e: KeyboardEvent) => void;\n handleChange: (value: string) => void;\n /** Re-edit entry: triggered when caret enters a bold completed param. */\n startEditingParam: (paramId: string) => void;\n /** Re-edit caret-tracking after an input event (extends edit tail). */\n handleCaretAfterInput: (offset: number | null) => void;\n /** Re-edit caret-tracking on selection-only moves (may exit edit mode). */\n handleCaretMove: (offset: number | null) => void;\n /** Re-edit beforeinput intercept: replace the editing range atomically. */\n replaceEditingRange: (replacement: string) => boolean;\n}\n\nexport interface DOMRefs {\n input: HTMLDivElement;\n /** Non-editable inline pill list rendered as a sibling of the editable. */\n inlinePillContainer: HTMLSpanElement;\n dropdown: HTMLElement;\n /** The default built-in button when no `submitButton` was provided. Null when consumer passed `null` or a custom element. */\n submitButton: HTMLButtonElement | null;\n /** Aborts all listeners attached during buildDOM. */\n abort: AbortController;\n}\n\nconst SUBMIT_SVG = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\"><path d=\"M9 14V4M9 4L4 9M9 4L14 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nfunction supportsPlaintextOnly(): boolean {\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n return probe.contentEditable === \"plaintext-only\";\n}\n\nexport function buildDOM(container: HTMLElement, opts: RenderInputOptions): DOMRefs {\n const { listboxId } = opts;\n\n const dropdown = createDropdown(listboxId);\n container.appendChild(dropdown);\n\n const inputWrapper = document.createElement(\"div\");\n inputWrapper.className = \"magicx-aia-input-wrapper\";\n container.appendChild(inputWrapper);\n\n const editor = document.createElement(\"div\");\n editor.className = \"magicx-aia-editor\";\n editor.setAttribute(\"data-aia-editor\", \"\");\n inputWrapper.appendChild(editor);\n\n const input = document.createElement(\"div\");\n input.className = \"magicx-aia-input\";\n input.setAttribute(\"data-aia-input\", \"\");\n input.setAttribute(\"contenteditable\", supportsPlaintextOnly() ? \"plaintext-only\" : \"true\");\n input.setAttribute(\"role\", \"combobox\");\n input.setAttribute(\"aria-autocomplete\", \"list\");\n input.setAttribute(\"aria-haspopup\", \"listbox\");\n input.setAttribute(\"aria-controls\", listboxId);\n input.setAttribute(\"aria-expanded\", \"false\");\n input.setAttribute(\"spellcheck\", \"true\");\n input.setAttribute(\"enterkeyhint\", \"send\");\n editor.appendChild(input);\n\n // Pills sit as a sibling of the editable — they're never inside a\n // contentEditable subtree, so there's no risk of them becoming part of the\n // typing surface. Layout (CSS) keeps them visually adjacent to the text.\n const inlinePillContainer = document.createElement(\"span\");\n inlinePillContainer.className = \"magicx-aia-pill-list-container\";\n inlinePillContainer.setAttribute(\"data-aia-pill-list-container\", \"\");\n editor.appendChild(inlinePillContainer);\n\n let submitButton: HTMLButtonElement | null = null;\n let submitTarget: HTMLElement | null = null;\n if (opts.submitButton === undefined) {\n submitButton = document.createElement(\"button\");\n submitButton.type = \"button\";\n submitButton.className = \"magicx-aia-submit\";\n submitButton.setAttribute(\"aria-label\", \"Submit\");\n submitButton.setAttribute(\"data-aia-submit\", \"\");\n submitButton.innerHTML = SUBMIT_SVG;\n inputWrapper.appendChild(submitButton);\n submitTarget = submitButton;\n } else if (opts.submitButton !== null) {\n submitTarget = opts.submitButton;\n if (!submitTarget.hasAttribute(\"data-aia-submit\")) {\n submitTarget.setAttribute(\"data-aia-submit\", \"\");\n }\n inputWrapper.appendChild(submitTarget);\n }\n\n const abort = new AbortController();\n const { signal } = abort;\n\n let composing = false;\n // Tracks when an input event has just fired so the immediately-following\n // selectionchange knows to extend the edit tail rather than treat the\n // caret move as a navigation event.\n let lastInputAt = 0;\n\n const fireInput = () => {\n const raw = extractPlainText(input);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n opts.handleChange(newValue);\n };\n\n const findEnclosingParamId = (): string | null => {\n const sel = (input.ownerDocument ?? document).getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const anchor = sel.anchorNode;\n if (!anchor || !input.contains(anchor)) return null;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n const strong = startEl?.closest<HTMLElement>('strong[data-seg=\"completed\"][data-param-id]');\n return strong?.dataset.paramId ?? null;\n };\n\n inputWrapper.addEventListener(\n \"click\",\n (e) => {\n // Clicking a pill button should activate the pill, not steal focus.\n if ((e.target as HTMLElement | null)?.closest(\"[data-aia-pill]\")) return;\n input.focus();\n },\n { signal },\n );\n\n input.addEventListener(\n \"input\",\n () => {\n if (composing) return;\n lastInputAt = performance.now();\n fireInput();\n // After typing, extend the edit tail to the new caret position so the\n // user can keep typing past the param's original end without exiting.\n opts.handleCaretAfterInput(getCursorOffset(input));\n },\n { signal },\n );\n\n // selectionchange fires on the document (Selection API doesn't bubble to\n // elements). Filter to selections anchored inside our editor, then route\n // the caret state into the core. A short cooldown after `input` events\n // avoids treating the post-typing caret position as a \"move\" that would\n // exit edit mode.\n const doc = input.ownerDocument ?? document;\n doc.addEventListener(\n \"selectionchange\",\n () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!input.contains(sel.anchorNode!)) return;\n const enclosing = findEnclosingParamId();\n const editingId = opts.store.get().editingParam?.id ?? null;\n if (enclosing && enclosing !== editingId) {\n opts.startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAt < 50) {\n // Just-typed: caret move handled by handleCaretAfterInput above.\n return;\n }\n opts.handleCaretMove(getCursorOffset(input));\n },\n { signal },\n );\n\n input.addEventListener(\n \"compositionstart\",\n () => {\n composing = true;\n },\n { signal },\n );\n input.addEventListener(\n \"compositionend\",\n () => {\n composing = false;\n fireInput();\n },\n { signal },\n );\n\n input.addEventListener(\n \"beforeinput\",\n (e) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n // Re-edit mode atomic-replace: while the edited param's `<strong>` is\n // still in the DOM, swap the whole thing for whatever the user is\n // about to insert (or empty, for deletes). Without this, typing or\n // backspace would land inside the bold span instead of replacing it.\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (opts.replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n },\n { signal },\n );\n\n input.addEventListener(\n \"paste\",\n (e) => {\n e.preventDefault();\n const text = (e.clipboardData?.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = input.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!input.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n { signal },\n );\n\n input.addEventListener(\"keydown\", (e) => opts.handleKeyDown(e), { signal });\n\n input.addEventListener(\"focus\", () => opts.store.set({ isFocused: true }), { signal });\n input.addEventListener(\"blur\", () => opts.store.set({ isFocused: false }), { signal });\n\n if (submitTarget) {\n submitTarget.addEventListener(\n \"click\",\n (e) => {\n const state = opts.store.get();\n const canSubmit = !!state.text || state.completedParams.length > 0;\n if (!canSubmit || !opts.onSubmit) return;\n e.stopPropagation();\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n opts.onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n opts.afterSubmit?.();\n },\n { signal },\n );\n }\n\n if (opts.autoFocus !== false) {\n input.focus();\n }\n\n return { input, inlinePillContainer, dropdown, submitButton, abort };\n}\n\nexport function updateDOM(refs: DOMRefs, state: CoreState, opts: RenderInputOptions) {\n const { input, inlinePillContainer, dropdown, submitButton } = refs;\n const { pillPlacement, setActivePill, selectOption, store } = opts;\n\n input.setAttribute(\"aria-expanded\", String(state.isDropdownOpen));\n const activeDescendant =\n state.activeDropdownIndex >= 0 ? `${opts.listboxId}-option-${state.activeDropdownIndex}` : \"\";\n if (activeDescendant) {\n input.setAttribute(\"aria-activedescendant\", activeDescendant);\n } else {\n input.removeAttribute(\"aria-activedescendant\");\n }\n\n if (submitButton) {\n const canSubmit = !!state.text || state.completedParams.length > 0;\n submitButton.disabled = !canSubmit;\n }\n\n // Detect a fresh option selection BEFORE renderEditableContent mutates the\n // dataset. `newParamId` is set by selectOption() each time a suggestion\n // becomes a completed param. We compare against the last id the DOM saw so\n // the focus/caret jump only fires once per selection (not on every render\n // during the 650ms shimmer window).\n const previousParamId = input.dataset.newParamId ?? \"\";\n const justSelected = state.newParamId !== null && state.newParamId !== previousParamId;\n\n renderEditableContent({\n input,\n segments: state.segments,\n newParamId: state.newParamId,\n editingParamId: state.editingParam?.id ?? null,\n placeholderText: state.placeholderText,\n isFocused: state.isFocused,\n });\n\n if (pillPlacement === \"inline\") {\n const inlineLoading = state.isLoading && !state.editingParam && !state.inSelectionAnimation;\n if (inlineLoading || state.actionableSuggestions.length > 0) {\n renderPills(\n inlinePillContainer,\n state.actionableSuggestions,\n 0,\n setActivePill,\n false,\n inlineLoading,\n );\n } else {\n clearPills(inlinePillContainer);\n }\n } else {\n clearPills(inlinePillContainer);\n }\n\n if (justSelected) {\n // After option selection, focus jumped to the clicked dropdown option\n // (or stayed on the editor via the dropdown's mousedown preventDefault).\n // Either way, bring focus to the editable and park the caret at the\n // position the promoter chose — typically right after the new param's\n // trailing space. Falls back to end-of-input for safety.\n input.focus();\n setCursorOffset(input, state.caretOffset ?? state.text.length);\n } else if (state.isFocused) {\n // Controlled-mode setValue / programmatic reset: keep the caret at the\n // end when DOM text diverges from state. Skip when not focused so we\n // don't steal focus on unrelated state churn.\n const domText = extractPlainText(input);\n if (domText !== state.text) {\n setCursorOffset(input, state.text.length);\n }\n }\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata (regardless of the\n // latest server suggestions). Inline pills are unaffected — they still\n // reflect the live actionable suggestions.\n const dropdownPill: Suggestion | null = state.editingParam\n ? {\n type: state.editingParam.suggestionType,\n text: state.editingParam.suggestionPlaceholder,\n required: true,\n options: state.editingParam.options,\n }\n : null;\n const dropdownActivePill = dropdownPill ?? state.actionableSuggestions[0];\n\n renderDropdown(dropdown, {\n suggestions: dropdownActivePill\n ? [{ ...dropdownActivePill, options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n // Re-edit shows cached options, and the streak animation finishes before\n // we swap in the skeleton.\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n listboxId: opts.listboxId,\n pills: dropdownPill ? [dropdownPill] : state.actionableSuggestions,\n showPills: pillPlacement === \"dropdown\",\n onSelect: selectOption,\n onHighlight: (i) => store.set({ activeDropdownIndex: i }),\n onPillClick: setActivePill,\n });\n}\n","export type Listener<S> = (next: S, prev: S) => void;\n\nexport interface Store<S> {\n get: () => S;\n set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;\n subscribe: (listener: Listener<S>) => () => void;\n}\n\nexport function createStore<S>(initial: S): Store<S> {\n let state = initial;\n const listeners = new Set<Listener<S>>();\n return {\n get: () => state,\n set: (patch) => {\n const resolved = typeof patch === \"function\" ? patch(state) : patch;\n const next = { ...state, ...resolved };\n const prev = state;\n state = next;\n for (const l of listeners) l(next, prev);\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n","let injected = false;\n\n/** Inject core + appearance CSS into document.head once. Idempotent. */\nexport function injectStyles() {\n if (injected || typeof document === \"undefined\") return;\n if (document.querySelector(\"style[data-magicx-aia]\")) {\n injected = true;\n return;\n }\n injected = true;\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-magicx-aia\", \"\");\n style.textContent = STYLES;\n document.head.appendChild(style);\n}\n\n// Replaced at build time by tsup.config.core.ts / vitest.config.ts\ndeclare const __MAGICX_AC_STYLES__: string;\nconst STYLES = __MAGICX_AC_STYLES__;\n","import type { AppearanceMode, CompletedParamState, Suggestion, SuggestionOption } from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport {\n effectiveFilterBase,\n extractFilterQuery,\n filterOptions,\n findExactMatch,\n findPrefixOverlap,\n} from \"../utils/filtering\";\nimport { ModeController } from \"../utils/modeController\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { sendTelemetry, type TelemetrySource } from \"../utils/telemetry\";\nimport { FetchController } from \"./controllers/fetchController\";\nimport { KeyboardController } from \"./controllers/keyboardController\";\nimport { PillsController } from \"./controllers/pillsController\";\nimport { previousGraphemeBoundary, setCursorOffset } from \"./dom/cursorUtils\";\nimport { buildDropdownOnly, updateDropdownOnly } from \"./render/renderDropdownOnly\";\nimport { buildDOM, type DOMRefs, updateDOM } from \"./render/renderInput\";\nimport { createStore } from \"./state\";\nimport { injectStyles } from \"./styleInjector\";\nimport type { CoreOptions, CoreState, RenderMode } from \"./types\";\n\nlet idCounter = 0;\nfunction stableId(): string {\n return `:ac-${++idCounter}:`;\n}\n\nconst SELECTION_ANIMATION_MS = 500;\n\nfunction initialState(): CoreState {\n return {\n text: \"\",\n completedParams: [],\n suggestions: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: false,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n placeholderText: \"\",\n isDropdownOpen: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: null,\n inSelectionAnimation: false,\n };\n}\n\nexport class AIAutocomplete {\n private store = createStore<CoreState>(initialState());\n private _listboxId = stableId();\n private opts: CoreOptions;\n private fetchController: FetchController;\n private keyboardController: KeyboardController;\n private pillsController: PillsController;\n private modeController: ModeController | null = null;\n private container: HTMLElement;\n private unsubscribers: (() => void)[] = [];\n private derivedInProgress = false;\n private renderMode: RenderMode;\n private domRefs: DOMRefs | null = null;\n private dropdownRefs: { dropdown: HTMLElement } | null = null;\n private newParamTimer: number | undefined;\n private suggestionRemovalTimer: number | undefined;\n private selectionAnimationTimer: number | undefined;\n private externalListeners = new Set<(state: CoreState) => void>();\n private sessionId: string = crypto.randomUUID();\n\n constructor(container: HTMLElement, opts: CoreOptions = {}) {\n this.container = container;\n this.opts = opts;\n this.renderMode = opts.renderMode ?? \"full\";\n\n // Apply controlled initial values\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n\n // Controllers\n this.pillsController = new PillsController(this.store, {\n onPillSelected: ({ rawQuery, selectedPill, otherPills }) => {\n this.fireTelemetry(\"pill\", {\n raw_query: rawQuery,\n selected_pill: selectedPill,\n other_pills: otherPills,\n });\n },\n });\n\n this.fetchController = new FetchController(\n this.store,\n () => this.opts.apiConfig,\n () => this.opts.optionOverrides,\n () => this.opts.maskCompletedText,\n () => this.opts.onError,\n () => this.sessionId,\n {\n onAutoMatch: ({ active, matched, rawQuery }) => {\n this.fireTelemetry(\"option\", {\n raw_query: rawQuery,\n selected_option: matched.text,\n other_options: (active.options ?? [])\n .filter((o) => o.text !== matched.text)\n .map((o) => o.text),\n });\n },\n },\n );\n\n this.keyboardController = new KeyboardController(this.store, {\n columns: opts.columns ?? 2,\n listboxId: this.listboxId,\n getOnSubmit: () => this.opts.onSubmit,\n // Tier 1 (full) auto-resets after submit; Tier 2/3 leave it to the consumer.\n afterSubmit: this.renderMode === \"full\" ? () => this.reset() : undefined,\n selectOption: (option) => this.selectOption(option),\n removeParamAtCaret: (offset) => this.removeParamAtCaret(offset),\n exitEditMode: () => this.exitEditMode(),\n });\n\n // Derived state recomputation\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n this.recomputeDerived(next, prev);\n }),\n );\n\n // Event callbacks\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.text !== prev.text) this.opts.onChange?.(next.text);\n if (next.completedParams !== prev.completedParams)\n this.opts.onParamsChange?.(next.completedParams);\n if (next.isFocused !== prev.isFocused) {\n if (next.isFocused) this.opts.onFocus?.();\n else this.opts.onBlur?.();\n }\n this.opts.onStateChange?.(next);\n }),\n );\n\n // Setup DOM based on render mode\n if (this.renderMode !== \"headless\") {\n injectStyles();\n this.setupContainer();\n }\n if (this.renderMode === \"full\") {\n this.buildAndRenderFull();\n } else if (this.renderMode === \"dropdown\") {\n this.buildAndRenderDropdown();\n }\n this.fetchController.start();\n }\n\n // === Public API ===\n\n focus() {\n this.domRefs?.input.focus();\n }\n\n blur() {\n this.domRefs?.input.blur();\n }\n\n reset() {\n // skipNextFetch suppresses the debounced fetch the FetchController would\n // otherwise schedule in response to text/params changing here — we issue\n // the empty fetch ourselves below so the new session starts immediately.\n this.store.set({\n ...initialState(),\n skipNextFetch: true,\n });\n this.sessionId = crypto.randomUUID();\n this.fetchController.doFetch(\"\", []);\n }\n\n destroy() {\n this.fetchController.dispose();\n this.modeController?.destroy();\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n if (this.suggestionRemovalTimer) clearTimeout(this.suggestionRemovalTimer);\n if (this.selectionAnimationTimer) clearTimeout(this.selectionAnimationTimer);\n this.externalListeners.clear();\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n this.domRefs?.abort.abort();\n this.domRefs = null;\n this.dropdownRefs = null;\n if (this.renderMode !== \"headless\") {\n this.container.innerHTML = \"\";\n }\n }\n\n setMode(mode: AppearanceMode) {\n this.modeController?.setMode(mode);\n }\n\n setValue(text: string) {\n this.store.set({ text });\n }\n\n setCompletedParams(params: CompletedParamState[]) {\n this.store.set({ completedParams: params });\n }\n\n setActivePill(index: number) {\n this.pillsController.setActivePill(index);\n }\n\n removeLastParam() {\n this.pillsController.removeLastParam();\n }\n\n /**\n * Backspace inside a completed param: drop the param's \"completed\" status so\n * it renders as plain (un-bold) text, AND remove one grapheme before the\n * caret — same single-character delete a normal Backspace would do. The\n * remaining text stays in the input so the user can continue editing what\n * they had typed instead of losing the whole phrase.\n *\n * Returns true when a param was reconciled (caller should `preventDefault`).\n */\n removeParamAtCaret(offset: number): boolean {\n const state = this.store.get();\n const { text, completedParams } = state;\n let pos = 0;\n for (let i = 0; i < completedParams.length; i++) {\n const param = completedParams[i];\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n const paramStart = idx;\n const paramEnd = idx + param.text.length;\n if (offset > paramStart && offset <= paramEnd) {\n const deleteStart = previousGraphemeBoundary(text, offset);\n const newText = text.slice(0, deleteStart) + text.slice(offset);\n const newParams = completedParams.filter((_, j) => j !== i);\n this.store.set((s) => ({\n text: newText,\n filterBase: Math.min(s.filterBase, newText.length),\n completedParams: newParams,\n pillTapped: false,\n activeDropdownIndex: -1,\n }));\n this.scheduleSetCursor(deleteStart);\n return true;\n }\n pos = paramEnd;\n }\n return false;\n }\n\n /**\n * Set the editor caret at the given plain-text offset. Uses the core's own\n * `domRefs.input` in \"full\" mode; falls back to the wrapper-provided\n * `setCursor` callback in \"headless\" mode where the wrapper owns the DOM.\n */\n private scheduleSetCursor(offset: number) {\n queueMicrotask(() => {\n const refs = this.domRefs;\n if (refs) {\n setCursorOffset(refs.input, offset);\n } else {\n this.opts.setCursor?.(offset);\n }\n });\n }\n\n clearNewParamId() {\n this.store.set({ newParamId: null });\n }\n\n /**\n * Enter re-edit mode for the bold completed param with the given id. The\n * caller is responsible for highlighting the param via the Selection API\n * (DOM concern). This method just sets the state snapshot so the dropdown\n * starts filtering the param's cached options.\n */\n startEditingParam(paramId: string) {\n const state = this.store.get();\n if (state.editingParam?.id === paramId) return;\n const param = state.completedParams.find((p) => p.id === paramId);\n if (!param) return;\n // Find the param's position in text (same approach as deriveSegments).\n let pos = 0;\n let anchor = -1;\n for (const p of state.completedParams) {\n const idx = state.text.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === paramId) {\n anchor = idx;\n break;\n }\n pos = idx + p.text.length;\n }\n if (anchor < 0) return;\n this.store.set({\n editingParam: param,\n editingAnchor: anchor,\n editingTail: anchor + param.text.length,\n caretOffset: anchor + param.text.length,\n activeDropdownIndex: -1,\n });\n }\n\n /**\n * Replace the editing range (`text[editingAnchor..editingTail]`) with the\n * given replacement. Used by the DOM layer's `beforeinput` intercept: while\n * the edited param's strong still exists in `completedParams`, typing or\n * backspace should swap the WHOLE param atomically (instead of inserting\n * one char into the bold span). Returns true when the replacement was\n * applied — callers should `preventDefault` only in that case.\n */\n replaceEditingRange(replacement: string): boolean {\n const state = this.store.get();\n const editing = state.editingParam;\n const anchor = state.editingAnchor;\n const tail = state.editingTail;\n if (!editing || anchor == null || tail == null) return false;\n // Only intercept while the param's strong is still in the DOM (i.e. it\n // hasn't already been replaced by an earlier keystroke).\n if (!state.completedParams.some((p) => p.id === editing.id)) return false;\n const newText = state.text.slice(0, anchor) + replacement + state.text.slice(tail);\n const newTail = anchor + replacement.length;\n this.store.set((s) => ({\n text: newText,\n completedParams: s.completedParams.filter((p) => p.id !== editing.id),\n editingTail: newTail,\n caretOffset: newTail,\n activeDropdownIndex: -1,\n }));\n this.scheduleSetCursor(newTail);\n this.maybePromoteEditExactMatch();\n return true;\n }\n\n /** Clear re-edit state. Selection collapsing is a DOM concern handled by the caller. */\n exitEditMode() {\n const state = this.store.get();\n if (!state.editingParam) return;\n this.store.set({\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n activeDropdownIndex: -1,\n });\n }\n\n /**\n * Update caret offset after a text-input event. While in edit mode, extends\n * `editingTail` to keep up with the user typing past the previous tail.\n * Exits edit mode if the user backspaced past `editingAnchor` (deleting a\n * character before where the edit started).\n */\n handleCaretAfterInput(offset: number | null) {\n const state = this.store.get();\n const patch: Partial<CoreState> = { caretOffset: offset };\n if (state.editingParam && state.editingAnchor != null && offset != null) {\n if (offset < state.editingAnchor) {\n patch.editingParam = null;\n patch.editingAnchor = null;\n patch.editingTail = null;\n patch.activeDropdownIndex = -1;\n } else if (state.editingTail != null) {\n patch.editingTail = Math.max(state.editingTail, offset);\n }\n }\n this.store.set(patch);\n this.maybePromoteEditExactMatch();\n }\n\n /**\n * Update caret offset from a selection-move event that was NOT preceded by\n * an input event (so the user moved the cursor by click or arrows, not by\n * typing). Exits edit mode if the caret moved outside the edit region.\n */\n handleCaretMove(offset: number | null) {\n const state = this.store.get();\n if (\n state.editingParam &&\n state.editingAnchor != null &&\n state.editingTail != null &&\n offset != null &&\n (offset < state.editingAnchor || offset > state.editingTail)\n ) {\n this.store.set({\n caretOffset: offset,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n activeDropdownIndex: -1,\n });\n return;\n }\n this.store.set({ caretOffset: offset });\n }\n\n setActiveDropdownIndex(index: number) {\n this.store.set({ activeDropdownIndex: index });\n }\n\n handleTextChange(value: string) {\n this.handleChange(value);\n }\n\n handleKeyDown(e: KeyboardEvent) {\n this.keyboardController.handleKeyDown(e);\n }\n\n setFocused(focused: boolean) {\n if (this.store.get().isFocused === focused) return;\n this.store.set({ isFocused: focused });\n }\n\n /** Subscribe to state changes (fires after derived state is settled). Returns unsubscribe function. */\n subscribe(listener: (state: CoreState) => void): () => void {\n this.externalListeners.add(listener);\n return () => {\n this.externalListeners.delete(listener);\n };\n }\n\n getState(): CoreState {\n return this.store.get();\n }\n\n get listboxId(): string {\n return this._listboxId;\n }\n\n get isReady(): boolean {\n return this.store.get().isReady;\n }\n\n on(event: string, callback: (...args: unknown[]) => void): () => void {\n switch (event) {\n case \"submit\":\n this.opts.onSubmit = callback as CoreOptions[\"onSubmit\"];\n return () => {\n this.opts.onSubmit = undefined;\n };\n case \"error\":\n this.opts.onError = callback as CoreOptions[\"onError\"];\n return () => {\n this.opts.onError = undefined;\n };\n case \"change\":\n this.opts.onChange = callback as CoreOptions[\"onChange\"];\n return () => {\n this.opts.onChange = undefined;\n };\n case \"paramsChange\":\n this.opts.onParamsChange = callback as CoreOptions[\"onParamsChange\"];\n return () => {\n this.opts.onParamsChange = undefined;\n };\n case \"stateChange\":\n this.opts.onStateChange = callback as CoreOptions[\"onStateChange\"];\n return () => {\n this.opts.onStateChange = undefined;\n };\n case \"focus\":\n this.opts.onFocus = callback as CoreOptions[\"onFocus\"];\n return () => {\n this.opts.onFocus = undefined;\n };\n case \"blur\":\n this.opts.onBlur = callback as CoreOptions[\"onBlur\"];\n return () => {\n this.opts.onBlur = undefined;\n };\n default:\n return () => {};\n }\n }\n\n update(opts: Partial<CoreOptions>) {\n Object.assign(this.opts, opts);\n if (opts.mode !== undefined) {\n this.modeController?.setMode(opts.mode);\n }\n if (opts.optionsPosition !== undefined) {\n this.container.dataset.optionsPosition = opts.optionsPosition;\n }\n if (opts.animations !== undefined) {\n this.container.dataset.animations = opts.animations ? \"on\" : \"off\";\n }\n if (opts.pillPlacement !== undefined) {\n this.container.dataset.pillPlacement = opts.pillPlacement;\n this.store.set({});\n }\n if (opts.dropdownTrigger !== undefined || opts.closeDropdownOnBlur !== undefined) {\n // Trigger recompute so isDropdownOpen updates\n this.store.set({});\n }\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n }\n\n // === Public (for framework wrappers) ===\n\n selectOption(option: SuggestionOption) {\n const state = this.store.get();\n\n // Re-edit path: replace the highlighted bold param's range with the new\n // option. The new param inherits the *same* cached suggestion metadata\n // (suggestionType/placeholder/options), so re-editing it again would show\n // the same options. Bypasses the normal selectOption flow entirely.\n if (state.editingParam && state.editingAnchor != null && state.editingTail != null) {\n this.selectOptionInEditMode(option);\n return;\n }\n\n const activeSuggestion = state.actionableSuggestions[0];\n if (!activeSuggestion) return;\n\n const { rawQuery: telemetryRawQuery } = buildQuery(state.text, state.completedParams);\n this.fireTelemetry(\"option\", {\n raw_query: telemetryRawQuery,\n selected_option: option.text,\n other_options: state.filteredOptions.filter((o) => o.text !== option.text).map((o) => o.text),\n });\n\n const base = state.filterBase;\n let prefix = state.text.slice(0, base);\n\n const inputWasEmpty = prefix.length === 0 && state.text.length === 0;\n // The user is still typing within the server-provided placeholder (e.g. typed\n // \"Cre\" for placeholder \"Create a\"). Selecting an option here should keep the\n // placeholder rather than discard it — otherwise tapping \"email\" replaces\n // \"Cre\" with just \"email\" instead of \"Create a email\".\n const inputIsPlaceholderPrefix =\n prefix.length === 0 &&\n state.text.length > 0 &&\n state.placeholderText.length > 0 &&\n state.placeholderText.toLowerCase().startsWith(state.text.toLowerCase());\n if ((inputWasEmpty || inputIsPlaceholderPrefix) && state.placeholderText) {\n prefix = `${state.placeholderText} `;\n }\n\n const overlapChars = findPrefixOverlap(prefix, option.text);\n if (overlapChars > 0) {\n prefix = prefix.slice(0, prefix.length - overlapChars);\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = `${prefix}${needsSpace ? \" \" : \"\"}${option.text} `;\n const finalText =\n (inputWasEmpty || inputIsPlaceholderPrefix) && newText.length > 0\n ? newText[0].toUpperCase() + newText.slice(1)\n : newText;\n\n const optionStart = finalText.toLowerCase().lastIndexOf(option.text.toLowerCase());\n const optionInFinal =\n optionStart >= 0\n ? finalText.slice(optionStart, optionStart + option.text.length)\n : option.text;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: optionInFinal,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options ?? [],\n metadata: option.metadata,\n };\n\n const remainingActionable = state.actionableSuggestions.length - 1;\n\n this.store.set((s) => ({\n text: finalText,\n filterBase: finalText.length,\n completedParams: [...s.completedParams, completed],\n newParamId: completed.id,\n caretOffset: finalText.length,\n pillTapped: false,\n activeDropdownIndex: -1,\n skipNextFetch: remainingActionable > 0,\n inSelectionAnimation: true,\n }));\n\n this.startSelectionAnimationTimer();\n\n // Suggestion removal timing depends on whether a fetch is firing.\n if (this.suggestionRemovalTimer) clearTimeout(this.suggestionRemovalTimer);\n if (remainingActionable > 0) {\n // Cached next-pill exists; no fetch fires. Remove the just-clicked\n // suggestion after the streak animation so the next pill becomes\n // active. The animation keeps playing on the option while it's still\n // in the DOM.\n this.suggestionRemovalTimer = window.setTimeout(() => {\n this.store.set((s) => ({\n suggestions: s.suggestions.filter((sg) => sg !== activeSuggestion),\n }));\n }, SELECTION_ANIMATION_MS);\n }\n // When `remainingActionable === 0` a fetch fires. We deliberately keep\n // the just-selected suggestion in state until the response lands — the\n // dropdown then mirrors its pill/option layout (count + widths) as the\n // loading skeleton, instead of falling back to the generic placeholder.\n }\n\n private startSelectionAnimationTimer() {\n if (this.selectionAnimationTimer) clearTimeout(this.selectionAnimationTimer);\n this.selectionAnimationTimer = window.setTimeout(() => {\n this.store.set({ inSelectionAnimation: false });\n }, SELECTION_ANIMATION_MS);\n }\n\n private selectOptionInEditMode(option: SuggestionOption) {\n const state = this.store.get();\n const editing = state.editingParam;\n const anchor = state.editingAnchor;\n const tail = state.editingTail;\n if (!editing || anchor == null || tail == null) return;\n\n this.fireTelemetry(\"option\", {\n raw_query: buildQuery(state.text, state.completedParams).rawQuery,\n selected_option: option.text,\n other_options: editing.options.filter((o) => o.text !== option.text).map((o) => o.text),\n });\n\n const before = state.text.slice(0, anchor);\n const after = state.text.slice(tail);\n // Capitalize when replacing at the very start of the input — matches the\n // case-handling in the normal selectOption path for \"first letter of the\n // input is uppercase\".\n const optionText =\n anchor === 0 && option.text.length > 0\n ? option.text[0].toUpperCase() + option.text.slice(1)\n : option.text;\n // Preserve the trailing-space convention: a single space follows the\n // replaced text unless the next char already provides one.\n const needsTrailingSpace = after.length === 0 || after[0] !== \" \";\n const replacement = needsTrailingSpace ? `${optionText} ` : optionText;\n const newText = before + replacement + after;\n // Caret lands AFTER the trailing space — whether we just added it or it\n // was already there from the original text. Matches the normal\n // selectOption flow where the caret sits past the trailing space ready\n // to type the next word.\n const caretPos = anchor + replacement.length + (needsTrailingSpace ? 0 : 1);\n\n const newParam: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: editing.suggestionType,\n text: optionText,\n kind: option.kind,\n suggestionType: editing.suggestionType,\n suggestionPlaceholder: editing.suggestionPlaceholder,\n options: editing.options,\n metadata: option.metadata,\n };\n const oldIdx = state.completedParams.findIndex((p) => p.id === editing.id);\n const params = state.completedParams.filter((p) => p.id !== editing.id);\n const insertAt = oldIdx >= 0 ? Math.min(oldIdx, params.length) : params.length;\n params.splice(insertAt, 0, newParam);\n\n this.store.set({\n text: newText,\n completedParams: params,\n newParamId: newParam.id,\n filterBase: caretPos,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n pillTapped: false,\n skipNextFetch: true,\n inSelectionAnimation: true,\n });\n this.startSelectionAnimationTimer();\n // Park the caret right after the replacement (not at end of text) once\n // the render microtask commits.\n this.scheduleSetCursor(caretPos);\n }\n\n private fireTelemetry(type: \"pill\" | \"option\", queryData: Record<string, unknown>) {\n // Vanilla consumers don't pass `source` — derive from renderMode.\n // The React hook always uses renderMode \"headless\" but Tier 1 explicitly\n // passes source: \"full-sdk\" via opts to override.\n const source: TelemetrySource =\n this.opts.source ?? (this.renderMode === \"full\" ? \"full-sdk\" : \"headless-sdk\");\n void sendTelemetry({\n source,\n sessionId: this.sessionId,\n type,\n queryData,\n apiConfig: this.opts.apiConfig,\n });\n }\n\n private recomputeDerived(next: CoreState, _prev: CoreState) {\n if (this.derivedInProgress) return;\n this.derivedInProgress = true;\n const segments = deriveSegments(next.text, next.completedParams);\n const actionableSuggestions = next.suggestions.filter((s) => s.type !== \"placeholder\");\n const activeSuggestion = actionableSuggestions[0] as Suggestion | undefined;\n const overrideFn = activeSuggestion\n ? this.opts.optionOverrides?.[activeSuggestion.type]\n : undefined;\n\n const placeholderText = next.suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n\n // Clamp filterBase so it never exceeds text length (matches old React behavior).\n // Promote the placeholder to filterBase when the user has typed through it —\n // the filter query should be just the text past the server-suggested prefix.\n const clampedFilterBase = effectiveFilterBase(\n next.text,\n Math.min(next.filterBase, next.text.length),\n placeholderText,\n );\n // When filterBase is 0 and no fetch has set it yet, don't filter by typed text —\n // the user is still typing the initial query and no server context exists\n const hasServerContext = next.lastRawQuery !== \"\" || clampedFilterBase > 0;\n const filterQuery = hasServerContext\n ? extractFilterQuery(next.text, clampedFilterBase, next.filterInProgress)\n : \"\";\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n\n // Re-edit mode: dropdown filters the edited param's cached options instead\n // of the active suggestion's options. While the bold param's still in the\n // DOM (user just tapped it, hasn't typed yet), show the FULL cached list —\n // filtering by the param's own text would only match itself. Once the\n // user starts typing (param removed from completedParams), filter by what\n // they typed.\n const inEditMode = next.editingParam != null && next.editingAnchor != null;\n let filteredOptions: SuggestionOption[];\n if (inEditMode && next.editingParam && next.editingAnchor != null) {\n const editingId = next.editingParam.id;\n const paramStillPresent = next.completedParams.some((p) => p.id === editingId);\n const editCaret = next.caretOffset ?? next.editingAnchor;\n const editQuery = paramStillPresent ? \"\" : next.text.slice(next.editingAnchor, editCaret);\n filteredOptions = filterOptions(next.editingParam.options, editQuery);\n } else {\n filteredOptions = filterOptions(baseOptions, filterQuery);\n }\n\n const trigger = this.opts.dropdownTrigger ?? \"auto\";\n const closeOnBlur = this.opts.closeDropdownOnBlur ?? true;\n let isDropdownOpen = false;\n if (inEditMode) {\n // While re-editing, the dropdown is governed solely by whether cached\n // options match the query — focus/manual gates don't apply (the user\n // is in a deliberate edit interaction).\n const focusGate = closeOnBlur ? next.isFocused : true;\n isDropdownOpen = filteredOptions.length > 0 && focusGate;\n } else if (trigger === \"auto\") {\n const focusGate = closeOnBlur ? next.isFocused : true;\n // Outside re-edit, dropdown only opens when the caret is at the end of\n // the input — middle-of-text caret should NOT show suggestions. Trailing\n // whitespace is ignored so the dropdown stays open right after an option\n // selection (which appends a trailing space) or when the user pauses on\n // a word boundary.\n const trimmedEnd = next.text.replace(/\\s+$/, \"\").length;\n const caretAtEnd = next.caretOffset == null || next.caretOffset >= trimmedEnd;\n isDropdownOpen = (filteredOptions.length > 0 || next.isLoading) && focusGate && caretAtEnd;\n } else if (trigger === \"manual\") {\n isDropdownOpen = (filteredOptions.length > 0 || next.isLoading) && next.pillTapped;\n }\n\n this.store.set({\n segments,\n actionableSuggestions,\n filteredOptions,\n placeholderText,\n isDropdownOpen,\n });\n this.derivedInProgress = false;\n\n // Notify external listeners after derived state is settled\n const settled = this.store.get();\n for (const listener of this.externalListeners) {\n listener(settled);\n }\n }\n\n private setupContainer() {\n this.container.classList.add(\"magicx-aia\");\n // In dropdown mode, pills are always in the dropdown\n this.container.dataset.pillPlacement =\n this.renderMode === \"dropdown\" ? \"dropdown\" : (this.opts.pillPlacement ?? \"inline\");\n this.container.dataset.optionsPosition = this.opts.optionsPosition ?? \"below\";\n this.container.dataset.animations = (this.opts.animations ?? true) ? \"on\" : \"off\";\n\n // ModeController\n this.modeController = new ModeController(this.container, this.opts.mode ?? \"auto\");\n }\n\n private buildAndRenderFull() {\n const self = this;\n const renderOpts = {\n store: this.store,\n listboxId: this.listboxId,\n get pillPlacement() {\n return (self.opts.pillPlacement ?? \"inline\") as \"inline\" | \"dropdown\";\n },\n get onSubmit() {\n return self.opts.onSubmit;\n },\n // Tier 1 only (this code path runs only for renderMode === \"full\").\n afterSubmit: () => self.reset(),\n submitButton: this.opts.submitButton,\n autoFocus: this.opts.autoFocus ?? true,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n handleKeyDown: (e: KeyboardEvent) => this.keyboardController.handleKeyDown(e),\n handleChange: (value: string) => this.handleChange(value),\n startEditingParam: (id: string) => this.startEditingParam(id),\n handleCaretAfterInput: (offset: number | null) => this.handleCaretAfterInput(offset),\n handleCaretMove: (offset: number | null) => this.handleCaretMove(offset),\n replaceEditingRange: (replacement: string) => this.replaceEditingRange(replacement),\n };\n\n this.domRefs = buildDOM(this.container, renderOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.domRefs) {\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n }\n });\n\n // Initial render\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n this.subscribeNewParamTimer();\n }\n\n private buildAndRenderDropdown() {\n const dropdownOpts = {\n store: this.store,\n listboxId: this.listboxId,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n };\n\n this.dropdownRefs = buildDropdownOnly(this.container, dropdownOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.dropdownRefs) {\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n }\n });\n\n // Initial render\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n this.subscribeNewParamTimer();\n }\n\n /** Batched render subscriber — coalesces multiple store.set calls into one DOM update. */\n private subscribeBatchedRender(render: () => void) {\n let scheduled = false;\n this.unsubscribers.push(\n this.store.subscribe(() => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n render();\n });\n }),\n );\n }\n\n /** Auto-clear newParamId after shimmer animation. */\n private subscribeNewParamTimer() {\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.newParamId && next.newParamId !== prev.newParamId) {\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n this.newParamTimer = window.setTimeout(() => {\n this.store.set({ newParamId: null });\n }, 650);\n }\n }),\n );\n }\n\n private handleChange(newValue: string) {\n const state = this.store.get();\n this.store.set({\n text: newValue,\n pillTapped: false,\n activeDropdownIndex: -1,\n });\n\n const { valid, invalid } = reconcileParams(newValue, state.completedParams);\n if (invalid.length > 0) {\n this.store.set({ completedParams: valid });\n }\n\n this.maybePromoteExactMatch(newValue);\n }\n\n /**\n * When the user has typed text that exactly matches (case-insensitive) one\n * of the active suggestion's options, promote it to a completed param right\n * away. The fetchController does the same check when the debounced fetch\n * lands; doing it instantly here means bold styling appears as soon as the\n * option is fully typed, without waiting 100–300ms for the round-trip.\n */\n private maybePromoteExactMatch(newValue: string) {\n const s = this.store.get();\n const actionable = s.suggestions.filter((sg) => sg.type !== \"placeholder\");\n const active = actionable[0];\n if (!active?.options) return;\n const placeholderText = s.suggestions\n .filter((sg) => sg.type === \"placeholder\")\n .map((sg) => sg.text)\n .join(\" \");\n const effBase = effectiveFilterBase(newValue, s.filterBase, placeholderText);\n const query = extractFilterQuery(newValue, effBase, s.filterInProgress);\n const match = findExactMatch(active.options, query);\n if (!match) return;\n // Preserve the case the user actually typed so deriveSegments (case-\n // sensitive indexOf) can still match the completed param inside newValue.\n const matchLower = match.text.toLowerCase();\n const optionStart = newValue.toLowerCase().lastIndexOf(matchLower);\n const paramStart =\n optionStart >= 0 ? optionStart : Math.max(0, newValue.length - match.text.length);\n const paramEnd = paramStart + match.text.length;\n const optionInText = newValue.slice(paramStart, paramEnd);\n // The user typed the option themselves — don't inject a trailing space.\n // If they wanted a space, they'd type one. (Auto-injecting one here\n // caused double-space states when the user added their own space, which\n // confused contentEditable's trailing-whitespace handling.)\n const newText = newValue;\n const hasTrailingSpace = paramEnd < newValue.length && newValue[paramEnd] === \" \";\n const caretPos = hasTrailingSpace ? paramEnd + 1 : paramEnd;\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: optionInText,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n this.store.set((prev) => ({\n text: newText,\n completedParams: [...prev.completedParams, completed],\n suggestions: prev.suggestions.filter((sg) => sg !== active),\n filterBase: caretPos,\n newParamId: completed.id,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n }));\n }\n\n /**\n * Edit-mode counterpart to {@link maybePromoteExactMatch}. When the user is\n * editing a bold completed param and the typed text exactly matches one of\n * that param's cached options, promote it back to a completed param (bold)\n * — same instant-bold affordance as the normal typing flow, just driven by\n * the edited param's cached options instead of the active suggestion.\n */\n private maybePromoteEditExactMatch() {\n const s = this.store.get();\n const editing = s.editingParam;\n const anchor = s.editingAnchor;\n const tail = s.editingTail;\n if (!editing || anchor == null || tail == null) return;\n // Skip while the original bold is still in completedParams (user hasn't\n // typed yet — the editQuery would just be the param's own text).\n if (s.completedParams.some((p) => p.id === editing.id)) return;\n const editQuery = s.text.slice(anchor, tail);\n const match = findExactMatch(editing.options, editQuery);\n if (!match) return;\n\n // Locate the matched portion within the edit region so we know where the\n // new param's text sits in the full input. Preserve the user's typed\n // casing so deriveSegments (case-sensitive indexOf) can still find it.\n const matchLower = match.text.toLowerCase();\n const matchStart = editQuery.toLowerCase().lastIndexOf(matchLower);\n const paramStart = anchor + Math.max(0, matchStart);\n const paramEnd = paramStart + match.text.length;\n const optionInText = s.text.slice(paramStart, paramEnd);\n\n // The user typed the option themselves — don't inject a trailing space.\n const newText = s.text;\n const hasTrailingSpace = paramEnd < s.text.length && s.text[paramEnd] === \" \";\n const caretPos = hasTrailingSpace ? paramEnd + 1 : paramEnd;\n\n const newParam: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: editing.suggestionType,\n text: optionInText,\n kind: match.kind,\n suggestionType: editing.suggestionType,\n suggestionPlaceholder: editing.suggestionPlaceholder,\n options: editing.options,\n metadata: match.metadata,\n };\n\n // Insert at the correct text-order position. The editing param is already\n // gone from completedParams; walk the remaining params and insert before\n // the first one whose text sits past the edit region.\n let insertAt = s.completedParams.length;\n let scanPos = 0;\n for (let i = 0; i < s.completedParams.length; i++) {\n const idx = newText.indexOf(s.completedParams[i].text, scanPos);\n if (idx === -1) continue;\n if (idx >= caretPos) {\n insertAt = i;\n break;\n }\n scanPos = idx + s.completedParams[i].text.length;\n }\n const newParams = [...s.completedParams];\n newParams.splice(insertAt, 0, newParam);\n\n this.store.set(() => ({\n text: newText,\n completedParams: newParams,\n newParamId: newParam.id,\n filterBase: caretPos,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n }));\n this.scheduleSetCursor(caretPos);\n }\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","s","AIAutocomplete_module_css_default","s","AIAutocompleteDropdown_module_css_default","s","PillList_module_css_default","import_jsx_runtime","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","rounded","loading","PillList_module_css_default","w","pill","e","import_react","s","SuggestionGrid_module_css_default","import_react","s","SuggestionItem_module_css_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","pressed","setPressed","timerRef","handleSelect","className","SuggestionItem_module_css_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","gridRef","hasBottomOverflow","setHasBottomOverflow","el","update","resizeObserver","SuggestionGrid_module_css_default","option","i","SuggestionItem","import_jsx_runtime","FALLBACK_SKELETON_BAR_WIDTHS","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","pills","onPillClick","showPills","isLoading","options","showsPills","showsOptions","showsFallbackSkeleton","isVisible","AIAutocompleteDropdown_module_css_default","e","PillList","SuggestionGrid","w","s","NON_EDITABLE_SELECTOR","segmenter","getGraphemeSegmenter","Segmenter","isInsideNonEditable","node","root","n","createTextWalker","extractPlainText","walker","out","plainTextLength","total","getCursorOffset","sel","anchorNode","anchorOffset","el","offset","plainTextLengthOfSubtree","offsetBeforeNode","child","target","setCursorOffset","doc","clamped","cumulative","targetOffset","lastNode","len","next","range","strongParent","cursorIsAtEnd","previousGraphemeBoundary","text","seg","slice","last","index","renderEditableContent","args","input","segments","newParamId","editingParamId","placeholderText","isFocused","empty","segKey","s","lastSegKey","lastNewParamId","lastEditingParamId","savedOffset","getCursorOffset","doc","frag","newLength","seg","strong","isNew","isEditing","classes","setCursorOffset","import_react","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","effectiveFilterBase","text","filterBase","placeholderText","extractFilterQuery","isInProgress","rawRegion","spaceIdx","findPrefixOverlap","prefix","optionText","trimmed","words","optionLower","i","candidate","suffixStart","filterOptions","options","query","lower","o","findExactMatch","ModeController","container","mode","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","TokenManager","config","forceRefresh","result","DEFAULT_API_ORIGIN","DEFAULT_SUGGEST_ENDPOINT","tokenManagers","isAccessTokenConfig","config","getApiKeyConfig","getTokenManager","manager","TokenManager","buildHeaders","apiConfig","buildApiKeyAuthHeader","apiKeyConfig","apiKey","deriveTelemetryEndpoint","suggestEndpoint","DEFAULT_SUGGEST_ENDPOINT","resolveAuthHeader","apiConfig","isAccessTokenConfig","getTokenManager","buildApiKeyAuthHeader","sendTelemetry","event","endpoint","headers","buildHeaders","authHeader","body","SDK_VERSION","hasWarnedMissingKey","generateRequestId","toWireParam","param","includeText","buildRequestBody","rawQuery","completedParams","sessionId","rawCount","p","contactAccountCount","doFetch","endpoint","headers","token","body","signal","fetchSuggestions","options","apiConfig","buildHeaders","DEFAULT_SUGGEST_ENDPOINT","jsonBody","isAccessTokenConfig","manager","getTokenManager","response","newToken","authHeader","buildApiKeyAuthHeader","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","FetchController","store","getApiConfig","getOptionOverrides","getMaskCompletedText","getOnError","getSessionId","callbacks","prevText","prevParams","next","rawQuery","completed","controller","version","textAtRequest","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","filterBase","filterInProgress","inProgressIdx","active","s","extraParam","query","extractFilterQuery","match","findExactMatch","err","caughtError","attemptFetch","minDiff","placeholderText","sg","effBase","effectiveFilterBase","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","isCursorAtEnd","target","cursorIsAtEnd","getEditableCaretOffset","getCursorOffset","KeyboardController","store","ctx","state","listboxId","getOnSubmit","columns","onSubmit","tappableIndices","cursorAtEnd","inEditMode","currentPos","nextPos","prevPos","rightNeighbor","editor","tail","setCursorOffset","leftNeighbor","anchor","offset","rawQuery","finalParams","buildQuery","placeholderVisible","hasHighlightedOption","filledText","s","sg","firstTappableIdx","o","tappable","i","buckets","grid","tracks","index","options","optionEl","actionable","moved","rest","_","placeholders","PillsController","store","callbacks","index","state","actionable","moved","rest","_","i","placeholders","rawQuery","buildQuery","s","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","renderPills","container","pills","activePillIndex","onSelectPill","rounded","loading","list","i","width","span","skel","existing","btn","used","pill","key","e","classes","clearPills","FALLBACK_SKELETON_BAR_WIDTHS","createDropdown","listboxId","dropdown","e","renderDropdown","state","filteredOptions","activeIndex","isOpen","isLoading","pills","showPills","onSelect","onHighlight","onPillClick","hasPills","hasOptions","wantsPillBar","pillBar","renderPills","grid","renderOptions","skeleton","width","bar","options","loading","optionsKey","o","lastKey","lastLoading","loadingFlag","listChanged","fragment","i","option","item","createOptionElement","items","isHighlighted","index","classes","streaks","streaksVert","content","tag","buildDropdownOnly","container","opts","dropdown","createDropdown","updateDropdownOnly","refs","state","renderDropdown","i","SUBMIT_SVG","supportsPlaintextOnly","probe","buildDOM","container","opts","listboxId","dropdown","createDropdown","inputWrapper","editor","input","inlinePillContainer","submitButton","submitTarget","abort","signal","composing","lastInputAt","fireInput","raw","extractPlainText","newValue","findEnclosingParamId","sel","anchor","e","getCursorOffset","doc","enclosing","editingId","inputEvent","t","replacement","text","range","node","state","rawQuery","finalParams","buildQuery","updateDOM","refs","pillPlacement","setActivePill","selectOption","store","activeDescendant","canSubmit","previousParamId","justSelected","renderEditableContent","inlineLoading","renderPills","clearPills","setCursorOffset","dropdownPill","dropdownActivePill","renderDropdown","i","createStore","initial","state","listeners","patch","resolved","next","prev","l","listener","injected","injectStyles","style","STYLES","idCounter","stableId","SELECTION_ANIMATION_MS","initialState","AIAutocomplete","container","opts","createStore","PillsController","rawQuery","selectedPill","otherPills","FetchController","active","matched","o","KeyboardController","option","offset","next","prev","injectStyles","unsub","mode","text","params","index","state","completedParams","pos","param","idx","paramStart","paramEnd","deleteStart","previousGraphemeBoundary","newText","newParams","_","j","s","refs","setCursorOffset","paramId","p","anchor","replacement","editing","tail","newTail","patch","value","focused","listener","event","callback","activeSuggestion","telemetryRawQuery","buildQuery","base","prefix","inputWasEmpty","inputIsPlaceholderPrefix","overlapChars","findPrefixOverlap","needsSpace","finalText","optionStart","optionInFinal","completed","remainingActionable","sg","before","after","optionText","needsTrailingSpace","caretPos","newParam","oldIdx","insertAt","type","queryData","source","sendTelemetry","_prev","segments","deriveSegments","actionableSuggestions","overrideFn","placeholderText","clampedFilterBase","effectiveFilterBase","filterQuery","extractFilterQuery","baseOptions","inEditMode","filteredOptions","editingId","paramStillPresent","editCaret","editQuery","filterOptions","trigger","closeOnBlur","isDropdownOpen","focusGate","trimmedEnd","caretAtEnd","settled","ModeController","self","renderOpts","e","id","buildDOM","updateDOM","dropdownOpts","buildDropdownOnly","updateDropdownOnly","render","scheduled","newValue","valid","invalid","reconcileParams","effBase","query","match","findExactMatch","matchLower","optionInText","matchStart","scanPos","i","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","apiConfig","columns","dropdownTrigger","closeDropdownOnBlur","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","instance","AIAutocomplete","args","offset","unsub","state","noop","apiConfigJson","prevOverridesRef","overridesVersion","prev","next","prevKeys","nextKeys","k","handleChange","e","raw","newValue","handleKeyDown","handleFocus","handleBlur","handleTextChange","value","handleKeyDownT1","native","setFocused","focused","startEditingParam","paramId","exitEditMode","handleCaretAfterInput","handleCaretMove","replaceEditingRange","replacement","setActivePill","index","removeLastParam","clearNewParamId","reset","selectOption","option","setActiveDropdownIndex","text","completedParams","actionableSuggestions","activeSuggestion","filteredOptions","activeDescendantId","editingParam","dropdownPill","dropdownActivePill","dropdownPills","import_jsx_runtime","resolveInitialMode","mode","plaintextOnlyCache","supportsPlaintextOnly","probe","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","className","apiConfig","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","submitButton","ref","containerRef","inputRef","handleSubmitRef","modeControllerRef","composingRef","lastSeenParamIdRef","lastEditingIdRef","caretOffsetRef","lastInputAtRef","el","ModeController","handleSetCursor","offset","setCursorOffset","completedParams","suggestionPills","setActivePill","segments","newParamId","clearNewParamId","placeholderText","isFocused","isDropdownOpen","isLoading","activeIndex","listboxId","handleTextChange","handleKeyDown","setFocused","editingParam","editingAnchor","caretOffset","startEditingParam","handleCaretAfterInput","handleCaretMove","replaceEditingRange","dropdownProps","reset","useAIAutocomplete","result","t","doc","onSelectionChange","sel","anchor","enclosing","getCursorOffset","renderEditableContent","previous","current","desired","plainTextLength","m","fireInput","raw","extractPlainText","next","handleInputEvent","onBeforeInput","e","inputEvent","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","range","node","handleKeyDownReact","canSubmit","handleSubmit","rawQuery","finalParams","buildQuery","handleWrapperClick","showInlinePills","showDropdownPills","activeDescendantId","ceMode","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/AIAutocomplete.module.css.js","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/AIAutocompleteDropdown.module.css.js","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/PillList.module.css.js","../src/components/PillList.tsx","../src/components/SuggestionGrid.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/SuggestionGrid.module.css.js","../src/components/SuggestionItem.tsx","css-module:/Users/saharshv/MagicX/ai-autocomplete-react/src/components/SuggestionItem.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/Users/saharshv/MagicX/ai-autocomplete-react/src/appearance.css.js","../src/core/dom/cursorUtils.ts","../src/hooks/useAIAutocomplete.ts","../src/utils/buildQuery.ts","../src/utils/filtering.ts","../src/utils/modeController.ts","../src/utils/segments.ts","../src/utils/tokenManager.ts","../src/utils/auth.ts","../src/utils/telemetry.ts","../src/utils/api.ts","../src/utils/overrides.ts","../src/core/controllers/fetchController.ts","../src/core/controllers/keyboardController.ts","../src/core/controllers/pillsController.ts","../src/core/derive/dropdown.ts","../src/core/derive/state.ts","../src/core/promotion/promote.ts","../src/core/reEdit/ReEditManager.ts","../src/core/render/reconcileList.ts","../src/core/render/renderPills.ts","../src/core/render/renderDropdown.ts","../src/core/render/renderDropdownOnly.ts","../src/core/render/renderEditable.ts","../src/core/render/renderInput.ts","../src/core/selection/SelectionFlow.ts","../src/core/state.ts","../src/core/styleInjector.ts","../src/core/util/Emitter.ts","../src/core/util/TimerScheduler.ts","../src/core/AIAutocomplete.ts","../src/hooks/useContentEditableEditor.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport \"./appearance.css\";\nimport { PillList } from \"./components/PillList\";\nimport { setCursorOffset } from \"./core/dom/cursorUtils\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport { useContentEditableEditor } from \"./hooks/useContentEditableEditor\";\nimport type {\n AIAutocompleteHandle,\n AIAutocompleteProps,\n AppearanceMode,\n AutocompleteResult,\n} from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\nimport { ModeController } from \"./utils/modeController\";\n\nfunction resolveInitialMode(mode: AppearanceMode): \"light\" | \"dark\" {\n if (mode !== \"auto\") return mode;\n if (typeof window === \"undefined\") return \"dark\";\n return window.matchMedia(\"(prefers-color-scheme: dark)\").matches ? \"dark\" : \"light\";\n}\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n className,\n apiConfig,\n columns,\n pillPlacement = \"inline\",\n mode = \"auto\",\n optionsPosition = \"below\",\n animations = true,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n autoFocus = true,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n submitButton,\n },\n ref,\n ) {\n const containerRef = useRef<HTMLDivElement>(null);\n const pillContainerRef = useRef<HTMLSpanElement>(null);\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const modeControllerRef = useRef<ModeController | null>(null);\n // Holds the editor's input *ref object* (not its current value) so the\n // setCursor callback — defined before useContentEditableEditor runs — can\n // dereference the live DOM element at call time without a one-render lag.\n const editorInputRefHolder = useRef<React.RefObject<HTMLDivElement> | null>(null);\n\n useEffect(() => {\n const el = containerRef.current;\n if (!el) return;\n if (modeControllerRef.current) {\n modeControllerRef.current.setMode(mode);\n } else {\n modeControllerRef.current = new ModeController(el, mode);\n }\n return () => {\n modeControllerRef.current?.destroy();\n modeControllerRef.current = null;\n };\n }, [mode]);\n\n const handleSetCursor = useCallback((offset: number) => {\n const el = editorInputRefHolder.current?.current;\n if (!el) return;\n el.focus();\n setCursorOffset(el, offset);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n newParamId,\n clearNewParamId,\n placeholderText,\n isFocused,\n isDropdownOpen,\n isLoading,\n activeIndex,\n listboxId,\n handleTextChange,\n handleKeyDown,\n setFocused,\n editingParam,\n editingAnchor,\n caretOffset,\n startEditingParam,\n handleCaretAfterInput,\n handleCaretMove,\n replaceEditingRange,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n columns,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n onFocus,\n onBlur,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n source: \"full-sdk\",\n setCursor: handleSetCursor,\n });\n\n // Shimmer auto-clear after the animation finishes.\n useEffect(() => {\n if (!newParamId) return;\n const t = window.setTimeout(() => clearNewParamId(), 650);\n return () => window.clearTimeout(t);\n }, [newParamId, clearNewParamId]);\n\n const activeDescendantId = activeIndex >= 0 ? `${listboxId}-option-${activeIndex}` : undefined;\n\n const { inputRef, editorProps, focus, blur, getPlainText } = useContentEditableEditor({\n segments,\n newParamId,\n editingParam,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n });\n\n // Wire the holder to the hook's ref. The ref *object* is stable across\n // renders, so this assignment is idempotent and reaches the live DOM\n // element via `.current` without snapshotting null on the first render.\n editorInputRefHolder.current = inputRef;\n\n // The pill list sits inline-adjacent to the editor and carries an 8px\n // left margin so it doesn't butt against the editor's text. When the\n // editor's text fills its line and the pill list wraps to a new line,\n // that margin becomes a stray indent at the start of the wrapped line.\n // Detect the wrap (pill below editor's last line, or editor empty) and\n // drop the margin via a data attribute the CSS keys off.\n // biome-ignore lint/correctness/useExhaustiveDependencies: segments/suggestionPills/isLoading are intentional re-measure triggers, not reads\n useLayoutEffect(() => {\n const container = pillContainerRef.current;\n const editor = inputRef.current;\n if (!container || !editor) return;\n\n const update = () => {\n const inner = container.firstElementChild as HTMLElement | null;\n if (!inner) return;\n const isEmpty = editor.dataset.aiaEmpty === \"true\";\n if (isEmpty) {\n container.setAttribute(\"data-aia-pill-wrapped\", \"\");\n return;\n }\n const cRect = inner.getBoundingClientRect();\n const eRect = editor.getBoundingClientRect();\n const wrapped = cRect.top >= eRect.bottom - 2;\n if (wrapped) container.setAttribute(\"data-aia-pill-wrapped\", \"\");\n else container.removeAttribute(\"data-aia-pill-wrapped\");\n };\n\n update();\n const ro = new ResizeObserver(update);\n ro.observe(editor);\n return () => ro.disconnect();\n }, [segments, suggestionPills.length, isLoading, inputRef]);\n\n useImperativeHandle(\n ref,\n () => ({\n focus,\n blur,\n reset,\n setMode: (m) => modeControllerRef.current?.setMode(m),\n }),\n [focus, blur, reset],\n );\n\n const canSubmit = !!segments.length || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const text = getPlainText();\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n onSubmit({\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n }, [canSubmit, completedParams, onSubmit, reset, getPlainText]);\n\n handleSubmitRef.current = handleSubmit;\n\n const handleWrapperClick = useCallback(\n (e: React.MouseEvent<HTMLDivElement>) => {\n // Clicking a pill activates it; don't steal focus away from where it lands.\n const target = e.target as HTMLElement | null;\n if (target?.closest(\"[data-aia-pill]\")) return;\n focus();\n },\n [focus],\n );\n\n const showInlinePills = pillPlacement === \"inline\";\n const showDropdownPills = pillPlacement === \"dropdown\";\n\n return (\n <div\n ref={containerRef}\n className={`magicx-aia ${styles.container} ${className ?? \"\"}`}\n data-pill-placement={pillPlacement}\n data-options-position={optionsPosition}\n data-animations={animations ? \"on\" : \"off\"}\n data-mode={resolveInitialMode(mode)}\n >\n <AIAutocompleteDropdown {...dropdownProps} showPills={showDropdownPills} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to editor focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to editor */}\n <div className={styles.inputWrapper} onClick={handleWrapperClick}>\n <div className={styles.editorArea} data-aia-editor=\"\">\n <div {...editorProps} className={styles.input} data-aia-input=\"\" />\n {showInlinePills && (isLoading || suggestionPills.length > 0) && (\n <span\n ref={pillContainerRef}\n className={styles.pillListContainer}\n data-aia-pill-list-container=\"\"\n >\n <PillList\n pills={suggestionPills}\n activePillIndex={0}\n onSelectPill={setActivePill}\n loading={isLoading}\n />\n </span>\n )}\n </div>\n {submitButton === null ? null : submitButton === undefined ? (\n <button\n type=\"button\"\n data-aia-submit=\"\"\n className={styles.submitButton}\n disabled={!canSubmit}\n onClick={(e) => {\n e.stopPropagation();\n handleSubmit();\n }}\n aria-label=\"Submit\"\n >\n <svg\n width=\"18\"\n height=\"18\"\n viewBox=\"0 0 18 18\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Submit\"\n >\n <path\n d=\"M9 14V4M9 4L4 9M9 4L14 9\"\n stroke=\"currentColor\"\n strokeWidth=\"2\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n />\n </svg>\n </button>\n ) : (\n // biome-ignore lint/a11y/useKeyWithClickEvents: consumer-provided element handles its own keyboard interaction\n // biome-ignore lint/a11y/noStaticElementInteractions: transparent slot — click bubbles from consumer's element\n <span\n data-aia-submit=\"\"\n className={styles.submitSlot}\n onClick={(e) => {\n if (!canSubmit) return;\n e.stopPropagation();\n handleSubmit();\n }}\n >\n {submitButton}\n </span>\n )}\n </div>\n </div>\n );\n },\n);\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-cc65f4cc\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-cc65f4cc\";\n s.textContent = `.AIAutocomplete-module_container_KKjFU {\n position: relative;\n /* Inherits the host page's font by default. Consumers can pin a specific\n font on the library via \\`--aia-font-family: 'Custom Font'\\` without\n affecting the surrounding page. */\n font-family: var(--aia-font-family, inherit);\n container-type: inline-size;\n}\n\n.AIAutocomplete-module_inputWrapper_FLq1b {\n padding: 20px;\n border: 1px solid var(--aia-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 4px;\n}\n\n.AIAutocomplete-module_editorArea_7rBWq {\n position: relative;\n flex: 1;\n min-width: 0;\n min-height: 26.6px;\n line-height: 26.6px;\n font-family: inherit;\n font-size: var(--aia-written-text-font-size, 19px);\n white-space: pre-wrap;\n word-break: break-word;\n overflow-wrap: anywhere;\n}\n\n.AIAutocomplete-module_input_IW-P- {\n display: inline;\n outline: none;\n background: transparent;\n color: var(--aia-written-text-color, var(--aia-color-text-default, #fff));\n caret-color: var(\n --aia-caret-color,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff))\n );\n font-weight: 250;\n /* Align the text's inline box with the pill list (also vertical-align: middle)\n so they share a vertical center when pills stretch the line box to ~36px. */\n vertical-align: middle;\n}\n\n/* Completed params render as inline bold runs. \\`:where()\\` keeps specificity\n at (0,2,0) so consumers can override without \\`!important\\`. */\n:where(.AIAutocomplete-module_input_IW-P-) strong {\n font-weight: 500;\n letter-spacing: -0.01em;\n}\n\n/* Re-edit highlight — the editing class is written by the shared renderer\n (a global string), so target it via an attribute selector to bypass\n CSS Modules' class-name hashing. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"] {\n background-color: color-mix(in srgb, var(--aia-edit-outline, currentColor) 20%, transparent);\n border-radius: 4px;\n caret-color: transparent;\n}\n\n/* In re-edit mode the caret is parked just *before* the bold strong (see\n useContentEditableEditor.ts) — that means it sits in the parent .input, not\n inside the strong, so the rule above doesn't hide it. Use :has() to hide\n the caret on the whole editor while any completed param is selected. */\n.AIAutocomplete-module_input_IW-P-:has(strong[class~=\"magicx-aia-segment--editing\"]) {\n caret-color: transparent;\n}\n\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::selection {\n background: transparent;\n color: inherit;\n}\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-segment--editing\"]::-moz-selection {\n background: transparent;\n color: inherit;\n}\n\n/* Placeholder via ::before so it doesn't enter the editable DOM. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"][data-placeholder]::before {\n content: attr(data-placeholder);\n color: var(--aia-color-text-muted, #c1c4cb);\n opacity: 0.7;\n pointer-events: none;\n}\n\n/* Empty inline contentEditables have no inline box for the caret to render\n in. Switch to inline-block (min-width matches the caret line) when empty,\n so the caret stays visible while focused. */\n.AIAutocomplete-module_input_IW-P-[data-aia-empty=\"true\"] {\n display: inline-block;\n min-width: 1px;\n vertical-align: top;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA {\n display: inline;\n margin-left: 8px;\n}\n\n.AIAutocomplete-module_pillListContainer_h92IA:empty,\n.AIAutocomplete-module_pillListContainer_h92IA[data-aia-pill-wrapped] {\n margin-left: 0;\n}\n\n.AIAutocomplete-module_submitButton_sl1Mi {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--aia-submit-bg, var(--aia-color-text-default, #fff));\n color: var(--aia-submit-color, var(--aia-color-bg-default, #000));\n cursor: pointer;\n display: flex;\n align-items: center;\n justify-content: center;\n padding: 0;\n transition: opacity 0.2s ease;\n}\n\n.AIAutocomplete-module_submitButton_sl1Mi:hover {\n opacity: 0.85;\n}\n\n.AIAutocomplete-module_submitSlot_GhuCM {\n display: contents;\n}\n\n/* Text shimmer on a newly promoted completed param. The shared renderer\n (core/render/renderEditable.ts) stamps the global class names below onto\n the just-added <strong>; we match them via [class~=] to bypass CSS Modules'\n hashing — same trick as the editing-outline rule above. */\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-shimmer-revealed\"] {\n color: transparent;\n background: linear-gradient(\n 120deg,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 0%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 44%,\n #b0b0b0 48%,\n #b0b0b0 52%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 56%,\n var(--aia-written-text-color, var(--aia-color-text-default, #fff)) 100%\n );\n background-size: 200% 100%;\n -webkit-background-clip: text;\n background-clip: text;\n}\n\n:where(.AIAutocomplete-module_input_IW-P-) strong[class~=\"magicx-aia-shimmer-sweep\"] {\n animation: AIAutocomplete-module_textShimmer_eCLdq 650ms ease-out forwards;\n}\n\n@keyframes AIAutocomplete-module_textShimmer_eCLdq {\n 0% {\n background-position: 100% 0;\n }\n 100% {\n background-position: -50% 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"container\":\"AIAutocomplete-module_container_KKjFU\",\"inputWrapper\":\"AIAutocomplete-module_inputWrapper_FLq1b\",\"editorArea\":\"AIAutocomplete-module_editorArea_7rBWq\",\"input\":\"AIAutocomplete-module_input_IW-P-\",\"pillListContainer\":\"AIAutocomplete-module_pillListContainer_h92IA\",\"submitButton\":\"AIAutocomplete-module_submitButton_sl1Mi\",\"submitSlot\":\"AIAutocomplete-module_submitSlot_GhuCM\",\"textShimmer\":\"AIAutocomplete-module_textShimmer_eCLdq\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-2eef895d\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-2eef895d\";\n s.textContent = `.AIAutocompleteDropdown-module_dropdown_yz2KC {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n max-width: 516px;\n margin-top: 6px;\n display: flex;\n flex-direction: column;\n overflow: hidden;\n container-type: inline-size;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset, /* same color as bg */\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset, /* same color as bg */\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n border-radius: 28px;\n}\n\n.AIAutocompleteDropdown-module_visible_QCoXj {\n opacity: 1;\n pointer-events: auto;\n}\n\n.AIAutocompleteDropdown-module_pillBar_pwTXe {\n padding: 27px 27px 0px 27px;\n overflow-x: auto;\n overflow-y: hidden;\n scrollbar-width: none;\n mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n -webkit-mask-image: linear-gradient(to right, #000 0, #000 calc(100% - 48px), transparent 100%);\n}\n\n.AIAutocompleteDropdown-module_pillBar_pwTXe::-webkit-scrollbar {\n display: none;\n}\n\n/* --- Fallback loading skeleton (only when no pills/options are cached) --- */\n.AIAutocompleteDropdown-module_skeletonBars_HVr9C {\n display: flex;\n flex-direction: column;\n gap: 20px;\n padding: 25px;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx {\n display: block;\n height: 19px;\n border-radius: 999px;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n opacity: 0.5;\n animation: AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q 1.4s ease-in-out infinite;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(2) {\n animation-delay: 150ms;\n}\n\n.AIAutocompleteDropdown-module_skeletonBar_O3xIx:nth-child(3) {\n animation-delay: 300ms;\n}\n\n@keyframes AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q {\n 0%,\n 100% {\n opacity: 0.5;\n }\n 50% {\n opacity: 0.25;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"dropdown\":\"AIAutocompleteDropdown-module_dropdown_yz2KC\",\"visible\":\"AIAutocompleteDropdown-module_visible_QCoXj\",\"pillBar\":\"AIAutocompleteDropdown-module_pillBar_pwTXe\",\"skeletonBars\":\"AIAutocompleteDropdown-module_skeletonBars_HVr9C\",\"skeletonBar\":\"AIAutocompleteDropdown-module_skeletonBar_O3xIx\",\"aiaSkeletonPulse\":\"AIAutocompleteDropdown-module_aiaSkeletonPulse_G8W7q\"};","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-b745b4fb\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-b745b4fb\";\n s.textContent = `.PillList-module_list_qvLqO {\n position: relative;\n z-index: 1;\n pointer-events: auto;\n display: inline-flex;\n gap: 5px;\n align-items: center;\n vertical-align: middle;\n transform: translateY(-3px);\n}\n\n.PillList-module_pill_osSyz {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 13px 13px;\n border: none;\n border-radius: 999px;\n background: rgba(49, 50, 85, 0.25);\n background: color-mix(\n in srgb,\n var(--aia-pill-bg, var(--aia-color-background-supportive, #313255)) 25%,\n transparent\n );\n color: var(--aia-pill-color, var(--aia-color-text-muted, #c1c4cb));\n font-family: inherit;\n font-size: var(--aia-pill-font-size, 19px);\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: PillList-module_fadeIn_Aezob 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n box-shadow:\n hsla(0, 0%, 100%, 1) -3.2px -3.2px 3.2px -3.2px inset,\n hsla(0, 0%, 100%, 1) 6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) -6.4px 6.4px 1.6px -8px inset,\n var(--aia-dropdown-bg, transparent) 6.4px -6.4px 1.6px -8px inset,\n hsla(0, 0%, 100%, 0.15) -1.6px 0px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.15) 0px -1.6px 0px -1.6px inset,\n hsla(0, 0%, 100%, 0.3) 0px 1.6px 0px 0px inset,\n hsla(0, 0%, 100%, 0.3) 1.6px 0px 0px 0px inset,\n inset 0 0 30px 5px hsla(0, 0%, 0%, 0.05),\n hsla(0, 0%, 0%, 0.08) 0px 0px 30px 2px;\n backdrop-filter: blur(30px);\n}\n\n.PillList-module_rounded_WvXy4 {\n border-radius: 999px;\n}\n\n/* Loading skeleton — preserves the pill's exact box (same width and height)\n and just hides the text. The pill's native background acts as the visible\n shape; the pulse provides the shimmer. */\n.PillList-module_skeleton_Lp8x6 {\n pointer-events: none;\n cursor: default;\n color: transparent;\n animation: PillList-module_skeletonPulse_xZ8Yf 1.4s ease-in-out infinite;\n}\n\n@keyframes PillList-module_skeletonPulse_xZ8Yf {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n\n.PillList-module_pill_osSyz:hover {\n filter: brightness(1.2);\n}\n\n.PillList-module_active_Oll-- {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes PillList-module_fadeIn_Aezob {\n from {\n opacity: 0;\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"list\":\"PillList-module_list_qvLqO\",\"pill\":\"PillList-module_pill_osSyz\",\"fadeIn\":\"PillList-module_fadeIn_Aezob\",\"rounded\":\"PillList-module_rounded_WvXy4\",\"skeleton\":\"PillList-module_skeleton_Lp8x6\",\"skeletonPulse\":\"PillList-module_skeletonPulse_xZ8Yf\",\"active\":\"PillList-module_active_Oll--\"};","import type { Suggestion } from \"../types\";\nimport styles from \"./PillList.module.css\";\n\ninterface PillListProps {\n pills: Suggestion[];\n activePillIndex: number;\n onSelectPill: (index: number) => void;\n /** Use capsule-shaped pills (fully rounded). Default: false. */\n rounded?: boolean;\n /**\n * When true, the rendered pills become non-interactive shimmering skeletons.\n * Real pills (with their text) are rendered when provided so widths/positions\n * match the previous state; when `pills` is empty, fixed-width fallback\n * placeholders are rendered instead.\n */\n loading?: boolean;\n}\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function PillList({\n pills,\n activePillIndex,\n onSelectPill,\n rounded,\n loading,\n}: PillListProps) {\n if (loading && pills.length === 0) {\n return (\n <span className={styles.list} data-aia-pill-list-loading=\"\">\n {FALLBACK_SKELETON_WIDTHS.map((w, i) => (\n <span\n key={`skel-${w}`}\n data-aia-pill-skeleton=\"\"\n className={`${styles.pill} ${rounded ? styles.rounded : \"\"} ${styles.skeleton}`}\n style={{ width: w, opacity: getPillOpacity(i) }}\n />\n ))}\n </span>\n );\n }\n\n return (\n <span className={styles.list} data-aia-pill-list-loading={loading ? \"\" : undefined}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n data-aia-pill=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n tabIndex={-1}\n contentEditable={false}\n suppressContentEditableWarning\n className={`${styles.pill} ${rounded ? styles.rounded : \"\"} ${i === activePillIndex && !loading ? styles.active : \"\"} ${loading ? styles.skeleton : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onMouseDown={(e) => e.preventDefault()}\n onClick={loading ? undefined : () => onSelectPill(i)}\n disabled={loading}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionGrid.module.css\";\nimport { SuggestionItem } from \"./SuggestionItem\";\n\ninterface SuggestionGridProps {\n options: SuggestionOption[];\n activeIndex: number;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n listboxId: string;\n loading?: boolean;\n}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n loading,\n}: SuggestionGridProps) {\n const gridRef = useRef<HTMLDivElement>(null);\n const [hasBottomOverflow, setHasBottomOverflow] = useState(false);\n\n useEffect(() => {\n const el = gridRef.current;\n if (!el) return;\n\n const update = () => {\n setHasBottomOverflow(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n };\n\n el.addEventListener(\"scroll\", update, { passive: true });\n const resizeObserver = new ResizeObserver(update);\n resizeObserver.observe(el);\n\n return () => {\n el.removeEventListener(\"scroll\", update);\n resizeObserver.disconnect();\n };\n }, []);\n\n // Re-measure synchronously when the option list changes. ResizeObserver\n // misses this case (the grid hits max-height, so scrollHeight grows but the\n // observed box doesn't) and useEffect would leave a frame of stale fade.\n // biome-ignore lint/correctness/useExhaustiveDependencies: options is a trigger-only dep\n useLayoutEffect(() => {\n const el = gridRef.current;\n if (!el) return;\n setHasBottomOverflow(el.scrollHeight - el.scrollTop - el.clientHeight > 1);\n }, [options]);\n\n return (\n <div className={styles.scrollWrapper} data-fade={hasBottomOverflow ? \"\" : undefined}>\n <div ref={gridRef} className={styles.grid}>\n {options.map((option, i) => (\n <SuggestionItem\n key={option.text}\n option={option}\n isHighlighted={i === activeIndex}\n onSelect={onSelect}\n onHighlight={() => onHighlight(i)}\n id={`${listboxId}-option-${i}`}\n loading={loading}\n />\n ))}\n </div>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-d91f2b06\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-d91f2b06\";\n s.textContent = `.SuggestionGrid-module_scrollWrapper_MOqfw {\n position: relative;\n}\n\n.SuggestionGrid-module_scrollWrapper_MOqfw::after {\n content: \"\";\n position: absolute;\n left: 0;\n right: 0;\n bottom: 0;\n height: 50%;\n pointer-events: none;\n opacity: 0;\n transition: opacity 150ms ease-out;\n backdrop-filter: blur(12px);\n mask-image: linear-gradient(to bottom, transparent, white);\n}\n\n.SuggestionGrid-module_scrollWrapper_MOqfw[data-fade]::after {\n opacity: 1;\n}\n\n.SuggestionGrid-module_grid_jvaPb {\n display: grid;\n grid-template-columns: minmax(0, 250px);\n /* Pack rows from the top instead of stretching to fill the grid container. */\n grid-auto-rows: min-content;\n align-content: start;\n max-width: 100cqi;\n padding: 8px 8px;\n max-height: 200px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3)) transparent;\n}\n\n@container (min-width: 516px) {\n .SuggestionGrid-module_grid_jvaPb {\n grid-template-columns: repeat(2, minmax(0, 250px));\n justify-content: start;\n }\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar {\n width: 6px;\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.SuggestionGrid-module_grid_jvaPb::-webkit-scrollbar-thumb {\n background: var(--aia-scrollbar-thumb, rgba(0, 0, 0, 0.3));\n border-radius: 3px;\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"scrollWrapper\":\"SuggestionGrid-module_scrollWrapper_MOqfw\",\"grid\":\"SuggestionGrid-module_grid_jvaPb\"};","import { useEffect, useRef, useState } from \"react\";\nimport type { SuggestionOption } from \"../types\";\nimport styles from \"./SuggestionItem.module.css\";\n\ninterface SuggestionItemProps {\n option: SuggestionOption;\n isHighlighted: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: () => void;\n id: string;\n loading?: boolean;\n}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n loading,\n}: SuggestionItemProps) {\n const [pressed, setPressed] = useState(false);\n const timerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n return () => clearTimeout(timerRef.current);\n }, []);\n\n const handleSelect = () => {\n if (loading || !option.is_tappable || pressed) return;\n setPressed(true);\n onSelect(option);\n clearTimeout(timerRef.current);\n timerRef.current = setTimeout(() => setPressed(false), 500);\n };\n\n const className = [\n styles.item,\n isHighlighted && !loading ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n pressed ? styles.pressed : \"\",\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n data-aia-option=\"\"\n data-aia-loading={loading ? \"\" : undefined}\n aria-selected={isHighlighted}\n className={className}\n tabIndex={loading || !option.is_tappable ? -1 : 0}\n onClick={handleSelect}\n onKeyDown={(e) => {\n if (!loading && option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n handleSelect();\n }\n }}\n onMouseEnter={!loading && option.is_tappable ? onHighlight : undefined}\n >\n <div className={styles.streaks} />\n <div className={styles.streaksVert} />\n <span className={styles.content}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </span>\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-f6bdc634\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-f6bdc634\";\n s.textContent = `.SuggestionItem-module_item_d4vpD {\n position: relative;\n overflow: visible;\n display: flex;\n /* Top-align so single-line and multi-line options in the same row share\n the same baseline at the top edge of the cell. */\n align-items: flex-start;\n font-family: inherit;\n font-size: var(--aia-option-font-size, 19px);\n line-height: 24px;\n color: var(--aia-option-color, var(--aia-color-text-muted, #c1c4cb));\n white-space: normal;\n word-break: break-word;\n opacity: 0.4;\n border-radius: 12px;\n padding: 13px 13px;\n animation: SuggestionItem-module_fadeIn_I8u35 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes SuggestionItem-module_fadeIn_I8u35 {\n from {\n opacity: 0;\n }\n}\n\n.SuggestionItem-module_content_T-Qba {\n position: relative;\n z-index: 2;\n}\n\n.SuggestionItem-module_tappable_70KcX {\n cursor: pointer;\n}\n\n.SuggestionItem-module_tappable_70KcX:hover {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n}\n\n.SuggestionItem-module_nonTappable_xSZM- {\n cursor: default;\n opacity: 0.3;\n}\n\n.SuggestionItem-module_highlighted_Hb0SU {\n color: var(--aia-option-color-selected, var(--aia-color-text-default, #fff));\n background: var(--aia-option-bg, transparent);\n opacity: 0.5;\n}\n\n.SuggestionItem-module_tag_e3Fwe {\n font-size: 11px;\n margin-left: 6px;\n opacity: 0.5;\n}\n\n.SuggestionItem-module_pressed_98o-r {\n opacity: 0.8;\n color: var(--aia-color-text-default, #fff);\n background: rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n animation:\n SuggestionItem-module_glassFade_oyiSj 500ms ease forwards,\n SuggestionItem-module_tapDown_G3WGz 500ms ease forwards;\n}\n\n@keyframes SuggestionItem-module_tapDown_G3WGz {\n 0% {\n transform: scale(1);\n }\n 30% {\n transform: scale(0.97);\n }\n 100% {\n transform: scale(1);\n }\n}\n\n@keyframes SuggestionItem-module_glassFade_oyiSj {\n 0% {\n background: var(--aia-streak-glass-bg, rgba(255, 255, 255, 0.1));\n }\n 100% {\n background: transparent;\n }\n}\n\n/* Border streaks — horizontal segments */\n\n.SuggestionItem-module_streaks_d9PEB {\n position: absolute;\n inset: 0;\n z-index: 1;\n pointer-events: none;\n border-radius: inherit;\n overflow: hidden;\n}\n\n/* Bottom horizontal: 40% from right → right corner */\n.SuggestionItem-module_streaks_d9PEB::before {\n content: \"\";\n position: absolute;\n bottom: -3px;\n left: 60%;\n width: 0;\n height: 6px;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.5) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Top horizontal: 40% from left → left corner */\n.SuggestionItem-module_streaks_d9PEB::after {\n content: \"\";\n position: absolute;\n top: -3px;\n right: 60%;\n width: 0;\n height: 6px;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.5) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.2);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Border streaks — vertical segments */\n\n.SuggestionItem-module_streaksVert_ERlV1 {\n position: absolute;\n inset: 0;\n z-index: 1;\n pointer-events: none;\n border-radius: inherit;\n overflow: hidden;\n}\n\n/* Right vertical: bottom-right corner → up */\n.SuggestionItem-module_streaksVert_ERlV1::before {\n content: \"\";\n position: absolute;\n bottom: 0;\n right: -3px;\n width: 6px;\n height: 0;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.4) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n/* Left vertical: top-left corner → down */\n.SuggestionItem-module_streaksVert_ERlV1::after {\n content: \"\";\n position: absolute;\n top: 0;\n left: -3px;\n width: 6px;\n height: 0;\n opacity: 0;\n background: radial-gradient(\n ellipse at center,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.4) 0%,\n rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15) 40%,\n transparent 70%\n );\n box-shadow: 0 0 12px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.15);\n filter: blur(1px);\n border-radius: 50%;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaks_d9PEB::before {\n animation: SuggestionItem-module_streakHorizRight_aboGz 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaks_d9PEB::after {\n animation: SuggestionItem-module_streakHorizLeft_BreWJ 500ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaksVert_ERlV1::before {\n animation: SuggestionItem-module_streakVertUp_to1GD 300ms cubic-bezier(0.3, 0, 0.2, 1) 200ms forwards;\n}\n\n.SuggestionItem-module_pressed_98o-r .SuggestionItem-module_streaksVert_ERlV1::after {\n animation: SuggestionItem-module_streakVertDown_OrcLh 300ms cubic-bezier(0.3, 0, 0.2, 1) 200ms forwards;\n}\n\n/* Horizontal: bottom center-ish → right edge */\n@keyframes SuggestionItem-module_streakHorizRight_aboGz {\n 0% {\n width: 0;\n height: 4px;\n opacity: 0;\n filter: blur(1px);\n box-shadow: 0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 15% {\n height: 4px;\n opacity: 1;\n filter: blur(1px);\n box-shadow: 0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 80% {\n width: 50%;\n height: 10px;\n opacity: 0.8;\n filter: blur(3px);\n box-shadow: 0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.1);\n }\n 100% {\n width: 50%;\n height: 12px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.03);\n }\n}\n\n/* Horizontal: top center-ish → left edge */\n@keyframes SuggestionItem-module_streakHorizLeft_BreWJ {\n 0% {\n width: 0;\n height: 4px;\n opacity: 0;\n filter: blur(1px);\n box-shadow: 0 0 8px 3px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 15% {\n height: 4px;\n opacity: 1;\n filter: blur(1px);\n box-shadow: 0 0 10px 4px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.3);\n }\n 80% {\n width: 50%;\n height: 10px;\n opacity: 0.8;\n filter: blur(3px);\n box-shadow: 0 0 16px 6px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.1);\n }\n 100% {\n width: 50%;\n height: 12px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 20px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.03);\n }\n}\n\n/* Vertical segments start matching horizontal state at 200ms handoff */\n@keyframes SuggestionItem-module_streakVertUp_to1GD {\n 0% {\n height: 0;\n width: 6px;\n opacity: 0.9;\n filter: blur(1.8px);\n box-shadow: 0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.25);\n }\n 75% {\n height: 100%;\n width: 10px;\n opacity: 0.4;\n filter: blur(3px);\n box-shadow: 0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n }\n 100% {\n height: 100%;\n width: 14px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.02);\n }\n}\n\n@keyframes SuggestionItem-module_streakVertDown_OrcLh {\n 0% {\n height: 0;\n width: 6px;\n opacity: 0.9;\n filter: blur(1.8px);\n box-shadow: 0 0 12px 5px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.25);\n }\n 75% {\n height: 100%;\n width: 10px;\n opacity: 0.4;\n filter: blur(3px);\n box-shadow: 0 0 18px 8px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.06);\n }\n 100% {\n height: 100%;\n width: 14px;\n opacity: 0;\n filter: blur(5px);\n box-shadow: 0 0 24px 10px rgba(var(--aia-streak-rgb, 255, 255, 255), 0.02);\n }\n}\n\n/* Loading state — preserve the row's exact dimensions. The content stays an\n inline span so the line box and padding match the non-loading state byte\n for byte. Just hide the text and apply a background as a skeleton bar; the\n pulse provides the shimmer. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] {\n cursor: default;\n animation: SuggestionItem-module_skeletonPulse_plvdD 1.4s ease-in-out infinite;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_content_T-Qba {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n border-radius: 999px;\n}\n\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_tag_e3Fwe {\n display: none;\n}\n\n@keyframes SuggestionItem-module_skeletonPulse_plvdD {\n 0%,\n 100% {\n filter: brightness(1);\n }\n 50% {\n filter: brightness(0.55);\n }\n}\n`;\n document.head.appendChild(s);\n}\nexport default {\"item\":\"SuggestionItem-module_item_d4vpD\",\"fadeIn\":\"SuggestionItem-module_fadeIn_I8u35\",\"content\":\"SuggestionItem-module_content_T-Qba\",\"tappable\":\"SuggestionItem-module_tappable_70KcX\",\"nonTappable\":\"SuggestionItem-module_nonTappable_xSZM-\",\"highlighted\":\"SuggestionItem-module_highlighted_Hb0SU\",\"tag\":\"SuggestionItem-module_tag_e3Fwe\",\"pressed\":\"SuggestionItem-module_pressed_98o-r\",\"glassFade\":\"SuggestionItem-module_glassFade_oyiSj\",\"tapDown\":\"SuggestionItem-module_tapDown_G3WGz\",\"streaks\":\"SuggestionItem-module_streaks_d9PEB\",\"streaksVert\":\"SuggestionItem-module_streaksVert_ERlV1\",\"streakHorizRight\":\"SuggestionItem-module_streakHorizRight_aboGz\",\"streakHorizLeft\":\"SuggestionItem-module_streakHorizLeft_BreWJ\",\"streakVertUp\":\"SuggestionItem-module_streakVertUp_to1GD\",\"streakVertDown\":\"SuggestionItem-module_streakVertDown_OrcLh\",\"skeletonPulse\":\"SuggestionItem-module_skeletonPulse_plvdD\"};","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { PillList } from \"./components/PillList\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n pills,\n onPillClick,\n showPills = true,\n isLoading = false,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const options = activeSuggestion?.options ?? [];\n const showsPills = showPills && pills && pills.length > 0 && onPillClick;\n const showsOptions = options.length > 0;\n // Guarantee at least one option bar during loading — if the cached state\n // had no options, render the fallback skeleton bars regardless of whether\n // pills are present, so the dropdown never shows pills with an empty body.\n const showsFallbackSkeleton = isLoading && !showsOptions;\n const isVisible = isOpen && (showsOptions || showsPills || isLoading);\n\n return (\n <div\n id={id}\n role=\"listbox\"\n data-aia-dropdown=\"\"\n data-aia-loading={isLoading ? \"\" : undefined}\n className={`${styles.dropdown} ${isVisible ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {showPills && pills && pills.length > 0 && onPillClick && (\n <div className={styles.pillBar} data-aia-pillbar=\"\">\n <PillList\n pills={pills}\n activePillIndex={0}\n onSelectPill={onPillClick}\n rounded\n loading={isLoading}\n />\n </div>\n )}\n {showPills && (!pills || pills.length === 0) && isLoading && (\n <div className={styles.pillBar} data-aia-pillbar=\"\">\n <PillList pills={[]} activePillIndex={0} onSelectPill={() => {}} rounded loading />\n </div>\n )}\n {showsOptions && (\n <SuggestionGrid\n options={options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n loading={isLoading}\n />\n )}\n {showsFallbackSkeleton && (\n <div className={styles.skeletonBars} data-aia-skeleton-bars=\"\">\n {FALLBACK_SKELETON_BAR_WIDTHS.map((w) => (\n <span key={`bar-${w}`} className={styles.skeletonBar} style={{ width: w }} />\n ))}\n </div>\n )}\n </div>\n );\n}\n","if (typeof document !== \"undefined\" && !document.getElementById(\"ac-style-dc8da745\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-dc8da745\";\n s.textContent = `/*\n * Built-in appearance defaults — zero specificity via :where().\n * Consumer CSS always wins without !important.\n *\n * Resolution priority (highest wins):\n * 1. Consumer CSS targeting new vars (--aia-pill-bg, etc.)\n * 2. Consumer CSS targeting legacy vars (--aia-color-*, via fallback chain)\n * 3. These built-in defaults\n */\n\n/*\n * Library-scoped box-sizing reset. The SDK's pill / option / wrapper styles\n * mix explicit dimensions with padding (e.g. .magicx-aia-pill has height:36px\n * + padding:13px) and were authored assuming \\`border-box\\`. In consumer apps\n * without a global \\`* { box-sizing: border-box }\\` reset the pill rendered\n * ~62px tall instead of 36px. Scoping the reset to \\`.magicx-aia\\` descendants\n * keeps the library self-contained without leaking onto consumer markup.\n */\n:where(.magicx-aia, .magicx-aia *, .magicx-aia *::before, .magicx-aia *::after) {\n box-sizing: border-box;\n}\n\n/* Light mode defaults (base) */\n:where(.magicx-aia),\n:where(.magicx-aia[data-mode=\"light\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #000000;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #000000;\n --aia-option-color-selected: #000000;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #000000;\n --aia-written-text-font-size: 19px;\n --aia-caret-color: var(--aia-written-text-color, #000000);\n\n --aia-submit-bg: #000000;\n --aia-submit-color: #ffffff;\n\n --aia-color-text-muted: #6b7280;\n\n --aia-skeleton-bg: rgba(189, 189, 189, 0.51);\n\n --aia-streak-rgb: 99, 102, 241;\n --aia-streak-glass-bg: rgba(99, 102, 241, 0.1);\n}\n\n/* Dark mode defaults */\n:where(.magicx-aia[data-mode=\"dark\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #ffffff;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #ffffff;\n --aia-option-color-selected: #ffffff;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #ffffff;\n --aia-written-text-font-size: 19px;\n --aia-caret-color: var(--aia-written-text-color, #ffffff);\n\n --aia-submit-bg: #ffffff;\n --aia-submit-color: #000000;\n\n --aia-color-text-muted: #c1c4cb;\n\n --aia-skeleton-bg: #333539;\n\n --aia-streak-rgb: 255, 255, 255;\n --aia-streak-glass-bg: rgba(255, 255, 255, 0.1);\n}\n\n/* optionsPosition: dropdown above the input */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 6px;\n flex-direction: column-reverse;\n}\n\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-pillbar] {\n padding: 0 27px 27px 27px;\n}\n\n/* Disable all animations when data-animations=\"off\" */\n:where(.magicx-aia[data-animations=\"off\"]) *,\n:where(.magicx-aia[data-animations=\"off\"]) *::before,\n:where(.magicx-aia[data-animations=\"off\"]) *::after {\n animation-duration: 0s !important;\n transition-duration: 0s !important;\n}\n`;\n document.head.appendChild(s);\n}\nexport {};","/**\n * Plain-text caret utilities for contentEditable elements.\n *\n * Offsets are measured in plain-text characters that come from the editable\n * region only — subtrees inside `[contenteditable=\"false\"]` (e.g. pills)\n * contribute zero characters. Callers can think in string offsets without\n * touching DOM Ranges directly.\n */\n\nconst NON_EDITABLE_SELECTOR = '[contenteditable=\"false\"]';\n\ninterface GraphemeSegmenter {\n segment(input: string): Iterable<{ index: number; segment: string }>;\n}\n\nlet segmenter: GraphemeSegmenter | null | undefined;\nfunction getGraphemeSegmenter(): GraphemeSegmenter | null {\n if (segmenter !== undefined) return segmenter;\n // Intl.Segmenter is ES2022; lib target is ES2020. Access via globalThis to\n // avoid a hard compile dependency on the newer lib.\n const Segmenter = (globalThis as { Intl: typeof Intl & { Segmenter?: unknown } }).Intl\n .Segmenter as undefined | (new (locale?: string, options?: object) => GraphemeSegmenter);\n if (!Segmenter) {\n segmenter = null;\n return null;\n }\n try {\n segmenter = new Segmenter(undefined, { granularity: \"grapheme\" });\n } catch {\n segmenter = null;\n }\n return segmenter ?? null;\n}\n\nfunction isInsideNonEditable(node: Node, root: HTMLElement): boolean {\n let n: Node | null = node;\n while (n && n !== root) {\n if (n.nodeType === Node.ELEMENT_NODE) {\n const el = n as HTMLElement;\n if (el.matches(NON_EDITABLE_SELECTOR)) return true;\n }\n n = n.parentNode;\n }\n return false;\n}\n\nfunction createTextWalker(root: HTMLElement): TreeWalker {\n return (root.ownerDocument ?? document).createTreeWalker(root, NodeFilter.SHOW_TEXT, {\n acceptNode(node) {\n return isInsideNonEditable(node, root) ? NodeFilter.FILTER_REJECT : NodeFilter.FILTER_ACCEPT;\n },\n });\n}\n\nexport function extractPlainText(root: HTMLElement): string {\n const walker = createTextWalker(root);\n let out = \"\";\n let node = walker.nextNode() as Text | null;\n while (node) {\n out += node.data;\n node = walker.nextNode() as Text | null;\n }\n return out;\n}\n\nexport function plainTextLength(root: HTMLElement): number {\n const walker = createTextWalker(root);\n let total = 0;\n let node = walker.nextNode() as Text | null;\n while (node) {\n total += node.data.length;\n node = walker.nextNode() as Text | null;\n }\n return total;\n}\n\n/**\n * Read the current caret offset (in plain-text characters) within `root`.\n * Returns null when no selection is anchored inside `root`.\n */\nexport function getCursorOffset(root: HTMLElement): number | null {\n const sel = (root.ownerDocument ?? document).getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const anchorNode = sel.anchorNode;\n const anchorOffset = sel.anchorOffset;\n if (!anchorNode || !root.contains(anchorNode)) return null;\n\n // When the anchor is the editable itself (or an element child), interpret\n // anchorOffset as a child index and sum text lengths up to that child.\n if (anchorNode.nodeType === Node.ELEMENT_NODE) {\n const el = anchorNode as Element;\n if (isInsideNonEditable(el, root) && el !== root) return null;\n let offset = 0;\n for (let i = 0; i < anchorOffset && i < el.childNodes.length; i++) {\n offset += plainTextLengthOfSubtree(el.childNodes[i], root);\n }\n // Add lengths of previous siblings + ancestors up to root.\n return offset + offsetBeforeNode(el, root);\n }\n\n if (anchorNode.nodeType !== Node.TEXT_NODE) return null;\n if (isInsideNonEditable(anchorNode, root)) return null;\n\n return offsetBeforeNode(anchorNode, root) + anchorOffset;\n}\n\nfunction plainTextLengthOfSubtree(node: Node, root: HTMLElement): number {\n if (node.nodeType === Node.TEXT_NODE) {\n return isInsideNonEditable(node, root) ? 0 : (node as Text).data.length;\n }\n if (node.nodeType !== Node.ELEMENT_NODE) return 0;\n const el = node as HTMLElement;\n if (el.matches(NON_EDITABLE_SELECTOR)) return 0;\n let total = 0;\n for (const child of Array.from(el.childNodes)) {\n total += plainTextLengthOfSubtree(child, root);\n }\n return total;\n}\n\nfunction offsetBeforeNode(target: Node, root: HTMLElement): number {\n const walker = createTextWalker(root);\n let total = 0;\n let node = walker.nextNode() as Text | null;\n while (node) {\n if (node === target) return total;\n // If target is an ancestor element of this text node, we've already passed it.\n if (target.nodeType === Node.ELEMENT_NODE && (target as Element).contains(node)) {\n return total;\n }\n total += node.data.length;\n node = walker.nextNode() as Text | null;\n }\n return total;\n}\n\n/**\n * Set the caret at the given plain-text offset within `root`.\n *\n * Boundary policy: when the offset falls at the seam between text nodes, the\n * caret is placed at the START of the *following* text node so newly typed\n * characters do not inherit a preceding `<strong>`'s bold styling. When the\n * caret would land at the trailing edge of a text node inside a `<strong>`\n * with no following text node, we use `setStartAfter(strong)` so the caret\n * sits OUTSIDE the bold subtree — otherwise a caret at the end of a strong's\n * text is still \"inside\" the strong, which would falsely trigger re-edit mode.\n */\nexport function setCursorOffset(root: HTMLElement, offset: number): void {\n const doc = root.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel) return;\n\n const clamped = Math.max(0, Math.min(offset, plainTextLength(root)));\n const walker = createTextWalker(root);\n let cumulative = 0;\n let target: Text | null = null;\n let targetOffset = 0;\n let node = walker.nextNode() as Text | null;\n let lastNode: Text | null = null;\n\n while (node) {\n const len = node.data.length;\n if (clamped < cumulative + len) {\n target = node;\n targetOffset = clamped - cumulative;\n break;\n }\n if (clamped === cumulative + len) {\n const next = walker.nextNode() as Text | null;\n if (next) {\n // Prefer the start of the following text node so the caret sits past\n // any preceding `<strong>` boundary.\n target = next;\n targetOffset = 0;\n } else {\n target = node;\n targetOffset = len;\n }\n break;\n }\n cumulative += len;\n lastNode = node;\n node = walker.nextNode() as Text | null;\n }\n\n const range = doc.createRange();\n if (target) {\n // Boundary policy: the caret must never land at the leading or trailing\n // edge of a `<strong>`'s text node — visually it sits AT the boundary\n // but the DOM anchor is still INSIDE the strong, which would falsely\n // trigger re-edit mode. Hop OUT of the strong at those boundaries.\n const strongParent = target.parentElement?.closest<HTMLElement>('strong[data-seg=\"completed\"]');\n if (strongParent && strongParent !== root && root.contains(strongParent)) {\n if (targetOffset === 0) {\n range.setStartBefore(strongParent);\n } else if (targetOffset === target.data.length) {\n range.setStartAfter(strongParent);\n } else {\n range.setStart(target, targetOffset);\n }\n } else {\n range.setStart(target, targetOffset);\n }\n } else if (lastNode) {\n range.setStart(lastNode, lastNode.data.length);\n } else {\n range.setStart(root, 0);\n }\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n}\n\n/**\n * True when the caret offset equals the editable's plain-text length —\n * meaning the only content to the right is non-editable (e.g. trailing pills).\n */\nexport function cursorIsAtEnd(root: HTMLElement): boolean {\n const offset = getCursorOffset(root);\n if (offset == null) return false;\n return offset >= plainTextLength(root);\n}\n\n/**\n * Step back one grapheme from a plain-text offset, falling back to one UTF-16\n * code unit when Intl.Segmenter is unavailable. Used by Backspace handling so\n * emoji and combining marks are deleted as a single user-perceived character.\n */\nexport function previousGraphemeBoundary(text: string, offset: number): number {\n if (offset <= 0) return 0;\n const seg = getGraphemeSegmenter();\n if (!seg) return offset - 1;\n const slice = text.slice(0, offset);\n let last = 0;\n for (const { index } of seg.segment(slice)) {\n if (index < offset) last = index;\n }\n return last;\n}\n","import {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport { AIAutocomplete as CoreAIAutocomplete } from \"../core/AIAutocomplete\";\nimport type { CoreState } from \"../core/types\";\nimport type {\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\n\n/**\n * Pre-mount / SSR fallback. Identical shape to the post-mount CoreState so\n * the hook's return is single-shaped — no `if (!instance) return ...` branch.\n * `isLoading: true` matches the historical SSR bail-out: consumers using\n * `isLoading` to render a skeleton see one on the first paint instead of a\n * flash of blank content while the mount effect creates the core instance.\n */\nconst EMPTY_STATE: CoreState = {\n text: \"\",\n completedParams: [],\n suggestions: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: true,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n placeholderText: \"\",\n isDropdownOpen: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: null,\n inSelectionAnimation: false,\n};\n\ninterface CoreActions {\n handleTextChange: (value: string) => void;\n handleKeyDown: (e: KeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n setFocused: (focused: boolean) => void;\n startEditingParam: (paramId: string) => void;\n exitEditMode: () => void;\n handleCaretAfterInput: (offset: number | null) => void;\n handleCaretMove: (offset: number | null) => void;\n replaceEditingRange: (replacement: string) => boolean;\n setActivePill: (index: number) => void;\n removeLastParam: () => void;\n clearNewParamId: () => void;\n reset: () => void;\n selectOption: (option: SuggestionOption) => void;\n setActiveDropdownIndex: (index: number) => void;\n handleFocus: () => void;\n handleBlur: () => void;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n apiConfig,\n columns = 2,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n onFocus,\n onBlur,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n source,\n setCursor,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n const instanceRef = useRef<CoreAIAutocomplete | null>(null);\n const [coreState, setCoreState] = useState<CoreState | null>(null);\n\n // Refs for caller-supplied callbacks. The CoreAIAutocomplete instance is\n // mount-only (created once); these refs let the stable proxy callbacks\n // inside it pick up the latest props on every render.\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const onFocusRef = useRef(onFocus);\n onFocusRef.current = onFocus;\n const onBlurRef = useRef(onBlur);\n onBlurRef.current = onBlur;\n const setCursorRef = useRef(setCursor);\n setCursorRef.current = setCursor;\n\n // Create, subscribe, and destroy the core instance in one mount-only effect.\n // Keeping creation out of render (and pairing it with the cleanup) is what\n // makes this StrictMode-safe — otherwise cleanup nulls the ref, render\n // re-creates, and the store subscription drives an infinite setState loop.\n // biome-ignore lint/correctness/useExhaustiveDependencies: initial-opts snapshot; later changes are synced by the update-effect below\n useEffect(() => {\n if (typeof document === \"undefined\") return;\n const instance = new CoreAIAutocomplete(document.createElement(\"div\"), {\n renderMode: \"headless\",\n apiConfig,\n optionOverrides,\n maskCompletedText,\n columns,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n source,\n value: controlledValue,\n completedParams: controlledParams,\n onSubmit: (...args) => onSubmitRef.current?.(...args),\n onError: (...args) => onErrorRef.current?.(...args),\n onChange: (...args) => onChangeRef.current?.(...args),\n onParamsChange: (...args) => onParamsChangeRef.current?.(...args),\n onFocus: () => onFocusRef.current?.(),\n onBlur: () => onBlurRef.current?.(),\n setCursor: (offset) => setCursorRef.current?.(offset),\n });\n instanceRef.current = instance;\n setCoreState(instance.getState());\n const unsub = instance.subscribe((state) => setCoreState(state));\n return () => {\n unsub();\n instance.destroy();\n if (instanceRef.current === instance) instanceRef.current = null;\n };\n }, []);\n\n // Sync controlled value\n useEffect(() => {\n if (controlledValue !== undefined) instanceRef.current?.setValue(controlledValue);\n }, [controlledValue]);\n\n // Sync controlled params\n useEffect(() => {\n if (controlledParams !== undefined) instanceRef.current?.setCompletedParams(controlledParams);\n }, [controlledParams]);\n\n // Sync apiConfig/optionOverrides/dropdownTrigger when values change\n const apiConfigJson = JSON.stringify(apiConfig ?? null);\n const prevOverridesRef = useRef(optionOverrides);\n const overridesVersion = useRef(0);\n if (optionOverrides !== prevOverridesRef.current) {\n const prev = prevOverridesRef.current;\n const next = optionOverrides;\n const prevKeys = Object.keys(prev ?? {});\n const nextKeys = Object.keys(next ?? {});\n if (\n prevKeys.length !== nextKeys.length ||\n nextKeys.some(\n (k) =>\n !(prev as Record<string, unknown>)?.[k] ||\n (next as Record<string, unknown>)[k] !== (prev as Record<string, unknown>)[k],\n )\n ) {\n overridesVersion.current++;\n }\n prevOverridesRef.current = optionOverrides;\n }\n // biome-ignore lint/correctness/useExhaustiveDependencies: overridesVersion tracks shallow changes to fn-valued optionOverrides\n useEffect(() => {\n instanceRef.current?.update({\n apiConfig,\n optionOverrides,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n });\n }, [\n apiConfigJson,\n overridesVersion.current,\n dropdownTrigger,\n closeDropdownOnBlur,\n showNonTappableOptions,\n ]);\n\n // Single stable action surface. Built once via the useRef-with-null-init\n // pattern (the idiomatic \"create once, never recreate\" idiom in React — see\n // https://react.dev/reference/react/useRef). Every entry forwards to the\n // current core instance via `instanceRef.current` so the closure picks up\n // the live instance even though the actions object itself never changes.\n const actionsRef = useRef<CoreActions | null>(null);\n if (actionsRef.current === null) {\n actionsRef.current = {\n handleTextChange: (value) => instanceRef.current?.handleTextChange(value),\n handleKeyDown: (e) => {\n const native = \"nativeEvent\" in e ? e.nativeEvent : e;\n instanceRef.current?.handleKeyDown(native);\n },\n setFocused: (focused) => instanceRef.current?.setFocused(focused),\n startEditingParam: (paramId) => instanceRef.current?.startEditingParam(paramId),\n exitEditMode: () => instanceRef.current?.exitEditMode(),\n handleCaretAfterInput: (offset) => instanceRef.current?.handleCaretAfterInput(offset),\n handleCaretMove: (offset) => instanceRef.current?.handleCaretMove(offset),\n replaceEditingRange: (replacement) =>\n instanceRef.current?.replaceEditingRange(replacement) ?? false,\n setActivePill: (index) => instanceRef.current?.setActivePill(index),\n removeLastParam: () => instanceRef.current?.removeLastParam(),\n clearNewParamId: () => instanceRef.current?.clearNewParamId(),\n reset: () => instanceRef.current?.reset(),\n selectOption: (option) => instanceRef.current?.selectOption(option),\n setActiveDropdownIndex: (index) => instanceRef.current?.setActiveDropdownIndex(index),\n handleFocus: () => instanceRef.current?.setFocused(true),\n handleBlur: () => instanceRef.current?.setFocused(false),\n };\n }\n const actions = actionsRef.current;\n\n // textarea-specific adapter — capitalizes the first character on first\n // keystroke. Kept separate from `actions.handleTextChange` because the\n // capitalization rule belongs to the textarea host, not the core.\n const handleChange = useCallback((e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const shouldCapitalize =\n raw.length > 0 &&\n !(e.nativeEvent as InputEvent)?.isComposing &&\n raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n instanceRef.current?.handleTextChange(newValue);\n }, []);\n\n const handleKeyDownTextarea = useCallback((e: KeyboardEvent<HTMLTextAreaElement>) => {\n instanceRef.current?.handleKeyDown(e.nativeEvent);\n }, []);\n\n // Snapshot the live instance + state for this render.\n const instance = instanceRef.current;\n const state = coreState ?? EMPTY_STATE;\n const text = controlledValue !== undefined ? controlledValue : state.text;\n const completedParams = controlledParams !== undefined ? controlledParams : state.completedParams;\n\n const actionableSuggestions = state.actionableSuggestions;\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const listboxId = instance?.listboxId ?? \"\";\n\n const activeDescendantId =\n state.activeDropdownIndex >= 0 && instance\n ? `${listboxId}-option-${state.activeDropdownIndex}`\n : undefined;\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata. The options grid\n // shows the cached options regardless of the latest server response.\n const editingParam = state.editingParam;\n const dropdownPill: Suggestion | null = editingParam\n ? {\n type: editingParam.suggestionType,\n text: editingParam.suggestionPlaceholder,\n required: true,\n options: editingParam.options,\n }\n : null;\n const dropdownActivePill = dropdownPill ?? activeSuggestion;\n const dropdownPills = dropdownPill ? [dropdownPill] : actionableSuggestions;\n\n // UI-visible loading — suppressed during the post-select streak animation\n // and during re-edit (cached options remain visible there). Pre-mount we\n // report loading=true so SSR / first-paint consumers render a skeleton\n // instead of a flash of blank content while the mount effect runs.\n const uiLoading =\n !instance || (state.isLoading && !state.editingParam && !state.inSelectionAnimation);\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: actions.setActivePill,\n removeLastParam: actions.removeLastParam,\n segments: state.segments,\n newParamId: state.newParamId,\n clearNewParamId: actions.clearNewParamId,\n suggestions: state.suggestions,\n activeIndex: state.activeDropdownIndex,\n isReady: state.isReady,\n isLoading: uiLoading,\n isFocused: state.isFocused,\n isDropdownOpen: state.isDropdownOpen,\n placeholderText: state.placeholderText,\n listboxId,\n error: state.error,\n handleTextChange: actions.handleTextChange,\n handleKeyDown: actions.handleKeyDown,\n setFocused: actions.setFocused,\n editingParam,\n editingAnchor: state.editingAnchor,\n caretOffset: state.caretOffset,\n startEditingParam: actions.startEditingParam,\n exitEditMode: actions.exitEditMode,\n handleCaretAfterInput: actions.handleCaretAfterInput,\n handleCaretMove: actions.handleCaretMove,\n replaceEditingRange: actions.replaceEditingRange,\n inputProps: {\n value: text,\n placeholder: state.placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDownTextarea,\n onFocus: actions.handleFocus,\n onBlur: actions.handleBlur,\n role: \"combobox\" as const,\n \"aria-expanded\": state.isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset: actions.reset,\n dropdownProps: {\n suggestions: dropdownActivePill\n ? [{ ...dropdownActivePill, options: state.filteredOptions }]\n : [],\n activeIndex: state.activeDropdownIndex,\n onSelect: actions.selectOption,\n onHighlight: actions.setActiveDropdownIndex,\n isOpen: state.isDropdownOpen,\n id: listboxId,\n pills: dropdownPills,\n onPillClick: actions.setActivePill,\n isLoading: uiLoading,\n },\n };\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Returns a filter base that respects the server-suggested placeholder. When\n * `filterBase` hasn't been set by a fetch yet (still 0) and `text` starts with\n * `placeholderText`, the placeholder occupies the same role as `filterBase` —\n * the user's filter query is whatever they typed past it. Returns `filterBase`\n * unchanged otherwise.\n */\nexport function effectiveFilterBase(\n text: string,\n filterBase: number,\n placeholderText: string,\n): number {\n if (filterBase > 0 || !placeholderText) return filterBase;\n if (text.toLowerCase().startsWith(placeholderText.toLowerCase())) {\n return placeholderText.length;\n }\n return filterBase;\n}\n\n/**\n * Extracts the effective filter query from the region after filterBase.\n * If the server marked the region as in_progress, the full region is used.\n * Otherwise, filtering only starts after the first space (to avoid filtering\n * mid-word when the user continues typing a word that was already in the input).\n */\nexport function extractFilterQuery(\n text: string,\n filterBase: number,\n isInProgress: boolean,\n): string {\n const rawRegion = text.slice(filterBase);\n if (isInProgress || filterBase === 0 || text[filterBase - 1] === \" \") {\n return rawRegion;\n }\n const spaceIdx = rawRegion.indexOf(\" \");\n return spaceIdx === -1 ? \"\" : rawRegion.slice(spaceIdx + 1);\n}\n\n/**\n * Finds the longest word-boundary-aligned suffix of `prefix` that matches a\n * prefix of `optionText` (case-insensitive). Returns the number of characters\n * to remove from the end of `prefix` to avoid duplication.\n */\nexport function findPrefixOverlap(prefix: string, optionText: string): number {\n // Normalize internal whitespace so words.join(\" \") roundtrips losslessly\n const trimmed = prefix.trimEnd().replace(/\\s+/g, \" \");\n if (trimmed.length === 0 || optionText.length === 0) return 0;\n\n const words = trimmed.split(\" \");\n const optionLower = optionText.toLowerCase();\n\n // Try from longest suffix (all words) to shortest (last word only)\n for (let i = 0; i < words.length; i++) {\n const candidate = words.slice(i).join(\" \");\n if (optionLower.startsWith(candidate.toLowerCase())) {\n const suffixStart = trimmed.length - candidate.length;\n return prefix.length - suffixStart;\n }\n }\n\n return 0;\n}\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption[] {\n if (!options) return [];\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption | null {\n if (!options) return null;\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { AppearanceMode } from \"../types\";\n\nexport class ModeController {\n private mediaQuery: MediaQueryList | null = null;\n\n constructor(\n private container: HTMLElement,\n private mode: AppearanceMode = \"auto\",\n ) {\n this.apply();\n }\n\n setMode(mode: AppearanceMode) {\n this.detachListener();\n this.mode = mode;\n this.apply();\n }\n\n destroy() {\n this.detachListener();\n }\n\n private apply() {\n if (this.mode === \"auto\") {\n this.mediaQuery ??= window.matchMedia(\"(prefers-color-scheme: dark)\");\n this.mediaQuery.addEventListener(\"change\", this.onSystemChange);\n this.container.dataset.mode = this.mediaQuery.matches ? \"dark\" : \"light\";\n } else {\n this.container.dataset.mode = this.mode;\n }\n }\n\n private onSystemChange = (e: MediaQueryListEvent) => {\n this.container.dataset.mode = e.matches ? \"dark\" : \"light\";\n };\n\n private detachListener() {\n this.mediaQuery?.removeEventListener(\"change\", this.onSystemChange);\n }\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import type { AccessTokenConfig } from \"../types\";\n\n/** Refresh 30 seconds before stated expiry to absorb clock drift and request latency. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport class TokenManager {\n private current: string | null = null;\n private expiresAt: number | null = null;\n private inFlightRefresh: Promise<string> | null = null;\n\n constructor(private config: AccessTokenConfig) {\n if (config.accessToken) {\n this.current = config.accessToken;\n }\n }\n\n /** Returns a valid token, refreshing if needed. Single-flight: concurrent callers share one refresh. */\n async getToken(forceRefresh = false): Promise<string> {\n if (!forceRefresh && this.current && !this.isExpired()) {\n return this.current;\n }\n if (!forceRefresh && this.inFlightRefresh) {\n return this.inFlightRefresh;\n }\n this.inFlightRefresh = this.refresh();\n try {\n return await this.inFlightRefresh;\n } finally {\n this.inFlightRefresh = null;\n }\n }\n\n private async refresh(): Promise<string> {\n const result = await this.config.getAccessToken();\n this.current = result.accessToken;\n this.expiresAt = result.expiresAt ?? null;\n return this.current;\n }\n\n private isExpired(): boolean {\n if (this.expiresAt == null) return false;\n return Date.now() >= this.expiresAt - REFRESH_SKEW_MS;\n }\n}\n","import type { AccessTokenConfig, APIConfig, APIKeyConfig } from \"../types\";\nimport { TokenManager } from \"./tokenManager\";\n\n/** Default backend origin used when apiConfig.endpoint is not set. */\nexport const DEFAULT_API_ORIGIN = \"https://api.ai-autocomplete.com\";\nexport const DEFAULT_SUGGEST_ENDPOINT = `${DEFAULT_API_ORIGIN}/api/suggest`;\n\n// Keyed by getAccessToken function reference (stable across React re-renders)\nconst tokenManagers = new WeakMap<AccessTokenConfig[\"getAccessToken\"], TokenManager>();\n\nexport function isAccessTokenConfig(config?: APIConfig): config is AccessTokenConfig {\n return config?.type === \"accessToken\";\n}\n\nexport function getApiKeyConfig(config?: APIConfig): APIKeyConfig | undefined {\n if (!config || isAccessTokenConfig(config)) return undefined;\n return config;\n}\n\nexport function getTokenManager(config: AccessTokenConfig): TokenManager {\n let manager = tokenManagers.get(config.getAccessToken);\n if (!manager) {\n manager = new TokenManager(config);\n tokenManagers.set(config.getAccessToken, manager);\n }\n return manager;\n}\n\n/**\n * Builds shared (non-auth) request headers used by every backend call.\n * Mirrors what /suggest sends so /api/telemetry/events sees the same envelope.\n */\nexport function buildHeaders(apiConfig?: APIConfig): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n ...(apiConfig?.appIdentifier && { \"X-App-Identifier\": apiConfig.appIdentifier }),\n ...apiConfig?.headers,\n };\n}\n\n/**\n * Returns the Authorization header value for an API-key config, or `null` if no\n * apiKey is set (matches /suggest's behavior of sending the request without an\n * Authorization header in that case — the warn lives in api.ts so it fires only\n * for the user-visible suggest call).\n */\nexport function buildApiKeyAuthHeader(apiConfig?: APIConfig): string | null {\n const apiKeyConfig = getApiKeyConfig(apiConfig);\n const apiKey = apiKeyConfig?.apiKey;\n if (!apiKey) return null;\n const scheme = apiKeyConfig?.authScheme ?? \"Bearer\";\n return scheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n}\n","import type { APIConfig } from \"../types\";\nimport {\n buildApiKeyAuthHeader,\n buildHeaders,\n DEFAULT_SUGGEST_ENDPOINT,\n getTokenManager,\n isAccessTokenConfig,\n} from \"./auth\";\n\nexport type TelemetrySource = \"full-sdk\" | \"headless-sdk\" | \"endpoint-direct\";\nexport type TelemetryType = \"pill\" | \"option\";\n\nexport interface TelemetryEvent {\n source: TelemetrySource;\n sessionId: string;\n type: TelemetryType;\n queryData: Record<string, unknown>;\n apiConfig?: APIConfig;\n}\n\n/**\n * Telemetry sits next to /suggest on the server, so we derive the URL by\n * rewriting the trailing `/suggest` segment. This preserves whatever origin\n * and path-prefix the consumer configured — including relative dev-proxy\n * paths like \"/api/suggest\" → \"/api/telemetry/events\" or \"/ac/api/suggest\" →\n * \"/ac/api/telemetry/events\".\n */\nfunction deriveTelemetryEndpoint(suggestEndpoint?: string): string {\n const base = suggestEndpoint ?? DEFAULT_SUGGEST_ENDPOINT;\n return base.replace(/\\/suggest(\\?|#|$)/, \"/telemetry/events$1\");\n}\n\n/**\n * Resolves Authorization header using the same logic as /suggest:\n * - accessToken mode → Bearer from TokenManager\n * - apiKey mode → Bearer/Basic from configured key\n * - neither → null (request is sent without an Authorization header, matching\n * /suggest's behavior)\n */\nasync function resolveAuthHeader(apiConfig?: APIConfig): Promise<string | null> {\n if (isAccessTokenConfig(apiConfig)) {\n const token = await getTokenManager(apiConfig).getToken();\n return `Bearer ${token}`;\n }\n return buildApiKeyAuthHeader(apiConfig);\n}\n\n/**\n * Fire-and-forget telemetry POST. Never throws; failures are swallowed so the\n * UI is never disrupted by analytics. Auth headers are constructed via the\n * same helpers used by /suggest, so credential resolution stays consistent\n * across endpoints.\n */\nexport async function sendTelemetry(event: TelemetryEvent): Promise<void> {\n try {\n const endpoint = deriveTelemetryEndpoint(event.apiConfig?.endpoint);\n const headers = buildHeaders(event.apiConfig);\n const authHeader = await resolveAuthHeader(event.apiConfig);\n if (authHeader) headers.Authorization = authHeader;\n\n const body = JSON.stringify({\n source: event.source,\n session_id: event.sessionId,\n type: event.type,\n at: new Date().toISOString(),\n query_data: event.queryData,\n });\n\n await fetch(endpoint, { method: \"POST\", headers, body });\n } catch {\n // best-effort\n }\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\nimport {\n buildApiKeyAuthHeader,\n buildHeaders,\n DEFAULT_SUGGEST_ENDPOINT,\n getTokenManager,\n isAccessTokenConfig,\n} from \"./auth\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\nlet hasWarnedMissingKey = false;\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nfunction buildRequestBody(\n rawQuery: string,\n completedParams: CompletedParamState[],\n includeText: boolean,\n sessionId: string,\n): AutocompleteRequest {\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n return {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n session_id: sessionId,\n },\n };\n}\n\nasync function doFetch(\n endpoint: string,\n headers: Record<string, string>,\n token: string,\n body: string,\n signal?: AbortSignal,\n): Promise<Response> {\n return fetch(endpoint, {\n method: \"POST\",\n headers: { ...headers, Authorization: `Bearer ${token}` },\n body,\n signal,\n });\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options: {\n sessionId: string;\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options.apiConfig;\n const includeText = !options.maskCompletedText;\n const body = buildRequestBody(rawQuery, completedParams, includeText, options.sessionId);\n const headers = buildHeaders(apiConfig);\n const endpoint = apiConfig?.endpoint ?? DEFAULT_SUGGEST_ENDPOINT;\n const jsonBody = JSON.stringify(body);\n\n // === Access token mode ===\n if (isAccessTokenConfig(apiConfig)) {\n const manager = getTokenManager(apiConfig);\n const token = await manager.getToken();\n\n let response = await doFetch(endpoint, headers, token, jsonBody, options.signal);\n\n // 401 retry: force-refresh token and retry exactly once\n if (response.status === 401) {\n const newToken = await manager.getToken(true);\n response = await doFetch(endpoint, headers, newToken, jsonBody, options.signal);\n }\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n }\n\n // === API key mode (default) ===\n const authHeader = buildApiKeyAuthHeader(apiConfig);\n if (!authHeader && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No apiKey in apiConfig. Requests will be sent without an Authorization header.\",\n );\n }\n if (authHeader) headers.Authorization = authHeader;\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: jsonBody,\n signal: options.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../../types\";\nimport { fetchSuggestions } from \"../../utils/api\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport {\n effectiveFilterBase,\n extractFilterQuery,\n filterOptions,\n findExactMatch,\n} from \"../../utils/filtering\";\nimport { applyOptionOverrides } from \"../../utils/overrides\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\nexport interface FetchAutoMatchEvent {\n active: Suggestion;\n matched: SuggestionOption;\n rawQuery: string;\n}\n\nexport interface FetchControllerCallbacks {\n onAutoMatch?: (event: FetchAutoMatchEvent) => void;\n}\n\nexport class FetchController {\n private fetchVersion = 0;\n private abortController: AbortController | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private slowDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: (() => void) | null = null;\n\n constructor(\n private store: Store<CoreState>,\n private getApiConfig: () => APIConfig | undefined,\n private getOptionOverrides: () => OptionOverrides | undefined,\n private getMaskCompletedText: () => boolean | undefined,\n private getOnError: () => ((error: Error) => void) | undefined,\n private getSessionId: () => string,\n private callbacks: FetchControllerCallbacks = {},\n ) {}\n\n start() {\n // Initial fetch\n this.doFetch(\"\", []);\n\n // Subscribe to state changes for debounced fetching\n let prevText = this.store.get().text;\n let prevParams = this.store.get().completedParams;\n this.unsubscribe = this.store.subscribe((next) => {\n if (next.text !== prevText || next.completedParams !== prevParams) {\n prevText = next.text;\n prevParams = next.completedParams;\n this.scheduleFetch();\n }\n });\n }\n\n dispose() {\n this.abortController?.abort();\n this.clearTimers();\n this.unsubscribe?.();\n }\n\n async doFetch(rawQuery: string, completed: CompletedParamState[]) {\n this.abortController?.abort();\n const controller = new AbortController();\n this.abortController = controller;\n const version = ++this.fetchVersion;\n const textAtRequest = this.store.get().text.length;\n\n this.store.set({ isLoading: true, error: null });\n\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n sessionId: this.getSessionId(),\n maskCompletedText: this.getMaskCompletedText(),\n signal: controller.signal,\n apiConfig: this.getApiConfig(),\n });\n\n if (version !== this.fetchVersion) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n this.getOptionOverrides(),\n );\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = this.store.get().text;\n let filterBase: number;\n let filterInProgress: boolean;\n\n if (lastInput?.state === \"in_progress\") {\n filterInProgress = true;\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n filterBase = inProgressIdx !== -1 ? inProgressIdx : textAtRequest;\n } else {\n filterInProgress = false;\n filterBase = textAtRequest;\n }\n\n // Check if user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n let extraParam: CompletedParamState | null = null;\n if (active) {\n const query = extractFilterQuery(currentText, filterBase, filterInProgress);\n const match = findExactMatch(active.options, query);\n if (match) {\n extraParam = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n newSuggestions = newSuggestions.filter((s) => s !== active);\n this.callbacks.onAutoMatch?.({ active, matched: match, rawQuery });\n }\n }\n\n this.store.set((s) => ({\n suggestions: newSuggestions,\n isLoading: false,\n isReady: res.data.is_ready ?? false,\n lastRawQuery: rawQuery,\n activeDropdownIndex: -1,\n filterBase,\n filterInProgress,\n ...(extraParam ? { completedParams: [...s.completedParams, extraParam] } : {}),\n }));\n } catch (err) {\n if (version === this.fetchVersion) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n this.store.set({ error: caughtError, isLoading: false });\n this.getOnError()?.(caughtError);\n }\n }\n }\n\n private scheduleFetch() {\n this.clearTimers();\n const state = this.store.get();\n\n if (state.skipNextFetch) {\n this.store.set({ skipNextFetch: false });\n return;\n }\n\n const attemptFetch = (minDiff: number): boolean => {\n const s = this.store.get();\n if (!s.text && s.completedParams.length === 0) {\n this.doFetch(\"\", []);\n return true;\n }\n\n const placeholderText = s.suggestions\n .filter((sg: Suggestion) => sg.type === \"placeholder\")\n .map((sg: Suggestion) => sg.text)\n .join(\" \");\n const effBase = effectiveFilterBase(s.text, s.filterBase, placeholderText);\n const currentQuery = extractFilterQuery(s.text, effBase, s.filterInProgress);\n const actionable = s.suggestions.filter((sg: Suggestion) => sg.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n // Mirror the filter-zone behavior for placeholder suggestions: if the user is\n // still typing a prefix of the server-provided placeholder, don't fetch yet.\n if (\n s.completedParams.length === 0 &&\n s.text.length > 0 &&\n placeholderText.length > 0 &&\n placeholderText.toLowerCase().startsWith(s.text.toLowerCase())\n ) {\n return false;\n }\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(s.text, s.completedParams);\n const isDeleting = rawQuery.length < s.lastRawQuery.length;\n const charDiff = Math.abs(rawQuery.length - s.lastRawQuery.length);\n if (isDeleting || charDiff >= minDiff) {\n this.doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n this.debounceTimer = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n }\n }, DEBOUNCE_MS);\n\n this.slowDebounceTimer = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n }\n\n private clearTimers() {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n this.debounceTimer = null;\n this.slowDebounceTimer = null;\n }\n}\n","import type { AutocompleteResult, SuggestionOption } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { cursorIsAtEnd, getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface KeyboardContext {\n columns: number;\n listboxId: string;\n getOnSubmit: () => ((result: AutocompleteResult) => void) | undefined;\n /** Optional hook invoked after onSubmit fires (used by Tier 1 to auto-reset). */\n afterSubmit?: () => void;\n selectOption: (option: SuggestionOption) => void;\n /**\n * Tier 1 only: remove a completed param at the given caret offset, returning\n * true when a param was removed. Tier 2 consumers can omit this — Backspace\n * falls back to the browser default in their own input element.\n */\n removeParamAtCaret?: (offset: number) => boolean;\n /** Tier 1 only: exit re-edit mode (Escape, arrow-key escape). */\n exitEditMode?: () => void;\n}\n\n/**\n * Returns true when the caret in the event target sits at the end of its\n * editable content. Works for both `<textarea>`/`<input>` (Tier 2 consumer\n * inputs) and our contentEditable Tier 1 editor.\n */\nfunction isCursorAtEnd(target: EventTarget | null): boolean {\n if (target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement) {\n return target.selectionStart != null && target.selectionStart === target.value.length;\n }\n if (target instanceof HTMLElement && target.hasAttribute(\"data-aia-input\")) {\n return cursorIsAtEnd(target);\n }\n return false;\n}\n\nfunction getEditableCaretOffset(target: EventTarget | null): number | null {\n if (target instanceof HTMLElement && target.hasAttribute(\"data-aia-input\")) {\n return getCursorOffset(target);\n }\n return null;\n}\n\nexport class KeyboardController {\n constructor(\n private store: Store<CoreState>,\n private ctx: KeyboardContext,\n ) {}\n\n handleKeyDown(e: KeyboardEvent) {\n const state = this.store.get();\n const { listboxId, getOnSubmit } = this.ctx;\n const columns = this.getEffectiveColumns();\n const onSubmit = getOnSubmit();\n const tappableIndices = this.getTappableIndices(columns);\n\n switch (e.key) {\n case \"ArrowDown\": {\n const cursorAtEnd = isCursorAtEnd(e.target);\n // While re-editing a bold param, the dropdown is showing cached\n // options for it — ArrowDown should descend into them regardless of\n // whether the caret is \"at end\" of the input.\n const inEditMode = !!state.editingParam;\n if (!cursorAtEnd && !inEditMode && state.activeDropdownIndex < 0) break;\n\n e.preventDefault();\n if (!state.isDropdownOpen && state.actionableSuggestions.length > 0) {\n this.store.set({ pillTapped: true, activeDropdownIndex: tappableIndices[0] ?? 0 });\n break;\n }\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n this.store.set({ activeDropdownIndex: tappableIndices[nextPos] });\n break;\n }\n case \"ArrowUp\": {\n if (tappableIndices.length === 0 || state.activeDropdownIndex < 0) break;\n e.preventDefault();\n if (state.activeDropdownIndex < columns) {\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n this.store.set({ activeDropdownIndex: tappableIndices[prevPos] });\n break;\n }\n case \"ArrowRight\": {\n // When a dropdown option is highlighted, arrows navigate the grid\n // only — the caret in the editor stays put. Always preventDefault so\n // a press at the rightmost column doesn't fall through to caret\n // movement.\n if (state.activeDropdownIndex >= 0) {\n e.preventDefault();\n const col = state.activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = state.activeDropdownIndex + 1;\n if (\n rightNeighbor < state.filteredOptions.length &&\n state.filteredOptions[rightNeighbor]?.is_tappable\n ) {\n this.store.set({ activeDropdownIndex: rightNeighbor });\n }\n }\n break;\n }\n // No highlight → arrow keys move the caret. In re-edit mode that\n // means collapse the highlight to the param's trailing edge and exit.\n if (state.editingParam && e.target instanceof HTMLElement && state.editingTail != null) {\n e.preventDefault();\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const tail = state.editingTail;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, tail);\n break;\n }\n const atEnd = isCursorAtEnd(e.target);\n if (atEnd && state.actionableSuggestions.length > 1) {\n e.preventDefault();\n this.pillsSetActivePill(1);\n }\n break;\n }\n case \"ArrowLeft\": {\n // When a dropdown option is highlighted, arrows navigate the grid\n // only — the caret stays put. Always preventDefault so a press at\n // the leftmost column doesn't fall through to caret movement.\n if (state.activeDropdownIndex >= 0) {\n e.preventDefault();\n if (state.activeDropdownIndex % columns > 0) {\n const leftNeighbor = state.activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && state.filteredOptions[leftNeighbor]?.is_tappable) {\n this.store.set({ activeDropdownIndex: leftNeighbor });\n }\n }\n break;\n }\n // No highlight → arrow keys move the caret.\n if (state.editingParam && e.target instanceof HTMLElement && state.editingAnchor != null) {\n e.preventDefault();\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const anchor = state.editingAnchor;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, anchor);\n break;\n }\n break;\n }\n case \"Backspace\": {\n // In re-edit mode the entire bold param is selected; the browser's\n // default Backspace handles deletion of the selected range. Skip\n // removeParamAtCaret so we don't double-handle.\n if (state.editingParam) break;\n if (!this.ctx.removeParamAtCaret) break;\n const offset = getEditableCaretOffset(e.target);\n if (offset == null) break;\n if (this.ctx.removeParamAtCaret(offset)) {\n e.preventDefault();\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable\n ) {\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (onSubmit) {\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n this.ctx.afterSubmit?.();\n }\n break;\n }\n case \"Tab\": {\n const placeholderVisible = !state.text && !!state.placeholderText;\n const hasHighlightedOption =\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable;\n\n // Placeholder visible + option highlighted → defer to selectOption,\n // which prepends the placeholder text to the option (see AIAutocomplete.selectOption).\n if (placeholderVisible && !hasHighlightedOption) {\n // Tab on a placeholder commits the suggested text as plain typed\n // text — it is NOT a completed param, so it does not render bold.\n // The placeholder suggestion is dropped so it stops showing.\n e.preventDefault();\n const filledText = state.placeholderText;\n this.store.set((s) => ({\n text: filledText,\n filterBase: filledText.length,\n suggestions: s.suggestions.filter((sg) => sg.type !== \"placeholder\"),\n }));\n // Park caret at the end of the just-filled text. queueMicrotask\n // runs AFTER the batched-render microtask so we override the\n // renderer's default caret-clamp.\n if (e.target instanceof HTMLElement) {\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n queueMicrotask(() => setCursorOffset(editor, filledText.length));\n }\n } else if (hasHighlightedOption) {\n e.preventDefault();\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (state.isDropdownOpen) {\n const firstTappableIdx = state.filteredOptions.findIndex((o) => o.is_tappable);\n if (firstTappableIdx >= 0) {\n e.preventDefault();\n this.clickOrSelect(firstTappableIdx, state.filteredOptions, listboxId);\n }\n }\n break;\n }\n case \"Escape\": {\n if (state.editingParam && e.target instanceof HTMLElement && state.editingTail != null) {\n const editor = e.target.closest<HTMLElement>(\"[data-aia-input]\") ?? e.target;\n const tail = state.editingTail;\n this.ctx.exitEditMode?.();\n setCursorOffset(editor, tail);\n }\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n }\n }\n\n private getTappableIndices(columns: number): number[] {\n const state = this.store.get();\n const tappable = state.filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }\n\n /**\n * The grid uses a container query to switch between 1 and 2 columns based on\n * width, so the prop value can disagree with what's actually rendered. Read\n * the live column count from the grid; fall back to the prop if unavailable.\n */\n private getEffectiveColumns(): number {\n const firstOption = document.getElementById(`${this.ctx.listboxId}-option-0`);\n const grid = firstOption?.parentElement;\n if (!grid) return this.ctx.columns;\n const tracks = getComputedStyle(grid).gridTemplateColumns.split(\" \").filter(Boolean).length;\n return tracks > 0 ? tracks : this.ctx.columns;\n }\n\n private clickOrSelect(index: number, options: SuggestionOption[], listboxId: string) {\n const optionEl = document.getElementById(`${listboxId}-option-${index}`);\n if (optionEl) {\n optionEl.click();\n } else {\n this.ctx.selectOption(options[index]);\n }\n }\n\n /** Delegate to pills controller logic inline (avoids circular dep) */\n private pillsSetActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n}\n","import { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface PillSelectedEvent {\n rawQuery: string;\n selectedPill: string;\n otherPills: string[];\n}\n\nexport interface PillsControllerCallbacks {\n onPillSelected?: (event: PillSelectedEvent) => void;\n}\n\nexport class PillsController {\n constructor(\n private store: Store<CoreState>,\n private callbacks: PillsControllerCallbacks = {},\n ) {}\n\n setActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n\n if (this.callbacks.onPillSelected) {\n const { rawQuery } = buildQuery(state.text, state.completedParams);\n this.callbacks.onPillSelected({\n rawQuery,\n selectedPill: moved.text,\n otherPills: rest.map((s) => s.text),\n });\n }\n\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n\n removeLastParam() {\n const state = this.store.get();\n if (state.completedParams.length === 0) return;\n this.store.set((s) => ({\n completedParams: s.completedParams.slice(0, -1),\n activeDropdownIndex: -1,\n }));\n }\n}\n","export interface DropdownVisibilityInputs {\n /** True while re-editing a bold param. Bypasses caret-at-end and manual-trigger gating. */\n inEditMode: boolean;\n /** Number of options the dropdown would render right now (post-filter). */\n filteredOptionsLength: number;\n isFocused: boolean;\n text: string;\n caretOffset: number | null;\n isLoading: boolean;\n /** True after the user tapped a pill in `manual` trigger mode. */\n pillTapped: boolean;\n}\n\nexport interface DropdownVisibilityOpts {\n dropdownTrigger?: \"auto\" | \"manual\" | \"hidden\";\n closeDropdownOnBlur?: boolean;\n}\n\n// Pure: is the dropdown open right now? See call site in deriveAll for the gating rules.\nexport function computeDropdownVisibility(\n inputs: DropdownVisibilityInputs,\n opts: DropdownVisibilityOpts,\n): boolean {\n const trigger = opts.dropdownTrigger ?? \"auto\";\n const closeOnBlur = opts.closeDropdownOnBlur ?? true;\n const hasOptions = inputs.filteredOptionsLength > 0;\n\n if (inputs.inEditMode) {\n // While re-editing, dropdown visibility is governed solely by whether\n // cached options match the query — focus/manual gates don't apply (the\n // user is in a deliberate edit interaction).\n const focusGate = closeOnBlur ? inputs.isFocused : true;\n return hasOptions && focusGate;\n }\n\n if (trigger === \"auto\") {\n const focusGate = closeOnBlur ? inputs.isFocused : true;\n // Outside re-edit, dropdown only opens when the caret is at the end of\n // the input — middle-of-text caret should NOT show suggestions. Trailing\n // whitespace is ignored so the dropdown stays open right after an option\n // selection (which appends a trailing space) or when the user pauses on\n // a word boundary.\n const trimmedEnd = inputs.text.replace(/\\s+$/, \"\").length;\n const caretAtEnd = inputs.caretOffset == null || inputs.caretOffset >= trimmedEnd;\n return (hasOptions || inputs.isLoading) && focusGate && caretAtEnd;\n }\n\n if (trigger === \"manual\") {\n return (hasOptions || inputs.isLoading) && inputs.pillTapped;\n }\n\n return false;\n}\n","import type { Suggestion, SuggestionOption } from \"../../types\";\nimport { effectiveFilterBase, extractFilterQuery, filterOptions } from \"../../utils/filtering\";\nimport { deriveSegments } from \"../../utils/segments\";\nimport type { CoreDerivedState, CoreInputState, CoreOptions } from \"../types\";\nimport { computeDropdownVisibility } from \"./dropdown\";\n\n// Pure derive: raw inputs + opts → segments / actionable / filtered / placeholder / isDropdownOpen.\nexport function deriveAll(inputs: CoreInputState, opts: CoreOptions): CoreDerivedState {\n const segments = deriveSegments(inputs.text, inputs.completedParams);\n const actionableSuggestions = inputs.suggestions.filter((s) => s.type !== \"placeholder\");\n const activeSuggestion = actionableSuggestions[0] as Suggestion | undefined;\n const overrideFn = activeSuggestion ? opts.optionOverrides?.[activeSuggestion.type] : undefined;\n\n const placeholderText = inputs.suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n\n // Clamp filterBase so it never exceeds text length. Promote the placeholder\n // to filterBase when the user has typed through it — the filter query should\n // be just the text past the server-suggested prefix.\n const clampedFilterBase = effectiveFilterBase(\n inputs.text,\n Math.min(inputs.filterBase, inputs.text.length),\n placeholderText,\n );\n // When filterBase is 0 and no fetch has set it yet, don't filter by typed\n // text — the user is still typing the initial query and no server context\n // exists.\n const hasServerContext = inputs.lastRawQuery !== \"\" || clampedFilterBase > 0;\n const filterQuery = hasServerContext\n ? extractFilterQuery(inputs.text, clampedFilterBase, inputs.filterInProgress)\n : \"\";\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n\n // Re-edit mode: dropdown filters the edited param's cached options instead\n // of the active suggestion's options. While the bold param's still in the\n // DOM (user just tapped it, hasn't typed yet), show the FULL cached list —\n // filtering by the param's own text would only match itself. Once the user\n // starts typing (param removed from completedParams), filter by what they\n // typed.\n const inEditMode = inputs.editingParam != null && inputs.editingAnchor != null;\n let filteredOptions: SuggestionOption[];\n if (inEditMode && inputs.editingParam && inputs.editingAnchor != null) {\n const editingId = inputs.editingParam.id;\n const paramStillPresent = inputs.completedParams.some((p) => p.id === editingId);\n const editCaret = inputs.caretOffset ?? inputs.editingAnchor;\n const editQuery = paramStillPresent ? \"\" : inputs.text.slice(inputs.editingAnchor, editCaret);\n filteredOptions = filterOptions(inputs.editingParam.options, editQuery);\n } else {\n filteredOptions = filterOptions(baseOptions, filterQuery);\n }\n // Consumer-controlled visibility of non-tappable options. Defaults to true\n // (current behavior). When false, strip them from what the dropdown sees.\n if (opts.showNonTappableOptions === false) {\n filteredOptions = filteredOptions.filter((o) => o.is_tappable);\n }\n\n const isDropdownOpen = computeDropdownVisibility(\n {\n inEditMode,\n filteredOptionsLength: filteredOptions.length,\n isFocused: inputs.isFocused,\n text: inputs.text,\n caretOffset: inputs.caretOffset,\n isLoading: inputs.isLoading,\n pillTapped: inputs.pillTapped,\n },\n {\n dropdownTrigger: opts.dropdownTrigger,\n closeDropdownOnBlur: opts.closeDropdownOnBlur,\n },\n );\n\n return {\n segments,\n actionableSuggestions,\n filteredOptions,\n placeholderText,\n isDropdownOpen,\n };\n}\n","import type { CompletedParamState, Suggestion } from \"../../types\";\nimport { effectiveFilterBase, extractFilterQuery, findExactMatch } from \"../../utils/filtering\";\nimport type { CoreState } from \"../types\";\n\nexport type PromotionContext =\n | {\n mode: \"fresh\";\n text: string;\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n filterBase: number;\n filterInProgress: boolean;\n }\n | {\n mode: \"edit\";\n text: string;\n completedParams: CompletedParamState[];\n editingParam: CompletedParamState;\n editingAnchor: number;\n editingTail: number;\n };\n\nexport interface PromotionResult {\n patch: Partial<CoreState>;\n caretPos: number;\n}\n\n// Promote typed text to a bold param when it exact-matches an option; null when no match.\nexport function tryPromoteExactMatch(ctx: PromotionContext): PromotionResult | null {\n if (ctx.mode === \"fresh\") {\n return promoteFresh(ctx);\n }\n return promoteEdit(ctx);\n}\n\nfunction promoteFresh(ctx: Extract<PromotionContext, { mode: \"fresh\" }>): PromotionResult | null {\n const { text, completedParams, suggestions, filterBase, filterInProgress } = ctx;\n const actionable = suggestions.filter((sg) => sg.type !== \"placeholder\");\n const active = actionable[0];\n if (!active?.options) return null;\n\n const placeholderText = suggestions\n .filter((sg) => sg.type === \"placeholder\")\n .map((sg) => sg.text)\n .join(\" \");\n const effBase = effectiveFilterBase(text, filterBase, placeholderText);\n const query = extractFilterQuery(text, effBase, filterInProgress);\n const match = findExactMatch(active.options, query);\n if (!match) return null;\n\n // Preserve the case the user actually typed so deriveSegments (case-sensitive\n // indexOf) can still match the completed param inside the text.\n const matchLower = match.text.toLowerCase();\n const optionStart = text.toLowerCase().lastIndexOf(matchLower);\n const paramStart = optionStart >= 0 ? optionStart : Math.max(0, text.length - match.text.length);\n const paramEnd = paramStart + match.text.length;\n const optionInText = text.slice(paramStart, paramEnd);\n\n const hasTrailingSpace = paramEnd < text.length && text[paramEnd] === \" \";\n const caretPos = hasTrailingSpace ? paramEnd + 1 : paramEnd;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: optionInText,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n\n return {\n patch: {\n text,\n completedParams: [...completedParams, completed],\n suggestions: suggestions.filter((sg) => sg !== active),\n filterBase: caretPos,\n newParamId: completed.id,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n },\n caretPos,\n };\n}\n\nfunction promoteEdit(ctx: Extract<PromotionContext, { mode: \"edit\" }>): PromotionResult | null {\n const { text, completedParams, editingParam, editingAnchor, editingTail } = ctx;\n // Skip while the original bold is still in completedParams (user hasn't\n // typed yet — the editQuery would just be the param's own text).\n if (completedParams.some((p) => p.id === editingParam.id)) return null;\n\n const editQuery = text.slice(editingAnchor, editingTail);\n const match = findExactMatch(editingParam.options, editQuery);\n if (!match) return null;\n\n // Locate the matched portion within the edit region so we know where the\n // new param's text sits in the full input. Preserve the user's typed\n // casing so deriveSegments (case-sensitive indexOf) can still find it.\n const matchLower = match.text.toLowerCase();\n const matchStart = editQuery.toLowerCase().lastIndexOf(matchLower);\n const paramStart = editingAnchor + Math.max(0, matchStart);\n const paramEnd = paramStart + match.text.length;\n const optionInText = text.slice(paramStart, paramEnd);\n\n const hasTrailingSpace = paramEnd < text.length && text[paramEnd] === \" \";\n const caretPos = hasTrailingSpace ? paramEnd + 1 : paramEnd;\n\n const newParam: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: editingParam.suggestionType,\n text: optionInText,\n kind: match.kind,\n suggestionType: editingParam.suggestionType,\n suggestionPlaceholder: editingParam.suggestionPlaceholder,\n options: editingParam.options,\n metadata: match.metadata,\n };\n\n // Insert at the correct text-order position. The editing param is already\n // gone from completedParams; walk the remaining params and insert before\n // the first one whose text sits past the edit region.\n let insertAt = completedParams.length;\n let scanPos = 0;\n for (let i = 0; i < completedParams.length; i++) {\n const idx = text.indexOf(completedParams[i].text, scanPos);\n if (idx === -1) continue;\n if (idx >= caretPos) {\n insertAt = i;\n break;\n }\n scanPos = idx + completedParams[i].text.length;\n }\n const newParams = [...completedParams];\n newParams.splice(insertAt, 0, newParam);\n\n return {\n patch: {\n text,\n completedParams: newParams,\n newParamId: newParam.id,\n filterBase: caretPos,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n },\n caretPos,\n };\n}\n","import type { CompletedParamState, SuggestionOption } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { tryPromoteExactMatch } from \"../promotion/promote\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface ReEditDeps {\n store: Store<CoreState>;\n scheduleSetCursor: (offset: number) => void;\n fireTelemetry: (type: \"pill\" | \"option\", data: Record<string, unknown>) => void;\n startSelectionAnimationTimer: () => void;\n}\n\n// Re-edit lifecycle: enter / exit / atomic replace / caret tracking / select / promote-back-to-bold.\nexport class ReEditManager {\n constructor(private deps: ReEditDeps) {}\n\n // Caller highlights the param via Selection API; this just sets the state snapshot.\n start(paramId: string): void {\n const state = this.deps.store.get();\n if (state.editingParam?.id === paramId) return;\n const param = state.completedParams.find((p) => p.id === paramId);\n if (!param) return;\n // Find the param's position in text (same approach as deriveSegments).\n let pos = 0;\n let anchor = -1;\n for (const p of state.completedParams) {\n const idx = state.text.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === paramId) {\n anchor = idx;\n break;\n }\n pos = idx + p.text.length;\n }\n if (anchor < 0) return;\n this.deps.store.set({\n editingParam: param,\n editingAnchor: anchor,\n editingTail: anchor + param.text.length,\n caretOffset: anchor + param.text.length,\n activeDropdownIndex: -1,\n });\n }\n\n /** Clear re-edit state. Selection collapsing is a DOM concern handled by the caller. */\n exit(): void {\n const state = this.deps.store.get();\n if (!state.editingParam) return;\n this.deps.store.set({\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n activeDropdownIndex: -1,\n });\n }\n\n // Atomic swap of `text[anchor..tail]` while the bold is still in completedParams; returns true if applied (caller preventDefaults).\n replaceRange(replacement: string): boolean {\n const state = this.deps.store.get();\n const editing = state.editingParam;\n const anchor = state.editingAnchor;\n const tail = state.editingTail;\n if (!editing || anchor == null || tail == null) return false;\n // Only intercept while the param's strong is still in the DOM (i.e. it\n // hasn't already been replaced by an earlier keystroke).\n if (!state.completedParams.some((p) => p.id === editing.id)) return false;\n const newText = state.text.slice(0, anchor) + replacement + state.text.slice(tail);\n const newTail = anchor + replacement.length;\n this.deps.store.set((s) => ({\n text: newText,\n completedParams: s.completedParams.filter((p) => p.id !== editing.id),\n editingTail: newTail,\n caretOffset: newTail,\n activeDropdownIndex: -1,\n }));\n this.deps.scheduleSetCursor(newTail);\n this.tryPromote();\n return true;\n }\n\n // Post-input: extends editingTail forward; exits if caret backspaced past anchor.\n caretAfterInput(offset: number | null): void {\n const state = this.deps.store.get();\n const patch: Partial<CoreState> = { caretOffset: offset };\n if (state.editingParam && state.editingAnchor != null && offset != null) {\n if (offset < state.editingAnchor) {\n patch.editingParam = null;\n patch.editingAnchor = null;\n patch.editingTail = null;\n patch.activeDropdownIndex = -1;\n } else if (state.editingTail != null) {\n patch.editingTail = Math.max(state.editingTail, offset);\n }\n }\n this.deps.store.set(patch);\n this.tryPromote();\n }\n\n // Caret moved by click/arrows (not typing): exits if outside [anchor, tail].\n caretMove(offset: number | null): void {\n const state = this.deps.store.get();\n if (\n state.editingParam &&\n state.editingAnchor != null &&\n state.editingTail != null &&\n offset != null &&\n (offset < state.editingAnchor || offset > state.editingTail)\n ) {\n this.deps.store.set({\n caretOffset: offset,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n activeDropdownIndex: -1,\n });\n return;\n }\n this.deps.store.set({ caretOffset: offset });\n }\n\n // Select-option flow for re-edit: new param inherits the same cached suggestion metadata.\n selectOption(option: SuggestionOption): void {\n const state = this.deps.store.get();\n const editing = state.editingParam;\n const anchor = state.editingAnchor;\n const tail = state.editingTail;\n if (!editing || anchor == null || tail == null) return;\n\n this.deps.fireTelemetry(\"option\", {\n raw_query: buildQuery(state.text, state.completedParams).rawQuery,\n selected_option: option.text,\n other_options: editing.options.filter((o) => o.text !== option.text).map((o) => o.text),\n });\n\n const before = state.text.slice(0, anchor);\n const after = state.text.slice(tail);\n // Capitalize when replacing at the very start of the input — matches the\n // case-handling in the normal selectOption path for \"first letter of the\n // input is uppercase\".\n const optionText =\n anchor === 0 && option.text.length > 0\n ? option.text[0].toUpperCase() + option.text.slice(1)\n : option.text;\n // Preserve the trailing-space convention: a single space follows the\n // replaced text unless the next char already provides one.\n const needsTrailingSpace = after.length === 0 || after[0] !== \" \";\n const replacement = needsTrailingSpace ? `${optionText} ` : optionText;\n const newText = before + replacement + after;\n // Caret lands AFTER the trailing space — whether we just added it or it\n // was already there from the original text.\n const caretPos = anchor + replacement.length + (needsTrailingSpace ? 0 : 1);\n\n const newParam: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: editing.suggestionType,\n text: optionText,\n kind: option.kind,\n suggestionType: editing.suggestionType,\n suggestionPlaceholder: editing.suggestionPlaceholder,\n options: editing.options,\n metadata: option.metadata,\n };\n const oldIdx = state.completedParams.findIndex((p) => p.id === editing.id);\n const params = state.completedParams.filter((p) => p.id !== editing.id);\n const insertAt = oldIdx >= 0 ? Math.min(oldIdx, params.length) : params.length;\n params.splice(insertAt, 0, newParam);\n\n this.deps.store.set({\n text: newText,\n completedParams: params,\n newParamId: newParam.id,\n filterBase: caretPos,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: caretPos,\n activeDropdownIndex: -1,\n pillTapped: false,\n skipNextFetch: true,\n inSelectionAnimation: true,\n });\n this.deps.startSelectionAnimationTimer();\n // Park caret right after the replacement (not end of text) once the render microtask commits.\n this.deps.scheduleSetCursor(caretPos);\n }\n\n private tryPromote(): void {\n const s = this.deps.store.get();\n if (!s.editingParam || s.editingAnchor == null || s.editingTail == null) return;\n const result = tryPromoteExactMatch({\n mode: \"edit\",\n text: s.text,\n completedParams: s.completedParams,\n editingParam: s.editingParam,\n editingAnchor: s.editingAnchor,\n editingTail: s.editingTail,\n });\n if (!result) return;\n this.deps.store.set(result.patch);\n this.deps.scheduleSetCursor(result.caretPos);\n }\n}\n","const KEY_ATTR = \"data-aia-key\";\n\nexport interface ReconcileOptions<T> {\n keyOf: (item: T, index: number) => string;\n create: (item: T, index: number) => HTMLElement;\n update?: (el: HTMLElement, item: T, index: number) => void;\n}\n\n// Keyed DOM reconcile — reuses/repositions/removes `data-aia-key` children; unkeyed children untouched.\nexport function reconcileList<T>(\n parent: Element,\n items: readonly T[],\n opts: ReconcileOptions<T>,\n): HTMLElement[] {\n const existing = new Map<string, HTMLElement>();\n for (const child of Array.from(parent.children)) {\n const key = child.getAttribute(KEY_ATTR);\n if (key != null) existing.set(key, child as HTMLElement);\n }\n\n const used = new Set<string>();\n const result: HTMLElement[] = [];\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const key = opts.keyOf(item, i);\n used.add(key);\n let el = existing.get(key);\n if (!el) {\n el = opts.create(item, i);\n el.setAttribute(KEY_ATTR, key);\n }\n opts.update?.(el, item, i);\n if (parent.children[i] !== el) {\n parent.insertBefore(el, parent.children[i] ?? null);\n }\n result.push(el);\n }\n\n for (const [key, el] of existing) {\n if (!used.has(key)) el.remove();\n }\n\n return result;\n}\n","import type { Suggestion } from \"../../types\";\nimport { reconcileList } from \"./reconcileList\";\n\nconst FALLBACK_SKELETON_WIDTHS = [125, 69];\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function renderPills(\n container: HTMLElement,\n pills: Suggestion[],\n activePillIndex: number,\n onSelectPill: (index: number) => void,\n rounded = false,\n loading = false,\n) {\n let list = container.querySelector<HTMLElement>(\".magicx-aia-pill-list\");\n if (!list) {\n list = document.createElement(\"span\");\n list.className = \"magicx-aia-pill-list\";\n container.appendChild(list);\n }\n\n // No cached pills + loading → fallback fixed-width placeholders.\n if (loading && pills.length === 0) {\n list.setAttribute(\"data-aia-pill-list-loading\", \"\");\n list.innerHTML = \"\";\n for (let i = 0; i < FALLBACK_SKELETON_WIDTHS.length; i++) {\n const width = FALLBACK_SKELETON_WIDTHS[i];\n const span = document.createElement(\"span\");\n span.setAttribute(\"data-aia-pill-skeleton\", \"\");\n span.className = `magicx-aia-pill magicx-aia-pill--skeleton${rounded ? \" magicx-aia-pill--rounded\" : \"\"}`;\n span.style.width = `${width}px`;\n span.style.opacity = String(getPillOpacity(i));\n list.appendChild(span);\n }\n return;\n }\n\n if (loading) {\n list.setAttribute(\"data-aia-pill-list-loading\", \"\");\n } else {\n list.removeAttribute(\"data-aia-pill-list-loading\");\n }\n\n // Drop any leftover fallback placeholders before diffing the real pills.\n for (const skel of list.querySelectorAll<HTMLElement>(\"[data-aia-pill-skeleton]\")) {\n skel.remove();\n }\n\n reconcileList(list, pills, {\n keyOf: (pill) => `${pill.type}-${pill.text}`,\n create: (pill) => {\n const btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.tabIndex = -1;\n btn.setAttribute(\"data-aia-pill\", \"\");\n btn.setAttribute(\"contenteditable\", \"false\");\n btn.textContent = pill.text;\n btn.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return btn;\n },\n update: (el, _pill, i) => {\n const btn = el as HTMLButtonElement;\n const classes = [\"magicx-aia-pill\"];\n if (rounded) classes.push(\"magicx-aia-pill--rounded\");\n if (i === activePillIndex && !loading) classes.push(\"magicx-aia-pill--active\");\n if (loading) classes.push(\"magicx-aia-pill--skeleton\");\n btn.className = classes.join(\" \");\n btn.style.width = \"\";\n btn.style.opacity = String(getPillOpacity(i));\n if (loading) {\n btn.setAttribute(\"data-aia-loading\", \"\");\n btn.disabled = true;\n btn.onclick = null;\n } else {\n btn.removeAttribute(\"data-aia-loading\");\n btn.disabled = false;\n btn.onclick = () => onSelectPill(i);\n }\n },\n });\n}\n\nexport function clearPills(container: HTMLElement) {\n container.querySelector(\".magicx-aia-pill-list\")?.remove();\n}\n","import type { Suggestion, SuggestionOption } from \"../../types\";\nimport { reconcileList } from \"./reconcileList\";\nimport { renderPills } from \"./renderPills\";\n\nconst FALLBACK_SKELETON_BAR_WIDTHS = [159, 119, 164];\n\ninterface DropdownState {\n suggestions: Suggestion[];\n filteredOptions: SuggestionOption[];\n activeIndex: number;\n isOpen: boolean;\n isLoading: boolean;\n listboxId: string;\n pills: Suggestion[];\n showPills: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPillClick: (index: number) => void;\n}\n\nexport function createDropdown(listboxId: string): HTMLElement {\n const dropdown = document.createElement(\"div\");\n dropdown.id = listboxId;\n dropdown.setAttribute(\"role\", \"listbox\");\n dropdown.setAttribute(\"data-aia-dropdown\", \"\");\n dropdown.className = \"magicx-aia-dropdown\";\n dropdown.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return dropdown;\n}\n\nexport function renderDropdown(dropdown: HTMLElement, state: DropdownState) {\n const {\n filteredOptions,\n activeIndex,\n isOpen,\n isLoading,\n pills,\n showPills,\n onSelect,\n onHighlight,\n onPillClick,\n } = state;\n\n const hasPills = showPills && pills.length > 0;\n const hasOptions = filteredOptions.length > 0;\n const isVisible = isOpen && (hasOptions || hasPills || isLoading);\n\n if (isVisible) {\n dropdown.classList.add(\"magicx-aia-dropdown--visible\");\n } else {\n dropdown.classList.remove(\"magicx-aia-dropdown--visible\");\n }\n\n if (isLoading) {\n dropdown.setAttribute(\"data-aia-loading\", \"\");\n } else {\n dropdown.removeAttribute(\"data-aia-loading\");\n }\n\n // --- Pill bar ---\n // Render the pill bar when we have real pills OR when loading + showPills\n // (so the bar can host the fallback placeholder pills).\n const wantsPillBar = hasPills || (isLoading && showPills);\n let pillBar = dropdown.querySelector<HTMLElement>(\".magicx-aia-pill-bar\");\n if (wantsPillBar) {\n if (!pillBar) {\n pillBar = document.createElement(\"div\");\n pillBar.className = \"magicx-aia-pill-bar\";\n pillBar.setAttribute(\"data-aia-pillbar\", \"\");\n dropdown.insertBefore(pillBar, dropdown.firstChild);\n }\n renderPills(pillBar, pills, 0, onPillClick, true, isLoading);\n } else if (pillBar) {\n pillBar.remove();\n }\n\n // --- Options grid ---\n let grid = dropdown.querySelector<HTMLElement>(\".magicx-aia-grid\");\n if (hasOptions) {\n if (!grid) {\n grid = document.createElement(\"div\");\n grid.className = \"magicx-aia-grid\";\n dropdown.appendChild(grid);\n }\n renderOptions(\n grid,\n filteredOptions,\n activeIndex,\n onSelect,\n onHighlight,\n state.listboxId,\n isLoading,\n );\n } else if (grid) {\n grid.remove();\n }\n\n // --- Fallback skeleton bars (when loading with no cached options) ---\n let skeleton = dropdown.querySelector<HTMLElement>(\".magicx-aia-skeleton-bars\");\n if (isLoading && !hasOptions) {\n if (!skeleton) {\n skeleton = document.createElement(\"div\");\n skeleton.className = \"magicx-aia-skeleton-bars\";\n skeleton.setAttribute(\"data-aia-skeleton-bars\", \"\");\n for (const width of FALLBACK_SKELETON_BAR_WIDTHS) {\n const bar = document.createElement(\"span\");\n bar.className = \"magicx-aia-skeleton-bar\";\n bar.style.width = `${width}px`;\n skeleton.appendChild(bar);\n }\n dropdown.appendChild(skeleton);\n }\n } else if (skeleton) {\n skeleton.remove();\n }\n}\n\nfunction renderOptions(\n grid: HTMLElement,\n options: SuggestionOption[],\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n loading: boolean,\n) {\n // Loading flips re-key every option so any cached non-loading element\n // is replaced rather than reused with stale loading attrs.\n const loadingFlag = loading ? \"1\" : \"0\";\n\n reconcileList(grid, options, {\n keyOf: (opt) => `${opt.text}\\0${loadingFlag}`,\n create: (option) => buildOptionElement(option, loading),\n update: (el, option, i) => {\n const isHighlighted = i === activeIndex && !loading;\n el.id = `${listboxId}-option-${i}`;\n el.dataset.aiaIndex = String(i);\n el.setAttribute(\"aria-selected\", String(isHighlighted));\n el.classList.toggle(\"magicx-aia-option--highlighted\", isHighlighted);\n // Reassign every render so reused elements don't hold stale closures.\n if (!loading && option.is_tappable) {\n el.onclick = () => {\n el.classList.add(\"magicx-aia-option--pressed\");\n onSelect(option);\n setTimeout(() => el.classList.remove(\"magicx-aia-option--pressed\"), 500);\n };\n el.onmouseenter = () => {\n const idx = Number.parseInt(el.dataset.aiaIndex ?? \"-1\", 10);\n if (idx >= 0) onHighlight(idx);\n };\n } else {\n el.onclick = null;\n el.onmouseenter = null;\n }\n },\n });\n}\n\nfunction buildOptionElement(option: SuggestionOption, loading: boolean): HTMLElement {\n const item = document.createElement(\"div\");\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"data-aia-option\", \"\");\n if (loading) item.setAttribute(\"data-aia-loading\", \"\");\n item.tabIndex = loading || !option.is_tappable ? -1 : 0;\n\n const classes = [\"magicx-aia-option\"];\n if (option.is_tappable) {\n classes.push(\"magicx-aia-option--tappable\");\n } else {\n classes.push(\"magicx-aia-option--non-tappable\");\n }\n item.className = classes.join(\" \");\n\n const streaks = document.createElement(\"div\");\n streaks.className = \"magicx-aia-streaks\";\n item.appendChild(streaks);\n\n const streaksVert = document.createElement(\"div\");\n streaksVert.className = \"magicx-aia-streaks-vert\";\n item.appendChild(streaksVert);\n\n const content = document.createElement(\"span\");\n content.className = \"magicx-aia-option-content\";\n content.textContent = option.icon ? `${option.icon} ${option.text}` : option.text;\n\n if (option.tag) {\n const tag = document.createElement(\"span\");\n tag.className = \"magicx-aia-option-tag\";\n tag.textContent = option.tag;\n content.appendChild(tag);\n }\n\n item.appendChild(content);\n\n return item;\n}\n","import type { SuggestionOption } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\n\ninterface DropdownOnlyRefs {\n dropdown: HTMLElement;\n}\n\ninterface DropdownOnlyOptions {\n store: Store<CoreState>;\n listboxId: string;\n selectOption: (option: SuggestionOption) => void;\n setActivePill: (index: number) => void;\n}\n\nexport function buildDropdownOnly(\n container: HTMLElement,\n opts: DropdownOnlyOptions,\n): DropdownOnlyRefs {\n const dropdown = createDropdown(opts.listboxId);\n container.appendChild(dropdown);\n return { dropdown };\n}\n\nexport function updateDropdownOnly(\n refs: DropdownOnlyRefs,\n state: CoreState,\n opts: DropdownOnlyOptions,\n) {\n renderDropdown(refs.dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n // Re-edit shows cached options, and the streak animation finishes before\n // we swap in the skeleton.\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: true, // always show pills in dropdown-only mode\n onSelect: opts.selectOption,\n onHighlight: (i) => opts.store.set({ activeDropdownIndex: i }),\n onPillClick: opts.setActivePill,\n });\n}\n","import type { Segment } from \"../../types\";\nimport { getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\n\ninterface RenderEditableArgs {\n input: HTMLElement;\n segments: Segment[];\n newParamId: string | null;\n /** When set, the matching `<strong>` is decorated with the editing class. */\n editingParamId: string | null;\n placeholderText: string;\n isFocused: boolean;\n}\n\n/**\n * Renders text segments — including bold `<strong>` runs for completed params\n * — into the contentEditable input. Pills are NOT rendered here; they live as\n * a sibling element so the editable's subtree never contains non-editable\n * children. See renderInput.ts for the pill list placement.\n *\n * Skips rebuilds when the segment key is unchanged so an in-flight shimmer\n * animation isn't interrupted by unrelated state churn.\n */\nexport function renderEditableContent(args: RenderEditableArgs) {\n const { input, segments, newParamId, editingParamId, placeholderText, isFocused } = args;\n\n const empty = segments.length === 0;\n input.dataset.aiaEmpty = empty ? \"true\" : \"false\";\n if (empty && placeholderText) {\n input.dataset.placeholder = placeholderText;\n } else {\n delete input.dataset.placeholder;\n }\n\n const segKey = segments.map((s) => `${s.type}:${s.value}`).join(\"\\0\");\n const lastSegKey = input.dataset.segKey ?? \"\";\n const lastNewParamId = input.dataset.newParamId ?? \"\";\n const lastEditingParamId = input.dataset.editingParamId ?? \"\";\n if (\n segKey === lastSegKey &&\n (newParamId ?? \"\") === lastNewParamId &&\n (editingParamId ?? \"\") === lastEditingParamId\n ) {\n return;\n }\n\n const savedOffset = isFocused ? getCursorOffset(input) : null;\n input.dataset.segKey = segKey;\n input.dataset.newParamId = newParamId ?? \"\";\n input.dataset.editingParamId = editingParamId ?? \"\";\n\n const doc = input.ownerDocument ?? document;\n const frag = doc.createDocumentFragment();\n let newLength = 0;\n for (const seg of segments) {\n newLength += seg.value.length;\n if (seg.type === \"completed\") {\n const strong = doc.createElement(\"strong\");\n strong.dataset.seg = \"completed\";\n strong.dataset.paramId = seg.param.id;\n const isNew = seg.param.id === newParamId;\n const isEditing = seg.param.id === editingParamId;\n const classes = [\"magicx-aia-segment\", \"magicx-aia-segment--completed\"];\n if (isNew) classes.push(\"magicx-aia-shimmer-revealed\", \"magicx-aia-shimmer-sweep\");\n if (isEditing) classes.push(\"magicx-aia-segment--editing\");\n strong.className = classes.join(\" \");\n strong.textContent = seg.value;\n frag.appendChild(strong);\n } else {\n frag.appendChild(doc.createTextNode(seg.value));\n }\n }\n input.replaceChildren(frag);\n input.dataset.aiaTextLength = String(newLength);\n\n if (savedOffset != null) {\n // Restore the caret to where the browser left it (clamped to the new\n // text length). Callers that need the caret at a specific position\n // (e.g. Tab-on-placeholder, edit-mode replacement) schedule their own\n // `setCursorOffset` via `queueMicrotask` after the store mutation.\n setCursorOffset(input, Math.max(0, Math.min(savedOffset, newLength)));\n }\n}\n","import type { AutocompleteResult, Suggestion } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { extractPlainText, getCursorOffset, setCursorOffset } from \"../dom/cursorUtils\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\nimport { renderEditableContent } from \"./renderEditable\";\nimport { clearPills, renderPills } from \"./renderPills\";\n\ninterface RenderInputOptions {\n store: Store<CoreState>;\n listboxId: string;\n pillPlacement: \"inline\" | \"dropdown\" | \"hidden\";\n autoFocus?: boolean;\n onSubmit?: (result: AutocompleteResult) => void;\n /** Invoked after onSubmit fires — Tier 1 uses this to auto-reset. */\n afterSubmit?: () => void;\n submitButton?: HTMLElement | null;\n selectOption: (option: import(\"../../types\").SuggestionOption) => void;\n setActivePill: (index: number) => void;\n handleKeyDown: (e: KeyboardEvent) => void;\n handleChange: (value: string) => void;\n /** Re-edit entry: triggered when caret enters a bold completed param. */\n startEditingParam: (paramId: string) => void;\n /** Re-edit caret-tracking after an input event (extends edit tail). */\n handleCaretAfterInput: (offset: number | null) => void;\n /** Re-edit caret-tracking on selection-only moves (may exit edit mode). */\n handleCaretMove: (offset: number | null) => void;\n /** Re-edit beforeinput intercept: replace the editing range atomically. */\n replaceEditingRange: (replacement: string) => boolean;\n}\n\nexport interface DOMRefs {\n input: HTMLDivElement;\n /** Non-editable inline pill list rendered as a sibling of the editable. */\n inlinePillContainer: HTMLSpanElement;\n dropdown: HTMLElement;\n /** The default built-in button when no `submitButton` was provided. Null when consumer passed `null` or a custom element. */\n submitButton: HTMLButtonElement | null;\n /** Aborts all listeners attached during buildDOM. */\n abort: AbortController;\n}\n\nconst SUBMIT_SVG = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\"><path d=\"M9 14V4M9 4L4 9M9 4L14 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nfunction supportsPlaintextOnly(): boolean {\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n return probe.contentEditable === \"plaintext-only\";\n}\n\nexport function buildDOM(container: HTMLElement, opts: RenderInputOptions): DOMRefs {\n const { listboxId } = opts;\n\n const dropdown = createDropdown(listboxId);\n container.appendChild(dropdown);\n\n const inputWrapper = document.createElement(\"div\");\n inputWrapper.className = \"magicx-aia-input-wrapper\";\n container.appendChild(inputWrapper);\n\n const editor = document.createElement(\"div\");\n editor.className = \"magicx-aia-editor\";\n editor.setAttribute(\"data-aia-editor\", \"\");\n inputWrapper.appendChild(editor);\n\n const input = document.createElement(\"div\");\n input.className = \"magicx-aia-input\";\n input.setAttribute(\"data-aia-input\", \"\");\n input.setAttribute(\"contenteditable\", supportsPlaintextOnly() ? \"plaintext-only\" : \"true\");\n input.setAttribute(\"role\", \"combobox\");\n input.setAttribute(\"aria-autocomplete\", \"list\");\n input.setAttribute(\"aria-haspopup\", \"listbox\");\n input.setAttribute(\"aria-controls\", listboxId);\n input.setAttribute(\"aria-expanded\", \"false\");\n input.setAttribute(\"spellcheck\", \"true\");\n input.setAttribute(\"enterkeyhint\", \"send\");\n editor.appendChild(input);\n\n // Pills sit as a sibling of the editable — they're never inside a\n // contentEditable subtree, so there's no risk of them becoming part of the\n // typing surface. Layout (CSS) keeps them visually adjacent to the text.\n const inlinePillContainer = document.createElement(\"span\");\n inlinePillContainer.className = \"magicx-aia-pill-list-container\";\n inlinePillContainer.setAttribute(\"data-aia-pill-list-container\", \"\");\n editor.appendChild(inlinePillContainer);\n\n let submitButton: HTMLButtonElement | null = null;\n let submitTarget: HTMLElement | null = null;\n if (opts.submitButton === undefined) {\n submitButton = document.createElement(\"button\");\n submitButton.type = \"button\";\n submitButton.className = \"magicx-aia-submit\";\n submitButton.setAttribute(\"aria-label\", \"Submit\");\n submitButton.setAttribute(\"data-aia-submit\", \"\");\n submitButton.innerHTML = SUBMIT_SVG;\n inputWrapper.appendChild(submitButton);\n submitTarget = submitButton;\n } else if (opts.submitButton !== null) {\n submitTarget = opts.submitButton;\n if (!submitTarget.hasAttribute(\"data-aia-submit\")) {\n submitTarget.setAttribute(\"data-aia-submit\", \"\");\n }\n inputWrapper.appendChild(submitTarget);\n }\n\n const abort = new AbortController();\n const { signal } = abort;\n\n let composing = false;\n // Tracks when an input event has just fired so the immediately-following\n // selectionchange knows to extend the edit tail rather than treat the\n // caret move as a navigation event.\n let lastInputAt = 0;\n\n const fireInput = () => {\n const raw = extractPlainText(input);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n opts.handleChange(newValue);\n };\n\n const findEnclosingParamId = (): string | null => {\n const sel = (input.ownerDocument ?? document).getSelection();\n if (!sel || sel.rangeCount === 0) return null;\n const anchor = sel.anchorNode;\n if (!anchor || !input.contains(anchor)) return null;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n const strong = startEl?.closest<HTMLElement>('strong[data-seg=\"completed\"][data-param-id]');\n return strong?.dataset.paramId ?? null;\n };\n\n inputWrapper.addEventListener(\n \"click\",\n (e) => {\n // Clicking a pill button should activate the pill, not steal focus.\n if ((e.target as HTMLElement | null)?.closest(\"[data-aia-pill]\")) return;\n input.focus();\n },\n { signal },\n );\n\n input.addEventListener(\n \"input\",\n () => {\n if (composing) return;\n lastInputAt = performance.now();\n fireInput();\n // After typing, extend the edit tail to the new caret position so the\n // user can keep typing past the param's original end without exiting.\n opts.handleCaretAfterInput(getCursorOffset(input));\n },\n { signal },\n );\n\n // selectionchange fires on the document (Selection API doesn't bubble to\n // elements). Filter to selections anchored inside our editor, then route\n // the caret state into the core. A short cooldown after `input` events\n // avoids treating the post-typing caret position as a \"move\" that would\n // exit edit mode.\n const doc = input.ownerDocument ?? document;\n doc.addEventListener(\n \"selectionchange\",\n () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!input.contains(sel.anchorNode!)) return;\n const enclosing = findEnclosingParamId();\n const editingId = opts.store.get().editingParam?.id ?? null;\n if (enclosing && enclosing !== editingId) {\n opts.startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAt < 50) {\n // Just-typed: caret move handled by handleCaretAfterInput above.\n return;\n }\n opts.handleCaretMove(getCursorOffset(input));\n },\n { signal },\n );\n\n input.addEventListener(\n \"compositionstart\",\n () => {\n composing = true;\n },\n { signal },\n );\n input.addEventListener(\n \"compositionend\",\n () => {\n composing = false;\n fireInput();\n },\n { signal },\n );\n\n input.addEventListener(\n \"beforeinput\",\n (e) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n // Re-edit mode atomic-replace: while the edited param's `<strong>` is\n // still in the DOM, swap the whole thing for whatever the user is\n // about to insert (or empty, for deletes). Without this, typing or\n // backspace would land inside the bold span instead of replacing it.\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (opts.replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n },\n { signal },\n );\n\n input.addEventListener(\n \"paste\",\n (e) => {\n e.preventDefault();\n const text = (e.clipboardData?.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = input.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!input.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n { signal },\n );\n\n input.addEventListener(\"keydown\", (e) => opts.handleKeyDown(e), { signal });\n\n input.addEventListener(\"focus\", () => opts.store.set({ isFocused: true }), { signal });\n input.addEventListener(\"blur\", () => opts.store.set({ isFocused: false }), { signal });\n\n if (submitTarget) {\n submitTarget.addEventListener(\n \"click\",\n (e) => {\n const state = opts.store.get();\n const canSubmit = !!state.text || state.completedParams.length > 0;\n if (!canSubmit || !opts.onSubmit) return;\n e.stopPropagation();\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n opts.onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n opts.afterSubmit?.();\n },\n { signal },\n );\n }\n\n if (opts.autoFocus !== false) {\n input.focus();\n }\n\n return { input, inlinePillContainer, dropdown, submitButton, abort };\n}\n\nexport function updateDOM(refs: DOMRefs, state: CoreState, opts: RenderInputOptions) {\n const { input, inlinePillContainer, dropdown, submitButton } = refs;\n const { pillPlacement, setActivePill, selectOption, store } = opts;\n\n input.setAttribute(\"aria-expanded\", String(state.isDropdownOpen));\n const activeDescendant =\n state.activeDropdownIndex >= 0 ? `${opts.listboxId}-option-${state.activeDropdownIndex}` : \"\";\n if (activeDescendant) {\n input.setAttribute(\"aria-activedescendant\", activeDescendant);\n } else {\n input.removeAttribute(\"aria-activedescendant\");\n }\n\n if (submitButton) {\n const canSubmit = !!state.text || state.completedParams.length > 0;\n submitButton.disabled = !canSubmit;\n }\n\n // Detect a fresh option selection BEFORE renderEditableContent mutates the\n // dataset. `newParamId` is set by selectOption() each time a suggestion\n // becomes a completed param. We compare against the last id the DOM saw so\n // the focus/caret jump only fires once per selection (not on every render\n // during the 650ms shimmer window).\n const previousParamId = input.dataset.newParamId ?? \"\";\n const justSelected = state.newParamId !== null && state.newParamId !== previousParamId;\n\n renderEditableContent({\n input,\n segments: state.segments,\n newParamId: state.newParamId,\n editingParamId: state.editingParam?.id ?? null,\n placeholderText: state.placeholderText,\n isFocused: state.isFocused,\n });\n\n if (pillPlacement === \"inline\") {\n const inlineLoading = state.isLoading && !state.editingParam && !state.inSelectionAnimation;\n if (inlineLoading || state.actionableSuggestions.length > 0) {\n renderPills(\n inlinePillContainer,\n state.actionableSuggestions,\n 0,\n setActivePill,\n false,\n inlineLoading,\n );\n } else {\n clearPills(inlinePillContainer);\n }\n } else {\n clearPills(inlinePillContainer);\n }\n\n if (justSelected) {\n // After option selection, focus jumped to the clicked dropdown option\n // (or stayed on the editor via the dropdown's mousedown preventDefault).\n // Either way, bring focus to the editable and park the caret at the\n // position the promoter chose — typically right after the new param's\n // trailing space. Falls back to end-of-input for safety.\n input.focus();\n setCursorOffset(input, state.caretOffset ?? state.text.length);\n } else if (state.isFocused) {\n // Controlled-mode setValue / programmatic reset: keep the caret at the\n // end when DOM text diverges from state. Skip when not focused so we\n // don't steal focus on unrelated state churn.\n const domText = extractPlainText(input);\n if (domText !== state.text) {\n setCursorOffset(input, state.text.length);\n }\n }\n\n // In re-edit mode, the dropdown's pill bar shows a synthetic pill built\n // from the edited param's cached suggestion metadata (regardless of the\n // latest server suggestions). Inline pills are unaffected — they still\n // reflect the live actionable suggestions.\n const dropdownPill: Suggestion | null = state.editingParam\n ? {\n type: state.editingParam.suggestionType,\n text: state.editingParam.suggestionPlaceholder,\n required: true,\n options: state.editingParam.options,\n }\n : null;\n const dropdownActivePill = dropdownPill ?? state.actionableSuggestions[0];\n\n renderDropdown(dropdown, {\n suggestions: dropdownActivePill\n ? [{ ...dropdownActivePill, options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n // Re-edit shows cached options, and the streak animation finishes before\n // we swap in the skeleton.\n isLoading: state.isLoading && !state.editingParam && !state.inSelectionAnimation,\n listboxId: opts.listboxId,\n pills: dropdownPill ? [dropdownPill] : state.actionableSuggestions,\n showPills: pillPlacement === \"dropdown\",\n onSelect: selectOption,\n onHighlight: (i) => store.set({ activeDropdownIndex: i }),\n onPillClick: setActivePill,\n });\n}\n","import type { CompletedParamState, Suggestion, SuggestionOption } from \"../../types\";\nimport { findPrefixOverlap } from \"../../utils/filtering\";\nimport type { CoreInputState } from \"../types\";\n\nexport interface SelectionInputs {\n text: string;\n completedParams: CompletedParamState[];\n filterBase: number;\n filteredOptions: SuggestionOption[];\n actionableSuggestions: Suggestion[];\n placeholderText: string;\n}\n\nexport interface SelectionTelemetry {\n selectedOption: string;\n otherOptions: string[];\n}\n\nexport interface SelectionResult {\n patch: Partial<CoreInputState>;\n telemetry: SelectionTelemetry;\n /** The suggestion being consumed by this selection (filtered out post-animation when more remain). */\n consumedSuggestion: Suggestion;\n /** Number of actionable suggestions left after this one is consumed. */\n remainingActionable: number;\n}\n\n// Pure: non-edit-mode option selection → patch + telemetry + follow-up; null when no active suggestion.\nexport function computeSelectionPatch(\n inputs: SelectionInputs,\n option: SuggestionOption,\n): SelectionResult | null {\n const activeSuggestion = inputs.actionableSuggestions[0];\n if (!activeSuggestion) return null;\n\n const base = inputs.filterBase;\n let prefix = inputs.text.slice(0, base);\n\n const inputWasEmpty = prefix.length === 0 && inputs.text.length === 0;\n // The user is still typing within the server-provided placeholder (e.g.\n // typed \"Cre\" for placeholder \"Create a\"). Selecting an option here should\n // keep the placeholder rather than discard it — otherwise tapping \"email\"\n // replaces \"Cre\" with just \"email\" instead of \"Create a email\".\n const inputIsPlaceholderPrefix =\n prefix.length === 0 &&\n inputs.text.length > 0 &&\n inputs.placeholderText.length > 0 &&\n inputs.placeholderText.toLowerCase().startsWith(inputs.text.toLowerCase());\n if ((inputWasEmpty || inputIsPlaceholderPrefix) && inputs.placeholderText) {\n prefix = `${inputs.placeholderText} `;\n }\n\n const overlapChars = findPrefixOverlap(prefix, option.text);\n if (overlapChars > 0) {\n prefix = prefix.slice(0, prefix.length - overlapChars);\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = `${prefix}${needsSpace ? \" \" : \"\"}${option.text} `;\n const finalText =\n (inputWasEmpty || inputIsPlaceholderPrefix) && newText.length > 0\n ? newText[0].toUpperCase() + newText.slice(1)\n : newText;\n\n // Preserve the case of the option as it ends up in the final text (matters\n // when capitalize-first-letter rewrote it) so deriveSegments (case-sensitive\n // indexOf) can locate it.\n const optionStart = finalText.toLowerCase().lastIndexOf(option.text.toLowerCase());\n const optionInFinal =\n optionStart >= 0 ? finalText.slice(optionStart, optionStart + option.text.length) : option.text;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: optionInFinal,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options ?? [],\n metadata: option.metadata,\n };\n\n const remainingActionable = inputs.actionableSuggestions.length - 1;\n\n return {\n patch: {\n text: finalText,\n filterBase: finalText.length,\n completedParams: [...inputs.completedParams, completed],\n newParamId: completed.id,\n caretOffset: finalText.length,\n pillTapped: false,\n activeDropdownIndex: -1,\n skipNextFetch: remainingActionable > 0,\n inSelectionAnimation: true,\n },\n telemetry: {\n selectedOption: option.text,\n otherOptions: inputs.filteredOptions.filter((o) => o.text !== option.text).map((o) => o.text),\n },\n consumedSuggestion: activeSuggestion,\n remainingActionable,\n };\n}\n","export type Listener<S> = (next: S, prev: S) => void;\n\nexport interface Store<S> {\n get: () => S;\n set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;\n subscribe: (listener: Listener<S>) => () => void;\n}\n\nexport function createStore<S>(initial: S): Store<S> {\n let state = initial;\n const listeners = new Set<Listener<S>>();\n return {\n get: () => state,\n set: (patch) => {\n const resolved = typeof patch === \"function\" ? patch(state) : patch;\n const next = { ...state, ...resolved };\n const prev = state;\n state = next;\n for (const l of listeners) l(next, prev);\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n\n// Narrows set() to Partial<I> only — derived fields are read-only on the\n// store. Callbacks still receive I & D so they can branch on derived state.\nexport interface DerivedStore<I, D> {\n get: () => I & D;\n set: (patch: Partial<I> | ((s: I & D) => Partial<I>)) => void;\n subscribe: (listener: Listener<I & D>) => () => void;\n}\n\n// Wrap an input-only store with lazily-computed derived fields; cache invalidates on each set.\nexport function createDerivedStore<I extends object, D extends object>(\n base: Store<I>,\n derive: (inputs: I) => D,\n): DerivedStore<I, D> {\n let cachedInputs: I | undefined;\n let cachedDerived: D | undefined;\n\n const deriveCached = (inputs: I): D => {\n if (inputs !== cachedInputs) {\n cachedInputs = inputs;\n cachedDerived = derive(inputs);\n }\n return cachedDerived as D;\n };\n\n return {\n get: () => {\n const inputs = base.get();\n return { ...inputs, ...deriveCached(inputs) } as I & D;\n },\n set: (patch) => {\n // For function-form patches, materialize the full (inputs + derived) state\n // so the callback sees the same shape that `get()` returns — otherwise\n // `s.filteredOptions` etc. would be undefined at runtime despite type-checking.\n if (typeof patch === \"function\") {\n base.set((inputs) => {\n const full = { ...inputs, ...deriveCached(inputs) } as I & D;\n return patch(full);\n });\n } else {\n base.set(patch);\n }\n },\n // `prev` order intentional: prev for this notification was last notification's\n // `next` and is still in the single-slot cache → free hit. Computing `next`\n // after warms the cache for the next notification's prev.\n subscribe: (listener) =>\n base.subscribe((next, prev) => {\n const prevFull = { ...prev, ...deriveCached(prev) } as I & D;\n const nextFull = { ...next, ...deriveCached(next) } as I & D;\n listener(nextFull, prevFull);\n }),\n };\n}\n","let injected = false;\n\n/** Inject core + appearance CSS into document.head once. Idempotent. */\nexport function injectStyles() {\n if (injected || typeof document === \"undefined\") return;\n if (document.querySelector(\"style[data-magicx-aia]\")) {\n injected = true;\n return;\n }\n injected = true;\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-magicx-aia\", \"\");\n style.textContent = STYLES;\n document.head.appendChild(style);\n}\n\n// Replaced at build time by tsup.config.core.ts / vitest.config.ts\ndeclare const __MAGICX_AC_STYLES__: string;\nconst STYLES = __MAGICX_AC_STYLES__;\n","type EventMap = Record<string, readonly unknown[]>;\ntype Listener<Args extends readonly unknown[]> = (...args: Args) => void;\n\n// Typed multi-listener emitter — on() adds, returned fn removes that listener, emit() fans out.\nexport class Emitter<E extends EventMap> {\n private listeners: { [K in keyof E]?: Set<Listener<E[K]>> } = {};\n\n on<K extends keyof E>(event: K, listener: Listener<E[K]>): () => void {\n // Wrap each registration in its own closure so the same `listener` reference\n // registered twice gets two independent Set slots (and unsubscribing one\n // doesn't take down the other).\n const entry: Listener<E[K]> = (...args) => listener(...args);\n let set = this.listeners[event];\n if (!set) {\n set = new Set();\n this.listeners[event] = set;\n }\n set.add(entry);\n return () => {\n this.listeners[event]?.delete(entry);\n };\n }\n\n emit<K extends keyof E>(event: K, ...args: E[K]): void {\n const set = this.listeners[event];\n if (!set) return;\n for (const listener of set) listener(...args);\n }\n\n hasListeners<K extends keyof E>(event: K): boolean {\n return (this.listeners[event]?.size ?? 0) > 0;\n }\n\n clear(): void {\n this.listeners = {};\n }\n}\n","// Keyed timer registry — schedule() auto-cancels the prior timer under the same key; clearAll() on destroy.\nexport class TimerScheduler {\n private timers = new Map<string, ReturnType<typeof setTimeout>>();\n\n schedule(key: string, fn: () => void, ms: number): void {\n this.clear(key);\n const id = setTimeout(() => {\n this.timers.delete(key);\n fn();\n }, ms);\n this.timers.set(key, id);\n }\n\n clear(key: string): void {\n const id = this.timers.get(key);\n if (id !== undefined) {\n clearTimeout(id);\n this.timers.delete(key);\n }\n }\n\n clearAll(): void {\n for (const id of this.timers.values()) clearTimeout(id);\n this.timers.clear();\n }\n}\n","import type {\n AppearanceMode,\n AutocompleteResult,\n CompletedParamState,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions } from \"../utils/filtering\";\nimport { ModeController } from \"../utils/modeController\";\nimport { reconcileParams } from \"../utils/segments\";\nimport { sendTelemetry, type TelemetrySource } from \"../utils/telemetry\";\nimport { FetchController } from \"./controllers/fetchController\";\nimport { KeyboardController } from \"./controllers/keyboardController\";\nimport { PillsController } from \"./controllers/pillsController\";\nimport { deriveAll } from \"./derive/state\";\nimport { previousGraphemeBoundary, setCursorOffset } from \"./dom/cursorUtils\";\nimport { tryPromoteExactMatch } from \"./promotion/promote\";\nimport { ReEditManager } from \"./reEdit/ReEditManager\";\nimport { buildDropdownOnly, updateDropdownOnly } from \"./render/renderDropdownOnly\";\nimport { buildDOM, type DOMRefs, updateDOM } from \"./render/renderInput\";\nimport { computeSelectionPatch } from \"./selection/SelectionFlow\";\nimport { createDerivedStore, createStore } from \"./state\";\nimport { injectStyles } from \"./styleInjector\";\nimport type { CoreInputState, CoreOptions, CoreState, RenderMode } from \"./types\";\nimport { Emitter } from \"./util/Emitter\";\nimport { TimerScheduler } from \"./util/TimerScheduler\";\n\nexport type AIAutocompleteEvents = {\n submit: [result: AutocompleteResult];\n error: [error: Error];\n change: [text: string];\n paramsChange: [params: CompletedParamState[]];\n stateChange: [state: CoreState];\n focus: [];\n blur: [];\n};\n\n// `update()` excludes event-listener props — they're registered once at construction.\n// Callers who need to swap a handler must use `on()` (and call the returned unsubscribe).\nexport type CoreUpdateOptions = Partial<\n Omit<\n CoreOptions,\n \"onSubmit\" | \"onError\" | \"onChange\" | \"onParamsChange\" | \"onStateChange\" | \"onFocus\" | \"onBlur\"\n >\n>;\n\nconst TIMER_NEW_PARAM = \"newParam\";\nconst TIMER_SUGGESTION_REMOVAL = \"suggestionRemoval\";\nconst TIMER_SELECTION_ANIMATION = \"selectionAnimation\";\nconst NEW_PARAM_SHIMMER_MS = 650;\n\nlet idCounter = 0;\nfunction stableId(): string {\n return `:ac-${++idCounter}:`;\n}\n\nconst SELECTION_ANIMATION_MS = 500;\n\nfunction initialInputs(): CoreInputState {\n return {\n text: \"\",\n completedParams: [],\n suggestions: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: false,\n isReady: false,\n error: null,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n editingParam: null,\n editingAnchor: null,\n editingTail: null,\n caretOffset: null,\n inSelectionAnimation: false,\n };\n}\n\nexport class AIAutocomplete {\n private inputStore = createStore<CoreInputState>(initialInputs());\n private store: ReturnType<\n typeof createDerivedStore<CoreInputState, ReturnType<typeof deriveAll>>\n >;\n private _listboxId = stableId();\n private opts: CoreOptions;\n private fetchController: FetchController;\n private keyboardController: KeyboardController;\n private pillsController: PillsController;\n private reEdit: ReEditManager;\n private modeController: ModeController | null = null;\n private container: HTMLElement;\n private unsubscribers: (() => void)[] = [];\n private renderMode: RenderMode;\n private domRefs: DOMRefs | null = null;\n private dropdownRefs: { dropdown: HTMLElement } | null = null;\n private timers = new TimerScheduler();\n private emitter = new Emitter<AIAutocompleteEvents>();\n private sessionId: string = crypto.randomUUID();\n\n // Stable dispatchers — bound once, handed to controllers / renderers when listeners exist.\n // Avoids allocating a fresh arrow per `getOnSubmit()` / error-getter call.\n private readonly emitSubmit = (result: AutocompleteResult) => this.emitter.emit(\"submit\", result);\n private readonly emitError = (err: Error) => this.emitter.emit(\"error\", err);\n\n constructor(container: HTMLElement, opts: CoreOptions = {}) {\n this.container = container;\n this.opts = opts;\n this.renderMode = opts.renderMode ?? \"full\";\n\n // Wrap the raw input store with a lazily-derived layer. `derive` closes\n // over `this.opts` so changes via `update()` are picked up on the next\n // get() (a fresh `store.set({})` invalidates the memoization).\n this.store = createDerivedStore(this.inputStore, (inputs) => deriveAll(inputs, this.opts));\n\n // Register any opts.on* callbacks as the initial listener set. Use `on()`\n // after construction for additional or replacement listeners — `update()`\n // does NOT swap these (intentional, since stable proxies from React refs\n // depend on it).\n if (opts.onSubmit) this.emitter.on(\"submit\", opts.onSubmit);\n if (opts.onError) this.emitter.on(\"error\", opts.onError);\n if (opts.onChange) this.emitter.on(\"change\", opts.onChange);\n if (opts.onParamsChange) this.emitter.on(\"paramsChange\", opts.onParamsChange);\n if (opts.onStateChange) this.emitter.on(\"stateChange\", opts.onStateChange);\n if (opts.onFocus) this.emitter.on(\"focus\", opts.onFocus);\n if (opts.onBlur) this.emitter.on(\"blur\", opts.onBlur);\n\n // Apply controlled initial values\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n\n // Controllers\n this.pillsController = new PillsController(this.store, {\n onPillSelected: ({ rawQuery, selectedPill, otherPills }) => {\n this.fireTelemetry(\"pill\", {\n raw_query: rawQuery,\n selected_pill: selectedPill,\n other_pills: otherPills,\n });\n },\n });\n\n this.reEdit = new ReEditManager({\n store: this.store,\n scheduleSetCursor: (offset) => this.scheduleSetCursor(offset),\n fireTelemetry: (type, data) => this.fireTelemetry(type, data),\n startSelectionAnimationTimer: () => this.startSelectionAnimationTimer(),\n });\n\n this.fetchController = new FetchController(\n this.store,\n () => this.opts.apiConfig,\n () => this.opts.optionOverrides,\n () => this.opts.maskCompletedText,\n () => (this.emitter.hasListeners(\"error\") ? this.emitError : undefined),\n () => this.sessionId,\n {\n onAutoMatch: ({ active, matched, rawQuery }) => {\n this.fireTelemetry(\"option\", {\n raw_query: rawQuery,\n selected_option: matched.text,\n other_options: (active.options ?? [])\n .filter((o) => o.text !== matched.text)\n .map((o) => o.text),\n });\n },\n },\n );\n\n this.keyboardController = new KeyboardController(this.store, {\n columns: opts.columns ?? 2,\n listboxId: this.listboxId,\n getOnSubmit: () => (this.emitter.hasListeners(\"submit\") ? this.emitSubmit : undefined),\n // Tier 1 (full) auto-resets after submit; Tier 2/3 leave it to the consumer.\n afterSubmit: this.renderMode === \"full\" ? () => this.reset() : undefined,\n selectOption: (option) => this.selectOption(option),\n removeParamAtCaret: (offset) => this.removeParamAtCaret(offset),\n exitEditMode: () => this.exitEditMode(),\n });\n\n // Event callbacks (derived state materializes lazily through the wrapper —\n // no recompute subscriber needed).\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.text !== prev.text) this.emitter.emit(\"change\", next.text);\n if (next.completedParams !== prev.completedParams)\n this.emitter.emit(\"paramsChange\", next.completedParams);\n if (next.isFocused !== prev.isFocused) {\n if (next.isFocused) this.emitter.emit(\"focus\");\n else this.emitter.emit(\"blur\");\n }\n this.emitter.emit(\"stateChange\", next);\n }),\n );\n\n // Auto-exit re-edit + fire an immediate fetch when the user has typed past\n // their re-edited param so that the filtered options collapse to zero —\n // staying in re-edit with a dead filter just strands them in stale UI.\n this.unsubscribers.push(this.store.subscribe(() => this.maybeExitReEditOnNoMatch()));\n\n // Setup DOM based on render mode\n if (this.renderMode !== \"headless\") {\n injectStyles();\n this.setupContainer();\n }\n if (this.renderMode === \"full\") {\n this.buildAndRenderFull();\n } else if (this.renderMode === \"dropdown\") {\n this.buildAndRenderDropdown();\n }\n this.fetchController.start();\n }\n\n // === Public API ===\n\n focus() {\n this.domRefs?.input.focus();\n }\n\n blur() {\n this.domRefs?.input.blur();\n }\n\n reset() {\n // skipNextFetch suppresses the debounced fetch the FetchController would\n // otherwise schedule in response to text/params changing here — we issue\n // the empty fetch ourselves below so the new session starts immediately.\n this.store.set({\n ...initialInputs(),\n skipNextFetch: true,\n });\n this.sessionId = crypto.randomUUID();\n this.fetchController.doFetch(\"\", []);\n }\n\n destroy() {\n this.fetchController.dispose();\n this.modeController?.destroy();\n this.timers.clearAll();\n this.emitter.clear();\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n this.domRefs?.abort.abort();\n this.domRefs = null;\n this.dropdownRefs = null;\n if (this.renderMode !== \"headless\") {\n this.container.innerHTML = \"\";\n }\n }\n\n setMode(mode: AppearanceMode) {\n this.modeController?.setMode(mode);\n }\n\n setValue(text: string) {\n this.store.set({ text });\n }\n\n setCompletedParams(params: CompletedParamState[]) {\n this.store.set({ completedParams: params });\n }\n\n setActivePill(index: number) {\n this.pillsController.setActivePill(index);\n // Park the caret at the end of the text after a pill tap so the dropdown's\n // auto-trigger gate (caret-at-end) opens — and so continued typing filters\n // the newly-active pill's options instead of landing in the middle of a\n // prior token.\n const endOffset = this.store.get().text.length;\n this.store.set({ caretOffset: endOffset, isFocused: true });\n this.scheduleSetCursor(endOffset);\n }\n\n removeLastParam() {\n this.pillsController.removeLastParam();\n }\n\n /**\n * Backspace inside a completed param: drop the param's \"completed\" status so\n * it renders as plain (un-bold) text, AND remove one grapheme before the\n * caret — same single-character delete a normal Backspace would do. The\n * remaining text stays in the input so the user can continue editing what\n * they had typed instead of losing the whole phrase.\n *\n * Returns true when a param was reconciled (caller should `preventDefault`).\n */\n removeParamAtCaret(offset: number): boolean {\n const state = this.store.get();\n const { text, completedParams } = state;\n let pos = 0;\n for (let i = 0; i < completedParams.length; i++) {\n const param = completedParams[i];\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n const paramStart = idx;\n const paramEnd = idx + param.text.length;\n if (offset > paramStart && offset <= paramEnd) {\n const deleteStart = previousGraphemeBoundary(text, offset);\n const newText = text.slice(0, deleteStart) + text.slice(offset);\n const newParams = completedParams.filter((_, j) => j !== i);\n this.store.set((s) => ({\n text: newText,\n filterBase: Math.min(s.filterBase, newText.length),\n completedParams: newParams,\n pillTapped: false,\n activeDropdownIndex: -1,\n }));\n this.scheduleSetCursor(deleteStart);\n return true;\n }\n pos = paramEnd;\n }\n return false;\n }\n\n /**\n * Set the editor caret at the given plain-text offset. Uses the core's own\n * `domRefs.input` in \"full\" mode; falls back to the wrapper-provided\n * `setCursor` callback in \"headless\" mode where the wrapper owns the DOM.\n *\n * Also focuses the input — setting a selection range without focus leaves a\n * visible caret that doesn't actually accept typing, and every caller (pill\n * tap, post-promote refocus, re-edit entry, Backspace-into-param) expects\n * the editor to be focused afterwards.\n */\n private scheduleSetCursor(offset: number) {\n queueMicrotask(() => {\n const refs = this.domRefs;\n if (refs) {\n refs.input.focus();\n setCursorOffset(refs.input, offset);\n } else {\n this.opts.setCursor?.(offset);\n }\n });\n }\n\n clearNewParamId() {\n this.store.set({ newParamId: null });\n }\n\n startEditingParam(paramId: string) {\n this.reEdit.start(paramId);\n }\n\n replaceEditingRange(replacement: string): boolean {\n return this.reEdit.replaceRange(replacement);\n }\n\n exitEditMode() {\n this.reEdit.exit();\n }\n\n handleCaretAfterInput(offset: number | null) {\n this.reEdit.caretAfterInput(offset);\n }\n\n handleCaretMove(offset: number | null) {\n this.reEdit.caretMove(offset);\n }\n\n setActiveDropdownIndex(index: number) {\n this.store.set({ activeDropdownIndex: index });\n }\n\n handleTextChange(value: string) {\n this.handleChange(value);\n }\n\n handleKeyDown(e: KeyboardEvent) {\n this.keyboardController.handleKeyDown(e);\n }\n\n setFocused(focused: boolean) {\n if (this.store.get().isFocused === focused) return;\n this.store.set({ isFocused: focused });\n }\n\n /** Subscribe to state changes. Listener receives the full (input + derived) shape. */\n subscribe(listener: (state: CoreState) => void): () => void {\n return this.store.subscribe((next) => listener(next));\n }\n\n getState(): CoreState {\n return this.store.get();\n }\n\n get listboxId(): string {\n return this._listboxId;\n }\n\n get isReady(): boolean {\n return this.store.get().isReady;\n }\n\n /**\n * Subscribe to an event. Multiple listeners may register for the same event;\n * `emit` fans out to all of them. The returned function removes only the\n * listener it registered.\n *\n * Note: `opts.on*` listeners passed at construction are equivalent to calling\n * `on()` once each; their unsubscribe handles are not exposed.\n */\n on<E extends keyof AIAutocompleteEvents>(\n event: E,\n callback: (...args: AIAutocompleteEvents[E]) => void,\n ): () => void {\n return this.emitter.on(event, callback);\n }\n\n update(opts: CoreUpdateOptions) {\n Object.assign(this.opts, opts);\n if (opts.mode !== undefined) {\n this.modeController?.setMode(opts.mode);\n }\n if (opts.optionsPosition !== undefined) {\n this.container.dataset.optionsPosition = opts.optionsPosition;\n }\n if (opts.animations !== undefined) {\n this.container.dataset.animations = opts.animations ? \"on\" : \"off\";\n }\n if (opts.pillPlacement !== undefined) {\n this.container.dataset.pillPlacement = opts.pillPlacement;\n this.store.set({});\n }\n if (\n opts.dropdownTrigger !== undefined ||\n opts.closeDropdownOnBlur !== undefined ||\n opts.showNonTappableOptions !== undefined\n ) {\n // Trigger recompute so isDropdownOpen / filteredOptions update\n this.store.set({});\n }\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n }\n\n // === Public (for framework wrappers) ===\n\n selectOption(option: SuggestionOption) {\n const state = this.store.get();\n\n // Re-edit path: replace the highlighted bold param's range with the new\n // option. Bypasses the normal selectOption flow entirely.\n if (state.editingParam && state.editingAnchor != null && state.editingTail != null) {\n this.reEdit.selectOption(option);\n return;\n }\n\n const result = computeSelectionPatch(state, option);\n if (!result) return;\n\n this.fireTelemetry(\"option\", {\n raw_query: buildQuery(state.text, state.completedParams).rawQuery,\n selected_option: result.telemetry.selectedOption,\n other_options: result.telemetry.otherOptions,\n });\n\n this.store.set(result.patch);\n this.startSelectionAnimationTimer();\n\n // Suggestion removal timing depends on whether a fetch is firing.\n this.timers.clear(TIMER_SUGGESTION_REMOVAL);\n if (result.remainingActionable > 0) {\n // Cached next-pill exists; no fetch fires. Remove the just-clicked\n // suggestion after the streak animation so the next pill becomes\n // active. The animation keeps playing on the option while it's still\n // in the DOM.\n const consumed = result.consumedSuggestion;\n this.timers.schedule(\n TIMER_SUGGESTION_REMOVAL,\n () => {\n this.store.set((s) => ({\n suggestions: s.suggestions.filter((sg) => sg !== consumed),\n }));\n },\n SELECTION_ANIMATION_MS,\n );\n }\n // When `remainingActionable === 0` a fetch fires. We deliberately keep\n // the just-selected suggestion in state until the response lands — the\n // dropdown then mirrors its pill/option layout (count + widths) as the\n // loading skeleton, instead of falling back to the generic placeholder.\n }\n\n private startSelectionAnimationTimer() {\n this.timers.schedule(\n TIMER_SELECTION_ANIMATION,\n () => this.store.set({ inSelectionAnimation: false }),\n SELECTION_ANIMATION_MS,\n );\n }\n\n private fireTelemetry(type: \"pill\" | \"option\", queryData: Record<string, unknown>) {\n // Vanilla consumers don't pass `source` — derive from renderMode.\n // The React hook always uses renderMode \"headless\" but Tier 1 explicitly\n // passes source: \"full-sdk\" via opts to override.\n const source: TelemetrySource =\n this.opts.source ?? (this.renderMode === \"full\" ? \"full-sdk\" : \"headless-sdk\");\n void sendTelemetry({\n source,\n sessionId: this.sessionId,\n type,\n queryData,\n apiConfig: this.opts.apiConfig,\n });\n }\n\n private setupContainer() {\n this.container.classList.add(\"magicx-aia\");\n // In dropdown mode, pills are always in the dropdown\n this.container.dataset.pillPlacement =\n this.renderMode === \"dropdown\" ? \"dropdown\" : (this.opts.pillPlacement ?? \"inline\");\n this.container.dataset.optionsPosition = this.opts.optionsPosition ?? \"below\";\n this.container.dataset.animations = (this.opts.animations ?? true) ? \"on\" : \"off\";\n\n // ModeController\n this.modeController = new ModeController(this.container, this.opts.mode ?? \"auto\");\n }\n\n private buildAndRenderFull() {\n const self = this;\n const renderOpts = {\n store: this.store,\n listboxId: this.listboxId,\n get pillPlacement() {\n return (self.opts.pillPlacement ?? \"inline\") as \"inline\" | \"dropdown\";\n },\n get onSubmit() {\n return self.emitter.hasListeners(\"submit\") ? self.emitSubmit : undefined;\n },\n // Tier 1 only (this code path runs only for renderMode === \"full\").\n afterSubmit: () => self.reset(),\n submitButton: this.opts.submitButton,\n autoFocus: this.opts.autoFocus ?? true,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n handleKeyDown: (e: KeyboardEvent) => this.keyboardController.handleKeyDown(e),\n handleChange: (value: string) => this.handleChange(value),\n startEditingParam: (id: string) => this.startEditingParam(id),\n handleCaretAfterInput: (offset: number | null) => this.handleCaretAfterInput(offset),\n handleCaretMove: (offset: number | null) => this.handleCaretMove(offset),\n replaceEditingRange: (replacement: string) => this.replaceEditingRange(replacement),\n };\n\n this.domRefs = buildDOM(this.container, renderOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.domRefs) {\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n }\n });\n\n // Initial render\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n this.subscribeNewParamTimer();\n }\n\n private buildAndRenderDropdown() {\n const dropdownOpts = {\n store: this.store,\n listboxId: this.listboxId,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n };\n\n this.dropdownRefs = buildDropdownOnly(this.container, dropdownOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.dropdownRefs) {\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n }\n });\n\n // Initial render\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n this.subscribeNewParamTimer();\n }\n\n /** Batched render subscriber — coalesces multiple store.set calls into one DOM update. */\n private subscribeBatchedRender(render: () => void) {\n let scheduled = false;\n this.unsubscribers.push(\n this.store.subscribe(() => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n render();\n });\n }),\n );\n }\n\n /** Auto-clear newParamId after shimmer animation. */\n private subscribeNewParamTimer() {\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.newParamId && next.newParamId !== prev.newParamId) {\n this.timers.schedule(\n TIMER_NEW_PARAM,\n () => this.store.set({ newParamId: null }),\n NEW_PARAM_SHIMMER_MS,\n );\n }\n }),\n );\n }\n\n private handleChange(newValue: string) {\n const state = this.store.get();\n this.store.set({\n text: newValue,\n pillTapped: false,\n activeDropdownIndex: -1,\n });\n\n const { valid, invalid } = reconcileParams(newValue, state.completedParams);\n if (invalid.length > 0) {\n this.store.set({ completedParams: valid });\n }\n\n this.maybePromoteExactMatch(newValue);\n }\n\n /**\n * In re-edit mode, once the user has typed enough that no *tappable* options\n * still match (non-tappable options are kept by filterOptions regardless of\n * the query, so they don't count as \"still matching\"), exit re-edit and\n * fire an immediate fetch so the dropdown swaps over to fresh server\n * suggestions instead of staying frozen on a dead filter.\n *\n * Guarded against re-entry: once we exit, editingParam is null and the\n * subscription early-returns on subsequent fires.\n */\n private maybeExitReEditOnNoMatch() {\n const s = this.store.get();\n if (!s.editingParam || s.editingAnchor == null) return;\n // Skip until the user has actually started typing — when the param is\n // still in completedParams, the editQuery is \"\" and matches everything.\n if (s.completedParams.some((p) => p.id === s.editingParam?.id)) return;\n const editCaret = s.caretOffset ?? s.editingAnchor;\n const editQuery = s.text.slice(s.editingAnchor, editCaret);\n const matched = filterOptions(s.editingParam.options, editQuery);\n if (matched.some((o) => o.is_tappable)) return;\n this.reEdit.exit();\n const { rawQuery, completedParams } = buildQuery(s.text, s.completedParams);\n this.fetchController.doFetch(rawQuery, completedParams);\n }\n\n /**\n * When the user has typed text that exactly matches (case-insensitive) one\n * of the active suggestion's options, promote it to a completed param right\n * away. The fetchController does the same check when the debounced fetch\n * lands; doing it instantly here means bold styling appears as soon as the\n * option is fully typed, without waiting 100–300ms for the round-trip.\n */\n private maybePromoteExactMatch(newValue: string) {\n const s = this.store.get();\n const result = tryPromoteExactMatch({\n mode: \"fresh\",\n text: newValue,\n completedParams: s.completedParams,\n suggestions: s.suggestions,\n filterBase: s.filterBase,\n filterInProgress: s.filterInProgress,\n });\n if (!result) return;\n this.store.set(result.patch);\n }\n}\n","import {\n type ClipboardEvent as ReactClipboardEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\";\nimport {\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n setCursorOffset,\n} from \"../core/dom/cursorUtils\";\nimport { renderEditableContent } from \"../core/render/renderEditable\";\nimport type { CompletedParamState, Segment } from \"../types\";\n\nlet plaintextOnlyCache: boolean | undefined;\nfunction supportsPlaintextOnly(): boolean {\n if (plaintextOnlyCache !== undefined) return plaintextOnlyCache;\n if (typeof document === \"undefined\") return false;\n const probe = document.createElement(\"div\");\n probe.setAttribute(\"contenteditable\", \"plaintext-only\");\n plaintextOnlyCache = probe.contentEditable === \"plaintext-only\";\n return plaintextOnlyCache;\n}\n\nexport interface UseContentEditableEditorOptions {\n /** Derived segments (text + bold completed-param runs) for the editor body. */\n segments: readonly Segment[];\n /** The most recently promoted param — shimmer + post-promote refocus key. */\n newParamId: string | null;\n /** The bold param currently being re-edited (or null). */\n editingParam: CompletedParamState | null;\n /** Plain-text offset where re-edit started; caret parks here on entry. */\n editingAnchor: number | null;\n /** Live caret offset within the editor, used by post-promote refocus. */\n caretOffset: number | null;\n /** Server-suggested placeholder (rendered via ::before when empty). */\n placeholderText: string;\n /** Whether the editor currently has focus — passes through to segment renderer. */\n isFocused: boolean;\n /** ARIA `aria-expanded` value for the input. */\n isDropdownOpen: boolean;\n /** ARIA `aria-controls` value pointing at the listbox. */\n listboxId: string;\n /** ARIA `aria-activedescendant` value pointing at the highlighted option (or undefined). */\n activeDescendantId: string | undefined;\n /** Focus the editor on mount (Tier 1 default). */\n autoFocus: boolean;\n /** Forwarded to the core whenever the plain-text content changes. */\n handleTextChange: (value: string) => void;\n /** Forwarded to the core for keyboard handling. */\n handleKeyDown: (e: ReactKeyboardEvent<HTMLElement> | globalThis.KeyboardEvent) => void;\n /** Forwarded to the core after each input event (extends edit tail, etc.). */\n handleCaretAfterInput: (offset: number | null) => void;\n /** Forwarded to the core on selectionchange (exits re-edit when caret leaves). */\n handleCaretMove: (offset: number | null) => void;\n /** Forwarded to the core when the caret lands inside a bold param's strong. */\n startEditingParam: (id: string) => void;\n /** Forwarded to the core during a `beforeinput` — atomic re-edit replacement. */\n replaceEditingRange: (replacement: string) => boolean;\n /** Forwarded to the core on native focus/blur. */\n setFocused: (focused: boolean) => void;\n}\n\nexport interface UseContentEditableEditorReturn {\n inputRef: React.RefObject<HTMLDivElement>;\n // Spread onto the contentEditable element; consumer supplies className.\n editorProps: {\n ref: React.RefObject<HTMLDivElement>;\n contentEditable: boolean;\n suppressContentEditableWarning: true;\n tabIndex: 0;\n role: \"combobox\";\n \"aria-autocomplete\": \"list\";\n \"aria-haspopup\": \"listbox\";\n \"aria-controls\": string;\n \"aria-expanded\": boolean;\n \"aria-activedescendant\": string | undefined;\n spellCheck: true;\n enterKeyHint: \"send\";\n onInput: () => void;\n onKeyDown: (e: ReactKeyboardEvent<HTMLDivElement>) => void;\n onCompositionStart: () => void;\n onCompositionEnd: () => void;\n onPaste: (e: ReactClipboardEvent<HTMLDivElement>) => void;\n onFocus: () => void;\n onBlur: () => void;\n };\n /** Current plain-text content of the editor (used by submit). */\n getPlainText: () => string;\n /** Imperative focus / blur (used by the parent's imperative handle). */\n focus: () => void;\n blur: () => void;\n}\n\n/**\n * Owns every concern that's specific to running the autocomplete on top of a\n * contentEditable host: composition state, caret tracking, selectionchange,\n * `beforeinput` interception, paste sanitization, plaintext-only feature\n * detection, segment rendering, post-promote refocus, and re-edit caret park.\n *\n * The hook stays React-agnostic above the contentEditable adapter — see\n * `core/render/renderEditable.ts` for the underlying DOM mutations. Callers\n * spread `editorProps` onto a `<div>` (className is theirs to provide).\n */\nexport function useContentEditableEditor(\n opts: UseContentEditableEditorOptions,\n): UseContentEditableEditorReturn {\n const {\n segments,\n newParamId,\n editingParam,\n editingAnchor,\n caretOffset,\n placeholderText,\n isFocused,\n isDropdownOpen,\n listboxId,\n activeDescendantId,\n autoFocus,\n handleTextChange,\n handleKeyDown,\n handleCaretAfterInput,\n handleCaretMove,\n startEditingParam,\n replaceEditingRange,\n setFocused,\n } = opts;\n\n const inputRef = useRef<HTMLDivElement>(null);\n const composingRef = useRef(false);\n const lastSeenParamIdRef = useRef(\"\");\n const lastEditingIdRef = useRef(\"\");\n const caretOffsetRef = useRef<number | null>(null);\n // Set in the input event handler; selectionchange suppresses post-input\n // caret-move tracking within this window so typing doesn't get treated\n // as navigation.\n const lastInputAtRef = useRef(0);\n\n caretOffsetRef.current = caretOffset;\n\n // Auto-focus on mount once the host element is mounted.\n useEffect(() => {\n if (!autoFocus) return;\n const el = inputRef.current;\n if (!el) return;\n if (document.activeElement === el) {\n setFocused(true);\n } else {\n el.focus();\n }\n }, [autoFocus, setFocused]);\n\n // `selectionchange` is the canonical signal for \"caret moved\" in\n // contentEditable land. Anchored inside the editor: a caret that lands\n // inside a `<strong>` triggers re-edit mode; a caret that leaves the\n // current editing region exits it.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const doc = el.ownerDocument ?? document;\n const onSelectionChange = () => {\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n if (!sel.anchorNode || !el.contains(sel.anchorNode)) return;\n const anchor = sel.anchorNode;\n const startEl =\n anchor.nodeType === Node.ELEMENT_NODE ? (anchor as Element) : anchor.parentElement;\n const strong = startEl?.closest<HTMLElement>('strong[data-seg=\"completed\"][data-param-id]');\n const enclosing = strong?.dataset.paramId ?? null;\n if (enclosing && enclosing !== editingParam?.id) {\n startEditingParam(enclosing);\n return;\n }\n if (performance.now() - lastInputAtRef.current < 50) return;\n handleCaretMove(getCursorOffset(el));\n };\n doc.addEventListener(\"selectionchange\", onSelectionChange);\n return () => doc.removeEventListener(\"selectionchange\", onSelectionChange);\n }, [editingParam, startEditingParam, handleCaretMove]);\n\n // Render segments imperatively into the contentEditable. useLayoutEffect\n // runs before paint so the caret is restored without a one-frame flicker.\n // MUST run before the post-promote refocus + re-edit caret park effects\n // below — keep this declaration order.\n useLayoutEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n renderEditableContent({\n input: el,\n segments: segments as Segment[],\n newParamId,\n editingParamId: editingParam?.id ?? null,\n placeholderText: placeholderText ?? \"\",\n isFocused,\n });\n }, [segments, newParamId, editingParam, placeholderText, isFocused]);\n\n // After a fresh option selection (newParamId changed), refocus the editor\n // and place the caret at the end of the just-promoted segment. Mirrors the\n // vanilla core's `justSelected` logic in renderInput.ts.\n useLayoutEffect(() => {\n const previous = lastSeenParamIdRef.current;\n const current = newParamId ?? \"\";\n lastSeenParamIdRef.current = current;\n if (!current || current === previous) return;\n const el = inputRef.current;\n if (!el) return;\n el.focus();\n // Every promote path stamps `caretOffset` with the position right after\n // the new param's trailing space, so use it. Read via ref so the effect\n // stays gated on newParamId (not every caret-move).\n const desired = caretOffsetRef.current ?? plainTextLength(el);\n setCursorOffset(el, desired);\n }, [newParamId]);\n\n // On re-edit-mode entry, park the caret just BEFORE the bold strong so\n // typing/backspace via the `beforeinput` intercept replaces the param\n // cleanly (instead of inserting mid-letter inside the bold span).\n useLayoutEffect(() => {\n const previous = lastEditingIdRef.current;\n const current = editingParam?.id ?? \"\";\n lastEditingIdRef.current = current;\n if (!current || current === previous || editingAnchor == null) return;\n const el = inputRef.current;\n if (!el) return;\n setCursorOffset(el, editingAnchor);\n }, [editingParam, editingAnchor]);\n\n const fireInput = useCallback(() => {\n if (composingRef.current) return;\n const el = inputRef.current;\n if (!el) return;\n const raw = extractPlainText(el);\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const next = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n handleTextChange(next);\n }, [handleTextChange]);\n\n const handleInputEvent = useCallback(() => {\n lastInputAtRef.current = performance.now();\n fireInput();\n const el = inputRef.current;\n if (el) handleCaretAfterInput(getCursorOffset(el));\n }, [fireInput, handleCaretAfterInput]);\n\n // React's synthetic `onBeforeInput` is wired to the legacy `textInput`\n // event and doesn't reliably fire for `delete*` input types, so we attach\n // a native `beforeinput` listener directly on the editor.\n useEffect(() => {\n const el = inputRef.current;\n if (!el) return;\n const onBeforeInput = (e: Event) => {\n const inputEvent = e as InputEvent;\n const t = inputEvent.inputType;\n if (t === \"insertParagraph\" || t === \"insertLineBreak\" || t === \"insertFromDrop\") {\n e.preventDefault();\n return;\n }\n if (t.startsWith(\"insert\") || t.startsWith(\"delete\")) {\n const replacement = t.startsWith(\"delete\") ? \"\" : (inputEvent.data ?? \"\");\n if (replaceEditingRange(replacement)) {\n e.preventDefault();\n }\n }\n };\n el.addEventListener(\"beforeinput\", onBeforeInput);\n return () => el.removeEventListener(\"beforeinput\", onBeforeInput);\n }, [replaceEditingRange]);\n\n const handleCompositionStart = useCallback(() => {\n composingRef.current = true;\n }, []);\n\n const handleCompositionEnd = useCallback(() => {\n composingRef.current = false;\n fireInput();\n }, [fireInput]);\n\n const handlePaste = useCallback(\n (e: ReactClipboardEvent<HTMLDivElement>) => {\n e.preventDefault();\n const el = inputRef.current;\n if (!el) return;\n const text = (e.clipboardData.getData(\"text/plain\") ?? \"\").replace(/\\r?\\n/g, \" \");\n if (!text) return;\n const doc = el.ownerDocument ?? document;\n const sel = doc.getSelection();\n if (!sel || sel.rangeCount === 0) return;\n const range = sel.getRangeAt(0);\n if (!el.contains(range.startContainer)) return;\n range.deleteContents();\n const node = doc.createTextNode(text);\n range.insertNode(node);\n range.setStartAfter(node);\n range.collapse(true);\n sel.removeAllRanges();\n sel.addRange(range);\n fireInput();\n },\n [fireInput],\n );\n\n const handleKeyDownReact = useCallback(\n (e: ReactKeyboardEvent<HTMLDivElement>) => handleKeyDown(e),\n [handleKeyDown],\n );\n\n const handleFocus = useCallback(() => setFocused(true), [setFocused]);\n const handleBlur = useCallback(() => setFocused(false), [setFocused]);\n\n const focus = useCallback(() => inputRef.current?.focus(), []);\n const blur = useCallback(() => inputRef.current?.blur(), []);\n const getPlainText = useCallback(() => {\n const el = inputRef.current;\n return el ? extractPlainText(el) : \"\";\n }, []);\n\n const ceMode = supportsPlaintextOnly() ? \"plaintext-only\" : \"true\";\n\n return {\n inputRef,\n editorProps: {\n ref: inputRef,\n contentEditable: ceMode as unknown as boolean,\n suppressContentEditableWarning: true,\n tabIndex: 0,\n role: \"combobox\",\n \"aria-autocomplete\": \"list\",\n \"aria-haspopup\": \"listbox\",\n \"aria-controls\": listboxId,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n spellCheck: true,\n enterKeyHint: \"send\",\n onInput: handleInputEvent,\n onKeyDown: handleKeyDownReact,\n onCompositionStart: handleCompositionStart,\n onCompositionEnd: handleCompositionEnd,\n onPaste: handlePaste,\n onFocus: handleFocus,\n onBlur: handleBlur,\n },\n getPlainText,\n focus,\n blur,\n };\n}\n"],"mappings":"ubAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,oBAAAE,GAAA,2BAAAC,GAAA,sBAAAC,KAAA,eAAAC,GAAAL,ICAA,IAAAM,EAOO,iBCPP,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAqKhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,GAAQ,CAAC,UAAY,wCAAwC,aAAe,2CAA2C,WAAa,yCAAyC,MAAQ,oCAAoC,kBAAoB,gDAAgD,aAAe,2CAA2C,WAAa,yCAAyC,YAAc,yCAAyC,EC1K3c,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmFhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,GAAQ,CAAC,SAAW,+CAA+C,QAAU,8CAA8C,QAAU,8CAA8C,aAAe,mDAAmD,YAAc,kDAAkD,iBAAmB,sDAAsD,ECxFrY,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAoFhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,EAAQ,CAAC,KAAO,6BAA6B,KAAO,6BAA6B,OAAS,+BAA+B,QAAU,gCAAgC,SAAW,iCAAiC,cAAgB,sCAAsC,OAAS,8BAA8B,ECpDzS,IAAAC,GAAA,6BAnBJC,GAA2B,CAAC,IAAK,EAAE,EAEzC,SAASC,GAAeC,EAAuB,CAC7C,OAAIA,IAAU,EAAU,GACpBA,IAAU,EAAU,GACjB,GACT,CAEO,SAASC,GAAS,CACvB,MAAAC,EACA,gBAAAC,EACA,aAAAC,EACA,QAAAC,EACA,QAAAC,CACF,EAAkB,CAChB,OAAIA,GAAWJ,EAAM,SAAW,KAE5B,QAAC,QAAK,UAAWK,EAAO,KAAM,6BAA2B,GACtD,SAAAT,GAAyB,IAAI,CAACU,EAAGC,OAChC,QAAC,QAEC,yBAAuB,GACvB,UAAW,GAAGF,EAAO,IAAI,IAAIF,EAAUE,EAAO,QAAU,EAAE,IAAIA,EAAO,QAAQ,GAC7E,MAAO,CAAE,MAAOC,EAAG,QAAST,GAAeU,CAAC,CAAE,GAHzC,QAAQD,CAAC,EAIhB,CACD,EACH,KAKF,QAAC,QAAK,UAAWD,EAAO,KAAM,6BAA4BD,EAAU,GAAK,OACtE,SAAAJ,EAAM,IAAI,CAACQ,EAAMD,OAChB,QAAC,UAEC,KAAK,SACL,gBAAc,GACd,mBAAkBH,EAAU,GAAK,OACjC,SAAU,GACV,gBAAiB,GACjB,+BAA8B,GAC9B,UAAW,GAAGC,EAAO,IAAI,IAAIF,EAAUE,EAAO,QAAU,EAAE,IAAIE,IAAMN,GAAmB,CAACG,EAAUC,EAAO,OAAS,EAAE,IAAID,EAAUC,EAAO,SAAW,EAAE,GACtJ,MAAO,CAAE,QAASR,GAAeU,CAAC,CAAE,EACpC,YAAcE,GAAMA,EAAE,eAAe,EACrC,QAASL,EAAU,OAAY,IAAMF,EAAaK,CAAC,EACnD,SAAUH,EAET,SAAAI,EAAK,MAbD,GAAGA,EAAK,IAAI,IAAIA,EAAK,IAAI,EAchC,CACD,EACH,CAEJ,CCtEA,IAAAE,GAA6D,iBCA7D,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAwDhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,GAAQ,CAAC,cAAgB,4CAA4C,KAAO,kCAAkC,EC7DrH,IAAAC,GAA4C,iBCA5C,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAuVhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,EAAQ,CAAC,KAAO,mCAAmC,OAAS,qCAAqC,QAAU,sCAAsC,SAAW,uCAAuC,YAAc,0CAA0C,YAAc,0CAA0C,IAAM,kCAAkC,QAAU,sCAAsC,UAAY,wCAAwC,QAAU,sCAAsC,QAAU,sCAAsC,YAAc,0CAA0C,iBAAmB,+CAA+C,gBAAkB,8CAA8C,aAAe,2CAA2C,eAAiB,6CAA6C,cAAgB,2CAA2C,ED7R74B,IAAAC,GAAA,6BAlDC,SAASC,GAAe,CAC7B,OAAAC,EACA,cAAAC,EACA,SAAAC,EACA,YAAAC,EACA,GAAAC,EACA,QAAAC,CACF,EAAwB,CACtB,GAAM,CAACC,EAASC,CAAU,KAAI,aAAS,EAAK,EACtCC,KAAW,WAAkD,MAAS,KAE5E,cAAU,IACD,IAAM,aAAaA,EAAS,OAAO,EACzC,CAAC,CAAC,EAEL,IAAMC,EAAe,IAAM,CACrBJ,GAAW,CAACL,EAAO,aAAeM,IACtCC,EAAW,EAAI,EACfL,EAASF,CAAM,EACf,aAAaQ,EAAS,OAAO,EAC7BA,EAAS,QAAU,WAAW,IAAMD,EAAW,EAAK,EAAG,GAAG,EAC5D,EAEMG,EAAY,CAChBC,EAAO,KACPV,GAAiB,CAACI,EAAUM,EAAO,YAAc,GACjDX,EAAO,YAAcW,EAAO,SAAWA,EAAO,YAC9CL,EAAUK,EAAO,QAAU,EAC7B,EACG,OAAO,OAAO,EACd,KAAK,GAAG,EAEX,SACE,SAAC,OACC,GAAIP,EACJ,KAAK,SACL,kBAAgB,GAChB,mBAAkBC,EAAU,GAAK,OACjC,gBAAeJ,EACf,UAAWS,EACX,SAAUL,GAAW,CAACL,EAAO,YAAc,GAAK,EAChD,QAASS,EACT,UAAYG,GAAM,CACZ,CAACP,GAAWL,EAAO,cAAgBY,EAAE,MAAQ,SAAWA,EAAE,MAAQ,OACpEA,EAAE,eAAe,EACjBH,EAAa,EAEjB,EACA,aAAc,CAACJ,GAAWL,EAAO,YAAcG,EAAc,OAE7D,qBAAC,OAAI,UAAWQ,EAAO,QAAS,KAChC,QAAC,OAAI,UAAWA,EAAO,YAAa,KACpC,SAAC,QAAK,UAAWA,EAAO,QACrB,UAAAX,EAAO,KAAO,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,GAAKA,EAAO,KACvDA,EAAO,QAAO,QAAC,QAAK,UAAWW,EAAO,IAAM,SAAAX,EAAO,IAAI,GAC1D,GACF,CAEJ,CFdU,IAAAa,GAAA,6BA3CH,SAASC,GAAe,CAC7B,QAAAC,EACA,YAAAC,EACA,SAAAC,EACA,YAAAC,EACA,UAAAC,EACA,QAAAC,CACF,EAAwB,CACtB,IAAMC,KAAU,WAAuB,IAAI,EACrC,CAACC,EAAmBC,CAAoB,KAAI,aAAS,EAAK,EAEhE,uBAAU,IAAM,CACd,IAAMC,EAAKH,EAAQ,QACnB,GAAI,CAACG,EAAI,OAET,IAAMC,EAAS,IAAM,CACnBF,EAAqBC,EAAG,aAAeA,EAAG,UAAYA,EAAG,aAAe,CAAC,CAC3E,EAEAA,EAAG,iBAAiB,SAAUC,EAAQ,CAAE,QAAS,EAAK,CAAC,EACvD,IAAMC,EAAiB,IAAI,eAAeD,CAAM,EAChD,OAAAC,EAAe,QAAQF,CAAE,EAElB,IAAM,CACXA,EAAG,oBAAoB,SAAUC,CAAM,EACvCC,EAAe,WAAW,CAC5B,CACF,EAAG,CAAC,CAAC,KAML,oBAAgB,IAAM,CACpB,IAAMF,EAAKH,EAAQ,QACdG,GACLD,EAAqBC,EAAG,aAAeA,EAAG,UAAYA,EAAG,aAAe,CAAC,CAC3E,EAAG,CAACT,CAAO,CAAC,KAGV,QAAC,OAAI,UAAWY,GAAO,cAAe,YAAWL,EAAoB,GAAK,OACxE,oBAAC,OAAI,IAAKD,EAAS,UAAWM,GAAO,KAClC,SAAAZ,EAAQ,IAAI,CAACa,EAAQC,OACpB,QAACC,GAAA,CAEC,OAAQF,EACR,cAAeC,IAAMb,EACrB,SAAUC,EACV,YAAa,IAAMC,EAAYW,CAAC,EAChC,GAAI,GAAGV,CAAS,WAAWU,CAAC,GAC5B,QAAST,GANJQ,EAAO,IAOd,CACD,EACH,EACF,CAEJ,CIvCI,IAAAG,EAAA,6BA1BEC,GAA+B,CAAC,IAAK,IAAK,GAAG,EAE5C,SAASC,GAAuB,CACrC,YAAAC,EACA,YAAAC,EACA,SAAAC,EACA,YAAAC,EACA,OAAAC,EACA,GAAAC,EACA,UAAAC,EACA,MAAAC,EACA,YAAAC,EACA,UAAAC,EAAY,GACZ,UAAAC,EAAY,EACd,EAAgC,CAE9B,IAAMC,EADmBX,EAAY,CAAC,GACJ,SAAW,CAAC,EACxCY,EAAaH,GAAaF,GAASA,EAAM,OAAS,GAAKC,EACvDK,EAAeF,EAAQ,OAAS,EAIhCG,EAAwBJ,GAAa,CAACG,EACtCE,EAAYX,IAAWS,GAAgBD,GAAcF,GAE3D,SACE,QAAC,OACC,GAAIL,EACJ,KAAK,UACL,oBAAkB,GAClB,mBAAkBK,EAAY,GAAK,OACnC,UAAW,GAAGM,GAAO,QAAQ,IAAID,EAAYC,GAAO,QAAU,EAAE,IAAIV,GAAa,EAAE,GACnF,YAAcW,GAAMA,EAAE,eAAe,EAEpC,UAAAR,GAAaF,GAASA,EAAM,OAAS,GAAKC,MACzC,OAAC,OAAI,UAAWQ,GAAO,QAAS,mBAAiB,GAC/C,mBAACE,GAAA,CACC,MAAOX,EACP,gBAAiB,EACjB,aAAcC,EACd,QAAO,GACP,QAASE,EACX,EACF,EAEDD,IAAc,CAACF,GAASA,EAAM,SAAW,IAAMG,MAC9C,OAAC,OAAI,UAAWM,GAAO,QAAS,mBAAiB,GAC/C,mBAACE,GAAA,CAAS,MAAO,CAAC,EAAG,gBAAiB,EAAG,aAAc,IAAM,CAAC,EAAG,QAAO,GAAC,QAAO,GAAC,EACnF,EAEDL,MACC,OAACM,GAAA,CACC,QAASR,EACT,YAAaV,EACb,SAAUC,EACV,YAAaC,EACb,UAAWE,EACX,QAASK,EACX,EAEDI,MACC,OAAC,OAAI,UAAWE,GAAO,aAAc,yBAAuB,GACzD,SAAAlB,GAA6B,IAAKsB,MACjC,OAAC,QAAsB,UAAWJ,GAAO,YAAa,MAAO,CAAE,MAAOI,CAAE,GAA7D,OAAOA,CAAC,EAAwD,CAC5E,EACH,GAEJ,CAEJ,CC1EA,GAAI,OAAO,SAAa,KAAe,CAAC,SAAS,eAAe,mBAAmB,EAAG,CACpF,IAAMC,EAAI,SAAS,cAAc,OAAO,EACxCA,EAAE,GAAK,oBACPA,EAAE,YAAc;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgGhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CC3FA,IAAMC,GAAwB,4BAM1BC,GACJ,SAASC,IAAiD,CACxD,GAAID,KAAc,OAAW,OAAOA,GAGpC,IAAME,EAAa,WAA+D,KAC/E,UACH,GAAI,CAACA,EACH,OAAAF,GAAY,KACL,KAET,GAAI,CACFA,GAAY,IAAIE,EAAU,OAAW,CAAE,YAAa,UAAW,CAAC,CAClE,MAAQ,CACNF,GAAY,IACd,CACA,OAAOA,IAAa,IACtB,CAEA,SAASG,GAAoBC,EAAYC,EAA4B,CACnE,IAAIC,EAAiBF,EACrB,KAAOE,GAAKA,IAAMD,GAAM,CACtB,GAAIC,EAAE,WAAa,KAAK,cACXA,EACJ,QAAQP,EAAqB,EAAG,MAAO,GAEhDO,EAAIA,EAAE,UACR,CACA,MAAO,EACT,CAEA,SAASC,GAAiBF,EAA+B,CACvD,OAAQA,EAAK,eAAiB,UAAU,iBAAiBA,EAAM,WAAW,UAAW,CACnF,WAAWD,EAAM,CACf,OAAOD,GAAoBC,EAAMC,CAAI,EAAI,WAAW,cAAgB,WAAW,aACjF,CACF,CAAC,CACH,CAEO,SAASG,GAAiBH,EAA2B,CAC1D,IAAMI,EAASF,GAAiBF,CAAI,EAChCK,EAAM,GACNN,EAAOK,EAAO,SAAS,EAC3B,KAAOL,GACLM,GAAON,EAAK,KACZA,EAAOK,EAAO,SAAS,EAEzB,OAAOC,CACT,CAEO,SAASC,GAAgBN,EAA2B,CACzD,IAAMI,EAASF,GAAiBF,CAAI,EAChCO,EAAQ,EACRR,EAAOK,EAAO,SAAS,EAC3B,KAAOL,GACLQ,GAASR,EAAK,KAAK,OACnBA,EAAOK,EAAO,SAAS,EAEzB,OAAOG,CACT,CAMO,SAASC,EAAgBR,EAAkC,CAChE,IAAMS,GAAOT,EAAK,eAAiB,UAAU,aAAa,EAC1D,GAAI,CAACS,GAAOA,EAAI,aAAe,EAAG,OAAO,KACzC,IAAMC,EAAaD,EAAI,WACjBE,EAAeF,EAAI,aACzB,GAAI,CAACC,GAAc,CAACV,EAAK,SAASU,CAAU,EAAG,OAAO,KAItD,GAAIA,EAAW,WAAa,KAAK,aAAc,CAC7C,IAAME,EAAKF,EACX,GAAIZ,GAAoBc,EAAIZ,CAAI,GAAKY,IAAOZ,EAAM,OAAO,KACzD,IAAIa,EAAS,EACb,QAASC,EAAI,EAAGA,EAAIH,GAAgBG,EAAIF,EAAG,WAAW,OAAQE,IAC5DD,GAAUE,GAAyBH,EAAG,WAAWE,CAAC,EAAGd,CAAI,EAG3D,OAAOa,EAASG,GAAiBJ,EAAIZ,CAAI,CAC3C,CAGA,OADIU,EAAW,WAAa,KAAK,WAC7BZ,GAAoBY,EAAYV,CAAI,EAAU,KAE3CgB,GAAiBN,EAAYV,CAAI,EAAIW,CAC9C,CAEA,SAASI,GAAyBhB,EAAYC,EAA2B,CACvE,GAAID,EAAK,WAAa,KAAK,UACzB,OAAOD,GAAoBC,EAAMC,CAAI,EAAI,EAAKD,EAAc,KAAK,OAEnE,GAAIA,EAAK,WAAa,KAAK,aAAc,MAAO,GAChD,IAAMa,EAAKb,EACX,GAAIa,EAAG,QAAQlB,EAAqB,EAAG,MAAO,GAC9C,IAAIa,EAAQ,EACZ,QAAWU,KAAS,MAAM,KAAKL,EAAG,UAAU,EAC1CL,GAASQ,GAAyBE,EAAOjB,CAAI,EAE/C,OAAOO,CACT,CAEA,SAASS,GAAiBE,EAAclB,EAA2B,CACjE,IAAMI,EAASF,GAAiBF,CAAI,EAChCO,EAAQ,EACRR,EAAOK,EAAO,SAAS,EAC3B,KAAOL,GAAM,CAGX,GAFIA,IAASmB,GAETA,EAAO,WAAa,KAAK,cAAiBA,EAAmB,SAASnB,CAAI,EAC5E,OAAOQ,EAETA,GAASR,EAAK,KAAK,OACnBA,EAAOK,EAAO,SAAS,CACzB,CACA,OAAOG,CACT,CAaO,SAASY,EAAgBnB,EAAmBa,EAAsB,CACvE,IAAMO,EAAMpB,EAAK,eAAiB,SAC5BS,EAAMW,EAAI,aAAa,EAC7B,GAAI,CAACX,EAAK,OAEV,IAAMY,EAAU,KAAK,IAAI,EAAG,KAAK,IAAIR,EAAQP,GAAgBN,CAAI,CAAC,CAAC,EAC7DI,EAASF,GAAiBF,CAAI,EAChCsB,EAAa,EACbJ,EAAsB,KACtBK,EAAe,EACfxB,EAAOK,EAAO,SAAS,EACvBoB,EAAwB,KAE5B,KAAOzB,GAAM,CACX,IAAM0B,EAAM1B,EAAK,KAAK,OACtB,GAAIsB,EAAUC,EAAaG,EAAK,CAC9BP,EAASnB,EACTwB,EAAeF,EAAUC,EACzB,KACF,CACA,GAAID,IAAYC,EAAaG,EAAK,CAChC,IAAMC,EAAOtB,EAAO,SAAS,EACzBsB,GAGFR,EAASQ,EACTH,EAAe,IAEfL,EAASnB,EACTwB,EAAeE,GAEjB,KACF,CACAH,GAAcG,EACdD,EAAWzB,EACXA,EAAOK,EAAO,SAAS,CACzB,CAEA,IAAMuB,EAAQP,EAAI,YAAY,EAC9B,GAAIF,EAAQ,CAKV,IAAMU,EAAeV,EAAO,eAAe,QAAqB,8BAA8B,EAC1FU,GAAgBA,IAAiB5B,GAAQA,EAAK,SAAS4B,CAAY,EACjEL,IAAiB,EACnBI,EAAM,eAAeC,CAAY,EACxBL,IAAiBL,EAAO,KAAK,OACtCS,EAAM,cAAcC,CAAY,EAEhCD,EAAM,SAAST,EAAQK,CAAY,EAGrCI,EAAM,SAAST,EAAQK,CAAY,CAEvC,MAAWC,EACTG,EAAM,SAASH,EAAUA,EAAS,KAAK,MAAM,EAE7CG,EAAM,SAAS3B,EAAM,CAAC,EAExB2B,EAAM,SAAS,EAAI,EACnBlB,EAAI,gBAAgB,EACpBA,EAAI,SAASkB,CAAK,CACpB,CAMO,SAASE,GAAc7B,EAA4B,CACxD,IAAMa,EAASL,EAAgBR,CAAI,EACnC,OAAIa,GAAU,KAAa,GACpBA,GAAUP,GAAgBN,CAAI,CACvC,CAOO,SAAS8B,GAAyBC,EAAclB,EAAwB,CAC7E,GAAIA,GAAU,EAAG,MAAO,GACxB,IAAMmB,EAAMpC,GAAqB,EACjC,GAAI,CAACoC,EAAK,OAAOnB,EAAS,EAC1B,IAAMoB,EAAQF,EAAK,MAAM,EAAGlB,CAAM,EAC9BqB,EAAO,EACX,OAAW,CAAE,MAAAC,CAAM,IAAKH,EAAI,QAAQC,CAAK,EACnCE,EAAQtB,IAAQqB,EAAOC,GAE7B,OAAOD,CACT,CC9OA,IAAAE,EAOO,iBCQA,SAASC,EAAWC,EAAcC,EAA0D,CACjG,IAAIC,EAASF,EACPG,EAAqC,CAAC,EACtCC,EAAuC,CAAC,EAE9C,QAAWC,KAASJ,EAAiB,CACnC,IAAMK,GAASH,EAAWE,EAAM,IAAI,GAAK,GAAK,EAC9CF,EAAWE,EAAM,IAAI,EAAIC,EAGzB,IAAMC,EAAc,KADJF,EAAM,KAAK,YAAY,EAAE,QAAQ,OAAQ,GAAG,CAC5B,IAAIC,CAAK,KAGnCE,EAAQN,EAAO,QAAQG,EAAM,IAAI,EACnCG,IAAU,KACZN,EAASA,EAAO,MAAM,EAAGM,CAAK,EAAID,EAAcL,EAAO,MAAMM,EAAQH,EAAM,KAAK,MAAM,GAGxFD,EAAc,KAAK,CAAE,GAAGC,EAAO,YAAAE,CAAY,CAAC,CAC9C,CAEA,MAAO,CAAE,SAAUL,EAAQ,gBAAiBE,CAAc,CAC5D,CC5BO,SAASK,GACdC,EACAC,EACAC,EACQ,CACR,OAAID,EAAa,GAAK,CAACC,EAAwBD,EAC3CD,EAAK,YAAY,EAAE,WAAWE,EAAgB,YAAY,CAAC,EACtDA,EAAgB,OAElBD,CACT,CAQO,SAASE,GACdH,EACAC,EACAG,EACQ,CACR,IAAMC,EAAYL,EAAK,MAAMC,CAAU,EACvC,GAAIG,GAAgBH,IAAe,GAAKD,EAAKC,EAAa,CAAC,IAAM,IAC/D,OAAOI,EAET,IAAMC,EAAWD,EAAU,QAAQ,GAAG,EACtC,OAAOC,IAAa,GAAK,GAAKD,EAAU,MAAMC,EAAW,CAAC,CAC5D,CAOO,SAASC,GAAkBC,EAAgBC,EAA4B,CAE5E,IAAMC,EAAUF,EAAO,QAAQ,EAAE,QAAQ,OAAQ,GAAG,EACpD,GAAIE,EAAQ,SAAW,GAAKD,EAAW,SAAW,EAAG,MAAO,GAE5D,IAAME,EAAQD,EAAQ,MAAM,GAAG,EACzBE,EAAcH,EAAW,YAAY,EAG3C,QAASI,EAAI,EAAGA,EAAIF,EAAM,OAAQE,IAAK,CACrC,IAAMC,EAAYH,EAAM,MAAME,CAAC,EAAE,KAAK,GAAG,EACzC,GAAID,EAAY,WAAWE,EAAU,YAAY,CAAC,EAAG,CACnD,IAAMC,EAAcL,EAAQ,OAASI,EAAU,OAC/C,OAAON,EAAO,OAASO,CACzB,CACF,CAEA,MAAO,EACT,CAKO,SAASC,GACdC,EACAC,EACoB,CACpB,GAAI,CAACD,EAAS,MAAO,CAAC,EACtB,IAAMP,EAAUQ,EAAM,UAAU,EAChC,GAAI,CAACR,EAAS,OAAOO,EACrB,IAAME,EAAQT,EAAQ,YAAY,EAClC,OAAOO,EAAQ,OAAQG,GAAM,CAACA,EAAE,aAAeA,EAAE,KAAK,YAAY,EAAE,SAASD,CAAK,CAAC,CACrF,CAKO,SAASE,GACdJ,EACAC,EACyB,CACzB,GAAI,CAACD,EAAS,OAAO,KACrB,IAAMP,EAAUQ,EAAM,KAAK,EAC3B,GAAI,CAACR,EAAS,OAAO,KACrB,IAAMS,EAAQT,EAAQ,YAAY,EAClC,OAAOO,EAAQ,KAAMG,GAAMA,EAAE,aAAeA,EAAE,KAAK,YAAY,IAAMD,CAAK,GAAK,IACjF,CCzFO,IAAMG,GAAN,KAAqB,CAG1B,YACUC,EACAC,EAAuB,OAC/B,CAFQ,eAAAD,EACA,UAAAC,EAJV,KAAQ,WAAoC,KA6B5C,KAAQ,eAAkB,GAA2B,CACnD,KAAK,UAAU,QAAQ,KAAO,EAAE,QAAU,OAAS,OACrD,EAzBE,KAAK,MAAM,CACb,CAEA,QAAQA,EAAsB,CAC5B,KAAK,eAAe,EACpB,KAAK,KAAOA,EACZ,KAAK,MAAM,CACb,CAEA,SAAU,CACR,KAAK,eAAe,CACtB,CAEQ,OAAQ,CACV,KAAK,OAAS,QAChB,KAAK,aAAL,KAAK,WAAe,OAAO,WAAW,8BAA8B,GACpE,KAAK,WAAW,iBAAiB,SAAU,KAAK,cAAc,EAC9D,KAAK,UAAU,QAAQ,KAAO,KAAK,WAAW,QAAU,OAAS,SAEjE,KAAK,UAAU,QAAQ,KAAO,KAAK,IAEvC,CAMQ,gBAAiB,CACvB,KAAK,YAAY,oBAAoB,SAAU,KAAK,cAAc,CACpE,CACF,EClCO,SAASC,GAAeC,EAAcC,EAAmD,CAC9F,IAAMC,EAAoB,CAAC,EACvBC,EAAM,EAEV,QAAWC,KAASH,EAAiB,CACnC,IAAMI,EAAML,EAAK,QAAQI,EAAM,KAAMD,CAAG,EACpCE,IAAQ,KACRA,EAAMF,GACRD,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOF,EAAK,MAAMG,EAAKE,CAAG,CAAE,CAAC,EAE3DH,EAAO,KAAK,CAAE,KAAM,YAAa,MAAOE,EAAM,KAAM,MAAAA,CAAM,CAAC,EAC3DD,EAAME,EAAMD,EAAM,KAAK,OACzB,CAEA,IAAME,EAAYN,EAAK,MAAMG,CAAG,EAChC,OAAIG,GACFJ,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOI,CAAU,CAAC,EAGzCJ,CACT,CAKO,SAASK,GACdP,EACAC,EACkE,CAClE,IAAMO,EAA+B,CAAC,EAChCC,EAAiC,CAAC,EACpCN,EAAM,EAEV,QAAWC,KAASH,EAAiB,CACnC,IAAMI,EAAML,EAAK,QAAQI,EAAM,KAAMD,CAAG,EACpCE,IAAQ,GACVI,EAAQ,KAAKL,CAAK,GAElBI,EAAM,KAAKJ,CAAK,EAChBD,EAAME,EAAMD,EAAM,KAAK,OAE3B,CAEA,MAAO,CAAE,MAAAI,EAAO,QAAAC,CAAQ,CAC1B,CC5CO,IAAMC,GAAN,KAAmB,CAKxB,YAAoBC,EAA2B,CAA3B,YAAAA,EAJpB,KAAQ,QAAyB,KACjC,KAAQ,UAA2B,KACnC,KAAQ,gBAA0C,KAG5CA,EAAO,cACT,KAAK,QAAUA,EAAO,YAE1B,CAGA,MAAM,SAASC,EAAe,GAAwB,CACpD,GAAI,CAACA,GAAgB,KAAK,SAAW,CAAC,KAAK,UAAU,EACnD,OAAO,KAAK,QAEd,GAAI,CAACA,GAAgB,KAAK,gBACxB,OAAO,KAAK,gBAEd,KAAK,gBAAkB,KAAK,QAAQ,EACpC,GAAI,CACF,OAAO,MAAM,KAAK,eACpB,QAAE,CACA,KAAK,gBAAkB,IACzB,CACF,CAEA,MAAc,SAA2B,CACvC,IAAMC,EAAS,MAAM,KAAK,OAAO,eAAe,EAChD,YAAK,QAAUA,EAAO,YACtB,KAAK,UAAYA,EAAO,WAAa,KAC9B,KAAK,OACd,CAEQ,WAAqB,CAC3B,OAAI,KAAK,WAAa,KAAa,GAC5B,KAAK,IAAI,GAAK,KAAK,UAAY,GACxC,CACF,ECvCO,IAAMC,GAAqB,kCACrBC,GAA2B,GAAGD,EAAkB,eAGvDE,GAAgB,IAAI,QAEnB,SAASC,GAAoBC,EAAiD,CACnF,OAAOA,GAAQ,OAAS,aAC1B,CAEO,SAASC,GAAgBD,EAA8C,CAC5E,GAAI,GAACA,GAAUD,GAAoBC,CAAM,GACzC,OAAOA,CACT,CAEO,SAASE,GAAgBF,EAAyC,CACvE,IAAIG,EAAUL,GAAc,IAAIE,EAAO,cAAc,EACrD,OAAKG,IACHA,EAAU,IAAIC,GAAaJ,CAAM,EACjCF,GAAc,IAAIE,EAAO,eAAgBG,CAAO,GAE3CA,CACT,CAMO,SAASE,GAAaC,EAA+C,CAC1E,MAAO,CACL,eAAgB,mBAChB,GAAIA,GAAW,eAAiB,CAAE,mBAAoBA,EAAU,aAAc,EAC9E,GAAGA,GAAW,OAChB,CACF,CAQO,SAASC,GAAsBD,EAAsC,CAC1E,IAAME,EAAeP,GAAgBK,CAAS,EACxCG,EAASD,GAAc,OAC7B,OAAKC,GACUD,GAAc,YAAc,YACzB,QAAU,SAAS,KAAKC,CAAM,CAAC,GAAK,UAAUA,CAAM,GAFlD,IAGtB,CCzBA,SAASC,GAAwBC,EAAkC,CAEjE,OADaA,GAAmBC,IACpB,QAAQ,oBAAqB,qBAAqB,CAChE,CASA,eAAeC,GAAkBC,EAA+C,CAC9E,OAAIC,GAAoBD,CAAS,EAExB,UADO,MAAME,GAAgBF,CAAS,EAAE,SAAS,CAClC,GAEjBG,GAAsBH,CAAS,CACxC,CAQA,eAAsBI,GAAcC,EAAsC,CACxE,GAAI,CACF,IAAMC,EAAWV,GAAwBS,EAAM,WAAW,QAAQ,EAC5DE,EAAUC,GAAaH,EAAM,SAAS,EACtCI,EAAa,MAAMV,GAAkBM,EAAM,SAAS,EACtDI,IAAYF,EAAQ,cAAgBE,GAExC,IAAMC,EAAO,KAAK,UAAU,CAC1B,OAAQL,EAAM,OACd,WAAYA,EAAM,UAClB,KAAMA,EAAM,KACZ,GAAI,IAAI,KAAK,EAAE,YAAY,EAC3B,WAAYA,EAAM,SACpB,CAAC,EAED,MAAM,MAAMC,EAAU,CAAE,OAAQ,OAAQ,QAAAC,EAAS,KAAAG,CAAK,CAAC,CACzD,MAAQ,CAER,CACF,CCvDA,IAAMC,GAAc,SAEhBC,GAAsB,GAE1B,SAASC,IAA4B,CACnC,OAAO,OAAO,WAAW,CAC3B,CAEA,SAASC,GAAYC,EAA4BC,EAAsC,CACrF,MAAO,CACL,YAAaD,EAAM,YACnB,KAAMA,EAAM,KACZ,GAAIC,GAAe,CAAE,KAAMD,EAAM,IAAK,EACtC,KAAMA,EAAM,IACd,CACF,CAEA,SAASE,GACPC,EACAC,EACAH,EACAI,EACqB,CACrB,IAAMC,EAAWF,EAAgB,KAC9BG,GAAMA,EAAE,OAAS,WAAaA,EAAE,UAAU,qBAC7C,GAAG,UAAU,sBACPC,EAAsB,OAAOF,GAAa,SAAWA,EAAW,OAEtE,MAAO,CACL,KAAM,CACJ,UAAWH,EACX,iBAAkBC,EAAgB,IAAKG,GAAMR,GAAYQ,EAAGN,CAAW,CAAC,EACxE,GAAIO,GAAuB,MAAQ,CAAE,sBAAuBA,CAAoB,CAClF,EACA,KAAM,CACJ,WAAYV,GAAkB,EAC9B,WAAY,IAAI,KAAK,EAAE,YAAY,EACnC,SAAU,OAAO,UAAc,IAAc,UAAU,SAAW,QAClE,eAAgBF,GAChB,WAAYS,CACd,CACF,CACF,CAEA,eAAeI,GACbC,EACAC,EACAC,EACAC,EACAC,EACmB,CACnB,OAAO,MAAMJ,EAAU,CACrB,OAAQ,OACR,QAAS,CAAE,GAAGC,EAAS,cAAe,UAAUC,CAAK,EAAG,EACxD,KAAAC,EACA,OAAAC,CACF,CAAC,CACH,CAEA,eAAsBC,GACpBZ,EACAC,EACAY,EAM+B,CAC/B,IAAMC,EAAYD,EAAQ,UACpBf,EAAc,CAACe,EAAQ,kBACvBH,EAAOX,GAAiBC,EAAUC,EAAiBH,EAAae,EAAQ,SAAS,EACjFL,EAAUO,GAAaD,CAAS,EAChCP,EAAWO,GAAW,UAAYE,GAClCC,EAAW,KAAK,UAAUP,CAAI,EAGpC,GAAIQ,GAAoBJ,CAAS,EAAG,CAClC,IAAMK,EAAUC,GAAgBN,CAAS,EACnCL,EAAQ,MAAMU,EAAQ,SAAS,EAEjCE,EAAW,MAAMf,GAAQC,EAAUC,EAASC,EAAOQ,EAAUJ,EAAQ,MAAM,EAG/E,GAAIQ,EAAS,SAAW,IAAK,CAC3B,IAAMC,EAAW,MAAMH,EAAQ,SAAS,EAAI,EAC5CE,EAAW,MAAMf,GAAQC,EAAUC,EAASc,EAAUL,EAAUJ,EAAQ,MAAM,CAChF,CAEA,GAAI,CAACQ,EAAS,GACZ,MAAM,IAAI,MAAM,cAAcA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAGxE,OAAOA,EAAS,KAAK,CACvB,CAGA,IAAME,EAAaC,GAAsBV,CAAS,EAC9C,CAACS,GAAc,CAAC7B,KAClBA,GAAsB,GAEtB,QAAQ,KACN,iGACF,GAEE6B,IAAYf,EAAQ,cAAgBe,GAExC,IAAMF,EAAW,MAAM,MAAMd,EAAU,CACrC,OAAQ,OACR,QAAAC,EACA,KAAMS,EACN,OAAQJ,EAAQ,MAClB,CAAC,EAED,GAAI,CAACQ,EAAS,GACZ,MAAM,IAAI,MAAM,cAAcA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAGxE,OAAOA,EAAS,KAAK,CACvB,CClIO,SAASI,GACdC,EACAC,EACc,CACd,OAAKA,EACED,EAAY,IAAKE,GAAM,CAC5B,IAAMC,EAAKF,EAAUC,EAAE,IAAI,EAC3B,GAAI,CAACC,EAAI,OAAOD,EAChB,IAAME,EAAQD,EAAG,EAAE,EACnB,GAAIC,EAAM,SAAW,EAAG,OAAOF,EAC/B,IAAMG,EAAgB,IAAI,IAAID,EAAM,IAAKE,GAAMA,EAAE,IAAI,CAAC,EAChDC,GAAWL,EAAE,SAAW,CAAC,GAAG,OAAQI,GAAM,CAACD,EAAc,IAAIC,EAAE,IAAI,CAAC,EAC1E,MAAO,CAAE,GAAGJ,EAAG,QAAS,CAAC,GAAGE,EAAO,GAAGG,CAAO,CAAE,CACjD,CAAC,EATsBP,CAUzB,CCDA,IAAMQ,GAAc,IACdC,GAAmB,IACnBC,GAAiB,EAYVC,GAAN,KAAsB,CAO3B,YACUC,EACAC,EACAC,EACAC,EACAC,EACAC,EACAC,EAAsC,CAAC,EAC/C,CAPQ,WAAAN,EACA,kBAAAC,EACA,wBAAAC,EACA,0BAAAC,EACA,gBAAAC,EACA,kBAAAC,EACA,eAAAC,EAbV,KAAQ,aAAe,EACvB,KAAQ,gBAA0C,KAClD,KAAQ,cAAsD,KAC9D,KAAQ,kBAA0D,KAClE,KAAQ,YAAmC,IAUxC,CAEH,OAAQ,CAEN,KAAK,QAAQ,GAAI,CAAC,CAAC,EAGnB,IAAIC,EAAW,KAAK,MAAM,IAAI,EAAE,KAC5BC,EAAa,KAAK,MAAM,IAAI,EAAE,gBAClC,KAAK,YAAc,KAAK,MAAM,UAAWC,GAAS,EAC5CA,EAAK,OAASF,GAAYE,EAAK,kBAAoBD,KACrDD,EAAWE,EAAK,KAChBD,EAAaC,EAAK,gBAClB,KAAK,cAAc,EAEvB,CAAC,CACH,CAEA,SAAU,CACR,KAAK,iBAAiB,MAAM,EAC5B,KAAK,YAAY,EACjB,KAAK,cAAc,CACrB,CAEA,MAAM,QAAQC,EAAkBC,EAAkC,CAChE,KAAK,iBAAiB,MAAM,EAC5B,IAAMC,EAAa,IAAI,gBACvB,KAAK,gBAAkBA,EACvB,IAAMC,EAAU,EAAE,KAAK,aACjBC,EAAgB,KAAK,MAAM,IAAI,EAAE,KAAK,OAE5C,KAAK,MAAM,IAAI,CAAE,UAAW,GAAM,MAAO,IAAK,CAAC,EAE/C,GAAI,CACF,IAAMC,EAAM,MAAMC,GAAiBN,EAAUC,EAAW,CACtD,UAAW,KAAK,aAAa,EAC7B,kBAAmB,KAAK,qBAAqB,EAC7C,OAAQC,EAAW,OACnB,UAAW,KAAK,aAAa,CAC/B,CAAC,EAED,GAAIC,IAAY,KAAK,aAAc,OAEnC,IAAII,EAAiBC,GACnBH,EAAI,KAAK,aAAe,CAAC,EACzB,KAAK,mBAAmB,CAC1B,EAEMI,EAAQJ,EAAI,KAAK,OAAS,CAAC,EAC3BK,EAAYD,EAAMA,EAAM,OAAS,CAAC,EAClCE,EAAc,KAAK,MAAM,IAAI,EAAE,KACjCC,EACAC,EAEJ,GAAIH,GAAW,QAAU,cAAe,CACtCG,EAAmB,GACnB,IAAMC,EAAgBH,EAAY,YAAY,EAAE,YAAYD,EAAU,KAAK,YAAY,CAAC,EACxFE,EAAaE,IAAkB,GAAKA,EAAgBV,CACtD,MACES,EAAmB,GACnBD,EAAaR,EAKf,IAAMW,EADaR,EAAe,OAAQS,GAAMA,EAAE,OAAS,aAAa,EAC9C,CAAC,EACvBC,EAAyC,KAC7C,GAAIF,EAAQ,CACV,IAAMG,EAAQC,GAAmBR,EAAaC,EAAYC,CAAgB,EACpEO,EAAQC,GAAeN,EAAO,QAASG,CAAK,EAC9CE,IACFH,EAAa,CACX,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMF,EAAO,KACb,KAAMK,EAAM,KACZ,KAAMA,EAAM,KACZ,eAAgBL,EAAO,KACvB,sBAAuBA,EAAO,KAC9B,QAASA,EAAO,SAAW,CAAC,EAC5B,SAAUK,EAAM,QAClB,EACAb,EAAiBA,EAAe,OAAQS,GAAMA,IAAMD,CAAM,EAC1D,KAAK,UAAU,cAAc,CAAE,OAAAA,EAAQ,QAASK,EAAO,SAAApB,CAAS,CAAC,EAErE,CAEA,KAAK,MAAM,IAAKgB,IAAO,CACrB,YAAaT,EACb,UAAW,GACX,QAASF,EAAI,KAAK,UAAY,GAC9B,aAAcL,EACd,oBAAqB,GACrB,WAAAY,EACA,iBAAAC,EACA,GAAII,EAAa,CAAE,gBAAiB,CAAC,GAAGD,EAAE,gBAAiBC,CAAU,CAAE,EAAI,CAAC,CAC9E,EAAE,CACJ,OAASK,EAAK,CACZ,GAAInB,IAAY,KAAK,aAAc,CACjC,IAAMoB,EAAcD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EACtE,KAAK,MAAM,IAAI,CAAE,MAAOC,EAAa,UAAW,EAAM,CAAC,EACvD,KAAK,WAAW,IAAIA,CAAW,CACjC,CACF,CACF,CAEQ,eAAgB,CAItB,GAHA,KAAK,YAAY,EACH,KAAK,MAAM,IAAI,EAEnB,cAAe,CACvB,KAAK,MAAM,IAAI,CAAE,cAAe,EAAM,CAAC,EACvC,MACF,CAEA,IAAMC,EAAgBC,GAA6B,CACjD,IAAMT,EAAI,KAAK,MAAM,IAAI,EACzB,GAAI,CAACA,EAAE,MAAQA,EAAE,gBAAgB,SAAW,EAC1C,YAAK,QAAQ,GAAI,CAAC,CAAC,EACZ,GAGT,IAAMU,EAAkBV,EAAE,YACvB,OAAQW,GAAmBA,EAAG,OAAS,aAAa,EACpD,IAAKA,GAAmBA,EAAG,IAAI,EAC/B,KAAK,GAAG,EACLC,EAAUC,GAAoBb,EAAE,KAAMA,EAAE,WAAYU,CAAe,EACnEI,EAAeX,GAAmBH,EAAE,KAAMY,EAASZ,EAAE,gBAAgB,EAErED,EADaC,EAAE,YAAY,OAAQW,GAAmBA,EAAG,OAAS,aAAa,EAC3D,CAAC,EAErBI,GADkBhB,EAASiB,GAAcjB,EAAO,QAASe,CAAY,EAAI,CAAC,GACvC,OAAQG,GAAwBA,EAAE,WAAW,EAChFC,EAAgBnB,EAASM,GAAeN,EAAO,QAASe,CAAY,IAAM,KAAO,GAEjFK,EAAiBL,EAAa,KAAK,EAAE,OAAS,EAKpD,GAJIC,EAAiB,OAAS,GAAK,CAACG,GAAiBC,GAKnDnB,EAAE,gBAAgB,SAAW,GAC7BA,EAAE,KAAK,OAAS,GAChBU,EAAgB,OAAS,GACzBA,EAAgB,YAAY,EAAE,WAAWV,EAAE,KAAK,YAAY,CAAC,EAE7D,MAAO,GAGT,GAAM,CAAE,SAAAhB,EAAU,gBAAiBoC,CAAc,EAAIC,EAAWrB,EAAE,KAAMA,EAAE,eAAe,EACnFsB,EAAatC,EAAS,OAASgB,EAAE,aAAa,OAC9CuB,EAAW,KAAK,IAAIvC,EAAS,OAASgB,EAAE,aAAa,MAAM,EACjE,OAAIsB,GAAcC,GAAYd,GAC5B,KAAK,QAAQzB,EAAUoC,CAAa,EAC7B,IAEF,EACT,EAEA,KAAK,cAAgB,WAAW,IAAM,CAChCZ,EAAapC,EAAc,GACzB,KAAK,mBAAmB,aAAa,KAAK,iBAAiB,CAEnE,EAAGF,EAAW,EAEd,KAAK,kBAAoB,WAAW,IAAMsC,EAAa,CAAC,EAAGrC,EAAgB,CAC7E,CAEQ,aAAc,CAChB,KAAK,eAAe,aAAa,KAAK,aAAa,EACnD,KAAK,mBAAmB,aAAa,KAAK,iBAAiB,EAC/D,KAAK,cAAgB,KACrB,KAAK,kBAAoB,IAC3B,CACF,ECjMA,SAASqD,GAAcC,EAAqC,CAC1D,OAAIA,aAAkB,qBAAuBA,aAAkB,iBACtDA,EAAO,gBAAkB,MAAQA,EAAO,iBAAmBA,EAAO,MAAM,OAE7EA,aAAkB,aAAeA,EAAO,aAAa,gBAAgB,EAChEC,GAAcD,CAAM,EAEtB,EACT,CAEA,SAASE,GAAuBF,EAA2C,CACzE,OAAIA,aAAkB,aAAeA,EAAO,aAAa,gBAAgB,EAChEG,EAAgBH,CAAM,EAExB,IACT,CAEO,IAAMI,GAAN,KAAyB,CAC9B,YACUC,EACAC,EACR,CAFQ,WAAAD,EACA,SAAAC,CACP,CAEH,cAAc,EAAkB,CAC9B,IAAMC,EAAQ,KAAK,MAAM,IAAI,EACvB,CAAE,UAAAC,EAAW,YAAAC,CAAY,EAAI,KAAK,IAClCC,EAAU,KAAK,oBAAoB,EACnCC,EAAWF,EAAY,EACvBG,EAAkB,KAAK,mBAAmBF,CAAO,EAEvD,OAAQ,EAAE,IAAK,CACb,IAAK,YAAa,CAChB,IAAMG,EAAcd,GAAc,EAAE,MAAM,EAIpCe,EAAa,CAAC,CAACP,EAAM,aAC3B,GAAI,CAACM,GAAe,CAACC,GAAcP,EAAM,oBAAsB,EAAG,MAGlE,GADA,EAAE,eAAe,EACb,CAACA,EAAM,gBAAkBA,EAAM,sBAAsB,OAAS,EAAG,CACnE,KAAK,MAAM,IAAI,CAAE,WAAY,GAAM,oBAAqBK,EAAgB,CAAC,GAAK,CAAE,CAAC,EACjF,KACF,CACA,GAAIA,EAAgB,SAAW,EAAG,OAClC,IAAMG,EAAaH,EAAgB,QAAQL,EAAM,mBAAmB,EAC9DS,EAAUD,EAAaH,EAAgB,OAAS,EAAIG,EAAa,EAAI,EAC3E,KAAK,MAAM,IAAI,CAAE,oBAAqBH,EAAgBI,CAAO,CAAE,CAAC,EAChE,KACF,CACA,IAAK,UAAW,CACd,GAAIJ,EAAgB,SAAW,GAAKL,EAAM,oBAAsB,EAAG,MAEnE,GADA,EAAE,eAAe,EACbA,EAAM,oBAAsBG,EAAS,CACvC,KAAK,MAAM,IAAI,CAAE,oBAAqB,EAAG,CAAC,EAC1C,KACF,CACA,IAAMK,EAAaH,EAAgB,QAAQL,EAAM,mBAAmB,EAC9DU,EAAUF,EAAa,EAAIA,EAAa,EAAIH,EAAgB,OAAS,EAC3E,KAAK,MAAM,IAAI,CAAE,oBAAqBA,EAAgBK,CAAO,CAAE,CAAC,EAChE,KACF,CACA,IAAK,aAAc,CAKjB,GAAIV,EAAM,qBAAuB,EAAG,CAGlC,GAFA,EAAE,eAAe,EACLA,EAAM,oBAAsBG,EAC9BA,EAAU,EAAG,CACrB,IAAMQ,EAAgBX,EAAM,oBAAsB,EAEhDW,EAAgBX,EAAM,gBAAgB,QACtCA,EAAM,gBAAgBW,CAAa,GAAG,aAEtC,KAAK,MAAM,IAAI,CAAE,oBAAqBA,CAAc,CAAC,CAEzD,CACA,KACF,CAGA,GAAIX,EAAM,cAAgB,EAAE,kBAAkB,aAAeA,EAAM,aAAe,KAAM,CACtF,EAAE,eAAe,EACjB,IAAMY,EAAS,EAAE,OAAO,QAAqB,kBAAkB,GAAK,EAAE,OAChEC,EAAOb,EAAM,YACnB,KAAK,IAAI,eAAe,EACxBc,EAAgBF,EAAQC,CAAI,EAC5B,KACF,CACcrB,GAAc,EAAE,MAAM,GACvBQ,EAAM,sBAAsB,OAAS,IAChD,EAAE,eAAe,EACjB,KAAK,mBAAmB,CAAC,GAE3B,KACF,CACA,IAAK,YAAa,CAIhB,GAAIA,EAAM,qBAAuB,EAAG,CAElC,GADA,EAAE,eAAe,EACbA,EAAM,oBAAsBG,EAAU,EAAG,CAC3C,IAAMY,EAAef,EAAM,oBAAsB,EAC7Ce,GAAgB,GAAKf,EAAM,gBAAgBe,CAAY,GAAG,aAC5D,KAAK,MAAM,IAAI,CAAE,oBAAqBA,CAAa,CAAC,CAExD,CACA,KACF,CAEA,GAAIf,EAAM,cAAgB,EAAE,kBAAkB,aAAeA,EAAM,eAAiB,KAAM,CACxF,EAAE,eAAe,EACjB,IAAMY,EAAS,EAAE,OAAO,QAAqB,kBAAkB,GAAK,EAAE,OAChEI,EAAShB,EAAM,cACrB,KAAK,IAAI,eAAe,EACxBc,EAAgBF,EAAQI,CAAM,EAC9B,KACF,CACA,KACF,CACA,IAAK,YAAa,CAKhB,GADIhB,EAAM,cACN,CAAC,KAAK,IAAI,mBAAoB,MAClC,IAAMiB,EAAStB,GAAuB,EAAE,MAAM,EAC9C,GAAIsB,GAAU,KAAM,MAChB,KAAK,IAAI,mBAAmBA,CAAM,GACpC,EAAE,eAAe,EAEnB,KACF,CACA,IAAK,QAAS,CAEZ,GADA,EAAE,eAAe,EAEfjB,EAAM,qBAAuB,GAC7BA,EAAM,gBAAgBA,EAAM,mBAAmB,GAAG,YAElD,KAAK,cAAcA,EAAM,oBAAqBA,EAAM,gBAAiBC,CAAS,UACrEG,EAAU,CACnB,GAAM,CAAE,SAAAc,EAAU,gBAAiBC,CAAY,EAAIC,EACjDpB,EAAM,KACNA,EAAM,eACR,EACAI,EAAS,CACP,MAAOJ,EAAM,KAAK,KAAK,EACvB,UAAWkB,EACX,iBAAkBC,CACpB,CAAC,EACD,KAAK,IAAI,cAAc,CACzB,CACA,KACF,CACA,IAAK,MAAO,CACV,IAAME,EAAqB,CAACrB,EAAM,MAAQ,CAAC,CAACA,EAAM,gBAC5CsB,EACJtB,EAAM,qBAAuB,GAC7BA,EAAM,gBAAgBA,EAAM,mBAAmB,GAAG,YAIpD,GAAIqB,GAAsB,CAACC,EAAsB,CAI/C,EAAE,eAAe,EACjB,IAAMC,EAAavB,EAAM,gBASzB,GARA,KAAK,MAAM,IAAKwB,IAAO,CACrB,KAAMD,EACN,WAAYA,EAAW,OACvB,YAAaC,EAAE,YAAY,OAAQC,GAAOA,EAAG,OAAS,aAAa,CACrE,EAAE,EAIE,EAAE,kBAAkB,YAAa,CACnC,IAAMb,EAAS,EAAE,OAAO,QAAqB,kBAAkB,GAAK,EAAE,OACtE,eAAe,IAAME,EAAgBF,EAAQW,EAAW,MAAM,CAAC,CACjE,CACF,SAAWD,EACT,EAAE,eAAe,EACjB,KAAK,cAActB,EAAM,oBAAqBA,EAAM,gBAAiBC,CAAS,UACrED,EAAM,eAAgB,CAC/B,IAAM0B,EAAmB1B,EAAM,gBAAgB,UAAW2B,GAAMA,EAAE,WAAW,EACzED,GAAoB,IACtB,EAAE,eAAe,EACjB,KAAK,cAAcA,EAAkB1B,EAAM,gBAAiBC,CAAS,EAEzE,CACA,KACF,CACA,IAAK,SAAU,CACb,GAAID,EAAM,cAAgB,EAAE,kBAAkB,aAAeA,EAAM,aAAe,KAAM,CACtF,IAAMY,EAAS,EAAE,OAAO,QAAqB,kBAAkB,GAAK,EAAE,OAChEC,EAAOb,EAAM,YACnB,KAAK,IAAI,eAAe,EACxBc,EAAgBF,EAAQC,CAAI,CAC9B,CACA,KAAK,MAAM,IAAI,CAAE,oBAAqB,EAAG,CAAC,EAC1C,KACF,CACF,CACF,CAEQ,mBAAmBV,EAA2B,CAEpD,IAAMyB,EADQ,KAAK,MAAM,IAAI,EACN,gBACpB,IAAI,CAACD,EAAGE,IAAOF,EAAE,YAAcE,EAAI,EAAG,EACtC,OAAQA,GAAMA,IAAM,EAAE,EACnBC,EAAsB,MAAM,KAAK,CAAE,OAAQ3B,CAAQ,EAAG,IAAM,CAAC,CAAC,EACpE,QAAW0B,KAAKD,EAAUE,EAAQD,EAAI1B,CAAO,EAAE,KAAK0B,CAAC,EACrD,OAAOC,EAAQ,KAAK,CACtB,CAOQ,qBAA8B,CAEpC,IAAMC,EADc,SAAS,eAAe,GAAG,KAAK,IAAI,SAAS,WAAW,GAClD,cAC1B,GAAI,CAACA,EAAM,OAAO,KAAK,IAAI,QAC3B,IAAMC,EAAS,iBAAiBD,CAAI,EAAE,oBAAoB,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,OACrF,OAAOC,EAAS,EAAIA,EAAS,KAAK,IAAI,OACxC,CAEQ,cAAcC,EAAeC,EAA6BjC,EAAmB,CACnF,IAAMkC,EAAW,SAAS,eAAe,GAAGlC,CAAS,WAAWgC,CAAK,EAAE,EACnEE,EACFA,EAAS,MAAM,EAEf,KAAK,IAAI,aAAaD,EAAQD,CAAK,CAAC,CAExC,CAGQ,mBAAmBA,EAAe,CACxC,IAAMjC,EAAQ,KAAK,MAAM,IAAI,EACvBoC,EAAapC,EAAM,YAAY,OAAQ,GAAM,EAAE,OAAS,aAAa,EAC3E,GAAIiC,EAAQ,GAAKA,GAASG,EAAW,OAAQ,OAC7C,IAAMC,EAAQD,EAAWH,CAAK,EACxBK,EAAOF,EAAW,OAAO,CAACG,EAAGV,IAAMA,IAAMI,CAAK,EAC9CO,EAAexC,EAAM,YAAY,OAAQ,GAAM,EAAE,OAAS,aAAa,EAC7E,KAAK,MAAM,IAAI,CACb,YAAa,CAAC,GAAGwC,EAAcH,EAAO,GAAGC,CAAI,EAC7C,WAAY,GACZ,oBAAqB,EACvB,CAAC,CACH,CACF,EC5QO,IAAMG,GAAN,KAAsB,CAC3B,YACUC,EACAC,EAAsC,CAAC,EAC/C,CAFQ,WAAAD,EACA,eAAAC,CACP,CAEH,cAAcC,EAAe,CAC3B,IAAMC,EAAQ,KAAK,MAAM,IAAI,EACvBC,EAAaD,EAAM,YAAY,OAAQ,GAAM,EAAE,OAAS,aAAa,EAC3E,GAAID,EAAQ,GAAKA,GAASE,EAAW,OAAQ,OAC7C,IAAMC,EAAQD,EAAWF,CAAK,EACxBI,EAAOF,EAAW,OAAO,CAACG,EAAGC,IAAMA,IAAMN,CAAK,EAC9CO,EAAeN,EAAM,YAAY,OAAQ,GAAM,EAAE,OAAS,aAAa,EAE7E,GAAI,KAAK,UAAU,eAAgB,CACjC,GAAM,CAAE,SAAAO,CAAS,EAAIC,EAAWR,EAAM,KAAMA,EAAM,eAAe,EACjE,KAAK,UAAU,eAAe,CAC5B,SAAAO,EACA,aAAcL,EAAM,KACpB,WAAYC,EAAK,IAAKM,GAAMA,EAAE,IAAI,CACpC,CAAC,CACH,CAEA,KAAK,MAAM,IAAI,CACb,YAAa,CAAC,GAAGH,EAAcJ,EAAO,GAAGC,CAAI,EAC7C,WAAY,GACZ,oBAAqB,EACvB,CAAC,CACH,CAEA,iBAAkB,CACF,KAAK,MAAM,IAAI,EACnB,gBAAgB,SAAW,GACrC,KAAK,MAAM,IAAKM,IAAO,CACrB,gBAAiBA,EAAE,gBAAgB,MAAM,EAAG,EAAE,EAC9C,oBAAqB,EACvB,EAAE,CACJ,CACF,ECjCO,SAASC,GACdC,EACAC,EACS,CACT,IAAMC,EAAUD,EAAK,iBAAmB,OAClCE,EAAcF,EAAK,qBAAuB,GAC1CG,EAAaJ,EAAO,sBAAwB,EAElD,GAAIA,EAAO,WAAY,CAIrB,IAAMK,EAAYF,EAAcH,EAAO,UAAY,GACnD,OAAOI,GAAcC,CACvB,CAEA,GAAIH,IAAY,OAAQ,CACtB,IAAMG,EAAYF,EAAcH,EAAO,UAAY,GAM7CM,EAAaN,EAAO,KAAK,QAAQ,OAAQ,EAAE,EAAE,OAC7CO,EAAaP,EAAO,aAAe,MAAQA,EAAO,aAAeM,EACvE,OAAQF,GAAcJ,EAAO,YAAcK,GAAaE,CAC1D,CAEA,OAAIL,IAAY,UACNE,GAAcJ,EAAO,YAAcA,EAAO,WAG7C,EACT,CC7CO,SAASQ,GAAUC,EAAwBC,EAAqC,CACrF,IAAMC,EAAWC,GAAeH,EAAO,KAAMA,EAAO,eAAe,EAC7DI,EAAwBJ,EAAO,YAAY,OAAQK,GAAMA,EAAE,OAAS,aAAa,EACjFC,EAAmBF,EAAsB,CAAC,EAC1CG,EAAaD,EAAmBL,EAAK,kBAAkBK,EAAiB,IAAI,EAAI,OAEhFE,EAAkBR,EAAO,YAC5B,OAAQK,GAAMA,EAAE,OAAS,aAAa,EACtC,IAAKA,GAAMA,EAAE,IAAI,EACjB,KAAK,GAAG,EAKLI,EAAoBC,GACxBV,EAAO,KACP,KAAK,IAAIA,EAAO,WAAYA,EAAO,KAAK,MAAM,EAC9CQ,CACF,EAKMG,EADmBX,EAAO,eAAiB,IAAMS,EAAoB,EAEvEG,GAAmBZ,EAAO,KAAMS,EAAmBT,EAAO,gBAAgB,EAC1E,GACEa,EAAcP,EAChBC,EACEA,EAAWI,EAAY,KAAK,CAAC,EAC5BL,EAAiB,SAAW,CAAC,EAChC,CAAC,EAQCQ,EAAad,EAAO,cAAgB,MAAQA,EAAO,eAAiB,KACtEe,EACJ,GAAID,GAAcd,EAAO,cAAgBA,EAAO,eAAiB,KAAM,CACrE,IAAMgB,EAAYhB,EAAO,aAAa,GAChCiB,EAAoBjB,EAAO,gBAAgB,KAAMkB,GAAMA,EAAE,KAAOF,CAAS,EACzEG,EAAYnB,EAAO,aAAeA,EAAO,cACzCoB,EAAYH,EAAoB,GAAKjB,EAAO,KAAK,MAAMA,EAAO,cAAemB,CAAS,EAC5FJ,EAAkBM,GAAcrB,EAAO,aAAa,QAASoB,CAAS,CACxE,MACEL,EAAkBM,GAAcR,EAAaF,CAAW,EAItDV,EAAK,yBAA2B,KAClCc,EAAkBA,EAAgB,OAAQO,GAAMA,EAAE,WAAW,GAG/D,IAAMC,EAAiBC,GACrB,CACE,WAAAV,EACA,sBAAuBC,EAAgB,OACvC,UAAWf,EAAO,UAClB,KAAMA,EAAO,KACb,YAAaA,EAAO,YACpB,UAAWA,EAAO,UAClB,WAAYA,EAAO,UACrB,EACA,CACE,gBAAiBC,EAAK,gBACtB,oBAAqBA,EAAK,mBAC5B,CACF,EAEA,MAAO,CACL,SAAAC,EACA,sBAAAE,EACA,gBAAAW,EACA,gBAAAP,EACA,eAAAe,CACF,CACF,CCzDO,SAASE,GAAqBC,EAA+C,CAClF,OAAIA,EAAI,OAAS,QACRC,GAAaD,CAAG,EAElBE,GAAYF,CAAG,CACxB,CAEA,SAASC,GAAaD,EAA2E,CAC/F,GAAM,CAAE,KAAAG,EAAM,gBAAAC,EAAiB,YAAAC,EAAa,WAAAC,EAAY,iBAAAC,CAAiB,EAAIP,EAEvEQ,EADaH,EAAY,OAAQI,GAAOA,EAAG,OAAS,aAAa,EAC7C,CAAC,EAC3B,GAAI,CAACD,GAAQ,QAAS,OAAO,KAE7B,IAAME,EAAkBL,EACrB,OAAQI,GAAOA,EAAG,OAAS,aAAa,EACxC,IAAKA,GAAOA,EAAG,IAAI,EACnB,KAAK,GAAG,EACLE,EAAUC,GAAoBT,EAAMG,EAAYI,CAAe,EAC/DG,EAAQC,GAAmBX,EAAMQ,EAASJ,CAAgB,EAC1DQ,EAAQC,GAAeR,EAAO,QAASK,CAAK,EAClD,GAAI,CAACE,EAAO,OAAO,KAInB,IAAME,EAAaF,EAAM,KAAK,YAAY,EACpCG,EAAcf,EAAK,YAAY,EAAE,YAAYc,CAAU,EACvDE,EAAaD,GAAe,EAAIA,EAAc,KAAK,IAAI,EAAGf,EAAK,OAASY,EAAM,KAAK,MAAM,EACzFK,EAAWD,EAAaJ,EAAM,KAAK,OACnCM,EAAelB,EAAK,MAAMgB,EAAYC,CAAQ,EAG9CE,EADmBF,EAAWjB,EAAK,QAAUA,EAAKiB,CAAQ,IAAM,IAClCA,EAAW,EAAIA,EAE7CG,EAAiC,CACrC,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMf,EAAO,KACb,KAAMa,EACN,KAAMN,EAAM,KACZ,eAAgBP,EAAO,KACvB,sBAAuBA,EAAO,KAC9B,QAASA,EAAO,SAAW,CAAC,EAC5B,SAAUO,EAAM,QAClB,EAEA,MAAO,CACL,MAAO,CACL,KAAAZ,EACA,gBAAiB,CAAC,GAAGC,EAAiBmB,CAAS,EAC/C,YAAalB,EAAY,OAAQI,GAAOA,IAAOD,CAAM,EACrD,WAAYc,EACZ,WAAYC,EAAU,GACtB,YAAaD,EACb,oBAAqB,EACvB,EACA,SAAAA,CACF,CACF,CAEA,SAASpB,GAAYF,EAA0E,CAC7F,GAAM,CAAE,KAAAG,EAAM,gBAAAC,EAAiB,aAAAoB,EAAc,cAAAC,EAAe,YAAAC,CAAY,EAAI1B,EAG5E,GAAII,EAAgB,KAAMuB,GAAMA,EAAE,KAAOH,EAAa,EAAE,EAAG,OAAO,KAElE,IAAMI,EAAYzB,EAAK,MAAMsB,EAAeC,CAAW,EACjDX,EAAQC,GAAeQ,EAAa,QAASI,CAAS,EAC5D,GAAI,CAACb,EAAO,OAAO,KAKnB,IAAME,EAAaF,EAAM,KAAK,YAAY,EACpCc,EAAaD,EAAU,YAAY,EAAE,YAAYX,CAAU,EAC3DE,EAAaM,EAAgB,KAAK,IAAI,EAAGI,CAAU,EACnDT,EAAWD,EAAaJ,EAAM,KAAK,OACnCM,EAAelB,EAAK,MAAMgB,EAAYC,CAAQ,EAG9CE,EADmBF,EAAWjB,EAAK,QAAUA,EAAKiB,CAAQ,IAAM,IAClCA,EAAW,EAAIA,EAE7CU,EAAgC,CACpC,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMN,EAAa,eACnB,KAAMH,EACN,KAAMN,EAAM,KACZ,eAAgBS,EAAa,eAC7B,sBAAuBA,EAAa,sBACpC,QAASA,EAAa,QACtB,SAAUT,EAAM,QAClB,EAKIgB,EAAW3B,EAAgB,OAC3B4B,EAAU,EACd,QAASC,EAAI,EAAGA,EAAI7B,EAAgB,OAAQ6B,IAAK,CAC/C,IAAMC,EAAM/B,EAAK,QAAQC,EAAgB6B,CAAC,EAAE,KAAMD,CAAO,EACzD,GAAIE,IAAQ,GACZ,IAAIA,GAAOZ,EAAU,CACnBS,EAAWE,EACX,KACF,CACAD,EAAUE,EAAM9B,EAAgB6B,CAAC,EAAE,KAAK,OAC1C,CACA,IAAME,EAAY,CAAC,GAAG/B,CAAe,EACrC,OAAA+B,EAAU,OAAOJ,EAAU,EAAGD,CAAQ,EAE/B,CACL,MAAO,CACL,KAAA3B,EACA,gBAAiBgC,EACjB,WAAYL,EAAS,GACrB,WAAYR,EACZ,aAAc,KACd,cAAe,KACf,YAAa,KACb,YAAaA,EACb,oBAAqB,EACvB,EACA,SAAAA,CACF,CACF,CC1IO,IAAMc,GAAN,KAAoB,CACzB,YAAoBC,EAAkB,CAAlB,UAAAA,CAAmB,CAGvC,MAAMC,EAAuB,CAC3B,IAAMC,EAAQ,KAAK,KAAK,MAAM,IAAI,EAClC,GAAIA,EAAM,cAAc,KAAOD,EAAS,OACxC,IAAME,EAAQD,EAAM,gBAAgB,KAAME,GAAMA,EAAE,KAAOH,CAAO,EAChE,GAAI,CAACE,EAAO,OAEZ,IAAIE,EAAM,EACNC,EAAS,GACb,QAAWF,KAAKF,EAAM,gBAAiB,CACrC,IAAMK,EAAML,EAAM,KAAK,QAAQE,EAAE,KAAMC,CAAG,EAC1C,GAAIE,IAAQ,GACZ,IAAIH,EAAE,KAAOH,EAAS,CACpBK,EAASC,EACT,KACF,CACAF,EAAME,EAAMH,EAAE,KAAK,OACrB,CACIE,EAAS,GACb,KAAK,KAAK,MAAM,IAAI,CAClB,aAAcH,EACd,cAAeG,EACf,YAAaA,EAASH,EAAM,KAAK,OACjC,YAAaG,EAASH,EAAM,KAAK,OACjC,oBAAqB,EACvB,CAAC,CACH,CAGA,MAAa,CACG,KAAK,KAAK,MAAM,IAAI,EACvB,cACX,KAAK,KAAK,MAAM,IAAI,CAClB,aAAc,KACd,cAAe,KACf,YAAa,KACb,oBAAqB,EACvB,CAAC,CACH,CAGA,aAAaK,EAA8B,CACzC,IAAMN,EAAQ,KAAK,KAAK,MAAM,IAAI,EAC5BO,EAAUP,EAAM,aAChBI,EAASJ,EAAM,cACfQ,EAAOR,EAAM,YAInB,GAHI,CAACO,GAAWH,GAAU,MAAQI,GAAQ,MAGtC,CAACR,EAAM,gBAAgB,KAAME,GAAMA,EAAE,KAAOK,EAAQ,EAAE,EAAG,MAAO,GACpE,IAAME,EAAUT,EAAM,KAAK,MAAM,EAAGI,CAAM,EAAIE,EAAcN,EAAM,KAAK,MAAMQ,CAAI,EAC3EE,EAAUN,EAASE,EAAY,OACrC,YAAK,KAAK,MAAM,IAAKK,IAAO,CAC1B,KAAMF,EACN,gBAAiBE,EAAE,gBAAgB,OAAQT,GAAMA,EAAE,KAAOK,EAAQ,EAAE,EACpE,YAAaG,EACb,YAAaA,EACb,oBAAqB,EACvB,EAAE,EACF,KAAK,KAAK,kBAAkBA,CAAO,EACnC,KAAK,WAAW,EACT,EACT,CAGA,gBAAgBE,EAA6B,CAC3C,IAAMZ,EAAQ,KAAK,KAAK,MAAM,IAAI,EAC5Ba,EAA4B,CAAE,YAAaD,CAAO,EACpDZ,EAAM,cAAgBA,EAAM,eAAiB,MAAQY,GAAU,OAC7DA,EAASZ,EAAM,eACjBa,EAAM,aAAe,KACrBA,EAAM,cAAgB,KACtBA,EAAM,YAAc,KACpBA,EAAM,oBAAsB,IACnBb,EAAM,aAAe,OAC9Ba,EAAM,YAAc,KAAK,IAAIb,EAAM,YAAaY,CAAM,IAG1D,KAAK,KAAK,MAAM,IAAIC,CAAK,EACzB,KAAK,WAAW,CAClB,CAGA,UAAUD,EAA6B,CACrC,IAAMZ,EAAQ,KAAK,KAAK,MAAM,IAAI,EAClC,GACEA,EAAM,cACNA,EAAM,eAAiB,MACvBA,EAAM,aAAe,MACrBY,GAAU,OACTA,EAASZ,EAAM,eAAiBY,EAASZ,EAAM,aAChD,CACA,KAAK,KAAK,MAAM,IAAI,CAClB,YAAaY,EACb,aAAc,KACd,cAAe,KACf,YAAa,KACb,oBAAqB,EACvB,CAAC,EACD,MACF,CACA,KAAK,KAAK,MAAM,IAAI,CAAE,YAAaA,CAAO,CAAC,CAC7C,CAGA,aAAaE,EAAgC,CAC3C,IAAMd,EAAQ,KAAK,KAAK,MAAM,IAAI,EAC5BO,EAAUP,EAAM,aAChBI,EAASJ,EAAM,cACfQ,EAAOR,EAAM,YACnB,GAAI,CAACO,GAAWH,GAAU,MAAQI,GAAQ,KAAM,OAEhD,KAAK,KAAK,cAAc,SAAU,CAChC,UAAWO,EAAWf,EAAM,KAAMA,EAAM,eAAe,EAAE,SACzD,gBAAiBc,EAAO,KACxB,cAAeP,EAAQ,QAAQ,OAAQS,GAAMA,EAAE,OAASF,EAAO,IAAI,EAAE,IAAKE,GAAMA,EAAE,IAAI,CACxF,CAAC,EAED,IAAMC,EAASjB,EAAM,KAAK,MAAM,EAAGI,CAAM,EACnCc,EAAQlB,EAAM,KAAK,MAAMQ,CAAI,EAI7BW,EACJf,IAAW,GAAKU,EAAO,KAAK,OAAS,EACjCA,EAAO,KAAK,CAAC,EAAE,YAAY,EAAIA,EAAO,KAAK,MAAM,CAAC,EAClDA,EAAO,KAGPM,EAAqBF,EAAM,SAAW,GAAKA,EAAM,CAAC,IAAM,IACxDZ,EAAcc,EAAqB,GAAGD,CAAU,IAAMA,EACtDV,EAAUQ,EAASX,EAAcY,EAGjCG,EAAWjB,EAASE,EAAY,QAAUc,EAAqB,EAAI,GAEnEE,EAAgC,CACpC,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMf,EAAQ,eACd,KAAMY,EACN,KAAML,EAAO,KACb,eAAgBP,EAAQ,eACxB,sBAAuBA,EAAQ,sBAC/B,QAASA,EAAQ,QACjB,SAAUO,EAAO,QACnB,EACMS,EAASvB,EAAM,gBAAgB,UAAWE,GAAMA,EAAE,KAAOK,EAAQ,EAAE,EACnEiB,EAASxB,EAAM,gBAAgB,OAAQE,GAAMA,EAAE,KAAOK,EAAQ,EAAE,EAChEkB,EAAWF,GAAU,EAAI,KAAK,IAAIA,EAAQC,EAAO,MAAM,EAAIA,EAAO,OACxEA,EAAO,OAAOC,EAAU,EAAGH,CAAQ,EAEnC,KAAK,KAAK,MAAM,IAAI,CAClB,KAAMb,EACN,gBAAiBe,EACjB,WAAYF,EAAS,GACrB,WAAYD,EACZ,aAAc,KACd,cAAe,KACf,YAAa,KACb,YAAaA,EACb,oBAAqB,GACrB,WAAY,GACZ,cAAe,GACf,qBAAsB,EACxB,CAAC,EACD,KAAK,KAAK,6BAA6B,EAEvC,KAAK,KAAK,kBAAkBA,CAAQ,CACtC,CAEQ,YAAmB,CACzB,IAAMV,EAAI,KAAK,KAAK,MAAM,IAAI,EAC9B,GAAI,CAACA,EAAE,cAAgBA,EAAE,eAAiB,MAAQA,EAAE,aAAe,KAAM,OACzE,IAAMe,EAASC,GAAqB,CAClC,KAAM,OACN,KAAMhB,EAAE,KACR,gBAAiBA,EAAE,gBACnB,aAAcA,EAAE,aAChB,cAAeA,EAAE,cACjB,YAAaA,EAAE,WACjB,CAAC,EACIe,IACL,KAAK,KAAK,MAAM,IAAIA,EAAO,KAAK,EAChC,KAAK,KAAK,kBAAkBA,EAAO,QAAQ,EAC7C,CACF,EC3MA,IAAME,GAAW,eASV,SAASC,GACdC,EACAC,EACAC,EACe,CACf,IAAMC,EAAW,IAAI,IACrB,QAAWC,KAAS,MAAM,KAAKJ,EAAO,QAAQ,EAAG,CAC/C,IAAMK,EAAMD,EAAM,aAAaN,EAAQ,EACnCO,GAAO,MAAMF,EAAS,IAAIE,EAAKD,CAAoB,CACzD,CAEA,IAAME,EAAO,IAAI,IACXC,EAAwB,CAAC,EAC/B,QAASC,EAAI,EAAGA,EAAIP,EAAM,OAAQO,IAAK,CACrC,IAAMC,EAAOR,EAAMO,CAAC,EACdH,EAAMH,EAAK,MAAMO,EAAMD,CAAC,EAC9BF,EAAK,IAAID,CAAG,EACZ,IAAIK,EAAKP,EAAS,IAAIE,CAAG,EACpBK,IACHA,EAAKR,EAAK,OAAOO,EAAMD,CAAC,EACxBE,EAAG,aAAaZ,GAAUO,CAAG,GAE/BH,EAAK,SAASQ,EAAID,EAAMD,CAAC,EACrBR,EAAO,SAASQ,CAAC,IAAME,GACzBV,EAAO,aAAaU,EAAIV,EAAO,SAASQ,CAAC,GAAK,IAAI,EAEpDD,EAAO,KAAKG,CAAE,CAChB,CAEA,OAAW,CAACL,EAAKK,CAAE,IAAKP,EACjBG,EAAK,IAAID,CAAG,GAAGK,EAAG,OAAO,EAGhC,OAAOH,CACT,CCxCA,IAAMI,GAA2B,CAAC,IAAK,EAAE,EAEzC,SAASC,GAAeC,EAAuB,CAC7C,OAAIA,IAAU,EAAU,GACpBA,IAAU,EAAU,GACjB,GACT,CAEO,SAASC,GACdC,EACAC,EACAC,EACAC,EACAC,EAAU,GACVC,EAAU,GACV,CACA,IAAIC,EAAON,EAAU,cAA2B,uBAAuB,EAQvE,GAPKM,IACHA,EAAO,SAAS,cAAc,MAAM,EACpCA,EAAK,UAAY,uBACjBN,EAAU,YAAYM,CAAI,GAIxBD,GAAWJ,EAAM,SAAW,EAAG,CACjCK,EAAK,aAAa,6BAA8B,EAAE,EAClDA,EAAK,UAAY,GACjB,QAASC,EAAI,EAAGA,EAAIX,GAAyB,OAAQW,IAAK,CACxD,IAAMC,EAAQZ,GAAyBW,CAAC,EAClCE,EAAO,SAAS,cAAc,MAAM,EAC1CA,EAAK,aAAa,yBAA0B,EAAE,EAC9CA,EAAK,UAAY,4CAA4CL,EAAU,4BAA8B,EAAE,GACvGK,EAAK,MAAM,MAAQ,GAAGD,CAAK,KAC3BC,EAAK,MAAM,QAAU,OAAOZ,GAAeU,CAAC,CAAC,EAC7CD,EAAK,YAAYG,CAAI,CACvB,CACA,MACF,CAEIJ,EACFC,EAAK,aAAa,6BAA8B,EAAE,EAElDA,EAAK,gBAAgB,4BAA4B,EAInD,QAAWI,KAAQJ,EAAK,iBAA8B,0BAA0B,EAC9EI,EAAK,OAAO,EAGdC,GAAcL,EAAML,EAAO,CACzB,MAAQW,GAAS,GAAGA,EAAK,IAAI,IAAIA,EAAK,IAAI,GAC1C,OAASA,GAAS,CAChB,IAAMC,EAAM,SAAS,cAAc,QAAQ,EAC3C,OAAAA,EAAI,KAAO,SACXA,EAAI,SAAW,GACfA,EAAI,aAAa,gBAAiB,EAAE,EACpCA,EAAI,aAAa,kBAAmB,OAAO,EAC3CA,EAAI,YAAcD,EAAK,KACvBC,EAAI,iBAAiB,YAAcC,GAAMA,EAAE,eAAe,CAAC,EACpDD,CACT,EACA,OAAQ,CAACE,EAAIC,EAAOT,IAAM,CACxB,IAAMM,EAAME,EACNE,EAAU,CAAC,iBAAiB,EAC9Bb,GAASa,EAAQ,KAAK,0BAA0B,EAChDV,IAAML,GAAmB,CAACG,GAASY,EAAQ,KAAK,yBAAyB,EACzEZ,GAASY,EAAQ,KAAK,2BAA2B,EACrDJ,EAAI,UAAYI,EAAQ,KAAK,GAAG,EAChCJ,EAAI,MAAM,MAAQ,GAClBA,EAAI,MAAM,QAAU,OAAOhB,GAAeU,CAAC,CAAC,EACxCF,GACFQ,EAAI,aAAa,mBAAoB,EAAE,EACvCA,EAAI,SAAW,GACfA,EAAI,QAAU,OAEdA,EAAI,gBAAgB,kBAAkB,EACtCA,EAAI,SAAW,GACfA,EAAI,QAAU,IAAMV,EAAaI,CAAC,EAEtC,CACF,CAAC,CACH,CAEO,SAASW,GAAWlB,EAAwB,CACjDA,EAAU,cAAc,uBAAuB,GAAG,OAAO,CAC3D,CCrFA,IAAMmB,GAA+B,CAAC,IAAK,IAAK,GAAG,EAgB5C,SAASC,GAAeC,EAAgC,CAC7D,IAAMC,EAAW,SAAS,cAAc,KAAK,EAC7C,OAAAA,EAAS,GAAKD,EACdC,EAAS,aAAa,OAAQ,SAAS,EACvCA,EAAS,aAAa,oBAAqB,EAAE,EAC7CA,EAAS,UAAY,sBACrBA,EAAS,iBAAiB,YAAcC,GAAMA,EAAE,eAAe,CAAC,EACzDD,CACT,CAEO,SAASE,GAAeF,EAAuBG,EAAsB,CAC1E,GAAM,CACJ,gBAAAC,EACA,YAAAC,EACA,OAAAC,EACA,UAAAC,EACA,MAAAC,EACA,UAAAC,EACA,SAAAC,EACA,YAAAC,EACA,YAAAC,CACF,EAAIT,EAEEU,EAAWJ,GAAaD,EAAM,OAAS,EACvCM,EAAaV,EAAgB,OAAS,EAC1BE,IAAWQ,GAAcD,GAAYN,GAGrDP,EAAS,UAAU,IAAI,8BAA8B,EAErDA,EAAS,UAAU,OAAO,8BAA8B,EAGtDO,EACFP,EAAS,aAAa,mBAAoB,EAAE,EAE5CA,EAAS,gBAAgB,kBAAkB,EAM7C,IAAMe,EAAeF,GAAaN,GAAaE,EAC3CO,EAAUhB,EAAS,cAA2B,sBAAsB,EACpEe,GACGC,IACHA,EAAU,SAAS,cAAc,KAAK,EACtCA,EAAQ,UAAY,sBACpBA,EAAQ,aAAa,mBAAoB,EAAE,EAC3ChB,EAAS,aAAagB,EAAShB,EAAS,UAAU,GAEpDiB,GAAYD,EAASR,EAAO,EAAGI,EAAa,GAAML,CAAS,GAClDS,GACTA,EAAQ,OAAO,EAIjB,IAAIE,EAAOlB,EAAS,cAA2B,kBAAkB,EAC7Dc,GACGI,IACHA,EAAO,SAAS,cAAc,KAAK,EACnCA,EAAK,UAAY,kBACjBlB,EAAS,YAAYkB,CAAI,GAE3BC,GACED,EACAd,EACAC,EACAK,EACAC,EACAR,EAAM,UACNI,CACF,GACSW,GACTA,EAAK,OAAO,EAId,IAAIE,EAAWpB,EAAS,cAA2B,2BAA2B,EAC9E,GAAIO,GAAa,CAACO,GAChB,GAAI,CAACM,EAAU,CACbA,EAAW,SAAS,cAAc,KAAK,EACvCA,EAAS,UAAY,2BACrBA,EAAS,aAAa,yBAA0B,EAAE,EAClD,QAAWC,KAASxB,GAA8B,CAChD,IAAMyB,EAAM,SAAS,cAAc,MAAM,EACzCA,EAAI,UAAY,0BAChBA,EAAI,MAAM,MAAQ,GAAGD,CAAK,KAC1BD,EAAS,YAAYE,CAAG,CAC1B,CACAtB,EAAS,YAAYoB,CAAQ,CAC/B,OACSA,GACTA,EAAS,OAAO,CAEpB,CAEA,SAASD,GACPD,EACAK,EACAlB,EACAK,EACAC,EACAZ,EACAyB,EACA,CAGA,IAAMC,EAAcD,EAAU,IAAM,IAEpCE,GAAcR,EAAMK,EAAS,CAC3B,MAAQI,GAAQ,GAAGA,EAAI,IAAI,KAAKF,CAAW,GAC3C,OAASG,GAAWC,GAAmBD,EAAQJ,CAAO,EACtD,OAAQ,CAACM,EAAIF,EAAQG,IAAM,CACzB,IAAMC,EAAgBD,IAAM1B,GAAe,CAACmB,EAC5CM,EAAG,GAAK,GAAG/B,CAAS,WAAWgC,CAAC,GAChCD,EAAG,QAAQ,SAAW,OAAOC,CAAC,EAC9BD,EAAG,aAAa,gBAAiB,OAAOE,CAAa,CAAC,EACtDF,EAAG,UAAU,OAAO,iCAAkCE,CAAa,EAE/D,CAACR,GAAWI,EAAO,aACrBE,EAAG,QAAU,IAAM,CACjBA,EAAG,UAAU,IAAI,4BAA4B,EAC7CpB,EAASkB,CAAM,EACf,WAAW,IAAME,EAAG,UAAU,OAAO,4BAA4B,EAAG,GAAG,CACzE,EACAA,EAAG,aAAe,IAAM,CACtB,IAAMG,EAAM,OAAO,SAASH,EAAG,QAAQ,UAAY,KAAM,EAAE,EACvDG,GAAO,GAAGtB,EAAYsB,CAAG,CAC/B,IAEAH,EAAG,QAAU,KACbA,EAAG,aAAe,KAEtB,CACF,CAAC,CACH,CAEA,SAASD,GAAmBD,EAA0BJ,EAA+B,CACnF,IAAMU,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,aAAa,OAAQ,QAAQ,EAClCA,EAAK,aAAa,kBAAmB,EAAE,EACnCV,GAASU,EAAK,aAAa,mBAAoB,EAAE,EACrDA,EAAK,SAAWV,GAAW,CAACI,EAAO,YAAc,GAAK,EAEtD,IAAMO,EAAU,CAAC,mBAAmB,EAChCP,EAAO,YACTO,EAAQ,KAAK,6BAA6B,EAE1CA,EAAQ,KAAK,iCAAiC,EAEhDD,EAAK,UAAYC,EAAQ,KAAK,GAAG,EAEjC,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,qBACpBF,EAAK,YAAYE,CAAO,EAExB,IAAMC,EAAc,SAAS,cAAc,KAAK,EAChDA,EAAY,UAAY,0BACxBH,EAAK,YAAYG,CAAW,EAE5B,IAAMC,EAAU,SAAS,cAAc,MAAM,EAI7C,GAHAA,EAAQ,UAAY,4BACpBA,EAAQ,YAAcV,EAAO,KAAO,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,GAAKA,EAAO,KAEzEA,EAAO,IAAK,CACd,IAAMW,EAAM,SAAS,cAAc,MAAM,EACzCA,EAAI,UAAY,wBAChBA,EAAI,YAAcX,EAAO,IACzBU,EAAQ,YAAYC,CAAG,CACzB,CAEA,OAAAL,EAAK,YAAYI,CAAO,EAEjBJ,CACT,CCnLO,SAASM,GACdC,EACAC,EACkB,CAClB,IAAMC,EAAWC,GAAeF,EAAK,SAAS,EAC9C,OAAAD,EAAU,YAAYE,CAAQ,EACvB,CAAE,SAAAA,CAAS,CACpB,CAEO,SAASE,GACdC,EACAC,EACAL,EACA,CACAM,GAAeF,EAAK,SAAU,CAC5B,YACEC,EAAM,sBAAsB,OAAS,EACjC,CAAC,CAAE,GAAGA,EAAM,sBAAsB,CAAC,EAAG,QAASA,EAAM,eAAgB,CAAC,EACtE,CAAC,EACP,gBAAiBA,EAAM,gBACvB,YAAaA,EAAM,oBACnB,OAAQA,EAAM,eAGd,UAAWA,EAAM,WAAa,CAACA,EAAM,cAAgB,CAACA,EAAM,qBAC5D,UAAWL,EAAK,UAChB,MAAOK,EAAM,sBACb,UAAW,GACX,SAAUL,EAAK,aACf,YAAcO,GAAMP,EAAK,MAAM,IAAI,CAAE,oBAAqBO,CAAE,CAAC,EAC7D,YAAaP,EAAK,aACpB,CAAC,CACH,CC1BO,SAASQ,GAAsBC,EAA0B,CAC9D,GAAM,CAAE,MAAAC,EAAO,SAAAC,EAAU,WAAAC,EAAY,eAAAC,EAAgB,gBAAAC,EAAiB,UAAAC,CAAU,EAAIN,EAE9EO,EAAQL,EAAS,SAAW,EAClCD,EAAM,QAAQ,SAAWM,EAAQ,OAAS,QACtCA,GAASF,EACXJ,EAAM,QAAQ,YAAcI,EAE5B,OAAOJ,EAAM,QAAQ,YAGvB,IAAMO,EAASN,EAAS,IAAKO,GAAM,GAAGA,EAAE,IAAI,IAAIA,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,EAC9DC,EAAaT,EAAM,QAAQ,QAAU,GACrCU,EAAiBV,EAAM,QAAQ,YAAc,GAC7CW,EAAqBX,EAAM,QAAQ,gBAAkB,GAC3D,GACEO,IAAWE,IACVP,GAAc,MAAQQ,IACtBP,GAAkB,MAAQQ,EAE3B,OAGF,IAAMC,EAAcP,EAAYQ,EAAgBb,CAAK,EAAI,KACzDA,EAAM,QAAQ,OAASO,EACvBP,EAAM,QAAQ,WAAaE,GAAc,GACzCF,EAAM,QAAQ,eAAiBG,GAAkB,GAEjD,IAAMW,EAAMd,EAAM,eAAiB,SAC7Be,EAAOD,EAAI,uBAAuB,EACpCE,EAAY,EAChB,QAAWC,KAAOhB,EAEhB,GADAe,GAAaC,EAAI,MAAM,OACnBA,EAAI,OAAS,YAAa,CAC5B,IAAMC,EAASJ,EAAI,cAAc,QAAQ,EACzCI,EAAO,QAAQ,IAAM,YACrBA,EAAO,QAAQ,QAAUD,EAAI,MAAM,GACnC,IAAME,EAAQF,EAAI,MAAM,KAAOf,EACzBkB,EAAYH,EAAI,MAAM,KAAOd,EAC7BkB,EAAU,CAAC,qBAAsB,+BAA+B,EAClEF,GAAOE,EAAQ,KAAK,8BAA+B,0BAA0B,EAC7ED,GAAWC,EAAQ,KAAK,6BAA6B,EACzDH,EAAO,UAAYG,EAAQ,KAAK,GAAG,EACnCH,EAAO,YAAcD,EAAI,MACzBF,EAAK,YAAYG,CAAM,CACzB,MACEH,EAAK,YAAYD,EAAI,eAAeG,EAAI,KAAK,CAAC,EAGlDjB,EAAM,gBAAgBe,CAAI,EAC1Bf,EAAM,QAAQ,cAAgB,OAAOgB,CAAS,EAE1CJ,GAAe,MAKjBU,EAAgBtB,EAAO,KAAK,IAAI,EAAG,KAAK,IAAIY,EAAaI,CAAS,CAAC,CAAC,CAExE,CCtCA,IAAMO,GAAa,8NAEnB,SAASC,IAAiC,CACxC,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1C,OAAAA,EAAM,aAAa,kBAAmB,gBAAgB,EAC/CA,EAAM,kBAAoB,gBACnC,CAEO,SAASC,GAASC,EAAwBC,EAAmC,CAClF,GAAM,CAAE,UAAAC,CAAU,EAAID,EAEhBE,EAAWC,GAAeF,CAAS,EACzCF,EAAU,YAAYG,CAAQ,EAE9B,IAAME,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,UAAY,2BACzBL,EAAU,YAAYK,CAAY,EAElC,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,UAAY,oBACnBA,EAAO,aAAa,kBAAmB,EAAE,EACzCD,EAAa,YAAYC,CAAM,EAE/B,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,mBAClBA,EAAM,aAAa,iBAAkB,EAAE,EACvCA,EAAM,aAAa,kBAAmBV,GAAsB,EAAI,iBAAmB,MAAM,EACzFU,EAAM,aAAa,OAAQ,UAAU,EACrCA,EAAM,aAAa,oBAAqB,MAAM,EAC9CA,EAAM,aAAa,gBAAiB,SAAS,EAC7CA,EAAM,aAAa,gBAAiBL,CAAS,EAC7CK,EAAM,aAAa,gBAAiB,OAAO,EAC3CA,EAAM,aAAa,aAAc,MAAM,EACvCA,EAAM,aAAa,eAAgB,MAAM,EACzCD,EAAO,YAAYC,CAAK,EAKxB,IAAMC,EAAsB,SAAS,cAAc,MAAM,EACzDA,EAAoB,UAAY,iCAChCA,EAAoB,aAAa,+BAAgC,EAAE,EACnEF,EAAO,YAAYE,CAAmB,EAEtC,IAAIC,EAAyC,KACzCC,EAAmC,KACnCT,EAAK,eAAiB,QACxBQ,EAAe,SAAS,cAAc,QAAQ,EAC9CA,EAAa,KAAO,SACpBA,EAAa,UAAY,oBACzBA,EAAa,aAAa,aAAc,QAAQ,EAChDA,EAAa,aAAa,kBAAmB,EAAE,EAC/CA,EAAa,UAAYb,GACzBS,EAAa,YAAYI,CAAY,EACrCC,EAAeD,GACNR,EAAK,eAAiB,OAC/BS,EAAeT,EAAK,aACfS,EAAa,aAAa,iBAAiB,GAC9CA,EAAa,aAAa,kBAAmB,EAAE,EAEjDL,EAAa,YAAYK,CAAY,GAGvC,IAAMC,EAAQ,IAAI,gBACZ,CAAE,OAAAC,CAAO,EAAID,EAEfE,EAAY,GAIZC,EAAc,EAEZC,EAAY,IAAM,CACtB,IAAMC,EAAMC,GAAiBV,CAAK,EAE5BW,EADmBF,EAAI,OAAS,GAAKA,EAAI,CAAC,IAAMA,EAAI,CAAC,EAAE,YAAY,EACrCA,EAAI,CAAC,EAAE,YAAY,EAAIA,EAAI,MAAM,CAAC,EAAIA,EAC1Ef,EAAK,aAAaiB,CAAQ,CAC5B,EAEMC,EAAuB,IAAqB,CAChD,IAAMC,GAAOb,EAAM,eAAiB,UAAU,aAAa,EAC3D,GAAI,CAACa,GAAOA,EAAI,aAAe,EAAG,OAAO,KACzC,IAAMC,EAASD,EAAI,WACnB,MAAI,CAACC,GAAU,CAACd,EAAM,SAASc,CAAM,EAAU,MAE7CA,EAAO,WAAa,KAAK,aAAgBA,EAAqBA,EAAO,gBAC/C,QAAqB,6CAA6C,GAC3E,QAAQ,SAAW,IACpC,EAEAhB,EAAa,iBACX,QACCiB,GAAM,CAEAA,EAAE,QAA+B,QAAQ,iBAAiB,GAC/Df,EAAM,MAAM,CACd,EACA,CAAE,OAAAK,CAAO,CACX,EAEAL,EAAM,iBACJ,QACA,IAAM,CACAM,IACJC,EAAc,YAAY,IAAI,EAC9BC,EAAU,EAGVd,EAAK,sBAAsBsB,EAAgBhB,CAAK,CAAC,EACnD,EACA,CAAE,OAAAK,CAAO,CACX,EAOA,IAAMY,EAAMjB,EAAM,eAAiB,SACnC,OAAAiB,EAAI,iBACF,kBACA,IAAM,CACJ,IAAMJ,EAAMI,EAAI,aAAa,EAE7B,GADI,CAACJ,GAAOA,EAAI,aAAe,GAC3B,CAACb,EAAM,SAASa,EAAI,UAAW,EAAG,OACtC,IAAMK,EAAYN,EAAqB,EACjCO,EAAYzB,EAAK,MAAM,IAAI,EAAE,cAAc,IAAM,KACvD,GAAIwB,GAAaA,IAAcC,EAAW,CACxCzB,EAAK,kBAAkBwB,CAAS,EAChC,MACF,CACI,YAAY,IAAI,EAAIX,EAAc,IAItCb,EAAK,gBAAgBsB,EAAgBhB,CAAK,CAAC,CAC7C,EACA,CAAE,OAAAK,CAAO,CACX,EAEAL,EAAM,iBACJ,mBACA,IAAM,CACJM,EAAY,EACd,EACA,CAAE,OAAAD,CAAO,CACX,EACAL,EAAM,iBACJ,iBACA,IAAM,CACJM,EAAY,GACZE,EAAU,CACZ,EACA,CAAE,OAAAH,CAAO,CACX,EAEAL,EAAM,iBACJ,cACCe,GAAM,CACL,IAAMK,EAAaL,EACbM,EAAID,EAAW,UACrB,GAAIC,IAAM,mBAAqBA,IAAM,mBAAqBA,IAAM,iBAAkB,CAChFN,EAAE,eAAe,EACjB,MACF,CAKA,GAAIM,EAAE,WAAW,QAAQ,GAAKA,EAAE,WAAW,QAAQ,EAAG,CACpD,IAAMC,EAAcD,EAAE,WAAW,QAAQ,EAAI,GAAMD,EAAW,MAAQ,GAClE1B,EAAK,oBAAoB4B,CAAW,GACtCP,EAAE,eAAe,CAErB,CACF,EACA,CAAE,OAAAV,CAAO,CACX,EAEAL,EAAM,iBACJ,QACCe,GAAM,CACLA,EAAE,eAAe,EACjB,IAAMQ,GAAQR,EAAE,eAAe,QAAQ,YAAY,GAAK,IAAI,QAAQ,SAAU,GAAG,EACjF,GAAI,CAACQ,EAAM,OACX,IAAMN,EAAMjB,EAAM,eAAiB,SAC7Ba,EAAMI,EAAI,aAAa,EAC7B,GAAI,CAACJ,GAAOA,EAAI,aAAe,EAAG,OAClC,IAAMW,EAAQX,EAAI,WAAW,CAAC,EAC9B,GAAI,CAACb,EAAM,SAASwB,EAAM,cAAc,EAAG,OAC3CA,EAAM,eAAe,EACrB,IAAMC,EAAOR,EAAI,eAAeM,CAAI,EACpCC,EAAM,WAAWC,CAAI,EACrBD,EAAM,cAAcC,CAAI,EACxBD,EAAM,SAAS,EAAI,EACnBX,EAAI,gBAAgB,EACpBA,EAAI,SAASW,CAAK,EAClBhB,EAAU,CACZ,EACA,CAAE,OAAAH,CAAO,CACX,EAEAL,EAAM,iBAAiB,UAAYe,GAAMrB,EAAK,cAAcqB,CAAC,EAAG,CAAE,OAAAV,CAAO,CAAC,EAE1EL,EAAM,iBAAiB,QAAS,IAAMN,EAAK,MAAM,IAAI,CAAE,UAAW,EAAK,CAAC,EAAG,CAAE,OAAAW,CAAO,CAAC,EACrFL,EAAM,iBAAiB,OAAQ,IAAMN,EAAK,MAAM,IAAI,CAAE,UAAW,EAAM,CAAC,EAAG,CAAE,OAAAW,CAAO,CAAC,EAEjFF,GACFA,EAAa,iBACX,QACCY,GAAM,CACL,IAAMW,EAAQhC,EAAK,MAAM,IAAI,EAE7B,GAAI,EADc,CAAC,CAACgC,EAAM,MAAQA,EAAM,gBAAgB,OAAS,IAC/C,CAAChC,EAAK,SAAU,OAClCqB,EAAE,gBAAgB,EAClB,GAAM,CAAE,SAAAY,EAAU,gBAAiBC,CAAY,EAAIC,EACjDH,EAAM,KACNA,EAAM,eACR,EACAhC,EAAK,SAAS,CACZ,MAAOgC,EAAM,KAAK,KAAK,EACvB,UAAWC,EACX,iBAAkBC,CACpB,CAAC,EACDlC,EAAK,cAAc,CACrB,EACA,CAAE,OAAAW,CAAO,CACX,EAGEX,EAAK,YAAc,IACrBM,EAAM,MAAM,EAGP,CAAE,MAAAA,EAAO,oBAAAC,EAAqB,SAAAL,EAAU,aAAAM,EAAc,MAAAE,CAAM,CACrE,CAEO,SAAS0B,GAAUC,EAAeL,EAAkBhC,EAA0B,CACnF,GAAM,CAAE,MAAAM,EAAO,oBAAAC,EAAqB,SAAAL,EAAU,aAAAM,CAAa,EAAI6B,EACzD,CAAE,cAAAC,EAAe,cAAAC,EAAe,aAAAC,EAAc,MAAAC,CAAM,EAAIzC,EAE9DM,EAAM,aAAa,gBAAiB,OAAO0B,EAAM,cAAc,CAAC,EAChE,IAAMU,EACJV,EAAM,qBAAuB,EAAI,GAAGhC,EAAK,SAAS,WAAWgC,EAAM,mBAAmB,GAAK,GAO7F,GANIU,EACFpC,EAAM,aAAa,wBAAyBoC,CAAgB,EAE5DpC,EAAM,gBAAgB,uBAAuB,EAG3CE,EAAc,CAChB,IAAMmC,EAAY,CAAC,CAACX,EAAM,MAAQA,EAAM,gBAAgB,OAAS,EACjExB,EAAa,SAAW,CAACmC,CAC3B,CAOA,IAAMC,EAAkBtC,EAAM,QAAQ,YAAc,GAC9CuC,EAAeb,EAAM,aAAe,MAAQA,EAAM,aAAeY,EAWvE,GATAE,GAAsB,CACpB,MAAAxC,EACA,SAAU0B,EAAM,SAChB,WAAYA,EAAM,WAClB,eAAgBA,EAAM,cAAc,IAAM,KAC1C,gBAAiBA,EAAM,gBACvB,UAAWA,EAAM,SACnB,CAAC,EAEGM,IAAkB,SAAU,CAC9B,IAAMS,EAAgBf,EAAM,WAAa,CAACA,EAAM,cAAgB,CAACA,EAAM,qBACnEe,GAAiBf,EAAM,sBAAsB,OAAS,EACxDgB,GACEzC,EACAyB,EAAM,sBACN,EACAO,EACA,GACAQ,CACF,EAEAE,GAAW1C,CAAmB,CAElC,MACE0C,GAAW1C,CAAmB,EAG5BsC,GAMFvC,EAAM,MAAM,EACZ4C,EAAgB5C,EAAO0B,EAAM,aAAeA,EAAM,KAAK,MAAM,GACpDA,EAAM,WAIChB,GAAiBV,CAAK,IACtB0B,EAAM,MACpBkB,EAAgB5C,EAAO0B,EAAM,KAAK,MAAM,EAQ5C,IAAMmB,EAAkCnB,EAAM,aAC1C,CACE,KAAMA,EAAM,aAAa,eACzB,KAAMA,EAAM,aAAa,sBACzB,SAAU,GACV,QAASA,EAAM,aAAa,OAC9B,EACA,KACEoB,EAAqBD,GAAgBnB,EAAM,sBAAsB,CAAC,EAExEqB,GAAenD,EAAU,CACvB,YAAakD,EACT,CAAC,CAAE,GAAGA,EAAoB,QAASpB,EAAM,eAAgB,CAAC,EAC1D,CAAC,EACL,gBAAiBA,EAAM,gBACvB,YAAaA,EAAM,oBACnB,OAAQA,EAAM,eAGd,UAAWA,EAAM,WAAa,CAACA,EAAM,cAAgB,CAACA,EAAM,qBAC5D,UAAWhC,EAAK,UAChB,MAAOmD,EAAe,CAACA,CAAY,EAAInB,EAAM,sBAC7C,UAAWM,IAAkB,WAC7B,SAAUE,EACV,YAAcc,GAAMb,EAAM,IAAI,CAAE,oBAAqBa,CAAE,CAAC,EACxD,YAAaf,CACf,CAAC,CACH,CClWO,SAASgB,GACdC,EACAC,EACwB,CACxB,IAAMC,EAAmBF,EAAO,sBAAsB,CAAC,EACvD,GAAI,CAACE,EAAkB,OAAO,KAE9B,IAAMC,EAAOH,EAAO,WAChBI,EAASJ,EAAO,KAAK,MAAM,EAAGG,CAAI,EAEhCE,EAAgBD,EAAO,SAAW,GAAKJ,EAAO,KAAK,SAAW,EAK9DM,EACJF,EAAO,SAAW,GAClBJ,EAAO,KAAK,OAAS,GACrBA,EAAO,gBAAgB,OAAS,GAChCA,EAAO,gBAAgB,YAAY,EAAE,WAAWA,EAAO,KAAK,YAAY,CAAC,GACtEK,GAAiBC,IAA6BN,EAAO,kBACxDI,EAAS,GAAGJ,EAAO,eAAe,KAGpC,IAAMO,EAAeC,GAAkBJ,EAAQH,EAAO,IAAI,EACtDM,EAAe,IACjBH,EAASA,EAAO,MAAM,EAAGA,EAAO,OAASG,CAAY,GAGvD,IAAME,EAAaL,EAAO,OAAS,GAAKA,EAAOA,EAAO,OAAS,CAAC,IAAM,IAChEM,EAAU,GAAGN,CAAM,GAAGK,EAAa,IAAM,EAAE,GAAGR,EAAO,IAAI,IACzDU,GACHN,GAAiBC,IAA6BI,EAAQ,OAAS,EAC5DA,EAAQ,CAAC,EAAE,YAAY,EAAIA,EAAQ,MAAM,CAAC,EAC1CA,EAKAE,EAAcD,EAAU,YAAY,EAAE,YAAYV,EAAO,KAAK,YAAY,CAAC,EAC3EY,EACJD,GAAe,EAAID,EAAU,MAAMC,EAAaA,EAAcX,EAAO,KAAK,MAAM,EAAIA,EAAO,KAEvFa,EAAiC,CACrC,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMZ,EAAiB,KACvB,KAAMW,EACN,KAAMZ,EAAO,KACb,eAAgBC,EAAiB,KACjC,sBAAuBA,EAAiB,KACxC,QAASA,EAAiB,SAAW,CAAC,EACtC,SAAUD,EAAO,QACnB,EAEMc,EAAsBf,EAAO,sBAAsB,OAAS,EAElE,MAAO,CACL,MAAO,CACL,KAAMW,EACN,WAAYA,EAAU,OACtB,gBAAiB,CAAC,GAAGX,EAAO,gBAAiBc,CAAS,EACtD,WAAYA,EAAU,GACtB,YAAaH,EAAU,OACvB,WAAY,GACZ,oBAAqB,GACrB,cAAeI,EAAsB,EACrC,qBAAsB,EACxB,EACA,UAAW,CACT,eAAgBd,EAAO,KACvB,aAAcD,EAAO,gBAAgB,OAAQgB,GAAMA,EAAE,OAASf,EAAO,IAAI,EAAE,IAAKe,GAAMA,EAAE,IAAI,CAC9F,EACA,mBAAoBd,EACpB,oBAAAa,CACF,CACF,CChGO,SAASE,GAAeC,EAAsB,CACnD,IAAIC,EAAQD,EACNE,EAAY,IAAI,IACtB,MAAO,CACL,IAAK,IAAMD,EACX,IAAME,GAAU,CACd,IAAMC,EAAW,OAAOD,GAAU,WAAaA,EAAMF,CAAK,EAAIE,EACxDE,EAAO,CAAE,GAAGJ,EAAO,GAAGG,CAAS,EAC/BE,EAAOL,EACbA,EAAQI,EACR,QAAWE,KAAKL,EAAWK,EAAEF,EAAMC,CAAI,CACzC,EACA,UAAYE,IACVN,EAAU,IAAIM,CAAQ,EACf,IAAM,CACXN,EAAU,OAAOM,CAAQ,CAC3B,EAEJ,CACF,CAWO,SAASC,GACdC,EACAC,EACoB,CACpB,IAAIC,EACAC,EAEEC,EAAgBC,IAChBA,IAAWH,IACbA,EAAeG,EACfF,EAAgBF,EAAOI,CAAM,GAExBF,GAGT,MAAO,CACL,IAAK,IAAM,CACT,IAAME,EAASL,EAAK,IAAI,EACxB,MAAO,CAAE,GAAGK,EAAQ,GAAGD,EAAaC,CAAM,CAAE,CAC9C,EACA,IAAMZ,GAAU,CAIV,OAAOA,GAAU,WACnBO,EAAK,IAAKK,GAAW,CACnB,IAAMC,EAAO,CAAE,GAAGD,EAAQ,GAAGD,EAAaC,CAAM,CAAE,EAClD,OAAOZ,EAAMa,CAAI,CACnB,CAAC,EAEDN,EAAK,IAAIP,CAAK,CAElB,EAIA,UAAYK,GACVE,EAAK,UAAU,CAACL,EAAMC,IAAS,CAC7B,IAAMW,EAAW,CAAE,GAAGX,EAAM,GAAGQ,EAAaR,CAAI,CAAE,EAC5CY,EAAW,CAAE,GAAGb,EAAM,GAAGS,EAAaT,CAAI,CAAE,EAClDG,EAASU,EAAUD,CAAQ,CAC7B,CAAC,CACL,CACF,CCjFA,IAAIE,GAAW,GAGR,SAASC,IAAe,CAC7B,GAAID,IAAY,OAAO,SAAa,IAAa,OACjD,GAAI,SAAS,cAAc,wBAAwB,EAAG,CACpDA,GAAW,GACX,MACF,CACAA,GAAW,GAEX,IAAME,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,aAAa,kBAAmB,EAAE,EACxCA,EAAM,YAAcC,GACpB,SAAS,KAAK,YAAYD,CAAK,CACjC,CAIA,IAAMC,GAAS,GCfR,IAAMC,GAAN,KAAkC,CAAlC,cACL,KAAQ,UAAsD,CAAC,EAE/D,GAAsBC,EAAUC,EAAsC,CAIpE,IAAMC,EAAwB,IAAIC,IAASF,EAAS,GAAGE,CAAI,EACvDC,EAAM,KAAK,UAAUJ,CAAK,EAC9B,OAAKI,IACHA,EAAM,IAAI,IACV,KAAK,UAAUJ,CAAK,EAAII,GAE1BA,EAAI,IAAIF,CAAK,EACN,IAAM,CACX,KAAK,UAAUF,CAAK,GAAG,OAAOE,CAAK,CACrC,CACF,CAEA,KAAwBF,KAAaG,EAAkB,CACrD,IAAMC,EAAM,KAAK,UAAUJ,CAAK,EAChC,GAAKI,EACL,QAAWH,KAAYG,EAAKH,EAAS,GAAGE,CAAI,CAC9C,CAEA,aAAgCH,EAAmB,CACjD,OAAQ,KAAK,UAAUA,CAAK,GAAG,MAAQ,GAAK,CAC9C,CAEA,OAAc,CACZ,KAAK,UAAY,CAAC,CACpB,CACF,ECnCO,IAAMK,GAAN,KAAqB,CAArB,cACL,KAAQ,OAAS,IAAI,IAErB,SAASC,EAAaC,EAAgBC,EAAkB,CACtD,KAAK,MAAMF,CAAG,EACd,IAAMG,EAAK,WAAW,IAAM,CAC1B,KAAK,OAAO,OAAOH,CAAG,EACtBC,EAAG,CACL,EAAGC,CAAE,EACL,KAAK,OAAO,IAAIF,EAAKG,CAAE,CACzB,CAEA,MAAMH,EAAmB,CACvB,IAAMG,EAAK,KAAK,OAAO,IAAIH,CAAG,EAC1BG,IAAO,SACT,aAAaA,CAAE,EACf,KAAK,OAAO,OAAOH,CAAG,EAE1B,CAEA,UAAiB,CACf,QAAWG,KAAM,KAAK,OAAO,OAAO,EAAG,aAAaA,CAAE,EACtD,KAAK,OAAO,MAAM,CACpB,CACF,ECqBA,IAAMC,GAAkB,WAClBC,GAA2B,oBAC3BC,GAA4B,qBAC5BC,GAAuB,IAEzBC,GAAY,EAChB,SAASC,IAAmB,CAC1B,MAAO,OAAO,EAAED,EAAS,GAC3B,CAEA,IAAME,GAAyB,IAE/B,SAASC,IAAgC,CACvC,MAAO,CACL,KAAM,GACN,gBAAiB,CAAC,EAClB,YAAa,CAAC,EACd,oBAAqB,GACrB,WAAY,KACZ,UAAW,GACX,QAAS,GACT,MAAO,KACP,WAAY,EACZ,iBAAkB,GAClB,WAAY,GACZ,cAAe,GACf,aAAc,GACd,UAAW,GACX,aAAc,KACd,cAAe,KACf,YAAa,KACb,YAAa,KACb,qBAAsB,EACxB,CACF,CAEO,IAAMC,GAAN,KAAqB,CA0B1B,YAAYC,EAAwBC,EAAoB,CAAC,EAAG,CAzB5D,KAAQ,WAAaC,GAA4BJ,GAAc,CAAC,EAIhE,KAAQ,WAAaF,GAAS,EAM9B,KAAQ,eAAwC,KAEhD,KAAQ,cAAgC,CAAC,EAEzC,KAAQ,QAA0B,KAClC,KAAQ,aAAiD,KACzD,KAAQ,OAAS,IAAIO,GACrB,KAAQ,QAAU,IAAIC,GACtB,KAAQ,UAAoB,OAAO,WAAW,EAI9C,KAAiB,WAAcC,GAA+B,KAAK,QAAQ,KAAK,SAAUA,CAAM,EAChG,KAAiB,UAAaC,GAAe,KAAK,QAAQ,KAAK,QAASA,CAAG,EAGzE,KAAK,UAAYN,EACjB,KAAK,KAAOC,EACZ,KAAK,WAAaA,EAAK,YAAc,OAKrC,KAAK,MAAQM,GAAmB,KAAK,WAAaC,GAAWC,GAAUD,EAAQ,KAAK,IAAI,CAAC,EAMrFP,EAAK,UAAU,KAAK,QAAQ,GAAG,SAAUA,EAAK,QAAQ,EACtDA,EAAK,SAAS,KAAK,QAAQ,GAAG,QAASA,EAAK,OAAO,EACnDA,EAAK,UAAU,KAAK,QAAQ,GAAG,SAAUA,EAAK,QAAQ,EACtDA,EAAK,gBAAgB,KAAK,QAAQ,GAAG,eAAgBA,EAAK,cAAc,EACxEA,EAAK,eAAe,KAAK,QAAQ,GAAG,cAAeA,EAAK,aAAa,EACrEA,EAAK,SAAS,KAAK,QAAQ,GAAG,QAASA,EAAK,OAAO,EACnDA,EAAK,QAAQ,KAAK,QAAQ,GAAG,OAAQA,EAAK,MAAM,EAGhDA,EAAK,QAAU,QACjB,KAAK,MAAM,IAAI,CAAE,KAAMA,EAAK,KAAM,CAAC,EAEjCA,EAAK,kBAAoB,QAC3B,KAAK,MAAM,IAAI,CAAE,gBAAiBA,EAAK,eAAgB,CAAC,EAI1D,KAAK,gBAAkB,IAAIS,GAAgB,KAAK,MAAO,CACrD,eAAgB,CAAC,CAAE,SAAAC,EAAU,aAAAC,EAAc,WAAAC,CAAW,IAAM,CAC1D,KAAK,cAAc,OAAQ,CACzB,UAAWF,EACX,cAAeC,EACf,YAAaC,CACf,CAAC,CACH,CACF,CAAC,EAED,KAAK,OAAS,IAAIC,GAAc,CAC9B,MAAO,KAAK,MACZ,kBAAoBC,GAAW,KAAK,kBAAkBA,CAAM,EAC5D,cAAe,CAACC,EAAMC,IAAS,KAAK,cAAcD,EAAMC,CAAI,EAC5D,6BAA8B,IAAM,KAAK,6BAA6B,CACxE,CAAC,EAED,KAAK,gBAAkB,IAAIC,GACzB,KAAK,MACL,IAAM,KAAK,KAAK,UAChB,IAAM,KAAK,KAAK,gBAChB,IAAM,KAAK,KAAK,kBAChB,IAAO,KAAK,QAAQ,aAAa,OAAO,EAAI,KAAK,UAAY,OAC7D,IAAM,KAAK,UACX,CACE,YAAa,CAAC,CAAE,OAAAC,EAAQ,QAAAC,EAAS,SAAAT,CAAS,IAAM,CAC9C,KAAK,cAAc,SAAU,CAC3B,UAAWA,EACX,gBAAiBS,EAAQ,KACzB,eAAgBD,EAAO,SAAW,CAAC,GAChC,OAAQE,GAAMA,EAAE,OAASD,EAAQ,IAAI,EACrC,IAAKC,GAAMA,EAAE,IAAI,CACtB,CAAC,CACH,CACF,CACF,EAEA,KAAK,mBAAqB,IAAIC,GAAmB,KAAK,MAAO,CAC3D,QAASrB,EAAK,SAAW,EACzB,UAAW,KAAK,UAChB,YAAa,IAAO,KAAK,QAAQ,aAAa,QAAQ,EAAI,KAAK,WAAa,OAE5E,YAAa,KAAK,aAAe,OAAS,IAAM,KAAK,MAAM,EAAI,OAC/D,aAAesB,GAAW,KAAK,aAAaA,CAAM,EAClD,mBAAqBR,GAAW,KAAK,mBAAmBA,CAAM,EAC9D,aAAc,IAAM,KAAK,aAAa,CACxC,CAAC,EAID,KAAK,cAAc,KACjB,KAAK,MAAM,UAAU,CAACS,EAAMC,IAAS,CAC/BD,EAAK,OAASC,EAAK,MAAM,KAAK,QAAQ,KAAK,SAAUD,EAAK,IAAI,EAC9DA,EAAK,kBAAoBC,EAAK,iBAChC,KAAK,QAAQ,KAAK,eAAgBD,EAAK,eAAe,EACpDA,EAAK,YAAcC,EAAK,YACtBD,EAAK,UAAW,KAAK,QAAQ,KAAK,OAAO,EACxC,KAAK,QAAQ,KAAK,MAAM,GAE/B,KAAK,QAAQ,KAAK,cAAeA,CAAI,CACvC,CAAC,CACH,EAKA,KAAK,cAAc,KAAK,KAAK,MAAM,UAAU,IAAM,KAAK,yBAAyB,CAAC,CAAC,EAG/E,KAAK,aAAe,aACtBE,GAAa,EACb,KAAK,eAAe,GAElB,KAAK,aAAe,OACtB,KAAK,mBAAmB,EACf,KAAK,aAAe,YAC7B,KAAK,uBAAuB,EAE9B,KAAK,gBAAgB,MAAM,CAC7B,CAIA,OAAQ,CACN,KAAK,SAAS,MAAM,MAAM,CAC5B,CAEA,MAAO,CACL,KAAK,SAAS,MAAM,KAAK,CAC3B,CAEA,OAAQ,CAIN,KAAK,MAAM,IAAI,CACb,GAAG5B,GAAc,EACjB,cAAe,EACjB,CAAC,EACD,KAAK,UAAY,OAAO,WAAW,EACnC,KAAK,gBAAgB,QAAQ,GAAI,CAAC,CAAC,CACrC,CAEA,SAAU,CACR,KAAK,gBAAgB,QAAQ,EAC7B,KAAK,gBAAgB,QAAQ,EAC7B,KAAK,OAAO,SAAS,EACrB,KAAK,QAAQ,MAAM,EACnB,QAAW6B,KAAS,KAAK,cAAeA,EAAM,EAC9C,KAAK,cAAgB,CAAC,EACtB,KAAK,SAAS,MAAM,MAAM,EAC1B,KAAK,QAAU,KACf,KAAK,aAAe,KAChB,KAAK,aAAe,aACtB,KAAK,UAAU,UAAY,GAE/B,CAEA,QAAQC,EAAsB,CAC5B,KAAK,gBAAgB,QAAQA,CAAI,CACnC,CAEA,SAASC,EAAc,CACrB,KAAK,MAAM,IAAI,CAAE,KAAAA,CAAK,CAAC,CACzB,CAEA,mBAAmBC,EAA+B,CAChD,KAAK,MAAM,IAAI,CAAE,gBAAiBA,CAAO,CAAC,CAC5C,CAEA,cAAcC,EAAe,CAC3B,KAAK,gBAAgB,cAAcA,CAAK,EAKxC,IAAMC,EAAY,KAAK,MAAM,IAAI,EAAE,KAAK,OACxC,KAAK,MAAM,IAAI,CAAE,YAAaA,EAAW,UAAW,EAAK,CAAC,EAC1D,KAAK,kBAAkBA,CAAS,CAClC,CAEA,iBAAkB,CAChB,KAAK,gBAAgB,gBAAgB,CACvC,CAWA,mBAAmBjB,EAAyB,CAC1C,IAAMkB,EAAQ,KAAK,MAAM,IAAI,EACvB,CAAE,KAAAJ,EAAM,gBAAAK,CAAgB,EAAID,EAC9BE,EAAM,EACV,QAASC,EAAI,EAAGA,EAAIF,EAAgB,OAAQE,IAAK,CAC/C,IAAMC,EAAQH,EAAgBE,CAAC,EACzBE,EAAMT,EAAK,QAAQQ,EAAM,KAAMF,CAAG,EACxC,GAAIG,IAAQ,GAAI,SAChB,IAAMC,EAAaD,EACbE,EAAWF,EAAMD,EAAM,KAAK,OAClC,GAAItB,EAASwB,GAAcxB,GAAUyB,EAAU,CAC7C,IAAMC,EAAcC,GAAyBb,EAAMd,CAAM,EACnD4B,EAAUd,EAAK,MAAM,EAAGY,CAAW,EAAIZ,EAAK,MAAMd,CAAM,EACxD6B,EAAYV,EAAgB,OAAO,CAACW,EAAGC,IAAMA,IAAMV,CAAC,EAC1D,YAAK,MAAM,IAAKW,IAAO,CACrB,KAAMJ,EACN,WAAY,KAAK,IAAII,EAAE,WAAYJ,EAAQ,MAAM,EACjD,gBAAiBC,EACjB,WAAY,GACZ,oBAAqB,EACvB,EAAE,EACF,KAAK,kBAAkBH,CAAW,EAC3B,EACT,CACAN,EAAMK,CACR,CACA,MAAO,EACT,CAYQ,kBAAkBzB,EAAgB,CACxC,eAAe,IAAM,CACnB,IAAMiC,EAAO,KAAK,QACdA,GACFA,EAAK,MAAM,MAAM,EACjBC,EAAgBD,EAAK,MAAOjC,CAAM,GAElC,KAAK,KAAK,YAAYA,CAAM,CAEhC,CAAC,CACH,CAEA,iBAAkB,CAChB,KAAK,MAAM,IAAI,CAAE,WAAY,IAAK,CAAC,CACrC,CAEA,kBAAkBmC,EAAiB,CACjC,KAAK,OAAO,MAAMA,CAAO,CAC3B,CAEA,oBAAoBC,EAA8B,CAChD,OAAO,KAAK,OAAO,aAAaA,CAAW,CAC7C,CAEA,cAAe,CACb,KAAK,OAAO,KAAK,CACnB,CAEA,sBAAsBpC,EAAuB,CAC3C,KAAK,OAAO,gBAAgBA,CAAM,CACpC,CAEA,gBAAgBA,EAAuB,CACrC,KAAK,OAAO,UAAUA,CAAM,CAC9B,CAEA,uBAAuBgB,EAAe,CACpC,KAAK,MAAM,IAAI,CAAE,oBAAqBA,CAAM,CAAC,CAC/C,CAEA,iBAAiBqB,EAAe,CAC9B,KAAK,aAAaA,CAAK,CACzB,CAEA,cAAc,EAAkB,CAC9B,KAAK,mBAAmB,cAAc,CAAC,CACzC,CAEA,WAAWC,EAAkB,CACvB,KAAK,MAAM,IAAI,EAAE,YAAcA,GACnC,KAAK,MAAM,IAAI,CAAE,UAAWA,CAAQ,CAAC,CACvC,CAGA,UAAUC,EAAkD,CAC1D,OAAO,KAAK,MAAM,UAAW9B,GAAS8B,EAAS9B,CAAI,CAAC,CACtD,CAEA,UAAsB,CACpB,OAAO,KAAK,MAAM,IAAI,CACxB,CAEA,IAAI,WAAoB,CACtB,OAAO,KAAK,UACd,CAEA,IAAI,SAAmB,CACrB,OAAO,KAAK,MAAM,IAAI,EAAE,OAC1B,CAUA,GACE+B,EACAC,EACY,CACZ,OAAO,KAAK,QAAQ,GAAGD,EAAOC,CAAQ,CACxC,CAEA,OAAOvD,EAAyB,CAC9B,OAAO,OAAO,KAAK,KAAMA,CAAI,EACzBA,EAAK,OAAS,QAChB,KAAK,gBAAgB,QAAQA,EAAK,IAAI,EAEpCA,EAAK,kBAAoB,SAC3B,KAAK,UAAU,QAAQ,gBAAkBA,EAAK,iBAE5CA,EAAK,aAAe,SACtB,KAAK,UAAU,QAAQ,WAAaA,EAAK,WAAa,KAAO,OAE3DA,EAAK,gBAAkB,SACzB,KAAK,UAAU,QAAQ,cAAgBA,EAAK,cAC5C,KAAK,MAAM,IAAI,CAAC,CAAC,IAGjBA,EAAK,kBAAoB,QACzBA,EAAK,sBAAwB,QAC7BA,EAAK,yBAA2B,SAGhC,KAAK,MAAM,IAAI,CAAC,CAAC,EAEfA,EAAK,QAAU,QACjB,KAAK,MAAM,IAAI,CAAE,KAAMA,EAAK,KAAM,CAAC,EAEjCA,EAAK,kBAAoB,QAC3B,KAAK,MAAM,IAAI,CAAE,gBAAiBA,EAAK,eAAgB,CAAC,CAE5D,CAIA,aAAasB,EAA0B,CACrC,IAAMU,EAAQ,KAAK,MAAM,IAAI,EAI7B,GAAIA,EAAM,cAAgBA,EAAM,eAAiB,MAAQA,EAAM,aAAe,KAAM,CAClF,KAAK,OAAO,aAAaV,CAAM,EAC/B,MACF,CAEA,IAAMlB,EAASoD,GAAsBxB,EAAOV,CAAM,EAClD,GAAKlB,IAEL,KAAK,cAAc,SAAU,CAC3B,UAAWqD,EAAWzB,EAAM,KAAMA,EAAM,eAAe,EAAE,SACzD,gBAAiB5B,EAAO,UAAU,eAClC,cAAeA,EAAO,UAAU,YAClC,CAAC,EAED,KAAK,MAAM,IAAIA,EAAO,KAAK,EAC3B,KAAK,6BAA6B,EAGlC,KAAK,OAAO,MAAMb,EAAwB,EACtCa,EAAO,oBAAsB,GAAG,CAKlC,IAAMsD,EAAWtD,EAAO,mBACxB,KAAK,OAAO,SACVb,GACA,IAAM,CACJ,KAAK,MAAM,IAAKuD,IAAO,CACrB,YAAaA,EAAE,YAAY,OAAQa,GAAOA,IAAOD,CAAQ,CAC3D,EAAE,CACJ,EACA9D,EACF,CACF,CAKF,CAEQ,8BAA+B,CACrC,KAAK,OAAO,SACVJ,GACA,IAAM,KAAK,MAAM,IAAI,CAAE,qBAAsB,EAAM,CAAC,EACpDI,EACF,CACF,CAEQ,cAAcmB,EAAyB6C,EAAoC,CAIjF,IAAMC,EACJ,KAAK,KAAK,SAAW,KAAK,aAAe,OAAS,WAAa,gBAC5DC,GAAc,CACjB,OAAAD,EACA,UAAW,KAAK,UAChB,KAAA9C,EACA,UAAA6C,EACA,UAAW,KAAK,KAAK,SACvB,CAAC,CACH,CAEQ,gBAAiB,CACvB,KAAK,UAAU,UAAU,IAAI,YAAY,EAEzC,KAAK,UAAU,QAAQ,cACrB,KAAK,aAAe,WAAa,WAAc,KAAK,KAAK,eAAiB,SAC5E,KAAK,UAAU,QAAQ,gBAAkB,KAAK,KAAK,iBAAmB,QACtE,KAAK,UAAU,QAAQ,WAAc,KAAK,KAAK,YAAc,GAAQ,KAAO,MAG5E,KAAK,eAAiB,IAAIG,GAAe,KAAK,UAAW,KAAK,KAAK,MAAQ,MAAM,CACnF,CAEQ,oBAAqB,CAC3B,IAAMC,EAAO,KACPC,EAAa,CACjB,MAAO,KAAK,MACZ,UAAW,KAAK,UAChB,IAAI,eAAgB,CAClB,OAAQD,EAAK,KAAK,eAAiB,QACrC,EACA,IAAI,UAAW,CACb,OAAOA,EAAK,QAAQ,aAAa,QAAQ,EAAIA,EAAK,WAAa,MACjE,EAEA,YAAa,IAAMA,EAAK,MAAM,EAC9B,aAAc,KAAK,KAAK,aACxB,UAAW,KAAK,KAAK,WAAa,GAClC,aAAe1C,GAA6B,KAAK,aAAaA,CAAM,EACpE,cAAgBQ,GAAkB,KAAK,gBAAgB,cAAcA,CAAK,EAC1E,cAAgBoC,GAAqB,KAAK,mBAAmB,cAAcA,CAAC,EAC5E,aAAef,GAAkB,KAAK,aAAaA,CAAK,EACxD,kBAAoBgB,GAAe,KAAK,kBAAkBA,CAAE,EAC5D,sBAAwBrD,GAA0B,KAAK,sBAAsBA,CAAM,EACnF,gBAAkBA,GAA0B,KAAK,gBAAgBA,CAAM,EACvE,oBAAsBoC,GAAwB,KAAK,oBAAoBA,CAAW,CACpF,EAEA,KAAK,QAAUkB,GAAS,KAAK,UAAWH,CAAU,EAElD,KAAK,uBAAuB,IAAM,CAC5B,KAAK,SACPI,GAAU,KAAK,QAAS,KAAK,MAAM,IAAI,EAAGJ,CAAU,CAExD,CAAC,EAGDI,GAAU,KAAK,QAAS,KAAK,MAAM,IAAI,EAAGJ,CAAU,EACpD,KAAK,uBAAuB,CAC9B,CAEQ,wBAAyB,CAC/B,IAAMK,EAAe,CACnB,MAAO,KAAK,MACZ,UAAW,KAAK,UAChB,aAAehD,GAA6B,KAAK,aAAaA,CAAM,EACpE,cAAgBQ,GAAkB,KAAK,gBAAgB,cAAcA,CAAK,CAC5E,EAEA,KAAK,aAAeyC,GAAkB,KAAK,UAAWD,CAAY,EAElE,KAAK,uBAAuB,IAAM,CAC5B,KAAK,cACPE,GAAmB,KAAK,aAAc,KAAK,MAAM,IAAI,EAAGF,CAAY,CAExE,CAAC,EAGDE,GAAmB,KAAK,aAAc,KAAK,MAAM,IAAI,EAAGF,CAAY,EACpE,KAAK,uBAAuB,CAC9B,CAGQ,uBAAuBG,EAAoB,CACjD,IAAIC,EAAY,GAChB,KAAK,cAAc,KACjB,KAAK,MAAM,UAAU,IAAM,CACrBA,IACJA,EAAY,GACZ,eAAe,IAAM,CACnBA,EAAY,GACZD,EAAO,CACT,CAAC,EACH,CAAC,CACH,CACF,CAGQ,wBAAyB,CAC/B,KAAK,cAAc,KACjB,KAAK,MAAM,UAAU,CAAClD,EAAMC,IAAS,CAC/BD,EAAK,YAAcA,EAAK,aAAeC,EAAK,YAC9C,KAAK,OAAO,SACVlC,GACA,IAAM,KAAK,MAAM,IAAI,CAAE,WAAY,IAAK,CAAC,EACzCG,EACF,CAEJ,CAAC,CACH,CACF,CAEQ,aAAakF,EAAkB,CACrC,IAAM3C,EAAQ,KAAK,MAAM,IAAI,EAC7B,KAAK,MAAM,IAAI,CACb,KAAM2C,EACN,WAAY,GACZ,oBAAqB,EACvB,CAAC,EAED,GAAM,CAAE,MAAAC,EAAO,QAAAC,CAAQ,EAAIC,GAAgBH,EAAU3C,EAAM,eAAe,EACtE6C,EAAQ,OAAS,GACnB,KAAK,MAAM,IAAI,CAAE,gBAAiBD,CAAM,CAAC,EAG3C,KAAK,uBAAuBD,CAAQ,CACtC,CAYQ,0BAA2B,CACjC,IAAM7B,EAAI,KAAK,MAAM,IAAI,EAIzB,GAHI,CAACA,EAAE,cAAgBA,EAAE,eAAiB,MAGtCA,EAAE,gBAAgB,KAAMiC,GAAMA,EAAE,KAAOjC,EAAE,cAAc,EAAE,EAAG,OAChE,IAAMkC,EAAYlC,EAAE,aAAeA,EAAE,cAC/BmC,EAAYnC,EAAE,KAAK,MAAMA,EAAE,cAAekC,CAAS,EAEzD,GADgBE,GAAcpC,EAAE,aAAa,QAASmC,CAAS,EACnD,KAAM7D,GAAMA,EAAE,WAAW,EAAG,OACxC,KAAK,OAAO,KAAK,EACjB,GAAM,CAAE,SAAAV,EAAU,gBAAAuB,CAAgB,EAAIwB,EAAWX,EAAE,KAAMA,EAAE,eAAe,EAC1E,KAAK,gBAAgB,QAAQpC,EAAUuB,CAAe,CACxD,CASQ,uBAAuB0C,EAAkB,CAC/C,IAAM7B,EAAI,KAAK,MAAM,IAAI,EACnB1C,EAAS+E,GAAqB,CAClC,KAAM,QACN,KAAMR,EACN,gBAAiB7B,EAAE,gBACnB,YAAaA,EAAE,YACf,WAAYA,EAAE,WACd,iBAAkBA,EAAE,gBACtB,CAAC,EACI1C,GACL,KAAK,MAAM,IAAIA,EAAO,KAAK,CAC7B,CACF,E5BjpBA,IAAMgF,GAAyB,CAC7B,KAAM,GACN,gBAAiB,CAAC,EAClB,YAAa,CAAC,EACd,oBAAqB,GACrB,WAAY,KACZ,UAAW,GACX,QAAS,GACT,MAAO,KACP,SAAU,CAAC,EACX,sBAAuB,CAAC,EACxB,gBAAiB,CAAC,EAClB,gBAAiB,GACjB,eAAgB,GAChB,WAAY,EACZ,iBAAkB,GAClB,WAAY,GACZ,cAAe,GACf,aAAc,GACd,UAAW,GACX,aAAc,KACd,cAAe,KACf,YAAa,KACb,YAAa,KACb,qBAAsB,EACxB,EAqBO,SAASC,GAAkB,CAChC,SAAAC,EACA,QAAAC,EACA,gBAAAC,EACA,kBAAAC,EACA,UAAAC,EACA,QAAAC,EAAU,EACV,gBAAAC,EACA,oBAAAC,EACA,uBAAAC,EACA,QAAAC,EACA,OAAAC,EACA,MAAOC,EACP,gBAAiBC,EACjB,SAAUC,EACV,eAAAC,EACA,OAAAC,EACA,UAAAC,CACF,EAAsD,CACpD,IAAMC,KAAc,UAAkC,IAAI,EACpD,CAACC,EAAWC,CAAY,KAAI,YAA2B,IAAI,EAK3DC,KAAc,UAAOpB,CAAQ,EACnCoB,EAAY,QAAUpB,EACtB,IAAMqB,KAAa,UAAOpB,CAAO,EACjCoB,EAAW,QAAUpB,EACrB,IAAMqB,KAAc,UAAOT,CAAY,EACvCS,EAAY,QAAUT,EACtB,IAAMU,MAAoB,UAAOT,CAAc,EAC/CS,GAAkB,QAAUT,EAC5B,IAAMU,KAAa,UAAOf,CAAO,EACjCe,EAAW,QAAUf,EACrB,IAAMgB,KAAY,UAAOf,CAAM,EAC/Be,EAAU,QAAUf,EACpB,IAAMgB,MAAe,UAAOV,CAAS,EACrCU,GAAa,QAAUV,KAOvB,aAAU,IAAM,CACd,GAAI,OAAO,SAAa,IAAa,OACrC,IAAMW,EAAW,IAAIC,GAAmB,SAAS,cAAc,KAAK,EAAG,CACrE,WAAY,WACZ,UAAAxB,EACA,gBAAAF,EACA,kBAAAC,EACA,QAAAE,EACA,gBAAAC,EACA,oBAAAC,EACA,uBAAAC,EACA,OAAAO,EACA,MAAOJ,EACP,gBAAiBC,EACjB,SAAU,IAAIiB,IAAST,EAAY,UAAU,GAAGS,CAAI,EACpD,QAAS,IAAIA,IAASR,EAAW,UAAU,GAAGQ,CAAI,EAClD,SAAU,IAAIA,IAASP,EAAY,UAAU,GAAGO,CAAI,EACpD,eAAgB,IAAIA,IAASN,GAAkB,UAAU,GAAGM,CAAI,EAChE,QAAS,IAAML,EAAW,UAAU,EACpC,OAAQ,IAAMC,EAAU,UAAU,EAClC,UAAYK,GAAWJ,GAAa,UAAUI,CAAM,CACtD,CAAC,EACDb,EAAY,QAAUU,EACtBR,EAAaQ,EAAS,SAAS,CAAC,EAChC,IAAMI,EAAQJ,EAAS,UAAWK,GAAUb,EAAaa,CAAK,CAAC,EAC/D,MAAO,IAAM,CACXD,EAAM,EACNJ,EAAS,QAAQ,EACbV,EAAY,UAAYU,IAAUV,EAAY,QAAU,KAC9D,CACF,EAAG,CAAC,CAAC,KAGL,aAAU,IAAM,CACVN,IAAoB,QAAWM,EAAY,SAAS,SAASN,CAAe,CAClF,EAAG,CAACA,CAAe,CAAC,KAGpB,aAAU,IAAM,CACVC,IAAqB,QAAWK,EAAY,SAAS,mBAAmBL,CAAgB,CAC9F,EAAG,CAACA,CAAgB,CAAC,EAGrB,IAAMqB,EAAgB,KAAK,UAAU7B,GAAa,IAAI,EAChD8B,KAAmB,UAAOhC,CAAe,EACzCiC,MAAmB,UAAO,CAAC,EACjC,GAAIjC,IAAoBgC,EAAiB,QAAS,CAChD,IAAME,EAAOF,EAAiB,QACxBG,EAAOnC,EACPoC,EAAW,OAAO,KAAKF,GAAQ,CAAC,CAAC,EACjCG,GAAW,OAAO,KAAKF,GAAQ,CAAC,CAAC,GAErCC,EAAS,SAAWC,GAAS,QAC7BA,GAAS,KACNC,IACC,CAAEJ,IAAmCI,EAAC,GACrCH,EAAiCG,EAAC,IAAOJ,EAAiCI,EAAC,CAChF,IAEAL,GAAiB,UAEnBD,EAAiB,QAAUhC,CAC7B,IAEA,aAAU,IAAM,CACde,EAAY,SAAS,OAAO,CAC1B,UAAAb,EACA,gBAAAF,EACA,gBAAAI,EACA,oBAAAC,EACA,uBAAAC,CACF,CAAC,CACH,EAAG,CACDyB,EACAE,GAAiB,QACjB7B,EACAC,EACAC,CACF,CAAC,EAOD,IAAMiC,KAAa,UAA2B,IAAI,EAC9CA,EAAW,UAAY,OACzBA,EAAW,QAAU,CACnB,iBAAmBC,GAAUzB,EAAY,SAAS,iBAAiByB,CAAK,EACxE,cAAgBC,GAAM,CACpB,IAAMC,EAAS,gBAAiBD,EAAIA,EAAE,YAAcA,EACpD1B,EAAY,SAAS,cAAc2B,CAAM,CAC3C,EACA,WAAaC,GAAY5B,EAAY,SAAS,WAAW4B,CAAO,EAChE,kBAAoBC,GAAY7B,EAAY,SAAS,kBAAkB6B,CAAO,EAC9E,aAAc,IAAM7B,EAAY,SAAS,aAAa,EACtD,sBAAwBa,GAAWb,EAAY,SAAS,sBAAsBa,CAAM,EACpF,gBAAkBA,GAAWb,EAAY,SAAS,gBAAgBa,CAAM,EACxE,oBAAsBiB,GACpB9B,EAAY,SAAS,oBAAoB8B,CAAW,GAAK,GAC3D,cAAgBC,GAAU/B,EAAY,SAAS,cAAc+B,CAAK,EAClE,gBAAiB,IAAM/B,EAAY,SAAS,gBAAgB,EAC5D,gBAAiB,IAAMA,EAAY,SAAS,gBAAgB,EAC5D,MAAO,IAAMA,EAAY,SAAS,MAAM,EACxC,aAAegC,GAAWhC,EAAY,SAAS,aAAagC,CAAM,EAClE,uBAAyBD,GAAU/B,EAAY,SAAS,uBAAuB+B,CAAK,EACpF,YAAa,IAAM/B,EAAY,SAAS,WAAW,EAAI,EACvD,WAAY,IAAMA,EAAY,SAAS,WAAW,EAAK,CACzD,GAEF,IAAMiC,EAAUT,EAAW,QAKrBU,MAAe,eAAaR,GAAwC,CACxE,IAAMS,EAAMT,EAAE,OAAO,MAKfU,GAHJD,EAAI,OAAS,GACb,CAAET,EAAE,aAA4B,aAChCS,EAAI,CAAC,IAAMA,EAAI,CAAC,EAAE,YAAY,EACIA,EAAI,CAAC,EAAE,YAAY,EAAIA,EAAI,MAAM,CAAC,EAAIA,EAC1EnC,EAAY,SAAS,iBAAiBoC,EAAQ,CAChD,EAAG,CAAC,CAAC,EAECC,MAAwB,eAAaX,GAA0C,CACnF1B,EAAY,SAAS,cAAc0B,EAAE,WAAW,CAClD,EAAG,CAAC,CAAC,EAGChB,EAAWV,EAAY,QACvBe,EAAQd,GAAapB,GACrByD,GAAO5C,IAAoB,OAAYA,EAAkBqB,EAAM,KAC/DwB,EAAkB5C,IAAqB,OAAYA,EAAmBoB,EAAM,gBAE5EyB,EAAwBzB,EAAM,sBAC9B0B,EAA2CD,EAAsB,CAAC,EAClEE,EAAYhC,GAAU,WAAa,GAEnCiC,EACJ5B,EAAM,qBAAuB,GAAKL,EAC9B,GAAGgC,CAAS,WAAW3B,EAAM,mBAAmB,GAChD,OAKA6B,EAAe7B,EAAM,aACrB8B,EAAkCD,EACpC,CACE,KAAMA,EAAa,eACnB,KAAMA,EAAa,sBACnB,SAAU,GACV,QAASA,EAAa,OACxB,EACA,KACEE,EAAqBD,GAAgBJ,EACrCM,GAAgBF,EAAe,CAACA,CAAY,EAAIL,EAMhDQ,GACJ,CAACtC,GAAaK,EAAM,WAAa,CAACA,EAAM,cAAgB,CAACA,EAAM,qBAEjE,MAAO,CACL,gBAAAwB,EACA,gBAAiBC,EACjB,cAAeP,EAAQ,cACvB,gBAAiBA,EAAQ,gBACzB,SAAUlB,EAAM,SAChB,WAAYA,EAAM,WAClB,gBAAiBkB,EAAQ,gBACzB,YAAalB,EAAM,YACnB,YAAaA,EAAM,oBACnB,QAASA,EAAM,QACf,UAAWiC,GACX,UAAWjC,EAAM,UACjB,eAAgBA,EAAM,eACtB,gBAAiBA,EAAM,gBACvB,UAAA2B,EACA,MAAO3B,EAAM,MACb,iBAAkBkB,EAAQ,iBAC1B,cAAeA,EAAQ,cACvB,WAAYA,EAAQ,WACpB,aAAAW,EACA,cAAe7B,EAAM,cACrB,YAAaA,EAAM,YACnB,kBAAmBkB,EAAQ,kBAC3B,aAAcA,EAAQ,aACtB,sBAAuBA,EAAQ,sBAC/B,gBAAiBA,EAAQ,gBACzB,oBAAqBA,EAAQ,oBAC7B,WAAY,CACV,MAAOK,GACP,YAAavB,EAAM,iBAAmB,OACtC,SAAUmB,GACV,UAAWG,GACX,QAASJ,EAAQ,YACjB,OAAQA,EAAQ,WAChB,KAAM,WACN,gBAAiBlB,EAAM,eACvB,wBAAyB4B,EACzB,oBAAqB,OACrB,gBAAiBD,CACnB,EACA,MAAOT,EAAQ,MACf,cAAe,CACb,YAAaa,EACT,CAAC,CAAE,GAAGA,EAAoB,QAAS/B,EAAM,eAAgB,CAAC,EAC1D,CAAC,EACL,YAAaA,EAAM,oBACnB,SAAUkB,EAAQ,aAClB,YAAaA,EAAQ,uBACrB,OAAQlB,EAAM,eACd,GAAI2B,EACJ,MAAOK,GACP,YAAad,EAAQ,cACrB,UAAWe,EACb,CACF,CACF,C6BjVA,IAAAC,EAOO,iBAUP,IAAIC,GACJ,SAASC,IAAiC,CACxC,GAAID,KAAuB,OAAW,OAAOA,GAC7C,GAAI,OAAO,SAAa,IAAa,MAAO,GAC5C,IAAME,EAAQ,SAAS,cAAc,KAAK,EAC1C,OAAAA,EAAM,aAAa,kBAAmB,gBAAgB,EACtDF,GAAqBE,EAAM,kBAAoB,iBACxCF,EACT,CAkFO,SAASG,GACdC,EACgC,CAChC,GAAM,CACJ,SAAAC,EACA,WAAAC,EACA,aAAAC,EACA,cAAAC,EACA,YAAAC,EACA,gBAAAC,EACA,UAAAC,EACA,eAAAC,EACA,UAAAC,EACA,mBAAAC,EACA,UAAAC,EACA,iBAAAC,EACA,cAAAC,EACA,sBAAAC,EACA,gBAAAC,EACA,kBAAAC,EACA,oBAAAC,EACA,WAAAC,CACF,EAAIlB,EAEEmB,KAAW,UAAuB,IAAI,EACtCC,KAAe,UAAO,EAAK,EAC3BC,KAAqB,UAAO,EAAE,EAC9BC,KAAmB,UAAO,EAAE,EAC5BC,MAAiB,UAAsB,IAAI,EAI3CC,KAAiB,UAAO,CAAC,EAE/BD,GAAe,QAAUlB,KAGzB,aAAU,IAAM,CACd,GAAI,CAACM,EAAW,OAChB,IAAMc,EAAKN,EAAS,QACfM,IACD,SAAS,gBAAkBA,EAC7BP,EAAW,EAAI,EAEfO,EAAG,MAAM,EAEb,EAAG,CAACd,EAAWO,CAAU,CAAC,KAM1B,aAAU,IAAM,CACd,IAAMO,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMC,EAAMD,EAAG,eAAiB,SAC1BE,EAAoB,IAAM,CAC9B,IAAMC,EAAMF,EAAI,aAAa,EAE7B,GADI,CAACE,GAAOA,EAAI,aAAe,GAC3B,CAACA,EAAI,YAAc,CAACH,EAAG,SAASG,EAAI,UAAU,EAAG,OACrD,IAAMC,EAASD,EAAI,WAIbE,GAFJD,EAAO,WAAa,KAAK,aAAgBA,EAAqBA,EAAO,gBAC/C,QAAqB,6CAA6C,GAChE,QAAQ,SAAW,KAC7C,GAAIC,GAAaA,IAAc3B,GAAc,GAAI,CAC/Ca,EAAkBc,CAAS,EAC3B,MACF,CACI,YAAY,IAAI,EAAIN,EAAe,QAAU,IACjDT,EAAgBgB,EAAgBN,CAAE,CAAC,CACrC,EACA,OAAAC,EAAI,iBAAiB,kBAAmBC,CAAiB,EAClD,IAAMD,EAAI,oBAAoB,kBAAmBC,CAAiB,CAC3E,EAAG,CAACxB,EAAca,EAAmBD,CAAe,CAAC,KAMrD,mBAAgB,IAAM,CACpB,IAAMU,EAAKN,EAAS,QACfM,GACLO,GAAsB,CACpB,MAAOP,EACP,SAAUxB,EACV,WAAAC,EACA,eAAgBC,GAAc,IAAM,KACpC,gBAAiBG,GAAmB,GACpC,UAAAC,CACF,CAAC,CACH,EAAG,CAACN,EAAUC,EAAYC,EAAcG,EAAiBC,CAAS,CAAC,KAKnE,mBAAgB,IAAM,CACpB,IAAM0B,EAAWZ,EAAmB,QAC9Ba,EAAUhC,GAAc,GAE9B,GADAmB,EAAmB,QAAUa,EACzB,CAACA,GAAWA,IAAYD,EAAU,OACtC,IAAMR,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACTA,EAAG,MAAM,EAIT,IAAMU,EAAUZ,GAAe,SAAWa,GAAgBX,CAAE,EAC5DY,EAAgBZ,EAAIU,CAAO,CAC7B,EAAG,CAACjC,CAAU,CAAC,KAKf,mBAAgB,IAAM,CACpB,IAAM+B,EAAWX,EAAiB,QAC5BY,EAAU/B,GAAc,IAAM,GAEpC,GADAmB,EAAiB,QAAUY,EACvB,CAACA,GAAWA,IAAYD,GAAY7B,GAAiB,KAAM,OAC/D,IAAMqB,EAAKN,EAAS,QACfM,GACLY,EAAgBZ,EAAIrB,CAAa,CACnC,EAAG,CAACD,EAAcC,CAAa,CAAC,EAEhC,IAAMkC,KAAY,eAAY,IAAM,CAClC,GAAIlB,EAAa,QAAS,OAC1B,IAAMK,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMc,EAAMC,GAAiBf,CAAE,EAEzBgB,EADmBF,EAAI,OAAS,GAAKA,EAAI,CAAC,IAAMA,EAAI,CAAC,EAAE,YAAY,EACzCA,EAAI,CAAC,EAAE,YAAY,EAAIA,EAAI,MAAM,CAAC,EAAIA,EACtE3B,EAAiB6B,CAAI,CACvB,EAAG,CAAC7B,CAAgB,CAAC,EAEf8B,MAAmB,eAAY,IAAM,CACzClB,EAAe,QAAU,YAAY,IAAI,EACzCc,EAAU,EACV,IAAMb,EAAKN,EAAS,QAChBM,GAAIX,EAAsBiB,EAAgBN,CAAE,CAAC,CACnD,EAAG,CAACa,EAAWxB,CAAqB,CAAC,KAKrC,aAAU,IAAM,CACd,IAAMW,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMkB,EAAiBC,GAAa,CAClC,IAAMC,EAAaD,EACbE,EAAID,EAAW,UACrB,GAAIC,IAAM,mBAAqBA,IAAM,mBAAqBA,IAAM,iBAAkB,CAChFF,EAAE,eAAe,EACjB,MACF,CACA,GAAIE,EAAE,WAAW,QAAQ,GAAKA,EAAE,WAAW,QAAQ,EAAG,CACpD,IAAMC,EAAcD,EAAE,WAAW,QAAQ,EAAI,GAAMD,EAAW,MAAQ,GAClE5B,EAAoB8B,CAAW,GACjCH,EAAE,eAAe,CAErB,CACF,EACA,OAAAnB,EAAG,iBAAiB,cAAekB,CAAa,EACzC,IAAMlB,EAAG,oBAAoB,cAAekB,CAAa,CAClE,EAAG,CAAC1B,CAAmB,CAAC,EAExB,IAAM+B,KAAyB,eAAY,IAAM,CAC/C5B,EAAa,QAAU,EACzB,EAAG,CAAC,CAAC,EAEC6B,KAAuB,eAAY,IAAM,CAC7C7B,EAAa,QAAU,GACvBkB,EAAU,CACZ,EAAG,CAACA,CAAS,CAAC,EAERY,MAAc,eACjBN,GAA2C,CAC1CA,EAAE,eAAe,EACjB,IAAMnB,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAM0B,GAAQP,EAAE,cAAc,QAAQ,YAAY,GAAK,IAAI,QAAQ,SAAU,GAAG,EAChF,GAAI,CAACO,EAAM,OACX,IAAMzB,EAAMD,EAAG,eAAiB,SAC1BG,EAAMF,EAAI,aAAa,EAC7B,GAAI,CAACE,GAAOA,EAAI,aAAe,EAAG,OAClC,IAAMwB,EAAQxB,EAAI,WAAW,CAAC,EAC9B,GAAI,CAACH,EAAG,SAAS2B,EAAM,cAAc,EAAG,OACxCA,EAAM,eAAe,EACrB,IAAMC,EAAO3B,EAAI,eAAeyB,CAAI,EACpCC,EAAM,WAAWC,CAAI,EACrBD,EAAM,cAAcC,CAAI,EACxBD,EAAM,SAAS,EAAI,EACnBxB,EAAI,gBAAgB,EACpBA,EAAI,SAASwB,CAAK,EAClBd,EAAU,CACZ,EACA,CAACA,CAAS,CACZ,EAEMgB,KAAqB,eACxBV,GAA0C/B,EAAc+B,CAAC,EAC1D,CAAC/B,CAAa,CAChB,EAEM0C,KAAc,eAAY,IAAMrC,EAAW,EAAI,EAAG,CAACA,CAAU,CAAC,EAC9DsC,MAAa,eAAY,IAAMtC,EAAW,EAAK,EAAG,CAACA,CAAU,CAAC,EAE9DuC,MAAQ,eAAY,IAAMtC,EAAS,SAAS,MAAM,EAAG,CAAC,CAAC,EACvDuC,KAAO,eAAY,IAAMvC,EAAS,SAAS,KAAK,EAAG,CAAC,CAAC,EACrDwC,KAAe,eAAY,IAAM,CACrC,IAAMlC,EAAKN,EAAS,QACpB,OAAOM,EAAKe,GAAiBf,CAAE,EAAI,EACrC,EAAG,CAAC,CAAC,EAECmC,GAAS/D,GAAsB,EAAI,iBAAmB,OAE5D,MAAO,CACL,SAAAsB,EACA,YAAa,CACX,IAAKA,EACL,gBAAiByC,GACjB,+BAAgC,GAChC,SAAU,EACV,KAAM,WACN,oBAAqB,OACrB,gBAAiB,UACjB,gBAAiBnD,EACjB,gBAAiBD,EACjB,wBAAyBE,EACzB,WAAY,GACZ,aAAc,OACd,QAASgC,GACT,UAAWY,EACX,mBAAoBN,EACpB,iBAAkBC,EAClB,QAASC,GACT,QAASK,EACT,OAAQC,EACV,EACA,aAAAG,EACA,MAAAF,GACA,KAAAC,CACF,CACF,CzCnGQ,IAAAG,EAAA,6BAlOR,SAASC,GAAmBC,EAAwC,CAClE,OAAIA,IAAS,OAAeA,EACxB,OAAO,OAAW,KACf,OAAO,WAAW,8BAA8B,EAAE,QADf,OACkC,OAC9E,CAEO,IAAMC,MAAiB,cAC5B,SACE,CACE,SAAAC,EACA,QAAAC,EACA,gBAAAC,EACA,kBAAAC,EACA,UAAAC,EACA,UAAAC,EACA,QAAAC,EACA,cAAAC,EAAgB,SAChB,KAAAT,EAAO,OACP,gBAAAU,EAAkB,QAClB,WAAAC,EAAa,GACb,gBAAAC,EACA,oBAAAC,EACA,uBAAAC,EACA,UAAAC,EAAY,GACZ,QAAAC,EACA,OAAAC,EACA,MAAAC,EACA,gBAAiBC,EACjB,SAAUC,EACV,eAAAC,EACA,aAAAC,CACF,EACAC,GACA,CACA,IAAMC,KAAe,UAAuB,IAAI,EAC1CC,KAAmB,UAAwB,IAAI,EAC/CC,MAAkB,UAA6C,IAAM,CAAC,CAAC,EACvEC,KAAoB,UAA8B,IAAI,EAItDC,KAAuB,UAA+C,IAAI,KAEhF,aAAU,IAAM,CACd,IAAMC,EAAKL,EAAa,QACxB,GAAKK,EACL,OAAIF,EAAkB,QACpBA,EAAkB,QAAQ,QAAQ3B,CAAI,EAEtC2B,EAAkB,QAAU,IAAIG,GAAeD,EAAI7B,CAAI,EAElD,IAAM,CACX2B,EAAkB,SAAS,QAAQ,EACnCA,EAAkB,QAAU,IAC9B,CACF,EAAG,CAAC3B,CAAI,CAAC,EAET,IAAM+B,MAAkB,eAAaC,GAAmB,CACtD,IAAMH,EAAKD,EAAqB,SAAS,QACpCC,IACLA,EAAG,MAAM,EACTI,EAAgBJ,EAAIG,CAAM,EAC5B,EAAG,CAAC,CAAC,EAEC,CACJ,gBAAAE,EACA,gBAAAC,EACA,cAAAC,GACA,SAAAC,GACA,WAAAC,EACA,gBAAAC,EACA,gBAAAC,GACA,UAAAC,EACA,eAAAC,EACA,UAAAC,EACA,YAAAC,EACA,UAAAC,EACA,iBAAAC,EACA,cAAAC,EACA,WAAAC,EACA,aAAAC,GACA,cAAAC,GACA,YAAAC,EACA,kBAAAC,EACA,sBAAAC,EACA,gBAAAC,GACA,oBAAAC,GACA,cAAAC,GACA,MAAAC,EACF,EAAIC,GAAkB,CACpB,SAAWC,GAAWjC,GAAgB,QAAQiC,CAAM,EACpD,QAAAxD,EACA,gBAAAC,EACA,kBAAAC,EACA,UAAAE,EACA,QAAAC,EACA,gBAAAI,EACA,oBAAAC,EACA,uBAAAC,EACA,QAAAE,EACA,OAAAC,EACA,MAAAC,EACA,gBAAiBC,EACjB,SAAUC,EACV,eAAAC,EACA,OAAQ,WACR,UAAWU,EACb,CAAC,KAGD,aAAU,IAAM,CACd,GAAI,CAACO,EAAY,OACjB,IAAMsB,EAAI,OAAO,WAAW,IAAMrB,EAAgB,EAAG,GAAG,EACxD,MAAO,IAAM,OAAO,aAAaqB,CAAC,CACpC,EAAG,CAACtB,EAAYC,CAAe,CAAC,EAEhC,IAAMsB,GAAqBjB,GAAe,EAAI,GAAGC,CAAS,WAAWD,CAAW,GAAK,OAE/E,CAAE,SAAAkB,GAAU,YAAAC,GAAa,MAAAC,GAAO,KAAAC,GAAM,aAAAC,EAAa,EAAIC,GAAyB,CACpF,SAAA9B,GACA,WAAAC,EACA,aAAAW,GACA,cAAAC,GACA,YAAAC,EACA,gBAAAX,GACA,UAAAC,EACA,eAAAC,EACA,UAAAG,EACA,mBAAAgB,GACA,UAAA9C,EACA,iBAAA+B,EACA,cAAAC,EACA,sBAAAM,EACA,gBAAAC,GACA,kBAAAF,EACA,oBAAAG,GACA,WAAAP,CACF,CAAC,EAKDpB,EAAqB,QAAUkC,MAS/B,mBAAgB,IAAM,CACpB,IAAMM,EAAY3C,EAAiB,QAC7B4C,EAASP,GAAS,QACxB,GAAI,CAACM,GAAa,CAACC,EAAQ,OAE3B,IAAMC,GAAS,IAAM,CACnB,IAAMC,GAAQH,EAAU,kBACxB,GAAI,CAACG,GAAO,OAEZ,GADgBF,EAAO,QAAQ,WAAa,OAC/B,CACXD,EAAU,aAAa,wBAAyB,EAAE,EAClD,MACF,CACA,IAAMI,GAAQD,GAAM,sBAAsB,EACpCE,GAAQJ,EAAO,sBAAsB,EAC3BG,GAAM,KAAOC,GAAM,OAAS,EAC/BL,EAAU,aAAa,wBAAyB,EAAE,EAC1DA,EAAU,gBAAgB,uBAAuB,CACxD,EAEAE,GAAO,EACP,IAAMI,GAAK,IAAI,eAAeJ,EAAM,EACpC,OAAAI,GAAG,QAAQL,CAAM,EACV,IAAMK,GAAG,WAAW,CAC7B,EAAG,CAACrC,GAAUF,EAAgB,OAAQQ,EAAWmB,EAAQ,CAAC,KAE1D,uBACEvC,GACA,KAAO,CACL,MAAAyC,GACA,KAAAC,GACA,MAAAR,GACA,QAAUkB,GAAMhD,EAAkB,SAAS,QAAQgD,CAAC,CACtD,GACA,CAACX,GAAOC,GAAMR,EAAK,CACrB,EAEA,IAAMmB,GAAY,CAAC,CAACvC,GAAS,QAAUH,EAAgB,OAAS,EAE1D2C,MAAe,eAAY,IAAM,CACrC,GAAI,CAACD,GAAW,OAChB,IAAME,EAAOZ,GAAa,EACpB,CAAE,SAAAa,EAAU,gBAAiBC,EAAY,EAAIC,EAAWH,EAAM5C,CAAe,EACnFhC,EAAS,CACP,MAAO4E,EAAK,KAAK,EACjB,UAAWC,EACX,iBAAkBC,EACpB,CAAC,EACDvB,GAAM,CACR,EAAG,CAACmB,GAAW1C,EAAiBhC,EAAUuD,GAAOS,EAAY,CAAC,EAE9DxC,GAAgB,QAAUmD,GAE1B,IAAMK,MAAqB,eACxBC,GAAwC,CAExBA,EAAE,QACL,QAAQ,iBAAiB,GACrCnB,GAAM,CACR,EACA,CAACA,EAAK,CACR,EAEMoB,GAAkB3E,IAAkB,SACpC4E,GAAoB5E,IAAkB,WAE5C,SACE,QAAC,OACC,IAAKe,EACL,UAAW,cAAc8D,GAAO,SAAS,IAAIhF,GAAa,EAAE,GAC5D,sBAAqBG,EACrB,wBAAuBC,EACvB,kBAAiBC,EAAa,KAAO,MACrC,YAAWZ,GAAmBC,CAAI,EAElC,oBAACuF,GAAA,CAAwB,GAAG/B,GAAe,UAAW6B,GAAmB,KAGzE,QAAC,OAAI,UAAWC,GAAO,aAAc,QAASJ,GAC5C,qBAAC,OAAI,UAAWI,GAAO,WAAY,kBAAgB,GACjD,oBAAC,OAAK,GAAGvB,GAAa,UAAWuB,GAAO,MAAO,iBAAe,GAAG,EAChEF,KAAoBzC,GAAaR,EAAgB,OAAS,OACzD,OAAC,QACC,IAAKV,EACL,UAAW6D,GAAO,kBAClB,+BAA6B,GAE7B,mBAACE,GAAA,CACC,MAAOrD,EACP,gBAAiB,EACjB,aAAcC,GACd,QAASO,EACX,EACF,GAEJ,EACCrB,IAAiB,KAAO,KAAOA,IAAiB,UAC/C,OAAC,UACC,KAAK,SACL,kBAAgB,GAChB,UAAWgE,GAAO,aAClB,SAAU,CAACV,GACX,QAAUO,GAAM,CACdA,EAAE,gBAAgB,EAClBN,GAAa,CACf,EACA,aAAW,SAEX,mBAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,KAAK,MACL,aAAW,SAEX,mBAAC,QACC,EAAE,2BACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACjB,EACF,EACF,KAIA,OAAC,QACC,kBAAgB,GAChB,UAAWS,GAAO,WAClB,QAAUH,GAAM,CACTP,KACLO,EAAE,gBAAgB,EAClBN,GAAa,EACf,EAEC,SAAAvD,EACH,GAEJ,GACF,CAEJ,CACF","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","s","AIAutocomplete_module_css_default","s","AIAutocompleteDropdown_module_css_default","s","PillList_module_css_default","import_jsx_runtime","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","rounded","loading","PillList_module_css_default","w","i","pill","e","import_react","s","SuggestionGrid_module_css_default","import_react","s","SuggestionItem_module_css_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","pressed","setPressed","timerRef","handleSelect","className","SuggestionItem_module_css_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","gridRef","hasBottomOverflow","setHasBottomOverflow","el","update","resizeObserver","SuggestionGrid_module_css_default","option","i","SuggestionItem","import_jsx_runtime","FALLBACK_SKELETON_BAR_WIDTHS","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","pills","onPillClick","showPills","isLoading","options","showsPills","showsOptions","showsFallbackSkeleton","isVisible","AIAutocompleteDropdown_module_css_default","e","PillList","SuggestionGrid","w","s","NON_EDITABLE_SELECTOR","segmenter","getGraphemeSegmenter","Segmenter","isInsideNonEditable","node","root","n","createTextWalker","extractPlainText","walker","out","plainTextLength","total","getCursorOffset","sel","anchorNode","anchorOffset","el","offset","i","plainTextLengthOfSubtree","offsetBeforeNode","child","target","setCursorOffset","doc","clamped","cumulative","targetOffset","lastNode","len","next","range","strongParent","cursorIsAtEnd","previousGraphemeBoundary","text","seg","slice","last","index","import_react","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","effectiveFilterBase","text","filterBase","placeholderText","extractFilterQuery","isInProgress","rawRegion","spaceIdx","findPrefixOverlap","prefix","optionText","trimmed","words","optionLower","i","candidate","suffixStart","filterOptions","options","query","lower","o","findExactMatch","ModeController","container","mode","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","TokenManager","config","forceRefresh","result","DEFAULT_API_ORIGIN","DEFAULT_SUGGEST_ENDPOINT","tokenManagers","isAccessTokenConfig","config","getApiKeyConfig","getTokenManager","manager","TokenManager","buildHeaders","apiConfig","buildApiKeyAuthHeader","apiKeyConfig","apiKey","deriveTelemetryEndpoint","suggestEndpoint","DEFAULT_SUGGEST_ENDPOINT","resolveAuthHeader","apiConfig","isAccessTokenConfig","getTokenManager","buildApiKeyAuthHeader","sendTelemetry","event","endpoint","headers","buildHeaders","authHeader","body","SDK_VERSION","hasWarnedMissingKey","generateRequestId","toWireParam","param","includeText","buildRequestBody","rawQuery","completedParams","sessionId","rawCount","p","contactAccountCount","doFetch","endpoint","headers","token","body","signal","fetchSuggestions","options","apiConfig","buildHeaders","DEFAULT_SUGGEST_ENDPOINT","jsonBody","isAccessTokenConfig","manager","getTokenManager","response","newToken","authHeader","buildApiKeyAuthHeader","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","FetchController","store","getApiConfig","getOptionOverrides","getMaskCompletedText","getOnError","getSessionId","callbacks","prevText","prevParams","next","rawQuery","completed","controller","version","textAtRequest","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","filterBase","filterInProgress","inProgressIdx","active","s","extraParam","query","extractFilterQuery","match","findExactMatch","err","caughtError","attemptFetch","minDiff","placeholderText","sg","effBase","effectiveFilterBase","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","isCursorAtEnd","target","cursorIsAtEnd","getEditableCaretOffset","getCursorOffset","KeyboardController","store","ctx","state","listboxId","getOnSubmit","columns","onSubmit","tappableIndices","cursorAtEnd","inEditMode","currentPos","nextPos","prevPos","rightNeighbor","editor","tail","setCursorOffset","leftNeighbor","anchor","offset","rawQuery","finalParams","buildQuery","placeholderVisible","hasHighlightedOption","filledText","s","sg","firstTappableIdx","o","tappable","i","buckets","grid","tracks","index","options","optionEl","actionable","moved","rest","_","placeholders","PillsController","store","callbacks","index","state","actionable","moved","rest","_","i","placeholders","rawQuery","buildQuery","s","computeDropdownVisibility","inputs","opts","trigger","closeOnBlur","hasOptions","focusGate","trimmedEnd","caretAtEnd","deriveAll","inputs","opts","segments","deriveSegments","actionableSuggestions","s","activeSuggestion","overrideFn","placeholderText","clampedFilterBase","effectiveFilterBase","filterQuery","extractFilterQuery","baseOptions","inEditMode","filteredOptions","editingId","paramStillPresent","p","editCaret","editQuery","filterOptions","o","isDropdownOpen","computeDropdownVisibility","tryPromoteExactMatch","ctx","promoteFresh","promoteEdit","text","completedParams","suggestions","filterBase","filterInProgress","active","sg","placeholderText","effBase","effectiveFilterBase","query","extractFilterQuery","match","findExactMatch","matchLower","optionStart","paramStart","paramEnd","optionInText","caretPos","completed","editingParam","editingAnchor","editingTail","p","editQuery","matchStart","newParam","insertAt","scanPos","i","idx","newParams","ReEditManager","deps","paramId","state","param","p","pos","anchor","idx","replacement","editing","tail","newText","newTail","s","offset","patch","option","buildQuery","o","before","after","optionText","needsTrailingSpace","caretPos","newParam","oldIdx","params","insertAt","result","tryPromoteExactMatch","KEY_ATTR","reconcileList","parent","items","opts","existing","child","key","used","result","i","item","el","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","renderPills","container","pills","activePillIndex","onSelectPill","rounded","loading","list","i","width","span","skel","reconcileList","pill","btn","e","el","_pill","classes","clearPills","FALLBACK_SKELETON_BAR_WIDTHS","createDropdown","listboxId","dropdown","e","renderDropdown","state","filteredOptions","activeIndex","isOpen","isLoading","pills","showPills","onSelect","onHighlight","onPillClick","hasPills","hasOptions","wantsPillBar","pillBar","renderPills","grid","renderOptions","skeleton","width","bar","options","loading","loadingFlag","reconcileList","opt","option","buildOptionElement","el","i","isHighlighted","idx","item","classes","streaks","streaksVert","content","tag","buildDropdownOnly","container","opts","dropdown","createDropdown","updateDropdownOnly","refs","state","renderDropdown","i","renderEditableContent","args","input","segments","newParamId","editingParamId","placeholderText","isFocused","empty","segKey","s","lastSegKey","lastNewParamId","lastEditingParamId","savedOffset","getCursorOffset","doc","frag","newLength","seg","strong","isNew","isEditing","classes","setCursorOffset","SUBMIT_SVG","supportsPlaintextOnly","probe","buildDOM","container","opts","listboxId","dropdown","createDropdown","inputWrapper","editor","input","inlinePillContainer","submitButton","submitTarget","abort","signal","composing","lastInputAt","fireInput","raw","extractPlainText","newValue","findEnclosingParamId","sel","anchor","e","getCursorOffset","doc","enclosing","editingId","inputEvent","t","replacement","text","range","node","state","rawQuery","finalParams","buildQuery","updateDOM","refs","pillPlacement","setActivePill","selectOption","store","activeDescendant","canSubmit","previousParamId","justSelected","renderEditableContent","inlineLoading","renderPills","clearPills","setCursorOffset","dropdownPill","dropdownActivePill","renderDropdown","i","computeSelectionPatch","inputs","option","activeSuggestion","base","prefix","inputWasEmpty","inputIsPlaceholderPrefix","overlapChars","findPrefixOverlap","needsSpace","newText","finalText","optionStart","optionInFinal","completed","remainingActionable","o","createStore","initial","state","listeners","patch","resolved","next","prev","l","listener","createDerivedStore","base","derive","cachedInputs","cachedDerived","deriveCached","inputs","full","prevFull","nextFull","injected","injectStyles","style","STYLES","Emitter","event","listener","entry","args","set","TimerScheduler","key","fn","ms","id","TIMER_NEW_PARAM","TIMER_SUGGESTION_REMOVAL","TIMER_SELECTION_ANIMATION","NEW_PARAM_SHIMMER_MS","idCounter","stableId","SELECTION_ANIMATION_MS","initialInputs","AIAutocomplete","container","opts","createStore","TimerScheduler","Emitter","result","err","createDerivedStore","inputs","deriveAll","PillsController","rawQuery","selectedPill","otherPills","ReEditManager","offset","type","data","FetchController","active","matched","o","KeyboardController","option","next","prev","injectStyles","unsub","mode","text","params","index","endOffset","state","completedParams","pos","i","param","idx","paramStart","paramEnd","deleteStart","previousGraphemeBoundary","newText","newParams","_","j","s","refs","setCursorOffset","paramId","replacement","value","focused","listener","event","callback","computeSelectionPatch","buildQuery","consumed","sg","queryData","source","sendTelemetry","ModeController","self","renderOpts","e","id","buildDOM","updateDOM","dropdownOpts","buildDropdownOnly","updateDropdownOnly","render","scheduled","newValue","valid","invalid","reconcileParams","p","editCaret","editQuery","filterOptions","tryPromoteExactMatch","EMPTY_STATE","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","apiConfig","columns","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","instance","AIAutocomplete","args","offset","unsub","state","apiConfigJson","prevOverridesRef","overridesVersion","prev","next","prevKeys","nextKeys","k","actionsRef","value","e","native","focused","paramId","replacement","index","option","actions","handleChange","raw","newValue","handleKeyDownTextarea","text","completedParams","actionableSuggestions","activeSuggestion","listboxId","activeDescendantId","editingParam","dropdownPill","dropdownActivePill","dropdownPills","uiLoading","import_react","plaintextOnlyCache","supportsPlaintextOnly","probe","useContentEditableEditor","opts","segments","newParamId","editingParam","editingAnchor","caretOffset","placeholderText","isFocused","isDropdownOpen","listboxId","activeDescendantId","autoFocus","handleTextChange","handleKeyDown","handleCaretAfterInput","handleCaretMove","startEditingParam","replaceEditingRange","setFocused","inputRef","composingRef","lastSeenParamIdRef","lastEditingIdRef","caretOffsetRef","lastInputAtRef","el","doc","onSelectionChange","sel","anchor","enclosing","getCursorOffset","renderEditableContent","previous","current","desired","plainTextLength","setCursorOffset","fireInput","raw","extractPlainText","next","handleInputEvent","onBeforeInput","e","inputEvent","t","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","range","node","handleKeyDownReact","handleFocus","handleBlur","focus","blur","getPlainText","ceMode","import_jsx_runtime","resolveInitialMode","mode","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","className","apiConfig","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","submitButton","ref","containerRef","pillContainerRef","handleSubmitRef","modeControllerRef","editorInputRefHolder","el","ModeController","handleSetCursor","offset","setCursorOffset","completedParams","suggestionPills","setActivePill","segments","newParamId","clearNewParamId","placeholderText","isFocused","isDropdownOpen","isLoading","activeIndex","listboxId","handleTextChange","handleKeyDown","setFocused","editingParam","editingAnchor","caretOffset","startEditingParam","handleCaretAfterInput","handleCaretMove","replaceEditingRange","dropdownProps","reset","useAIAutocomplete","result","t","activeDescendantId","inputRef","editorProps","focus","blur","getPlainText","useContentEditableEditor","container","editor","update","inner","cRect","eRect","ro","m","canSubmit","handleSubmit","text","rawQuery","finalParams","buildQuery","handleWrapperClick","e","showInlinePills","showDropdownPills","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList"]}