@magicx-eng/ai-autocomplete-vanilla 0.1.9 → 0.1.10
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/index.js +2 -1
- package/index.js.map +1 -1
- package/index.mjs +2 -1
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/core/index.ts","../src/utils/filtering.ts","../src/utils/modeController.ts","../src/utils/segments.ts","../src/utils/tokenManager.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/core/controllers/fetchController.ts","../src/core/controllers/keyboardController.ts","../src/core/controllers/pillsController.ts","../src/core/render/renderPills.ts","../src/core/render/renderDropdown.ts","../src/core/render/renderDropdownOnly.ts","../src/core/render/renderSegments.ts","../src/core/render/renderInput.ts","../src/core/state.ts","../src/core/styleInjector.ts","../src/core/AIAutocomplete.ts"],"sourcesContent":["// Re-export shared types consumers need\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n Segment,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nexport { AIAutocomplete } from \"./AIAutocomplete\";\nexport type { Store } from \"./state\";\nexport { createStore } from \"./state\";\nexport type { CoreOptions, CoreState, RenderMode } from \"./types\";\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Extracts the effective filter query from the region after filterBase.\n * If the server marked the region as in_progress, the full region is used.\n * Otherwise, filtering only starts after the first space (to avoid filtering\n * mid-word when the user continues typing a word that was already in the input).\n */\nexport function extractFilterQuery(\n text: string,\n filterBase: number,\n isInProgress: boolean,\n): string {\n const rawRegion = text.slice(filterBase);\n if (isInProgress || filterBase === 0 || text[filterBase - 1] === \" \") {\n return rawRegion;\n }\n const spaceIdx = rawRegion.indexOf(\" \");\n return spaceIdx === -1 ? \"\" : rawRegion.slice(spaceIdx + 1);\n}\n\n/**\n * Finds the longest word-boundary-aligned suffix of `prefix` that matches a\n * prefix of `optionText` (case-insensitive). Returns the number of characters\n * to remove from the end of `prefix` to avoid duplication.\n */\nexport function findPrefixOverlap(prefix: string, optionText: string): number {\n // Normalize internal whitespace so words.join(\" \") roundtrips losslessly\n const trimmed = prefix.trimEnd().replace(/\\s+/g, \" \");\n if (trimmed.length === 0 || optionText.length === 0) return 0;\n\n const words = trimmed.split(\" \");\n const optionLower = optionText.toLowerCase();\n\n // Try from longest suffix (all words) to shortest (last word only)\n for (let i = 0; i < words.length; i++) {\n const candidate = words.slice(i).join(\" \");\n if (optionLower.startsWith(candidate.toLowerCase())) {\n const suffixStart = trimmed.length - candidate.length;\n return prefix.length - suffixStart;\n }\n }\n\n return 0;\n}\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption[] {\n if (!options) return [];\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption | null {\n if (!options) return null;\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { AppearanceMode } from \"../types\";\n\nexport class ModeController {\n private mediaQuery: MediaQueryList | null = null;\n\n constructor(\n private container: HTMLElement,\n private mode: AppearanceMode = \"auto\",\n ) {\n this.apply();\n }\n\n setMode(mode: AppearanceMode) {\n this.detachListener();\n this.mode = mode;\n this.apply();\n }\n\n destroy() {\n this.detachListener();\n }\n\n private apply() {\n if (this.mode === \"auto\") {\n this.mediaQuery ??= window.matchMedia(\"(prefers-color-scheme: dark)\");\n this.mediaQuery.addEventListener(\"change\", this.onSystemChange);\n this.container.dataset.mode = this.mediaQuery.matches ? \"dark\" : \"light\";\n } else {\n this.container.dataset.mode = this.mode;\n }\n }\n\n private onSystemChange = (e: MediaQueryListEvent) => {\n this.container.dataset.mode = e.matches ? \"dark\" : \"light\";\n };\n\n private detachListener() {\n this.mediaQuery?.removeEventListener(\"change\", this.onSystemChange);\n }\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import type { AccessTokenConfig } from \"../types\";\n\n/** Refresh 30 seconds before stated expiry to absorb clock drift and request latency. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport class TokenManager {\n private current: string | null = null;\n private expiresAt: number | null = null;\n private inFlightRefresh: Promise<string> | null = null;\n\n constructor(private config: AccessTokenConfig) {\n if (config.accessToken) {\n this.current = config.accessToken;\n }\n }\n\n /** Returns a valid token, refreshing if needed. Single-flight: concurrent callers share one refresh. */\n async getToken(forceRefresh = false): Promise<string> {\n if (!forceRefresh && this.current && !this.isExpired()) {\n return this.current;\n }\n if (!forceRefresh && this.inFlightRefresh) {\n return this.inFlightRefresh;\n }\n this.inFlightRefresh = this.refresh();\n try {\n return await this.inFlightRefresh;\n } finally {\n this.inFlightRefresh = null;\n }\n }\n\n private async refresh(): Promise<string> {\n const result = await this.config.getAccessToken();\n this.current = result.accessToken;\n this.expiresAt = result.expiresAt ?? null;\n return this.current;\n }\n\n private isExpired(): boolean {\n if (this.expiresAt == null) return false;\n return Date.now() >= this.expiresAt - REFRESH_SKEW_MS;\n }\n}\n","import type {\n AccessTokenConfig,\n APIConfig,\n APIKeyConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\nimport { TokenManager } from \"./tokenManager\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\nlet hasWarnedMissingKey = false;\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nfunction isAccessTokenConfig(config?: APIConfig): config is AccessTokenConfig {\n return config?.type === \"accessToken\";\n}\n\nfunction getApiKeyConfig(config?: APIConfig): APIKeyConfig | undefined {\n if (!config || isAccessTokenConfig(config)) return undefined;\n return config;\n}\n\n// Keyed by getAccessToken function reference (stable across React re-renders)\nconst tokenManagers = new WeakMap<AccessTokenConfig[\"getAccessToken\"], TokenManager>();\n\nfunction getTokenManager(config: AccessTokenConfig): TokenManager {\n let manager = tokenManagers.get(config.getAccessToken);\n if (!manager) {\n manager = new TokenManager(config);\n tokenManagers.set(config.getAccessToken, manager);\n }\n return manager;\n}\n\nfunction buildRequestBody(\n rawQuery: string,\n completedParams: CompletedParamState[],\n includeText: boolean,\n sessionId: string,\n): AutocompleteRequest {\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n return {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n session_id: sessionId,\n },\n };\n}\n\nfunction buildHeaders(apiConfig?: APIConfig): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n ...(apiConfig?.appIdentifier && { \"X-App-Identifier\": apiConfig.appIdentifier }),\n ...apiConfig?.headers,\n };\n}\n\nasync function doFetch(\n endpoint: string,\n headers: Record<string, string>,\n token: string,\n body: string,\n signal?: AbortSignal,\n): Promise<Response> {\n return fetch(endpoint, {\n method: \"POST\",\n headers: { ...headers, Authorization: `Bearer ${token}` },\n body,\n signal,\n });\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options: {\n sessionId: string;\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options.apiConfig;\n const includeText = !options.maskCompletedText;\n const body = buildRequestBody(rawQuery, completedParams, includeText, options.sessionId);\n const headers = buildHeaders(apiConfig);\n const endpoint = apiConfig?.endpoint ?? \"https://api.ai-autocomplete.com/api/suggest\";\n const jsonBody = JSON.stringify(body);\n\n // === Access token mode ===\n if (isAccessTokenConfig(apiConfig)) {\n const manager = getTokenManager(apiConfig);\n const token = await manager.getToken();\n\n let response = await doFetch(endpoint, headers, token, jsonBody, options.signal);\n\n // 401 retry: force-refresh token and retry exactly once\n if (response.status === 401) {\n const newToken = await manager.getToken(true);\n response = await doFetch(endpoint, headers, newToken, jsonBody, options.signal);\n }\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n }\n\n // === API key mode (default) ===\n const apiKeyConfig = getApiKeyConfig(apiConfig);\n const apiKey = apiKeyConfig?.apiKey ?? \"\";\n\n if (!apiKey && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No apiKey in apiConfig. Requests will be sent without an Authorization header.\",\n );\n }\n\n if (apiKey) {\n const authScheme = apiKeyConfig?.authScheme ?? \"Bearer\";\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: jsonBody,\n signal: options.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { 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 {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../../types\";\nimport { fetchSuggestions } from \"../../utils/api\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { extractFilterQuery, filterOptions, findExactMatch } from \"../../utils/filtering\";\nimport { applyOptionOverrides } from \"../../utils/overrides\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\nexport class FetchController {\n private fetchVersion = 0;\n private abortController: AbortController | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private slowDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: (() => void) | null = null;\n\n constructor(\n private store: Store<CoreState>,\n private getApiConfig: () => APIConfig | undefined,\n private getOptionOverrides: () => OptionOverrides | undefined,\n private getMaskCompletedText: () => boolean | undefined,\n private getOnError: () => ((error: Error) => void) | undefined,\n private getSessionId: () => string,\n ) {}\n\n start() {\n // Initial fetch\n this.doFetch(\"\", []);\n\n // Subscribe to state changes for debounced fetching\n let prevText = this.store.get().text;\n let prevParams = this.store.get().completedParams;\n this.unsubscribe = this.store.subscribe((next) => {\n if (next.text !== prevText || next.completedParams !== prevParams) {\n prevText = next.text;\n prevParams = next.completedParams;\n this.scheduleFetch();\n }\n });\n }\n\n dispose() {\n this.abortController?.abort();\n this.clearTimers();\n this.unsubscribe?.();\n }\n\n async doFetch(rawQuery: string, completed: CompletedParamState[]) {\n this.abortController?.abort();\n const controller = new AbortController();\n this.abortController = controller;\n const version = ++this.fetchVersion;\n const state = this.store.get();\n const textAtRequest = state.text.length;\n\n const hasSuggestions = state.suggestions.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) this.store.set({ isLoading: true });\n this.store.set({ error: null });\n\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n sessionId: this.getSessionId(),\n maskCompletedText: this.getMaskCompletedText(),\n signal: controller.signal,\n apiConfig: this.getApiConfig(),\n });\n\n if (version !== this.fetchVersion) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n this.getOptionOverrides(),\n );\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = this.store.get().text;\n let filterBase: number;\n let filterInProgress: boolean;\n\n if (lastInput?.state === \"in_progress\") {\n filterInProgress = true;\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n filterBase = inProgressIdx !== -1 ? inProgressIdx : textAtRequest;\n } else {\n filterInProgress = false;\n filterBase = textAtRequest;\n }\n\n // Check if user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n let extraParam: CompletedParamState | null = null;\n if (active) {\n const query = extractFilterQuery(currentText, filterBase, filterInProgress);\n const match = findExactMatch(active.options, query);\n if (match) {\n extraParam = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n this.store.set((s) => ({\n suggestions: newSuggestions,\n isLoading: false,\n isReady: res.data.is_ready ?? false,\n lastRawQuery: rawQuery,\n activeDropdownIndex: -1,\n filterBase,\n filterInProgress,\n ...(extraParam ? { completedParams: [...s.completedParams, extraParam] } : {}),\n }));\n } catch (err) {\n if (version === this.fetchVersion) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n this.store.set({ error: caughtError, isLoading: false });\n this.getOnError()?.(caughtError);\n }\n }\n }\n\n private scheduleFetch() {\n this.clearTimers();\n const state = this.store.get();\n\n if (state.skipNextFetch) {\n this.store.set({ skipNextFetch: false });\n return;\n }\n\n const attemptFetch = (minDiff: number): boolean => {\n const s = this.store.get();\n if (!s.text && s.completedParams.length === 0) {\n this.doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = extractFilterQuery(s.text, s.filterBase, s.filterInProgress);\n const actionable = s.suggestions.filter((sg: Suggestion) => sg.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n // Mirror the filter-zone behavior for placeholder suggestions: if the user is\n // still typing a prefix of the server-provided placeholder, don't fetch yet.\n if (s.completedParams.length === 0 && s.text.length > 0) {\n const placeholderText = s.suggestions\n .filter((sg: Suggestion) => sg.type === \"placeholder\")\n .map((sg: Suggestion) => sg.text)\n .join(\" \");\n if (\n placeholderText.length > 0 &&\n placeholderText.toLowerCase().startsWith(s.text.toLowerCase())\n ) {\n return false;\n }\n }\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(s.text, s.completedParams);\n const isDeleting = rawQuery.length < s.lastRawQuery.length;\n const charDiff = Math.abs(rawQuery.length - s.lastRawQuery.length);\n if (isDeleting || charDiff >= minDiff) {\n this.doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n this.debounceTimer = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n }\n }, DEBOUNCE_MS);\n\n this.slowDebounceTimer = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n }\n\n private clearTimers() {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n this.debounceTimer = null;\n this.slowDebounceTimer = null;\n }\n}\n","import type { AutocompleteResult, SuggestionOption } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface KeyboardContext {\n columns: number;\n listboxId: string;\n getOnSubmit: () => ((result: AutocompleteResult) => void) | undefined;\n selectOption: (option: SuggestionOption) => void;\n}\n\nexport class KeyboardController {\n constructor(\n private store: Store<CoreState>,\n private ctx: KeyboardContext,\n ) {}\n\n handleKeyDown(e: KeyboardEvent) {\n const state = this.store.get();\n const { listboxId, getOnSubmit } = this.ctx;\n const columns = this.getEffectiveColumns();\n const onSubmit = getOnSubmit();\n const tappableIndices = this.getTappableIndices(columns);\n\n switch (e.key) {\n case \"ArrowDown\": {\n const target = e.target as HTMLTextAreaElement;\n const cursorAtEnd =\n target.selectionStart != null && target.selectionStart === target.value.length;\n if (!cursorAtEnd && state.activeDropdownIndex < 0) break;\n\n e.preventDefault();\n if (!state.isDropdownOpen && state.actionableSuggestions.length > 0) {\n this.store.set({ pillTapped: true, activeDropdownIndex: tappableIndices[0] ?? 0 });\n break;\n }\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n this.store.set({ activeDropdownIndex: tappableIndices[nextPos] });\n break;\n }\n case \"ArrowUp\": {\n if (tappableIndices.length === 0 || state.activeDropdownIndex < 0) break;\n e.preventDefault();\n if (state.activeDropdownIndex < columns) {\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n this.store.set({ activeDropdownIndex: tappableIndices[prevPos] });\n break;\n }\n case \"ArrowRight\": {\n if (state.activeDropdownIndex < 0) {\n const target = e.target as HTMLTextAreaElement;\n const atEnd =\n target.selectionStart != null && target.selectionStart === target.value.length;\n if (atEnd && state.actionableSuggestions.length > 1) {\n e.preventDefault();\n this.pillsSetActivePill(1);\n }\n break;\n }\n const col = state.activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = state.activeDropdownIndex + 1;\n if (\n rightNeighbor < state.filteredOptions.length &&\n state.filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n this.store.set({ activeDropdownIndex: rightNeighbor });\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (state.activeDropdownIndex < 0) break;\n if (state.activeDropdownIndex % columns > 0) {\n const leftNeighbor = state.activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && state.filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n this.store.set({ activeDropdownIndex: leftNeighbor });\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable\n ) {\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (onSubmit) {\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n }\n break;\n }\n case \"Tab\": {\n const placeholderVisible = !state.text && !!state.placeholderText;\n const hasHighlightedOption =\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable;\n\n // Placeholder visible + option highlighted → defer to selectOption,\n // which prepends the placeholder text to the option (see AIAutocomplete.selectOption).\n if (placeholderVisible && !hasHighlightedOption) {\n e.preventDefault();\n const placeholderSuggestion = state.suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n this.store.set((s) => ({\n text: state.placeholderText,\n filterBase: state.placeholderText.length,\n completedParams: [\n ...s.completedParams,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: state.placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options ?? [],\n },\n ],\n suggestions: s.suggestions.filter((sg) => sg !== placeholderSuggestion),\n }));\n } else {\n this.store.set({\n text: state.placeholderText,\n filterBase: state.placeholderText.length,\n });\n }\n } else if (hasHighlightedOption) {\n e.preventDefault();\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (state.isDropdownOpen) {\n const firstTappableIdx = state.filteredOptions.findIndex((o) => o.is_tappable);\n if (firstTappableIdx >= 0) {\n e.preventDefault();\n this.clickOrSelect(firstTappableIdx, state.filteredOptions, listboxId);\n }\n }\n break;\n }\n case \"Escape\":\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n }\n\n private getTappableIndices(columns: number): number[] {\n const state = this.store.get();\n const tappable = state.filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }\n\n /**\n * The grid uses a container query to switch between 1 and 2 columns based on\n * width, so the prop value can disagree with what's actually rendered. Read\n * the live column count from the grid; fall back to the prop if unavailable.\n */\n private getEffectiveColumns(): number {\n const firstOption = document.getElementById(`${this.ctx.listboxId}-option-0`);\n const grid = firstOption?.parentElement;\n if (!grid) return this.ctx.columns;\n const tracks = getComputedStyle(grid).gridTemplateColumns.split(\" \").filter(Boolean).length;\n return tracks > 0 ? tracks : this.ctx.columns;\n }\n\n private clickOrSelect(index: number, options: SuggestionOption[], listboxId: string) {\n const optionEl = document.getElementById(`${listboxId}-option-${index}`);\n if (optionEl) {\n optionEl.click();\n } else {\n this.ctx.selectOption(options[index]);\n }\n }\n\n /** Delegate to pills controller logic inline (avoids circular dep) */\n private pillsSetActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n}\n","import type { Suggestion } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport class PillsController {\n constructor(private store: Store<CoreState>) {}\n\n setActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n\n removeLastParam() {\n const state = this.store.get();\n if (state.completedParams.length === 0) return;\n const lastParam = state.completedParams[state.completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n this.store.set((s) => ({\n completedParams: s.completedParams.slice(0, -1),\n suggestions: [restoredSuggestion, ...s.suggestions],\n activeDropdownIndex: -1,\n }));\n }\n}\n","import type { Suggestion } from \"../../types\";\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function renderPills(\n container: HTMLElement,\n pills: Suggestion[],\n activePillIndex: number,\n onSelectPill: (index: number) => void,\n rounded = false,\n) {\n // Reuse or create the list wrapper\n let list = container.querySelector<HTMLElement>(\".magicx-aia-pill-list\");\n if (!list) {\n list = document.createElement(\"span\");\n list.className = \"magicx-aia-pill-list\";\n container.appendChild(list);\n }\n\n // Diff by key (type-text)\n const existing = new Map<string, HTMLButtonElement>();\n for (const btn of list.querySelectorAll<HTMLButtonElement>(\".magicx-aia-pill\")) {\n existing.set(btn.dataset.pillKey ?? \"\", btn);\n }\n\n const used = new Set<string>();\n for (let i = 0; i < pills.length; i++) {\n const pill = pills[i];\n const key = `${pill.type}-${pill.text}`;\n used.add(key);\n\n let btn = existing.get(key);\n if (!btn) {\n btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.dataset.pillKey = key;\n btn.setAttribute(\"data-aia-pill\", \"\");\n btn.textContent = pill.text;\n }\n\n btn.className = `magicx-aia-pill${rounded ? \" magicx-aia-pill--rounded\" : \"\"}${i === activePillIndex ? \" magicx-aia-pill--active\" : \"\"}`;\n btn.style.opacity = String(getPillOpacity(i));\n btn.onclick = () => onSelectPill(i);\n\n // Ensure correct order\n if (list.children[i] !== btn) {\n list.insertBefore(btn, list.children[i] ?? null);\n }\n }\n\n // Remove stale pills\n for (const [key, btn] of existing) {\n if (!used.has(key)) btn.remove();\n }\n}\n\nexport function clearPills(container: HTMLElement) {\n container.querySelector(\".magicx-aia-pill-list\")?.remove();\n}\n","import type { Suggestion, SuggestionOption } from \"../../types\";\nimport { renderPills } from \"./renderPills\";\n\ninterface DropdownState {\n suggestions: Suggestion[];\n filteredOptions: SuggestionOption[];\n activeIndex: number;\n isOpen: boolean;\n listboxId: string;\n pills: Suggestion[];\n showPills: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPillClick: (index: number) => void;\n}\n\nexport function createDropdown(listboxId: string): HTMLElement {\n const dropdown = document.createElement(\"div\");\n dropdown.id = listboxId;\n dropdown.setAttribute(\"role\", \"listbox\");\n dropdown.setAttribute(\"data-aia-dropdown\", \"\");\n dropdown.className = \"magicx-aia-dropdown\";\n dropdown.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return dropdown;\n}\n\nexport function renderDropdown(dropdown: HTMLElement, state: DropdownState) {\n const {\n filteredOptions,\n activeIndex,\n isOpen,\n pills,\n showPills,\n onSelect,\n onHighlight,\n onPillClick,\n } = state;\n\n const hasPills = showPills && pills.length > 0;\n const hasOptions = isOpen && filteredOptions.length > 0;\n const isVisible = hasOptions || (isOpen && hasPills);\n\n // Toggle visibility\n if (isVisible) {\n dropdown.classList.add(\"magicx-aia-dropdown--visible\");\n } else {\n dropdown.classList.remove(\"magicx-aia-dropdown--visible\");\n }\n\n // --- Pill bar ---\n let pillBar = dropdown.querySelector<HTMLElement>(\".magicx-aia-pill-bar\");\n if (hasPills) {\n if (!pillBar) {\n pillBar = document.createElement(\"div\");\n pillBar.className = \"magicx-aia-pill-bar\";\n pillBar.setAttribute(\"data-aia-pillbar\", \"\");\n dropdown.insertBefore(pillBar, dropdown.firstChild);\n }\n renderPills(pillBar, pills, 0, onPillClick, true);\n } else if (pillBar) {\n pillBar.remove();\n }\n\n // --- Options grid ---\n let grid = dropdown.querySelector<HTMLElement>(\".magicx-aia-grid\");\n if (filteredOptions.length > 0) {\n if (!grid) {\n grid = document.createElement(\"div\");\n grid.className = \"magicx-aia-grid\";\n dropdown.appendChild(grid);\n }\n renderOptions(grid, filteredOptions, activeIndex, onSelect, onHighlight, state.listboxId);\n } else if (grid) {\n grid.innerHTML = \"\";\n }\n}\n\nfunction renderOptions(\n grid: HTMLElement,\n options: SuggestionOption[],\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n) {\n const optionsKey = options.map((o) => o.text).join(\"\\0\");\n const lastKey = grid.dataset.optionsKey ?? \"\";\n const listChanged = optionsKey !== lastKey;\n grid.dataset.optionsKey = optionsKey;\n\n if (listChanged) {\n // Full rebuild — options changed (filter, new suggestion, etc.)\n const fragment = document.createDocumentFragment();\n\n for (let i = 0; i < options.length; i++) {\n const option = options[i];\n const item = createOptionElement(option, i, activeIndex, onSelect, onHighlight, listboxId);\n fragment.appendChild(item);\n }\n\n grid.innerHTML = \"\";\n grid.appendChild(fragment);\n } else {\n // Just update highlight classes — no DOM rebuild\n const items = grid.querySelectorAll<HTMLElement>(\".magicx-aia-option\");\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const isHighlighted = i === activeIndex;\n item.setAttribute(\"aria-selected\", String(isHighlighted));\n if (isHighlighted) {\n item.classList.add(\"magicx-aia-option--highlighted\");\n } else {\n item.classList.remove(\"magicx-aia-option--highlighted\");\n }\n }\n }\n}\n\nfunction createOptionElement(\n option: SuggestionOption,\n index: number,\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n): HTMLElement {\n const item = document.createElement(\"div\");\n item.id = `${listboxId}-option-${index}`;\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"data-aia-option\", \"\");\n item.setAttribute(\"aria-selected\", String(index === activeIndex));\n item.tabIndex = option.is_tappable ? 0 : -1;\n\n const classes = [\"magicx-aia-option\"];\n if (index === activeIndex) classes.push(\"magicx-aia-option--highlighted\");\n if (option.is_tappable) {\n classes.push(\"magicx-aia-option--tappable\");\n } else {\n classes.push(\"magicx-aia-option--non-tappable\");\n }\n item.className = classes.join(\" \");\n\n // Streaks\n const streaks = document.createElement(\"div\");\n streaks.className = \"magicx-aia-streaks\";\n item.appendChild(streaks);\n\n const streaksVert = document.createElement(\"div\");\n streaksVert.className = \"magicx-aia-streaks-vert\";\n item.appendChild(streaksVert);\n\n // Content\n const content = document.createElement(\"span\");\n content.className = \"magicx-aia-option-content\";\n content.textContent = option.icon ? `${option.icon} ${option.text}` : option.text;\n\n if (option.tag) {\n const tag = document.createElement(\"span\");\n tag.className = \"magicx-aia-option-tag\";\n tag.textContent = option.tag;\n content.appendChild(tag);\n }\n\n item.appendChild(content);\n\n // Events\n if (option.is_tappable) {\n item.addEventListener(\"click\", () => {\n item.classList.add(\"magicx-aia-option--pressed\");\n onSelect(option);\n setTimeout(() => item.classList.remove(\"magicx-aia-option--pressed\"), 400);\n });\n item.addEventListener(\"mouseenter\", () => onHighlight(index));\n }\n\n return item;\n}\n","import type { SuggestionOption } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\n\ninterface DropdownOnlyRefs {\n dropdown: HTMLElement;\n}\n\ninterface DropdownOnlyOptions {\n store: Store<CoreState>;\n listboxId: string;\n selectOption: (option: SuggestionOption) => void;\n setActivePill: (index: number) => void;\n}\n\nexport function buildDropdownOnly(\n container: HTMLElement,\n opts: DropdownOnlyOptions,\n): DropdownOnlyRefs {\n const dropdown = createDropdown(opts.listboxId);\n container.appendChild(dropdown);\n return { dropdown };\n}\n\nexport function updateDropdownOnly(\n refs: DropdownOnlyRefs,\n state: CoreState,\n opts: DropdownOnlyOptions,\n) {\n renderDropdown(refs.dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: true, // always show pills in dropdown-only mode\n onSelect: opts.selectOption,\n onHighlight: (i) => opts.store.set({ activeDropdownIndex: i }),\n onPillClick: opts.setActivePill,\n });\n}\n","import type { Segment } from \"../../types\";\n\n/**\n * Renders text segments into the sizer overlay.\n * Only rebuilds the DOM when segment content or newParamId changes,\n * preserving in-flight CSS animations (shimmer).\n * Cache keys stored on the DOM element to support multi-instance use.\n */\nexport function renderSegments(\n sizer: HTMLElement,\n segments: Segment[],\n newParamId: string | null,\n isEmpty: boolean,\n placeholderText: string,\n) {\n let sizerText = sizer.querySelector<HTMLElement>(\".magicx-aia-sizer-text\");\n let placeholder = sizer.querySelector<HTMLElement>(\".magicx-aia-placeholder\");\n\n if (isEmpty && placeholderText) {\n if (sizerText) sizerText.style.display = \"none\";\n if (!placeholder) {\n placeholder = document.createElement(\"span\");\n placeholder.className = \"magicx-aia-placeholder\";\n sizer.insertBefore(placeholder, sizer.firstChild);\n }\n placeholder.style.display = \"\";\n placeholder.textContent = `${placeholderText} `;\n sizer.dataset.segmentKey = \"\";\n return;\n }\n\n if (placeholder) placeholder.style.display = \"none\";\n if (!sizerText) {\n sizerText = document.createElement(\"span\");\n sizerText.className = \"magicx-aia-sizer-text\";\n sizer.insertBefore(sizerText, sizer.firstChild);\n }\n sizerText.style.display = \"\";\n sizerText.className = `magicx-aia-sizer-text${newParamId ? \" magicx-aia-sizer-text--visible\" : \"\"}`;\n\n const segmentKey = segments.map((s) => `${s.type}:${s.value}`).join(\"\\0\");\n const lastKey = sizer.dataset.segmentKey ?? \"\";\n const lastParamId = sizer.dataset.newParamId ?? \"\";\n if (segmentKey === lastKey && (newParamId ?? \"\") === lastParamId) {\n return; // Nothing changed — preserve existing DOM and animations\n }\n sizer.dataset.segmentKey = segmentKey;\n sizer.dataset.newParamId = newParamId ?? \"\";\n\n sizerText.innerHTML = \"\";\n for (const seg of segments) {\n const span = document.createElement(\"span\");\n if (seg.type === \"completed\") {\n const isNew = seg.param.id === newParamId;\n if (isNew) {\n span.className = \"magicx-aia-shimmer-revealed magicx-aia-shimmer-sweep\";\n } else {\n span.className = \"magicx-aia-segment magicx-aia-segment--completed\";\n }\n }\n span.textContent = seg.value;\n sizerText.appendChild(span);\n }\n\n if (segments.length === 0) {\n sizerText.textContent = \"\\u00A0\";\n }\n}\n","import type { AutocompleteResult } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\nimport { renderPills } from \"./renderPills\";\nimport { renderSegments } from \"./renderSegments\";\n\ninterface RenderInputOptions {\n store: Store<CoreState>;\n listboxId: string;\n pillPlacement: \"inline\" | \"dropdown\" | \"hidden\";\n autoFocus?: boolean;\n onSubmit?: (result: AutocompleteResult) => void;\n submitButton?: HTMLElement | null;\n selectOption: (option: import(\"../../types\").SuggestionOption) => void;\n setActivePill: (index: number) => void;\n handleKeyDown: (e: KeyboardEvent) => void;\n handleChange: (value: string) => void;\n}\n\nexport interface DOMRefs {\n textarea: HTMLTextAreaElement;\n dropdown: HTMLElement;\n sizer: HTMLElement;\n /** The default built-in button when no `submitButton` was provided. Null when consumer passed `null` or a custom element. */\n submitButton: HTMLButtonElement | null;\n inlinePillContainer: HTMLElement;\n}\n\nconst SUBMIT_SVG = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\"><path d=\"M9 14V4M9 4L4 9M9 4L14 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nexport function buildDOM(container: HTMLElement, opts: RenderInputOptions): DOMRefs {\n const { listboxId } = opts;\n\n // Dropdown\n const dropdown = createDropdown(listboxId);\n container.appendChild(dropdown);\n\n // Input wrapper\n const inputWrapper = document.createElement(\"div\");\n inputWrapper.className = \"magicx-aia-input-wrapper\";\n container.appendChild(inputWrapper);\n\n // Editor area\n const editor = document.createElement(\"div\");\n editor.className = \"magicx-aia-editor\";\n editor.setAttribute(\"data-aia-editor\", \"\");\n inputWrapper.appendChild(editor);\n\n // Sizer (overlay)\n const sizer = document.createElement(\"div\");\n sizer.className = \"magicx-aia-sizer\";\n sizer.setAttribute(\"aria-hidden\", \"true\");\n editor.appendChild(sizer);\n\n // Inline pill container (inside sizer, after segments)\n const inlinePillContainer = document.createElement(\"span\");\n sizer.appendChild(document.createTextNode(\" \"));\n sizer.appendChild(inlinePillContainer);\n\n // Textarea\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"magicx-aia-textarea\";\n textarea.rows = 1;\n textarea.setAttribute(\"role\", \"combobox\");\n textarea.setAttribute(\"aria-autocomplete\", \"list\");\n textarea.setAttribute(\"aria-controls\", listboxId);\n textarea.setAttribute(\"data-aia-textarea\", \"\");\n editor.appendChild(textarea);\n\n // Submit button — null means render nothing; undefined means default; HTMLElement means custom\n let submitButton: HTMLButtonElement | null = null;\n let submitTarget: HTMLElement | null = null;\n if (opts.submitButton === undefined) {\n submitButton = document.createElement(\"button\");\n submitButton.type = \"button\";\n submitButton.className = \"magicx-aia-submit\";\n submitButton.setAttribute(\"aria-label\", \"Submit\");\n submitButton.setAttribute(\"data-aia-submit\", \"\");\n submitButton.innerHTML = SUBMIT_SVG;\n inputWrapper.appendChild(submitButton);\n submitTarget = submitButton;\n } else if (opts.submitButton !== null) {\n submitTarget = opts.submitButton;\n if (!submitTarget.hasAttribute(\"data-aia-submit\")) {\n submitTarget.setAttribute(\"data-aia-submit\", \"\");\n }\n inputWrapper.appendChild(submitTarget);\n }\n\n // --- Event wiring ---\n\n // Click wrapper → focus textarea\n inputWrapper.addEventListener(\"click\", () => textarea.focus());\n\n // Textarea change\n textarea.addEventListener(\"input\", () => {\n const raw = textarea.value;\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n opts.handleChange(newValue);\n });\n\n // Keyboard\n textarea.addEventListener(\"keydown\", (e) => opts.handleKeyDown(e));\n\n // Focus tracking — auto-trigger uses this to open dropdown when focused\n textarea.addEventListener(\"focus\", () => opts.store.set({ isFocused: true }));\n textarea.addEventListener(\"blur\", () => opts.store.set({ isFocused: false }));\n\n // Submit click — wired on whatever element fills the slot (default or custom)\n if (submitTarget) {\n submitTarget.addEventListener(\"click\", (e) => {\n const state = opts.store.get();\n const canSubmit = !!state.text || state.completedParams.length > 0;\n if (!canSubmit || !opts.onSubmit) return;\n e.stopPropagation();\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n opts.onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n });\n }\n\n // Focus textarea on mount\n if (opts.autoFocus !== false) {\n textarea.focus();\n }\n\n return { textarea, dropdown, sizer, submitButton, inlinePillContainer };\n}\n\nexport function updateDOM(refs: DOMRefs, state: CoreState, opts: RenderInputOptions) {\n const { textarea, dropdown, sizer, submitButton, inlinePillContainer } = refs;\n const { pillPlacement, setActivePill, selectOption, store } = opts;\n\n // Textarea value\n if (textarea.value !== state.text) {\n textarea.value = state.text;\n }\n\n // Placeholder\n if (state.placeholderText) {\n textarea.placeholder = state.placeholderText;\n } else {\n textarea.removeAttribute(\"placeholder\");\n }\n\n // ARIA\n textarea.setAttribute(\"aria-expanded\", String(state.isDropdownOpen));\n const activeDescendant =\n state.activeDropdownIndex >= 0 ? `${opts.listboxId}-option-${state.activeDropdownIndex}` : \"\";\n if (activeDescendant) {\n textarea.setAttribute(\"aria-activedescendant\", activeDescendant);\n } else {\n textarea.removeAttribute(\"aria-activedescendant\");\n }\n\n // Shimmer: hide textarea text during animation\n if (state.newParamId) {\n textarea.classList.add(\"magicx-aia-textarea--hidden\");\n } else {\n textarea.classList.remove(\"magicx-aia-textarea--hidden\");\n }\n\n // Submit button disabled state — only applies to the default built-in button.\n // Consumer-provided buttons own their own disabled visuals.\n if (submitButton) {\n const canSubmit = !!state.text || state.completedParams.length > 0;\n submitButton.disabled = !canSubmit;\n }\n\n // Segments overlay\n renderSegments(sizer, state.segments, state.newParamId, !state.text, state.placeholderText);\n\n // Inline pills\n if (pillPlacement === \"inline\") {\n renderPills(inlinePillContainer, state.actionableSuggestions, 0, setActivePill);\n } else {\n // Clear inline pills in dropdown mode\n inlinePillContainer.innerHTML = \"\";\n }\n\n // Dropdown\n renderDropdown(dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: pillPlacement === \"dropdown\",\n onSelect: selectOption,\n onHighlight: (i) => store.set({ activeDropdownIndex: i }),\n onPillClick: setActivePill,\n });\n}\n","export type Listener<S> = (next: S, prev: S) => void;\n\nexport interface Store<S> {\n get: () => S;\n set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;\n subscribe: (listener: Listener<S>) => () => void;\n}\n\nexport function createStore<S>(initial: S): Store<S> {\n let state = initial;\n const listeners = new Set<Listener<S>>();\n return {\n get: () => state,\n set: (patch) => {\n const resolved = typeof patch === \"function\" ? patch(state) : patch;\n const next = { ...state, ...resolved };\n const prev = state;\n state = next;\n for (const l of listeners) l(next, prev);\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n","let injected = false;\n\n/** Inject core + appearance CSS into document.head once. Idempotent. */\nexport function injectStyles() {\n if (injected || typeof document === \"undefined\") return;\n if (document.querySelector(\"style[data-magicx-aia]\")) {\n injected = true;\n return;\n }\n injected = true;\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-magicx-aia\", \"\");\n style.textContent = STYLES;\n document.head.appendChild(style);\n}\n\n// Replaced at build time by tsup.config.core.ts / vitest.config.ts\ndeclare const __MAGICX_AC_STYLES__: string;\nconst STYLES = __MAGICX_AC_STYLES__;\n","import type { AppearanceMode, CompletedParamState, Suggestion, SuggestionOption } from \"../types\";\nimport { extractFilterQuery, filterOptions, findPrefixOverlap } from \"../utils/filtering\";\nimport { ModeController } from \"../utils/modeController\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { FetchController } from \"./controllers/fetchController\";\nimport { KeyboardController } from \"./controllers/keyboardController\";\nimport { PillsController } from \"./controllers/pillsController\";\nimport { buildDropdownOnly, updateDropdownOnly } from \"./render/renderDropdownOnly\";\nimport { buildDOM, type DOMRefs, updateDOM } from \"./render/renderInput\";\nimport { createStore } from \"./state\";\nimport { injectStyles } from \"./styleInjector\";\nimport type { CoreOptions, CoreState, RenderMode } from \"./types\";\n\nlet idCounter = 0;\nfunction stableId(): string {\n return `:ac-${++idCounter}:`;\n}\n\nfunction initialState(): CoreState {\n return {\n text: \"\",\n completedParams: [],\n suggestions: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: false,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n placeholderText: \"\",\n isDropdownOpen: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n };\n}\n\nexport class AIAutocomplete {\n private store = createStore<CoreState>(initialState());\n private _listboxId = stableId();\n private opts: CoreOptions;\n private fetchController: FetchController;\n private keyboardController: KeyboardController;\n private pillsController: PillsController;\n private modeController: ModeController | null = null;\n private container: HTMLElement;\n private unsubscribers: (() => void)[] = [];\n private derivedInProgress = false;\n private renderMode: RenderMode;\n private domRefs: DOMRefs | null = null;\n private dropdownRefs: { dropdown: HTMLElement } | null = null;\n private newParamTimer: number | undefined;\n private suggestionRemovalTimer: number | undefined;\n private externalListeners = new Set<(state: CoreState) => void>();\n private sessionId: string = crypto.randomUUID();\n\n constructor(container: HTMLElement, opts: CoreOptions = {}) {\n this.container = container;\n this.opts = opts;\n this.renderMode = opts.renderMode ?? \"full\";\n\n // Apply controlled initial values\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n\n // Controllers\n this.pillsController = new PillsController(this.store);\n\n this.fetchController = new FetchController(\n this.store,\n () => this.opts.apiConfig,\n () => this.opts.optionOverrides,\n () => this.opts.maskCompletedText,\n () => this.opts.onError,\n () => this.sessionId,\n );\n\n this.keyboardController = new KeyboardController(this.store, {\n columns: opts.columns ?? 2,\n listboxId: this.listboxId,\n getOnSubmit: () => this.opts.onSubmit,\n selectOption: (option) => this.selectOption(option),\n });\n\n // Derived state recomputation\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n this.recomputeDerived(next, prev);\n }),\n );\n\n // Event callbacks\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.text !== prev.text) this.opts.onChange?.(next.text);\n if (next.completedParams !== prev.completedParams)\n this.opts.onParamsChange?.(next.completedParams);\n if (next.isFocused !== prev.isFocused) {\n if (next.isFocused) this.opts.onFocus?.();\n else this.opts.onBlur?.();\n }\n this.opts.onStateChange?.(next);\n }),\n );\n\n // Setup DOM based on render mode\n if (this.renderMode !== \"headless\") {\n injectStyles();\n this.setupContainer();\n }\n if (this.renderMode === \"full\") {\n this.buildAndRenderFull();\n } else if (this.renderMode === \"dropdown\") {\n this.buildAndRenderDropdown();\n }\n this.fetchController.start();\n }\n\n // === Public API ===\n\n focus() {\n this.domRefs?.textarea.focus();\n }\n\n blur() {\n this.domRefs?.textarea.blur();\n }\n\n reset() {\n // skipNextFetch suppresses the debounced fetch the FetchController would\n // otherwise schedule in response to text/params changing here — we issue\n // the empty fetch ourselves below so the new session starts immediately.\n this.store.set({\n ...initialState(),\n skipNextFetch: true,\n });\n this.sessionId = crypto.randomUUID();\n this.fetchController.doFetch(\"\", []);\n }\n\n destroy() {\n this.fetchController.dispose();\n this.modeController?.destroy();\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n if (this.suggestionRemovalTimer) clearTimeout(this.suggestionRemovalTimer);\n this.externalListeners.clear();\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n this.domRefs = null;\n this.dropdownRefs = null;\n if (this.renderMode !== \"headless\") {\n this.container.innerHTML = \"\";\n }\n }\n\n setMode(mode: AppearanceMode) {\n this.modeController?.setMode(mode);\n }\n\n setValue(text: string) {\n this.store.set({ text });\n }\n\n setCompletedParams(params: CompletedParamState[]) {\n this.store.set({ completedParams: params });\n }\n\n setActivePill(index: number) {\n this.pillsController.setActivePill(index);\n }\n\n removeLastParam() {\n this.pillsController.removeLastParam();\n }\n\n clearNewParamId() {\n this.store.set({ newParamId: null });\n }\n\n setActiveDropdownIndex(index: number) {\n this.store.set({ activeDropdownIndex: index });\n }\n\n handleTextChange(value: string) {\n this.handleChange(value);\n }\n\n handleKeyDown(e: KeyboardEvent) {\n this.keyboardController.handleKeyDown(e);\n }\n\n setFocused(focused: boolean) {\n if (this.store.get().isFocused === focused) return;\n this.store.set({ isFocused: focused });\n }\n\n /** Subscribe to state changes (fires after derived state is settled). Returns unsubscribe function. */\n subscribe(listener: (state: CoreState) => void): () => void {\n this.externalListeners.add(listener);\n return () => {\n this.externalListeners.delete(listener);\n };\n }\n\n getState(): CoreState {\n return this.store.get();\n }\n\n get listboxId(): string {\n return this._listboxId;\n }\n\n get isReady(): boolean {\n return this.store.get().isReady;\n }\n\n on(event: string, callback: (...args: unknown[]) => void): () => void {\n switch (event) {\n case \"submit\":\n this.opts.onSubmit = callback as CoreOptions[\"onSubmit\"];\n return () => {\n this.opts.onSubmit = undefined;\n };\n case \"error\":\n this.opts.onError = callback as CoreOptions[\"onError\"];\n return () => {\n this.opts.onError = undefined;\n };\n case \"change\":\n this.opts.onChange = callback as CoreOptions[\"onChange\"];\n return () => {\n this.opts.onChange = undefined;\n };\n case \"paramsChange\":\n this.opts.onParamsChange = callback as CoreOptions[\"onParamsChange\"];\n return () => {\n this.opts.onParamsChange = undefined;\n };\n case \"stateChange\":\n this.opts.onStateChange = callback as CoreOptions[\"onStateChange\"];\n return () => {\n this.opts.onStateChange = undefined;\n };\n case \"focus\":\n this.opts.onFocus = callback as CoreOptions[\"onFocus\"];\n return () => {\n this.opts.onFocus = undefined;\n };\n case \"blur\":\n this.opts.onBlur = callback as CoreOptions[\"onBlur\"];\n return () => {\n this.opts.onBlur = undefined;\n };\n default:\n return () => {};\n }\n }\n\n update(opts: Partial<CoreOptions>) {\n Object.assign(this.opts, opts);\n if (opts.mode !== undefined) {\n this.modeController?.setMode(opts.mode);\n }\n if (opts.optionsPosition !== undefined) {\n this.container.dataset.optionsPosition = opts.optionsPosition;\n }\n if (opts.animations !== undefined) {\n this.container.dataset.animations = opts.animations ? \"on\" : \"off\";\n }\n if (opts.pillPlacement !== undefined) {\n this.container.dataset.pillPlacement = opts.pillPlacement;\n this.store.set({});\n }\n if (opts.dropdownTrigger !== undefined || opts.closeDropdownOnBlur !== undefined) {\n // Trigger recompute so isDropdownOpen updates\n this.store.set({});\n }\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n }\n\n // === Public (for framework wrappers) ===\n\n selectOption(option: SuggestionOption) {\n const state = this.store.get();\n const activeSuggestion = state.actionableSuggestions[0];\n if (!activeSuggestion) return;\n\n const base = state.filterBase;\n let prefix = state.text.slice(0, base);\n\n const inputWasEmpty = prefix.length === 0 && state.text.length === 0;\n // The user is still typing within the server-provided placeholder (e.g. typed\n // \"Cre\" for placeholder \"Create a\"). Selecting an option here should keep the\n // placeholder rather than discard it — otherwise tapping \"email\" replaces\n // \"Cre\" with just \"email\" instead of \"Create a email\".\n const inputIsPlaceholderPrefix =\n prefix.length === 0 &&\n state.text.length > 0 &&\n state.placeholderText.length > 0 &&\n state.placeholderText.toLowerCase().startsWith(state.text.toLowerCase());\n if ((inputWasEmpty || inputIsPlaceholderPrefix) && state.placeholderText) {\n prefix = `${state.placeholderText} `;\n }\n\n const overlapChars = findPrefixOverlap(prefix, option.text);\n if (overlapChars > 0) {\n prefix = prefix.slice(0, prefix.length - overlapChars);\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = `${prefix}${needsSpace ? \" \" : \"\"}${option.text} `;\n const finalText =\n (inputWasEmpty || inputIsPlaceholderPrefix) && newText.length > 0\n ? newText[0].toUpperCase() + newText.slice(1)\n : newText;\n\n const optionStart = finalText.toLowerCase().lastIndexOf(option.text.toLowerCase());\n const optionInFinal =\n optionStart >= 0\n ? finalText.slice(optionStart, optionStart + option.text.length)\n : option.text;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: optionInFinal,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options ?? [],\n metadata: option.metadata,\n };\n\n const remainingActionable = state.actionableSuggestions.length - 1;\n\n this.store.set((s) => ({\n text: finalText,\n filterBase: finalText.length,\n completedParams: [...s.completedParams, completed],\n newParamId: completed.id,\n pillTapped: false,\n activeDropdownIndex: -1,\n skipNextFetch: remainingActionable > 0,\n }));\n\n // Delay suggestion removal for animation\n this.suggestionRemovalTimer = window.setTimeout(() => {\n this.store.set((s) => ({\n suggestions: s.suggestions.filter((sg) => sg !== activeSuggestion),\n }));\n }, 400);\n }\n\n private recomputeDerived(next: CoreState, _prev: CoreState) {\n if (this.derivedInProgress) return;\n this.derivedInProgress = true;\n const segments = deriveSegments(next.text, next.completedParams);\n const actionableSuggestions = next.suggestions.filter((s) => s.type !== \"placeholder\");\n const activeSuggestion = actionableSuggestions[0] as Suggestion | undefined;\n const overrideFn = activeSuggestion\n ? this.opts.optionOverrides?.[activeSuggestion.type]\n : undefined;\n\n // Clamp filterBase so it never exceeds text length (matches old React behavior)\n const clampedFilterBase = Math.min(next.filterBase, next.text.length);\n // When filterBase is 0 and no fetch has set it yet, don't filter by typed text —\n // the user is still typing the initial query and no server context exists\n const hasServerContext = next.lastRawQuery !== \"\" || clampedFilterBase > 0;\n const filterQuery = hasServerContext\n ? extractFilterQuery(next.text, clampedFilterBase, next.filterInProgress)\n : \"\";\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = filterOptions(baseOptions, filterQuery);\n\n const placeholderText = next.suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n\n const trigger = this.opts.dropdownTrigger ?? \"auto\";\n const closeOnBlur = this.opts.closeDropdownOnBlur ?? true;\n let isDropdownOpen = false;\n if (trigger === \"auto\") {\n const focusGate = closeOnBlur ? next.isFocused : true;\n isDropdownOpen = !next.isLoading && filteredOptions.length > 0 && focusGate;\n } else if (trigger === \"manual\") {\n isDropdownOpen = !next.isLoading && filteredOptions.length > 0 && next.pillTapped;\n }\n\n this.store.set({\n segments,\n actionableSuggestions,\n filteredOptions,\n placeholderText,\n isDropdownOpen,\n });\n this.derivedInProgress = false;\n\n // Notify external listeners after derived state is settled\n const settled = this.store.get();\n for (const listener of this.externalListeners) {\n listener(settled);\n }\n }\n\n private setupContainer() {\n this.container.classList.add(\"magicx-aia\");\n // In dropdown mode, pills are always in the dropdown\n this.container.dataset.pillPlacement =\n this.renderMode === \"dropdown\" ? \"dropdown\" : (this.opts.pillPlacement ?? \"inline\");\n this.container.dataset.optionsPosition = this.opts.optionsPosition ?? \"below\";\n this.container.dataset.animations = (this.opts.animations ?? true) ? \"on\" : \"off\";\n\n // ModeController\n this.modeController = new ModeController(this.container, this.opts.mode ?? \"auto\");\n }\n\n private buildAndRenderFull() {\n const self = this;\n const renderOpts = {\n store: this.store,\n listboxId: this.listboxId,\n get pillPlacement() {\n return (self.opts.pillPlacement ?? \"inline\") as \"inline\" | \"dropdown\";\n },\n get onSubmit() {\n return self.opts.onSubmit;\n },\n submitButton: this.opts.submitButton,\n autoFocus: this.opts.autoFocus ?? true,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n handleKeyDown: (e: KeyboardEvent) => this.keyboardController.handleKeyDown(e),\n handleChange: (value: string) => this.handleChange(value),\n };\n\n this.domRefs = buildDOM(this.container, renderOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.domRefs) {\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n }\n });\n\n // Initial render\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n this.subscribeNewParamTimer();\n }\n\n private buildAndRenderDropdown() {\n const dropdownOpts = {\n store: this.store,\n listboxId: this.listboxId,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n };\n\n this.dropdownRefs = buildDropdownOnly(this.container, dropdownOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.dropdownRefs) {\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n }\n });\n\n // Initial render\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n this.subscribeNewParamTimer();\n }\n\n /** Batched render subscriber — coalesces multiple store.set calls into one DOM update. */\n private subscribeBatchedRender(render: () => void) {\n let scheduled = false;\n this.unsubscribers.push(\n this.store.subscribe(() => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n render();\n });\n }),\n );\n }\n\n /** Auto-clear newParamId after shimmer animation. */\n private subscribeNewParamTimer() {\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.newParamId && next.newParamId !== prev.newParamId) {\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n this.newParamTimer = window.setTimeout(() => {\n this.store.set({ newParamId: null });\n }, 650);\n }\n }),\n );\n }\n\n private handleChange(newValue: string) {\n const state = this.store.get();\n this.store.set({\n text: newValue,\n pillTapped: false,\n activeDropdownIndex: -1,\n });\n\n const { valid, invalid } = reconcileParams(newValue, state.completedParams);\n if (invalid.length > 0) {\n this.store.set((s) => ({\n completedParams: valid,\n suggestions: [\n ...invalid.map((param) => ({\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n })),\n ...s.suggestions,\n ],\n }));\n }\n }\n}\n"],"mappings":"ibAAA,IAAAA,GAAA,GAAAC,GAAAD,GAAA,oBAAAE,EAAA,gBAAAC,IAAA,eAAAC,GAAAJ,ICQO,SAASK,EACdC,EACAC,EACAC,EACQ,CACR,IAAMC,EAAYH,EAAK,MAAMC,CAAU,EACvC,GAAIC,GAAgBD,IAAe,GAAKD,EAAKC,EAAa,CAAC,IAAM,IAC/D,OAAOE,EAET,IAAMC,EAAWD,EAAU,QAAQ,GAAG,EACtC,OAAOC,IAAa,GAAK,GAAKD,EAAU,MAAMC,EAAW,CAAC,CAC5D,CAOO,SAASC,EAAkBC,EAAgBC,EAA4B,CAE5E,IAAMC,EAAUF,EAAO,QAAQ,EAAE,QAAQ,OAAQ,GAAG,EACpD,GAAIE,EAAQ,SAAW,GAAKD,EAAW,SAAW,EAAG,MAAO,GAE5D,IAAME,EAAQD,EAAQ,MAAM,GAAG,EACzBE,EAAcH,EAAW,YAAY,EAG3C,QAASI,EAAI,EAAGA,EAAIF,EAAM,OAAQE,IAAK,CACrC,IAAMC,EAAYH,EAAM,MAAME,CAAC,EAAE,KAAK,GAAG,EACzC,GAAID,EAAY,WAAWE,EAAU,YAAY,CAAC,EAAG,CACnD,IAAMC,EAAcL,EAAQ,OAASI,EAAU,OAC/C,OAAON,EAAO,OAASO,CACzB,CACF,CAEA,MAAO,EACT,CAKO,SAASC,EACdC,EACAC,EACoB,CACpB,GAAI,CAACD,EAAS,MAAO,CAAC,EACtB,IAAMP,EAAUQ,EAAM,UAAU,EAChC,GAAI,CAACR,EAAS,OAAOO,EACrB,IAAME,EAAQT,EAAQ,YAAY,EAClC,OAAOO,EAAQ,OAAQG,GAAM,CAACA,EAAE,aAAeA,EAAE,KAAK,YAAY,EAAE,SAASD,CAAK,CAAC,CACrF,CAKO,SAASE,EACdJ,EACAC,EACyB,CACzB,GAAI,CAACD,EAAS,OAAO,KACrB,IAAMP,EAAUQ,EAAM,KAAK,EAC3B,GAAI,CAACR,EAAS,OAAO,KACrB,IAAMS,EAAQT,EAAQ,YAAY,EAClC,OAAOO,EAAQ,KAAMG,GAAMA,EAAE,aAAeA,EAAE,KAAK,YAAY,IAAMD,CAAK,GAAK,IACjF,CCtEO,IAAMG,EAAN,KAAqB,CAG1B,YACUC,EACAC,EAAuB,OAC/B,CAFQ,eAAAD,EACA,UAAAC,EAJV,KAAQ,WAAoC,KA6B5C,KAAQ,eAAkB,GAA2B,CACnD,KAAK,UAAU,QAAQ,KAAO,EAAE,QAAU,OAAS,OACrD,EAzBE,KAAK,MAAM,CACb,CAEA,QAAQA,EAAsB,CAC5B,KAAK,eAAe,EACpB,KAAK,KAAOA,EACZ,KAAK,MAAM,CACb,CAEA,SAAU,CACR,KAAK,eAAe,CACtB,CAEQ,OAAQ,CACV,KAAK,OAAS,QAChB,KAAK,aAAL,KAAK,WAAe,OAAO,WAAW,8BAA8B,GACpE,KAAK,WAAW,iBAAiB,SAAU,KAAK,cAAc,EAC9D,KAAK,UAAU,QAAQ,KAAO,KAAK,WAAW,QAAU,OAAS,SAEjE,KAAK,UAAU,QAAQ,KAAO,KAAK,IAEvC,CAMQ,gBAAiB,CACvB,KAAK,YAAY,oBAAoB,SAAU,KAAK,cAAc,CACpE,CACF,EClCO,SAASC,EAAeC,EAAcC,EAAmD,CAC9F,IAAMC,EAAoB,CAAC,EACvBC,EAAM,EAEV,QAAWC,KAASH,EAAiB,CACnC,IAAMI,EAAML,EAAK,QAAQI,EAAM,KAAMD,CAAG,EACpCE,IAAQ,KACRA,EAAMF,GACRD,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOF,EAAK,MAAMG,EAAKE,CAAG,CAAE,CAAC,EAE3DH,EAAO,KAAK,CAAE,KAAM,YAAa,MAAOE,EAAM,KAAM,MAAAA,CAAM,CAAC,EAC3DD,EAAME,EAAMD,EAAM,KAAK,OACzB,CAEA,IAAME,EAAYN,EAAK,MAAMG,CAAG,EAChC,OAAIG,GACFJ,EAAO,KAAK,CAAE,KAAM,OAAQ,MAAOI,CAAU,CAAC,EAGzCJ,CACT,CAKO,SAASK,EACdP,EACAC,EACkE,CAClE,IAAMO,EAA+B,CAAC,EAChCC,EAAiC,CAAC,EACpCN,EAAM,EAEV,QAAWC,KAASH,EAAiB,CACnC,IAAMI,EAAML,EAAK,QAAQI,EAAM,KAAMD,CAAG,EACpCE,IAAQ,GACVI,EAAQ,KAAKL,CAAK,GAElBI,EAAM,KAAKJ,CAAK,EAChBD,EAAME,EAAMD,EAAM,KAAK,OAE3B,CAEA,MAAO,CAAE,MAAAI,EAAO,QAAAC,CAAQ,CAC1B,CC5CO,IAAMC,EAAN,KAAmB,CAKxB,YAAoBC,EAA2B,CAA3B,YAAAA,EAJpB,KAAQ,QAAyB,KACjC,KAAQ,UAA2B,KACnC,KAAQ,gBAA0C,KAG5CA,EAAO,cACT,KAAK,QAAUA,EAAO,YAE1B,CAGA,MAAM,SAASC,EAAe,GAAwB,CACpD,GAAI,CAACA,GAAgB,KAAK,SAAW,CAAC,KAAK,UAAU,EACnD,OAAO,KAAK,QAEd,GAAI,CAACA,GAAgB,KAAK,gBACxB,OAAO,KAAK,gBAEd,KAAK,gBAAkB,KAAK,QAAQ,EACpC,GAAI,CACF,OAAO,MAAM,KAAK,eACpB,QAAE,CACA,KAAK,gBAAkB,IACzB,CACF,CAEA,MAAc,SAA2B,CACvC,IAAMC,EAAS,MAAM,KAAK,OAAO,eAAe,EAChD,YAAK,QAAUA,EAAO,YACtB,KAAK,UAAYA,EAAO,WAAa,KAC9B,KAAK,OACd,CAEQ,WAAqB,CAC3B,OAAI,KAAK,WAAa,KAAa,GAC5B,KAAK,IAAI,GAAK,KAAK,UAAY,GACxC,CACF,EC9BA,IAAMC,GAAc,SAEhBC,EAAsB,GAE1B,SAASC,IAA4B,CACnC,OAAO,OAAO,WAAW,CAC3B,CAEA,SAASC,GAAYC,EAA4BC,EAAsC,CACrF,MAAO,CACL,YAAaD,EAAM,YACnB,KAAMA,EAAM,KACZ,GAAIC,GAAe,CAAE,KAAMD,EAAM,IAAK,EACtC,KAAMA,EAAM,IACd,CACF,CAEA,SAASE,EAAoBC,EAAiD,CAC5E,OAAOA,GAAQ,OAAS,aAC1B,CAEA,SAASC,GAAgBD,EAA8C,CACrE,GAAI,GAACA,GAAUD,EAAoBC,CAAM,GACzC,OAAOA,CACT,CAGA,IAAME,EAAgB,IAAI,QAE1B,SAASC,GAAgBH,EAAyC,CAChE,IAAII,EAAUF,EAAc,IAAIF,EAAO,cAAc,EACrD,OAAKI,IACHA,EAAU,IAAIC,EAAaL,CAAM,EACjCE,EAAc,IAAIF,EAAO,eAAgBI,CAAO,GAE3CA,CACT,CAEA,SAASE,GACPC,EACAC,EACAV,EACAW,EACqB,CACrB,IAAMC,EAAWF,EAAgB,KAC9BG,GAAMA,EAAE,OAAS,WAAaA,EAAE,UAAU,qBAC7C,GAAG,UAAU,sBACPC,EAAsB,OAAOF,GAAa,SAAWA,EAAW,OAEtE,MAAO,CACL,KAAM,CACJ,UAAWH,EACX,iBAAkBC,EAAgB,IAAKG,GAAMf,GAAYe,EAAGb,CAAW,CAAC,EACxE,GAAIc,GAAuB,MAAQ,CAAE,sBAAuBA,CAAoB,CAClF,EACA,KAAM,CACJ,WAAYjB,GAAkB,EAC9B,WAAY,IAAI,KAAK,EAAE,YAAY,EACnC,SAAU,OAAO,UAAc,IAAc,UAAU,SAAW,QAClE,eAAgBF,GAChB,WAAYgB,CACd,CACF,CACF,CAEA,SAASI,GAAaC,EAA+C,CACnE,MAAO,CACL,eAAgB,mBAChB,GAAIA,GAAW,eAAiB,CAAE,mBAAoBA,EAAU,aAAc,EAC9E,GAAGA,GAAW,OAChB,CACF,CAEA,eAAeC,EACbC,EACAC,EACAC,EACAC,EACAC,EACmB,CACnB,OAAO,MAAMJ,EAAU,CACrB,OAAQ,OACR,QAAS,CAAE,GAAGC,EAAS,cAAe,UAAUC,CAAK,EAAG,EACxD,KAAAC,EACA,OAAAC,CACF,CAAC,CACH,CAEA,eAAsBC,EACpBd,EACAC,EACAc,EAM+B,CAC/B,IAAMR,EAAYQ,EAAQ,UACpBxB,EAAc,CAACwB,EAAQ,kBACvBH,EAAOb,GAAiBC,EAAUC,EAAiBV,EAAawB,EAAQ,SAAS,EACjFL,EAAUJ,GAAaC,CAAS,EAChCE,EAAWF,GAAW,UAAY,8CAClCS,EAAW,KAAK,UAAUJ,CAAI,EAGpC,GAAIpB,EAAoBe,CAAS,EAAG,CAClC,IAAMV,EAAUD,GAAgBW,CAAS,EACnCI,EAAQ,MAAMd,EAAQ,SAAS,EAEjCoB,EAAW,MAAMT,EAAQC,EAAUC,EAASC,EAAOK,EAAUD,EAAQ,MAAM,EAG/E,GAAIE,EAAS,SAAW,IAAK,CAC3B,IAAMC,EAAW,MAAMrB,EAAQ,SAAS,EAAI,EAC5CoB,EAAW,MAAMT,EAAQC,EAAUC,EAASQ,EAAUF,EAAUD,EAAQ,MAAM,CAChF,CAEA,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MAAM,cAAcA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAGxE,OAAOA,EAAS,KAAK,CACvB,CAGA,IAAME,EAAezB,GAAgBa,CAAS,EACxCa,EAASD,GAAc,QAAU,GAUvC,GARI,CAACC,GAAU,CAACjC,IACdA,EAAsB,GAEtB,QAAQ,KACN,iGACF,GAGEiC,EAAQ,CACV,IAAMC,EAAaF,GAAc,YAAc,SAC/CT,EAAQ,cAAgBW,IAAe,QAAU,SAAS,KAAKD,CAAM,CAAC,GAAK,UAAUA,CAAM,EAC7F,CAEA,IAAMH,EAAW,MAAM,MAAMR,EAAU,CACrC,OAAQ,OACR,QAAAC,EACA,KAAMM,EACN,OAAQD,EAAQ,MAClB,CAAC,EAED,GAAI,CAACE,EAAS,GACZ,MAAM,IAAI,MAAM,cAAcA,EAAS,MAAM,IAAIA,EAAS,UAAU,EAAE,EAGxE,OAAOA,EAAS,KAAK,CACvB,CCxJO,SAASK,EAAWC,EAAcC,EAA0D,CACjG,IAAIC,EAASF,EACPG,EAAqC,CAAC,EACtCC,EAAuC,CAAC,EAE9C,QAAWC,KAASJ,EAAiB,CACnC,IAAMK,GAASH,EAAWE,EAAM,IAAI,GAAK,GAAK,EAC9CF,EAAWE,EAAM,IAAI,EAAIC,EAGzB,IAAMC,EAAc,KADJF,EAAM,KAAK,YAAY,EAAE,QAAQ,OAAQ,GAAG,CAC5B,IAAIC,CAAK,KAGnCE,EAAQN,EAAO,QAAQG,EAAM,IAAI,EACnCG,IAAU,KACZN,EAASA,EAAO,MAAM,EAAGM,CAAK,EAAID,EAAcL,EAAO,MAAMM,EAAQH,EAAM,KAAK,MAAM,GAGxFD,EAAc,KAAK,CAAE,GAAGC,EAAO,YAAAE,CAAY,CAAC,CAC9C,CAEA,MAAO,CAAE,SAAUL,EAAQ,gBAAiBE,CAAc,CAC5D,CC/BO,SAASK,EACdC,EACAC,EACc,CACd,OAAKA,EACED,EAAY,IAAKE,GAAM,CAC5B,IAAMC,EAAKF,EAAUC,EAAE,IAAI,EAC3B,GAAI,CAACC,EAAI,OAAOD,EAChB,IAAME,EAAQD,EAAG,EAAE,EACnB,GAAIC,EAAM,SAAW,EAAG,OAAOF,EAC/B,IAAMG,EAAgB,IAAI,IAAID,EAAM,IAAKE,GAAMA,EAAE,IAAI,CAAC,EAChDC,GAAWL,EAAE,SAAW,CAAC,GAAG,OAAQI,GAAM,CAACD,EAAc,IAAIC,EAAE,IAAI,CAAC,EAC1E,MAAO,CAAE,GAAGJ,EAAG,QAAS,CAAC,GAAGE,EAAO,GAAGG,CAAO,CAAE,CACjD,CAAC,EATsBP,CAUzB,CCNA,IAAMQ,GAAc,IACdC,GAAmB,IACnBC,GAAiB,EAEVC,EAAN,KAAsB,CAO3B,YACUC,EACAC,EACAC,EACAC,EACAC,EACAC,EACR,CANQ,WAAAL,EACA,kBAAAC,EACA,wBAAAC,EACA,0BAAAC,EACA,gBAAAC,EACA,kBAAAC,EAZV,KAAQ,aAAe,EACvB,KAAQ,gBAA0C,KAClD,KAAQ,cAAsD,KAC9D,KAAQ,kBAA0D,KAClE,KAAQ,YAAmC,IASxC,CAEH,OAAQ,CAEN,KAAK,QAAQ,GAAI,CAAC,CAAC,EAGnB,IAAIC,EAAW,KAAK,MAAM,IAAI,EAAE,KAC5BC,EAAa,KAAK,MAAM,IAAI,EAAE,gBAClC,KAAK,YAAc,KAAK,MAAM,UAAWC,GAAS,EAC5CA,EAAK,OAASF,GAAYE,EAAK,kBAAoBD,KACrDD,EAAWE,EAAK,KAChBD,EAAaC,EAAK,gBAClB,KAAK,cAAc,EAEvB,CAAC,CACH,CAEA,SAAU,CACR,KAAK,iBAAiB,MAAM,EAC5B,KAAK,YAAY,EACjB,KAAK,cAAc,CACrB,CAEA,MAAM,QAAQC,EAAkBC,EAAkC,CAChE,KAAK,iBAAiB,MAAM,EAC5B,IAAMC,EAAa,IAAI,gBACvB,KAAK,gBAAkBA,EACvB,IAAMC,EAAU,EAAE,KAAK,aACjBC,EAAQ,KAAK,MAAM,IAAI,EACvBC,EAAgBD,EAAM,KAAK,OAEVA,EAAM,YAAY,KAAME,GAAMA,EAAE,OAAS,aAAa,GACxD,KAAK,MAAM,IAAI,CAAE,UAAW,EAAK,CAAC,EACvD,KAAK,MAAM,IAAI,CAAE,MAAO,IAAK,CAAC,EAE9B,GAAI,CACF,IAAMC,EAAM,MAAMC,EAAiBR,EAAUC,EAAW,CACtD,UAAW,KAAK,aAAa,EAC7B,kBAAmB,KAAK,qBAAqB,EAC7C,OAAQC,EAAW,OACnB,UAAW,KAAK,aAAa,CAC/B,CAAC,EAED,GAAIC,IAAY,KAAK,aAAc,OAEnC,IAAIM,EAAiBC,EACnBH,EAAI,KAAK,aAAe,CAAC,EACzB,KAAK,mBAAmB,CAC1B,EAEMI,EAAQJ,EAAI,KAAK,OAAS,CAAC,EAC3BK,EAAYD,EAAMA,EAAM,OAAS,CAAC,EAClCE,EAAc,KAAK,MAAM,IAAI,EAAE,KACjCC,EACAC,EAEJ,GAAIH,GAAW,QAAU,cAAe,CACtCG,EAAmB,GACnB,IAAMC,EAAgBH,EAAY,YAAY,EAAE,YAAYD,EAAU,KAAK,YAAY,CAAC,EACxFE,EAAaE,IAAkB,GAAKA,EAAgBX,CACtD,MACEU,EAAmB,GACnBD,EAAaT,EAKf,IAAMY,EADaR,EAAe,OAAQH,GAAMA,EAAE,OAAS,aAAa,EAC9C,CAAC,EACvBY,EAAyC,KAC7C,GAAID,EAAQ,CACV,IAAME,EAAQC,EAAmBP,EAAaC,EAAYC,CAAgB,EACpEM,EAAQC,EAAeL,EAAO,QAASE,CAAK,EAC9CE,IACFH,EAAa,CACX,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMD,EAAO,KACb,KAAMI,EAAM,KACZ,KAAMA,EAAM,KACZ,eAAgBJ,EAAO,KACvB,sBAAuBA,EAAO,KAC9B,QAASA,EAAO,SAAW,CAAC,EAC5B,SAAUI,EAAM,QAClB,EACAZ,EAAiBA,EAAe,OAAQH,GAAMA,IAAMW,CAAM,EAE9D,CAEA,KAAK,MAAM,IAAKX,IAAO,CACrB,YAAaG,EACb,UAAW,GACX,QAASF,EAAI,KAAK,UAAY,GAC9B,aAAcP,EACd,oBAAqB,GACrB,WAAAc,EACA,iBAAAC,EACA,GAAIG,EAAa,CAAE,gBAAiB,CAAC,GAAGZ,EAAE,gBAAiBY,CAAU,CAAE,EAAI,CAAC,CAC9E,EAAE,CACJ,OAASK,EAAK,CACZ,GAAIpB,IAAY,KAAK,aAAc,CACjC,IAAMqB,EAAcD,aAAe,MAAQA,EAAM,IAAI,MAAM,OAAOA,CAAG,CAAC,EACtE,KAAK,MAAM,IAAI,CAAE,MAAOC,EAAa,UAAW,EAAM,CAAC,EACvD,KAAK,WAAW,IAAIA,CAAW,CACjC,CACF,CACF,CAEQ,eAAgB,CAItB,GAHA,KAAK,YAAY,EACH,KAAK,MAAM,IAAI,EAEnB,cAAe,CACvB,KAAK,MAAM,IAAI,CAAE,cAAe,EAAM,CAAC,EACvC,MACF,CAEA,IAAMC,EAAgBC,GAA6B,CACjD,IAAMpB,EAAI,KAAK,MAAM,IAAI,EACzB,GAAI,CAACA,EAAE,MAAQA,EAAE,gBAAgB,SAAW,EAC1C,YAAK,QAAQ,GAAI,CAAC,CAAC,EACZ,GAGT,IAAMqB,EAAeP,EAAmBd,EAAE,KAAMA,EAAE,WAAYA,EAAE,gBAAgB,EAE1EW,EADaX,EAAE,YAAY,OAAQsB,GAAmBA,EAAG,OAAS,aAAa,EAC3D,CAAC,EAErBC,GADkBZ,EAASa,EAAcb,EAAO,QAASU,CAAY,EAAI,CAAC,GACvC,OAAQI,GAAwBA,EAAE,WAAW,EAChFC,EAAgBf,EAASK,EAAeL,EAAO,QAASU,CAAY,IAAM,KAAO,GAEjFM,EAAiBN,EAAa,KAAK,EAAE,OAAS,EACpD,GAAIE,EAAiB,OAAS,GAAK,CAACG,GAAiBC,EAAgB,MAAO,GAI5E,GAAI3B,EAAE,gBAAgB,SAAW,GAAKA,EAAE,KAAK,OAAS,EAAG,CACvD,IAAM4B,EAAkB5B,EAAE,YACvB,OAAQsB,GAAmBA,EAAG,OAAS,aAAa,EACpD,IAAKA,GAAmBA,EAAG,IAAI,EAC/B,KAAK,GAAG,EACX,GACEM,EAAgB,OAAS,GACzBA,EAAgB,YAAY,EAAE,WAAW5B,EAAE,KAAK,YAAY,CAAC,EAE7D,MAAO,EAEX,CAEA,GAAM,CAAE,SAAAN,EAAU,gBAAiBmC,CAAc,EAAIC,EAAW9B,EAAE,KAAMA,EAAE,eAAe,EACnF+B,EAAarC,EAAS,OAASM,EAAE,aAAa,OAC9CgC,EAAW,KAAK,IAAItC,EAAS,OAASM,EAAE,aAAa,MAAM,EACjE,OAAI+B,GAAcC,GAAYZ,GAC5B,KAAK,QAAQ1B,EAAUmC,CAAa,EAC7B,IAEF,EACT,EAEA,KAAK,cAAgB,WAAW,IAAM,CAChCV,EAAapC,EAAc,GACzB,KAAK,mBAAmB,aAAa,KAAK,iBAAiB,CAEnE,EAAGF,EAAW,EAEd,KAAK,kBAAoB,WAAW,IAAMsC,EAAa,CAAC,EAAGrC,EAAgB,CAC7E,CAEQ,aAAc,CAChB,KAAK,eAAe,aAAa,KAAK,aAAa,EACnD,KAAK,mBAAmB,aAAa,KAAK,iBAAiB,EAC/D,KAAK,cAAgB,KACrB,KAAK,kBAAoB,IAC3B,CACF,EClMO,IAAMmD,EAAN,KAAyB,CAC9B,YACUC,EACAC,EACR,CAFQ,WAAAD,EACA,SAAAC,CACP,CAEH,cAAc,EAAkB,CAC9B,IAAMC,EAAQ,KAAK,MAAM,IAAI,EACvB,CAAE,UAAAC,EAAW,YAAAC,CAAY,EAAI,KAAK,IAClCC,EAAU,KAAK,oBAAoB,EACnCC,EAAWF,EAAY,EACvBG,EAAkB,KAAK,mBAAmBF,CAAO,EAEvD,OAAQ,EAAE,IAAK,CACb,IAAK,YAAa,CAChB,IAAMG,EAAS,EAAE,OAGjB,GAAI,EADFA,EAAO,gBAAkB,MAAQA,EAAO,iBAAmBA,EAAO,MAAM,SACtDN,EAAM,oBAAsB,EAAG,MAGnD,GADA,EAAE,eAAe,EACb,CAACA,EAAM,gBAAkBA,EAAM,sBAAsB,OAAS,EAAG,CACnE,KAAK,MAAM,IAAI,CAAE,WAAY,GAAM,oBAAqBK,EAAgB,CAAC,GAAK,CAAE,CAAC,EACjF,KACF,CACA,GAAIA,EAAgB,SAAW,EAAG,OAClC,IAAME,EAAaF,EAAgB,QAAQL,EAAM,mBAAmB,EAC9DQ,EAAUD,EAAaF,EAAgB,OAAS,EAAIE,EAAa,EAAI,EAC3E,KAAK,MAAM,IAAI,CAAE,oBAAqBF,EAAgBG,CAAO,CAAE,CAAC,EAChE,KACF,CACA,IAAK,UAAW,CACd,GAAIH,EAAgB,SAAW,GAAKL,EAAM,oBAAsB,EAAG,MAEnE,GADA,EAAE,eAAe,EACbA,EAAM,oBAAsBG,EAAS,CACvC,KAAK,MAAM,IAAI,CAAE,oBAAqB,EAAG,CAAC,EAC1C,KACF,CACA,IAAMI,EAAaF,EAAgB,QAAQL,EAAM,mBAAmB,EAC9DS,EAAUF,EAAa,EAAIA,EAAa,EAAIF,EAAgB,OAAS,EAC3E,KAAK,MAAM,IAAI,CAAE,oBAAqBA,EAAgBI,CAAO,CAAE,CAAC,EAChE,KACF,CACA,IAAK,aAAc,CACjB,GAAIT,EAAM,oBAAsB,EAAG,CACjC,IAAMM,EAAS,EAAE,OAEfA,EAAO,gBAAkB,MAAQA,EAAO,iBAAmBA,EAAO,MAAM,QAC7DN,EAAM,sBAAsB,OAAS,IAChD,EAAE,eAAe,EACjB,KAAK,mBAAmB,CAAC,GAE3B,KACF,CAEA,GADYA,EAAM,oBAAsBG,EAC9BA,EAAU,EAAG,CACrB,IAAMO,EAAgBV,EAAM,oBAAsB,EAEhDU,EAAgBV,EAAM,gBAAgB,QACtCA,EAAM,gBAAgBU,CAAa,GAAG,cAEtC,EAAE,eAAe,EACjB,KAAK,MAAM,IAAI,CAAE,oBAAqBA,CAAc,CAAC,EAEzD,CACA,KACF,CACA,IAAK,YAAa,CAChB,GAAIV,EAAM,oBAAsB,EAAG,MACnC,GAAIA,EAAM,oBAAsBG,EAAU,EAAG,CAC3C,IAAMQ,EAAeX,EAAM,oBAAsB,EAC7CW,GAAgB,GAAKX,EAAM,gBAAgBW,CAAY,GAAG,cAC5D,EAAE,eAAe,EACjB,KAAK,MAAM,IAAI,CAAE,oBAAqBA,CAAa,CAAC,EAExD,CACA,KACF,CACA,IAAK,QAAS,CAEZ,GADA,EAAE,eAAe,EAEfX,EAAM,qBAAuB,GAC7BA,EAAM,gBAAgBA,EAAM,mBAAmB,GAAG,YAElD,KAAK,cAAcA,EAAM,oBAAqBA,EAAM,gBAAiBC,CAAS,UACrEG,EAAU,CACnB,GAAM,CAAE,SAAAQ,EAAU,gBAAiBC,CAAY,EAAIC,EACjDd,EAAM,KACNA,EAAM,eACR,EACAI,EAAS,CACP,MAAOJ,EAAM,KAAK,KAAK,EACvB,UAAWY,EACX,iBAAkBC,CACpB,CAAC,CACH,CACA,KACF,CACA,IAAK,MAAO,CACV,IAAME,EAAqB,CAACf,EAAM,MAAQ,CAAC,CAACA,EAAM,gBAC5CgB,EACJhB,EAAM,qBAAuB,GAC7BA,EAAM,gBAAgBA,EAAM,mBAAmB,GAAG,YAIpD,GAAIe,GAAsB,CAACC,EAAsB,CAC/C,EAAE,eAAe,EACjB,IAAMC,EAAwBjB,EAAM,YAAY,KAAMkB,GAAMA,EAAE,OAAS,aAAa,EAChFD,EACF,KAAK,MAAM,IAAKC,IAAO,CACrB,KAAMlB,EAAM,gBACZ,WAAYA,EAAM,gBAAgB,OAClC,gBAAiB,CACf,GAAGkB,EAAE,gBACL,CACE,GAAI,OAAO,WAAW,EACtB,YAAa,GACb,KAAMD,EAAsB,KAC5B,KAAMjB,EAAM,gBACZ,KAAM,KACN,eAAgBiB,EAAsB,KACtC,sBAAuBA,EAAsB,KAC7C,QAASA,EAAsB,SAAW,CAAC,CAC7C,CACF,EACA,YAAaC,EAAE,YAAY,OAAQC,GAAOA,IAAOF,CAAqB,CACxE,EAAE,EAEF,KAAK,MAAM,IAAI,CACb,KAAMjB,EAAM,gBACZ,WAAYA,EAAM,gBAAgB,MACpC,CAAC,CAEL,SAAWgB,EACT,EAAE,eAAe,EACjB,KAAK,cAAchB,EAAM,oBAAqBA,EAAM,gBAAiBC,CAAS,UACrED,EAAM,eAAgB,CAC/B,IAAMoB,EAAmBpB,EAAM,gBAAgB,UAAWqB,GAAMA,EAAE,WAAW,EACzED,GAAoB,IACtB,EAAE,eAAe,EACjB,KAAK,cAAcA,EAAkBpB,EAAM,gBAAiBC,CAAS,EAEzE,CACA,KACF,CACA,IAAK,SACH,KAAK,MAAM,IAAI,CAAE,oBAAqB,EAAG,CAAC,EAC1C,KACJ,CACF,CAEQ,mBAAmBE,EAA2B,CAEpD,IAAMmB,EADQ,KAAK,MAAM,IAAI,EACN,gBACpB,IAAI,CAACD,EAAGE,IAAOF,EAAE,YAAcE,EAAI,EAAG,EACtC,OAAQA,GAAMA,IAAM,EAAE,EACnBC,EAAsB,MAAM,KAAK,CAAE,OAAQrB,CAAQ,EAAG,IAAM,CAAC,CAAC,EACpE,QAAWoB,KAAKD,EAAUE,EAAQD,EAAIpB,CAAO,EAAE,KAAKoB,CAAC,EACrD,OAAOC,EAAQ,KAAK,CACtB,CAOQ,qBAA8B,CAEpC,IAAMC,EADc,SAAS,eAAe,GAAG,KAAK,IAAI,SAAS,WAAW,GAClD,cAC1B,GAAI,CAACA,EAAM,OAAO,KAAK,IAAI,QAC3B,IAAMC,EAAS,iBAAiBD,CAAI,EAAE,oBAAoB,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,OACrF,OAAOC,EAAS,EAAIA,EAAS,KAAK,IAAI,OACxC,CAEQ,cAAcC,EAAeC,EAA6B3B,EAAmB,CACnF,IAAM4B,EAAW,SAAS,eAAe,GAAG5B,CAAS,WAAW0B,CAAK,EAAE,EACnEE,EACFA,EAAS,MAAM,EAEf,KAAK,IAAI,aAAaD,EAAQD,CAAK,CAAC,CAExC,CAGQ,mBAAmBA,EAAe,CACxC,IAAM3B,EAAQ,KAAK,MAAM,IAAI,EACvB8B,EAAa9B,EAAM,YAAY,OAAQkB,GAAMA,EAAE,OAAS,aAAa,EAC3E,GAAIS,EAAQ,GAAKA,GAASG,EAAW,OAAQ,OAC7C,IAAMC,EAAQD,EAAWH,CAAK,EACxBK,EAAOF,EAAW,OAAO,CAACG,EAAGV,IAAMA,IAAMI,CAAK,EAC9CO,EAAelC,EAAM,YAAY,OAAQkB,GAAMA,EAAE,OAAS,aAAa,EAC7E,KAAK,MAAM,IAAI,CACb,YAAa,CAAC,GAAGgB,EAAcH,EAAO,GAAGC,CAAI,EAC7C,WAAY,GACZ,oBAAqB,EACvB,CAAC,CACH,CACF,EC9MO,IAAMG,EAAN,KAAsB,CAC3B,YAAoBC,EAAyB,CAAzB,WAAAA,CAA0B,CAE9C,cAAcC,EAAe,CAC3B,IAAMC,EAAQ,KAAK,MAAM,IAAI,EACvBC,EAAaD,EAAM,YAAY,OAAQE,GAAMA,EAAE,OAAS,aAAa,EAC3E,GAAIH,EAAQ,GAAKA,GAASE,EAAW,OAAQ,OAC7C,IAAME,EAAQF,EAAWF,CAAK,EACxBK,EAAOH,EAAW,OAAO,CAACI,EAAGC,IAAMA,IAAMP,CAAK,EAC9CQ,EAAeP,EAAM,YAAY,OAAQE,GAAMA,EAAE,OAAS,aAAa,EAC7E,KAAK,MAAM,IAAI,CACb,YAAa,CAAC,GAAGK,EAAcJ,EAAO,GAAGC,CAAI,EAC7C,WAAY,GACZ,oBAAqB,EACvB,CAAC,CACH,CAEA,iBAAkB,CAChB,IAAMJ,EAAQ,KAAK,MAAM,IAAI,EAC7B,GAAIA,EAAM,gBAAgB,SAAW,EAAG,OACxC,IAAMQ,EAAYR,EAAM,gBAAgBA,EAAM,gBAAgB,OAAS,CAAC,EAClES,EAAiC,CACrC,KAAMD,EAAU,eAChB,KAAMA,EAAU,sBAChB,SAAU,GACV,QAASA,EAAU,OACrB,EACA,KAAK,MAAM,IAAKN,IAAO,CACrB,gBAAiBA,EAAE,gBAAgB,MAAM,EAAG,EAAE,EAC9C,YAAa,CAACO,EAAoB,GAAGP,EAAE,WAAW,EAClD,oBAAqB,EACvB,EAAE,CACJ,CACF,ECnCA,SAASQ,GAAeC,EAAuB,CAC7C,OAAIA,IAAU,EAAU,GACpBA,IAAU,EAAU,GACjB,GACT,CAEO,SAASC,EACdC,EACAC,EACAC,EACAC,EACAC,EAAU,GACV,CAEA,IAAIC,EAAOL,EAAU,cAA2B,uBAAuB,EAClEK,IACHA,EAAO,SAAS,cAAc,MAAM,EACpCA,EAAK,UAAY,uBACjBL,EAAU,YAAYK,CAAI,GAI5B,IAAMC,EAAW,IAAI,IACrB,QAAWC,KAAOF,EAAK,iBAAoC,kBAAkB,EAC3EC,EAAS,IAAIC,EAAI,QAAQ,SAAW,GAAIA,CAAG,EAG7C,IAAMC,EAAO,IAAI,IACjB,QAASC,EAAI,EAAGA,EAAIR,EAAM,OAAQQ,IAAK,CACrC,IAAMC,EAAOT,EAAMQ,CAAC,EACdE,EAAM,GAAGD,EAAK,IAAI,IAAIA,EAAK,IAAI,GACrCF,EAAK,IAAIG,CAAG,EAEZ,IAAIJ,EAAMD,EAAS,IAAIK,CAAG,EACrBJ,IACHA,EAAM,SAAS,cAAc,QAAQ,EACrCA,EAAI,KAAO,SACXA,EAAI,QAAQ,QAAUI,EACtBJ,EAAI,aAAa,gBAAiB,EAAE,EACpCA,EAAI,YAAcG,EAAK,MAGzBH,EAAI,UAAY,kBAAkBH,EAAU,4BAA8B,EAAE,GAAGK,IAAMP,EAAkB,2BAA6B,EAAE,GACtIK,EAAI,MAAM,QAAU,OAAOV,GAAeY,CAAC,CAAC,EAC5CF,EAAI,QAAU,IAAMJ,EAAaM,CAAC,EAG9BJ,EAAK,SAASI,CAAC,IAAMF,GACvBF,EAAK,aAAaE,EAAKF,EAAK,SAASI,CAAC,GAAK,IAAI,CAEnD,CAGA,OAAW,CAACE,EAAKJ,CAAG,IAAKD,EAClBE,EAAK,IAAIG,CAAG,GAAGJ,EAAI,OAAO,CAEnC,CC1CO,SAASK,EAAeC,EAAgC,CAC7D,IAAMC,EAAW,SAAS,cAAc,KAAK,EAC7C,OAAAA,EAAS,GAAKD,EACdC,EAAS,aAAa,OAAQ,SAAS,EACvCA,EAAS,aAAa,oBAAqB,EAAE,EAC7CA,EAAS,UAAY,sBACrBA,EAAS,iBAAiB,YAAcC,GAAMA,EAAE,eAAe,CAAC,EACzDD,CACT,CAEO,SAASE,EAAeF,EAAuBG,EAAsB,CAC1E,GAAM,CACJ,gBAAAC,EACA,YAAAC,EACA,OAAAC,EACA,MAAAC,EACA,UAAAC,EACA,SAAAC,EACA,YAAAC,EACA,YAAAC,CACF,EAAIR,EAEES,EAAWJ,GAAaD,EAAM,OAAS,EAC1BD,GAAUF,EAAgB,OAAS,GACrBE,GAAUM,EAIzCZ,EAAS,UAAU,IAAI,8BAA8B,EAErDA,EAAS,UAAU,OAAO,8BAA8B,EAI1D,IAAIa,EAAUb,EAAS,cAA2B,sBAAsB,EACpEY,GACGC,IACHA,EAAU,SAAS,cAAc,KAAK,EACtCA,EAAQ,UAAY,sBACpBA,EAAQ,aAAa,mBAAoB,EAAE,EAC3Cb,EAAS,aAAaa,EAASb,EAAS,UAAU,GAEpDc,EAAYD,EAASN,EAAO,EAAGI,EAAa,EAAI,GACvCE,GACTA,EAAQ,OAAO,EAIjB,IAAIE,EAAOf,EAAS,cAA2B,kBAAkB,EAC7DI,EAAgB,OAAS,GACtBW,IACHA,EAAO,SAAS,cAAc,KAAK,EACnCA,EAAK,UAAY,kBACjBf,EAAS,YAAYe,CAAI,GAE3BC,GAAcD,EAAMX,EAAiBC,EAAaI,EAAUC,EAAaP,EAAM,SAAS,GAC/EY,IACTA,EAAK,UAAY,GAErB,CAEA,SAASC,GACPD,EACAE,EACAZ,EACAI,EACAC,EACAX,EACA,CACA,IAAMmB,EAAaD,EAAQ,IAAKE,GAAMA,EAAE,IAAI,EAAE,KAAK,IAAI,EACjDC,EAAUL,EAAK,QAAQ,YAAc,GACrCM,EAAcH,IAAeE,EAGnC,GAFAL,EAAK,QAAQ,WAAaG,EAEtBG,EAAa,CAEf,IAAMC,EAAW,SAAS,uBAAuB,EAEjD,QAASC,EAAI,EAAGA,EAAIN,EAAQ,OAAQM,IAAK,CACvC,IAAMC,EAASP,EAAQM,CAAC,EAClBE,EAAOC,GAAoBF,EAAQD,EAAGlB,EAAaI,EAAUC,EAAaX,CAAS,EACzFuB,EAAS,YAAYG,CAAI,CAC3B,CAEAV,EAAK,UAAY,GACjBA,EAAK,YAAYO,CAAQ,CAC3B,KAAO,CAEL,IAAMK,EAAQZ,EAAK,iBAA8B,oBAAoB,EACrE,QAASQ,EAAI,EAAGA,EAAII,EAAM,OAAQJ,IAAK,CACrC,IAAME,EAAOE,EAAMJ,CAAC,EACdK,EAAgBL,IAAMlB,EAC5BoB,EAAK,aAAa,gBAAiB,OAAOG,CAAa,CAAC,EACpDA,EACFH,EAAK,UAAU,IAAI,gCAAgC,EAEnDA,EAAK,UAAU,OAAO,gCAAgC,CAE1D,CACF,CACF,CAEA,SAASC,GACPF,EACAK,EACAxB,EACAI,EACAC,EACAX,EACa,CACb,IAAM0B,EAAO,SAAS,cAAc,KAAK,EACzCA,EAAK,GAAK,GAAG1B,CAAS,WAAW8B,CAAK,GACtCJ,EAAK,aAAa,OAAQ,QAAQ,EAClCA,EAAK,aAAa,kBAAmB,EAAE,EACvCA,EAAK,aAAa,gBAAiB,OAAOI,IAAUxB,CAAW,CAAC,EAChEoB,EAAK,SAAWD,EAAO,YAAc,EAAI,GAEzC,IAAMM,EAAU,CAAC,mBAAmB,EAChCD,IAAUxB,GAAayB,EAAQ,KAAK,gCAAgC,EACpEN,EAAO,YACTM,EAAQ,KAAK,6BAA6B,EAE1CA,EAAQ,KAAK,iCAAiC,EAEhDL,EAAK,UAAYK,EAAQ,KAAK,GAAG,EAGjC,IAAMC,EAAU,SAAS,cAAc,KAAK,EAC5CA,EAAQ,UAAY,qBACpBN,EAAK,YAAYM,CAAO,EAExB,IAAMC,EAAc,SAAS,cAAc,KAAK,EAChDA,EAAY,UAAY,0BACxBP,EAAK,YAAYO,CAAW,EAG5B,IAAMC,EAAU,SAAS,cAAc,MAAM,EAI7C,GAHAA,EAAQ,UAAY,4BACpBA,EAAQ,YAAcT,EAAO,KAAO,GAAGA,EAAO,IAAI,IAAIA,EAAO,IAAI,GAAKA,EAAO,KAEzEA,EAAO,IAAK,CACd,IAAMU,EAAM,SAAS,cAAc,MAAM,EACzCA,EAAI,UAAY,wBAChBA,EAAI,YAAcV,EAAO,IACzBS,EAAQ,YAAYC,CAAG,CACzB,CAEA,OAAAT,EAAK,YAAYQ,CAAO,EAGpBT,EAAO,cACTC,EAAK,iBAAiB,QAAS,IAAM,CACnCA,EAAK,UAAU,IAAI,4BAA4B,EAC/ChB,EAASe,CAAM,EACf,WAAW,IAAMC,EAAK,UAAU,OAAO,4BAA4B,EAAG,GAAG,CAC3E,CAAC,EACDA,EAAK,iBAAiB,aAAc,IAAMf,EAAYmB,CAAK,CAAC,GAGvDJ,CACT,CChKO,SAASU,EACdC,EACAC,EACkB,CAClB,IAAMC,EAAWC,EAAeF,EAAK,SAAS,EAC9C,OAAAD,EAAU,YAAYE,CAAQ,EACvB,CAAE,SAAAA,CAAS,CACpB,CAEO,SAASE,EACdC,EACAC,EACAL,EACA,CACAM,EAAeF,EAAK,SAAU,CAC5B,YACEC,EAAM,sBAAsB,OAAS,EACjC,CAAC,CAAE,GAAGA,EAAM,sBAAsB,CAAC,EAAG,QAASA,EAAM,eAAgB,CAAC,EACtE,CAAC,EACP,gBAAiBA,EAAM,gBACvB,YAAaA,EAAM,oBACnB,OAAQA,EAAM,eACd,UAAWL,EAAK,UAChB,MAAOK,EAAM,sBACb,UAAW,GACX,SAAUL,EAAK,aACf,YAAc,GAAMA,EAAK,MAAM,IAAI,CAAE,oBAAqB,CAAE,CAAC,EAC7D,YAAaA,EAAK,aACpB,CAAC,CACH,CCrCO,SAASO,EACdC,EACAC,EACAC,EACAC,EACAC,EACA,CACA,IAAIC,EAAYL,EAAM,cAA2B,wBAAwB,EACrEM,EAAcN,EAAM,cAA2B,yBAAyB,EAE5E,GAAIG,GAAWC,EAAiB,CAC1BC,IAAWA,EAAU,MAAM,QAAU,QACpCC,IACHA,EAAc,SAAS,cAAc,MAAM,EAC3CA,EAAY,UAAY,yBACxBN,EAAM,aAAaM,EAAaN,EAAM,UAAU,GAElDM,EAAY,MAAM,QAAU,GAC5BA,EAAY,YAAc,GAAGF,CAAe,IAC5CJ,EAAM,QAAQ,WAAa,GAC3B,MACF,CAEIM,IAAaA,EAAY,MAAM,QAAU,QACxCD,IACHA,EAAY,SAAS,cAAc,MAAM,EACzCA,EAAU,UAAY,wBACtBL,EAAM,aAAaK,EAAWL,EAAM,UAAU,GAEhDK,EAAU,MAAM,QAAU,GAC1BA,EAAU,UAAY,wBAAwBH,EAAa,kCAAoC,EAAE,GAEjG,IAAMK,EAAaN,EAAS,IAAKO,GAAM,GAAGA,EAAE,IAAI,IAAIA,EAAE,KAAK,EAAE,EAAE,KAAK,IAAI,EAClEC,EAAUT,EAAM,QAAQ,YAAc,GACtCU,EAAcV,EAAM,QAAQ,YAAc,GAChD,GAAI,EAAAO,IAAeE,IAAYP,GAAc,MAAQQ,GAGrD,CAAAV,EAAM,QAAQ,WAAaO,EAC3BP,EAAM,QAAQ,WAAaE,GAAc,GAEzCG,EAAU,UAAY,GACtB,QAAWM,KAAOV,EAAU,CAC1B,IAAMW,EAAO,SAAS,cAAc,MAAM,EACtCD,EAAI,OAAS,cACDA,EAAI,MAAM,KAAOT,EAE7BU,EAAK,UAAY,uDAEjBA,EAAK,UAAY,oDAGrBA,EAAK,YAAcD,EAAI,MACvBN,EAAU,YAAYO,CAAI,CAC5B,CAEIX,EAAS,SAAW,IACtBI,EAAU,YAAc,QAE5B,CCrCA,IAAMQ,GAAa,8NAEZ,SAASC,EAASC,EAAwBC,EAAmC,CAClF,GAAM,CAAE,UAAAC,CAAU,EAAID,EAGhBE,EAAWC,EAAeF,CAAS,EACzCF,EAAU,YAAYG,CAAQ,EAG9B,IAAME,EAAe,SAAS,cAAc,KAAK,EACjDA,EAAa,UAAY,2BACzBL,EAAU,YAAYK,CAAY,EAGlC,IAAMC,EAAS,SAAS,cAAc,KAAK,EAC3CA,EAAO,UAAY,oBACnBA,EAAO,aAAa,kBAAmB,EAAE,EACzCD,EAAa,YAAYC,CAAM,EAG/B,IAAMC,EAAQ,SAAS,cAAc,KAAK,EAC1CA,EAAM,UAAY,mBAClBA,EAAM,aAAa,cAAe,MAAM,EACxCD,EAAO,YAAYC,CAAK,EAGxB,IAAMC,EAAsB,SAAS,cAAc,MAAM,EACzDD,EAAM,YAAY,SAAS,eAAe,GAAG,CAAC,EAC9CA,EAAM,YAAYC,CAAmB,EAGrC,IAAMC,EAAW,SAAS,cAAc,UAAU,EAClDA,EAAS,UAAY,sBACrBA,EAAS,KAAO,EAChBA,EAAS,aAAa,OAAQ,UAAU,EACxCA,EAAS,aAAa,oBAAqB,MAAM,EACjDA,EAAS,aAAa,gBAAiBP,CAAS,EAChDO,EAAS,aAAa,oBAAqB,EAAE,EAC7CH,EAAO,YAAYG,CAAQ,EAG3B,IAAIC,EAAyC,KACzCC,EAAmC,KACvC,OAAIV,EAAK,eAAiB,QACxBS,EAAe,SAAS,cAAc,QAAQ,EAC9CA,EAAa,KAAO,SACpBA,EAAa,UAAY,oBACzBA,EAAa,aAAa,aAAc,QAAQ,EAChDA,EAAa,aAAa,kBAAmB,EAAE,EAC/CA,EAAa,UAAYZ,GACzBO,EAAa,YAAYK,CAAY,EACrCC,EAAeD,GACNT,EAAK,eAAiB,OAC/BU,EAAeV,EAAK,aACfU,EAAa,aAAa,iBAAiB,GAC9CA,EAAa,aAAa,kBAAmB,EAAE,EAEjDN,EAAa,YAAYM,CAAY,GAMvCN,EAAa,iBAAiB,QAAS,IAAMI,EAAS,MAAM,CAAC,EAG7DA,EAAS,iBAAiB,QAAS,IAAM,CACvC,IAAMG,EAAMH,EAAS,MAEfI,EADmBD,EAAI,OAAS,GAAKA,EAAI,CAAC,IAAMA,EAAI,CAAC,EAAE,YAAY,EACrCA,EAAI,CAAC,EAAE,YAAY,EAAIA,EAAI,MAAM,CAAC,EAAIA,EAC1EX,EAAK,aAAaY,CAAQ,CAC5B,CAAC,EAGDJ,EAAS,iBAAiB,UAAYK,GAAMb,EAAK,cAAca,CAAC,CAAC,EAGjEL,EAAS,iBAAiB,QAAS,IAAMR,EAAK,MAAM,IAAI,CAAE,UAAW,EAAK,CAAC,CAAC,EAC5EQ,EAAS,iBAAiB,OAAQ,IAAMR,EAAK,MAAM,IAAI,CAAE,UAAW,EAAM,CAAC,CAAC,EAGxEU,GACFA,EAAa,iBAAiB,QAAUG,GAAM,CAC5C,IAAMC,EAAQd,EAAK,MAAM,IAAI,EAE7B,GAAI,EADc,CAAC,CAACc,EAAM,MAAQA,EAAM,gBAAgB,OAAS,IAC/C,CAACd,EAAK,SAAU,OAClCa,EAAE,gBAAgB,EAClB,GAAM,CAAE,SAAAE,EAAU,gBAAiBC,CAAY,EAAIC,EACjDH,EAAM,KACNA,EAAM,eACR,EACAd,EAAK,SAAS,CACZ,MAAOc,EAAM,KAAK,KAAK,EACvB,UAAWC,EACX,iBAAkBC,CACpB,CAAC,CACH,CAAC,EAIChB,EAAK,YAAc,IACrBQ,EAAS,MAAM,EAGV,CAAE,SAAAA,EAAU,SAAAN,EAAU,MAAAI,EAAO,aAAAG,EAAc,oBAAAF,CAAoB,CACxE,CAEO,SAASW,EAAUC,EAAeL,EAAkBd,EAA0B,CACnF,GAAM,CAAE,SAAAQ,EAAU,SAAAN,EAAU,MAAAI,EAAO,aAAAG,EAAc,oBAAAF,CAAoB,EAAIY,EACnE,CAAE,cAAAC,EAAe,cAAAC,EAAe,aAAAC,EAAc,MAAAC,CAAM,EAAIvB,EAG1DQ,EAAS,QAAUM,EAAM,OAC3BN,EAAS,MAAQM,EAAM,MAIrBA,EAAM,gBACRN,EAAS,YAAcM,EAAM,gBAE7BN,EAAS,gBAAgB,aAAa,EAIxCA,EAAS,aAAa,gBAAiB,OAAOM,EAAM,cAAc,CAAC,EACnE,IAAMU,EACJV,EAAM,qBAAuB,EAAI,GAAGd,EAAK,SAAS,WAAWc,EAAM,mBAAmB,GAAK,GAgB7F,GAfIU,EACFhB,EAAS,aAAa,wBAAyBgB,CAAgB,EAE/DhB,EAAS,gBAAgB,uBAAuB,EAI9CM,EAAM,WACRN,EAAS,UAAU,IAAI,6BAA6B,EAEpDA,EAAS,UAAU,OAAO,6BAA6B,EAKrDC,EAAc,CAChB,IAAMgB,EAAY,CAAC,CAACX,EAAM,MAAQA,EAAM,gBAAgB,OAAS,EACjEL,EAAa,SAAW,CAACgB,CAC3B,CAGAC,EAAepB,EAAOQ,EAAM,SAAUA,EAAM,WAAY,CAACA,EAAM,KAAMA,EAAM,eAAe,EAGtFM,IAAkB,SACpBO,EAAYpB,EAAqBO,EAAM,sBAAuB,EAAGO,CAAa,EAG9Ed,EAAoB,UAAY,GAIlCqB,EAAe1B,EAAU,CACvB,YACEY,EAAM,sBAAsB,OAAS,EACjC,CAAC,CAAE,GAAGA,EAAM,sBAAsB,CAAC,EAAG,QAASA,EAAM,eAAgB,CAAC,EACtE,CAAC,EACP,gBAAiBA,EAAM,gBACvB,YAAaA,EAAM,oBACnB,OAAQA,EAAM,eACd,UAAWd,EAAK,UAChB,MAAOc,EAAM,sBACb,UAAWM,IAAkB,WAC7B,SAAUE,EACV,YAAcO,GAAMN,EAAM,IAAI,CAAE,oBAAqBM,CAAE,CAAC,EACxD,YAAaR,CACf,CAAC,CACH,CCrMO,SAASS,EAAeC,EAAsB,CACnD,IAAIC,EAAQD,EACNE,EAAY,IAAI,IACtB,MAAO,CACL,IAAK,IAAMD,EACX,IAAME,GAAU,CACd,IAAMC,EAAW,OAAOD,GAAU,WAAaA,EAAMF,CAAK,EAAIE,EACxDE,EAAO,CAAE,GAAGJ,EAAO,GAAGG,CAAS,EAC/BE,EAAOL,EACbA,EAAQI,EACR,QAAWE,KAAKL,EAAWK,EAAEF,EAAMC,CAAI,CACzC,EACA,UAAYE,IACVN,EAAU,IAAIM,CAAQ,EACf,IAAM,CACXN,EAAU,OAAOM,CAAQ,CAC3B,EAEJ,CACF,CC3BA,IAAIC,EAAW,GAGR,SAASC,GAAe,CAC7B,GAAID,GAAY,OAAO,SAAa,IAAa,OACjD,GAAI,SAAS,cAAc,wBAAwB,EAAG,CACpDA,EAAW,GACX,MACF,CACAA,EAAW,GAEX,IAAME,EAAQ,SAAS,cAAc,OAAO,EAC5CA,EAAM,aAAa,kBAAmB,EAAE,EACxCA,EAAM,YAAcC,GACpB,SAAS,KAAK,YAAYD,CAAK,CACjC,CAIA,IAAMC,GAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECNf,IAAIC,GAAY,EAChB,SAASC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","names":["index_exports","__export","AIAutocomplete","createStore","__toCommonJS","extractFilterQuery","text","filterBase","isInProgress","rawRegion","spaceIdx","findPrefixOverlap","prefix","optionText","trimmed","words","optionLower","i","candidate","suffixStart","filterOptions","options","query","lower","o","findExactMatch","ModeController","container","mode","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","TokenManager","config","forceRefresh","result","SDK_VERSION","hasWarnedMissingKey","generateRequestId","toWireParam","param","includeText","isAccessTokenConfig","config","getApiKeyConfig","tokenManagers","getTokenManager","manager","TokenManager","buildRequestBody","rawQuery","completedParams","sessionId","rawCount","p","contactAccountCount","buildHeaders","apiConfig","doFetch","endpoint","headers","token","body","signal","fetchSuggestions","options","jsonBody","response","newToken","apiKeyConfig","apiKey","authScheme","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","FetchController","store","getApiConfig","getOptionOverrides","getMaskCompletedText","getOnError","getSessionId","prevText","prevParams","next","rawQuery","completed","controller","version","state","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","filterBase","filterInProgress","inProgressIdx","active","extraParam","query","extractFilterQuery","match","findExactMatch","err","caughtError","attemptFetch","minDiff","currentQuery","sg","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","placeholderText","updatedParams","buildQuery","isDeleting","charDiff","KeyboardController","store","ctx","state","listboxId","getOnSubmit","columns","onSubmit","tappableIndices","target","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","placeholderVisible","hasHighlightedOption","placeholderSuggestion","s","sg","firstTappableIdx","o","tappable","i","buckets","grid","tracks","index","options","optionEl","actionable","moved","rest","_","placeholders","PillsController","store","index","state","actionable","s","moved","rest","_","i","placeholders","lastParam","restoredSuggestion","getPillOpacity","index","renderPills","container","pills","activePillIndex","onSelectPill","rounded","list","existing","btn","used","i","pill","key","createDropdown","listboxId","dropdown","e","renderDropdown","state","filteredOptions","activeIndex","isOpen","pills","showPills","onSelect","onHighlight","onPillClick","hasPills","pillBar","renderPills","grid","renderOptions","options","optionsKey","o","lastKey","listChanged","fragment","i","option","item","createOptionElement","items","isHighlighted","index","classes","streaks","streaksVert","content","tag","buildDropdownOnly","container","opts","dropdown","createDropdown","updateDropdownOnly","refs","state","renderDropdown","renderSegments","sizer","segments","newParamId","isEmpty","placeholderText","sizerText","placeholder","segmentKey","s","lastKey","lastParamId","seg","span","SUBMIT_SVG","buildDOM","container","opts","listboxId","dropdown","createDropdown","inputWrapper","editor","sizer","inlinePillContainer","textarea","submitButton","submitTarget","raw","newValue","e","state","rawQuery","finalParams","buildQuery","updateDOM","refs","pillPlacement","setActivePill","selectOption","store","activeDescendant","canSubmit","renderSegments","renderPills","renderDropdown","i","createStore","initial","state","listeners","patch","resolved","next","prev","l","listener","injected","injectStyles","style","STYLES","idCounter","stableId","initialState","AIAutocomplete","container","opts","createStore","PillsController","FetchController","KeyboardController","option","next","prev","injectStyles","unsub","mode","text","params","index","value","focused","listener","event","callback","state","activeSuggestion","base","prefix","inputWasEmpty","inputIsPlaceholderPrefix","overlapChars","findPrefixOverlap","needsSpace","newText","finalText","optionStart","optionInFinal","completed","remainingActionable","s","sg","_prev","segments","deriveSegments","actionableSuggestions","overrideFn","clampedFilterBase","filterQuery","extractFilterQuery","baseOptions","filteredOptions","filterOptions","placeholderText","trigger","closeOnBlur","isDropdownOpen","focusGate","settled","ModeController","self","renderOpts","e","buildDOM","updateDOM","dropdownOpts","buildDropdownOnly","updateDropdownOnly","render","scheduled","newValue","valid","invalid","reconcileParams","param"]}
|
|
1
|
+
{"version":3,"sources":["../src/core/index.ts","../src/utils/filtering.ts","../src/utils/modeController.ts","../src/utils/segments.ts","../src/utils/tokenManager.ts","../src/utils/api.ts","../src/utils/buildQuery.ts","../src/utils/overrides.ts","../src/core/controllers/fetchController.ts","../src/core/controllers/keyboardController.ts","../src/core/controllers/pillsController.ts","../src/core/render/renderPills.ts","../src/core/render/renderDropdown.ts","../src/core/render/renderDropdownOnly.ts","../src/core/render/renderSegments.ts","../src/core/render/renderInput.ts","../src/core/state.ts","../src/core/styleInjector.ts","../src/core/AIAutocomplete.ts"],"sourcesContent":["// Re-export shared types consumers need\nexport type {\n AccessTokenConfig,\n AccessTokenResult,\n APIConfig,\n APIKeyConfig,\n AppearanceMode,\n AutocompleteResult,\n CompletedParam,\n CompletedParamState,\n Segment,\n Suggestion,\n SuggestionOption,\n} from \"../types\";\nexport { AIAutocomplete } from \"./AIAutocomplete\";\nexport type { Store } from \"./state\";\nexport { createStore } from \"./state\";\nexport type { CoreOptions, CoreState, RenderMode } from \"./types\";\n","import type { SuggestionOption } from \"../types\";\n\n/**\n * Extracts the effective filter query from the region after filterBase.\n * If the server marked the region as in_progress, the full region is used.\n * Otherwise, filtering only starts after the first space (to avoid filtering\n * mid-word when the user continues typing a word that was already in the input).\n */\nexport function extractFilterQuery(\n text: string,\n filterBase: number,\n isInProgress: boolean,\n): string {\n const rawRegion = text.slice(filterBase);\n if (isInProgress || filterBase === 0 || text[filterBase - 1] === \" \") {\n return rawRegion;\n }\n const spaceIdx = rawRegion.indexOf(\" \");\n return spaceIdx === -1 ? \"\" : rawRegion.slice(spaceIdx + 1);\n}\n\n/**\n * Finds the longest word-boundary-aligned suffix of `prefix` that matches a\n * prefix of `optionText` (case-insensitive). Returns the number of characters\n * to remove from the end of `prefix` to avoid duplication.\n */\nexport function findPrefixOverlap(prefix: string, optionText: string): number {\n // Normalize internal whitespace so words.join(\" \") roundtrips losslessly\n const trimmed = prefix.trimEnd().replace(/\\s+/g, \" \");\n if (trimmed.length === 0 || optionText.length === 0) return 0;\n\n const words = trimmed.split(\" \");\n const optionLower = optionText.toLowerCase();\n\n // Try from longest suffix (all words) to shortest (last word only)\n for (let i = 0; i < words.length; i++) {\n const candidate = words.slice(i).join(\" \");\n if (optionLower.startsWith(candidate.toLowerCase())) {\n const suffixStart = trimmed.length - candidate.length;\n return prefix.length - suffixStart;\n }\n }\n\n return 0;\n}\n\n/**\n * Filters options using partial substring match on the text after the last completed param.\n */\nexport function filterOptions(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption[] {\n if (!options) return [];\n const trimmed = query.trimStart();\n if (!trimmed) return options;\n const lower = trimmed.toLowerCase();\n return options.filter((o) => !o.is_tappable || o.text.toLowerCase().includes(lower));\n}\n\n/**\n * Finds an exact match for the trimmed filter query against options.\n */\nexport function findExactMatch(\n options: SuggestionOption[] | undefined,\n query: string,\n): SuggestionOption | null {\n if (!options) return null;\n const trimmed = query.trim();\n if (!trimmed) return null;\n const lower = trimmed.toLowerCase();\n return options.find((o) => o.is_tappable && o.text.toLowerCase() === lower) ?? null;\n}\n","import type { AppearanceMode } from \"../types\";\n\nexport class ModeController {\n private mediaQuery: MediaQueryList | null = null;\n\n constructor(\n private container: HTMLElement,\n private mode: AppearanceMode = \"auto\",\n ) {\n this.apply();\n }\n\n setMode(mode: AppearanceMode) {\n this.detachListener();\n this.mode = mode;\n this.apply();\n }\n\n destroy() {\n this.detachListener();\n }\n\n private apply() {\n if (this.mode === \"auto\") {\n this.mediaQuery ??= window.matchMedia(\"(prefers-color-scheme: dark)\");\n this.mediaQuery.addEventListener(\"change\", this.onSystemChange);\n this.container.dataset.mode = this.mediaQuery.matches ? \"dark\" : \"light\";\n } else {\n this.container.dataset.mode = this.mode;\n }\n }\n\n private onSystemChange = (e: MediaQueryListEvent) => {\n this.container.dataset.mode = e.matches ? \"dark\" : \"light\";\n };\n\n private detachListener() {\n this.mediaQuery?.removeEventListener(\"change\", this.onSystemChange);\n }\n}\n","import type { CompletedParamState, Segment } from \"../types\";\n\n/**\n * Derives segments for overlay rendering by matching completed params in text.\n */\nexport function deriveSegments(text: string, completedParams: CompletedParamState[]): Segment[] {\n const result: Segment[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) continue;\n if (idx > pos) {\n result.push({ type: \"text\", value: text.slice(pos, idx) });\n }\n result.push({ type: \"completed\", value: param.text, param });\n pos = idx + param.text.length;\n }\n\n const remaining = text.slice(pos);\n if (remaining) {\n result.push({ type: \"text\", value: remaining });\n }\n\n return result;\n}\n\n/**\n * Checks which completed params still exist in the new text.\n */\nexport function reconcileParams(\n text: string,\n completedParams: CompletedParamState[],\n): { valid: CompletedParamState[]; invalid: CompletedParamState[] } {\n const valid: CompletedParamState[] = [];\n const invalid: CompletedParamState[] = [];\n let pos = 0;\n\n for (const param of completedParams) {\n const idx = text.indexOf(param.text, pos);\n if (idx === -1) {\n invalid.push(param);\n } else {\n valid.push(param);\n pos = idx + param.text.length;\n }\n }\n\n return { valid, invalid };\n}\n","import type { AccessTokenConfig } from \"../types\";\n\n/** Refresh 30 seconds before stated expiry to absorb clock drift and request latency. */\nconst REFRESH_SKEW_MS = 30_000;\n\nexport class TokenManager {\n private current: string | null = null;\n private expiresAt: number | null = null;\n private inFlightRefresh: Promise<string> | null = null;\n\n constructor(private config: AccessTokenConfig) {\n if (config.accessToken) {\n this.current = config.accessToken;\n }\n }\n\n /** Returns a valid token, refreshing if needed. Single-flight: concurrent callers share one refresh. */\n async getToken(forceRefresh = false): Promise<string> {\n if (!forceRefresh && this.current && !this.isExpired()) {\n return this.current;\n }\n if (!forceRefresh && this.inFlightRefresh) {\n return this.inFlightRefresh;\n }\n this.inFlightRefresh = this.refresh();\n try {\n return await this.inFlightRefresh;\n } finally {\n this.inFlightRefresh = null;\n }\n }\n\n private async refresh(): Promise<string> {\n const result = await this.config.getAccessToken();\n this.current = result.accessToken;\n this.expiresAt = result.expiresAt ?? null;\n return this.current;\n }\n\n private isExpired(): boolean {\n if (this.expiresAt == null) return false;\n return Date.now() >= this.expiresAt - REFRESH_SKEW_MS;\n }\n}\n","import type {\n AccessTokenConfig,\n APIConfig,\n APIKeyConfig,\n AutocompleteRequest,\n AutocompleteResponse,\n CompletedParam,\n CompletedParamState,\n} from \"../types\";\nimport { TokenManager } from \"./tokenManager\";\n\n// Replaced at build time by tsup/vitest `define` config with the package.json version.\ndeclare const __SDK_VERSION__: string;\nconst SDK_VERSION = __SDK_VERSION__;\n\nlet hasWarnedMissingKey = false;\n\nfunction generateRequestId(): string {\n return crypto.randomUUID();\n}\n\nfunction toWireParam(param: CompletedParamState, includeText: boolean): CompletedParam {\n return {\n placeholder: param.placeholder,\n type: param.type,\n ...(includeText && { text: param.text }),\n kind: param.kind,\n };\n}\n\nfunction isAccessTokenConfig(config?: APIConfig): config is AccessTokenConfig {\n return config?.type === \"accessToken\";\n}\n\nfunction getApiKeyConfig(config?: APIConfig): APIKeyConfig | undefined {\n if (!config || isAccessTokenConfig(config)) return undefined;\n return config;\n}\n\n// Keyed by getAccessToken function reference (stable across React re-renders)\nconst tokenManagers = new WeakMap<AccessTokenConfig[\"getAccessToken\"], TokenManager>();\n\nfunction getTokenManager(config: AccessTokenConfig): TokenManager {\n let manager = tokenManagers.get(config.getAccessToken);\n if (!manager) {\n manager = new TokenManager(config);\n tokenManagers.set(config.getAccessToken, manager);\n }\n return manager;\n}\n\nfunction buildRequestBody(\n rawQuery: string,\n completedParams: CompletedParamState[],\n includeText: boolean,\n sessionId: string,\n): AutocompleteRequest {\n const rawCount = completedParams.find(\n (p) => p.type === \"contact\" && p.metadata?.contact_account_count,\n )?.metadata?.contact_account_count;\n const contactAccountCount = typeof rawCount === \"number\" ? rawCount : undefined;\n\n return {\n data: {\n raw_query: rawQuery,\n completed_params: completedParams.map((p) => toWireParam(p, includeText)),\n ...(contactAccountCount != null && { contact_account_count: contactAccountCount }),\n },\n meta: {\n request_id: generateRequestId(),\n request_at: new Date().toISOString(),\n language: typeof navigator !== \"undefined\" ? navigator.language : \"en-US\",\n client_version: SDK_VERSION,\n session_id: sessionId,\n },\n };\n}\n\nfunction buildHeaders(apiConfig?: APIConfig): Record<string, string> {\n return {\n \"Content-Type\": \"application/json\",\n ...(apiConfig?.appIdentifier && { \"X-App-Identifier\": apiConfig.appIdentifier }),\n ...apiConfig?.headers,\n };\n}\n\nasync function doFetch(\n endpoint: string,\n headers: Record<string, string>,\n token: string,\n body: string,\n signal?: AbortSignal,\n): Promise<Response> {\n return fetch(endpoint, {\n method: \"POST\",\n headers: { ...headers, Authorization: `Bearer ${token}` },\n body,\n signal,\n });\n}\n\nexport async function fetchSuggestions(\n rawQuery: string,\n completedParams: CompletedParamState[],\n options: {\n sessionId: string;\n maskCompletedText?: boolean;\n signal?: AbortSignal;\n apiConfig?: APIConfig;\n },\n): Promise<AutocompleteResponse> {\n const apiConfig = options.apiConfig;\n const includeText = !options.maskCompletedText;\n const body = buildRequestBody(rawQuery, completedParams, includeText, options.sessionId);\n const headers = buildHeaders(apiConfig);\n const endpoint = apiConfig?.endpoint ?? \"https://api.ai-autocomplete.com/api/suggest\";\n const jsonBody = JSON.stringify(body);\n\n // === Access token mode ===\n if (isAccessTokenConfig(apiConfig)) {\n const manager = getTokenManager(apiConfig);\n const token = await manager.getToken();\n\n let response = await doFetch(endpoint, headers, token, jsonBody, options.signal);\n\n // 401 retry: force-refresh token and retry exactly once\n if (response.status === 401) {\n const newToken = await manager.getToken(true);\n response = await doFetch(endpoint, headers, newToken, jsonBody, options.signal);\n }\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n }\n\n // === API key mode (default) ===\n const apiKeyConfig = getApiKeyConfig(apiConfig);\n const apiKey = apiKeyConfig?.apiKey ?? \"\";\n\n if (!apiKey && !hasWarnedMissingKey) {\n hasWarnedMissingKey = true;\n // biome-ignore lint/suspicious/noConsole: intentional dev warning\n console.warn(\n \"[AIAutocomplete] No apiKey in apiConfig. Requests will be sent without an Authorization header.\",\n );\n }\n\n if (apiKey) {\n const authScheme = apiKeyConfig?.authScheme ?? \"Bearer\";\n headers.Authorization = authScheme === \"Basic\" ? `Basic ${btoa(apiKey)}` : `Bearer ${apiKey}`;\n }\n\n const response = await fetch(endpoint, {\n method: \"POST\",\n headers,\n body: jsonBody,\n signal: options.signal,\n });\n\n if (!response.ok) {\n throw new Error(`API error: ${response.status} ${response.statusText}`);\n }\n\n return response.json() as Promise<AutocompleteResponse>;\n}\n","import type { 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 {\n APIConfig,\n CompletedParamState,\n OptionOverrides,\n Suggestion,\n SuggestionOption,\n} from \"../../types\";\nimport { fetchSuggestions } from \"../../utils/api\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport { extractFilterQuery, filterOptions, findExactMatch } from \"../../utils/filtering\";\nimport { applyOptionOverrides } from \"../../utils/overrides\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nconst DEBOUNCE_MS = 100;\nconst SLOW_DEBOUNCE_MS = 300;\nconst MIN_CHARS_DIFF = 2;\n\nexport class FetchController {\n private fetchVersion = 0;\n private abortController: AbortController | null = null;\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private slowDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n private unsubscribe: (() => void) | null = null;\n\n constructor(\n private store: Store<CoreState>,\n private getApiConfig: () => APIConfig | undefined,\n private getOptionOverrides: () => OptionOverrides | undefined,\n private getMaskCompletedText: () => boolean | undefined,\n private getOnError: () => ((error: Error) => void) | undefined,\n private getSessionId: () => string,\n ) {}\n\n start() {\n // Initial fetch\n this.doFetch(\"\", []);\n\n // Subscribe to state changes for debounced fetching\n let prevText = this.store.get().text;\n let prevParams = this.store.get().completedParams;\n this.unsubscribe = this.store.subscribe((next) => {\n if (next.text !== prevText || next.completedParams !== prevParams) {\n prevText = next.text;\n prevParams = next.completedParams;\n this.scheduleFetch();\n }\n });\n }\n\n dispose() {\n this.abortController?.abort();\n this.clearTimers();\n this.unsubscribe?.();\n }\n\n async doFetch(rawQuery: string, completed: CompletedParamState[]) {\n this.abortController?.abort();\n const controller = new AbortController();\n this.abortController = controller;\n const version = ++this.fetchVersion;\n const state = this.store.get();\n const textAtRequest = state.text.length;\n\n const hasSuggestions = state.suggestions.some((s) => s.type !== \"placeholder\");\n if (!hasSuggestions) this.store.set({ isLoading: true });\n this.store.set({ error: null });\n\n try {\n const res = await fetchSuggestions(rawQuery, completed, {\n sessionId: this.getSessionId(),\n maskCompletedText: this.getMaskCompletedText(),\n signal: controller.signal,\n apiConfig: this.getApiConfig(),\n });\n\n if (version !== this.fetchVersion) return;\n\n let newSuggestions = applyOptionOverrides(\n res.data.suggestions ?? [],\n this.getOptionOverrides(),\n );\n\n const input = res.data.input ?? [];\n const lastInput = input[input.length - 1];\n const currentText = this.store.get().text;\n let filterBase: number;\n let filterInProgress: boolean;\n\n if (lastInput?.state === \"in_progress\") {\n filterInProgress = true;\n const inProgressIdx = currentText.toLowerCase().lastIndexOf(lastInput.text.toLowerCase());\n filterBase = inProgressIdx !== -1 ? inProgressIdx : textAtRequest;\n } else {\n filterInProgress = false;\n filterBase = textAtRequest;\n }\n\n // Check if user already typed an exact match while waiting\n const actionable = newSuggestions.filter((s) => s.type !== \"placeholder\");\n const active = actionable[0];\n let extraParam: CompletedParamState | null = null;\n if (active) {\n const query = extractFilterQuery(currentText, filterBase, filterInProgress);\n const match = findExactMatch(active.options, query);\n if (match) {\n extraParam = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: active.type,\n text: match.text,\n kind: match.kind,\n suggestionType: active.type,\n suggestionPlaceholder: active.text,\n options: active.options ?? [],\n metadata: match.metadata,\n };\n newSuggestions = newSuggestions.filter((s) => s !== active);\n }\n }\n\n this.store.set((s) => ({\n suggestions: newSuggestions,\n isLoading: false,\n isReady: res.data.is_ready ?? false,\n lastRawQuery: rawQuery,\n activeDropdownIndex: -1,\n filterBase,\n filterInProgress,\n ...(extraParam ? { completedParams: [...s.completedParams, extraParam] } : {}),\n }));\n } catch (err) {\n if (version === this.fetchVersion) {\n const caughtError = err instanceof Error ? err : new Error(String(err));\n this.store.set({ error: caughtError, isLoading: false });\n this.getOnError()?.(caughtError);\n }\n }\n }\n\n private scheduleFetch() {\n this.clearTimers();\n const state = this.store.get();\n\n if (state.skipNextFetch) {\n this.store.set({ skipNextFetch: false });\n return;\n }\n\n const attemptFetch = (minDiff: number): boolean => {\n const s = this.store.get();\n if (!s.text && s.completedParams.length === 0) {\n this.doFetch(\"\", []);\n return true;\n }\n\n const currentQuery = extractFilterQuery(s.text, s.filterBase, s.filterInProgress);\n const actionable = s.suggestions.filter((sg: Suggestion) => sg.type !== \"placeholder\");\n const active = actionable[0];\n const currentFiltered = active ? filterOptions(active.options, currentQuery) : [];\n const tappableFiltered = currentFiltered.filter((o: SuggestionOption) => o.is_tappable);\n const hasExactMatch = active ? findExactMatch(active.options, currentQuery) !== null : false;\n\n const isInFilterZone = currentQuery.trim().length > 0;\n if (tappableFiltered.length > 0 && !hasExactMatch && isInFilterZone) return false;\n\n // Mirror the filter-zone behavior for placeholder suggestions: if the user is\n // still typing a prefix of the server-provided placeholder, don't fetch yet.\n if (s.completedParams.length === 0 && s.text.length > 0) {\n const placeholderText = s.suggestions\n .filter((sg: Suggestion) => sg.type === \"placeholder\")\n .map((sg: Suggestion) => sg.text)\n .join(\" \");\n if (\n placeholderText.length > 0 &&\n placeholderText.toLowerCase().startsWith(s.text.toLowerCase())\n ) {\n return false;\n }\n }\n\n const { rawQuery, completedParams: updatedParams } = buildQuery(s.text, s.completedParams);\n const isDeleting = rawQuery.length < s.lastRawQuery.length;\n const charDiff = Math.abs(rawQuery.length - s.lastRawQuery.length);\n if (isDeleting || charDiff >= minDiff) {\n this.doFetch(rawQuery, updatedParams);\n return true;\n }\n return false;\n };\n\n this.debounceTimer = setTimeout(() => {\n if (attemptFetch(MIN_CHARS_DIFF)) {\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n }\n }, DEBOUNCE_MS);\n\n this.slowDebounceTimer = setTimeout(() => attemptFetch(1), SLOW_DEBOUNCE_MS);\n }\n\n private clearTimers() {\n if (this.debounceTimer) clearTimeout(this.debounceTimer);\n if (this.slowDebounceTimer) clearTimeout(this.slowDebounceTimer);\n this.debounceTimer = null;\n this.slowDebounceTimer = null;\n }\n}\n","import type { AutocompleteResult, SuggestionOption } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport interface KeyboardContext {\n columns: number;\n listboxId: string;\n getOnSubmit: () => ((result: AutocompleteResult) => void) | undefined;\n selectOption: (option: SuggestionOption) => void;\n}\n\nexport class KeyboardController {\n constructor(\n private store: Store<CoreState>,\n private ctx: KeyboardContext,\n ) {}\n\n handleKeyDown(e: KeyboardEvent) {\n const state = this.store.get();\n const { listboxId, getOnSubmit } = this.ctx;\n const columns = this.getEffectiveColumns();\n const onSubmit = getOnSubmit();\n const tappableIndices = this.getTappableIndices(columns);\n\n switch (e.key) {\n case \"ArrowDown\": {\n const target = e.target as HTMLTextAreaElement;\n const cursorAtEnd =\n target.selectionStart != null && target.selectionStart === target.value.length;\n if (!cursorAtEnd && state.activeDropdownIndex < 0) break;\n\n e.preventDefault();\n if (!state.isDropdownOpen && state.actionableSuggestions.length > 0) {\n this.store.set({ pillTapped: true, activeDropdownIndex: tappableIndices[0] ?? 0 });\n break;\n }\n if (tappableIndices.length === 0) return;\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const nextPos = currentPos < tappableIndices.length - 1 ? currentPos + 1 : 0;\n this.store.set({ activeDropdownIndex: tappableIndices[nextPos] });\n break;\n }\n case \"ArrowUp\": {\n if (tappableIndices.length === 0 || state.activeDropdownIndex < 0) break;\n e.preventDefault();\n if (state.activeDropdownIndex < columns) {\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n const currentPos = tappableIndices.indexOf(state.activeDropdownIndex);\n const prevPos = currentPos > 0 ? currentPos - 1 : tappableIndices.length - 1;\n this.store.set({ activeDropdownIndex: tappableIndices[prevPos] });\n break;\n }\n case \"ArrowRight\": {\n if (state.activeDropdownIndex < 0) {\n const target = e.target as HTMLTextAreaElement;\n const atEnd =\n target.selectionStart != null && target.selectionStart === target.value.length;\n if (atEnd && state.actionableSuggestions.length > 1) {\n e.preventDefault();\n this.pillsSetActivePill(1);\n }\n break;\n }\n const col = state.activeDropdownIndex % columns;\n if (col < columns - 1) {\n const rightNeighbor = state.activeDropdownIndex + 1;\n if (\n rightNeighbor < state.filteredOptions.length &&\n state.filteredOptions[rightNeighbor]?.is_tappable\n ) {\n e.preventDefault();\n this.store.set({ activeDropdownIndex: rightNeighbor });\n }\n }\n break;\n }\n case \"ArrowLeft\": {\n if (state.activeDropdownIndex < 0) break;\n if (state.activeDropdownIndex % columns > 0) {\n const leftNeighbor = state.activeDropdownIndex - 1;\n if (leftNeighbor >= 0 && state.filteredOptions[leftNeighbor]?.is_tappable) {\n e.preventDefault();\n this.store.set({ activeDropdownIndex: leftNeighbor });\n }\n }\n break;\n }\n case \"Enter\": {\n e.preventDefault();\n if (\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable\n ) {\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (onSubmit) {\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n }\n break;\n }\n case \"Tab\": {\n const placeholderVisible = !state.text && !!state.placeholderText;\n const hasHighlightedOption =\n state.activeDropdownIndex >= 0 &&\n state.filteredOptions[state.activeDropdownIndex]?.is_tappable;\n\n // Placeholder visible + option highlighted → defer to selectOption,\n // which prepends the placeholder text to the option (see AIAutocomplete.selectOption).\n if (placeholderVisible && !hasHighlightedOption) {\n e.preventDefault();\n const placeholderSuggestion = state.suggestions.find((s) => s.type === \"placeholder\");\n if (placeholderSuggestion) {\n this.store.set((s) => ({\n text: state.placeholderText,\n filterBase: state.placeholderText.length,\n completedParams: [\n ...s.completedParams,\n {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: placeholderSuggestion.type,\n text: state.placeholderText,\n kind: null,\n suggestionType: placeholderSuggestion.type,\n suggestionPlaceholder: placeholderSuggestion.text,\n options: placeholderSuggestion.options ?? [],\n },\n ],\n suggestions: s.suggestions.filter((sg) => sg !== placeholderSuggestion),\n }));\n } else {\n this.store.set({\n text: state.placeholderText,\n filterBase: state.placeholderText.length,\n });\n }\n } else if (hasHighlightedOption) {\n e.preventDefault();\n this.clickOrSelect(state.activeDropdownIndex, state.filteredOptions, listboxId);\n } else if (state.isDropdownOpen) {\n const firstTappableIdx = state.filteredOptions.findIndex((o) => o.is_tappable);\n if (firstTappableIdx >= 0) {\n e.preventDefault();\n this.clickOrSelect(firstTappableIdx, state.filteredOptions, listboxId);\n }\n }\n break;\n }\n case \"Escape\":\n this.store.set({ activeDropdownIndex: -1 });\n break;\n }\n }\n\n private getTappableIndices(columns: number): number[] {\n const state = this.store.get();\n const tappable = state.filteredOptions\n .map((o, i) => (o.is_tappable ? i : -1))\n .filter((i) => i !== -1);\n const buckets: number[][] = Array.from({ length: columns }, () => []);\n for (const i of tappable) buckets[i % columns].push(i);\n return buckets.flat();\n }\n\n /**\n * The grid uses a container query to switch between 1 and 2 columns based on\n * width, so the prop value can disagree with what's actually rendered. Read\n * the live column count from the grid; fall back to the prop if unavailable.\n */\n private getEffectiveColumns(): number {\n const firstOption = document.getElementById(`${this.ctx.listboxId}-option-0`);\n const grid = firstOption?.parentElement;\n if (!grid) return this.ctx.columns;\n const tracks = getComputedStyle(grid).gridTemplateColumns.split(\" \").filter(Boolean).length;\n return tracks > 0 ? tracks : this.ctx.columns;\n }\n\n private clickOrSelect(index: number, options: SuggestionOption[], listboxId: string) {\n const optionEl = document.getElementById(`${listboxId}-option-${index}`);\n if (optionEl) {\n optionEl.click();\n } else {\n this.ctx.selectOption(options[index]);\n }\n }\n\n /** Delegate to pills controller logic inline (avoids circular dep) */\n private pillsSetActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n}\n","import type { Suggestion } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\n\nexport class PillsController {\n constructor(private store: Store<CoreState>) {}\n\n setActivePill(index: number) {\n const state = this.store.get();\n const actionable = state.suggestions.filter((s) => s.type !== \"placeholder\");\n if (index < 0 || index >= actionable.length) return;\n const moved = actionable[index];\n const rest = actionable.filter((_, i) => i !== index);\n const placeholders = state.suggestions.filter((s) => s.type === \"placeholder\");\n this.store.set({\n suggestions: [...placeholders, moved, ...rest],\n pillTapped: true,\n activeDropdownIndex: -1,\n });\n }\n\n removeLastParam() {\n const state = this.store.get();\n if (state.completedParams.length === 0) return;\n const lastParam = state.completedParams[state.completedParams.length - 1];\n const restoredSuggestion: Suggestion = {\n type: lastParam.suggestionType,\n text: lastParam.suggestionPlaceholder,\n required: true,\n options: lastParam.options,\n };\n this.store.set((s) => ({\n completedParams: s.completedParams.slice(0, -1),\n suggestions: [restoredSuggestion, ...s.suggestions],\n activeDropdownIndex: -1,\n }));\n }\n}\n","import type { Suggestion } from \"../../types\";\n\nfunction getPillOpacity(index: number): number {\n if (index === 0) return 0.4;\n if (index === 1) return 0.3;\n return 0.15;\n}\n\nexport function renderPills(\n container: HTMLElement,\n pills: Suggestion[],\n activePillIndex: number,\n onSelectPill: (index: number) => void,\n rounded = false,\n) {\n // Reuse or create the list wrapper\n let list = container.querySelector<HTMLElement>(\".magicx-aia-pill-list\");\n if (!list) {\n list = document.createElement(\"span\");\n list.className = \"magicx-aia-pill-list\";\n container.appendChild(list);\n }\n\n // Diff by key (type-text)\n const existing = new Map<string, HTMLButtonElement>();\n for (const btn of list.querySelectorAll<HTMLButtonElement>(\".magicx-aia-pill\")) {\n existing.set(btn.dataset.pillKey ?? \"\", btn);\n }\n\n const used = new Set<string>();\n for (let i = 0; i < pills.length; i++) {\n const pill = pills[i];\n const key = `${pill.type}-${pill.text}`;\n used.add(key);\n\n let btn = existing.get(key);\n if (!btn) {\n btn = document.createElement(\"button\");\n btn.type = \"button\";\n btn.dataset.pillKey = key;\n btn.setAttribute(\"data-aia-pill\", \"\");\n btn.textContent = pill.text;\n }\n\n btn.className = `magicx-aia-pill${rounded ? \" magicx-aia-pill--rounded\" : \"\"}${i === activePillIndex ? \" magicx-aia-pill--active\" : \"\"}`;\n btn.style.opacity = String(getPillOpacity(i));\n btn.onclick = () => onSelectPill(i);\n\n // Ensure correct order\n if (list.children[i] !== btn) {\n list.insertBefore(btn, list.children[i] ?? null);\n }\n }\n\n // Remove stale pills\n for (const [key, btn] of existing) {\n if (!used.has(key)) btn.remove();\n }\n}\n\nexport function clearPills(container: HTMLElement) {\n container.querySelector(\".magicx-aia-pill-list\")?.remove();\n}\n","import type { Suggestion, SuggestionOption } from \"../../types\";\nimport { renderPills } from \"./renderPills\";\n\ninterface DropdownState {\n suggestions: Suggestion[];\n filteredOptions: SuggestionOption[];\n activeIndex: number;\n isOpen: boolean;\n listboxId: string;\n pills: Suggestion[];\n showPills: boolean;\n onSelect: (option: SuggestionOption) => void;\n onHighlight: (index: number) => void;\n onPillClick: (index: number) => void;\n}\n\nexport function createDropdown(listboxId: string): HTMLElement {\n const dropdown = document.createElement(\"div\");\n dropdown.id = listboxId;\n dropdown.setAttribute(\"role\", \"listbox\");\n dropdown.setAttribute(\"data-aia-dropdown\", \"\");\n dropdown.className = \"magicx-aia-dropdown\";\n dropdown.addEventListener(\"mousedown\", (e) => e.preventDefault());\n return dropdown;\n}\n\nexport function renderDropdown(dropdown: HTMLElement, state: DropdownState) {\n const {\n filteredOptions,\n activeIndex,\n isOpen,\n pills,\n showPills,\n onSelect,\n onHighlight,\n onPillClick,\n } = state;\n\n const hasPills = showPills && pills.length > 0;\n const hasOptions = isOpen && filteredOptions.length > 0;\n const isVisible = hasOptions || (isOpen && hasPills);\n\n // Toggle visibility\n if (isVisible) {\n dropdown.classList.add(\"magicx-aia-dropdown--visible\");\n } else {\n dropdown.classList.remove(\"magicx-aia-dropdown--visible\");\n }\n\n // --- Pill bar ---\n let pillBar = dropdown.querySelector<HTMLElement>(\".magicx-aia-pill-bar\");\n if (hasPills) {\n if (!pillBar) {\n pillBar = document.createElement(\"div\");\n pillBar.className = \"magicx-aia-pill-bar\";\n pillBar.setAttribute(\"data-aia-pillbar\", \"\");\n dropdown.insertBefore(pillBar, dropdown.firstChild);\n }\n renderPills(pillBar, pills, 0, onPillClick, true);\n } else if (pillBar) {\n pillBar.remove();\n }\n\n // --- Options grid ---\n let grid = dropdown.querySelector<HTMLElement>(\".magicx-aia-grid\");\n if (filteredOptions.length > 0) {\n if (!grid) {\n grid = document.createElement(\"div\");\n grid.className = \"magicx-aia-grid\";\n dropdown.appendChild(grid);\n }\n renderOptions(grid, filteredOptions, activeIndex, onSelect, onHighlight, state.listboxId);\n } else if (grid) {\n grid.innerHTML = \"\";\n }\n}\n\nfunction renderOptions(\n grid: HTMLElement,\n options: SuggestionOption[],\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n) {\n const optionsKey = options.map((o) => o.text).join(\"\\0\");\n const lastKey = grid.dataset.optionsKey ?? \"\";\n const listChanged = optionsKey !== lastKey;\n grid.dataset.optionsKey = optionsKey;\n\n if (listChanged) {\n // Full rebuild — options changed (filter, new suggestion, etc.)\n const fragment = document.createDocumentFragment();\n\n for (let i = 0; i < options.length; i++) {\n const option = options[i];\n const item = createOptionElement(option, i, activeIndex, onSelect, onHighlight, listboxId);\n fragment.appendChild(item);\n }\n\n grid.innerHTML = \"\";\n grid.appendChild(fragment);\n } else {\n // Just update highlight classes — no DOM rebuild\n const items = grid.querySelectorAll<HTMLElement>(\".magicx-aia-option\");\n for (let i = 0; i < items.length; i++) {\n const item = items[i];\n const isHighlighted = i === activeIndex;\n item.setAttribute(\"aria-selected\", String(isHighlighted));\n if (isHighlighted) {\n item.classList.add(\"magicx-aia-option--highlighted\");\n } else {\n item.classList.remove(\"magicx-aia-option--highlighted\");\n }\n }\n }\n}\n\nfunction createOptionElement(\n option: SuggestionOption,\n index: number,\n activeIndex: number,\n onSelect: (option: SuggestionOption) => void,\n onHighlight: (index: number) => void,\n listboxId: string,\n): HTMLElement {\n const item = document.createElement(\"div\");\n item.id = `${listboxId}-option-${index}`;\n item.setAttribute(\"role\", \"option\");\n item.setAttribute(\"data-aia-option\", \"\");\n item.setAttribute(\"aria-selected\", String(index === activeIndex));\n item.tabIndex = option.is_tappable ? 0 : -1;\n\n const classes = [\"magicx-aia-option\"];\n if (index === activeIndex) classes.push(\"magicx-aia-option--highlighted\");\n if (option.is_tappable) {\n classes.push(\"magicx-aia-option--tappable\");\n } else {\n classes.push(\"magicx-aia-option--non-tappable\");\n }\n item.className = classes.join(\" \");\n\n // Streaks\n const streaks = document.createElement(\"div\");\n streaks.className = \"magicx-aia-streaks\";\n item.appendChild(streaks);\n\n const streaksVert = document.createElement(\"div\");\n streaksVert.className = \"magicx-aia-streaks-vert\";\n item.appendChild(streaksVert);\n\n // Content\n const content = document.createElement(\"span\");\n content.className = \"magicx-aia-option-content\";\n content.textContent = option.icon ? `${option.icon} ${option.text}` : option.text;\n\n if (option.tag) {\n const tag = document.createElement(\"span\");\n tag.className = \"magicx-aia-option-tag\";\n tag.textContent = option.tag;\n content.appendChild(tag);\n }\n\n item.appendChild(content);\n\n // Events\n if (option.is_tappable) {\n item.addEventListener(\"click\", () => {\n item.classList.add(\"magicx-aia-option--pressed\");\n onSelect(option);\n setTimeout(() => item.classList.remove(\"magicx-aia-option--pressed\"), 400);\n });\n item.addEventListener(\"mouseenter\", () => onHighlight(index));\n }\n\n return item;\n}\n","import type { SuggestionOption } from \"../../types\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\n\ninterface DropdownOnlyRefs {\n dropdown: HTMLElement;\n}\n\ninterface DropdownOnlyOptions {\n store: Store<CoreState>;\n listboxId: string;\n selectOption: (option: SuggestionOption) => void;\n setActivePill: (index: number) => void;\n}\n\nexport function buildDropdownOnly(\n container: HTMLElement,\n opts: DropdownOnlyOptions,\n): DropdownOnlyRefs {\n const dropdown = createDropdown(opts.listboxId);\n container.appendChild(dropdown);\n return { dropdown };\n}\n\nexport function updateDropdownOnly(\n refs: DropdownOnlyRefs,\n state: CoreState,\n opts: DropdownOnlyOptions,\n) {\n renderDropdown(refs.dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: true, // always show pills in dropdown-only mode\n onSelect: opts.selectOption,\n onHighlight: (i) => opts.store.set({ activeDropdownIndex: i }),\n onPillClick: opts.setActivePill,\n });\n}\n","import type { Segment } from \"../../types\";\n\n/**\n * Renders text segments into the sizer overlay.\n * Only rebuilds the DOM when segment content or newParamId changes,\n * preserving in-flight CSS animations (shimmer).\n * Cache keys stored on the DOM element to support multi-instance use.\n */\nexport function renderSegments(\n sizer: HTMLElement,\n segments: Segment[],\n newParamId: string | null,\n isEmpty: boolean,\n placeholderText: string,\n) {\n let sizerText = sizer.querySelector<HTMLElement>(\".magicx-aia-sizer-text\");\n let placeholder = sizer.querySelector<HTMLElement>(\".magicx-aia-placeholder\");\n\n if (isEmpty && placeholderText) {\n if (sizerText) sizerText.style.display = \"none\";\n if (!placeholder) {\n placeholder = document.createElement(\"span\");\n placeholder.className = \"magicx-aia-placeholder\";\n sizer.insertBefore(placeholder, sizer.firstChild);\n }\n placeholder.style.display = \"\";\n placeholder.textContent = `${placeholderText} `;\n sizer.dataset.segmentKey = \"\";\n return;\n }\n\n if (placeholder) placeholder.style.display = \"none\";\n if (!sizerText) {\n sizerText = document.createElement(\"span\");\n sizerText.className = \"magicx-aia-sizer-text\";\n sizer.insertBefore(sizerText, sizer.firstChild);\n }\n sizerText.style.display = \"\";\n sizerText.className = `magicx-aia-sizer-text${newParamId ? \" magicx-aia-sizer-text--visible\" : \"\"}`;\n\n const segmentKey = segments.map((s) => `${s.type}:${s.value}`).join(\"\\0\");\n const lastKey = sizer.dataset.segmentKey ?? \"\";\n const lastParamId = sizer.dataset.newParamId ?? \"\";\n if (segmentKey === lastKey && (newParamId ?? \"\") === lastParamId) {\n return; // Nothing changed — preserve existing DOM and animations\n }\n sizer.dataset.segmentKey = segmentKey;\n sizer.dataset.newParamId = newParamId ?? \"\";\n\n sizerText.innerHTML = \"\";\n for (const seg of segments) {\n const span = document.createElement(\"span\");\n if (seg.type === \"completed\") {\n const isNew = seg.param.id === newParamId;\n if (isNew) {\n span.className = \"magicx-aia-shimmer-revealed magicx-aia-shimmer-sweep\";\n } else {\n span.className = \"magicx-aia-segment magicx-aia-segment--completed\";\n }\n }\n span.textContent = seg.value;\n sizerText.appendChild(span);\n }\n\n if (segments.length === 0) {\n sizerText.textContent = \"\\u00A0\";\n }\n}\n","import type { AutocompleteResult } from \"../../types\";\nimport { buildQuery } from \"../../utils/buildQuery\";\nimport type { Store } from \"../state\";\nimport type { CoreState } from \"../types\";\nimport { createDropdown, renderDropdown } from \"./renderDropdown\";\nimport { renderPills } from \"./renderPills\";\nimport { renderSegments } from \"./renderSegments\";\n\ninterface RenderInputOptions {\n store: Store<CoreState>;\n listboxId: string;\n pillPlacement: \"inline\" | \"dropdown\" | \"hidden\";\n autoFocus?: boolean;\n onSubmit?: (result: AutocompleteResult) => void;\n submitButton?: HTMLElement | null;\n selectOption: (option: import(\"../../types\").SuggestionOption) => void;\n setActivePill: (index: number) => void;\n handleKeyDown: (e: KeyboardEvent) => void;\n handleChange: (value: string) => void;\n}\n\nexport interface DOMRefs {\n textarea: HTMLTextAreaElement;\n dropdown: HTMLElement;\n sizer: HTMLElement;\n /** The default built-in button when no `submitButton` was provided. Null when consumer passed `null` or a custom element. */\n submitButton: HTMLButtonElement | null;\n inlinePillContainer: HTMLElement;\n}\n\nconst SUBMIT_SVG = `<svg width=\"18\" height=\"18\" viewBox=\"0 0 18 18\" fill=\"none\" role=\"img\" aria-label=\"Submit\"><path d=\"M9 14V4M9 4L4 9M9 4L14 9\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\"/></svg>`;\n\nexport function buildDOM(container: HTMLElement, opts: RenderInputOptions): DOMRefs {\n const { listboxId } = opts;\n\n // Dropdown\n const dropdown = createDropdown(listboxId);\n container.appendChild(dropdown);\n\n // Input wrapper\n const inputWrapper = document.createElement(\"div\");\n inputWrapper.className = \"magicx-aia-input-wrapper\";\n container.appendChild(inputWrapper);\n\n // Editor area\n const editor = document.createElement(\"div\");\n editor.className = \"magicx-aia-editor\";\n editor.setAttribute(\"data-aia-editor\", \"\");\n inputWrapper.appendChild(editor);\n\n // Sizer (overlay)\n const sizer = document.createElement(\"div\");\n sizer.className = \"magicx-aia-sizer\";\n sizer.setAttribute(\"aria-hidden\", \"true\");\n editor.appendChild(sizer);\n\n // Inline pill container (inside sizer, after segments)\n const inlinePillContainer = document.createElement(\"span\");\n sizer.appendChild(document.createTextNode(\" \"));\n sizer.appendChild(inlinePillContainer);\n\n // Textarea\n const textarea = document.createElement(\"textarea\");\n textarea.className = \"magicx-aia-textarea\";\n textarea.rows = 1;\n textarea.setAttribute(\"role\", \"combobox\");\n textarea.setAttribute(\"aria-autocomplete\", \"list\");\n textarea.setAttribute(\"aria-controls\", listboxId);\n textarea.setAttribute(\"data-aia-textarea\", \"\");\n editor.appendChild(textarea);\n\n // Submit button — null means render nothing; undefined means default; HTMLElement means custom\n let submitButton: HTMLButtonElement | null = null;\n let submitTarget: HTMLElement | null = null;\n if (opts.submitButton === undefined) {\n submitButton = document.createElement(\"button\");\n submitButton.type = \"button\";\n submitButton.className = \"magicx-aia-submit\";\n submitButton.setAttribute(\"aria-label\", \"Submit\");\n submitButton.setAttribute(\"data-aia-submit\", \"\");\n submitButton.innerHTML = SUBMIT_SVG;\n inputWrapper.appendChild(submitButton);\n submitTarget = submitButton;\n } else if (opts.submitButton !== null) {\n submitTarget = opts.submitButton;\n if (!submitTarget.hasAttribute(\"data-aia-submit\")) {\n submitTarget.setAttribute(\"data-aia-submit\", \"\");\n }\n inputWrapper.appendChild(submitTarget);\n }\n\n // --- Event wiring ---\n\n // Click wrapper → focus textarea\n inputWrapper.addEventListener(\"click\", () => textarea.focus());\n\n // Textarea change\n textarea.addEventListener(\"input\", () => {\n const raw = textarea.value;\n const shouldCapitalize = raw.length > 0 && raw[0] !== raw[0].toUpperCase();\n const newValue = shouldCapitalize ? raw[0].toUpperCase() + raw.slice(1) : raw;\n opts.handleChange(newValue);\n });\n\n // Keyboard\n textarea.addEventListener(\"keydown\", (e) => opts.handleKeyDown(e));\n\n // Focus tracking — auto-trigger uses this to open dropdown when focused\n textarea.addEventListener(\"focus\", () => opts.store.set({ isFocused: true }));\n textarea.addEventListener(\"blur\", () => opts.store.set({ isFocused: false }));\n\n // Submit click — wired on whatever element fills the slot (default or custom)\n if (submitTarget) {\n submitTarget.addEventListener(\"click\", (e) => {\n const state = opts.store.get();\n const canSubmit = !!state.text || state.completedParams.length > 0;\n if (!canSubmit || !opts.onSubmit) return;\n e.stopPropagation();\n const { rawQuery, completedParams: finalParams } = buildQuery(\n state.text,\n state.completedParams,\n );\n opts.onSubmit({\n query: state.text.trim(),\n raw_query: rawQuery,\n completed_params: finalParams,\n });\n });\n }\n\n // Focus textarea on mount\n if (opts.autoFocus !== false) {\n textarea.focus();\n }\n\n return { textarea, dropdown, sizer, submitButton, inlinePillContainer };\n}\n\nexport function updateDOM(refs: DOMRefs, state: CoreState, opts: RenderInputOptions) {\n const { textarea, dropdown, sizer, submitButton, inlinePillContainer } = refs;\n const { pillPlacement, setActivePill, selectOption, store } = opts;\n\n // Textarea value\n if (textarea.value !== state.text) {\n textarea.value = state.text;\n }\n\n // Placeholder\n if (state.placeholderText) {\n textarea.placeholder = state.placeholderText;\n } else {\n textarea.removeAttribute(\"placeholder\");\n }\n\n // ARIA\n textarea.setAttribute(\"aria-expanded\", String(state.isDropdownOpen));\n const activeDescendant =\n state.activeDropdownIndex >= 0 ? `${opts.listboxId}-option-${state.activeDropdownIndex}` : \"\";\n if (activeDescendant) {\n textarea.setAttribute(\"aria-activedescendant\", activeDescendant);\n } else {\n textarea.removeAttribute(\"aria-activedescendant\");\n }\n\n // Shimmer: hide textarea text during animation\n if (state.newParamId) {\n textarea.classList.add(\"magicx-aia-textarea--hidden\");\n } else {\n textarea.classList.remove(\"magicx-aia-textarea--hidden\");\n }\n\n // Submit button disabled state — only applies to the default built-in button.\n // Consumer-provided buttons own their own disabled visuals.\n if (submitButton) {\n const canSubmit = !!state.text || state.completedParams.length > 0;\n submitButton.disabled = !canSubmit;\n }\n\n // Segments overlay\n renderSegments(sizer, state.segments, state.newParamId, !state.text, state.placeholderText);\n\n // Inline pills\n if (pillPlacement === \"inline\") {\n renderPills(inlinePillContainer, state.actionableSuggestions, 0, setActivePill);\n } else {\n // Clear inline pills in dropdown mode\n inlinePillContainer.innerHTML = \"\";\n }\n\n // Dropdown\n renderDropdown(dropdown, {\n suggestions:\n state.actionableSuggestions.length > 0\n ? [{ ...state.actionableSuggestions[0], options: state.filteredOptions }]\n : [],\n filteredOptions: state.filteredOptions,\n activeIndex: state.activeDropdownIndex,\n isOpen: state.isDropdownOpen,\n listboxId: opts.listboxId,\n pills: state.actionableSuggestions,\n showPills: pillPlacement === \"dropdown\",\n onSelect: selectOption,\n onHighlight: (i) => store.set({ activeDropdownIndex: i }),\n onPillClick: setActivePill,\n });\n}\n","export type Listener<S> = (next: S, prev: S) => void;\n\nexport interface Store<S> {\n get: () => S;\n set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;\n subscribe: (listener: Listener<S>) => () => void;\n}\n\nexport function createStore<S>(initial: S): Store<S> {\n let state = initial;\n const listeners = new Set<Listener<S>>();\n return {\n get: () => state,\n set: (patch) => {\n const resolved = typeof patch === \"function\" ? patch(state) : patch;\n const next = { ...state, ...resolved };\n const prev = state;\n state = next;\n for (const l of listeners) l(next, prev);\n },\n subscribe: (listener) => {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n","let injected = false;\n\n/** Inject core + appearance CSS into document.head once. Idempotent. */\nexport function injectStyles() {\n if (injected || typeof document === \"undefined\") return;\n if (document.querySelector(\"style[data-magicx-aia]\")) {\n injected = true;\n return;\n }\n injected = true;\n\n const style = document.createElement(\"style\");\n style.setAttribute(\"data-magicx-aia\", \"\");\n style.textContent = STYLES;\n document.head.appendChild(style);\n}\n\n// Replaced at build time by tsup.config.core.ts / vitest.config.ts\ndeclare const __MAGICX_AC_STYLES__: string;\nconst STYLES = __MAGICX_AC_STYLES__;\n","import type { AppearanceMode, CompletedParamState, Suggestion, SuggestionOption } from \"../types\";\nimport { extractFilterQuery, filterOptions, findPrefixOverlap } from \"../utils/filtering\";\nimport { ModeController } from \"../utils/modeController\";\nimport { deriveSegments, reconcileParams } from \"../utils/segments\";\nimport { FetchController } from \"./controllers/fetchController\";\nimport { KeyboardController } from \"./controllers/keyboardController\";\nimport { PillsController } from \"./controllers/pillsController\";\nimport { buildDropdownOnly, updateDropdownOnly } from \"./render/renderDropdownOnly\";\nimport { buildDOM, type DOMRefs, updateDOM } from \"./render/renderInput\";\nimport { createStore } from \"./state\";\nimport { injectStyles } from \"./styleInjector\";\nimport type { CoreOptions, CoreState, RenderMode } from \"./types\";\n\nlet idCounter = 0;\nfunction stableId(): string {\n return `:ac-${++idCounter}:`;\n}\n\nfunction initialState(): CoreState {\n return {\n text: \"\",\n completedParams: [],\n suggestions: [],\n activeDropdownIndex: -1,\n newParamId: null,\n isLoading: false,\n isReady: false,\n error: null,\n segments: [],\n actionableSuggestions: [],\n filteredOptions: [],\n placeholderText: \"\",\n isDropdownOpen: false,\n filterBase: 0,\n filterInProgress: false,\n pillTapped: false,\n skipNextFetch: false,\n lastRawQuery: \"\",\n isFocused: false,\n };\n}\n\nexport class AIAutocomplete {\n private store = createStore<CoreState>(initialState());\n private _listboxId = stableId();\n private opts: CoreOptions;\n private fetchController: FetchController;\n private keyboardController: KeyboardController;\n private pillsController: PillsController;\n private modeController: ModeController | null = null;\n private container: HTMLElement;\n private unsubscribers: (() => void)[] = [];\n private derivedInProgress = false;\n private renderMode: RenderMode;\n private domRefs: DOMRefs | null = null;\n private dropdownRefs: { dropdown: HTMLElement } | null = null;\n private newParamTimer: number | undefined;\n private suggestionRemovalTimer: number | undefined;\n private externalListeners = new Set<(state: CoreState) => void>();\n private sessionId: string = crypto.randomUUID();\n\n constructor(container: HTMLElement, opts: CoreOptions = {}) {\n this.container = container;\n this.opts = opts;\n this.renderMode = opts.renderMode ?? \"full\";\n\n // Apply controlled initial values\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n\n // Controllers\n this.pillsController = new PillsController(this.store);\n\n this.fetchController = new FetchController(\n this.store,\n () => this.opts.apiConfig,\n () => this.opts.optionOverrides,\n () => this.opts.maskCompletedText,\n () => this.opts.onError,\n () => this.sessionId,\n );\n\n this.keyboardController = new KeyboardController(this.store, {\n columns: opts.columns ?? 2,\n listboxId: this.listboxId,\n getOnSubmit: () => this.opts.onSubmit,\n selectOption: (option) => this.selectOption(option),\n });\n\n // Derived state recomputation\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n this.recomputeDerived(next, prev);\n }),\n );\n\n // Event callbacks\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.text !== prev.text) this.opts.onChange?.(next.text);\n if (next.completedParams !== prev.completedParams)\n this.opts.onParamsChange?.(next.completedParams);\n if (next.isFocused !== prev.isFocused) {\n if (next.isFocused) this.opts.onFocus?.();\n else this.opts.onBlur?.();\n }\n this.opts.onStateChange?.(next);\n }),\n );\n\n // Setup DOM based on render mode\n if (this.renderMode !== \"headless\") {\n injectStyles();\n this.setupContainer();\n }\n if (this.renderMode === \"full\") {\n this.buildAndRenderFull();\n } else if (this.renderMode === \"dropdown\") {\n this.buildAndRenderDropdown();\n }\n this.fetchController.start();\n }\n\n // === Public API ===\n\n focus() {\n this.domRefs?.textarea.focus();\n }\n\n blur() {\n this.domRefs?.textarea.blur();\n }\n\n reset() {\n // skipNextFetch suppresses the debounced fetch the FetchController would\n // otherwise schedule in response to text/params changing here — we issue\n // the empty fetch ourselves below so the new session starts immediately.\n this.store.set({\n ...initialState(),\n skipNextFetch: true,\n });\n this.sessionId = crypto.randomUUID();\n this.fetchController.doFetch(\"\", []);\n }\n\n destroy() {\n this.fetchController.dispose();\n this.modeController?.destroy();\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n if (this.suggestionRemovalTimer) clearTimeout(this.suggestionRemovalTimer);\n this.externalListeners.clear();\n for (const unsub of this.unsubscribers) unsub();\n this.unsubscribers = [];\n this.domRefs = null;\n this.dropdownRefs = null;\n if (this.renderMode !== \"headless\") {\n this.container.innerHTML = \"\";\n }\n }\n\n setMode(mode: AppearanceMode) {\n this.modeController?.setMode(mode);\n }\n\n setValue(text: string) {\n this.store.set({ text });\n }\n\n setCompletedParams(params: CompletedParamState[]) {\n this.store.set({ completedParams: params });\n }\n\n setActivePill(index: number) {\n this.pillsController.setActivePill(index);\n }\n\n removeLastParam() {\n this.pillsController.removeLastParam();\n }\n\n clearNewParamId() {\n this.store.set({ newParamId: null });\n }\n\n setActiveDropdownIndex(index: number) {\n this.store.set({ activeDropdownIndex: index });\n }\n\n handleTextChange(value: string) {\n this.handleChange(value);\n }\n\n handleKeyDown(e: KeyboardEvent) {\n this.keyboardController.handleKeyDown(e);\n }\n\n setFocused(focused: boolean) {\n if (this.store.get().isFocused === focused) return;\n this.store.set({ isFocused: focused });\n }\n\n /** Subscribe to state changes (fires after derived state is settled). Returns unsubscribe function. */\n subscribe(listener: (state: CoreState) => void): () => void {\n this.externalListeners.add(listener);\n return () => {\n this.externalListeners.delete(listener);\n };\n }\n\n getState(): CoreState {\n return this.store.get();\n }\n\n get listboxId(): string {\n return this._listboxId;\n }\n\n get isReady(): boolean {\n return this.store.get().isReady;\n }\n\n on(event: string, callback: (...args: unknown[]) => void): () => void {\n switch (event) {\n case \"submit\":\n this.opts.onSubmit = callback as CoreOptions[\"onSubmit\"];\n return () => {\n this.opts.onSubmit = undefined;\n };\n case \"error\":\n this.opts.onError = callback as CoreOptions[\"onError\"];\n return () => {\n this.opts.onError = undefined;\n };\n case \"change\":\n this.opts.onChange = callback as CoreOptions[\"onChange\"];\n return () => {\n this.opts.onChange = undefined;\n };\n case \"paramsChange\":\n this.opts.onParamsChange = callback as CoreOptions[\"onParamsChange\"];\n return () => {\n this.opts.onParamsChange = undefined;\n };\n case \"stateChange\":\n this.opts.onStateChange = callback as CoreOptions[\"onStateChange\"];\n return () => {\n this.opts.onStateChange = undefined;\n };\n case \"focus\":\n this.opts.onFocus = callback as CoreOptions[\"onFocus\"];\n return () => {\n this.opts.onFocus = undefined;\n };\n case \"blur\":\n this.opts.onBlur = callback as CoreOptions[\"onBlur\"];\n return () => {\n this.opts.onBlur = undefined;\n };\n default:\n return () => {};\n }\n }\n\n update(opts: Partial<CoreOptions>) {\n Object.assign(this.opts, opts);\n if (opts.mode !== undefined) {\n this.modeController?.setMode(opts.mode);\n }\n if (opts.optionsPosition !== undefined) {\n this.container.dataset.optionsPosition = opts.optionsPosition;\n }\n if (opts.animations !== undefined) {\n this.container.dataset.animations = opts.animations ? \"on\" : \"off\";\n }\n if (opts.pillPlacement !== undefined) {\n this.container.dataset.pillPlacement = opts.pillPlacement;\n this.store.set({});\n }\n if (opts.dropdownTrigger !== undefined || opts.closeDropdownOnBlur !== undefined) {\n // Trigger recompute so isDropdownOpen updates\n this.store.set({});\n }\n if (opts.value !== undefined) {\n this.store.set({ text: opts.value });\n }\n if (opts.completedParams !== undefined) {\n this.store.set({ completedParams: opts.completedParams });\n }\n }\n\n // === Public (for framework wrappers) ===\n\n selectOption(option: SuggestionOption) {\n const state = this.store.get();\n const activeSuggestion = state.actionableSuggestions[0];\n if (!activeSuggestion) return;\n\n const base = state.filterBase;\n let prefix = state.text.slice(0, base);\n\n const inputWasEmpty = prefix.length === 0 && state.text.length === 0;\n // The user is still typing within the server-provided placeholder (e.g. typed\n // \"Cre\" for placeholder \"Create a\"). Selecting an option here should keep the\n // placeholder rather than discard it — otherwise tapping \"email\" replaces\n // \"Cre\" with just \"email\" instead of \"Create a email\".\n const inputIsPlaceholderPrefix =\n prefix.length === 0 &&\n state.text.length > 0 &&\n state.placeholderText.length > 0 &&\n state.placeholderText.toLowerCase().startsWith(state.text.toLowerCase());\n if ((inputWasEmpty || inputIsPlaceholderPrefix) && state.placeholderText) {\n prefix = `${state.placeholderText} `;\n }\n\n const overlapChars = findPrefixOverlap(prefix, option.text);\n if (overlapChars > 0) {\n prefix = prefix.slice(0, prefix.length - overlapChars);\n }\n\n const needsSpace = prefix.length > 0 && prefix[prefix.length - 1] !== \" \";\n const newText = `${prefix}${needsSpace ? \" \" : \"\"}${option.text} `;\n const finalText =\n (inputWasEmpty || inputIsPlaceholderPrefix) && newText.length > 0\n ? newText[0].toUpperCase() + newText.slice(1)\n : newText;\n\n const optionStart = finalText.toLowerCase().lastIndexOf(option.text.toLowerCase());\n const optionInFinal =\n optionStart >= 0\n ? finalText.slice(optionStart, optionStart + option.text.length)\n : option.text;\n\n const completed: CompletedParamState = {\n id: crypto.randomUUID(),\n placeholder: \"\",\n type: activeSuggestion.type,\n text: optionInFinal,\n kind: option.kind,\n suggestionType: activeSuggestion.type,\n suggestionPlaceholder: activeSuggestion.text,\n options: activeSuggestion.options ?? [],\n metadata: option.metadata,\n };\n\n const remainingActionable = state.actionableSuggestions.length - 1;\n\n this.store.set((s) => ({\n text: finalText,\n filterBase: finalText.length,\n completedParams: [...s.completedParams, completed],\n newParamId: completed.id,\n pillTapped: false,\n activeDropdownIndex: -1,\n skipNextFetch: remainingActionable > 0,\n }));\n\n // Delay suggestion removal for animation\n this.suggestionRemovalTimer = window.setTimeout(() => {\n this.store.set((s) => ({\n suggestions: s.suggestions.filter((sg) => sg !== activeSuggestion),\n }));\n }, 400);\n }\n\n private recomputeDerived(next: CoreState, _prev: CoreState) {\n if (this.derivedInProgress) return;\n this.derivedInProgress = true;\n const segments = deriveSegments(next.text, next.completedParams);\n const actionableSuggestions = next.suggestions.filter((s) => s.type !== \"placeholder\");\n const activeSuggestion = actionableSuggestions[0] as Suggestion | undefined;\n const overrideFn = activeSuggestion\n ? this.opts.optionOverrides?.[activeSuggestion.type]\n : undefined;\n\n // Clamp filterBase so it never exceeds text length (matches old React behavior)\n const clampedFilterBase = Math.min(next.filterBase, next.text.length);\n // When filterBase is 0 and no fetch has set it yet, don't filter by typed text —\n // the user is still typing the initial query and no server context exists\n const hasServerContext = next.lastRawQuery !== \"\" || clampedFilterBase > 0;\n const filterQuery = hasServerContext\n ? extractFilterQuery(next.text, clampedFilterBase, next.filterInProgress)\n : \"\";\n const baseOptions = activeSuggestion\n ? overrideFn\n ? overrideFn(filterQuery.trim())\n : (activeSuggestion.options ?? [])\n : [];\n const filteredOptions = filterOptions(baseOptions, filterQuery);\n\n const placeholderText = next.suggestions\n .filter((s) => s.type === \"placeholder\")\n .map((s) => s.text)\n .join(\" \");\n\n const trigger = this.opts.dropdownTrigger ?? \"auto\";\n const closeOnBlur = this.opts.closeDropdownOnBlur ?? true;\n let isDropdownOpen = false;\n if (trigger === \"auto\") {\n const focusGate = closeOnBlur ? next.isFocused : true;\n isDropdownOpen = !next.isLoading && filteredOptions.length > 0 && focusGate;\n } else if (trigger === \"manual\") {\n isDropdownOpen = !next.isLoading && filteredOptions.length > 0 && next.pillTapped;\n }\n\n this.store.set({\n segments,\n actionableSuggestions,\n filteredOptions,\n placeholderText,\n isDropdownOpen,\n });\n this.derivedInProgress = false;\n\n // Notify external listeners after derived state is settled\n const settled = this.store.get();\n for (const listener of this.externalListeners) {\n listener(settled);\n }\n }\n\n private setupContainer() {\n this.container.classList.add(\"magicx-aia\");\n // In dropdown mode, pills are always in the dropdown\n this.container.dataset.pillPlacement =\n this.renderMode === \"dropdown\" ? \"dropdown\" : (this.opts.pillPlacement ?? \"inline\");\n this.container.dataset.optionsPosition = this.opts.optionsPosition ?? \"below\";\n this.container.dataset.animations = (this.opts.animations ?? true) ? \"on\" : \"off\";\n\n // ModeController\n this.modeController = new ModeController(this.container, this.opts.mode ?? \"auto\");\n }\n\n private buildAndRenderFull() {\n const self = this;\n const renderOpts = {\n store: this.store,\n listboxId: this.listboxId,\n get pillPlacement() {\n return (self.opts.pillPlacement ?? \"inline\") as \"inline\" | \"dropdown\";\n },\n get onSubmit() {\n return self.opts.onSubmit;\n },\n submitButton: this.opts.submitButton,\n autoFocus: this.opts.autoFocus ?? true,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n handleKeyDown: (e: KeyboardEvent) => this.keyboardController.handleKeyDown(e),\n handleChange: (value: string) => this.handleChange(value),\n };\n\n this.domRefs = buildDOM(this.container, renderOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.domRefs) {\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n }\n });\n\n // Initial render\n updateDOM(this.domRefs, this.store.get(), renderOpts);\n this.subscribeNewParamTimer();\n }\n\n private buildAndRenderDropdown() {\n const dropdownOpts = {\n store: this.store,\n listboxId: this.listboxId,\n selectOption: (option: SuggestionOption) => this.selectOption(option),\n setActivePill: (index: number) => this.pillsController.setActivePill(index),\n };\n\n this.dropdownRefs = buildDropdownOnly(this.container, dropdownOpts);\n\n this.subscribeBatchedRender(() => {\n if (this.dropdownRefs) {\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n }\n });\n\n // Initial render\n updateDropdownOnly(this.dropdownRefs, this.store.get(), dropdownOpts);\n this.subscribeNewParamTimer();\n }\n\n /** Batched render subscriber — coalesces multiple store.set calls into one DOM update. */\n private subscribeBatchedRender(render: () => void) {\n let scheduled = false;\n this.unsubscribers.push(\n this.store.subscribe(() => {\n if (scheduled) return;\n scheduled = true;\n queueMicrotask(() => {\n scheduled = false;\n render();\n });\n }),\n );\n }\n\n /** Auto-clear newParamId after shimmer animation. */\n private subscribeNewParamTimer() {\n this.unsubscribers.push(\n this.store.subscribe((next, prev) => {\n if (next.newParamId && next.newParamId !== prev.newParamId) {\n if (this.newParamTimer) clearTimeout(this.newParamTimer);\n this.newParamTimer = window.setTimeout(() => {\n this.store.set({ newParamId: null });\n }, 650);\n }\n }),\n );\n }\n\n private handleChange(newValue: string) {\n const state = this.store.get();\n this.store.set({\n text: newValue,\n pillTapped: false,\n activeDropdownIndex: -1,\n });\n\n const { valid, invalid } = reconcileParams(newValue, state.completedParams);\n if (invalid.length > 0) {\n this.store.set((s) => ({\n completedParams: valid,\n suggestions: [\n ...invalid.map((param) => ({\n type: param.suggestionType,\n text: param.suggestionPlaceholder,\n required: true,\n options: param.options,\n })),\n ...s.suggestions,\n ],\n }));\n }\n }\n}\n"],"mappings":"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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;ECNf,IAAIC,GAAY,EAChB,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","names":["index_exports","__export","AIAutocomplete","createStore","__toCommonJS","extractFilterQuery","text","filterBase","isInProgress","rawRegion","spaceIdx","findPrefixOverlap","prefix","optionText","trimmed","words","optionLower","i","candidate","suffixStart","filterOptions","options","query","lower","o","findExactMatch","ModeController","container","mode","deriveSegments","text","completedParams","result","pos","param","idx","remaining","reconcileParams","valid","invalid","TokenManager","config","forceRefresh","result","SDK_VERSION","hasWarnedMissingKey","generateRequestId","toWireParam","param","includeText","isAccessTokenConfig","config","getApiKeyConfig","tokenManagers","getTokenManager","manager","TokenManager","buildRequestBody","rawQuery","completedParams","sessionId","rawCount","p","contactAccountCount","buildHeaders","apiConfig","doFetch","endpoint","headers","token","body","signal","fetchSuggestions","options","jsonBody","response","newToken","apiKeyConfig","apiKey","authScheme","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","FetchController","store","getApiConfig","getOptionOverrides","getMaskCompletedText","getOnError","getSessionId","prevText","prevParams","next","rawQuery","completed","controller","version","state","textAtRequest","s","res","fetchSuggestions","newSuggestions","applyOptionOverrides","input","lastInput","currentText","filterBase","filterInProgress","inProgressIdx","active","extraParam","query","extractFilterQuery","match","findExactMatch","err","caughtError","attemptFetch","minDiff","currentQuery","sg","tappableFiltered","filterOptions","o","hasExactMatch","isInFilterZone","placeholderText","updatedParams","buildQuery","isDeleting","charDiff","KeyboardController","store","ctx","state","listboxId","getOnSubmit","columns","onSubmit","tappableIndices","target","currentPos","nextPos","prevPos","rightNeighbor","leftNeighbor","rawQuery","finalParams","buildQuery","placeholderVisible","hasHighlightedOption","placeholderSuggestion","s","sg","firstTappableIdx","o","tappable","i","buckets","grid","tracks","index","options","optionEl","actionable","moved","rest","_","placeholders","PillsController","store","index","state","actionable","s","moved","rest","_","i","placeholders","lastParam","restoredSuggestion","getPillOpacity","index","renderPills","container","pills","activePillIndex","onSelectPill","rounded","list","existing","btn","used","i","pill","key","createDropdown","listboxId","dropdown","e","renderDropdown","state","filteredOptions","activeIndex","isOpen","pills","showPills","onSelect","onHighlight","onPillClick","hasPills","pillBar","renderPills","grid","renderOptions","options","optionsKey","o","lastKey","listChanged","fragment","i","option","item","createOptionElement","items","isHighlighted","index","classes","streaks","streaksVert","content","tag","buildDropdownOnly","container","opts","dropdown","createDropdown","updateDropdownOnly","refs","state","renderDropdown","renderSegments","sizer","segments","newParamId","isEmpty","placeholderText","sizerText","placeholder","segmentKey","s","lastKey","lastParamId","seg","span","SUBMIT_SVG","buildDOM","container","opts","listboxId","dropdown","createDropdown","inputWrapper","editor","sizer","inlinePillContainer","textarea","submitButton","submitTarget","raw","newValue","e","state","rawQuery","finalParams","buildQuery","updateDOM","refs","pillPlacement","setActivePill","selectOption","store","activeDescendant","canSubmit","renderSegments","renderPills","renderDropdown","i","createStore","initial","state","listeners","patch","resolved","next","prev","l","listener","injected","injectStyles","style","STYLES","idCounter","stableId","initialState","AIAutocomplete","container","opts","createStore","PillsController","FetchController","KeyboardController","option","next","prev","injectStyles","unsub","mode","text","params","index","value","focused","listener","event","callback","state","activeSuggestion","base","prefix","inputWasEmpty","inputIsPlaceholderPrefix","overlapChars","findPrefixOverlap","needsSpace","newText","finalText","optionStart","optionInFinal","completed","remainingActionable","s","sg","_prev","segments","deriveSegments","actionableSuggestions","overrideFn","clampedFilterBase","filterQuery","extractFilterQuery","baseOptions","filteredOptions","filterOptions","placeholderText","trigger","closeOnBlur","isDropdownOpen","focusGate","settled","ModeController","self","renderOpts","e","buildDOM","updateDOM","dropdownOpts","buildDropdownOnly","updateDropdownOnly","render","scheduled","newValue","valid","invalid","reconcileParams","param"]}
|