@magicx-eng/ai-autocomplete-react 0.6.8 → 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 +141 -3
- package/dist/index.d.mts +86 -4
- package/dist/index.d.ts +86 -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
|
|
@@ -318,6 +419,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
318
419
|
| Field | Type | Description |
|
|
319
420
|
|---|---|---|
|
|
320
421
|
| `completedParams` | `CompletedParamState[]` | Filled parameters. |
|
|
422
|
+
| `skippedParams` | `SkippedParamState[]` | Suggestions the user dismissed with <kbd>→</kbd>. Nothing renders them — pass them to `buildSubmitResult` for a hand-rolled submit. |
|
|
321
423
|
| `suggestionPills` | `Suggestion[]` | Unfilled suggestions (pills). First item is the active pill. |
|
|
322
424
|
| `segments` | `Segment[]` | Input text split into typed text vs completed params — completed segments render as bold `<strong>` runs inside the editor. |
|
|
323
425
|
| `newParamId` | `string \| null` | ID of the most recently added param (for shimmer animation). |
|
|
@@ -328,6 +430,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
328
430
|
| `isDropdownOpen` | `boolean` | Whether the dropdown should be visible. Drive your own dropdown's visibility with this in Tier 3. |
|
|
329
431
|
| `placeholderText` | `string` | Suggested placeholder text for the current step. |
|
|
330
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. |
|
|
331
434
|
|
|
332
435
|
**Actions**
|
|
333
436
|
|
|
@@ -337,6 +440,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
337
440
|
| `removeLastParam` | `() => void` | Remove the last completed param from state. The text stays in the input as plain text. |
|
|
338
441
|
| `clearNewParamId` | `() => void` | Clear shimmer animation state. |
|
|
339
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. |
|
|
340
444
|
|
|
341
445
|
**Input forwarding (custom inputs)** — call these instead of spreading `inputProps` when your input isn't a `<textarea>` (contentEditable / rich-text editors):
|
|
342
446
|
|
|
@@ -352,7 +456,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
|
|
|
352
456
|
| Field | Type | Description |
|
|
353
457
|
|---|---|---|
|
|
354
458
|
| `inputProps` | `object` | Spread onto a `<textarea>`. Includes `value`, `placeholder`, `onChange`, `onKeyDown`, and ARIA attributes. |
|
|
355
|
-
| `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. |
|
|
356
460
|
|
|
357
461
|
### `<AIAutocompleteDropdown />`
|
|
358
462
|
|
|
@@ -372,6 +476,9 @@ The dropdown component for Tier 2. Spread `dropdownProps` from the hook (and add
|
|
|
372
476
|
| `pills?` | `Suggestion[]` | Pills to render inside the dropdown. |
|
|
373
477
|
| `onPillClick?` | `(index: number) => void` | Called when a pill is clicked. |
|
|
374
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. |
|
|
375
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. |
|
|
376
483
|
|
|
377
484
|
### `AutocompleteResult`
|
|
@@ -380,7 +487,19 @@ The dropdown component for Tier 2. Spread `dropdownProps` from the hook (and add
|
|
|
380
487
|
|---|---|---|
|
|
381
488
|
| `query` | `string` | Plain text as the user sees it. |
|
|
382
489
|
| `raw_query` | `string` | Text with placeholder tokens (e.g. `"Create a {{TASK_1}}"`). |
|
|
383
|
-
| `completed_params` | `CompletedParam[]` | Filled parameter values. |
|
|
490
|
+
| `completed_params` | `CompletedParam[]` | Filled parameter values, followed by any the user skipped (see below). |
|
|
491
|
+
|
|
492
|
+
#### Skipped parameters
|
|
493
|
+
|
|
494
|
+
Pressing <kbd>→</kbd> at the end of the input dismisses the active pill. The dismissal is reported to the server — and included in `completed_params` here — as an entry with no placeholder and the sentinel text `"skipped"`:
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
{ placeholder: "", type: "goal", text: "skipped", kind: null }
|
|
498
|
+
```
|
|
499
|
+
|
|
500
|
+
Tier 2 consumers who build their own submit payload get the raw skips from the hook as `skippedParams`, and can fold them in the same way with the exported `buildSubmitResult(text, completedParams, skippedParams)`.
|
|
501
|
+
|
|
502
|
+
> **Reading `skippedParams` directly:** the array is append-only until `reset()`. The "drop a skip whose type got filled" rule is applied when the payload is built, not by pruning the array — so if the user skips `goal` and later fills one, the raw array still holds the `goal` entry. That's deliberate: the filter self-heals if they then delete that param's text, where pruning would discard the signal for good. `buildSubmitResult` applies the rule for you; to apply it elsewhere (say, a "you skipped X" badge), use the exported `withSkippedParams(completedParams, skippedParams)`.
|
|
384
503
|
|
|
385
504
|
---
|
|
386
505
|
|
|
@@ -418,6 +537,21 @@ Override on the container (via `className`). All defaults use `:where()` (zero s
|
|
|
418
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). |
|
|
419
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), …)`). |
|
|
420
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. |
|
|
421
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. |
|
|
422
556
|
|
|
423
557
|
Legacy `--aia-color-*` variables are still supported as fallbacks.
|
|
@@ -446,7 +580,11 @@ For styling beyond the CSS variables, target these stable `data-aia-*` attribute
|
|
|
446
580
|
| `[data-aia-pill]` | Each unfilled-suggestion pill |
|
|
447
581
|
| `[data-aia-pillbar]` | Pill bar container inside the dropdown |
|
|
448
582
|
| `[data-aia-option]` | Each suggestion option |
|
|
449
|
-
| `[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 |
|
|
450
588
|
|
|
451
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`).
|
|
452
590
|
|
package/dist/index.d.mts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
1
3
|
import * as react from 'react';
|
|
2
4
|
import { ReactNode, KeyboardEvent, ChangeEvent } from 'react';
|
|
3
|
-
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, Suggestion, SuggestionOption, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
4
|
-
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Segment, Suggestion, SuggestionOption, TaskKind } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
interface AIAutocompleteHandle {
|
|
@@ -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;
|
|
@@ -90,6 +142,13 @@ interface UseAIAutocompleteOptions {
|
|
|
90
142
|
}
|
|
91
143
|
interface UseAIAutocompleteReturn {
|
|
92
144
|
completedParams: CompletedParamState[];
|
|
145
|
+
/**
|
|
146
|
+
* Suggestions the user dismissed with the skip key (→). Not rendered
|
|
147
|
+
* anywhere — pass them to `buildSubmitResult` (or read them for your own
|
|
148
|
+
* telemetry) so a hand-rolled submit carries the same `text: "skipped"`
|
|
149
|
+
* entries the SDK's own requests do.
|
|
150
|
+
*/
|
|
151
|
+
skippedParams: SkippedParamState[];
|
|
93
152
|
suggestionPills: Suggestion[];
|
|
94
153
|
setActivePill: (index: number) => void;
|
|
95
154
|
removeLastParam: () => void;
|
|
@@ -113,6 +172,18 @@ interface UseAIAutocompleteReturn {
|
|
|
113
172
|
placeholderText: string;
|
|
114
173
|
listboxId: string;
|
|
115
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;
|
|
116
187
|
/** Tier 1 helper: forward plain-text input to the core (autocapitalize handled). */
|
|
117
188
|
handleTextChange: (value: string) => void;
|
|
118
189
|
/** Tier 1 helper: forward keyboard events to the core. */
|
|
@@ -170,6 +241,17 @@ interface AIAutocompleteDropdownProps {
|
|
|
170
241
|
isLoading?: boolean;
|
|
171
242
|
/** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
|
|
172
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;
|
|
173
255
|
/**
|
|
174
256
|
* Where the dropdown opens relative to the input. When `"above"`, the dropdown
|
|
175
257
|
* positions itself above (and reverses its internal layout so options sit
|
|
@@ -193,8 +275,8 @@ interface AIAutocompleteDropdownProps {
|
|
|
193
275
|
|
|
194
276
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
195
277
|
|
|
196
|
-
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;
|
|
197
279
|
|
|
198
|
-
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;
|
|
199
281
|
|
|
200
282
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
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';
|
|
1
3
|
import * as react from 'react';
|
|
2
4
|
import { ReactNode, KeyboardEvent, ChangeEvent } from 'react';
|
|
3
|
-
import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, Suggestion, SuggestionOption, Segment } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
4
|
-
export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, OptionOverrides, Segment, Suggestion, SuggestionOption, TaskKind } from '@magicx-eng/ai-autocomplete-vanilla';
|
|
5
5
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
6
6
|
|
|
7
7
|
interface AIAutocompleteHandle {
|
|
@@ -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;
|
|
@@ -90,6 +142,13 @@ interface UseAIAutocompleteOptions {
|
|
|
90
142
|
}
|
|
91
143
|
interface UseAIAutocompleteReturn {
|
|
92
144
|
completedParams: CompletedParamState[];
|
|
145
|
+
/**
|
|
146
|
+
* Suggestions the user dismissed with the skip key (→). Not rendered
|
|
147
|
+
* anywhere — pass them to `buildSubmitResult` (or read them for your own
|
|
148
|
+
* telemetry) so a hand-rolled submit carries the same `text: "skipped"`
|
|
149
|
+
* entries the SDK's own requests do.
|
|
150
|
+
*/
|
|
151
|
+
skippedParams: SkippedParamState[];
|
|
93
152
|
suggestionPills: Suggestion[];
|
|
94
153
|
setActivePill: (index: number) => void;
|
|
95
154
|
removeLastParam: () => void;
|
|
@@ -113,6 +172,18 @@ interface UseAIAutocompleteReturn {
|
|
|
113
172
|
placeholderText: string;
|
|
114
173
|
listboxId: string;
|
|
115
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;
|
|
116
187
|
/** Tier 1 helper: forward plain-text input to the core (autocapitalize handled). */
|
|
117
188
|
handleTextChange: (value: string) => void;
|
|
118
189
|
/** Tier 1 helper: forward keyboard events to the core. */
|
|
@@ -170,6 +241,17 @@ interface AIAutocompleteDropdownProps {
|
|
|
170
241
|
isLoading?: boolean;
|
|
171
242
|
/** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
|
|
172
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;
|
|
173
255
|
/**
|
|
174
256
|
* Where the dropdown opens relative to the input. When `"above"`, the dropdown
|
|
175
257
|
* positions itself above (and reverses its internal layout so options sit
|
|
@@ -193,8 +275,8 @@ interface AIAutocompleteDropdownProps {
|
|
|
193
275
|
|
|
194
276
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
195
277
|
|
|
196
|
-
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;
|
|
197
279
|
|
|
198
|
-
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;
|
|
199
281
|
|
|
200
282
|
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|