@magicx-eng/ai-autocomplete-react 0.26.1 → 0.27.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 CHANGED
@@ -288,7 +288,7 @@ Skip `<AIAutocompleteDropdown />` and render the suggestions UI yourself. `dropd
288
288
 
289
289
  > **Option icons.** An option may carry an icon: `icon_svg` is inline SVG markup and `icon` its name. The built-in dropdown draws the SVG before the option's text, in the text color, and hides it while the row shows its loading skeleton. When rendering options yourself, pass `icon_svg` through the exported `sanitizeOptionIconSvg` before inserting it — it reduces the markup to plain vector drawing and returns `null` for anything else — and use `optionLabel(option)` for the text — it is the option's `text` alone; `icon` is the icon's name and is never shown as text, even when `icon_svg` is missing or fails to draw. A picked option's `icon` / `icon_svg` are copied onto its completed parameter, and the chip in the input draws the glyph before its text. Both surfaces can be switched off: `showOptionIcons: false` renders option rows as text only and `showChipIcons: false` renders chips as text only; either way the icon element is omitted rather than hidden.
290
290
 
291
- > **Option pictures and counts.** An option may also carry `image_url` — a picture of the best-matching catalog item offering it — and `item_count`, how many items offer it (each is present only when the server includes it; when it includes counts, the options also arrive ordered by them, most items first; a starting state carries pictures but no counts). The built-in dropdown draws the picture as a square thumbnail before the option's text (in place of its `icon_svg`, so a row never leads with two visuals) and the count as a muted label at the row's trailing edge (`"12 items"`); a skeleton row keeps the tile's placeholder fill and hides the count. The unit word after the number is a token: set `--aia-option-count-unit: "sneakers"` to name what is being counted, `--aia-option-count-unit-one: "sneaker"` for a count of 1 (it falls back to the plural token), or `--aia-option-count-unit: ""` for the number alone. When rendering options yourself, pass `image_url` through the exported `optionImageSrc` before using it as an `<img src>` — it returns the URL only when it is `http(s)` and `null` otherwise — and `formatOptionCount(option.item_count)` gives the number the built-in rows print (`null` when there is no count); `optionCountLabel(count, unit?)` appends a unit for a dropdown that prints the word itself (`"item"` / `"items"` by default; one word, a `{ one, other }` pair, or `""` for none). Both surfaces can be switched off: `showOptionImages: false` renders rows without pictures (an option's icon then draws instead) and `showOptionCounts: false` hides the counts. A picked option's `image_url` is copied onto its completed parameter too, and the chip in the input draws it as a small rounded tile before its text, in place of the icon; `showChipImages: false` renders chips without pictures (the icon then draws instead). The tile is sized by `--aia-option-image-size` (40px), rounded by `--aia-option-image-radius` (12px), spaced by `--aia-option-image-gap` (12px) and filled by `--aia-option-image-bg` while its picture loads; the count reads `--aia-option-count-font-size` (12px), `--aia-option-count-color` and `--aia-option-count-opacity` (0.6); the chip's tile reads `--aia-chip-image-size` (1.25em of the chip's font), `--aia-chip-image-radius` (4px) and `--aia-chip-image-bg`.
291
+ > **Option pictures and counts.** An option may also carry `image_url` — a picture of the best-matching catalog item offering it — and `item_count`, how many items offer it (each is present only when the server includes it; when it includes counts, the options also arrive ordered by them, most items first; a starting state carries pictures but no counts). The built-in dropdown draws the picture as a square thumbnail before the option's text (in place of its `icon_svg`, so a row never leads with two visuals) and the count as a muted label at the row's trailing edge (`"12 items"`); a skeleton row keeps the tile's placeholder fill and hides the count. The unit word after the number is a token: set `--aia-option-count-unit: "sneakers"` to name what is being counted, `--aia-option-count-unit-one: "sneaker"` for a count of 1 (it falls back to the plural token), or `--aia-option-count-unit: ""` for the number alone. When rendering options yourself, pass `image_url` through the exported `optionImageSrc` before using it as an `<img src>` — it returns the URL only when it is `http(s)` and `null` otherwise — and `formatOptionCount(option.item_count)` gives the number the built-in rows print (`null` when there is no count); `optionCountLabel(count, unit?)` appends a unit for a dropdown that prints the word itself (`"item"` / `"items"` by default; one word, a `{ one, other }` pair, or `""` for none). Both surfaces can be switched off: `showOptionImages: false` renders rows without pictures (an option's icon then draws instead) and `showOptionCounts: false` hides the counts. A picked option's `image_url` is copied onto its completed parameter too, and the chip in the input draws it as a small rounded tile before its text, in place of the icon; `showChipImages: false` renders chips without pictures (the icon then draws instead). The tile is sized by `--aia-option-image-size` (40px), rounded by `--aia-option-image-radius` (12px), spaced by `--aia-option-image-gap` (12px) and filled by `--aia-option-image-bg` (default: `--aia-skeleton-bg`) while its picture loads; the count reads `--aia-option-count-font-size` (12px), `--aia-option-count-color` and `--aia-option-count-opacity` (0.6); the chip's tile reads `--aia-chip-image-size` (1.25em of the chip's font), `--aia-chip-image-radius` (4px) and `--aia-chip-image-bg` (default: `--aia-skeleton-bg`).
292
292
 
293
293
  ```tsx
