import type { APIConfig, AutocompleteResult, CompletedParamState, CustomFieldsReport, DateMonthView, DateRange, FormatType, IdentifiedParamState, MatchedItem, OptionOverrides, Product, ProductsConfig, Segment, SkippedParamState, Suggestion } from "@magicx-eng/ai-autocomplete-vanilla"; /** * Construction-time options for {@link AIAutocompleteController}. * * Mirrors the props the React `useAIAutocomplete()` hook accepts, minus the * fields that only make sense for a React component shell (`columns` is here; * `autoFocus`, `className`, `pillPlacement`, etc. live on the Tier 1 * `` component). * * @public */ export interface AIAutocompleteControllerOptions { /** Runtime API configuration (apiKey, endpoint, etc.). */ apiConfig?: APIConfig; /** * Optional user context. Include whatever you know about the user — a * profile, preferences, workspace, anything — to personalize suggested * parameters and options to them. */ additionalContext?: Record; /** * BCP 47 language tag (e.g. `"es"`), sent with every suggestion request. * Default: the browser language (`navigator.language`), else `"en-US"`. */ language?: string; /** * Your product id. When set, what the dropdown offers before anything is * typed is read from a cacheable URL for your product, with no credential, * instead of a suggestion request; it falls back to a suggestion request * when it cannot be read. */ productId?: string; /** * Stable id for this visitor, kept by the host across page loads. Rides on * telemetry events so searches can be joined to what the visitor does * afterwards. Must be a UUID v4; omit to send none. A function is called * only once the server has funnel telemetry on. */ visitorId?: string | (() => string | undefined); /** Per-suggestion-type client-side option overrides. */ optionOverrides?: OptionOverrides; /** When true, completed params' literal text is omitted from API requests. */ maskCompletedText?: boolean; /** Number of columns in the dropdown grid. Default: 2. */ columns?: number; /** * Where the dropdown opens relative to the input. Default: "below". * * Read by the keyboard controller to decide which vertical-arrow key opens * the dropdown from the input — ArrowDown when the dropdown is below, * ArrowUp when it's above. */ optionsPosition?: "above" | "below"; /** * When the dropdown appears. "auto" (default) shows when options are * available; "manual" shows only on pill tap; "hidden" never shows. */ dropdownTrigger?: "auto" | "manual" | "hidden"; /** When true (default), the dropdown closes if the input loses focus. */ closeDropdownOnBlur?: boolean; /** When true (default), non-tappable options render alongside tappable ones. */ showNonTappableOptions?: boolean; /** * SDK surface identifier — sent as meta.source on both /api/suggest and * telemetry events. Set automatically to "full-sdk" by the Tier 1 * `` component. Defaults to "headless-sdk". * @internal */ source?: "full-sdk" | "headless-sdk"; /** Called when the user submits (Enter key or `submit()` action). */ onSubmit?: (result: AutocompleteResult) => void; /** * Called after every successful suggestion round-trip with the structured * query as the SDK now understands it — the same `AutocompleteResult` shape * `onSubmit` delivers, so a consumer can mirror the query as it is built * (a live preview, a draft, analytics) without waiting for submit. * * Fires once per response that was applied, including the initial request * on construction (an empty result). Does not fire for a request that * failed, was aborted, or was superseded before it returned, and nothing * fires for a keystroke that hasn't been sent yet — read `getResult()` for * the current value on demand. */ onResult?: (result: AutocompleteResult) => void; /** Called when a fetch fails. */ onError?: (error: Error) => void; /** Called when the editor text changes (controlled-mode signal). */ onChange?: (text: string) => void; /** Called when completed params change (controlled-mode signal). */ onParamsChange?: (params: CompletedParamState[]) => void; /** Called when the input gains focus. */ onFocus?: () => void; /** Called when the input loses focus. */ onBlur?: () => void; /** * When true (default), the dropdown renders a horizontal row of product * cards below the options grid whenever it has products to show: by default * the items the `/suggest` response reports as matching the query, or the * results of a custom `products` search. Set to false to render no strip * and run no custom search. */ showProducts?: boolean; /** * Custom source for the product strip. Omit it and the strip shows the * items the `/suggest` response itself reports as matching the query, with * no extra request. Set it and the dropdown is fed by the integration's own * search endpoint on the SDK's existing fetch cadence instead; the server's * items are then not rendered. */ products?: ProductsConfig; /** * Runs synchronously with the SDK's cards and their response items in the same order. * The product strip shows the returned array. * Does not apply to a custom products integration. * A throw or a result that is not an array keeps the SDK's cards. */ mapProducts?: (products: Product[], items: MatchedItem[]) => Product[]; /** * Called when the user activates a product card. The SDK does not navigate — * the integration decides what a selection means. Modifier / middle clicks * are left to the browser (cmd-click still opens a tab) and don't fire this. */ onProductSelect?: (product: Product) => void; /** Initial controlled text value. */ value?: string; /** Initial controlled completed params. */ completedParams?: CompletedParamState[]; /** * Caret-set callback. Invoked by the core when re-edit / Backspace flows * need the editor caret parked at a specific plain-text offset. The Tier 1 * `` component wires this from its editor host; headless * consumers can leave it unset. * @internal */ setCursor?: (offset: number) => void; } /** * Subset of {@link AIAutocompleteControllerOptions} that can be changed after * construction. Excludes event callbacks (those are registered once at * construction — see vanilla `CoreUpdateOptions`). * * @public */ export type AIAutocompleteControllerUpdate = Partial>; /** * Snapshot of the controller's reactive state. Each field is also exposed as * a stand-alone observable on the controller (e.g. `controller.text$`). * * `suggestionPills` mirrors React's `suggestionPills` — the actionable * subset of `suggestions` ready for pill rendering. `isLoading` is the * UI-visible loading flag (suppressed during the post-select press * animation and during re-edit, where cached options stay visible). * * @public */ export interface AIAutocompleteControllerState { text: string; completedParams: CompletedParamState[]; /** * Suggestions the user dismissed with the skip key (→). Nothing renders * them — pass them to `buildSubmitResult` so a hand-rolled submit carries * the same `text: "skipped"` entries the SDK's own requests do. */ skippedParams: SkippedParamState[]; /** * Params the server identified in the user's own words. Already rendered * through `segments`; exposed so a hand-rolled submit can pass them to * `buildSubmitResult` and report the same `identified_params` the SDK's * own results carry. */ identifiedParams: IdentifiedParamState[]; suggestionPills: Suggestion[]; segments: Segment[]; newParamId: string | null; suggestions: Suggestion[]; /** * What the product strip shows: the items the latest `/suggest` response * reported as matching the query, or the results of a custom `products` * search. Already folded into the dropdown snapshot — read it here only * when rendering your own strip. */ products: Product[]; /** * The catalog grounding report the latest response carried, or null when it * carried none: which of the query's constraints the catalog applied, which * it dropped, and how many items (and which) the applied ones left * standing. Null is "no news", not an empty catalog. */ customFields: CustomFieldsReport | null; activeIndex: number; isLoading: boolean; isReady: boolean; isFocused: boolean; isDropdownOpen: boolean; placeholderText: string; error: Error | null; editingParam: CompletedParamState | null; /** * Set while the user is picking a date for a span the server identified as * one — "september 5th" in "fly to vegas on september 5th". Null otherwise. */ editingIdentified: { id: string; parameter: string; anchor: number; tail: number; /** The date the span was read as, or a range's start. Null when it couldn't be read. */ iso: string | null; /** The other end, when the span reads as a range rather than as one day. */ isoEnd: string | null; /** Whether that span is answered by a calendar, or a calendar in two taps. */ format: FormatType; } | null; editingAnchor: number | null; caretOffset: number | null; } /** * Composite state shape for the dropdown view layer. Tier 2 consumers bind * the dropdown component to this snapshot; Tier 1 uses the same shape * internally. * * @public */ export interface AIAutocompleteDropdownState { /** Active suggestion + filtered options to render in the grid. */ suggestions: Suggestion[]; /** Currently highlighted option index. -1 when none. */ activeIndex: number; /** Whether the dropdown should be visible. */ isOpen: boolean; /** Pills to render in the dropdown's pillbar (re-edit pill or all suggestion pills). */ pills: Suggestion[]; /** Whether the active pill renders selected (full opacity) vs. the `first` tier. */ isActivePillSelected: boolean; /** True when the dropdown should render its loading skeleton. */ isLoading: boolean; /** Whether the input has no typed text — the sole state that surfaces "tab to select" in the footer hint. */ isInputEmpty: boolean; /** Product cards to render below the options grid. Empty renders no strip. */ products: Product[]; /** * True while a completed param is being re-edited. The pillbar then shows * the param being re-edited — not skippable — so the skip button hides. * Optional (undefined ⇒ not editing) so existing consumer code constructing * this state — test fixtures, fake controllers — keeps compiling across the * minor bump that introduced it. */ isEditing?: boolean; /** * True for the ~170ms window after an option is selected, while the answered * suggestion animates out. `isLoading` is deliberately suppressed in that * window, but the core's `skipActivePill()` no-ops in it — the skip button * renders disabled off this flag instead of swallowing clicks silently. * Optional (undefined ⇒ false) for the same compile-compat reason as * `isEditing`. */ inSelectionAnimation?: boolean; /** * True while the loading skeleton fades out before the response's options * replace it. Optional (undefined ⇒ false) for the same compile-compat * reason as `isEditing`. */ skeletonExiting?: boolean; /** * Where the dropdown opens relative to the input — mirrors the controller's * `optionsPosition` option. `` reads it from here, so * placement is configured once on the controller (no separate input to sync). */ optionsPosition: "above" | "below"; /** * How the active pill is answered. `"date"` and `"date-range"` render a * calendar in place of the options grid, and `suggestions[0].options` then * carries that month's cells rather than the parameter's own options — the * core swaps them before they reach here. A `"date-range"` parameter is * answered by two taps of that calendar, a start and an end, committed as one * span. Optional (undefined ⇒ `"options"`) for the same compile-compat reason * as `isEditing`. */ formatType?: FormatType; /** The month the calendar shows. Null/undefined unless `formatType` is a calendar one. */ dateView?: DateMonthView | null; /** `YYYY-MM-DD` already held by the param being re-edited, so its cell reads as the current answer. */ selectedDateIso?: string | null; /** Both ends of a range param being re-edited, so both cells read as the current answer. */ selectedDateRange?: DateRange | null; /** The first end of a range picked so far, while the user chooses the second. */ dateRangeStart?: string | null; } //# sourceMappingURL=types.d.ts.map