@magicx-eng/ai-autocomplete-react 0.2.0 → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/AIAutocomplete.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocomplete.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocompleteDropdown.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/PillList.module.css.js","../src/components/PillList.tsx","../src/components/SuggestionGrid.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionGrid.module.css.js","../src/components/SuggestionItem.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionItem.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/appearance.css.js","../src/hooks/useAIAutocomplete.ts","../src/hooks/useContentEditableEditor.ts"],"sourcesContent":["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 {\n type AppearanceMode,\n type AutocompleteResult,\n buildQuery,\n ModeController,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport { useContentEditableEditor } from \"./hooks/useContentEditableEditor\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps } from \"./types\";\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 optionsPosition,\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-67791514\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-67791514\";\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: 6px;\n padding: 2px 3px;\n /* Pull surrounding inline text back so the wider/taller fill doesn't shove\n the rest of the line — only the visible background grows. */\n margin: 0 -1.5px;\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-3819c762\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-3819c762\";\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-0fcb7940\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0fcb7940\";\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-ff33a0ab\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-ff33a0ab\";\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 <span className={styles.text}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n </span>\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-82820da7\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-82820da7\";\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 font-weight: 250;\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 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}\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}\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/* Skeleton fill is on the inner text span (a true inline element) so multi-\n line options wrap into one skeleton bar per line. The outer .content is a\n flex item — blockified by spec — so painting the background there would\n collapse all lines into one tall rectangle. \\`box-decoration-break: clone\\`\n makes the radius render cleanly on each line bar. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_text_yqoh9 {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n border-radius: 999px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\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\",\"text\":\"SuggestionItem-module_text_yqoh9\"};","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-0ae03977\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0ae03977\";\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: #4f4f4f;\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: #b0b0b0;\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: 13px 27px 13px 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 {};","import {\n AIAutocomplete as CoreAIAutocomplete,\n type CoreState,\n type Suggestion,\n type SuggestionOption,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { UseAIAutocompleteOptions, UseAIAutocompleteReturn } 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 optionsPosition,\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 optionsPosition,\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 optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n });\n }, [\n apiConfigJson,\n overridesVersion.current,\n dropdownTrigger,\n optionsPosition,\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 {\n type CompletedParamState,\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n renderEditableContent,\n type Segment,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ClipboardEvent as ReactClipboardEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\";\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":"AAAA,OACE,cAAAA,GACA,eAAAC,GACA,aAAAC,GACA,uBAAAC,GACA,mBAAAC,GACA,UAAAC,OACK,QCPP,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,EAyKhB,SAAS,KAAK,YAAYA,CAAC,CAC7B,CACA,IAAOC,EAAQ,CAAC,UAAY,wCAAwC,aAAe,2CAA2C,WAAa,yCAAyC,MAAQ,oCAAoC,kBAAoB,gDAAgD,aAAe,2CAA2C,WAAa,yCAAyC,YAAc,yCAAyC,EC9K3c,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,cAAAC,OAAA,oBAnBV,IAAMC,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,EAE5BL,GAAC,QAAK,UAAWU,EAAO,KAAM,6BAA2B,GACtD,SAAAT,GAAyB,IAAI,CAACU,EAAGC,IAChCZ,GAAC,QAEC,yBAAuB,GACvB,UAAW,GAAGU,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,EAKFX,GAAC,QAAK,UAAWU,EAAO,KAAM,6BAA4BD,EAAU,GAAK,OACtE,SAAAJ,EAAM,IAAI,CAACQ,EAAMD,IAChBZ,GAAC,UAEC,KAAK,SACL,gBAAc,GACd,mBAAkBS,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,OAAS,aAAAE,GAAW,mBAAAC,GAAiB,UAAAC,GAAQ,YAAAC,OAAgB,QCA7D,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,OAAS,aAAAC,GAAW,UAAAC,GAAQ,YAAAC,OAAgB,QCA5C,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;AAAA;AAAA;AAAA;AAAA;AAAA,EA4VhB,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,4CAA4C,KAAO,kCAAkC,EDlSv7B,cAAAC,GAEA,QAAAC,OAFA,oBAlDC,SAASC,GAAe,CAC7B,OAAAC,EACA,cAAAC,EACA,SAAAC,EACA,YAAAC,EACA,GAAAC,EACA,QAAAC,CACF,EAAwB,CACtB,GAAM,CAACC,EAASC,CAAU,EAAIC,GAAS,EAAK,EACtCC,EAAWC,GAAkD,MAAS,EAE5EC,GAAU,IACD,IAAM,aAAaF,EAAS,OAAO,EACzC,CAAC,CAAC,EAEL,IAAMG,EAAe,IAAM,CACrBP,GAAW,CAACL,EAAO,aAAeM,IACtCC,EAAW,EAAI,EACfL,EAASF,CAAM,EACf,aAAaS,EAAS,OAAO,EAC7BA,EAAS,QAAU,WAAW,IAAMF,EAAW,EAAK,EAAG,GAAG,EAC5D,EAEMM,EAAY,CAChBC,EAAO,KACPb,GAAiB,CAACI,EAAUS,EAAO,YAAc,GACjDd,EAAO,YAAcc,EAAO,SAAWA,EAAO,YAC9CR,EAAUQ,EAAO,QAAU,EAC7B,EACG,OAAO,OAAO,EACd,KAAK,GAAG,EAEX,OACEhB,GAAC,OACC,GAAIM,EACJ,KAAK,SACL,kBAAgB,GAChB,mBAAkBC,EAAU,GAAK,OACjC,gBAAeJ,EACf,UAAWY,EACX,SAAUR,GAAW,CAACL,EAAO,YAAc,GAAK,EAChD,QAASY,EACT,UAAYG,GAAM,CACZ,CAACV,GAAWL,EAAO,cAAgBe,EAAE,MAAQ,SAAWA,EAAE,MAAQ,OACpEA,EAAE,eAAe,EACjBH,EAAa,EAEjB,EACA,aAAc,CAACP,GAAWL,EAAO,YAAcG,EAAc,OAE7D,UAAAN,GAAC,OAAI,UAAWiB,EAAO,QAAS,EAChCjB,GAAC,OAAI,UAAWiB,EAAO,YAAa,EACpChB,GAAC,QAAK,UAAWgB,EAAO,QACtB,UAAAjB,GAAC,QAAK,UAAWiB,EAAO,KACrB,SAAAd,EAAO,KAAO,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,GAAKA,EAAO,KAC1D,EACCA,EAAO,KAAOH,GAAC,QAAK,UAAWiB,EAAO,IAAM,SAAAd,EAAO,IAAI,GAC1D,GACF,CAEJ,CFhBU,cAAAgB,OAAA,oBA3CH,SAASC,GAAe,CAC7B,QAAAC,EACA,YAAAC,EACA,SAAAC,EACA,YAAAC,EACA,UAAAC,EACA,QAAAC,CACF,EAAwB,CACtB,IAAMC,EAAUC,GAAuB,IAAI,EACrC,CAACC,EAAmBC,CAAoB,EAAIC,GAAS,EAAK,EAEhE,OAAAC,GAAU,IAAM,CACd,IAAMC,EAAKN,EAAQ,QACnB,GAAI,CAACM,EAAI,OAET,IAAMC,EAAS,IAAM,CACnBJ,EAAqBG,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,EAMLC,GAAgB,IAAM,CACpB,IAAMH,EAAKN,EAAQ,QACdM,GACLH,EAAqBG,EAAG,aAAeA,EAAG,UAAYA,EAAG,aAAe,CAAC,CAC3E,EAAG,CAACZ,CAAO,CAAC,EAGVF,GAAC,OAAI,UAAWkB,GAAO,cAAe,YAAWR,EAAoB,GAAK,OACxE,SAAAV,GAAC,OAAI,IAAKQ,EAAS,UAAWU,GAAO,KAClC,SAAAhB,EAAQ,IAAI,CAACiB,EAAQC,IACpBpB,GAACqB,GAAA,CAEC,OAAQF,EACR,cAAeC,IAAMjB,EACrB,SAAUC,EACV,YAAa,IAAMC,EAAYe,CAAC,EAChC,GAAI,GAAGd,CAAS,WAAWc,CAAC,GAC5B,QAASb,GANJY,EAAO,IAOd,CACD,EACH,EACF,CAEJ,CIvCI,OAUM,OAAAG,GAVN,QAAAC,OAAA,oBA1BJ,IAAMC,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,OACEb,GAAC,OACC,GAAIQ,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,GACzCZ,GAAC,OAAI,UAAWoB,GAAO,QAAS,mBAAiB,GAC/C,SAAApB,GAACsB,GAAA,CACC,MAAOX,EACP,gBAAiB,EACjB,aAAcC,EACd,QAAO,GACP,QAASE,EACX,EACF,EAEDD,IAAc,CAACF,GAASA,EAAM,SAAW,IAAMG,GAC9Cd,GAAC,OAAI,UAAWoB,GAAO,QAAS,mBAAiB,GAC/C,SAAApB,GAACsB,GAAA,CAAS,MAAO,CAAC,EAAG,gBAAiB,EAAG,aAAc,IAAM,CAAC,EAAG,QAAO,GAAC,QAAO,GAAC,EACnF,EAEDL,GACCjB,GAACuB,GAAA,CACC,QAASR,EACT,YAAaV,EACb,SAAUC,EACV,YAAaC,EACb,UAAWE,EACX,QAASK,EACX,EAEDI,GACClB,GAAC,OAAI,UAAWoB,GAAO,aAAc,yBAAuB,GACzD,SAAAlB,GAA6B,IAAKsB,GACjCxB,GAAC,QAAsB,UAAWoB,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,CVzFA,OAGE,cAAAC,GACA,kBAAAC,GACA,mBAAAC,OACK,sCWjBP,OACE,kBAAkBC,OAIb,sCACP,OAGE,eAAAC,GACA,aAAAC,GACA,UAAAC,EACA,YAAAC,OACK,QAUP,IAAMC,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,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,EAActB,EAAkC,IAAI,EACpD,CAACuB,EAAWC,CAAY,EAAIvB,GAA2B,IAAI,EAK3DwB,EAAczB,EAAOI,CAAQ,EACnCqB,EAAY,QAAUrB,EACtB,IAAMsB,EAAa1B,EAAOK,CAAO,EACjCqB,EAAW,QAAUrB,EACrB,IAAMsB,EAAc3B,EAAOkB,CAAY,EACvCS,EAAY,QAAUT,EACtB,IAAMU,EAAoB5B,EAAOmB,CAAc,EAC/CS,EAAkB,QAAUT,EAC5B,IAAMU,EAAa7B,EAAOc,CAAO,EACjCe,EAAW,QAAUf,EACrB,IAAMgB,EAAY9B,EAAOe,CAAM,EAC/Be,EAAU,QAAUf,EACpB,IAAMgB,EAAe/B,EAAOqB,CAAS,EACrCU,EAAa,QAAUV,EAOvBtB,GAAU,IAAM,CACd,GAAI,OAAO,SAAa,IAAa,OACrC,IAAMiC,EAAW,IAAInC,GAAmB,SAAS,cAAc,KAAK,EAAG,CACrE,WAAY,WACZ,UAAAW,EACA,gBAAAF,EACA,kBAAAC,EACA,QAAAE,EACA,gBAAAC,EACA,gBAAAC,EACA,oBAAAC,EACA,uBAAAC,EACA,OAAAO,EACA,MAAOJ,EACP,gBAAiBC,EACjB,SAAU,IAAIgB,IAASR,EAAY,UAAU,GAAGQ,CAAI,EACpD,QAAS,IAAIA,IAASP,EAAW,UAAU,GAAGO,CAAI,EAClD,SAAU,IAAIA,IAASN,EAAY,UAAU,GAAGM,CAAI,EACpD,eAAgB,IAAIA,IAASL,EAAkB,UAAU,GAAGK,CAAI,EAChE,QAAS,IAAMJ,EAAW,UAAU,EACpC,OAAQ,IAAMC,EAAU,UAAU,EAClC,UAAYI,GAAWH,EAAa,UAAUG,CAAM,CACtD,CAAC,EACDZ,EAAY,QAAUU,EACtBR,EAAaQ,EAAS,SAAS,CAAC,EAChC,IAAMG,EAAQH,EAAS,UAAWI,GAAUZ,EAAaY,CAAK,CAAC,EAC/D,MAAO,IAAM,CACXD,EAAM,EACNH,EAAS,QAAQ,EACbV,EAAY,UAAYU,IAAUV,EAAY,QAAU,KAC9D,CACF,EAAG,CAAC,CAAC,EAGLvB,GAAU,IAAM,CACViB,IAAoB,QAAWM,EAAY,SAAS,SAASN,CAAe,CAClF,EAAG,CAACA,CAAe,CAAC,EAGpBjB,GAAU,IAAM,CACVkB,IAAqB,QAAWK,EAAY,SAAS,mBAAmBL,CAAgB,CAC9F,EAAG,CAACA,CAAgB,CAAC,EAGrB,IAAMoB,GAAgB,KAAK,UAAU7B,GAAa,IAAI,EAChD8B,EAAmBtC,EAAOM,CAAe,EACzCiC,EAAmBvC,EAAO,CAAC,EACjC,GAAIM,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,EAAiB,UAEnBD,EAAiB,QAAUhC,CAC7B,CAEAP,GAAU,IAAM,CACduB,EAAY,SAAS,OAAO,CAC1B,UAAAd,EACA,gBAAAF,EACA,gBAAAI,EACA,gBAAAC,EACA,oBAAAC,EACA,uBAAAC,CACF,CAAC,CACH,EAAG,CACDwB,GACAE,EAAiB,QACjB7B,EACAC,EACAC,EACAC,CACF,CAAC,EAOD,IAAMgC,EAAa7C,EAA2B,IAAI,EAC9C6C,EAAW,UAAY,OACzBA,EAAW,QAAU,CACnB,iBAAmBC,GAAUxB,EAAY,SAAS,iBAAiBwB,CAAK,EACxE,cAAgBC,GAAM,CACpB,IAAMC,EAAS,gBAAiBD,EAAIA,EAAE,YAAcA,EACpDzB,EAAY,SAAS,cAAc0B,CAAM,CAC3C,EACA,WAAaC,GAAY3B,EAAY,SAAS,WAAW2B,CAAO,EAChE,kBAAoBC,GAAY5B,EAAY,SAAS,kBAAkB4B,CAAO,EAC9E,aAAc,IAAM5B,EAAY,SAAS,aAAa,EACtD,sBAAwBY,GAAWZ,EAAY,SAAS,sBAAsBY,CAAM,EACpF,gBAAkBA,GAAWZ,EAAY,SAAS,gBAAgBY,CAAM,EACxE,oBAAsBiB,GACpB7B,EAAY,SAAS,oBAAoB6B,CAAW,GAAK,GAC3D,cAAgBC,GAAU9B,EAAY,SAAS,cAAc8B,CAAK,EAClE,gBAAiB,IAAM9B,EAAY,SAAS,gBAAgB,EAC5D,gBAAiB,IAAMA,EAAY,SAAS,gBAAgB,EAC5D,MAAO,IAAMA,EAAY,SAAS,MAAM,EACxC,aAAe+B,GAAW/B,EAAY,SAAS,aAAa+B,CAAM,EAClE,uBAAyBD,GAAU9B,EAAY,SAAS,uBAAuB8B,CAAK,EACpF,YAAa,IAAM9B,EAAY,SAAS,WAAW,EAAI,EACvD,WAAY,IAAMA,EAAY,SAAS,WAAW,EAAK,CACzD,GAEF,IAAMgC,EAAUT,EAAW,QAKrBU,EAAezD,GAAaiD,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,EAC1ElC,EAAY,SAAS,iBAAiBmC,EAAQ,CAChD,EAAG,CAAC,CAAC,EAECC,GAAwB5D,GAAaiD,GAA0C,CACnFzB,EAAY,SAAS,cAAcyB,EAAE,WAAW,CAClD,EAAG,CAAC,CAAC,EAGCf,EAAWV,EAAY,QACvBc,EAAQb,GAAarB,GACrByD,EAAO3C,IAAoB,OAAYA,EAAkBoB,EAAM,KAC/DwB,EAAkB3C,IAAqB,OAAYA,EAAmBmB,EAAM,gBAE5EyB,EAAwBzB,EAAM,sBAC9B0B,EAA2CD,EAAsB,CAAC,EAClEE,EAAY/B,GAAU,WAAa,GAEnCgC,EACJ5B,EAAM,qBAAuB,GAAKJ,EAC9B,GAAG+B,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,GAAqBD,GAAgBJ,EACrCM,GAAgBF,EAAe,CAACA,CAAY,EAAIL,EAMhDQ,GACJ,CAACrC,GAAaI,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,EACP,YAAavB,EAAM,iBAAmB,OACtC,SAAUmB,EACV,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,GACT,CAAC,CAAE,GAAGA,GAAoB,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,CCpVA,OAEE,oBAAAC,GACA,mBAAAC,GACA,mBAAAC,GACA,yBAAAC,GAEA,mBAAAC,OACK,sCACP,OAGE,eAAAC,EACA,aAAAC,GACA,mBAAAC,GACA,UAAAC,OACK,QAEP,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,EAAWxB,GAAuB,IAAI,EACtCyB,EAAezB,GAAO,EAAK,EAC3B0B,EAAqB1B,GAAO,EAAE,EAC9B2B,EAAmB3B,GAAO,EAAE,EAC5B4B,EAAiB5B,GAAsB,IAAI,EAI3C6B,EAAiB7B,GAAO,CAAC,EAE/B4B,EAAe,QAAUlB,EAGzBZ,GAAU,IAAM,CACd,GAAI,CAACkB,EAAW,OAChB,IAAMc,EAAKN,EAAS,QACfM,IACD,SAAS,gBAAkBA,EAC7BP,EAAW,EAAI,EAEfO,EAAG,MAAM,EAEb,EAAG,CAACd,EAAWO,CAAU,CAAC,EAM1BzB,GAAU,IAAM,CACd,IAAMgC,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,EAAgB3B,GAAgBqC,CAAE,CAAC,CACrC,EACA,OAAAC,EAAI,iBAAiB,kBAAmBC,CAAiB,EAClD,IAAMD,EAAI,oBAAoB,kBAAmBC,CAAiB,CAC3E,EAAG,CAACxB,EAAca,EAAmBD,CAAe,CAAC,EAMrDrB,GAAgB,IAAM,CACpB,IAAM+B,EAAKN,EAAS,QACfM,GACLnC,GAAsB,CACpB,MAAOmC,EACP,SAAUxB,EACV,WAAAC,EACA,eAAgBC,GAAc,IAAM,KACpC,gBAAiBG,GAAmB,GACpC,UAAAC,CACF,CAAC,CACH,EAAG,CAACN,EAAUC,EAAYC,EAAcG,EAAiBC,CAAS,CAAC,EAKnEb,GAAgB,IAAM,CACpB,IAAMqC,EAAWV,EAAmB,QAC9BW,EAAU9B,GAAc,GAE9B,GADAmB,EAAmB,QAAUW,EACzB,CAACA,GAAWA,IAAYD,EAAU,OACtC,IAAMN,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACTA,EAAG,MAAM,EAIT,IAAMQ,EAAUV,EAAe,SAAWlC,GAAgBoC,CAAE,EAC5DlC,GAAgBkC,EAAIQ,CAAO,CAC7B,EAAG,CAAC/B,CAAU,CAAC,EAKfR,GAAgB,IAAM,CACpB,IAAMqC,EAAWT,EAAiB,QAC5BU,EAAU7B,GAAc,IAAM,GAEpC,GADAmB,EAAiB,QAAUU,EACvB,CAACA,GAAWA,IAAYD,GAAY3B,GAAiB,KAAM,OAC/D,IAAMqB,EAAKN,EAAS,QACfM,GACLlC,GAAgBkC,EAAIrB,CAAa,CACnC,EAAG,CAACD,EAAcC,CAAa,CAAC,EAEhC,IAAM8B,EAAY1C,EAAY,IAAM,CAClC,GAAI4B,EAAa,QAAS,OAC1B,IAAMK,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMU,EAAMhD,GAAiBsC,CAAE,EAEzBW,EADmBD,EAAI,OAAS,GAAKA,EAAI,CAAC,IAAMA,EAAI,CAAC,EAAE,YAAY,EACzCA,EAAI,CAAC,EAAE,YAAY,EAAIA,EAAI,MAAM,CAAC,EAAIA,EACtEvB,EAAiBwB,CAAI,CACvB,EAAG,CAACxB,CAAgB,CAAC,EAEfyB,EAAmB7C,EAAY,IAAM,CACzCgC,EAAe,QAAU,YAAY,IAAI,EACzCU,EAAU,EACV,IAAMT,EAAKN,EAAS,QAChBM,GAAIX,EAAsB1B,GAAgBqC,CAAE,CAAC,CACnD,EAAG,CAACS,EAAWpB,CAAqB,CAAC,EAKrCrB,GAAU,IAAM,CACd,IAAMgC,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMa,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,GAClEvB,EAAoByB,CAAW,GACjCH,EAAE,eAAe,CAErB,CACF,EACA,OAAAd,EAAG,iBAAiB,cAAea,CAAa,EACzC,IAAMb,EAAG,oBAAoB,cAAea,CAAa,CAClE,EAAG,CAACrB,CAAmB,CAAC,EAExB,IAAM0B,EAAyBnD,EAAY,IAAM,CAC/C4B,EAAa,QAAU,EACzB,EAAG,CAAC,CAAC,EAECwB,GAAuBpD,EAAY,IAAM,CAC7C4B,EAAa,QAAU,GACvBc,EAAU,CACZ,EAAG,CAACA,CAAS,CAAC,EAERW,EAAcrD,EACjB+C,GAA2C,CAC1CA,EAAE,eAAe,EACjB,IAAMd,EAAKN,EAAS,QACpB,GAAI,CAACM,EAAI,OACT,IAAMqB,GAAQP,EAAE,cAAc,QAAQ,YAAY,GAAK,IAAI,QAAQ,SAAU,GAAG,EAChF,GAAI,CAACO,EAAM,OACX,IAAMpB,EAAMD,EAAG,eAAiB,SAC1BG,EAAMF,EAAI,aAAa,EAC7B,GAAI,CAACE,GAAOA,EAAI,aAAe,EAAG,OAClC,IAAMmB,EAAQnB,EAAI,WAAW,CAAC,EAC9B,GAAI,CAACH,EAAG,SAASsB,EAAM,cAAc,EAAG,OACxCA,EAAM,eAAe,EACrB,IAAMC,EAAOtB,EAAI,eAAeoB,CAAI,EACpCC,EAAM,WAAWC,CAAI,EACrBD,EAAM,cAAcC,CAAI,EACxBD,EAAM,SAAS,EAAI,EACnBnB,EAAI,gBAAgB,EACpBA,EAAI,SAASmB,CAAK,EAClBb,EAAU,CACZ,EACA,CAACA,CAAS,CACZ,EAEMe,EAAqBzD,EACxB+C,GAA0C1B,EAAc0B,CAAC,EAC1D,CAAC1B,CAAa,CAChB,EAEMqC,EAAc1D,EAAY,IAAM0B,EAAW,EAAI,EAAG,CAACA,CAAU,CAAC,EAC9DiC,EAAa3D,EAAY,IAAM0B,EAAW,EAAK,EAAG,CAACA,CAAU,CAAC,EAE9DkC,EAAQ5D,EAAY,IAAM2B,EAAS,SAAS,MAAM,EAAG,CAAC,CAAC,EACvDkC,GAAO7D,EAAY,IAAM2B,EAAS,SAAS,KAAK,EAAG,CAAC,CAAC,EACrDmC,EAAe9D,EAAY,IAAM,CACrC,IAAMiC,EAAKN,EAAS,QACpB,OAAOM,EAAKtC,GAAiBsC,CAAE,EAAI,EACrC,EAAG,CAAC,CAAC,EAEC8B,EAAS1D,GAAsB,EAAI,iBAAmB,OAE5D,MAAO,CACL,SAAAsB,EACA,YAAa,CACX,IAAKA,EACL,gBAAiBoC,EACjB,+BAAgC,GAChC,SAAU,EACV,KAAM,WACN,oBAAqB,OACrB,gBAAiB,UACjB,gBAAiB9C,EACjB,gBAAiBD,EACjB,wBAAyBE,EACzB,WAAY,GACZ,aAAc,OACd,QAAS2B,EACT,UAAWY,EACX,mBAAoBN,EACpB,iBAAkBC,GAClB,QAASC,EACT,QAASK,EACT,OAAQC,CACV,EACA,aAAAG,EACA,MAAAF,EACA,KAAAC,EACF,CACF,CZpGQ,cAAAG,EAIE,QAAAC,OAJF,oBAnOR,SAASC,GAAmBC,EAAwC,CAClE,OAAIA,IAAS,OAAeA,EACxB,OAAO,OAAW,KACf,OAAO,WAAW,8BAA8B,EAAE,QADf,OACkC,OAC9E,CAEO,IAAMC,GAAiBC,GAC5B,SACE,CACE,SAAAC,EACA,QAAAC,EACA,gBAAAC,EACA,kBAAAC,EACA,UAAAC,EACA,UAAAC,EACA,QAAAC,EACA,cAAAC,EAAgB,SAChB,KAAAV,EAAO,OACP,gBAAAW,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,EACA,CACA,IAAMC,EAAeC,GAAuB,IAAI,EAC1CC,EAAmBD,GAAwB,IAAI,EAC/CE,EAAkBF,GAA6C,IAAM,CAAC,CAAC,EACvEG,EAAoBH,GAA8B,IAAI,EAItDI,GAAuBJ,GAA+C,IAAI,EAEhFK,GAAU,IAAM,CACd,IAAMC,EAAKP,EAAa,QACxB,GAAKO,EACL,OAAIH,EAAkB,QACpBA,EAAkB,QAAQ,QAAQ7B,CAAI,EAEtC6B,EAAkB,QAAU,IAAII,GAAeD,EAAIhC,CAAI,EAElD,IAAM,CACX6B,EAAkB,SAAS,QAAQ,EACnCA,EAAkB,QAAU,IAC9B,CACF,EAAG,CAAC7B,CAAI,CAAC,EAET,IAAMkC,EAAkBC,GAAaC,GAAmB,CACtD,IAAMJ,EAAKF,GAAqB,SAAS,QACpCE,IACLA,EAAG,MAAM,EACTK,GAAgBL,EAAII,CAAM,EAC5B,EAAG,CAAC,CAAC,EAEC,CACJ,gBAAAE,EACA,gBAAAC,EACA,cAAAC,EACA,SAAAC,EACA,WAAAC,GACA,gBAAAC,EACA,gBAAAC,EACA,UAAAC,EACA,eAAAC,EACA,UAAAC,EACA,YAAAC,EACA,UAAAC,EACA,iBAAAC,EACA,cAAAC,EACA,WAAAC,EACA,aAAAC,GACA,cAAAC,GACA,YAAAC,GACA,kBAAAC,EACA,sBAAAC,EACA,gBAAAC,EACA,oBAAAC,GACA,cAAAC,GACA,MAAAC,EACF,EAAIC,GAAkB,CACpB,SAAWC,GAAWnC,EAAgB,QAAQmC,CAAM,EACpD,QAAA3D,EACA,gBAAAC,EACA,kBAAAC,EACA,UAAAE,EACA,QAAAC,EACA,gBAAAI,EACA,gBAAAF,EACA,oBAAAG,EACA,uBAAAC,EACA,QAAAE,EACA,OAAAC,EACA,MAAAC,EACA,gBAAiBC,EACjB,SAAUC,EACV,eAAAC,EACA,OAAQ,WACR,UAAWY,CACb,CAAC,EAGDH,GAAU,IAAM,CACd,GAAI,CAACW,GAAY,OACjB,IAAMsB,EAAI,OAAO,WAAW,IAAMrB,EAAgB,EAAG,GAAG,EACxD,MAAO,IAAM,OAAO,aAAaqB,CAAC,CACpC,EAAG,CAACtB,GAAYC,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,EACA,WAAAC,GACA,aAAAW,GACA,cAAAC,GACA,YAAAC,GACA,gBAAAX,EACA,UAAAC,EACA,eAAAC,EACA,UAAAG,EACA,mBAAAgB,GACA,UAAAjD,EACA,iBAAAkC,EACA,cAAAC,EACA,sBAAAM,EACA,gBAAAC,EACA,kBAAAF,EACA,oBAAAG,GACA,WAAAP,CACF,CAAC,EAKDtB,GAAqB,QAAUoC,GAS/BM,GAAgB,IAAM,CACpB,IAAMC,EAAY9C,EAAiB,QAC7B+C,EAASR,GAAS,QACxB,GAAI,CAACO,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,CAACtC,EAAUF,EAAgB,OAAQQ,EAAWmB,EAAQ,CAAC,EAE1Dc,GACExD,EACA,KAAO,CACL,MAAA4C,GACA,KAAAC,GACA,MAAAR,GACA,QAAUoB,GAAMpD,EAAkB,SAAS,QAAQoD,CAAC,CACtD,GACA,CAACb,GAAOC,GAAMR,EAAK,CACrB,EAEA,IAAMqB,GAAY,CAAC,CAACzC,EAAS,QAAUH,EAAgB,OAAS,EAE1D6C,GAAehD,GAAY,IAAM,CACrC,GAAI,CAAC+C,GAAW,OAChB,IAAME,EAAOd,GAAa,EACpB,CAAE,SAAAe,EAAU,gBAAiBC,EAAY,EAAIC,GAAWH,EAAM9C,CAAe,EACnFnC,EAAS,CACP,MAAOiF,EAAK,KAAK,EACjB,UAAWC,EACX,iBAAkBC,EACpB,CAAC,EACDzB,GAAM,CACR,EAAG,CAACqB,GAAW5C,EAAiBnC,EAAU0D,GAAOS,EAAY,CAAC,EAE9D1C,EAAgB,QAAUuD,GAE1B,IAAMK,GAAqBrD,GACxBsD,GAAwC,CAExBA,EAAE,QACL,QAAQ,iBAAiB,GACrCrB,GAAM,CACR,EACA,CAACA,EAAK,CACR,EAEMsB,GAAkBhF,IAAkB,SACpCiF,GAAoBjF,IAAkB,WAE5C,OACEZ,GAAC,OACC,IAAK2B,EACL,UAAW,cAAcmE,EAAO,SAAS,IAAIrF,GAAa,EAAE,GAC5D,sBAAqBG,EACrB,wBAAuBC,EACvB,kBAAiBC,EAAa,KAAO,MACrC,YAAWb,GAAmBC,CAAI,EAElC,UAAAH,EAACgG,GAAA,CAAwB,GAAGjC,GAAe,UAAW+B,GAAmB,EAGzE7F,GAAC,OAAI,UAAW8F,EAAO,aAAc,QAASJ,GAC5C,UAAA1F,GAAC,OAAI,UAAW8F,EAAO,WAAY,kBAAgB,GACjD,UAAA/F,EAAC,OAAK,GAAGsE,GAAa,UAAWyB,EAAO,MAAO,iBAAe,GAAG,EAChEF,KAAoB3C,GAAaR,EAAgB,OAAS,IACzD1C,EAAC,QACC,IAAK8B,EACL,UAAWiE,EAAO,kBAClB,+BAA6B,GAE7B,SAAA/F,EAACiG,GAAA,CACC,MAAOvD,EACP,gBAAiB,EACjB,aAAcC,EACd,QAASO,EACX,EACF,GAEJ,EACCxB,IAAiB,KAAO,KAAOA,IAAiB,OAC/C1B,EAAC,UACC,KAAK,SACL,kBAAgB,GAChB,UAAW+F,EAAO,aAClB,SAAU,CAACV,GACX,QAAUO,GAAM,CACdA,EAAE,gBAAgB,EAClBN,GAAa,CACf,EACA,aAAW,SAEX,SAAAtF,EAAC,OACC,MAAM,KACN,OAAO,KACP,QAAQ,YACR,KAAK,OACL,KAAK,MACL,aAAW,SAEX,SAAAA,EAAC,QACC,EAAE,2BACF,OAAO,eACP,YAAY,IACZ,cAAc,QACd,eAAe,QACjB,EACF,EACF,EAIAA,EAAC,QACC,kBAAgB,GAChB,UAAW+F,EAAO,WAClB,QAAUH,GAAM,CACTP,KACLO,EAAE,gBAAgB,EAClBN,GAAa,EACf,EAEC,SAAA5D,EACH,GAEJ,GACF,CAEJ,CACF","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useLayoutEffect","useRef","s","AIAutocomplete_module_css_default","s","AIAutocompleteDropdown_module_css_default","s","PillList_module_css_default","jsx","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","rounded","loading","PillList_module_css_default","w","i","pill","e","useEffect","useLayoutEffect","useRef","useState","s","SuggestionGrid_module_css_default","useEffect","useRef","useState","s","SuggestionItem_module_css_default","jsx","jsxs","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","pressed","setPressed","useState","timerRef","useRef","useEffect","handleSelect","className","SuggestionItem_module_css_default","e","jsx","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","gridRef","useRef","hasBottomOverflow","setHasBottomOverflow","useState","useEffect","el","update","resizeObserver","useLayoutEffect","SuggestionGrid_module_css_default","option","i","SuggestionItem","jsx","jsxs","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","buildQuery","ModeController","setCursorOffset","CoreAIAutocomplete","useCallback","useEffect","useRef","useState","EMPTY_STATE","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","apiConfig","columns","dropdownTrigger","optionsPosition","closeDropdownOnBlur","showNonTappableOptions","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","instance","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","extractPlainText","getCursorOffset","plainTextLength","renderEditableContent","setCursorOffset","useCallback","useEffect","useLayoutEffect","useRef","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","previous","current","desired","fireInput","raw","next","handleInputEvent","onBeforeInput","e","inputEvent","t","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","range","node","handleKeyDownReact","handleFocus","handleBlur","focus","blur","getPlainText","ceMode","jsx","jsxs","resolveInitialMode","mode","AIAutocomplete","forwardRef","onSubmit","onError","optionOverrides","maskCompletedText","className","apiConfig","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","submitButton","ref","containerRef","useRef","pillContainerRef","handleSubmitRef","modeControllerRef","editorInputRefHolder","useEffect","el","ModeController","handleSetCursor","useCallback","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","useLayoutEffect","container","editor","update","inner","cRect","eRect","ro","useImperativeHandle","m","canSubmit","handleSubmit","text","rawQuery","finalParams","buildQuery","handleWrapperClick","e","showInlinePills","showDropdownPills","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList"]}
1
+ {"version":3,"sources":["../src/AIAutocomplete.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocomplete.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/AIAutocompleteDropdown.module.css.js","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/PillList.module.css.js","../src/components/PillList.tsx","../src/components/SuggestionGrid.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionGrid.module.css.js","../src/components/SuggestionItem.tsx","css-module:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/components/SuggestionItem.module.css.js","../src/AIAutocompleteDropdown.tsx","plain-css:/home/runner/work/ai-autocomplete-sdk-js/ai-autocomplete-sdk-js/packages/react/src/appearance.css.js","../src/hooks/useAIAutocomplete.ts","../src/hooks/useContentEditableEditor.ts"],"sourcesContent":["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 {\n type AppearanceMode,\n type AutocompleteResult,\n buildQuery,\n ModeController,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport { useContentEditableEditor } from \"./hooks/useContentEditableEditor\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps } from \"./types\";\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 optionsPosition,\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 that case and drop the margin via a data attribute the CSS\n // keys off. The wrap detection (pill row's top vs editor's bottom)\n // already handles the placeholder-only case correctly: the placeholder\n // still occupies the editor's line box, so pills sitting beside it are\n // NOT wrapped and the margin stays.\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 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-67791514\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-67791514\";\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: 6px;\n padding: 2px 3px;\n /* Pull surrounding inline text back so the wider/taller fill doesn't shove\n the rest of the line — only the visible background grows. */\n margin: 0 -1.5px;\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}\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-3819c762\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-3819c762\";\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 3px 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-0fcb7940\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0fcb7940\";\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}\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-ff33a0ab\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-ff33a0ab\";\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 <span className={styles.text}>\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n </span>\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-82820da7\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-82820da7\";\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 font-weight: 250;\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 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}\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}\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/* Skeleton fill is on the inner text span (a true inline element) so multi-\n line options wrap into one skeleton bar per line. The outer .content is a\n flex item — blockified by spec — so painting the background there would\n collapse all lines into one tall rectangle. \\`box-decoration-break: clone\\`\n makes the radius render cleanly on each line bar. */\n.SuggestionItem-module_item_d4vpD[data-aia-loading] .SuggestionItem-module_text_yqoh9 {\n color: transparent;\n background: var(--aia-skeleton-bg, var(--aia-pill-bg, rgba(189, 189, 189, 0.51)));\n border-radius: 999px;\n -webkit-box-decoration-break: clone;\n box-decoration-break: clone;\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\",\"text\":\"SuggestionItem-module_text_yqoh9\"};","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-0ae03977\")) {\n const s = document.createElement(\"style\");\n s.id = \"ac-style-0ae03977\";\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: #4f4f4f;\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: #b0b0b0;\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: 13px 27px 13px 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 {};","import {\n AIAutocomplete as CoreAIAutocomplete,\n type CoreState,\n type Suggestion,\n type SuggestionOption,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useRef,\n useState,\n} from \"react\";\nimport type { UseAIAutocompleteOptions, UseAIAutocompleteReturn } 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 optionsPosition,\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 optionsPosition,\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 optionsPosition,\n closeDropdownOnBlur,\n showNonTappableOptions,\n });\n }, [\n apiConfigJson,\n overridesVersion.current,\n dropdownTrigger,\n optionsPosition,\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 {\n type CompletedParamState,\n extractPlainText,\n getCursorOffset,\n plainTextLength,\n renderEditableContent,\n type Segment,\n setCursorOffset,\n} from \"@magicx-eng/ai-autocomplete-vanilla\";\nimport {\n type ClipboardEvent as ReactClipboardEvent,\n type KeyboardEvent as ReactKeyboardEvent,\n useCallback,\n useEffect,\n useLayoutEffect,\n useRef,\n} from \"react\";\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":"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","names":["forwardRef","useCallback","useEffect","useImperativeHandle","useLayoutEffect","useRef","s","AIAutocomplete_module_css_default","s","AIAutocompleteDropdown_module_css_default","s","PillList_module_css_default","jsx","FALLBACK_SKELETON_WIDTHS","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","rounded","loading","PillList_module_css_default","w","i","pill","e","useEffect","useLayoutEffect","useRef","useState","s","SuggestionGrid_module_css_default","useEffect","useRef","useState","s","SuggestionItem_module_css_default","jsx","jsxs","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","loading","pressed","setPressed","useState","timerRef","useRef","useEffect","handleSelect","className","SuggestionItem_module_css_default","e","jsx","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","loading","gridRef","useRef","hasBottomOverflow","setHasBottomOverflow","useState","useEffect","el","update","resizeObserver","useLayoutEffect","SuggestionGrid_module_css_default","option","i","SuggestionItem","jsx","jsxs","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","buildQuery","ModeController","setCursorOffset","CoreAIAutocomplete","useCallback","useEffect","useRef","useState","EMPTY_STATE","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","apiConfig","columns","dropdownTrigger","optionsPosition","closeDropdownOnBlur","showNonTappableOptions","onFocus","onBlur","controlledValue","controlledParams","onChangeProp","onParamsChange","source","setCursor","instanceRef","coreState","setCoreState","onSubmitRef","onErrorRef","onChangeRef","onParamsChangeRef","onFocusRef","onBlurRef","setCursorRef","instance","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","extractPlainText","getCursorOffset","plainTextLength","renderEditableContent","setCursorOffset","useCallback","useEffect","useLayoutEffect","useRef","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","previous","current","desired","fireInput","raw","next","handleInputEvent","onBeforeInput","e","inputEvent","t","replacement","handleCompositionStart","handleCompositionEnd","handlePaste","text","range","node","handleKeyDownReact","handleFocus","handleBlur","focus","blur","getPlainText","ceMode","jsx","jsxs","resolveInitialMode","mode","AIAutocomplete","forwardRef","onSubmit","onError","optionOverrides","maskCompletedText","className","apiConfig","columns","pillPlacement","optionsPosition","animations","dropdownTrigger","closeDropdownOnBlur","showNonTappableOptions","autoFocus","onFocus","onBlur","value","controlledParams","onChangeProp","onParamsChange","submitButton","ref","containerRef","useRef","pillContainerRef","handleSubmitRef","modeControllerRef","editorInputRefHolder","useEffect","el","ModeController","handleSetCursor","useCallback","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","useLayoutEffect","container","editor","update","inner","cRect","eRect","ro","useImperativeHandle","m","canSubmit","handleSubmit","text","rawQuery","finalParams","buildQuery","handleWrapperClick","e","showInlinePills","showDropdownPills","AIAutocomplete_module_css_default","AIAutocompleteDropdown","PillList"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@magicx-eng/ai-autocomplete-react",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "AI Autocomplete React SDK — guided autocomplete with pill-based input and dropdown suggestions",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -29,7 +29,7 @@
29
29
  "react-dom": ">=17.0.0"
30
30
  },
31
31
  "dependencies": {
32
- "@magicx-eng/ai-autocomplete-vanilla": "0.2.0"
32
+ "@magicx-eng/ai-autocomplete-vanilla": "0.2.1"
33
33
  },
34
34
  "devDependencies": {
35
35
  "@testing-library/jest-dom": "^6.9.1",