@magicx-eng/ai-autocomplete-react 0.7.0 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +127 -2
- package/dist/index.d.mts +79 -4
- package/dist/index.d.ts +79 -4
- package/dist/index.js +225 -24
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +225 -24
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -246,9 +246,110 @@ function App() {
|
|
|
246
246
|
| `completedParams?` | `CompletedParamState[]` | — | Controlled completed params. |
|
|
247
247
|
| `onChange?` | `(value: string) => void` | — | Called when text changes (controlled mode). |
|
|
248
248
|
| `onParamsChange?` | `(params: CompletedParamState[]) => void` | — | Called when params change (controlled mode). |
|
|
249
|
+
| `products?` | `ProductsConfig` | — | Opt-in product strip — see [Product strip](#product-strip). Omit it and nothing about the dropdown changes. |
|
|
250
|
+
| `onProductSelect?` | `(product: Product) => void` | — | Called when a product card is activated. The SDK never navigates. |
|
|
249
251
|
| `submitButton?` | `ReactNode` | — | Custom submit button. Pass any `ReactNode` to replace the default arrow button. Pass `null` to render no button. Clicks bubble up and trigger submit, so consumer-supplied buttons work without re-wiring `onClick`. |
|
|
250
252
|
| `ref?` | `Ref<AIAutocompleteHandle>` | — | Imperative handle with `focus()`, `blur()`, `reset()`, and `setMode()`. |
|
|
251
253
|
|
|
254
|
+
#### Product strip
|
|
255
|
+
|
|
256
|
+
Opt in with `products` and the dropdown renders a horizontal row of product
|
|
257
|
+
cards below the options grid. Every platform (Shopify today, others later) has
|
|
258
|
+
its own search endpoint and its own response shape, so the SDK owns the UI and
|
|
259
|
+
the integration owns only the fetching and the mapping.
|
|
260
|
+
|
|
261
|
+
```tsx
|
|
262
|
+
import { AIAutocomplete, type Product } from "@magicx-eng/ai-autocomplete-react";
|
|
263
|
+
|
|
264
|
+
const products = {
|
|
265
|
+
// You own the request entirely — auth headers, GraphQL body, locale
|
|
266
|
+
// prefixes. Honour the signal: the SDK aborts it as soon as a newer query
|
|
267
|
+
// supersedes this one.
|
|
268
|
+
fetch: (query: string, signal: AbortSignal) =>
|
|
269
|
+
fetch(`/api/products?q=${encodeURIComponent(query)}`, { signal }).then((r) => r.json()),
|
|
270
|
+
|
|
271
|
+
// Pure mapping, kept out of `fetch` so you can unit-test it without a
|
|
272
|
+
// network.
|
|
273
|
+
transform: (raw: unknown): Product[] =>
|
|
274
|
+
(raw as ApiResponse).items.map((item) => ({
|
|
275
|
+
id: item.id,
|
|
276
|
+
title: item.title,
|
|
277
|
+
url: item.url,
|
|
278
|
+
imageUrl: item.image?.src ?? null, // null renders the placeholder tile
|
|
279
|
+
price: formatMoney(item.price), // you know the currency
|
|
280
|
+
vendor: item.brand,
|
|
281
|
+
})),
|
|
282
|
+
|
|
283
|
+
limit: 8, // applied by the SDK, after transform
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
<AIAutocomplete
|
|
287
|
+
onSubmit={handleSubmit}
|
|
288
|
+
products={products}
|
|
289
|
+
// Selection emits — the SDK never navigates.
|
|
290
|
+
onProductSelect={(product) => router.push(product.url)}
|
|
291
|
+
/>;
|
|
292
|
+
```
|
|
293
|
+
|
|
294
|
+
`Product` is exactly six fields; only `id`, `title` and `url` are required:
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
type Product = {
|
|
298
|
+
id: string;
|
|
299
|
+
title: string;
|
|
300
|
+
url: string;
|
|
301
|
+
imageUrl?: string | null;
|
|
302
|
+
price?: string;
|
|
303
|
+
vendor?: string;
|
|
304
|
+
};
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**What the SDK guarantees**
|
|
308
|
+
|
|
309
|
+
- **One fetch cadence.** The product search rides the same debounce, the same
|
|
310
|
+
`AbortController` and the same version guard as `/suggest` — there is no
|
|
311
|
+
second timer to drift out of step.
|
|
312
|
+
- **Empty queries never reach you.** On mount and after `reset()` the strip
|
|
313
|
+
clears.
|
|
314
|
+
- **Out-of-order responses are dropped.** A slow response for an older query is
|
|
315
|
+
never rendered over a newer one.
|
|
316
|
+
- **Failure is silent.** A rejected `fetch` or a throwing `transform` clears the
|
|
317
|
+
strip, logs once, and leaves the suggestions half untouched — no `error`
|
|
318
|
+
state, no `onError`, no effect on `isLoading`.
|
|
319
|
+
- **The two halves are independent.** The panel opens if *either* has content,
|
|
320
|
+
so products keep it open when option filtering empties the option list.
|
|
321
|
+
`dropdownTrigger` (`manual` / `hidden`) still gates the panel as before.
|
|
322
|
+
- **Inline configs are safe.** `products={{ fetch, transform }}` written inline
|
|
323
|
+
re-creates the object on every render; the hook forwards through a stable
|
|
324
|
+
proxy, so only turning the strip on or off reaches the core. Two deliberate
|
|
325
|
+
consequences: swapping one live config for another leaves the previous
|
|
326
|
+
integration's cards up until the next request replaces them (toggle
|
|
327
|
+
`products` off and back on to clear immediately), and turning the strip on
|
|
328
|
+
mid-session shows nothing until the next `/suggest` request fires — the
|
|
329
|
+
product search rides that one scheduler, and enabling the strip doesn't
|
|
330
|
+
itself change the query.
|
|
331
|
+
|
|
332
|
+
**Selection and links.** Cards are real `<a href>` elements, so cmd/ctrl-click,
|
|
333
|
+
middle-click and "copy link address" behave natively. A plain left click is
|
|
334
|
+
intercepted (`preventDefault`) and emits `onProductSelect` instead.
|
|
335
|
+
|
|
336
|
+
`product.url` is used verbatim — the SDK trusts your `transform` output and
|
|
337
|
+
does not sanitise it, so validate the URL there if the platform response isn't
|
|
338
|
+
fully under your control. (Angular additionally runs its own `[href]`
|
|
339
|
+
sanitiser, so unrecognised schemes like `myapp://…` are rewritten to
|
|
340
|
+
`unsafe:…` in that package only.)
|
|
341
|
+
|
|
342
|
+
**Accessibility.** The strip is a `role="group"` labelled "Products"; each card
|
|
343
|
+
is a `role="option"` in the tab order, activated with Enter or Space, with a
|
|
344
|
+
visible focus ring. Tabbing into the strip does not close the panel. The row
|
|
345
|
+
scrolls horizontally by trackpad, wheel, touch and keyboard; the page never
|
|
346
|
+
scrolls sideways and the scrollbar chrome is hidden in all engines.
|
|
347
|
+
|
|
348
|
+
Tier 2 gets the same thing: pass `products` / `onProductSelect` to
|
|
349
|
+
`useAIAutocomplete()` and the strip renders inside `<AIAutocompleteDropdown />`
|
|
350
|
+
via `dropdownProps`. Tier 3 consumers read `products` from the hook and call
|
|
351
|
+
`selectProduct(product)` from their own cards.
|
|
352
|
+
|
|
252
353
|
#### Custom submit button
|
|
253
354
|
|
|
254
355
|
```tsx
|
|
@@ -329,6 +430,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
329
430
|
| `isDropdownOpen` | `boolean` | Whether the dropdown should be visible. Drive your own dropdown's visibility with this in Tier 3. |
|
|
330
431
|
| `placeholderText` | `string` | Suggested placeholder text for the current step. |
|
|
331
432
|
| `error` | `Error \| null` | Last fetch error. |
|
|
433
|
+
| `products` | `Product[]` | Results of the latest product search. Empty unless `products` is configured. Already spread into `dropdownProps` — read it directly only if you render your own strip. |
|
|
332
434
|
|
|
333
435
|
**Actions**
|
|
334
436
|
|
|
@@ -338,6 +440,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
338
440
|
| `removeLastParam` | `() => void` | Remove the last completed param from state. The text stays in the input as plain text. |
|
|
339
441
|
| `clearNewParamId` | `() => void` | Clear shimmer animation state. |
|
|
340
442
|
| `reset` | `() => void` | Clear all state, re-fetch, and start a new session (rotates `session_id`). Call this after handling submit. |
|
|
443
|
+
| `selectProduct` | `(product: Product) => void` | Announce a product selection (fires `onProductSelect`). The built-in dropdown calls this for you; hand-rolled strips call it themselves. Never navigates. |
|
|
341
444
|
|
|
342
445
|
**Input forwarding (custom inputs)** — call these instead of spreading `inputProps` when your input isn't a `<textarea>` (contentEditable / rich-text editors):
|
|
343
446
|
|
|
@@ -353,7 +456,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
353
456
|
| Field | Type | Description |
|
|
354
457
|
|---|---|---|
|
|
355
458
|
| `inputProps` | `object` | Spread onto a `<textarea>`. Includes `value`, `placeholder`, `onChange`, `onKeyDown`, and ARIA attributes. |
|
|
356
|
-
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Carries the options, `activeIndex`, `onSelect` / `onHighlight`, pills, open state, and `
|
|
459
|
+
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Carries the options, `activeIndex`, `onSelect` / `onHighlight`, pills, open state, `optionsPosition`, and the product strip's `products` / `onProductSelect` / `onProductFocusChange` — read these directly to render your own dropdown in Tier 3. |
|
|
357
460
|
|
|
358
461
|
### `<AIAutocompleteDropdown />`
|
|
359
462
|
|
|
@@ -373,6 +476,9 @@ The dropdown component for Tier 2. Spread `dropdownProps` from the hook (and add
|
|
|
373
476
|
| `pills?` | `Suggestion[]` | Pills to render inside the dropdown. |
|
|
374
477
|
| `onPillClick?` | `(index: number) => void` | Called when a pill is clicked. |
|
|
375
478
|
| `showPills?` | `boolean` | Whether to render pills. Default: `true`. |
|
|
479
|
+
| `products?` | `Product[]` | Product cards to render below the options grid. Empty (the default) renders no strip. |
|
|
480
|
+
| `onProductSelect?` | `(product: Product) => void` | Called when a card is activated. |
|
|
481
|
+
| `onProductFocusChange?` | `(focused: boolean) => void` | Called when focus enters/leaves the strip. Wired to `setFocused` by `dropdownProps` so a tabbed-to card doesn't close the panel. |
|
|
376
482
|
| `isLoading?` | `boolean` | When `true`, the dropdown renders its pills + options as a skeleton: text masked, layout (count and widths) preserved, shimmer pulse animating. Falls back to a generic 3-bar placeholder when no pills/options are cached. |
|
|
377
483
|
|
|
378
484
|
### `AutocompleteResult`
|
|
@@ -431,6 +537,21 @@ Override on the container (via `className`). All defaults use `:where()` (zero s
|
|
|
431
537
|
| `--aia-scrollbar-thumb` | `rgba(0, 0, 0, 0.3)` | `rgba(0, 0, 0, 0.3)` | Color of the option list's scrollbar thumb (Firefox + WebKit). |
|
|
432
538
|
| `--aia-streak-rgb` | `99, 102, 241` | `255, 255, 255` | Comma-separated RGB triplet used to tint the option-selection streak animation (consumed via `rgba(var(--aia-streak-rgb), …)`). |
|
|
433
539
|
| `--aia-streak-glass-bg` | `rgba(99, 102, 241, 0.1)` | `rgba(255, 255, 255, 0.1)` | Background fill for the streak's glass-pill effect. |
|
|
540
|
+
| `--aia-product-card-width` | `116px` | `116px` | Width of a product card in the strip. The media tile is square, so this also sets its height. |
|
|
541
|
+
| `--aia-product-gap` | `8px` | `8px` | Gap between product cards. |
|
|
542
|
+
| `--aia-product-bg` | `transparent` | `transparent` | Product card background. |
|
|
543
|
+
| `--aia-product-bg-active` | `--aia-option-bg` | `--aia-option-bg` | Product card background on hover. |
|
|
544
|
+
| `--aia-product-media-bg` | `--aia-skeleton-bg` | `--aia-skeleton-bg` | Fill behind the product image, and of the placeholder tile when a product has no image. |
|
|
545
|
+
| `--aia-product-placeholder-color` | `--aia-option-color` | `--aia-option-color` | Glyph color of the no-image placeholder tile. |
|
|
546
|
+
| `--aia-product-title-color` | `--aia-option-color-selected` | `--aia-option-color-selected` | Product title text. Follows the option colors by default, so theming the panel moves suggestions and products together. |
|
|
547
|
+
| `--aia-product-price-color` | `--aia-option-color-selected` | `--aia-option-color-selected` | Product price text. |
|
|
548
|
+
| `--aia-product-vendor-color` | `--aia-option-color` | `--aia-option-color` | Product vendor line. |
|
|
549
|
+
| `--aia-product-focus-ring` | `--aia-option-color-selected` | `--aia-option-color-selected` | Focus ring drawn on a keyboard-focused card. |
|
|
550
|
+
| `--aia-products-label-color` | `--aia-option-color` | `--aia-option-color` | "Products" section label. |
|
|
551
|
+
| `--aia-product-title-font-size` | `12px` | `12px` | Product title font size. |
|
|
552
|
+
| `--aia-product-price-font-size` | `11px` | `11px` | Product price font size. |
|
|
553
|
+
| `--aia-product-vendor-font-size` | `10px` | `10px` | Product vendor font size. |
|
|
554
|
+
| `--aia-products-label-font-size` | `11px` | `11px` | Section label font size. |
|
|
434
555
|
| `--aia-skeleton-bg` | `rgba(189, 189, 189, 0.25)` | `#1a1b1d` | Fill color for the loading skeleton bars and the masked text in cached pills/options. |
|
|
435
556
|
|
|
436
557
|
Legacy `--aia-color-*` variables are still supported as fallbacks.
|
|
@@ -459,7 +580,11 @@ For styling beyond the CSS variables, target these stable `data-aia-*` attribute
|
|
|
459
580
|
| `[data-aia-pill]` | Each unfilled-suggestion pill |
|
|
460
581
|
| `[data-aia-pillbar]` | Pill bar container inside the dropdown |
|
|
461
582
|
| `[data-aia-option]` | Each suggestion option |
|
|
462
|
-
| `[data-aia-dropdown]` | The dropdown root (listbox) |
|
|
583
|
+
| `[data-aia-dropdown]` | The dropdown root (listbox). Carries `data-aia-has-products` while the product strip has cards. |
|
|
584
|
+
| `[data-aia-products]` | Product strip section (label + row) |
|
|
585
|
+
| `[data-aia-products-row]` | The horizontally scrolling row of cards |
|
|
586
|
+
| `[data-aia-product]` | Each product card |
|
|
587
|
+
| `[data-aia-product-placeholder]` | Media tile of a card whose product has no image |
|
|
463
588
|
|
|
464
589
|
Completed params render as inline `<strong>` elements inside the editor. Override their weight with `[data-aia-input] strong { font-weight: 700; }` (the built-in style uses `:where()` so any consumer selector wins without `!important`).
|
|
465
590
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, Suggestion, SuggestionOption, SkippedParamState, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
2
|
-
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Segment, SkippedParamState, Suggestion, SuggestionOption, TaskKind, buildSubmitResult, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
1
|
+
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, ProductsConfig, Product, Suggestion, SuggestionOption, SkippedParamState, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
2
|
+
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Product, ProductsConfig, Segment, SkippedParamState, Suggestion, SuggestionOption, TaskKind, buildSubmitResult, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ReactNode, KeyboardEvent, ChangeEvent } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
@@ -42,6 +42,32 @@ interface AIAutocompleteProps {
|
|
|
42
42
|
completedParams?: CompletedParamState[];
|
|
43
43
|
onChange?: (value: string) => void;
|
|
44
44
|
onParamsChange?: (params: CompletedParamState[]) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Opt-in product strip. When set, the dropdown renders a horizontal row of
|
|
47
|
+
* product cards below the options grid, fed by your own search endpoint on
|
|
48
|
+
* the SDK's existing fetch cadence. Omit it and nothing about the dropdown
|
|
49
|
+
* changes — no request, no markup, no layout shift.
|
|
50
|
+
*
|
|
51
|
+
* The object may be re-created on every render: the hook forwards calls
|
|
52
|
+
* through a stable proxy, so only toggling the strip on or off reaches the
|
|
53
|
+
* core.
|
|
54
|
+
*
|
|
55
|
+
* Two consequences of that proxy, both deliberate:
|
|
56
|
+
* - Swapping one live config for another (A → B, both defined) can't be told
|
|
57
|
+
* apart from a re-render, so A's cards stay on screen until the next
|
|
58
|
+
* request replaces them. Toggle `products` off and back on to clear
|
|
59
|
+
* immediately.
|
|
60
|
+
* - Turning the strip on mid-session shows nothing until the next `/suggest`
|
|
61
|
+
* request fires, because the product search rides that one scheduler and
|
|
62
|
+
* enabling the strip doesn't itself change the query.
|
|
63
|
+
*/
|
|
64
|
+
products?: ProductsConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Called when the user activates a product card. The SDK does not navigate —
|
|
67
|
+
* you decide what a selection means. Modifier / middle clicks are left to the
|
|
68
|
+
* browser (so cmd-click still opens a tab) and don't fire this.
|
|
69
|
+
*/
|
|
70
|
+
onProductSelect?: (product: Product) => void;
|
|
45
71
|
/**
|
|
46
72
|
* Custom submit button. Pass any ReactNode to replace the default button.
|
|
47
73
|
* Pass `null` to render no button. Default (`undefined`) renders the built-in
|
|
@@ -75,6 +101,32 @@ interface UseAIAutocompleteOptions {
|
|
|
75
101
|
onFocus?: () => void;
|
|
76
102
|
/** Called when the input loses focus. */
|
|
77
103
|
onBlur?: () => void;
|
|
104
|
+
/**
|
|
105
|
+
* Opt-in product strip. When set, the dropdown renders a horizontal row of
|
|
106
|
+
* product cards below the options grid, fed by your own search endpoint on
|
|
107
|
+
* the SDK's existing fetch cadence. Omit it and nothing about the dropdown
|
|
108
|
+
* changes — no request, no markup, no layout shift.
|
|
109
|
+
*
|
|
110
|
+
* The object may be re-created on every render: the hook forwards calls
|
|
111
|
+
* through a stable proxy, so only toggling the strip on or off reaches the
|
|
112
|
+
* core.
|
|
113
|
+
*
|
|
114
|
+
* Two consequences of that proxy, both deliberate:
|
|
115
|
+
* - Swapping one live config for another (A → B, both defined) can't be told
|
|
116
|
+
* apart from a re-render, so A's cards stay on screen until the next
|
|
117
|
+
* request replaces them. Toggle `products` off and back on to clear
|
|
118
|
+
* immediately.
|
|
119
|
+
* - Turning the strip on mid-session shows nothing until the next `/suggest`
|
|
120
|
+
* request fires, because the product search rides that one scheduler and
|
|
121
|
+
* enabling the strip doesn't itself change the query.
|
|
122
|
+
*/
|
|
123
|
+
products?: ProductsConfig;
|
|
124
|
+
/**
|
|
125
|
+
* Called when the user activates a product card. The SDK does not navigate —
|
|
126
|
+
* you decide what a selection means. Modifier / middle clicks are left to the
|
|
127
|
+
* browser (so cmd-click still opens a tab) and don't fire this.
|
|
128
|
+
*/
|
|
129
|
+
onProductSelect?: (product: Product) => void;
|
|
78
130
|
value?: string;
|
|
79
131
|
completedParams?: CompletedParamState[];
|
|
80
132
|
onChange?: (value: string) => void;
|
|
@@ -120,6 +172,18 @@ interface UseAIAutocompleteReturn {
|
|
|
120
172
|
placeholderText: string;
|
|
121
173
|
listboxId: string;
|
|
122
174
|
error: Error | null;
|
|
175
|
+
/**
|
|
176
|
+
* Results of the latest product search. Always empty unless `products` is
|
|
177
|
+
* configured. Already spread into `dropdownProps` — read it directly only if
|
|
178
|
+
* you render your own strip.
|
|
179
|
+
*/
|
|
180
|
+
products: Product[];
|
|
181
|
+
/**
|
|
182
|
+
* Announce a product selection (fires `onProductSelect`). The built-in
|
|
183
|
+
* dropdown calls this for you; hand-rolled strips call it themselves. The SDK
|
|
184
|
+
* never navigates.
|
|
185
|
+
*/
|
|
186
|
+
selectProduct: (product: Product) => void;
|
|
123
187
|
/** Tier 1 helper: forward plain-text input to the core (autocapitalize handled). */
|
|
124
188
|
handleTextChange: (value: string) => void;
|
|
125
189
|
/** Tier 1 helper: forward keyboard events to the core. */
|
|
@@ -177,6 +241,17 @@ interface AIAutocompleteDropdownProps {
|
|
|
177
241
|
isLoading?: boolean;
|
|
178
242
|
/** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
|
|
179
243
|
isInputEmpty?: boolean;
|
|
244
|
+
/** Product cards to render below the options grid. Provided by `dropdownProps` from the hook. Empty (the default) renders no strip. */
|
|
245
|
+
products?: Product[];
|
|
246
|
+
/** Called when a product card is activated. Provided by `dropdownProps` from the hook. */
|
|
247
|
+
onProductSelect?: (product: Product) => void;
|
|
248
|
+
/**
|
|
249
|
+
* Called when focus moves into / out of the product strip. The panel closes
|
|
250
|
+
* on blur by default and the input blurs the instant a card takes focus, so
|
|
251
|
+
* without this a card is unreachable by Tab. Provided by `dropdownProps`
|
|
252
|
+
* from the hook (wired to `setFocused`).
|
|
253
|
+
*/
|
|
254
|
+
onProductFocusChange?: (focused: boolean) => void;
|
|
180
255
|
/**
|
|
181
256
|
* Where the dropdown opens relative to the input. When `"above"`, the dropdown
|
|
182
257
|
* positions itself above (and reverses its internal layout so options sit
|
|
@@ -200,8 +275,8 @@ interface AIAutocompleteDropdownProps {
|
|
|
200
275
|
|
|
201
276
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
202
277
|
|
|
203
|
-
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, activeSelected, isLoading, isInputEmpty, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
278
|
+
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, activeSelected, isLoading, isInputEmpty, products, onProductSelect, onProductFocusChange, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
204
279
|
|
|
205
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
280
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
206
281
|
|
|
207
282
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, Suggestion, SuggestionOption, SkippedParamState, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
2
|
-
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Segment, SkippedParamState, Suggestion, SuggestionOption, TaskKind, buildSubmitResult, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
1
|
+
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, ProductsConfig, Product, Suggestion, SuggestionOption, SkippedParamState, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
2
|
+
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Product, ProductsConfig, Segment, SkippedParamState, Suggestion, SuggestionOption, TaskKind, buildSubmitResult, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
3
3
|
import * as react from 'react';
|
|
4
4
|
import { ReactNode, KeyboardEvent, ChangeEvent } from 'react';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
@@ -42,6 +42,32 @@ interface AIAutocompleteProps {
|
|
|
42
42
|
completedParams?: CompletedParamState[];
|
|
43
43
|
onChange?: (value: string) => void;
|
|
44
44
|
onParamsChange?: (params: CompletedParamState[]) => void;
|
|
45
|
+
/**
|
|
46
|
+
* Opt-in product strip. When set, the dropdown renders a horizontal row of
|
|
47
|
+
* product cards below the options grid, fed by your own search endpoint on
|
|
48
|
+
* the SDK's existing fetch cadence. Omit it and nothing about the dropdown
|
|
49
|
+
* changes — no request, no markup, no layout shift.
|
|
50
|
+
*
|
|
51
|
+
* The object may be re-created on every render: the hook forwards calls
|
|
52
|
+
* through a stable proxy, so only toggling the strip on or off reaches the
|
|
53
|
+
* core.
|
|
54
|
+
*
|
|
55
|
+
* Two consequences of that proxy, both deliberate:
|
|
56
|
+
* - Swapping one live config for another (A → B, both defined) can't be told
|
|
57
|
+
* apart from a re-render, so A's cards stay on screen until the next
|
|
58
|
+
* request replaces them. Toggle `products` off and back on to clear
|
|
59
|
+
* immediately.
|
|
60
|
+
* - Turning the strip on mid-session shows nothing until the next `/suggest`
|
|
61
|
+
* request fires, because the product search rides that one scheduler and
|
|
62
|
+
* enabling the strip doesn't itself change the query.
|
|
63
|
+
*/
|
|
64
|
+
products?: ProductsConfig;
|
|
65
|
+
/**
|
|
66
|
+
* Called when the user activates a product card. The SDK does not navigate —
|
|
67
|
+
* you decide what a selection means. Modifier / middle clicks are left to the
|
|
68
|
+
* browser (so cmd-click still opens a tab) and don't fire this.
|
|
69
|
+
*/
|
|
70
|
+
onProductSelect?: (product: Product) => void;
|
|
45
71
|
/**
|
|
46
72
|
* Custom submit button. Pass any ReactNode to replace the default button.
|
|
47
73
|
* Pass `null` to render no button. Default (`undefined`) renders the built-in
|
|
@@ -75,6 +101,32 @@ interface UseAIAutocompleteOptions {
|
|
|
75
101
|
onFocus?: () => void;
|
|
76
102
|
/** Called when the input loses focus. */
|
|
77
103
|
onBlur?: () => void;
|
|
104
|
+
/**
|
|
105
|
+
* Opt-in product strip. When set, the dropdown renders a horizontal row of
|
|
106
|
+
* product cards below the options grid, fed by your own search endpoint on
|
|
107
|
+
* the SDK's existing fetch cadence. Omit it and nothing about the dropdown
|
|
108
|
+
* changes — no request, no markup, no layout shift.
|
|
109
|
+
*
|
|
110
|
+
* The object may be re-created on every render: the hook forwards calls
|
|
111
|
+
* through a stable proxy, so only toggling the strip on or off reaches the
|
|
112
|
+
* core.
|
|
113
|
+
*
|
|
114
|
+
* Two consequences of that proxy, both deliberate:
|
|
115
|
+
* - Swapping one live config for another (A → B, both defined) can't be told
|
|
116
|
+
* apart from a re-render, so A's cards stay on screen until the next
|
|
117
|
+
* request replaces them. Toggle `products` off and back on to clear
|
|
118
|
+
* immediately.
|
|
119
|
+
* - Turning the strip on mid-session shows nothing until the next `/suggest`
|
|
120
|
+
* request fires, because the product search rides that one scheduler and
|
|
121
|
+
* enabling the strip doesn't itself change the query.
|
|
122
|
+
*/
|
|
123
|
+
products?: ProductsConfig;
|
|
124
|
+
/**
|
|
125
|
+
* Called when the user activates a product card. The SDK does not navigate —
|
|
126
|
+
* you decide what a selection means. Modifier / middle clicks are left to the
|
|
127
|
+
* browser (so cmd-click still opens a tab) and don't fire this.
|
|
128
|
+
*/
|
|
129
|
+
onProductSelect?: (product: Product) => void;
|
|
78
130
|
value?: string;
|
|
79
131
|
completedParams?: CompletedParamState[];
|
|
80
132
|
onChange?: (value: string) => void;
|
|
@@ -120,6 +172,18 @@ interface UseAIAutocompleteReturn {
|
|
|
120
172
|
placeholderText: string;
|
|
121
173
|
listboxId: string;
|
|
122
174
|
error: Error | null;
|
|
175
|
+
/**
|
|
176
|
+
* Results of the latest product search. Always empty unless `products` is
|
|
177
|
+
* configured. Already spread into `dropdownProps` — read it directly only if
|
|
178
|
+
* you render your own strip.
|
|
179
|
+
*/
|
|
180
|
+
products: Product[];
|
|
181
|
+
/**
|
|
182
|
+
* Announce a product selection (fires `onProductSelect`). The built-in
|
|
183
|
+
* dropdown calls this for you; hand-rolled strips call it themselves. The SDK
|
|
184
|
+
* never navigates.
|
|
185
|
+
*/
|
|
186
|
+
selectProduct: (product: Product) => void;
|
|
123
187
|
/** Tier 1 helper: forward plain-text input to the core (autocapitalize handled). */
|
|
124
188
|
handleTextChange: (value: string) => void;
|
|
125
189
|
/** Tier 1 helper: forward keyboard events to the core. */
|
|
@@ -177,6 +241,17 @@ interface AIAutocompleteDropdownProps {
|
|
|
177
241
|
isLoading?: boolean;
|
|
178
242
|
/** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
|
|
179
243
|
isInputEmpty?: boolean;
|
|
244
|
+
/** Product cards to render below the options grid. Provided by `dropdownProps` from the hook. Empty (the default) renders no strip. */
|
|
245
|
+
products?: Product[];
|
|
246
|
+
/** Called when a product card is activated. Provided by `dropdownProps` from the hook. */
|
|
247
|
+
onProductSelect?: (product: Product) => void;
|
|
248
|
+
/**
|
|
249
|
+
* Called when focus moves into / out of the product strip. The panel closes
|
|
250
|
+
* on blur by default and the input blurs the instant a card takes focus, so
|
|
251
|
+
* without this a card is unreachable by Tab. Provided by `dropdownProps`
|
|
252
|
+
* from the hook (wired to `setFocused`).
|
|
253
|
+
*/
|
|
254
|
+
onProductFocusChange?: (focused: boolean) => void;
|
|
180
255
|
/**
|
|
181
256
|
* Where the dropdown opens relative to the input. When `"above"`, the dropdown
|
|
182
257
|
* positions itself above (and reverses its internal layout so options sit
|
|
@@ -200,8 +275,8 @@ interface AIAutocompleteDropdownProps {
|
|
|
200
275
|
|
|
201
276
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
202
277
|
|
|
203
|
-
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, activeSelected, isLoading, isInputEmpty, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
278
|
+
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, activeSelected, isLoading, isInputEmpty, products, onProductSelect, onProductFocusChange, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
204
279
|
|
|
205
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
280
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
206
281
|
|
|
207
282
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|