@magicx-eng/ai-autocomplete-react 0.1.3 → 0.1.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/api.ts","../src/utils/buildQuery.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AIAutocompleteDropdownProps,\n AIAutocompleteProps,\n AutocompleteRequest,\n AutocompleteResponse,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n InputItem,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import { useCallback, useEffect, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteProps } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport function AIAutocomplete({\n onSubmit,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n}: AIAutocompleteProps) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n const handleSubmitRef = useRef<() => void>(() => {});\n\n useEffect(() => {\n textareaRef.current?.focus();\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n activePillIndex,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: () => handleSubmitRef.current(),\n optionOverrides,\n maskCompletedText,\n placeholder,\n });\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg width=\"72\" height=\"72\" viewBox=\"0 0 24 24\" fill=\"none\" role=\"img\" aria-label=\"Success\">\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList\n pills={suggestionPills}\n activePillIndex={activePillIndex}\n onSelectPill={setActivePill}\n />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\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 </div>\n </div>\n );\n}\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--color-text-default, #fff);\n caret-color: var(--color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--color-text-default, #fff);\n color: var(--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.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n animation: fadeIn 200ms ease forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 200ms ease forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import 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}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import 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}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div 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 />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n if (!isOpen || suggestions.length === 0) return null;\n\n const activeSuggestion = suggestions[0];\n if (activeSuggestion.options.length === 0) return null;\n\n return (\n // biome-ignore lint/a11y/noStaticElementInteractions: preventDefault keeps focus on textarea\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={() => {}}\n listboxId={id}\n />\n </div>\n );\n}\n",".list {\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.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--color-background-supportive, #313255);\n color: var(--color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 200ms ease forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","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}\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({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import {\n type ChangeEvent,\n type KeyboardEvent,\n useCallback,\n useEffect,\n useId,\n useMemo,\n useRef,\n useState,\n} from \"react\";\nimport type {\n CompletedParamState,\n Segment,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nfunction filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nfunction findExactMatch(options: SuggestionOption[], query: string): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nfunction deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nfunction reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nfunction applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Core state ===\n const [completedParams, setCompletedParams] = useState<CompletedParamState[]>([]);\n const [text, setText] = useState(\"\");\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useId();\n\n // === Fetch ===\n const doFetch = useCallback(async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n\n // Only show loading if no suggestions are currently displayed,\n // to avoid flickering the dropdown closed and reopened.\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n });\n\n // Only process the rest if this is still the latest request\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n // If the last input segment is in_progress, the filter should include\n // everything the user typed that hasn't been completed — set filterBase\n // to the end of all completed segments in the current text.\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.lastIndexOf(lastInput.text);\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = currentText.length;\n }\n } else {\n filterBaseRef.current = currentText.length;\n }\n\n // Check if the user already typed an exact match while waiting for the response\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n setError(err instanceof Error ? err : new Error(String(err)));\n setIsLoading(false);\n }\n }\n // biome-ignore lint/correctness/useExhaustiveDependencies: optionOverrides read via ref to keep doFetch stable\n }, []);\n\n // === Mount fetch ===\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n // Clamp filterBase if user backspaced\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n // biome-ignore lint/suspicious/noConsole: debug logging\n console.log(`[filter] base=${filterBaseRef.current} query=\"${filterQuery}\" text=\"${text}\"`);\n\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n // Server placeholder takes priority, custom placeholder is the fallback\n const placeholderText = serverPlaceholder || customPlaceholder || \"\";\n const actionableSuggestions = suggestions.filter((s) => s.type !== \"placeholder\");\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const filteredOptions = activeSuggestion\n ? overrideFn && filterQuery.trim()\n ? overrideFn(filterQuery.trim())\n : filterOptions(activeSuggestion.options ?? [], filterQuery)\n : [];\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Handlers ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n // Replace filter text + any partial word before it that the option completes.\n // Step 1: Always strip the filter text (everything after filterBase)\n const base = filterBaseRef.current;\n let prefix = text.slice(0, base);\n // Step 2: If the last word before filterBase is a partial start of the option,\n // trim it too (e.g. \"Create a campa|i\" → \"campa\" starts \"campaign\")\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n // If there are other actionable suggestions remaining, the client already\n // knows what to show next — skip the network call the debounce would trigger.\n const remainingActionable = actionableSuggestions.length - 1;\n if (remainingActionable > 0) {\n skipNextFetchRef.current = true;\n }\n },\n [activeSuggestion, actionableSuggestions, text],\n );\n\n const handleChange = useCallback(\n (e: ChangeEvent<HTMLTextAreaElement>) => {\n const raw = e.target.value;\n const newValue = raw.length > 0 ? raw[0].toUpperCase() + raw.slice(1) : raw;\n setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n // Reconcile — check if any completed params were modified\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n // Check exact match on the new filter query (only if no params were broken)\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion],\n );\n\n // === Debounced fetch on typing ===\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n /** Returns true if a fetch was triggered. */\n const attemptFetch = (minDiff: number): boolean => {\n // After selecting an option when other suggestions remain, skip the fetch\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n // Reset: if input is cleared, fetch fresh suggestions\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n // Check if current tappable options can still handle the filter\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n // Only skip fetch if there are tappable filtered options and no exact match.\n // Non-tappable options (hints) don't count — we still need server results.\n // Skip this gate if filterQuery is empty — options are showing vacuously.\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n // Fast debounce: fires at 100ms, requires >= 2 char diff\n // If it fetches, cancel the slow timer since the request is already made.\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n // Slow debounce: fires at 300ms, requires >= 1 char diff (catches single-char pauses)\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [text, completedParams, doFetch]);\n\n const getTappableIndices = useCallback(() => {\n const cols = 2;\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n // Reorder to column-first: all left column items, then all right column items\n const left = tappable.filter((i) => i % cols === 0);\n const right = tappable.filter((i) => i % cols === 1);\n return [...left, ...right];\n }, [filteredOptions]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n const cols = 2;\n if (activeDropdownIndex % cols === 0) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n const cols = 2;\n if (activeDropdownIndex % cols === 1) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n onSubmitRef.current();\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n if (placeholderSuggestion) {\n setCompletedParams((prev) => [\n ...prev,\n {\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n filteredOptions,\n hasPlaceholder,\n isDropdownOpen,\n placeholderText,\n selectOption,\n suggestions,\n getTappableIndices,\n text,\n ],\n );\n\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams]);\n\n const reEditParam = useCallback((param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n setText((prev) => {\n const idx = prev.indexOf(param.text);\n if (idx === -1) return prev;\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n });\n setCompletedParams((prev) => prev.filter((p) => p !== param));\n setSuggestions((prev) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n }, []);\n\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams([]);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n setIsReady(false);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n activePillIndex: 0,\n setActivePill,\n removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type {\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\nconst SDK_VERSION = \"0.1.0\";\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst API_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/api/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(): string {\n const key = process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(): \"Bearer\" | \"Basic\" {\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: { maskCompletedText?: boolean; signal?: AbortSignal },\n): Promise<AutocompleteResponse> {\n const apiKey = getApiKey();\n const authScheme = getAuthScheme();\n const includeText = !options?.maskCompletedText;\n\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(API_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","i","SuggestionItem","import_jsx_runtime","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","isOpen","id","className","activeSuggestion","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","import_jsx_runtime","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","import_react","SDK_VERSION","API_ENDPOINT","hasWarnedMissingKey","getApiKey","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiKey","authScheme","rawCount","p","contactAccountCount","body","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","deduped","useAIAutocomplete","onSubmit","optionOverrides","maskCompletedText","customPlaceholder","setCompletedParams","setText","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","isLoading","setIsLoading","error","setError","isReady","setIsReady","fetchVersionRef","abortRef","lastRawQueryRef","onSubmitRef","optionOverridesRef","maskCompletedTextRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","rawQuery","completed","controller","version","res","fetchSuggestions","newSuggestions","input","lastInput","currentText","inProgressIdx","active","match","prev","err","segments","filterQuery","placeholderText","actionableSuggestions","activeSuggestion","overrideFn","filteredOptions","hasPlaceholder","isDropdownOpen","selectOption","option","base","prefix","lastWord","needsSpace","newText","handleChange","e","raw","newValue","newFilterQuery","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","getTappableIndices","tappable","i","left","right","handleKeyDown","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","firstTappable","placeholderSuggestion","setActivePill","index","actionable","moved","rest","_","placeholders","removeLastParam","lastParam","restoredSuggestion","reEditParam","before","after","cleaned","p","reset","activeDescendantId","import_jsx_runtime","AIAutocomplete","onSubmit","optionOverrides","maskCompletedText","placeholder","className","textareaRef","showCheckmark","setShowCheckmark","handleSubmitRef","completedParams","suggestionPills","activePillIndex","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","handleContainerClick","canSubmit","handleSubmit","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/AIAutocomplete.tsx","../src/AIAutocomplete.module.css","../src/AIAutocompleteDropdown.module.css","../src/components/SuggestionGrid.module.css","../src/components/SuggestionItem.module.css","../src/components/SuggestionItem.tsx","../src/components/SuggestionGrid.tsx","../src/AIAutocompleteDropdown.tsx","../src/components/PillList.module.css","../src/components/PillList.tsx","../src/hooks/useAIAutocomplete.ts","../src/utils/filtering.ts","../src/utils/segments.ts","../src/hooks/useAutocompleteFetch.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/hooks/useAutocompleteKeyboard.ts","../src/hooks/useAutocompletePills.ts"],"sourcesContent":["export { AIAutocomplete } from \"./AIAutocomplete\";\nexport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nexport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nexport type {\n AIAutocompleteDropdownProps,\n AIAutocompleteHandle,\n AIAutocompleteProps,\n APIConfig,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n OptionOverrides,\n Segment,\n Suggestion,\n SuggestionOption,\n TaskKind,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"./types\";\n","import { forwardRef, useCallback, useEffect, useImperativeHandle, useRef, useState } from \"react\";\nimport styles from \"./AIAutocomplete.module.css\";\nimport { AIAutocompleteDropdown } from \"./AIAutocompleteDropdown\";\nimport { PillList } from \"./components/PillList\";\nimport { useAIAutocomplete } from \"./hooks/useAIAutocomplete\";\nimport type { AIAutocompleteHandle, AIAutocompleteProps, AutocompleteResult } from \"./types\";\nimport { buildQuery } from \"./utils/buildQuery\";\n\nexport const AIAutocomplete = forwardRef<AIAutocompleteHandle, AIAutocompleteProps>(\n function AIAutocomplete(\n {\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n className,\n apiConfig,\n columns,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n },\n ref,\n ) {\n const textareaRef = useRef<HTMLTextAreaElement>(null);\n const [showCheckmark, setShowCheckmark] = useState(false);\n // Render-phase ref assignment — matches the pattern in useAIAutocomplete.ts\n const handleSubmitRef = useRef<(result: AutocompleteResult) => void>(() => {});\n const checkmarkTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined);\n\n useEffect(() => {\n textareaRef.current?.focus();\n return () => clearTimeout(checkmarkTimerRef.current);\n }, []);\n\n const {\n completedParams,\n suggestionPills,\n setActivePill,\n segments,\n inputProps,\n dropdownProps,\n reset,\n } = useAIAutocomplete({\n onSubmit: (result) => handleSubmitRef.current(result),\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder,\n apiConfig,\n columns,\n value,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n });\n\n useImperativeHandle(\n ref,\n () => ({\n focus: () => textareaRef.current?.focus(),\n reset,\n }),\n [reset],\n );\n\n const handleContainerClick = () => {\n textareaRef.current?.focus();\n };\n\n const canSubmit = !!inputProps.value || completedParams.length > 0;\n\n const handleSubmit = useCallback(() => {\n if (!canSubmit) return;\n const { rawQuery, completedParams: finalParams } = buildQuery(\n inputProps.value,\n completedParams,\n );\n onSubmit({\n query: inputProps.value.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n reset();\n setShowCheckmark(true);\n clearTimeout(checkmarkTimerRef.current);\n checkmarkTimerRef.current = setTimeout(() => setShowCheckmark(false), 3000);\n }, [canSubmit, inputProps.value, completedParams, onSubmit, reset]);\n\n handleSubmitRef.current = handleSubmit;\n\n const { onChange, placeholder: inputPlaceholder, ...restProps } = inputProps;\n const isEmpty = !inputProps.value;\n\n return (\n <div className={`${styles.container} ${className ?? \"\"}`}>\n <div className={`${styles.checkmark} ${showCheckmark ? styles.checkmarkVisible : \"\"}`}>\n <svg\n width=\"72\"\n height=\"72\"\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n role=\"img\"\n aria-label=\"Success\"\n >\n <circle cx=\"12\" cy=\"12\" r=\"12\" fill=\"#34C759\" />\n <path\n d=\"M7 12.5l3.5 3.5L17 9\"\n stroke=\"#000\"\n strokeWidth=\"2.5\"\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={styles.checkmarkPath}\n />\n </svg>\n </div>\n <AIAutocompleteDropdown {...dropdownProps} />\n {/* biome-ignore lint/a11y/useKeyWithClickEvents: container click delegates to textarea focus */}\n {/* biome-ignore lint/a11y/noStaticElementInteractions: wrapper delegates focus to textarea */}\n <div className={styles.inputWrapper} onClick={handleContainerClick}>\n <div className={styles.editorArea}>\n <div className={styles.sizerContent} aria-hidden=\"true\">\n {isEmpty && inputPlaceholder ? (\n <span className={styles.placeholderText}>{inputPlaceholder} </span>\n ) : (\n <span className={styles.sizerText}>\n {segments.map((seg, i) => (\n // biome-ignore lint/suspicious/noArrayIndexKey: segments are positional and don't reorder\n <span key={`${i}-${seg.type}`}>{seg.value}</span>\n ))}\n {segments.length === 0 && \"\\u00A0\"}\n </span>\n )}\n {\" \"}\n <PillList pills={suggestionPills} activePillIndex={0} onSelectPill={setActivePill} />\n </div>\n <textarea\n ref={textareaRef}\n className={styles.textarea}\n rows={1}\n onChange={onChange}\n {...restProps}\n />\n </div>\n <button\n type=\"button\"\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 </div>\n </div>\n );\n },\n);\n",".container {\n position: relative;\n font-family: \"IBM Plex Sans\", sans-serif;\n}\n\n.checkmark {\n position: absolute;\n bottom: -130px;\n left: 50%;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n opacity: 0;\n pointer-events: none;\n z-index: 10;\n animation: none;\n}\n\n.checkmarkVisible {\n animation: checkmarkFadeInOut 3s ease forwards;\n}\n\n@keyframes checkmarkFadeInOut {\n 0% {\n opacity: 0;\n transform: translateX(-50%) translateY(8px) scale(0.8);\n }\n 10% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 80% {\n opacity: 1;\n transform: translateX(-50%) translateY(0) scale(1);\n }\n 100% {\n opacity: 0;\n transform: translateX(-50%) translateY(-8px) scale(0.8);\n }\n}\n\n.checkmarkPath {\n stroke-dasharray: 30;\n stroke-dashoffset: 30;\n}\n\n.checkmarkVisible .checkmarkPath {\n animation: drawCheck 0.4s ease forwards 0.1s;\n}\n\n@keyframes drawCheck {\n to {\n stroke-dashoffset: 0;\n }\n}\n\n.inputWrapper {\n min-height: 60px;\n padding: 24px;\n border: 1px solid var(--ac-color-border-default, #9ea5b2);\n border-radius: 23px;\n background: transparent;\n overflow: hidden;\n display: flex;\n align-items: center;\n gap: 12px;\n}\n\n.editorArea {\n position: relative;\n flex: 1;\n min-width: 0;\n}\n\n.sizerContent {\n position: relative;\n z-index: 1;\n pointer-events: none;\n min-height: 60px;\n white-space: pre-wrap;\n word-break: break-word;\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n}\n\n.sizerText {\n color: transparent;\n}\n\n.placeholderText {\n color: var(--ac-color-text-muted, #c1c4cb);\n opacity: 0.7;\n}\n\n.textarea {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n padding: 0;\n border: none;\n background: transparent;\n color: var(--ac-color-text-default, #fff);\n caret-color: var(--ac-color-text-default, #fff);\n font-family: inherit;\n font-size: 21px;\n line-height: 38px;\n white-space: pre-wrap;\n word-break: break-word;\n outline: none;\n resize: none;\n overflow: hidden;\n}\n\n.textarea::placeholder {\n color: var(--ac-color-text-muted, #c1c4cb);\n}\n\n.submitButton {\n flex-shrink: 0;\n width: 36px;\n height: 36px;\n border-radius: 50%;\n border: none;\n background: var(--ac-color-text-default, #fff);\n color: var(--ac-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.submitButton:hover {\n opacity: 0.85;\n}\n",".dropdown {\n position: absolute;\n left: 0;\n right: 0;\n top: 100%;\n margin-top: 6px;\n background: var(--ac-color-background-default, #00002d);\n border-radius: 23px;\n overflow: hidden;\n z-index: 10;\n opacity: 0;\n pointer-events: none;\n transition: opacity 400ms cubic-bezier(0.4, 0, 0.2, 1);\n}\n\n.visible {\n opacity: 1;\n pointer-events: auto;\n}\n",".grid {\n display: grid;\n grid-template-columns: 1fr 1fr;\n gap: 12px 18px;\n padding: 18px 24px;\n max-height: 192px;\n overflow-y: auto;\n scrollbar-width: thin;\n scrollbar-color: rgba(255, 255, 255, 0.3) transparent;\n}\n\n.grid::-webkit-scrollbar {\n width: 6px;\n}\n\n.grid::-webkit-scrollbar-track {\n background: transparent;\n}\n\n.grid::-webkit-scrollbar-thumb {\n background: rgba(255, 255, 255, 0.3);\n border-radius: 3px;\n}\n",".item {\n display: flex;\n align-items: center;\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n color: var(--ac-color-text-muted, #c1c4cb);\n white-space: nowrap;\n opacity: 0.35;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n\n.tappable {\n cursor: pointer;\n}\n\n.tappable:hover {\n color: var(--ac-color-text-default, #fff);\n}\n\n.nonTappable {\n cursor: default;\n opacity: 0.3;\n}\n\n.highlighted {\n color: var(--ac-color-text-default, #fff);\n opacity: 0.5;\n}\n\n.tag {\n font-size: 13px;\n margin-left: 6px;\n opacity: 0.5;\n}\n","import 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}\n\nexport function SuggestionItem({\n option,\n isHighlighted,\n onSelect,\n onHighlight,\n id,\n}: SuggestionItemProps) {\n const className = [\n styles.item,\n isHighlighted ? styles.highlighted : \"\",\n option.is_tappable ? styles.tappable : styles.nonTappable,\n ]\n .filter(Boolean)\n .join(\" \");\n\n return (\n <div\n id={id}\n role=\"option\"\n aria-selected={isHighlighted}\n className={className}\n tabIndex={option.is_tappable ? 0 : -1}\n onClick={() => option.is_tappable && onSelect(option)}\n onKeyDown={(e) => {\n if (option.is_tappable && (e.key === \"Enter\" || e.key === \" \")) {\n e.preventDefault();\n onSelect(option);\n }\n }}\n onMouseEnter={onHighlight}\n >\n {option.icon ? `${option.icon} ${option.text}` : option.text}\n {option.tag && <span className={styles.tag}>{option.tag}</span>}\n </div>\n );\n}\n","import 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}\n\nexport function SuggestionGrid({\n options,\n activeIndex,\n onSelect,\n onHighlight,\n listboxId,\n}: SuggestionGridProps) {\n return (\n <div 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 />\n ))}\n </div>\n );\n}\n","import styles from \"./AIAutocompleteDropdown.module.css\";\nimport { SuggestionGrid } from \"./components/SuggestionGrid\";\nimport type { AIAutocompleteDropdownProps } from \"./types\";\n\nexport function AIAutocompleteDropdown({\n suggestions,\n activeIndex,\n onSelect,\n onHighlight,\n isOpen,\n id,\n className,\n}: AIAutocompleteDropdownProps) {\n const activeSuggestion = suggestions[0];\n const hasOptions = isOpen && activeSuggestion && activeSuggestion.options.length > 0;\n\n return (\n <div\n id={id}\n role=\"listbox\"\n className={`${styles.dropdown} ${hasOptions ? styles.visible : \"\"} ${className ?? \"\"}`}\n onMouseDown={(e) => e.preventDefault()}\n >\n {activeSuggestion && activeSuggestion.options.length > 0 && (\n <SuggestionGrid\n options={activeSuggestion.options}\n activeIndex={activeIndex}\n onSelect={onSelect}\n onHighlight={onHighlight}\n listboxId={id}\n />\n )}\n </div>\n );\n}\n",".list {\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.pill {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n height: 36px;\n padding: 7px 9px;\n border: none;\n border-radius: 6px;\n background: var(--ac-color-background-supportive, #313255);\n color: var(--ac-color-text-muted, #c1c4cb);\n font-family: \"IBM Plex Sans\", sans-serif;\n font-size: 21px;\n line-height: 30px;\n cursor: pointer;\n white-space: nowrap;\n animation: fadeIn 400ms cubic-bezier(0.4, 0, 0.2, 1) forwards;\n}\n\n.pill:hover {\n filter: brightness(1.2);\n}\n\n.active {\n outline: 1px solid #5a5b8a;\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n}\n","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}\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({ pills, activePillIndex, onSelectPill }: PillListProps) {\n return (\n <span className={styles.list}>\n {pills.map((pill, i) => (\n <button\n key={`${pill.type}-${pill.text}`}\n type=\"button\"\n className={`${styles.pill} ${i === activePillIndex ? styles.active : \"\"}`}\n style={{ opacity: getPillOpacity(i) }}\n onClick={() => onSelectPill(i)}\n >\n {pill.text}\n </button>\n ))}\n </span>\n );\n}\n","import { type ChangeEvent, useCallback, useId, useMemo, useRef, useState } from \"react\";\nimport type {\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n UseAIAutocompleteOptions,\n UseAIAutocompleteReturn,\n} from \"../types\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { useAutocompleteFetch, useDebouncedFetch } from \"./useAutocompleteFetch\";\nimport { useAutocompleteKeyboard } from \"./useAutocompleteKeyboard\";\nimport { useAutocompletePills } from \"./useAutocompletePills\";\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n value: controlledValue,\n completedParams: controlledParams,\n onChange: onChangeProp,\n onParamsChange,\n}: UseAIAutocompleteOptions): UseAIAutocompleteReturn {\n // === Controlled / uncontrolled state ===\n const isTextControlled = controlledValue !== undefined;\n const isParamsControlled = controlledParams !== undefined;\n\n const [internalText, setInternalText] = useState(\"\");\n const [internalCompletedParams, setInternalCompletedParams] = useState<CompletedParamState[]>([]);\n const [suggestions, setSuggestions] = useState<Suggestion[]>([]);\n const [activeDropdownIndex, setActiveDropdownIndex] = useState(-1);\n\n const text = isTextControlled ? controlledValue : internalText;\n const completedParams = isParamsControlled ? controlledParams : internalCompletedParams;\n\n // === Refs — must be before setText/setCompletedParams which read them ===\n const onSubmitRef = useRef(onSubmit);\n onSubmitRef.current = onSubmit;\n const onChangeRef = useRef(onChangeProp);\n onChangeRef.current = onChangeProp;\n const onParamsChangeRef = useRef(onParamsChange);\n onParamsChangeRef.current = onParamsChange;\n const controlledValueRef = useRef(controlledValue);\n controlledValueRef.current = controlledValue;\n const controlledParamsRef = useRef(controlledParams);\n controlledParamsRef.current = controlledParams;\n\n // Stable setText that reads controlled value + callback via refs (no stale closures)\n const setText = useCallback(\n (value: string | ((prev: string) => string)) => {\n if (typeof value === \"function\") {\n if (isTextControlled) {\n const newVal = value(controlledValueRef.current ?? \"\");\n onChangeRef.current?.(newVal);\n } else {\n setInternalText((prev) => {\n const newVal = value(prev);\n onChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isTextControlled) setInternalText(value);\n onChangeRef.current?.(value);\n }\n },\n [isTextControlled],\n );\n\n // Stable setCompletedParams — same ref pattern\n const setCompletedParams = useCallback(\n (value: CompletedParamState[] | ((prev: CompletedParamState[]) => CompletedParamState[])) => {\n if (typeof value === \"function\") {\n if (isParamsControlled) {\n const newVal = value(controlledParamsRef.current ?? []);\n onParamsChangeRef.current?.(newVal);\n } else {\n setInternalCompletedParams((prev) => {\n const newVal = value(prev);\n onParamsChangeRef.current?.(newVal);\n return newVal;\n });\n }\n } else {\n if (!isParamsControlled) setInternalCompletedParams(value);\n onParamsChangeRef.current?.(value);\n }\n },\n [isParamsControlled],\n );\n const onErrorRef = useRef(onError);\n onErrorRef.current = onError;\n const optionOverridesRef = useRef(optionOverrides);\n optionOverridesRef.current = optionOverrides;\n const maskCompletedTextRef = useRef(maskCompletedText);\n maskCompletedTextRef.current = maskCompletedText;\n const apiConfigRef = useRef(apiConfig);\n apiConfigRef.current = apiConfig;\n const textRef = useRef(text);\n textRef.current = text;\n const suggestionsRef = useRef(suggestions);\n suggestionsRef.current = suggestions;\n const filterBaseRef = useRef(0);\n const pillTappedRef = useRef(false);\n const skipNextFetchRef = useRef(false);\n const listboxId = useId();\n\n // === Fetch ===\n const { doFetch, isLoading, error, isReady, lastRawQueryRef } = useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n });\n\n useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n });\n\n // === Derived ===\n const segments = useMemo(() => deriveSegments(text, completedParams), [text, completedParams]);\n\n filterBaseRef.current = Math.min(filterBaseRef.current, text.length);\n const filterQuery = text.slice(filterBaseRef.current);\n\n const placeholderText = useMemo(() => {\n const serverPlaceholder = suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n return serverPlaceholder || customPlaceholder || \"\";\n }, [suggestions, customPlaceholder]);\n const actionableSuggestions = useMemo(\n () => suggestions.filter((s) => s.type !== \"placeholder\"),\n [suggestions],\n );\n const activeSuggestion: Suggestion | undefined = actionableSuggestions[0];\n const overrideFn = activeSuggestion ? optionOverrides?.[activeSuggestion.type] : undefined;\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = useMemo(\n () => filterOptions(baseOptions, filterQuery),\n [baseOptions, filterQuery],\n );\n const hasPlaceholder = placeholderText.length > 0;\n const isDropdownOpen =\n !isLoading &&\n filteredOptions.length > 0 &&\n (!!text || pillTappedRef.current || !hasPlaceholder);\n\n // === Option selection ===\n const selectOption = useCallback(\n (option: SuggestionOption) => {\n if (!activeSuggestion) return;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: option.text,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: option.metadata,\n };\n\n const base = filterBaseRef.current;\n let prefix = textRef.current.slice(0, base);\n if (prefix.length > 0 && !prefix.endsWith(\" \")) {\n const lastWord = prefix.split(/\\s+/).pop() ?? \"\";\n if (lastWord && option.text.toLowerCase().startsWith(lastWord.toLowerCase())) {\n prefix = prefix.slice(0, prefix.length - lastWord.length);\n }\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = prefix + (needsSpace ? \" \" : \"\") + option.text + \" \";\n setText(newText);\n filterBaseRef.current = newText.length;\n setCompletedParams((prev) => [...prev, completed]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (remainingActionable > 0) {\n skipNextFetchRef.current = true;\n }\n },\n [activeSuggestion, actionableSuggestions, setText, setCompletedParams],\n );\n\n // === Text change handler ===\n const handleChange = useCallback(\n (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 setText(newValue);\n pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n\n const { valid, invalid } = reconcileParams(newValue, completedParams);\n if (invalid.length > 0) {\n setCompletedParams(() => valid);\n for (const param of invalid) {\n setSuggestions((prev) => [\n {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n },\n ...prev,\n ]);\n }\n }\n\n if (activeSuggestion && invalid.length === 0) {\n const newFilterQuery = newValue.slice(filterBaseRef.current);\n const match = findExactMatch(activeSuggestion.options, newFilterQuery);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: match.text,\n kind: match.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options,\n metadata: match.metadata,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n }\n }\n },\n [completedParams, activeSuggestion, setText, setCompletedParams],\n );\n\n // === Keyboard ===\n const { handleKeyDown } = useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n });\n\n // === Pills ===\n const pills = useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n });\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n pills.reEditParam(param).apply(setText);\n },\n [pills, setText],\n );\n\n // === Reset ===\n const reset = useCallback(() => {\n setText(\"\");\n setCompletedParams(() => []);\n setSuggestions([]);\n setActiveDropdownIndex(-1);\n filterBaseRef.current = 0;\n lastRawQueryRef.current = \"\";\n doFetch(\"\", []);\n }, [doFetch, setText, setCompletedParams, lastRawQueryRef]);\n\n const activeDescendantId =\n activeDropdownIndex >= 0 ? `${listboxId}-option-${activeDropdownIndex}` : undefined;\n\n return {\n completedParams,\n suggestionPills: actionableSuggestions,\n setActivePill: pills.setActivePill,\n removeLastParam: pills.removeLastParam,\n reEditParam,\n segments,\n suggestions,\n activeIndex: activeDropdownIndex,\n isReady,\n isLoading,\n error,\n inputProps: {\n value: text,\n placeholder: placeholderText || undefined,\n onChange: handleChange,\n onKeyDown: handleKeyDown,\n role: \"combobox\" as const,\n \"aria-expanded\": isDropdownOpen,\n \"aria-activedescendant\": activeDescendantId,\n \"aria-autocomplete\": \"list\" as const,\n \"aria-controls\": listboxId,\n },\n reset,\n dropdownProps: {\n suggestions: activeSuggestion ? [{ ...activeSuggestion, options: filteredOptions }] : [],\n activeIndex: activeDropdownIndex,\n onSelect: selectOption,\n onHighlight: setActiveDropdownIndex,\n isOpen: isDropdownOpen,\n id: listboxId,\n },\n };\n}\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(options: SuggestionOption[], query: string): SuggestionOption[] {\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[],\n query: string,\n): SuggestionOption | null {\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import { type MutableRefObject, useCallback, useEffect, useRef, useState } from \"react\";\nimport type {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { fetchSuggestions } from \"../utils/api\";\nimport { buildQuery } from \"../utils/buildQuery\";\nimport { filterOptions, findExactMatch } from \"../utils/filtering\";\nimport { applyOptionOverrides } from \"../utils/overrides\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\ninterface UseAutocompleteFetchOptions {\n textRef: MutableRefObject<string>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n filterBaseRef: MutableRefObject<number>;\n maskCompletedTextRef: MutableRefObject<boolean | undefined>;\n apiConfigRef: MutableRefObject<APIConfig | undefined>;\n optionOverridesRef: MutableRefObject<OptionOverrides | undefined>;\n onErrorRef: MutableRefObject<((error: Error) => void) | undefined>;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n}\n\ninterface UseAutocompleteFetchReturn {\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n isLoading: boolean;\n error: Error | null;\n isReady: boolean;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useAutocompleteFetch({\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n}: UseAutocompleteFetchOptions): UseAutocompleteFetchReturn {\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const [isReady, setIsReady] = useState(false);\n const fetchVersionRef = useRef(0);\n const abortRef = useRef<AbortController | null>(null);\n const lastRawQueryRef = useRef(\"\");\n\n const doFetch = useCallback(\n async (rawQuery: string, completed: CompletedParamState[]) => {\n abortRef.current?.abort();\n const controller = new AbortController();\n abortRef.current = controller;\n const version = ++fetchVersionRef.current;\n const textAtRequest = textRef.current.length;\n\n const hasSuggestions = suggestionsRef.current.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) setIsLoading(true);\n setError(null);\n try {\n const rawCount = completed.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n\n const res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\n contactAccountCount: typeof rawCount === \"number\" ? rawCount : undefined,\n apiConfig: apiConfigRef.current,\n });\n\n if (version !== fetchVersionRef.current) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n optionOverridesRef.current,\n );\n setIsReady(res.data.is_ready ?? false);\n lastRawQueryRef.current = rawQuery;\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = textRef.current;\n if (lastInput?.state === \"in_progress\") {\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n if (inProgressIdx !== -1) {\n filterBaseRef.current = inProgressIdx;\n } else {\n filterBaseRef.current = textAtRequest;\n }\n } else {\n filterBaseRef.current = textAtRequest;\n }\n\n // Check if the user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n if (active) {\n const query = currentText.slice(filterBaseRef.current);\n const match = findExactMatch(active.options, query);\n if (match) {\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options,\n metadata: match.metadata,\n },\n ]);\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n setSuggestions(newSuggestions);\n setIsLoading(false);\n setActiveDropdownIndex(-1);\n } catch (err) {\n if (version === fetchVersionRef.current) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n setError(caughtError);\n setIsLoading(false);\n onErrorRef.current?.(caughtError);\n }\n }\n },\n [\n textRef,\n suggestionsRef,\n filterBaseRef,\n maskCompletedTextRef,\n apiConfigRef,\n optionOverridesRef,\n onErrorRef,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n ],\n );\n\n // Mount fetch\n useEffect(() => {\n doFetch(\"\", []);\n return () => {\n abortRef.current?.abort();\n };\n }, [doFetch]);\n\n return { doFetch, isLoading, error, isReady, lastRawQueryRef };\n}\n\ninterface UseDebouncedFetchOptions {\n text: string;\n completedParams: CompletedParamState[];\n doFetch: (rawQuery: string, completed: CompletedParamState[]) => Promise<void>;\n filterBaseRef: MutableRefObject<number>;\n skipNextFetchRef: MutableRefObject<boolean>;\n suggestionsRef: MutableRefObject<Suggestion[]>;\n lastRawQueryRef: MutableRefObject<string>;\n}\n\nexport function useDebouncedFetch({\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n}: UseDebouncedFetchOptions): void {\n const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const slowDebounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const hasFetchedRef = useRef(true);\n\n useEffect(() => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n\n const attemptFetch = (minDiff: number): boolean => {\n if (skipNextFetchRef.current) {\n skipNextFetchRef.current = false;\n return false;\n }\n\n if (!text && completedParams.length === 0) {\n if (!hasFetchedRef.current) {\n hasFetchedRef.current = true;\n return false;\n }\n doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = text.slice(filterBaseRef.current);\n const currentSuggestions = suggestionsRef.current;\n const actionable = currentSuggestions.filter((s: Suggestion) => s.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(text, completedParams);\n const isDeleting = rawQuery.length < lastRawQueryRef.current.length;\n const charDiff = Math.abs(rawQuery.length - lastRawQueryRef.current.length);\n if (isDeleting || charDiff >= minDiff) {\n doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n debounceRef.current = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n }\n }, DEBOUNCE_MS);\n\n slowDebounceRef.current = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n\n return () => {\n if (debounceRef.current) clearTimeout(debounceRef.current);\n if (slowDebounceRef.current) clearTimeout(slowDebounceRef.current);\n };\n }, [\n text,\n completedParams,\n doFetch,\n filterBaseRef,\n skipNextFetchRef,\n suggestionsRef,\n lastRawQueryRef,\n ]);\n}\n","import type {\n APIConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\n\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = typeof __SDK_VERSION__ !== \"undefined\" ? __SDK_VERSION__ : \"0.0.0\";\n\n// process.env.* values are replaced at build time by the bundler's `define` config.\n// Use optional chaining (process?.env), NOT `typeof process !== \"undefined\"` guards —\n// the typeof guard prevents the replacement from taking effect in browsers.\ndeclare const process: { env: Record<string, string | undefined> } | undefined;\nconst API_ENDPOINT = process?.env.MAGICX_API_ENDPOINT || \"/api/suggest\";\n\nlet hasWarnedMissingKey = false;\n\nfunction getApiKey(config?: APIConfig): string {\n const key = config?.apiKey || process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY || \"\";\n if (!key && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). \" +\n \"Requests will be sent without an Authorization header.\",\n );\n }\n return key;\n}\n\nfunction getAuthScheme(config?: APIConfig): \"Bearer\" | \"Basic\" {\n if (config?.authScheme) return config.authScheme;\n const scheme = process?.env.MAGICX_AUTH_SCHEME;\n return scheme === \"Basic\" ? \"Basic\" : \"Bearer\";\n}\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options?: {\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n contactAccountCount?: number;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options?.apiConfig;\n const apiKey = getApiKey(apiConfig);\n const authScheme = getAuthScheme(apiConfig);\n const includeText = !options?.maskCompletedText;\n const contactAccountCount = options?.contactAccountCount;\n\n const body: AutocompleteRequest = {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n },\n };\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"X-App-Identifier\": process?.env.MAGICX_APP_IDENTIFIER || \"active-campaign-demo\",\n ...apiConfig?.headers,\n };\n if (apiKey) {\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(API_ENDPOINT, {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n signal: options?.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { CompletedParamState } from \"../types\";\n\ninterface BuildQueryResult {\n rawQuery: string;\n completedParams: CompletedParamState[];\n}\n\n/**\n * Takes the raw input text and completed params (without placeholders),\n * replaces each completed param's text in the string with a {{TYPE_N}} token,\n * and returns the transformed query + params with placeholders filled in.\n *\n * Replacements happen left-to-right, first occurrence only per param.\n * Counter is per-type (e.g. {{TASK_1}}, {{GOAL_1}}, {{GOAL_2}}).\n */\nexport function buildQuery(text: string, completedParams: CompletedParamState[]): BuildQueryResult {\n let result = text;\n const typeCounts: Record<string, number> = {};\n const updatedParams: CompletedParamState[] = [];\n\n for (const param of completedParams) {\n const count = (typeCounts[param.type] ?? 0) + 1;\n typeCounts[param.type] = count;\n\n const typeKey = param.type.toUpperCase().replace(/\\s+/g, \"_\");\n const placeholder = `{{${typeKey}_${count}}}`;\n\n // Replace first occurrence of the param text in the string\n const index = result.indexOf(param.text);\n if (index !== -1) {\n result = result.slice(0, index) + placeholder + result.slice(index + param.text.length);\n }\n\n updatedParams.push({ ...param, placeholder });\n }\n\n return { rawQuery: result, completedParams: updatedParams };\n}\n","import type { Suggestion, SuggestionOption } from \"../types\";\n\n/**\n * Applies option overrides by calling the override function with an empty query,\n * then prepending results to suggestions that match by type, deduplicating by text.\n */\nexport function applyOptionOverrides(\n suggestions: Suggestion[],\n overrides?: Record<string, (query: string) => SuggestionOption[]>,\n): Suggestion[] {\n if (!overrides) return suggestions;\n return suggestions.map((s) => {\n const fn = overrides[s.type];\n if (!fn) return s;\n const extra = fn(\"\");\n if (extra.length === 0) return s;\n const existingTexts = new Set(extra.map((o) => o.text));\n const deduped = (s.options ?? []).filter((o) => !existingTexts.has(o.text));\n return { ...s, options: [...extra, ...deduped] };\n });\n}\n","import { type KeyboardEvent, type MutableRefObject, useCallback } from \"react\";\nimport type {\n AutocompleteResult,\n CompletedParamState,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nimport { buildQuery } from \"../utils/buildQuery\";\n\ninterface UseAutocompleteKeyboardOptions {\n activeDropdownIndex: number;\n setActiveDropdownIndex: (index: number) => void;\n filteredOptions: SuggestionOption[];\n selectOption: (option: SuggestionOption) => void;\n onSubmitRef: MutableRefObject<((result: AutocompleteResult) => void) | undefined>;\n text: string;\n completedParams: CompletedParamState[];\n isDropdownOpen: boolean;\n hasPlaceholder: boolean;\n placeholderText: string;\n suggestions: Suggestion[];\n filterBaseRef: MutableRefObject<number>;\n columns: number;\n setText: (value: string) => void;\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: (prev: Suggestion[]) => Suggestion[]) => void;\n}\n\nexport function useAutocompleteKeyboard({\n activeDropdownIndex,\n setActiveDropdownIndex,\n filteredOptions,\n selectOption,\n onSubmitRef,\n text,\n completedParams,\n isDropdownOpen,\n hasPlaceholder,\n placeholderText,\n suggestions,\n filterBaseRef,\n columns,\n setText,\n setCompletedParams,\n setSuggestions,\n}: UseAutocompleteKeyboardOptions) {\n const getTappableIndices = useCallback(() => {\n const tappable = filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n const left = tappable.filter((i) => i % columns === 0);\n const right = tappable.filter((i) => i % columns === 1);\n return [...left, ...right];\n }, [filteredOptions, columns]);\n\n const handleKeyDown = useCallback(\n (e: KeyboardEvent<HTMLTextAreaElement>) => {\n const tappableIndices = getTappableIndices();\n\n switch (e.key) {\n case \"ArrowDown\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n setActiveDropdownIndex(tappableIndices[nextPos]);\n break;\n }\n case \"ArrowUp\": {\n e.preventDefault();\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n setActiveDropdownIndex(tappableIndices[prevPos]);\n break;\n }\n case \"ArrowRight\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns === 0) {\n const rightNeighbor = activeDropdownIndex + 1;\n if (\n rightNeighbor < filteredOptions.length &&\n filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n setActiveDropdownIndex(rightNeighbor);\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (activeDropdownIndex < 0) break;\n if (activeDropdownIndex % columns === 1) {\n const leftNeighbor = activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n setActiveDropdownIndex(leftNeighbor);\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (onSubmitRef.current) {\n const { rawQuery, completedParams: finalParams } = buildQuery(text, completedParams);\n const result: AutocompleteResult = {\n query: text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n };\n onSubmitRef.current(result);\n }\n break;\n }\n case \"Tab\": {\n if (activeDropdownIndex >= 0 && filteredOptions[activeDropdownIndex]?.is_tappable) {\n e.preventDefault();\n selectOption(filteredOptions[activeDropdownIndex]);\n } else if (isDropdownOpen) {\n const firstTappable = filteredOptions.find((o) => o.is_tappable);\n if (firstTappable) {\n e.preventDefault();\n selectOption(firstTappable);\n }\n } else if (!text && hasPlaceholder) {\n e.preventDefault();\n const placeholderSuggestion = suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n setCompletedParams((prev) => [\n ...prev,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options,\n },\n ]);\n setSuggestions((prev) => prev.filter((s) => s !== placeholderSuggestion));\n } else {\n setText(placeholderText);\n filterBaseRef.current = placeholderText.length;\n }\n }\n break;\n }\n case \"Escape\":\n setActiveDropdownIndex(-1);\n break;\n }\n },\n [\n activeDropdownIndex,\n columns,\n completedParams,\n filteredOptions,\n filterBaseRef,\n getTappableIndices,\n hasPlaceholder,\n isDropdownOpen,\n onSubmitRef,\n placeholderText,\n selectOption,\n setActiveDropdownIndex,\n setCompletedParams,\n setSuggestions,\n setText,\n suggestions,\n text,\n ],\n );\n\n return { handleKeyDown, getTappableIndices };\n}\n","import { type MutableRefObject, useCallback } from \"react\";\nimport type { CompletedParamState, Suggestion } from \"../types\";\n\ninterface UseAutocompletePillsOptions {\n completedParams: CompletedParamState[];\n suggestions: Suggestion[];\n setCompletedParams: (fn: (prev: CompletedParamState[]) => CompletedParamState[]) => void;\n setSuggestions: (fn: Suggestion[] | ((prev: Suggestion[]) => Suggestion[])) => void;\n setActiveDropdownIndex: (index: number) => void;\n filterBaseRef: MutableRefObject<number>;\n pillTappedRef: MutableRefObject<boolean>;\n}\n\nexport function useAutocompletePills({\n completedParams,\n suggestions,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n}: UseAutocompletePillsOptions) {\n const setActivePill = useCallback(\n (index: number) => {\n const actionable = suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = suggestions.filter((s) => s.type === \"placeholder\");\n setSuggestions([...placeholders, moved, ...rest]);\n pillTappedRef.current = true;\n setActiveDropdownIndex(-1);\n },\n [suggestions, setSuggestions, setActiveDropdownIndex, pillTappedRef],\n );\n\n const removeLastParam = useCallback(() => {\n if (completedParams.length === 0) return;\n const lastParam = completedParams[completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n setCompletedParams((prev) => prev.slice(0, -1));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n }, [completedParams, setCompletedParams, setSuggestions, setActiveDropdownIndex]);\n\n const reEditParam = useCallback(\n (param: CompletedParamState) => {\n const restoredSuggestion: Suggestion = {\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n };\n return {\n apply: (setText: (fn: (prev: string) => string) => void) => {\n setText((prev) => {\n let pos = 0;\n for (const p of completedParams) {\n const idx = prev.indexOf(p.text, pos);\n if (idx === -1) continue;\n if (p.id === param.id) {\n const before = prev.slice(0, idx);\n const after = prev.slice(idx + param.text.length);\n const cleaned = (before + after).replace(/ {2,}/g, \" \");\n filterBaseRef.current = Math.min(filterBaseRef.current, cleaned.length);\n return cleaned;\n }\n pos = idx + p.text.length;\n }\n return prev;\n });\n setCompletedParams((prev) => prev.filter((p) => p.id !== param.id));\n setSuggestions((prev: Suggestion[]) => [restoredSuggestion, ...prev]);\n setActiveDropdownIndex(-1);\n pillTappedRef.current = true;\n },\n };\n },\n [\n completedParams,\n setCompletedParams,\n setSuggestions,\n setActiveDropdownIndex,\n filterBaseRef,\n pillTappedRef,\n ],\n );\n\n return { setActivePill, removeLastParam, reEditParam };\n}\n"],"mappings":"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","names":["index_exports","__export","AIAutocomplete","AIAutocompleteDropdown","useAIAutocomplete","__toCommonJS","import_react","AIAutocomplete_default","AIAutocompleteDropdown_default","SuggestionGrid_default","SuggestionItem_default","import_jsx_runtime","SuggestionItem","option","isHighlighted","onSelect","onHighlight","id","className","SuggestionItem_default","e","import_jsx_runtime","SuggestionGrid","options","activeIndex","onSelect","onHighlight","listboxId","SuggestionGrid_default","option","SuggestionItem","import_jsx_runtime","AIAutocompleteDropdown","suggestions","activeIndex","onSelect","onHighlight","isOpen","id","className","activeSuggestion","hasOptions","AIAutocompleteDropdown_default","e","SuggestionGrid","PillList_default","import_jsx_runtime","getPillOpacity","index","PillList","pills","activePillIndex","onSelectPill","PillList_default","pill","i","import_react","filterOptions","options","query","trimmed","lower","o","findExactMatch","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","import_react","SDK_VERSION","API_ENDPOINT","hasWarnedMissingKey","getApiKey","config","key","getAuthScheme","generateRequestId","toWireParam","param","includeText","fetchSuggestions","rawQuery","completedParams","options","apiConfig","apiKey","authScheme","contactAccountCount","body","p","headers","response","buildQuery","text","completedParams","result","typeCounts","updatedParams","param","count","placeholder","index","applyOptionOverrides","suggestions","overrides","s","fn","extra","existingTexts","o","deduped","DEBOUNCE_MS","SLOW_DEBOUNCE_MS","MIN_CHARS_DIFF","useAutocompleteFetch","textRef","suggestionsRef","filterBaseRef","maskCompletedTextRef","apiConfigRef","optionOverridesRef","onErrorRef","setCompletedParams","setSuggestions","setActiveDropdownIndex","isLoading","setIsLoading","error","setError","isReady","setIsReady","fetchVersionRef","abortRef","lastRawQueryRef","doFetch","rawQuery","completed","controller","version","textAtRequest","s","rawCount","p","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","inProgressIdx","active","query","match","findExactMatch","prev","err","caughtError","useDebouncedFetch","text","completedParams","skipNextFetchRef","debounceRef","slowDebounceRef","hasFetchedRef","attemptFetch","minDiff","currentQuery","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","updatedParams","buildQuery","isDeleting","charDiff","import_react","useAutocompleteKeyboard","activeDropdownIndex","setActiveDropdownIndex","filteredOptions","selectOption","onSubmitRef","text","completedParams","isDropdownOpen","hasPlaceholder","placeholderText","suggestions","filterBaseRef","columns","setText","setCompletedParams","setSuggestions","getTappableIndices","tappable","o","i","left","right","e","tappableIndices","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","result","firstTappable","placeholderSuggestion","s","prev","import_react","useAutocompletePills","completedParams","suggestions","setCompletedParams","setSuggestions","setActiveDropdownIndex","filterBaseRef","pillTappedRef","setActivePill","index","actionable","s","moved","rest","_","i","placeholders","removeLastParam","lastParam","restoredSuggestion","prev","reEditParam","param","setText","pos","p","idx","before","after","cleaned","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","controlledValue","controlledParams","onChangeProp","onParamsChange","isTextControlled","isParamsControlled","internalText","setInternalText","internalCompletedParams","setInternalCompletedParams","suggestions","setSuggestions","activeDropdownIndex","setActiveDropdownIndex","text","completedParams","onSubmitRef","onChangeRef","onParamsChangeRef","controlledValueRef","controlledParamsRef","setText","value","newVal","prev","setCompletedParams","onErrorRef","optionOverridesRef","maskCompletedTextRef","apiConfigRef","textRef","suggestionsRef","filterBaseRef","pillTappedRef","skipNextFetchRef","listboxId","doFetch","isLoading","error","isReady","lastRawQueryRef","useAutocompleteFetch","useDebouncedFetch","segments","deriveSegments","filterQuery","placeholderText","s","actionableSuggestions","activeSuggestion","overrideFn","baseOptions","filteredOptions","filterOptions","hasPlaceholder","isDropdownOpen","selectOption","option","completed","base","prefix","lastWord","needsSpace","newText","handleChange","e","raw","newValue","valid","invalid","reconcileParams","param","newFilterQuery","match","findExactMatch","handleKeyDown","useAutocompleteKeyboard","pills","useAutocompletePills","reEditParam","reset","activeDescendantId","import_jsx_runtime","AIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","placeholder","className","apiConfig","columns","value","controlledParams","onChangeProp","onParamsChange","ref","textareaRef","showCheckmark","setShowCheckmark","handleSubmitRef","checkmarkTimerRef","completedParams","suggestionPills","setActivePill","segments","inputProps","dropdownProps","reset","useAIAutocomplete","result","handleContainerClick","canSubmit","handleSubmit","rawQuery","finalParams","buildQuery","onChange","inputPlaceholder","restProps","isEmpty","AIAutocomplete_default","AIAutocompleteDropdown","seg","i","PillList","e"]}
package/dist/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{useCallback as at,useEffect as it,useRef as _e,useState as lt}from"react";var w={};var xe={};var ye={};var X={};import{jsx as Fe,jsxs as Ke}from"react/jsx-runtime";function be({option:e,isHighlighted:c,onSelect:a,onHighlight:l,id:o}){let i=[X.item,c?X.highlighted:"",e.is_tappable?X.tappable:X.nonTappable].filter(Boolean).join(" ");return Ke("div",{id:o,role:"option","aria-selected":c,className:i,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&a(e),onKeyDown:n=>{e.is_tappable&&(n.key==="Enter"||n.key===" ")&&(n.preventDefault(),a(e))},onMouseEnter:l,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&Fe("span",{className:X.tag,children:e.tag})]})}import{jsx as ve}from"react/jsx-runtime";function Se({options:e,activeIndex:c,onSelect:a,onHighlight:l,listboxId:o}){return ve("div",{className:ye.grid,children:e.map((i,n)=>ve(be,{option:i,isHighlighted:n===c,onSelect:a,onHighlight:()=>l(n),id:`${o}-option-${n}`},i.text))})}import{jsx as Pe}from"react/jsx-runtime";function ue({suggestions:e,activeIndex:c,onSelect:a,isOpen:l,id:o,className:i}){if(!l||e.length===0)return null;let n=e[0];return n.options.length===0?null:Pe("div",{id:o,role:"listbox",className:`${xe.dropdown} ${i??""}`,onMouseDown:x=>x.preventDefault(),children:Pe(Se,{options:n.options,activeIndex:c,onSelect:a,onHighlight:()=>{},listboxId:o})})}var ae={};import{jsx as ke}from"react/jsx-runtime";function He(e){return e===0?.4:e===1?.3:.15}function we({pills:e,activePillIndex:c,onSelectPill:a}){return ke("span",{className:ae.list,children:e.map((l,o)=>ke("button",{type:"button",className:`${ae.pill} ${o===c?ae.active:""}`,style:{opacity:He(o)},onClick:()=>a(o),children:l.text},`${l.type}-${l.text}`))})}import{useCallback as T,useEffect as Ce,useId as Je,useMemo as Ze,useRef as P,useState as $}from"react";var Xe="0.1.0",We=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",Ae=!1;function Ge(){let e=process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!e&&!Ae&&(Ae=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),e}function Ye(){return process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function Ve(){return crypto.randomUUID()}function je(e,c){return{placeholder:e.placeholder,type:e.type,...c&&{text:e.text},kind:e.kind}}async function Ie(e,c,a){let l=Ge(),o=Ye(),i=!a?.maskCompletedText,n=c.find(h=>h.type==="contact"&&h.metadata?.contact_account_count)?.metadata?.contact_account_count,x=typeof n=="number"?n:void 0,y={data:{raw_query:e,completed_params:c.map(h=>je(h,i)),...x!=null&&{contact_account_count:x}},meta:{request_id:Ve(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:Xe}},g={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo"};l&&(g.Authorization=o==="Basic"?`Basic ${btoa(l)}`:`Bearer ${l}`);let d=await fetch(We,{method:"POST",headers:g,body:JSON.stringify(y),signal:a?.signal});if(!d.ok)throw new Error(`API error: ${d.status} ${d.statusText}`);return d.json()}function ie(e,c){let a=e,l={},o=[];for(let i of c){let n=(l[i.type]??0)+1;l[i.type]=n;let y=`{{${i.type.toUpperCase().replace(/\s+/g,"_")}_${n}}}`,g=a.indexOf(i.text);g!==-1&&(a=a.slice(0,g)+y+a.slice(g+i.text.length)),o.push({...i,placeholder:y})}return{rawQuery:a,completedParams:o}}var et=100,tt=300,ot=2;function Te(e,c){let a=c.trimStart();if(!a)return e;let l=a.toLowerCase();return e.filter(o=>!o.is_tappable||o.text.toLowerCase().includes(l))}function de(e,c){let a=c.trim();if(!a)return null;let l=a.toLowerCase();return e.find(o=>o.is_tappable&&o.text.toLowerCase()===l)??null}function nt(e,c){let a=[],l=0;for(let i of c){let n=e.indexOf(i.text,l);n!==-1&&(n>l&&a.push({type:"text",value:e.slice(l,n)}),a.push({type:"completed",value:i.text,param:i}),l=n+i.text.length)}let o=e.slice(l);return o&&a.push({type:"text",value:o}),a}function rt(e,c){let a=[],l=[],o=0;for(let i of c){let n=e.indexOf(i.text,o);n===-1?l.push(i):(a.push(i),o=n+i.text.length)}return{valid:a,invalid:l}}function st(e,c){return c?e.map(a=>{let l=c[a.type];if(!l)return a;let o=l("");if(o.length===0)return a;let i=new Set(o.map(x=>x.text)),n=(a.options??[]).filter(x=>!i.has(x.text));return{...a,options:[...o,...n]}}):e}function fe({onSubmit:e,optionOverrides:c,maskCompletedText:a,placeholder:l}){let[o,i]=$([]),[n,x]=$(""),[y,g]=$([]),[d,h]=$(-1),[V,U]=$(!1),[_,j]=$(null),[J,Z]=$(!1),E=P(0),q=P(null),z=P(""),F=P(e);F.current=e;let ee=P(c);ee.current=c;let te=P(a);te.current=a;let I=P(n);I.current=n;let D=P(y);D.current=y;let v=P(0),W=P(!1),le=P(!1),ce=Je(),N=T(async(r,u)=>{q.current?.abort();let t=new AbortController;q.current=t;let s=++E.current;D.current.some(p=>p.type!=="placeholder")||U(!0),j(null);try{let p=await Ie(r,u,{maskCompletedText:te.current,signal:t.signal});if(s!==E.current)return;let b=st(p.data.suggestions??[],ee.current);Z(p.data.is_ready??!1),z.current=r;let S=p.data.input??[],O=S[S.length-1],Q=I.current;if(O?.state==="in_progress"){let R=Q.lastIndexOf(O.text);R!==-1?v.current=R:v.current=Q.length}else v.current=Q.length;let C=b.filter(R=>R.type!=="placeholder")[0];if(C){let R=Q.slice(v.current),H=de(C.options,R);H&&(i(L=>[...L,{placeholder:"",type:C.type,text:H.text,kind:H.kind,suggestionType:C.type,suggestionPlaceholder:C.text,options:C.options,metadata:H.metadata}]),b=b.filter(L=>L!==C))}g(b),U(!1),h(-1)}catch(p){s===E.current&&(j(p instanceof Error?p:new Error(String(p))),U(!1))}},[]);Ce(()=>(N("",[]),()=>{q.current?.abort()}),[N]);let Oe=Ze(()=>nt(n,o),[n,o]);v.current=Math.min(v.current,n.length);let oe=n.slice(v.current);console.log(`[filter] base=${v.current} query="${oe}" text="${n}"`);let K=y.filter(r=>r.type==="placeholder").map(r=>r.text).join(" ")||l||"",ne=y.filter(r=>r.type!=="placeholder"),f=ne[0],me=f?c?.[f.type]:void 0,k=f?me&&oe.trim()?me(oe.trim()):Te(f.options??[],oe):[],pe=K.length>0,re=!V&&k.length>0&&(!!n||W.current||!pe),G=T(r=>{if(!f)return;let u={placeholder:"",type:f.type,text:r.text,kind:r.kind,suggestionType:f.type,suggestionPlaceholder:f.text,options:f.options,metadata:r.metadata},t=v.current,s=n.slice(0,t);if(s.length>0&&!s.endsWith(" ")){let S=s.split(/\s+/).pop()??"";S&&r.text.toLowerCase().startsWith(S.toLowerCase())&&(s=s.slice(0,s.length-S.length))}let m=s.length>0&&s[s.length-1]!==" ",p=s+(m?" ":"")+r.text+" ";x(p),v.current=p.length,i(S=>[...S,u]),g(S=>S.filter(O=>O!==f)),W.current=!1,h(-1),ne.length-1>0&&(le.current=!0)},[f,ne,n]),Re=T(r=>{let u=r.target.value,t=u.length>0?u[0].toUpperCase()+u.slice(1):u;x(t),W.current=!1,h(-1);let{valid:s,invalid:m}=rt(t,o);if(m.length>0){i(s);for(let p of m)g(b=>[{type:p.suggestionType,text:p.suggestionPlaceholder,required:!0,options:p.options},...b])}if(f&&m.length===0){let p=t.slice(v.current),b=de(f.options,p);b&&(i(S=>[...S,{placeholder:"",type:f.type,text:b.text,kind:b.kind,suggestionType:f.type,suggestionPlaceholder:f.text,options:f.options,metadata:b.metadata}]),g(S=>S.filter(O=>O!==f)))}},[o,f]),Y=P(null),M=P(null),ge=P(!0);Ce(()=>{Y.current&&clearTimeout(Y.current),M.current&&clearTimeout(M.current);let r=u=>{if(le.current)return le.current=!1,!1;if(!n&&o.length===0)return ge.current?(N("",[]),!0):(ge.current=!0,!1);let t=n.slice(v.current),p=D.current.filter(L=>L.type!=="placeholder")[0],S=(p?Te(p.options,t):[]).filter(L=>L.is_tappable),O=p?de(p.options,t)!==null:!1,Q=t.trim().length>0;if(S.length>0&&!O&&Q)return!1;let{rawQuery:se,completedParams:C}=ie(n,o),R=se.length<z.current.length,H=Math.abs(se.length-z.current.length);return R||H>=u?(N(se,C),!0):!1};return Y.current=setTimeout(()=>{r(ot)&&M.current&&clearTimeout(M.current)},et),M.current=setTimeout(()=>r(1),tt),()=>{Y.current&&clearTimeout(Y.current),M.current&&clearTimeout(M.current)}},[n,o,N]);let he=T(()=>{let u=k.map((m,p)=>m.is_tappable?p:-1).filter(m=>m!==-1),t=u.filter(m=>m%2===0),s=u.filter(m=>m%2===1);return[...t,...s]},[k]),Ee=T(r=>{let u=he();switch(r.key){case"ArrowDown":{if(r.preventDefault(),u.length===0)return;let t=u.indexOf(d),s=t<u.length-1?t+1:0;h(u[s]);break}case"ArrowUp":{if(r.preventDefault(),u.length===0)return;let t=u.indexOf(d),s=t>0?t-1:u.length-1;h(u[s]);break}case"ArrowRight":{if(d<0)break;if(d%2===0){let s=d+1;s<k.length&&k[s]?.is_tappable&&(r.preventDefault(),h(s))}break}case"ArrowLeft":{if(d<0)break;if(d%2===1){let s=d-1;s>=0&&k[s]?.is_tappable&&(r.preventDefault(),h(s))}break}case"Enter":{r.preventDefault(),d>=0&&k[d]?.is_tappable?G(k[d]):F.current&&F.current();break}case"Tab":{if(d>=0&&k[d]?.is_tappable)r.preventDefault(),G(k[d]);else if(re){let t=k.find(s=>s.is_tappable);t&&(r.preventDefault(),G(t))}else if(!n&&pe){r.preventDefault();let t=y.find(s=>s.type==="placeholder");x(K),v.current=K.length,t&&(i(s=>[...s,{placeholder:"",type:t.type,text:K,kind:null,suggestionType:t.type,suggestionPlaceholder:t.text,options:t.options}]),g(s=>s.filter(m=>m!==t)))}break}case"Escape":h(-1);break}},[d,k,pe,re,K,G,y,he,n]),De=T(r=>{let u=y.filter(p=>p.type!=="placeholder");if(r<0||r>=u.length)return;let t=u[r],s=u.filter((p,b)=>b!==r),m=y.filter(p=>p.type==="placeholder");g([...m,t,...s]),W.current=!0,h(-1)},[y]),Ne=T(()=>{if(o.length===0)return;let r=o[o.length-1],u={type:r.suggestionType,text:r.suggestionPlaceholder,required:!0,options:r.options};i(t=>t.slice(0,-1)),g(t=>[u,...t]),h(-1)},[o]),Me=T(r=>{let u={type:r.suggestionType,text:r.suggestionPlaceholder,required:!0,options:r.options};x(t=>{let s=t.indexOf(r.text);if(s===-1)return t;let m=t.slice(0,s),p=t.slice(s+r.text.length),b=(m+p).replace(/ {2,}/g," ");return v.current=Math.min(v.current,b.length),b}),i(t=>t.filter(s=>s!==r)),g(t=>[u,...t]),h(-1),W.current=!0},[]),Le=T(()=>{x(""),i([]),g([]),h(-1),Z(!1),v.current=0,z.current="",N("",[])},[N]),$e=d>=0?`${ce}-option-${d}`:void 0;return{completedParams:o,suggestionPills:ne,activePillIndex:0,setActivePill:De,removeLastParam:Ne,reEditParam:Me,segments:Oe,suggestions:y,activeIndex:d,isReady:J,isLoading:V,error:_,inputProps:{value:n,placeholder:K||void 0,onChange:Re,onKeyDown:Ee,role:"combobox","aria-expanded":re,"aria-activedescendant":$e,"aria-autocomplete":"list","aria-controls":ce},reset:Le,dropdownProps:{suggestions:f?[{...f,options:k}]:[],activeIndex:d,onSelect:G,isOpen:re,id:ce}}}import{jsx as A,jsxs as B}from"react/jsx-runtime";function ct({onSubmit:e,optionOverrides:c,maskCompletedText:a,placeholder:l,className:o}){let i=_e(null),[n,x]=lt(!1),y=_e(()=>{});it(()=>{i.current?.focus()},[]);let{completedParams:g,suggestionPills:d,activePillIndex:h,setActivePill:V,segments:U,inputProps:_,dropdownProps:j,reset:J}=fe({onSubmit:()=>y.current(),optionOverrides:c,maskCompletedText:a,placeholder:l}),Z=()=>{i.current?.focus()},E=!!_.value||g.length>0,q=at(()=>{if(!E)return;let{rawQuery:I,completedParams:D}=ie(_.value,g);e({query:_.value.trim(),raw_query:I,completed_params:D}),J(),x(!0),setTimeout(()=>x(!1),3e3)},[E,_.value,g,e,J]);y.current=q;let{onChange:z,placeholder:F,...ee}=_,te=!_.value;return B("div",{className:`${w.container} ${o??""}`,children:[A("div",{className:`${w.checkmark} ${n?w.checkmarkVisible:""}`,children:B("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[A("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),A("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:w.checkmarkPath})]})}),A(ue,{...j}),B("div",{className:w.inputWrapper,onClick:Z,children:[B("div",{className:w.editorArea,children:[B("div",{className:w.sizerContent,"aria-hidden":"true",children:[te&&F?B("span",{className:w.placeholderText,children:[F," "]}):B("span",{className:w.sizerText,children:[U.map((I,D)=>A("span",{children:I.value},`${D}-${I.type}`)),U.length===0&&"\xA0"]})," ",A(we,{pills:d,activePillIndex:h,onSelectPill:V})]}),A("textarea",{ref:i,className:w.textarea,rows:1,onChange:z,...ee})]}),A("button",{type:"button",className:w.submitButton,disabled:!E,onClick:I=>{I.stopPropagation(),q()},"aria-label":"Submit",children:A("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:A("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})}export{ct as AIAutocomplete,ue as AIAutocompleteDropdown,fe as useAIAutocomplete};
1
+ import{forwardRef as xt,useCallback as Pt,useEffect as vt,useImperativeHandle as At,useRef as Pe,useState as Ct}from"react";var F={};var he={};var Ie={};var X={};import{jsx as at,jsxs as st}from"react/jsx-runtime";function Re({option:e,isHighlighted:r,onSelect:t,onHighlight:o,id:n}){let a=[X.item,r?X.highlighted:"",e.is_tappable?X.tappable:X.nonTappable].filter(Boolean).join(" ");return st("div",{id:n,role:"option","aria-selected":r,className:a,tabIndex:e.is_tappable?0:-1,onClick:()=>e.is_tappable&&t(e),onKeyDown:i=>{e.is_tappable&&(i.key==="Enter"||i.key===" ")&&(i.preventDefault(),t(e))},onMouseEnter:o,children:[e.icon?`${e.icon} ${e.text}`:e.text,e.tag&&at("span",{className:X.tag,children:e.tag})]})}import{jsx as _e}from"react/jsx-runtime";function Te({options:e,activeIndex:r,onSelect:t,onHighlight:o,listboxId:n}){return _e("div",{className:Ie.grid,children:e.map((a,i)=>_e(Re,{option:a,isHighlighted:i===r,onSelect:t,onHighlight:()=>o(i),id:`${n}-option-${i}`},a.text))})}import{jsx as Ee}from"react/jsx-runtime";function be({suggestions:e,activeIndex:r,onSelect:t,onHighlight:o,isOpen:n,id:a,className:i}){let l=e[0],m=n&&l&&l.options.length>0;return Ee("div",{id:a,role:"listbox",className:`${he.dropdown} ${m?he.visible:""} ${i??""}`,onMouseDown:f=>f.preventDefault(),children:l&&l.options.length>0&&Ee(Te,{options:l.options,activeIndex:r,onSelect:t,onHighlight:o,listboxId:a})})}var re={};import{jsx as Me}from"react/jsx-runtime";function ct(e){return e===0?.4:e===1?.3:.15}function Ue({pills:e,activePillIndex:r,onSelectPill:t}){return Me("span",{className:re.list,children:e.map((o,n)=>Me("button",{type:"button",className:`${re.pill} ${n===r?re.active:""}`,style:{opacity:ct(n)},onClick:()=>t(n),children:o.text},`${o.type}-${o.text}`))})}import{useCallback as Y,useId as St,useMemo as se,useRef as U,useState as ie}from"react";function ae(e,r){let t=r.trimStart();if(!t)return e;let o=t.toLowerCase();return e.filter(n=>!n.is_tappable||n.text.toLowerCase().includes(o))}function ee(e,r){let t=r.trim();if(!t)return null;let o=t.toLowerCase();return e.find(n=>n.is_tappable&&n.text.toLowerCase()===o)??null}function Le(e,r){let t=[],o=0;for(let a of r){let i=e.indexOf(a.text,o);i!==-1&&(i>o&&t.push({type:"text",value:e.slice(o,i)}),t.push({type:"completed",value:a.text,param:a}),o=i+a.text.length)}let n=e.slice(o);return n&&t.push({type:"text",value:n}),t}function Ne(e,r){let t=[],o=[],n=0;for(let a of r){let i=e.indexOf(a.text,n);i===-1?o.push(a):(t.push(a),n=i+a.text.length)}return{valid:t,invalid:o}}import{useCallback as gt,useEffect as Ke,useRef as G,useState as ye}from"react";var lt="0.1.5",ut=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",De=!1;function pt(e){let r=e?.apiKey||process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!r&&!De&&(De=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),r}function mt(e){return e?.authScheme?e.authScheme:process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function dt(){return crypto.randomUUID()}function ft(e,r){return{placeholder:e.placeholder,type:e.type,...r&&{text:e.text},kind:e.kind}}async function Fe(e,r,t){let o=t?.apiConfig,n=pt(o),a=mt(o),i=!t?.maskCompletedText,l=t?.contactAccountCount,m={data:{raw_query:e,completed_params:r.map(h=>ft(h,i)),...l!=null&&{contact_account_count:l}},meta:{request_id:dt(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:lt}},f={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo",...o?.headers};n&&(f.Authorization=a==="Basic"?`Basic ${btoa(n)}`:`Bearer ${n}`);let u=await fetch(ut,{method:"POST",headers:f,body:JSON.stringify(m),signal:t?.signal});if(!u.ok)throw new Error(`API error: ${u.status} ${u.statusText}`);return u.json()}function W(e,r){let t=e,o={},n=[];for(let a of r){let i=(o[a.type]??0)+1;o[a.type]=i;let m=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,f=t.indexOf(a.text);f!==-1&&(t=t.slice(0,f)+m+t.slice(f+a.text.length)),n.push({...a,placeholder:m})}return{rawQuery:t,completedParams:n}}function $e(e,r){return r?e.map(t=>{let o=r[t.type];if(!o)return t;let n=o("");if(n.length===0)return t;let a=new Set(n.map(l=>l.text)),i=(t.options??[]).filter(l=>!a.has(l.text));return{...t,options:[...n,...i]}}):e}var ht=100,bt=300,yt=2;function je({textRef:e,suggestionsRef:r,filterBaseRef:t,maskCompletedTextRef:o,apiConfigRef:n,optionOverridesRef:a,onErrorRef:i,setCompletedParams:l,setSuggestions:m,setActiveDropdownIndex:f}){let[u,h]=ye(!1),[g,y]=ye(null),[C,S]=ye(!1),P=G(0),v=G(null),p=G(""),d=gt(async(s,c)=>{v.current?.abort();let x=new AbortController;v.current=x;let T=++P.current,L=e.current.length;r.current.some(N=>N.type!=="placeholder")||h(!0),y(null);try{let N=c.find(I=>I.type==="contact"&&I.metadata?.contact_account_count)?.metadata?.contact_account_count,D=await Fe(s,c,{maskCompletedText:o.current,signal:x.signal,contactAccountCount:typeof N=="number"?N:void 0,apiConfig:n.current});if(T!==P.current)return;let O=$e(D.data.suggestions??[],a.current);S(D.data.is_ready??!1),p.current=s;let R=D.data.input??[],j=R[R.length-1],B=e.current;if(j?.state==="in_progress"){let I=B.toLowerCase().lastIndexOf(j.text.toLowerCase());I!==-1?t.current=I:t.current=L}else t.current=L;let w=O.filter(I=>I.type!=="placeholder")[0];if(w){let I=B.slice(t.current),z=ee(w.options,I);z&&(l(_=>[..._,{id:crypto.randomUUID(),placeholder:"",type:w.type,text:z.text,kind:z.kind,suggestionType:w.type,suggestionPlaceholder:w.text,options:w.options,metadata:z.metadata}]),O=O.filter(_=>_!==w))}m(O),h(!1),f(-1)}catch(N){if(T===P.current){let D=N instanceof Error?N:new Error(String(N));y(D),h(!1),i.current?.(D)}}},[e,r,t,o,n,a,i,l,m,f]);return Ke(()=>(d("",[]),()=>{v.current?.abort()}),[d]),{doFetch:d,isLoading:u,error:g,isReady:C,lastRawQueryRef:p}}function ze({text:e,completedParams:r,doFetch:t,filterBaseRef:o,skipNextFetchRef:n,suggestionsRef:a,lastRawQueryRef:i}){let l=G(null),m=G(null),f=G(!0);Ke(()=>{l.current&&clearTimeout(l.current),m.current&&clearTimeout(m.current);let u=h=>{if(n.current)return n.current=!1,!1;if(!e&&r.length===0)return f.current?(t("",[]),!0):(f.current=!0,!1);let g=e.slice(o.current),S=a.current.filter(L=>L.type!=="placeholder")[0],v=(S?ae(S.options,g):[]).filter(L=>L.is_tappable),p=S?ee(S.options,g)!==null:!1,d=g.trim().length>0;if(v.length>0&&!p&&d)return!1;let{rawQuery:s,completedParams:c}=W(e,r),x=s.length<i.current.length,T=Math.abs(s.length-i.current.length);return x||T>=h?(t(s,c),!0):!1};return l.current=setTimeout(()=>{u(yt)&&m.current&&clearTimeout(m.current)},ht),m.current=setTimeout(()=>u(1),bt),()=>{l.current&&clearTimeout(l.current),m.current&&clearTimeout(m.current)}},[e,r,t,o,n,a,i])}import{useCallback as qe}from"react";function Be({activeDropdownIndex:e,setActiveDropdownIndex:r,filteredOptions:t,selectOption:o,onSubmitRef:n,text:a,completedParams:i,isDropdownOpen:l,hasPlaceholder:m,placeholderText:f,suggestions:u,filterBaseRef:h,columns:g,setText:y,setCompletedParams:C,setSuggestions:S}){let P=qe(()=>{let p=t.map((c,x)=>c.is_tappable?x:-1).filter(c=>c!==-1),d=p.filter(c=>c%g===0),s=p.filter(c=>c%g===1);return[...d,...s]},[t,g]);return{handleKeyDown:qe(p=>{let d=P();switch(p.key){case"ArrowDown":{if(p.preventDefault(),d.length===0)return;let s=d.indexOf(e),c=s<d.length-1?s+1:0;r(d[c]);break}case"ArrowUp":{if(p.preventDefault(),d.length===0)return;let s=d.indexOf(e),c=s>0?s-1:d.length-1;r(d[c]);break}case"ArrowRight":{if(e<0)break;if(e%g===0){let s=e+1;s<t.length&&t[s]?.is_tappable&&(p.preventDefault(),r(s))}break}case"ArrowLeft":{if(e<0)break;if(e%g===1){let s=e-1;s>=0&&t[s]?.is_tappable&&(p.preventDefault(),r(s))}break}case"Enter":{if(p.preventDefault(),e>=0&&t[e]?.is_tappable)o(t[e]);else if(n.current){let{rawQuery:s,completedParams:c}=W(a,i),x={query:a.trim(),raw_query:s,completed_params:c};n.current(x)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)p.preventDefault(),o(t[e]);else if(l){let s=t.find(c=>c.is_tappable);s&&(p.preventDefault(),o(s))}else if(!a&&m){p.preventDefault();let s=u.find(c=>c.type==="placeholder");s?(y(f),h.current=f.length,C(c=>[...c,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:f,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),S(c=>c.filter(x=>x!==s))):(y(f),h.current=f.length)}break}case"Escape":r(-1);break}},[e,g,i,t,h,P,m,l,n,f,o,r,C,S,y,u,a]),getTappableIndices:P}}import{useCallback as Se}from"react";function Qe({completedParams:e,suggestions:r,setCompletedParams:t,setSuggestions:o,setActiveDropdownIndex:n,filterBaseRef:a,pillTappedRef:i}){let l=Se(u=>{let h=r.filter(S=>S.type!=="placeholder");if(u<0||u>=h.length)return;let g=h[u],y=h.filter((S,P)=>P!==u),C=r.filter(S=>S.type==="placeholder");o([...C,g,...y]),i.current=!0,n(-1)},[r,o,n,i]),m=Se(()=>{if(e.length===0)return;let u=e[e.length-1],h={type:u.suggestionType,text:u.suggestionPlaceholder,required:!0,options:u.options};t(g=>g.slice(0,-1)),o(g=>[h,...g]),n(-1)},[e,t,o,n]),f=Se(u=>{let h={type:u.suggestionType,text:u.suggestionPlaceholder,required:!0,options:u.options};return{apply:g=>{g(y=>{let C=0;for(let S of e){let P=y.indexOf(S.text,C);if(P!==-1){if(S.id===u.id){let v=y.slice(0,P),p=y.slice(P+u.text.length),d=(v+p).replace(/ {2,}/g," ");return a.current=Math.min(a.current,d.length),d}C=P+S.text.length}}return y}),t(y=>y.filter(C=>C.id!==u.id)),o(y=>[h,...y]),n(-1),i.current=!0}}},[e,t,o,n,a,i]);return{setActivePill:l,removeLastParam:m,reEditParam:f}}function xe({onSubmit:e,onError:r,optionOverrides:t,maskCompletedText:o,placeholder:n,apiConfig:a,columns:i=2,value:l,completedParams:m,onChange:f,onParamsChange:u}){let h=l!==void 0,g=m!==void 0,[y,C]=ie(""),[S,P]=ie([]),[v,p]=ie([]),[d,s]=ie(-1),c=h?l:y,x=g?m:S,T=U(e);T.current=e;let L=U(f);L.current=f;let $=U(u);$.current=u;let N=U(l);N.current=l;let D=U(m);D.current=m;let O=Y(b=>{if(typeof b=="function")if(h){let k=b(N.current??"");L.current?.(k)}else C(k=>{let q=b(k);return L.current?.(q),q});else h||C(b),L.current?.(b)},[h]),R=Y(b=>{if(typeof b=="function")if(g){let k=b(D.current??[]);$.current?.(k)}else P(k=>{let q=b(k);return $.current?.(q),q});else g||P(b),$.current?.(b)},[g]),j=U(r);j.current=r;let B=U(t);B.current=t;let J=U(o);J.current=o;let w=U(a);w.current=a;let I=U(c);I.current=c;let z=U(v);z.current=v;let _=U(0),te=U(!1),ve=U(!1),ce=St(),{doFetch:le,isLoading:Ae,error:He,isReady:Ve,lastRawQueryRef:ue}=je({textRef:I,suggestionsRef:z,filterBaseRef:_,maskCompletedTextRef:J,apiConfigRef:w,optionOverridesRef:B,onErrorRef:j,setCompletedParams:R,setSuggestions:p,setActiveDropdownIndex:s});ze({text:c,completedParams:x,doFetch:le,filterBaseRef:_,skipNextFetchRef:ve,suggestionsRef:z,lastRawQueryRef:ue});let Xe=se(()=>Le(c,x),[c,x]);_.current=Math.min(_.current,c.length);let pe=c.slice(_.current),me=se(()=>v.filter(k=>k.type==="placeholder").map(k=>k.text).join(" ")||n||"",[v,n]),oe=se(()=>v.filter(b=>b.type!=="placeholder"),[v]),A=oe[0],Ce=A?t?.[A.type]:void 0,ke=A?Ce?Ce(pe.trim()):A.options??[]:[],de=se(()=>ae(ke,pe),[ke,pe]),we=me.length>0,fe=!Ae&&de.length>0&&(!!c||te.current||!we),Oe=Y(b=>{if(!A)return;let k={id:crypto.randomUUID(),placeholder:"",type:A.type,text:b.text,kind:b.kind,suggestionType:A.type,suggestionPlaceholder:A.text,options:A.options,metadata:b.metadata},q=_.current,E=I.current.slice(0,q);if(E.length>0&&!E.endsWith(" ")){let M=E.split(/\s+/).pop()??"";M&&b.text.toLowerCase().startsWith(M.toLowerCase())&&(E=E.slice(0,E.length-M.length))}let ge=E.length>0&&E[E.length-1]!==" ",H=E+(ge?" ":"")+b.text+" ";O(H),_.current=H.length,R(M=>[...M,k]),p(M=>M.filter(Z=>Z!==A)),te.current=!1,s(-1),oe.length-1>0&&(ve.current=!0)},[A,oe,O,R]),We=Y(b=>{let k=b.target.value,E=k.length>0&&!b.nativeEvent?.isComposing&&k[0]!==k[0].toUpperCase()?k[0].toUpperCase()+k.slice(1):k;O(E),te.current=!1,s(-1);let{valid:ge,invalid:H}=Ne(E,x);if(H.length>0){R(()=>ge);for(let V of H)p(M=>[{type:V.suggestionType,text:V.suggestionPlaceholder,required:!0,options:V.options},...M])}if(A&&H.length===0){let V=E.slice(_.current),M=ee(A.options,V);M&&(R(Z=>[...Z,{id:crypto.randomUUID(),placeholder:"",type:A.type,text:M.text,kind:M.kind,suggestionType:A.type,suggestionPlaceholder:A.text,options:A.options,metadata:M.metadata}]),p(Z=>Z.filter(et=>et!==A)))}},[x,A,O,R]),{handleKeyDown:Ge}=Be({activeDropdownIndex:d,setActiveDropdownIndex:s,filteredOptions:de,selectOption:Oe,onSubmitRef:T,text:c,completedParams:x,isDropdownOpen:fe,hasPlaceholder:we,placeholderText:me,suggestions:v,filterBaseRef:_,columns:i,setText:O,setCompletedParams:R,setSuggestions:p}),ne=Qe({completedParams:x,suggestions:v,setCompletedParams:R,setSuggestions:p,setActiveDropdownIndex:s,filterBaseRef:_,pillTappedRef:te}),Ye=Y(b=>{ne.reEditParam(b).apply(O)},[ne,O]),Je=Y(()=>{O(""),R(()=>[]),p([]),s(-1),_.current=0,ue.current="",le("",[])},[le,O,R,ue]),Ze=d>=0?`${ce}-option-${d}`:void 0;return{completedParams:x,suggestionPills:oe,setActivePill:ne.setActivePill,removeLastParam:ne.removeLastParam,reEditParam:Ye,segments:Xe,suggestions:v,activeIndex:d,isReady:Ve,isLoading:Ae,error:He,inputProps:{value:c,placeholder:me||void 0,onChange:We,onKeyDown:Ge,role:"combobox","aria-expanded":fe,"aria-activedescendant":Ze,"aria-autocomplete":"list","aria-controls":ce},reset:Je,dropdownProps:{suggestions:A?[{...A,options:de}]:[],activeIndex:d,onSelect:Oe,onHighlight:s,isOpen:fe,id:ce}}}import{jsx as K,jsxs as Q}from"react/jsx-runtime";var kt=xt(function({onSubmit:r,onError:t,optionOverrides:o,maskCompletedText:n,placeholder:a,className:i,apiConfig:l,columns:m,value:f,completedParams:u,onChange:h,onParamsChange:g},y){let C=Pe(null),[S,P]=Ct(!1),v=Pe(()=>{}),p=Pe(void 0);vt(()=>(C.current?.focus(),()=>clearTimeout(p.current)),[]);let{completedParams:d,suggestionPills:s,setActivePill:c,segments:x,inputProps:T,dropdownProps:L,reset:$}=xe({onSubmit:w=>v.current(w),onError:t,optionOverrides:o,maskCompletedText:n,placeholder:a,apiConfig:l,columns:m,value:f,completedParams:u,onChange:h,onParamsChange:g});At(y,()=>({focus:()=>C.current?.focus(),reset:$}),[$]);let N=()=>{C.current?.focus()},D=!!T.value||d.length>0,O=Pt(()=>{if(!D)return;let{rawQuery:w,completedParams:I}=W(T.value,d);r({query:T.value.trim(),raw_query:w,completed_params:I}),$(),P(!0),clearTimeout(p.current),p.current=setTimeout(()=>P(!1),3e3)},[D,T.value,d,r,$]);v.current=O;let{onChange:R,placeholder:j,...B}=T,J=!T.value;return Q("div",{className:`${F.container} ${i??""}`,children:[K("div",{className:`${F.checkmark} ${S?F.checkmarkVisible:""}`,children:Q("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[K("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),K("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:F.checkmarkPath})]})}),K(be,{...L}),Q("div",{className:F.inputWrapper,onClick:N,children:[Q("div",{className:F.editorArea,children:[Q("div",{className:F.sizerContent,"aria-hidden":"true",children:[J&&j?Q("span",{className:F.placeholderText,children:[j," "]}):Q("span",{className:F.sizerText,children:[x.map((w,I)=>K("span",{children:w.value},`${I}-${w.type}`)),x.length===0&&"\xA0"]})," ",K(Ue,{pills:s,activePillIndex:0,onSelectPill:c})]}),K("textarea",{ref:C,className:F.textarea,rows:1,onChange:R,...B})]}),K("button",{type:"button",className:F.submitButton,disabled:!D,onClick:w=>{w.stopPropagation(),O()},"aria-label":"Submit",children:K("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:K("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});export{kt as AIAutocomplete,be as AIAutocompleteDropdown,xe as useAIAutocomplete};
2
2
  //# sourceMappingURL=index.mjs.map