@magicx-eng/ai-autocomplete-react 0.1.5 → 0.1.6
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/README.md +68 -21
- package/dist/index.d.mts +7 -1
- package/dist/index.d.ts +7 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +1 -1
- package/dist/index.mjs.map +1 -1
- package/package.json +9 -8
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/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"]}
|
|
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 eagerSuggestions,\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 eagerSuggestions,\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, 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\nlet idCounter = 0;\nfunction useStableId(): string {\n const id = useRef<string | null>(null);\n if (id.current === null) {\n id.current = `:ac-${++idCounter}:`;\n }\n return id.current;\n}\n\nexport function useAIAutocomplete({\n onSubmit,\n onError,\n optionOverrides,\n maskCompletedText,\n placeholder: customPlaceholder,\n apiConfig,\n columns = 2,\n eagerSuggestions = true,\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 = useStableId();\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 pillTappedRef.current = false;\n setActiveDropdownIndex(-1);\n const remainingActionable = actionableSuggestions.length - 1;\n if (eagerSuggestions && remainingActionable > 0) {\n // Keep cached suggestions visible and skip the fetch\n setSuggestions((prev) => prev.filter((s) => s !== activeSuggestion));\n skipNextFetchRef.current = true;\n } else {\n // Clear all suggestions and let the debounced fetch bring fresh ones\n setSuggestions((prev) => prev.filter((s) => s.type === \"placeholder\"));\n }\n },\n [activeSuggestion, actionableSuggestions, eagerSuggestions, 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 res = await fetchSuggestions(rawQuery, completed, {\n maskCompletedText: maskCompletedTextRef.current,\n signal: controller.signal,\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\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\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 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\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 ...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 // Column-first ordering: all column-0 items, then column-1, etc.\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\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 const col = activeDropdownIndex % columns;\n if (col < columns - 1) {\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 > 0) {\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","rawCount","p","contactAccountCount","body","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","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","buckets","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","idCounter","useStableId","id","useAIAutocomplete","onSubmit","onError","optionOverrides","maskCompletedText","customPlaceholder","apiConfig","columns","eagerSuggestions","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","remainingActionable","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","eagerSuggestions","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{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};
|
|
1
|
+
import{forwardRef as vt,useCallback as At,useEffect as Ct,useImperativeHandle as kt,useRef as ve,useState as wt}from"react";var D={};var be={};var Re={};var G={};import{jsx as st,jsxs as it}from"react/jsx-runtime";function _e({option:e,isHighlighted:n,onSelect:t,onHighlight:o,id:r}){let a=[G.item,n?G.highlighted:"",e.is_tappable?G.tappable:G.nonTappable].filter(Boolean).join(" ");return it("div",{id:r,role:"option","aria-selected":n,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&&st("span",{className:G.tag,children:e.tag})]})}import{jsx as Te}from"react/jsx-runtime";function Me({options:e,activeIndex:n,onSelect:t,onHighlight:o,listboxId:r}){return Te("div",{className:Re.grid,children:e.map((a,i)=>Te(_e,{option:a,isHighlighted:i===n,onSelect:t,onHighlight:()=>o(i),id:`${r}-option-${i}`},a.text))})}import{jsx as Ee}from"react/jsx-runtime";function ye({suggestions:e,activeIndex:n,onSelect:t,onHighlight:o,isOpen:r,id:a,className:i}){let p=e[0],f=r&&p&&p.options.length>0;return Ee("div",{id:a,role:"listbox",className:`${be.dropdown} ${f?be.visible:""} ${i??""}`,onMouseDown:g=>g.preventDefault(),children:p&&p.options.length>0&&Ee(Me,{options:p.options,activeIndex:n,onSelect:t,onHighlight:o,listboxId:a})})}var ne={};import{jsx as Ue}from"react/jsx-runtime";function lt(e){return e===0?.4:e===1?.3:.15}function Le({pills:e,activePillIndex:n,onSelectPill:t}){return Ue("span",{className:ne.list,children:e.map((o,r)=>Ue("button",{type:"button",className:`${ne.pill} ${r===n?ne.active:""}`,style:{opacity:lt(r)},onClick:()=>t(r),children:o.text},`${o.type}-${o.text}`))})}import{useCallback as Z,useMemo as se,useRef as M,useState as ie}from"react";function ae(e,n){let t=n.trimStart();if(!t)return e;let o=t.toLowerCase();return e.filter(r=>!r.is_tappable||r.text.toLowerCase().includes(o))}function ee(e,n){let t=n.trim();if(!t)return null;let o=t.toLowerCase();return e.find(r=>r.is_tappable&&r.text.toLowerCase()===o)??null}function Ne(e,n){let t=[],o=0;for(let a of n){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 r=e.slice(o);return r&&t.push({type:"text",value:r}),t}function De(e,n){let t=[],o=[],r=0;for(let a of n){let i=e.indexOf(a.text,r);i===-1?o.push(a):(t.push(a),r=i+a.text.length)}return{valid:t,invalid:o}}import{useCallback as ht,useEffect as je,useRef as J,useState as Se}from"react";var ut="0.1.6",pt=process?.env.MAGICX_API_ENDPOINT||"/api/suggest",$e=!1;function mt(e){let n=e?.apiKey||process?.env.MAGICX_AI_AUTOCOMPLETE_API_KEY||"";return!n&&!$e&&($e=!0,console.warn("[AIAutocomplete] No API key set (MAGICX_AI_AUTOCOMPLETE_API_KEY). Requests will be sent without an Authorization header.")),n}function dt(e){return e?.authScheme?e.authScheme:process?.env.MAGICX_AUTH_SCHEME==="Basic"?"Basic":"Bearer"}function ft(){return crypto.randomUUID()}function gt(e,n){return{placeholder:e.placeholder,type:e.type,...n&&{text:e.text},kind:e.kind}}async function Fe(e,n,t){let o=t?.apiConfig,r=mt(o),a=dt(o),i=!t?.maskCompletedText,p=n.find(c=>c.type==="contact"&&c.metadata?.contact_account_count)?.metadata?.contact_account_count,f=typeof p=="number"?p:void 0,g={data:{raw_query:e,completed_params:n.map(c=>gt(c,i)),...f!=null&&{contact_account_count:f}},meta:{request_id:ft(),request_at:new Date().toISOString(),language:typeof navigator<"u"?navigator.language:"en-US",client_version:ut}},m={"Content-Type":"application/json","X-App-Identifier":process?.env.MAGICX_APP_IDENTIFIER||"active-campaign-demo",...o?.headers};r&&(m.Authorization=a==="Basic"?`Basic ${btoa(r)}`:`Bearer ${r}`);let h=await fetch(pt,{method:"POST",headers:m,body:JSON.stringify(g),signal:t?.signal});if(!h.ok)throw new Error(`API error: ${h.status} ${h.statusText}`);return h.json()}function Y(e,n){let t=e,o={},r=[];for(let a of n){let i=(o[a.type]??0)+1;o[a.type]=i;let f=`{{${a.type.toUpperCase().replace(/\s+/g,"_")}_${i}}}`,g=t.indexOf(a.text);g!==-1&&(t=t.slice(0,g)+f+t.slice(g+a.text.length)),r.push({...a,placeholder:f})}return{rawQuery:t,completedParams:r}}function Ke(e,n){return n?e.map(t=>{let o=n[t.type];if(!o)return t;let r=o("");if(r.length===0)return t;let a=new Set(r.map(p=>p.text)),i=(t.options??[]).filter(p=>!a.has(p.text));return{...t,options:[...r,...i]}}):e}var bt=100,yt=300,St=2;function ze({textRef:e,suggestionsRef:n,filterBaseRef:t,maskCompletedTextRef:o,apiConfigRef:r,optionOverridesRef:a,onErrorRef:i,setCompletedParams:p,setSuggestions:f,setActiveDropdownIndex:g}){let[m,h]=Se(!1),[c,y]=Se(null),[k,b]=Se(!1),A=J(0),E=J(null),d=J(""),l=ht(async(s,u)=>{E.current?.abort();let x=new AbortController;E.current=x;let w=++A.current,O=e.current.length;n.current.some(C=>C.type!=="placeholder")||h(!0),y(null);try{let C=await Fe(s,u,{maskCompletedText:o.current,signal:x.signal,apiConfig:r.current});if(w!==A.current)return;let L=Ke(C.data.suggestions??[],a.current);b(C.data.is_ready??!1),d.current=s;let z=C.data.input??[],_=z[z.length-1],T=e.current;if(_?.state==="in_progress"){let $=T.toLowerCase().lastIndexOf(_.text.toLowerCase());$!==-1?t.current=$:t.current=O}else t.current=O;let N=L.filter($=>$.type!=="placeholder")[0];if(N){let $=T.slice(t.current),I=ee(N.options,$);I&&(p(F=>[...F,{id:crypto.randomUUID(),placeholder:"",type:N.type,text:I.text,kind:I.kind,suggestionType:N.type,suggestionPlaceholder:N.text,options:N.options,metadata:I.metadata}]),L=L.filter(F=>F!==N))}f(L),h(!1),g(-1)}catch(C){if(w===A.current){let L=C instanceof Error?C:new Error(String(C));y(L),h(!1),i.current?.(L)}}},[e,n,t,o,r,a,i,p,f,g]);return je(()=>(l("",[]),()=>{E.current?.abort()}),[l]),{doFetch:l,isLoading:m,error:c,isReady:k,lastRawQueryRef:d}}function qe({text:e,completedParams:n,doFetch:t,filterBaseRef:o,skipNextFetchRef:r,suggestionsRef:a,lastRawQueryRef:i}){let p=J(null),f=J(null),g=J(!0);je(()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current);let m=h=>{if(r.current)return r.current=!1,!1;if(!e&&n.length===0)return g.current?(t("",[]),!0):(g.current=!0,!1);let c=e.slice(o.current),b=a.current.filter(O=>O.type!=="placeholder")[0],E=(b?ae(b.options,c):[]).filter(O=>O.is_tappable),d=b?ee(b.options,c)!==null:!1,l=c.trim().length>0;if(E.length>0&&!d&&l)return!1;let{rawQuery:s,completedParams:u}=Y(e,n),x=s.length<i.current.length,w=Math.abs(s.length-i.current.length);return x||w>=h?(t(s,u),!0):!1};return p.current=setTimeout(()=>{m(St)&&f.current&&clearTimeout(f.current)},bt),f.current=setTimeout(()=>m(1),yt),()=>{p.current&&clearTimeout(p.current),f.current&&clearTimeout(f.current)}},[e,n,t,o,r,a,i])}import{useCallback as Be}from"react";function Qe({activeDropdownIndex:e,setActiveDropdownIndex:n,filteredOptions:t,selectOption:o,onSubmitRef:r,text:a,completedParams:i,isDropdownOpen:p,hasPlaceholder:f,placeholderText:g,suggestions:m,filterBaseRef:h,columns:c,setText:y,setCompletedParams:k,setSuggestions:b}){let A=Be(()=>{let d=t.map((s,u)=>s.is_tappable?u:-1).filter(s=>s!==-1),l=Array.from({length:c},()=>[]);for(let s of d)l[s%c].push(s);return l.flat()},[t,c]);return{handleKeyDown:Be(d=>{let l=A();switch(d.key){case"ArrowDown":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s<l.length-1?s+1:0;n(l[u]);break}case"ArrowUp":{if(d.preventDefault(),l.length===0)return;let s=l.indexOf(e),u=s>0?s-1:l.length-1;n(l[u]);break}case"ArrowRight":{if(e<0)break;if(e%c<c-1){let u=e+1;u<t.length&&t[u]?.is_tappable&&(d.preventDefault(),n(u))}break}case"ArrowLeft":{if(e<0)break;if(e%c>0){let s=e-1;s>=0&&t[s]?.is_tappable&&(d.preventDefault(),n(s))}break}case"Enter":{if(d.preventDefault(),e>=0&&t[e]?.is_tappable)o(t[e]);else if(r.current){let{rawQuery:s,completedParams:u}=Y(a,i),x={query:a.trim(),raw_query:s,completed_params:u};r.current(x)}break}case"Tab":{if(e>=0&&t[e]?.is_tappable)d.preventDefault(),o(t[e]);else if(p){let s=t.find(u=>u.is_tappable);s&&(d.preventDefault(),o(s))}else if(!a&&f){d.preventDefault();let s=m.find(u=>u.type==="placeholder");s?(y(g),h.current=g.length,k(u=>[...u,{id:crypto.randomUUID(),placeholder:"",type:s.type,text:g,kind:null,suggestionType:s.type,suggestionPlaceholder:s.text,options:s.options}]),b(u=>u.filter(x=>x!==s))):(y(g),h.current=g.length)}break}case"Escape":n(-1);break}},[e,c,i,t,h,A,f,p,r,g,o,n,k,b,y,m,a]),getTappableIndices:A}}import{useCallback as xe}from"react";function He({completedParams:e,suggestions:n,setCompletedParams:t,setSuggestions:o,setActiveDropdownIndex:r,filterBaseRef:a,pillTappedRef:i}){let p=xe(m=>{let h=n.filter(b=>b.type!=="placeholder");if(m<0||m>=h.length)return;let c=h[m],y=h.filter((b,A)=>A!==m),k=n.filter(b=>b.type==="placeholder");o([...k,c,...y]),i.current=!0,r(-1)},[n,o,r,i]),f=xe(()=>{if(e.length===0)return;let m=e[e.length-1],h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};t(c=>c.slice(0,-1)),o(c=>[h,...c]),r(-1)},[e,t,o,r]),g=xe(m=>{let h={type:m.suggestionType,text:m.suggestionPlaceholder,required:!0,options:m.options};return{apply:c=>{c(y=>{let k=0;for(let b of e){let A=y.indexOf(b.text,k);if(A!==-1){if(b.id===m.id){let E=y.slice(0,A),d=y.slice(A+m.text.length),l=(E+d).replace(/ {2,}/g," ");return a.current=Math.min(a.current,l.length),l}k=A+b.text.length}}return y}),t(y=>y.filter(k=>k.id!==m.id)),o(y=>[h,...y]),r(-1),i.current=!0}}},[e,t,o,r,a,i]);return{setActivePill:p,removeLastParam:f,reEditParam:g}}var xt=0;function Pt(){let e=M(null);return e.current===null&&(e.current=`:ac-${++xt}:`),e.current}function Pe({onSubmit:e,onError:n,optionOverrides:t,maskCompletedText:o,placeholder:r,apiConfig:a,columns:i=2,eagerSuggestions:p=!0,value:f,completedParams:g,onChange:m,onParamsChange:h}){let c=f!==void 0,y=g!==void 0,[k,b]=ie(""),[A,E]=ie([]),[d,l]=ie([]),[s,u]=ie(-1),x=c?f:k,w=y?g:A,O=M(e);O.current=e;let B=M(m);B.current=m;let C=M(h);C.current=h;let L=M(f);L.current=f;let z=M(g);z.current=g;let _=Z(S=>{if(typeof S=="function")if(c){let v=S(L.current??"");B.current?.(v)}else b(v=>{let q=S(v);return B.current?.(q),q});else c||b(S),B.current?.(S)},[c]),T=Z(S=>{if(typeof S=="function")if(y){let v=S(z.current??[]);C.current?.(v)}else E(v=>{let q=S(v);return C.current?.(q),q});else y||E(S),C.current?.(S)},[y]),X=M(n);X.current=n;let N=M(t);N.current=t;let $=M(o);$.current=o;let I=M(a);I.current=a;let F=M(x);F.current=x;let ce=M(d);ce.current=d;let K=M(0),te=M(!1),Ae=M(!1),le=Pt(),{doFetch:ue,isLoading:Ce,error:Ve,isReady:Xe,lastRawQueryRef:pe}=ze({textRef:F,suggestionsRef:ce,filterBaseRef:K,maskCompletedTextRef:$,apiConfigRef:I,optionOverridesRef:N,onErrorRef:X,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u});qe({text:x,completedParams:w,doFetch:ue,filterBaseRef:K,skipNextFetchRef:Ae,suggestionsRef:ce,lastRawQueryRef:pe});let We=se(()=>Ne(x,w),[x,w]);K.current=Math.min(K.current,x.length);let me=x.slice(K.current),de=se(()=>d.filter(v=>v.type==="placeholder").map(v=>v.text).join(" ")||r||"",[d,r]),oe=se(()=>d.filter(S=>S.type!=="placeholder"),[d]),P=oe[0],ke=P?t?.[P.type]:void 0,we=P?ke?ke(me.trim()):P.options??[]:[],fe=se(()=>ae(we,me),[we,me]),Oe=de.length>0,ge=!Ce&&fe.length>0&&(!!x||te.current||!Oe),Ie=Z(S=>{if(!P)return;let v={id:crypto.randomUUID(),placeholder:"",type:P.type,text:S.text,kind:S.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:S.metadata},q=K.current,U=F.current.slice(0,q);if(U.length>0&&!U.endsWith(" ")){let R=U.split(/\s+/).pop()??"";R&&S.text.toLowerCase().startsWith(R.toLowerCase())&&(U=U.slice(0,U.length-R.length))}let he=U.length>0&&U[U.length-1]!==" ",W=U+(he?" ":"")+S.text+" ";_(W),K.current=W.length,T(R=>[...R,v]),te.current=!1,u(-1);let Q=oe.length-1;p&&Q>0?(l(R=>R.filter(H=>H!==P)),Ae.current=!0):l(R=>R.filter(H=>H.type==="placeholder"))},[P,oe,p,_,T]),Ge=Z(S=>{let v=S.target.value,U=v.length>0&&!S.nativeEvent?.isComposing&&v[0]!==v[0].toUpperCase()?v[0].toUpperCase()+v.slice(1):v;_(U),te.current=!1,u(-1);let{valid:he,invalid:W}=De(U,w);if(W.length>0){T(()=>he);for(let Q of W)l(R=>[{type:Q.suggestionType,text:Q.suggestionPlaceholder,required:!0,options:Q.options},...R])}if(P&&W.length===0){let Q=U.slice(K.current),R=ee(P.options,Q);R&&(T(H=>[...H,{id:crypto.randomUUID(),placeholder:"",type:P.type,text:R.text,kind:R.kind,suggestionType:P.type,suggestionPlaceholder:P.text,options:P.options,metadata:R.metadata}]),l(H=>H.filter(tt=>tt!==P)))}},[w,P,_,T]),{handleKeyDown:Ye}=Qe({activeDropdownIndex:s,setActiveDropdownIndex:u,filteredOptions:fe,selectOption:Ie,onSubmitRef:O,text:x,completedParams:w,isDropdownOpen:ge,hasPlaceholder:Oe,placeholderText:de,suggestions:d,filterBaseRef:K,columns:i,setText:_,setCompletedParams:T,setSuggestions:l}),re=He({completedParams:w,suggestions:d,setCompletedParams:T,setSuggestions:l,setActiveDropdownIndex:u,filterBaseRef:K,pillTappedRef:te}),Je=Z(S=>{re.reEditParam(S).apply(_)},[re,_]),Ze=Z(()=>{_(""),T(()=>[]),l([]),u(-1),K.current=0,pe.current="",ue("",[])},[ue,_,T,pe]),et=s>=0?`${le}-option-${s}`:void 0;return{completedParams:w,suggestionPills:oe,setActivePill:re.setActivePill,removeLastParam:re.removeLastParam,reEditParam:Je,segments:We,suggestions:d,activeIndex:s,isReady:Xe,isLoading:Ce,error:Ve,inputProps:{value:x,placeholder:de||void 0,onChange:Ge,onKeyDown:Ye,role:"combobox","aria-expanded":ge,"aria-activedescendant":et,"aria-autocomplete":"list","aria-controls":le},reset:Ze,dropdownProps:{suggestions:P?[{...P,options:fe}]:[],activeIndex:s,onSelect:Ie,onHighlight:u,isOpen:ge,id:le}}}import{jsx as j,jsxs as V}from"react/jsx-runtime";var Ot=vt(function({onSubmit:n,onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,className:i,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y},k){let b=ve(null),[A,E]=wt(!1),d=ve(()=>{}),l=ve(void 0);Ct(()=>(b.current?.focus(),()=>clearTimeout(l.current)),[]);let{completedParams:s,suggestionPills:u,setActivePill:x,segments:w,inputProps:O,dropdownProps:B,reset:C}=Pe({onSubmit:I=>d.current(I),onError:t,optionOverrides:o,maskCompletedText:r,placeholder:a,apiConfig:p,columns:f,eagerSuggestions:g,value:m,completedParams:h,onChange:c,onParamsChange:y});kt(k,()=>({focus:()=>b.current?.focus(),reset:C}),[C]);let L=()=>{b.current?.focus()},z=!!O.value||s.length>0,_=At(()=>{if(!z)return;let{rawQuery:I,completedParams:F}=Y(O.value,s);n({query:O.value.trim(),raw_query:I,completed_params:F}),C(),E(!0),clearTimeout(l.current),l.current=setTimeout(()=>E(!1),3e3)},[z,O.value,s,n,C]);d.current=_;let{onChange:T,placeholder:X,...N}=O,$=!O.value;return V("div",{className:`${D.container} ${i??""}`,children:[j("div",{className:`${D.checkmark} ${A?D.checkmarkVisible:""}`,children:V("svg",{width:"72",height:"72",viewBox:"0 0 24 24",fill:"none",role:"img","aria-label":"Success",children:[j("circle",{cx:"12",cy:"12",r:"12",fill:"#34C759"}),j("path",{d:"M7 12.5l3.5 3.5L17 9",stroke:"#000",strokeWidth:"2.5",strokeLinecap:"round",strokeLinejoin:"round",className:D.checkmarkPath})]})}),j(ye,{...B}),V("div",{className:D.inputWrapper,onClick:L,children:[V("div",{className:D.editorArea,children:[V("div",{className:D.sizerContent,"aria-hidden":"true",children:[$&&X?V("span",{className:D.placeholderText,children:[X," "]}):V("span",{className:D.sizerText,children:[w.map((I,F)=>j("span",{children:I.value},`${F}-${I.type}`)),w.length===0&&"\xA0"]})," ",j(Le,{pills:u,activePillIndex:0,onSelectPill:x})]}),j("textarea",{ref:b,className:D.textarea,rows:1,onChange:T,...N})]}),j("button",{type:"button",className:D.submitButton,disabled:!z,onClick:I=>{I.stopPropagation(),_()},"aria-label":"Submit",children:j("svg",{width:"18",height:"18",viewBox:"0 0 18 18",fill:"none",role:"img","aria-label":"Submit",children:j("path",{d:"M9 14V4M9 4L4 9M9 4L14 9",stroke:"currentColor",strokeWidth:"2",strokeLinecap:"round",strokeLinejoin:"round"})})})]})]})});export{Ot as AIAutocomplete,ye as AIAutocompleteDropdown,Pe as useAIAutocomplete};
|
|
2
2
|
//# sourceMappingURL=index.mjs.map
|