294
294
  import { useAIAutocomplete } from "@magicx-eng/ai-autocomplete-react";
@@ -365,6 +365,7 @@ function App() {
365
365
  | `onParamsChange?` | `(params: CompletedParamState[]) => void` | — | Called when params change (controlled mode). |
366
366
  | `showProducts?` | `boolean` | `true` | Render the product strip below the options whenever there are products to show — see [Product strip](#product-strip). Set to `false` to render no strip. |
367
367
  | `productsLayout?` | `"row" \| "list"` | `"row"` | How the strip lays its cards out: a horizontally scrolling row, or the same cards stacked as full-width rows — see [Product strip](#product-strip). |
368
+ | `productImageFallback?` | `"image" \| "initial"` | `"image"` | Fallback for a missing or blank product image URL, or an image load error. `"image"` shows the placeholder pictogram; `"initial"` shows the title initial. A working image still takes priority. See [Product strip](#product-strip). |
368
369
  | `products?` | `ProductsConfig` | — | Custom source for the product strip — see [Your own product search](#your-own-product-search-products). Omit it and the strip shows the items the `/suggest` response reports. |
369
370
  | `onProductSelect?` | `(product: Product) => void` | — | Called when a product card is activated. The SDK never navigates. |
370
371
  | `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`. |
@@ -409,6 +410,53 @@ default); `--aia-product-list-media-size` (44px) sizes the thumbnail and
409
410
  is the horizontal strip. Changing the prop re-lays the strip out at once, and
410
411
  `<AIAutocompleteDropdown>` takes the same prop in Tier 2.
411
412
 
413
+ **Product image fallback.** A product's image takes priority when its
414
+ `imageUrl` loads successfully. A missing or blank URL, or an image load error,
415
+ uses `productImageFallback`: `"image"` (the default) shows the existing
416
+ placeholder pictogram; `"initial"` shows the first character of the trimmed,
417
+ uppercased title. This is a Unicode grapheme (so a combined character or emoji
418
+ stays together), with a Unicode code point fallback in older browsers. An
419
+ empty or whitespace-only title shows `?`. The fallback works in both row and
420
+ list layouts. Initial tiles are decorative (`aria-hidden="true"`); the card's
421
+ visible title supplies its text.
422
+
423
+ Pass `productImageFallback="initial"` to `<AIAutocomplete>` or
424
+ `<AIAutocompleteDropdown>`. The hook also accepts the option and carries it
425
+ through `dropdownProps`:
426
+
427
+ ```tsx
428
+ // Tier 1
429
+ <AIAutocomplete onSubmit={handleSubmit} productImageFallback="initial" />;
430
+
431
+ // Tier 2
432
+ function ProductSearch() {
433
+ const { inputProps, dropdownProps } = useAIAutocomplete({
434
+ productImageFallback: "initial",
435
+ });
436
+ return (
437
+ <>
438
+ <textarea {...inputProps} />
439
+ <AIAutocompleteDropdown {...dropdownProps} mode="auto" />
440
+ </>
441
+ );
442
+ }
443
+ ```
444
+
445
+ Style the initial tile itself with `[data-aia-product-initial]`. For
446
+ example, wrap the widget in an element with `id="catalog-search"` and add this
447
+ rule to your stylesheet. The existing `--aia-product-media-bg` variable sets
448
+ the background; `color`, `font-size` and `border-radius` style the initial
449
+ without additional SDK options.
450
+
451
+ ```css
452
+ #catalog-search [data-aia-product-initial] {
453
+ --aia-product-media-bg: #eef2ff;
454
+ color: #4338ca;
455
+ font-size: 22px;
456
+ border-radius: 12px;
457
+ }
458
+ ```
459
+
412
460
  #### The catalog report (`customFields`)
413
461
 
414
462
  Every response that read the catalog also says what it did with the query. The
@@ -471,7 +519,7 @@ const products = {
471
519
  id: item.id,
472
520
  title: item.title,
473
521
  url: item.url,
474
- imageUrl: item.image?.src ?? null, // null renders the placeholder tile
522
+ imageUrl: item.image?.src ?? null, // null uses the configured productImageFallback
475
523
  price: formatMoney(item.price), // you know the currency
476
524
  vendor: item.brand,
477
525
  })),
@@ -542,7 +590,7 @@ scrolls horizontally by trackpad, wheel, touch and keyboard; the page never
542
590
  scrolls sideways and the scrollbar chrome is hidden in all engines.
543
591
 
544
592
  Tier 2 gets the same thing: `useAIAutocomplete()` takes `showProducts`,
545
- `products` and `onProductSelect`, and the strip renders inside
593
+ `products`, `productImageFallback` and `onProductSelect`, and the strip renders inside
546
594
  `<AIAutocompleteDropdown />` via `dropdownProps`. Tier 3 consumers read
547
595
  `products` (and `customFields`) from the hook and call
548
596
  `selectProduct(product)` from their own cards.
@@ -607,7 +655,7 @@ The SDK handles token refresh transparently: 401 → `getAccessToken` → retry
607
655
 
608
656
  ### `useAIAutocomplete(options)`
609
657
 
610
- The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocomplete />` except for the component-only rendering props: `className`, `ref`, `pillPlacement`, `mode`, `animations`, and `autoFocus` (those belong to the wrapping component — the hook doesn't own the input element). `optionsPosition` **is** accepted: it sets the arrow-key direction and flows through `dropdownProps` to the dropdown. `onFocus` and `onBlur` are forwarded and fire whenever the consumer-owned textarea's focus changes (they're driven by `inputProps.onFocus` / `inputProps.onBlur`). `onResult` is accepted too and fires after every successful round-trip — see [Reading the query as it's built](#reading-the-query-as-its-built).
658
+ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocomplete />` except for the component-only rendering props: `className`, `ref`, `pillPlacement`, `mode`, `animations`, and `autoFocus` (those belong to the wrapping component — the hook doesn't own the input element). `productImageFallback` is also accepted and forwarded through `dropdownProps`. `optionsPosition` **is** accepted: it sets the arrow-key direction and flows through `dropdownProps` to the dropdown. `onFocus` and `onBlur` are forwarded and fire whenever the consumer-owned textarea's focus changes (they're driven by `inputProps.onFocus` / `inputProps.onBlur`). `onResult` is accepted too and fires after every successful round-trip — see [Reading the query as it's built](#reading-the-query-as-its-built).
611
659
 
612
660
  #### Return Value
613
661
 
@@ -656,7 +704,7 @@ The headless hook for Tier 2 and Tier 3. Accepts the same options as `<AIAutocom
656
704
  | Field | Type | Description |
657
705
  |---|---|---|
658
706
  | `inputProps` | `object` | Spread onto a `<textarea>`. Includes `value`, `placeholder`, `onChange`, `onKeyDown`, and ARIA attributes. |
659
- | `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. |
707
+ | `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Carries the options, `activeIndex`, `onSelect` / `onHighlight`, pills, open state, `optionsPosition`, and the product strip's `products` / `productImageFallback` / `onProductSelect` / `onProductFocusChange` — read these directly to render your own dropdown in Tier 3. |
660
708
 
661
709
  ### `<AIAutocompleteDropdown />`
662
710
 
@@ -677,6 +725,7 @@ The dropdown component for Tier 2. Spread `dropdownProps` from the hook (and add
677
725
  | `onPillClick?` | `(index: number) => void` | Called when a pill is clicked. |
678
726
  | `showPills?` | `boolean` | Whether to render pills. Default: `true`. |
679
727
  | `products?` | `Product[]` | Product cards to render below the options grid. Empty renders no strip. |
728
+ | `productImageFallback?` | `"image" \| "initial"` | Default: `"image"`. Fallback for a missing or blank product image URL, or an image load error. `"image"` shows the placeholder pictogram; `"initial"` shows the title initial. A working image still takes priority. See [Product strip](#product-strip). Forwarded by the hook in `dropdownProps`. |
680
729
  | `onProductSelect?` | `(product: Product) => void` | Called when a card is activated. |
681
730
  | `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. |
682
731
  | `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. |
@@ -775,10 +824,10 @@ Override on the container (via `className`). The variables are declared with `:w
775
824
  | `--aia-product-gap` | `8px` | `8px` | Gap between product cards. |
776
825
  | `--aia-product-bg` | `transparent` | `transparent` | Product card background. |
777
826
  | `--aia-product-bg-active` | `--aia-option-bg` | `--aia-option-bg` | Product card background on hover. |
778
- | `--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. |
827
+ | `--aia-product-media-bg` | `--aia-skeleton-bg` | `--aia-skeleton-bg` | Fill behind product images and both fallback tiles (placeholder pictogram or title initial), used when an image URL is missing, blank or fails to load. |
779
828
  | `--aia-scroll-arrow-color` | `--aia-option-color` | `--aia-option-color` | Chevron color of the arrow (`--aia-scroll-arrow-color-hover` on hover). |
780
829
  | `--aia-placeholder-fade` | `120ms` | `120ms` | Fade-out of the outgoing placeholder phrase when the starting-state placeholder changes (the incoming one types itself in). |
781
- | `--aia-product-placeholder-image` | storefront pictogram | storefront pictogram | The image drawn on the placeholder tile when a product has no `imageUrl`: a two-tone storefront pictogram, inlined as a data URI. Set it to any `url(...)` to swap the pictogram; it is drawn centered and contained inside the tile, over `--aia-product-media-bg`. |
830
+ | `--aia-product-placeholder-image` | storefront pictogram | storefront pictogram | The pictogram used by `productImageFallback: "image"` (the default) when an image URL is missing, blank or fails to load. Defaults to a two-tone storefront inlined as a data URI. Set any `url(...)` to swap it; it is centered and contained over `--aia-product-media-bg`. Does not affect `"initial"` tiles. |
782
831
  | `--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. |
783
832
  | `--aia-product-price-color` | `--aia-option-color-selected` | `--aia-option-color-selected` | Product price text. |
784
833
  | `--aia-product-vendor-color` | `--aia-option-color` | `--aia-option-color` | Product vendor line. |
@@ -797,7 +846,7 @@ Override on the container (via `className`). The variables are declared with `:w
797
846
  | `--aia-date-today-ring` | `--aia-option-color` | `--aia-option-color` | Outline drawn around today's date. |
798
847
  | `--aia-date-selected-bg` | white at 12% | white at 12% | Fill behind the date a re-edited parameter already holds. |
799
848
  | `--aia-date-range-bg` | white at 6% | white at 6% | Band across the days between the two ends of a picked date range. The ends themselves use `--aia-date-selected-bg`. |
800
- | `--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. |
849
+ | `--aia-skeleton-bg` | `rgba(189, 189, 189, 0.083)` | `#1a1b1d` | Fill color for the loading skeleton bars and the masked text in cached pills/options, and of the option and chip image tiles while their picture loads (unless `--aia-option-image-bg` / `--aia-chip-image-bg` are set). |
801
850
 
802
851
  Legacy `--aia-color-*` variables are still supported as fallbacks.
803
852
 
@@ -838,7 +887,8 @@ For styling beyond the CSS variables, target these stable `data-aia-*` attribute
838
887
  | `[data-aia-products]` | Product strip section (label + row) |
839
888
  | `[data-aia-products-row]` | The horizontally scrolling row of cards |
840
889
  | `[data-aia-product]` | Each product card |
841
- | `[data-aia-product-placeholder]` | Media tile of a card whose product has no image |
890
+ | `[data-aia-product-placeholder]` | Media tile showing the placeholder pictogram (`productImageFallback: "image"`) after a missing/blank URL or load error. The existing hook is unchanged. |
891
+ | `[data-aia-product-initial]` | The media tile itself when it shows the title initial (`productImageFallback: "initial"`). Decorative (`aria-hidden="true"`); target it to style the background, color, font size and border radius. |
842
892
 
843
893
  Completed params render as inline `<strong>` elements inside the editor. Override their weight with `[data-aia-input] strong { font-weight: 700; }` — a selector that names the editor wins without `!important`, while a bare `strong { … }` page rule is kept out by the isolation reset.
844
894
 
package/dist/index.d.mts CHANGED
@@ -1,5 +1,5 @@
1
- import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, ProductsLayout, ProductsConfig, Product, Suggestion, SuggestionOption, FormatType, DateMonthView, DateRange, SkippedParamState, IdentifiedParamState, Segment, CustomFieldsReport } from '@magicx-eng/ai-autocomplete-vanilla';
2
- export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, DateMonthView, DateRange, ExpressedFilter, FilterOp, FormatType, IdentifiedParam, IdentifiedParamState, MatchedItem, MatchedItems, OptionOverrides, PRODUCT_PATH_PREFIX, Product, ProductsConfig, ProductsLayout, Segment, SkippedParamState, SubmitResultExtras, Suggestion, SuggestionOption, TaskKind, WEEKDAY_LABELS, buildSubmitResult, cellDay, cellIso, dateCellMarks, formatDate, formatDateRange, formatOptionCount, isoDate, monthLabel, optionCountLabel, optionHasImage, optionImageSrc, optionLabel, parseDate, parseLooseDate, parseLooseDateRange, productFromMatchedItem, productsFromCustomFields, sanitizeOptionIconSvg, selectedRangeFor, visibleDateRange, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
1
+ import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, ProductsLayout, ProductImageFallback, ProductsConfig, Product, Suggestion, SuggestionOption, FormatType, DateMonthView, DateRange, SkippedParamState, IdentifiedParamState, Segment, CustomFieldsReport } from '@magicx-eng/ai-autocomplete-vanilla';
2
+ export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, DateMonthView, DateRange, ExpressedFilter, FilterOp, FormatType, IdentifiedParam, IdentifiedParamState, MatchedItem, MatchedItems, OptionOverrides, PRODUCT_PATH_PREFIX, Product, ProductImageFallback, ProductsConfig, ProductsLayout, Segment, SkippedParamState, SubmitResultExtras, Suggestion, SuggestionOption, TaskKind, WEEKDAY_LABELS, buildSubmitResult, cellDay, cellIso, dateCellMarks, formatDate, formatDateRange, formatOptionCount, isoDate, monthLabel, optionCountLabel, optionHasImage, optionImageSrc, optionLabel, parseDate, parseLooseDate, parseLooseDateRange, productFromMatchedItem, productsFromCustomFields, sanitizeOptionIconSvg, selectedRangeFor, visibleDateRange, 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';
@@ -109,6 +109,12 @@ interface AIAutocompleteProps {
109
109
  * `--aia-product-list-max-height`.
110
110
  */
111
111
  productsLayout?: ProductsLayout;
112
+ /**
113
+ * Fallback for a missing or failed product image. "image" (default) uses
114
+ * the placeholder image; "initial" uses the title's first character.
115
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
116
+ */
117
+ productImageFallback?: ProductImageFallback;
112
118
  /**
113
119
  * Custom source for the product strip. Omit it and the strip shows the
114
120
  * items the `/suggest` response itself reports as matching the query, with
@@ -227,6 +233,12 @@ interface UseAIAutocompleteOptions {
227
233
  * `--aia-product-list-max-height`.
228
234
  */
229
235
  productsLayout?: ProductsLayout;
236
+ /**
237
+ * Fallback for a missing or failed product image. "image" (default) uses
238
+ * the placeholder image; "initial" uses the title's first character.
239
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
240
+ */
241
+ productImageFallback?: ProductImageFallback;
230
242
  /**
231
243
  * Custom source for the product strip. Omit it and the strip shows the
232
244
  * items the `/suggest` response itself reports as matching the query, with
@@ -439,6 +451,8 @@ interface AIAutocompleteDropdownProps {
439
451
  activeSelected?: boolean;
440
452
  /** True while a fetch for the latest query is in flight. Replaces options/pills with a skeleton. */
441
453
  isLoading?: boolean;
454
+ /** True while the loading skeleton fades out before the response's options replace it. Provided by `dropdownProps` from the hook. */
455
+ skeletonExiting?: boolean;
442
456
  /** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
443
457
  isInputEmpty?: boolean;
444
458
  /** Product cards to render below the options grid. Provided by `dropdownProps` from the hook. Empty (the default) renders no strip. */
@@ -447,6 +461,12 @@ interface AIAutocompleteDropdownProps {
447
461
  onProductSelect?: (product: Product) => void;
448
462
  /** How the product strip lays its cards out — see the Tier 1 prop of the same name. Default: `"row"`. */
449
463
  productsLayout?: ProductsLayout;
464
+ /**
465
+ * Fallback for a missing or failed product image. "image" (default) uses
466
+ * the placeholder image; "initial" uses the title's first character.
467
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
468
+ */
469
+ productImageFallback?: ProductImageFallback;
450
470
  /**
451
471
  * Called when focus moves into / out of the product strip. The panel closes
452
472
  * on blur by default and the input blurs the instant a card takes focus, so
@@ -499,8 +519,8 @@ interface AIAutocompleteDropdownProps {
499
519
 
500
520
  declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
501
521
 
502
- declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, onSkip, showSkipButton, showOptionIcons, showOptionImages, showOptionCounts, skipDisabled, activeSelected, isLoading, isInputEmpty, products, onProductSelect, onProductFocusChange, productsLayout, formatType, dateView, selectedDateIso, selectedDateRange, dateRangeStart, onPreviousMonth, onNextMonth, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
522
+ declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, onSkip, showSkipButton, showOptionIcons, showOptionImages, showOptionCounts, skipDisabled, activeSelected, isLoading, skeletonExiting, isInputEmpty, products, onProductSelect, onProductFocusChange, productsLayout, productImageFallback, formatType, dateView, selectedDateIso, selectedDateRange, dateRangeStart, onPreviousMonth, onNextMonth, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
503
523
 
504
- declare function useAIAutocomplete({ onSubmit, onResult, onError, optionOverrides, maskCompletedText, apiConfig, additionalContext, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, showOptionIcons, showOptionImages, showOptionCounts, showSkipButton, showProducts, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
524
+ declare function useAIAutocomplete({ onSubmit, onResult, onError, optionOverrides, maskCompletedText, apiConfig, additionalContext, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, showOptionIcons, showOptionImages, showOptionCounts, showSkipButton, showProducts, productImageFallback, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
505
525
 
506
526
  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, ProductsLayout, ProductsConfig, Product, Suggestion, SuggestionOption, FormatType, DateMonthView, DateRange, SkippedParamState, IdentifiedParamState, Segment, CustomFieldsReport } from '@magicx-eng/ai-autocomplete-vanilla';
2
- export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, DateMonthView, DateRange, ExpressedFilter, FilterOp, FormatType, IdentifiedParam, IdentifiedParamState, MatchedItem, MatchedItems, OptionOverrides, PRODUCT_PATH_PREFIX, Product, ProductsConfig, ProductsLayout, Segment, SkippedParamState, SubmitResultExtras, Suggestion, SuggestionOption, TaskKind, WEEKDAY_LABELS, buildSubmitResult, cellDay, cellIso, dateCellMarks, formatDate, formatDateRange, formatOptionCount, isoDate, monthLabel, optionCountLabel, optionHasImage, optionImageSrc, optionLabel, parseDate, parseLooseDate, parseLooseDateRange, productFromMatchedItem, productsFromCustomFields, sanitizeOptionIconSvg, selectedRangeFor, visibleDateRange, withSkippedParams } from '@magicx-eng/ai-autocomplete-vanilla';
1
+ import { AutocompleteResult, OptionOverrides, APIConfig, AppearanceMode, CompletedParamState, ProductsLayout, ProductImageFallback, ProductsConfig, Product, Suggestion, SuggestionOption, FormatType, DateMonthView, DateRange, SkippedParamState, IdentifiedParamState, Segment, CustomFieldsReport } from '@magicx-eng/ai-autocomplete-vanilla';
2
+ export { APIConfig, APIKeyConfig, AccessTokenConfig, AccessTokenResult, AppearanceMode, AutocompleteResult, CompletedParam, CompletedParamState, CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, DEFAULT_OPTION_COUNT_UNIT, DateMonthView, DateRange, ExpressedFilter, FilterOp, FormatType, IdentifiedParam, IdentifiedParamState, MatchedItem, MatchedItems, OptionOverrides, PRODUCT_PATH_PREFIX, Product, ProductImageFallback, ProductsConfig, ProductsLayout, Segment, SkippedParamState, SubmitResultExtras, Suggestion, SuggestionOption, TaskKind, WEEKDAY_LABELS, buildSubmitResult, cellDay, cellIso, dateCellMarks, formatDate, formatDateRange, formatOptionCount, isoDate, monthLabel, optionCountLabel, optionHasImage, optionImageSrc, optionLabel, parseDate, parseLooseDate, parseLooseDateRange, productFromMatchedItem, productsFromCustomFields, sanitizeOptionIconSvg, selectedRangeFor, visibleDateRange, 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';
@@ -109,6 +109,12 @@ interface AIAutocompleteProps {
109
109
  * `--aia-product-list-max-height`.
110
110
  */
111
111
  productsLayout?: ProductsLayout;
112
+ /**
113
+ * Fallback for a missing or failed product image. "image" (default) uses
114
+ * the placeholder image; "initial" uses the title's first character.
115
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
116
+ */
117
+ productImageFallback?: ProductImageFallback;
112
118
  /**
113
119
  * Custom source for the product strip. Omit it and the strip shows the
114
120
  * items the `/suggest` response itself reports as matching the query, with
@@ -227,6 +233,12 @@ interface UseAIAutocompleteOptions {
227
233
  * `--aia-product-list-max-height`.
228
234
  */
229
235
  productsLayout?: ProductsLayout;
236
+ /**
237
+ * Fallback for a missing or failed product image. "image" (default) uses
238
+ * the placeholder image; "initial" uses the title's first character.
239
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
240
+ */
241
+ productImageFallback?: ProductImageFallback;
230
242
  /**
231
243
  * Custom source for the product strip. Omit it and the strip shows the
232
244
  * items the `/suggest` response itself reports as matching the query, with
@@ -439,6 +451,8 @@ interface AIAutocompleteDropdownProps {
439
451
  activeSelected?: boolean;
440
452
  /** True while a fetch for the latest query is in flight. Replaces options/pills with a skeleton. */
441
453
  isLoading?: boolean;
454
+ /** True while the loading skeleton fades out before the response's options replace it. Provided by `dropdownProps` from the hook. */
455
+ skeletonExiting?: boolean;
442
456
  /** When the input has no typed text, the footer hint reads "tab to select". Provided by `dropdownProps` from the hook. */
443
457
  isInputEmpty?: boolean;
444
458
  /** Product cards to render below the options grid. Provided by `dropdownProps` from the hook. Empty (the default) renders no strip. */
@@ -447,6 +461,12 @@ interface AIAutocompleteDropdownProps {
447
461
  onProductSelect?: (product: Product) => void;
448
462
  /** How the product strip lays its cards out — see the Tier 1 prop of the same name. Default: `"row"`. */
449
463
  productsLayout?: ProductsLayout;
464
+ /**
465
+ * Fallback for a missing or failed product image. "image" (default) uses
466
+ * the placeholder image; "initial" uses the title's first character.
467
+ * Style initial tiles with `[data-aia-product-initial]` in CSS.
468
+ */
469
+ productImageFallback?: ProductImageFallback;
450
470
  /**
451
471
  * Called when focus moves into / out of the product strip. The panel closes
452
472
  * on blur by default and the input blurs the instant a card takes focus, so
@@ -499,8 +519,8 @@ interface AIAutocompleteDropdownProps {
499
519
 
500
520
  declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
501
521
 
502
- declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, onSkip, showSkipButton, showOptionIcons, showOptionImages, showOptionCounts, skipDisabled, activeSelected, isLoading, isInputEmpty, products, onProductSelect, onProductFocusChange, productsLayout, formatType, dateView, selectedDateIso, selectedDateRange, dateRangeStart, onPreviousMonth, onNextMonth, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
522
+ declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, onSkip, showSkipButton, showOptionIcons, showOptionImages, showOptionCounts, skipDisabled, activeSelected, isLoading, skeletonExiting, isInputEmpty, products, onProductSelect, onProductFocusChange, productsLayout, productImageFallback, formatType, dateView, selectedDateIso, selectedDateRange, dateRangeStart, onPreviousMonth, onNextMonth, optionsPosition, mode, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
503
523
 
504
- declare function useAIAutocomplete({ onSubmit, onResult, onError, optionOverrides, maskCompletedText, apiConfig, additionalContext, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, showOptionIcons, showOptionImages, showOptionCounts, showSkipButton, showProducts, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
524
+ declare function useAIAutocomplete({ onSubmit, onResult, onError, optionOverrides, maskCompletedText, apiConfig, additionalContext, columns, dropdownTrigger, optionsPosition, closeDropdownOnBlur, showNonTappableOptions, showOptionIcons, showOptionImages, showOptionCounts, showSkipButton, showProducts, productImageFallback, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, products, onProductSelect, source, setCursor, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
505
525
 
506
526
  export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };