@magicx-eng/ai-autocomplete-vanilla 0.20.2 → 0.21.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 +93 -18
- package/dist/index.d.mts +175 -20
- package/dist/index.d.ts +175 -20
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +2 -2
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -16,7 +16,8 @@ A framework-agnostic vanilla JS/TypeScript library that provides a guided AI-pow
|
|
|
16
16
|
- **Client-side filtering** — instant substring filtering on every keystroke
|
|
17
17
|
- **Datepicker** — date parameters are answered with a calendar instead of an option list. Click a day or navigate with the arrow keys; the date is committed the way it would be written — `Tuesday` for a date inside the next week, `March 23` for one later this year, `March 23 2027` for another year. Tapping a committed date re-opens the calendar on the month that text names now — for a weekday name, that is the next such day, not the one originally picked. A parameter whose options are written as spans (`September 11 - October 13`) gets the same calendar answered in two clicks, committed as one range.
|
|
18
18
|
- **Option overrides** — supply the options for a parameter yourself: a fixed list, a computed one, or one fetched from your own search endpoint as the user types
|
|
19
|
-
- **Product strip
|
|
19
|
+
- **Product strip** — the dropdown renders a horizontal row of product cards below the options, filled by default with the items the `/suggest` response reports as matching the query; plug in your own product search instead with `products`, or turn the strip off with `showProducts: false`
|
|
20
|
+
- **Catalog report** — every response says which of the query's constraints the catalog applied, which it had to drop, and how many items are left, on `customFields` / `custom_fields`
|
|
20
21
|
- **Controlled & uncontrolled** — works out of the box or integrates with external state
|
|
21
22
|
- **Accessible** — ARIA combobox 1.2 pattern with `role="listbox"`, `aria-activedescendant`
|
|
22
23
|
- **IME-safe** — composition events are buffered so input text is committed once, after composition ends
|
|
@@ -99,7 +100,10 @@ const ac = new AIAutocomplete(container, {
|
|
|
99
100
|
// this is only for sending the styles somewhere else. See "Shadow DOM".
|
|
100
101
|
styleRoot: undefined,
|
|
101
102
|
|
|
102
|
-
// Product strip
|
|
103
|
+
// Product strip. Shown by default from the items the /suggest response
|
|
104
|
+
// reports; false renders no strip.
|
|
105
|
+
showProducts: true,
|
|
106
|
+
// Custom source for the strip. Omit it and the server's items are shown.
|
|
103
107
|
products: {
|
|
104
108
|
fetch: (query, signal) => myPlatform.search(query, { signal }),
|
|
105
109
|
transform: (raw) => mapToProducts(raw),
|
|
@@ -153,10 +157,80 @@ ac.getResult(); // The AutocompleteResult as it stands right now
|
|
|
153
157
|
|
|
154
158
|
### Product strip
|
|
155
159
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
the
|
|
160
|
+
The dropdown renders a horizontal row of product cards below the options grid
|
|
161
|
+
whenever it has products to show. By default those are the items the
|
|
162
|
+
`/suggest` response itself reports as matching the query — no configuration,
|
|
163
|
+
no extra request: the cards land in the same state write as the suggestions,
|
|
164
|
+
so what the strip shows and what the pills offer always describe the same
|
|
165
|
+
narrowing.
|
|
166
|
+
|
|
167
|
+
```ts
|
|
168
|
+
import { AIAutocomplete } from "@magicx-eng/ai-autocomplete-vanilla";
|
|
169
|
+
|
|
170
|
+
new AIAutocomplete(container, {
|
|
171
|
+
apiConfig: { apiKey: "..." },
|
|
172
|
+
// Selection emits — the SDK never navigates.
|
|
173
|
+
onProductSelect: (product) => {
|
|
174
|
+
if (product.url) window.location.assign(product.url); // …or add to cart, or fill the input
|
|
175
|
+
},
|
|
176
|
+
});
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Each server item becomes a `Product` with `id` (the item's stable id), `title`,
|
|
180
|
+
`price` (the item's lowest price, verbatim as the catalog spells it — the
|
|
181
|
+
currency is yours to add), `vendor`, `imageUrl`, and a **relative** `url` of
|
|
182
|
+
`/products/{handle}` — the right link for a widget running on the storefront
|
|
183
|
+
itself. An item the catalog has no handle for gets no `url`: its card is still
|
|
184
|
+
activatable and still emits `onProductSelect`, it just has nothing for
|
|
185
|
+
cmd-click to open. `productFromMatchedItem` / `productsFromCustomFields` are
|
|
186
|
+
exported for a hand-rolled strip that wants the same mapping.
|
|
187
|
+
|
|
188
|
+
Set `showProducts: false` to render no strip at all. The catalog report
|
|
189
|
+
(below) stays readable either way.
|
|
190
|
+
|
|
191
|
+
#### The catalog report (`customFields`)
|
|
192
|
+
|
|
193
|
+
Every response that read the catalog also says what it did with the query, and
|
|
194
|
+
the SDK exposes that as `customFields` on state (and as `custom_fields` on
|
|
195
|
+
`AutocompleteResult`, so `onResult` / `getResult()` carry it too):
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
ac.subscribe((state) => {
|
|
199
|
+
const report = state.customFields;
|
|
200
|
+
if (!report) return; // no catalog was read for this response
|
|
201
|
+
count.textContent = `${report.items.total} results`;
|
|
202
|
+
if (report.dropped_filters.length > 0) {
|
|
203
|
+
// e.g. { param: "Color", value: "Chartreuse", op: "eq" } — the shopper asked
|
|
204
|
+
// for a colour no item carries, so the results ignore it. Say so.
|
|
205
|
+
note.textContent = `No match for ${report.dropped_filters.map((f) => f.value).join(", ")}`;
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
- `applied_filters` / `dropped_filters` — the constraints the server read out
|
|
211
|
+
of the query as `{ param, value, op }` (`op` is one of `eq`, `ne`, `lt`,
|
|
212
|
+
`lte`, `gt`, `gte`), split into the ones the catalog answered and the ones it
|
|
213
|
+
could not (a parameter it does not have, a bound that is not a number, a
|
|
214
|
+
value no item carries). The items answer the applied set, so the dropped
|
|
215
|
+
list is what tells "87 black t-shirts" from "no black item, so here are
|
|
216
|
+
t-shirts". Both are always arrays.
|
|
217
|
+
- `items.total` — how many items the applied filters left standing. It also
|
|
218
|
+
moves with the query's own words, so it drops as a typed word starts
|
|
219
|
+
matching a title. `items.matched` is the list the strip renders, capped by
|
|
220
|
+
the server; it is empty (with a non-zero `total`) when nothing narrowed the
|
|
221
|
+
catalog, where listing arbitrary items as matches would mislead.
|
|
222
|
+
- `null` means the response carried no report — no catalog was read for it
|
|
223
|
+
(a product with no catalog, the starting state, a response with no
|
|
224
|
+
option-bearing parameter to offer). That is "no news", not an empty
|
|
225
|
+
catalog. The strip clears on such a response rather than keeping an older
|
|
226
|
+
query's items.
|
|
227
|
+
|
|
228
|
+
#### Your own product search (`products`)
|
|
229
|
+
|
|
230
|
+
To source the cards from your own search instead — a platform with its own
|
|
231
|
+
endpoint and response shape — set `products`. The SDK owns the UI; you own
|
|
232
|
+
only the fetching and the mapping. The server's items are then not rendered
|
|
233
|
+
(they stay readable on `customFields`).
|
|
160
234
|
|
|
161
235
|
```ts
|
|
162
236
|
import { AIAutocomplete, type Product } from "@magicx-eng/ai-autocomplete-vanilla";
|
|
@@ -191,20 +265,19 @@ new AIAutocomplete(container, {
|
|
|
191
265
|
limit: 8, // applied by the SDK, after transform
|
|
192
266
|
},
|
|
193
267
|
|
|
194
|
-
// Selection emits — the SDK never navigates.
|
|
195
268
|
onProductSelect: (product) => {
|
|
196
|
-
window.location.assign(product.url);
|
|
269
|
+
if (product.url) window.location.assign(product.url);
|
|
197
270
|
},
|
|
198
271
|
});
|
|
199
272
|
```
|
|
200
273
|
|
|
201
|
-
`Product` is exactly six fields; only `id
|
|
274
|
+
`Product` is exactly six fields; only `id` and `title` are required:
|
|
202
275
|
|
|
203
276
|
```ts
|
|
204
277
|
type Product = {
|
|
205
278
|
id: string;
|
|
206
279
|
title: string;
|
|
207
|
-
url
|
|
280
|
+
url?: string; // absent = a card with no link (still activatable)
|
|
208
281
|
imageUrl?: string | null; // null renders the placeholder tile
|
|
209
282
|
price?: string; // pre-formatted by you
|
|
210
283
|
vendor?: string;
|
|
@@ -238,7 +311,7 @@ never navigates on your behalf.
|
|
|
238
311
|
|
|
239
312
|
`product.url` is used verbatim — the SDK trusts your `transform` output and
|
|
240
313
|
does not sanitise it, so validate the URL there if the platform response isn't
|
|
241
|
-
fully under your control. (Angular additionally runs its own `
|
|
314
|
+
fully under your control. (Angular additionally runs its own `href`
|
|
242
315
|
sanitiser, so unrecognised schemes like `myapp://…` are rewritten to
|
|
243
316
|
`unsafe:…` in that package only.)
|
|
244
317
|
|
|
@@ -248,11 +321,11 @@ visible focus ring. Tabbing into the strip does not close the panel. The row
|
|
|
248
321
|
scrolls horizontally by trackpad, wheel, touch and keyboard; the page never
|
|
249
322
|
scrolls sideways and the scrollbar chrome is hidden in all engines.
|
|
250
323
|
|
|
251
|
-
`update({ products })` swaps the integration
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
324
|
+
`update({ products })` swaps the integration and clears the current cards; the
|
|
325
|
+
strip repopulates on the *next* `/suggest` request, since the product search
|
|
326
|
+
rides that one scheduler and changing the config doesn't itself change the
|
|
327
|
+
query. `update({ products: undefined })` hands the strip back to the server's
|
|
328
|
+
items at once, and `update({ showProducts })` empties or restores it at once.
|
|
256
329
|
|
|
257
330
|
#### Custom submit button
|
|
258
331
|
|
|
@@ -400,7 +473,7 @@ input.addEventListener("blur", () => ac.setFocused(false));
|
|
|
400
473
|
|
|
401
474
|
Pills always render inside the dropdown in this mode. The library creates the dropdown DOM inside your container — you just provide the element and wire up your input's events.
|
|
402
475
|
|
|
403
|
-
The [product strip](#product-strip) works here too:
|
|
476
|
+
The [product strip](#product-strip) works here too: it renders inside the dropdown the library owns, from the server's items by default, and `products` / `showProducts` / `onProductSelect` behave exactly as in Tier 1.
|
|
404
477
|
|
|
405
478
|
> Focus/blur wiring is required when `dropdownTrigger` is `"auto"` (the default) — the dropdown only opens while the input is focused. Without `setFocused()`, the dropdown will never open.
|
|
406
479
|
|
|
@@ -482,7 +555,8 @@ unsub();
|
|
|
482
555
|
| `isSearchingOptions` | `boolean` | True while an [option override](#option-overrides) for the parameter on screen has been asked and hasn't answered. Render the same skeleton you render for `isLoading`; the built-in dropdowns do. |
|
|
483
556
|
| `inSelectionAnimation` | `boolean` | True for the 500 ms after a user-initiated option tap so the press animation can finish before the dropdown switches to the loading skeleton. |
|
|
484
557
|
| `editingParam` | `CompletedParamState \| null` | When non-null, the user is re-editing a bold completed param; cached options remain visible and the loading skeleton is suppressed. |
|
|
485
|
-
| `products` | `Product[]` |
|
|
558
|
+
| `products` | `Product[]` | What the product strip shows: the items the latest response reported as matching the query, or the results of a custom `products` search. See [Product strip](#product-strip) — Tier 3 consumers render their own cards and call `selectProduct(product)` to emit `onProductSelect`. |
|
|
559
|
+
| `customFields` | `CustomFieldsReport \| null` | The catalog report the latest response carried — applied and dropped filters, and the matching items' count and list — or `null` when it carried none. See [The catalog report](#the-catalog-report-customfields). |
|
|
486
560
|
| `isReady` | `boolean` | Server indicates query is complete |
|
|
487
561
|
| `error` | `Error \| null` | Last fetch error |
|
|
488
562
|
|
|
@@ -591,6 +665,7 @@ The structured query as the SDK currently understands it. The same object is pas
|
|
|
591
665
|
| `completed_params` | `CompletedParam[]` | Filled parameter values in query order, followed by any the user skipped (see below). |
|
|
592
666
|
| `identified_params` | `IdentifiedParam[]` | Parameters the server recognised in the user's own words, as `{ type, value }` — e.g. `{ type: "due_date", value: "Friday" }` when the user typed "by Friday" instead of picking a date. They are not tokenized in `raw_query`, and they are tentative: each response replaces the set, and an entry drops out as soon as its text is edited away. |
|
|
593
667
|
| `is_ready` | `boolean` | Whether the server considers the query complete enough to act on. |
|
|
668
|
+
| `custom_fields?` | `CustomFieldsReport` | What catalog grounding did for the latest applied response, when it read a catalog at all — see [Product strip](#product-strip). `applied_filters` and `dropped_filters` list the query's constraints as `{ param, value, op }`; `items.total` is how many items the applied ones left standing and `items.matched` the ones the strip renders. Absent (no key) when the response carried no report. |
|
|
594
669
|
|
|
595
670
|
#### Reading the query as it's built
|
|
596
671
|
|
package/dist/index.d.mts
CHANGED
|
@@ -74,12 +74,93 @@ interface AutocompleteResponse {
|
|
|
74
74
|
input: InputItem[];
|
|
75
75
|
suggestions: Suggestion[];
|
|
76
76
|
is_ready?: boolean;
|
|
77
|
+
/**
|
|
78
|
+
* What catalog grounding did for this request. Absent whenever no
|
|
79
|
+
* catalog was read — see {@link CustomFieldsReport}.
|
|
80
|
+
*/
|
|
81
|
+
custom_fields?: CustomFieldsReport;
|
|
77
82
|
};
|
|
78
83
|
meta: {
|
|
79
84
|
request_id: string;
|
|
80
85
|
request_at: string;
|
|
81
86
|
};
|
|
82
87
|
}
|
|
88
|
+
/** Comparison an {@link ExpressedFilter} applies to its value. */
|
|
89
|
+
type FilterOp = "eq" | "ne" | "lt" | "lte" | "gt" | "gte";
|
|
90
|
+
/**
|
|
91
|
+
* One constraint the server read out of the query — a parameter, a value and
|
|
92
|
+
* how the two compare ("price", "100", "lt").
|
|
93
|
+
*/
|
|
94
|
+
interface ExpressedFilter {
|
|
95
|
+
param: string;
|
|
96
|
+
value: string;
|
|
97
|
+
op: FilterOp;
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* One catalog item the query narrowed down to, in the shape needed to render
|
|
101
|
+
* it. Only `source_id` and `title` are always present.
|
|
102
|
+
*/
|
|
103
|
+
interface MatchedItem {
|
|
104
|
+
/** Stable identity of the item within the catalog. */
|
|
105
|
+
source_id: string;
|
|
106
|
+
/** The item's id in the platform it was imported from, when it has one. */
|
|
107
|
+
origin_id?: string;
|
|
108
|
+
title: string;
|
|
109
|
+
/**
|
|
110
|
+
* The item's lowest price, verbatim as the catalog spells it ("131.00").
|
|
111
|
+
* Not formatted for display: the currency is the storefront's to add.
|
|
112
|
+
*/
|
|
113
|
+
price?: string;
|
|
114
|
+
vendor?: string;
|
|
115
|
+
/**
|
|
116
|
+
* The platform's URL slug for the item, not a URL. The SDK builds a relative
|
|
117
|
+
* `/products/{handle}` link from it for the product strip, which is right for
|
|
118
|
+
* a widget running on the storefront itself.
|
|
119
|
+
*/
|
|
120
|
+
handle?: string;
|
|
121
|
+
image_url?: string;
|
|
122
|
+
}
|
|
123
|
+
/** The items the applied filters left standing. */
|
|
124
|
+
interface MatchedItems {
|
|
125
|
+
/**
|
|
126
|
+
* How many items the query narrowed the catalog to — `matched.length` at
|
|
127
|
+
* most, and larger when the list was capped. Also counts what the query's own
|
|
128
|
+
* words matched, so it drops as a typed word starts matching a title.
|
|
129
|
+
*/
|
|
130
|
+
total: number;
|
|
131
|
+
/**
|
|
132
|
+
* The items themselves, capped by the server. Empty with a non-zero `total`
|
|
133
|
+
* when nothing narrowed the catalog: naming arbitrary items as matches would
|
|
134
|
+
* be worse than naming none.
|
|
135
|
+
*/
|
|
136
|
+
matched: MatchedItem[];
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* What catalog grounding did for a request, as opposed to what it decided to
|
|
140
|
+
* ask next.
|
|
141
|
+
*
|
|
142
|
+
* Absent from a response whenever no catalog was read: a product with no
|
|
143
|
+
* catalog, a starting-state response, or a request whose suggestions offer no
|
|
144
|
+
* option-bearing parameter. Treat absence as "no news", not as an empty
|
|
145
|
+
* catalog.
|
|
146
|
+
*
|
|
147
|
+
* `applied_filters` and `dropped_filters` are what make `items` interpretable:
|
|
148
|
+
* the items answer the applied set, so without the dropped one "87 black
|
|
149
|
+
* t-shirts" and "no black item, so here are t-shirts" look identical. Both
|
|
150
|
+
* lists are always present, so a consumer reads `[]` rather than guarding a
|
|
151
|
+
* null.
|
|
152
|
+
*/
|
|
153
|
+
interface CustomFieldsReport {
|
|
154
|
+
/** Constraints the catalog read actually ran under. */
|
|
155
|
+
applied_filters: ExpressedFilter[];
|
|
156
|
+
/**
|
|
157
|
+
* Constraints the query expressed that the catalog could not answer — a
|
|
158
|
+
* parameter it does not have, a bound that is not a number, or a value no
|
|
159
|
+
* item carries. `items` were narrowed without them.
|
|
160
|
+
*/
|
|
161
|
+
dropped_filters: ExpressedFilter[];
|
|
162
|
+
items: MatchedItems;
|
|
163
|
+
}
|
|
83
164
|
interface CompletedParamState extends CompletedParam {
|
|
84
165
|
id: string;
|
|
85
166
|
text: string;
|
|
@@ -205,19 +286,24 @@ type OptionOverrides = Record<string, OptionOverride>;
|
|
|
205
286
|
/**
|
|
206
287
|
* A single product card in the dropdown's product strip.
|
|
207
288
|
*
|
|
208
|
-
* Platform-agnostic on purpose:
|
|
209
|
-
*
|
|
210
|
-
*
|
|
211
|
-
* `
|
|
212
|
-
* missing. Do NOT grow this shape casually; a
|
|
213
|
-
* every
|
|
289
|
+
* Platform-agnostic on purpose: the server's matched items (the default
|
|
290
|
+
* source) and every custom integration (Shopify search today, others later)
|
|
291
|
+
* map onto exactly these fields, so the SDK renders one strip regardless of
|
|
292
|
+
* where the results came from. Only `id` and `title` are required — the card
|
|
293
|
+
* reflows when any of the rest is missing. Do NOT grow this shape casually; a
|
|
294
|
+
* new field is a new contract every source has to satisfy.
|
|
214
295
|
*/
|
|
215
296
|
interface Product {
|
|
216
297
|
/** Stable identity — used as the render key, so it must be unique per result set. */
|
|
217
298
|
id: string;
|
|
218
299
|
title: string;
|
|
219
|
-
/**
|
|
220
|
-
|
|
300
|
+
/**
|
|
301
|
+
* Destination for the card's `href`. Absent, the card has no link — it is
|
|
302
|
+
* still activatable and still emits `onProductSelect`, but cmd-click and
|
|
303
|
+
* "copy link address" have nothing to open. Selection never navigates; see
|
|
304
|
+
* `onProductSelect`.
|
|
305
|
+
*/
|
|
306
|
+
url?: string;
|
|
221
307
|
/** Absent/null renders the placeholder tile — plenty of catalogues have no images. */
|
|
222
308
|
imageUrl?: string | null;
|
|
223
309
|
/** Pre-formatted by the integration, which is the side that knows the currency. */
|
|
@@ -225,9 +311,13 @@ interface Product {
|
|
|
225
311
|
vendor?: string;
|
|
226
312
|
}
|
|
227
313
|
/**
|
|
228
|
-
*
|
|
229
|
-
*
|
|
230
|
-
*
|
|
314
|
+
* Custom product-search wiring for the strip. Absent (the default), the strip
|
|
315
|
+
* shows the items the `/suggest` response itself reports as matching the query
|
|
316
|
+
* (`custom_fields.items`), with no extra request. Set it to source the cards
|
|
317
|
+
* from your own search instead: the server's items are then never rendered
|
|
318
|
+
* (they stay readable on `customFields`), and the SDK fetches through this
|
|
319
|
+
* config on its own cadence. To render no strip at all, set `showProducts`
|
|
320
|
+
* to false.
|
|
231
321
|
*/
|
|
232
322
|
interface ProductsConfig {
|
|
233
323
|
/**
|
|
@@ -289,6 +379,12 @@ interface AutocompleteResult {
|
|
|
289
379
|
identified_params: IdentifiedParam[];
|
|
290
380
|
/** Whether the server considers the query complete enough to act on. */
|
|
291
381
|
is_ready: boolean;
|
|
382
|
+
/**
|
|
383
|
+
* What catalog grounding did for the latest applied response — the filters
|
|
384
|
+
* it applied and dropped, and the items they left standing. Present only
|
|
385
|
+
* when that response carried the block; see {@link CustomFieldsReport}.
|
|
386
|
+
*/
|
|
387
|
+
custom_fields?: CustomFieldsReport;
|
|
292
388
|
}
|
|
293
389
|
|
|
294
390
|
/** A calendar month on screen. `month` is 0-based, matching `Date#getMonth`. */
|
|
@@ -458,12 +554,26 @@ interface CoreInputState {
|
|
|
458
554
|
} | null;
|
|
459
555
|
suggestions: Suggestion[];
|
|
460
556
|
/**
|
|
461
|
-
*
|
|
462
|
-
*
|
|
463
|
-
*
|
|
464
|
-
* never shows
|
|
557
|
+
* What the product strip shows. By default the items the latest `/suggest`
|
|
558
|
+
* response reported as matching the query (`custom_fields.items.matched`,
|
|
559
|
+
* mapped onto `Product`), replaced on every response and empty when the
|
|
560
|
+
* response carried none — so the strip never shows items belonging to an
|
|
561
|
+
* older query. With `opts.products` configured, the results of the latest
|
|
562
|
+
* custom search instead, already transformed and capped by its `limit`,
|
|
563
|
+
* cleared on an empty query and on a failed fetch/transform. Always empty
|
|
564
|
+
* while `opts.showProducts` is false.
|
|
465
565
|
*/
|
|
466
566
|
products: Product[];
|
|
567
|
+
/**
|
|
568
|
+
* The catalog grounding report the latest applied response carried, or null
|
|
569
|
+
* when it carried none. Replaced wholesale per response, so it always
|
|
570
|
+
* describes the suggestions on screen: which of the query's constraints the
|
|
571
|
+
* catalog applied, which it had to drop, and how many items (and which) the
|
|
572
|
+
* applied ones left standing. Null is "no news", not an empty catalog — a
|
|
573
|
+
* response reads no catalog when it has no option-bearing parameter to
|
|
574
|
+
* offer. See {@link CustomFieldsReport}.
|
|
575
|
+
*/
|
|
576
|
+
customFields: CustomFieldsReport | null;
|
|
467
577
|
/**
|
|
468
578
|
* The consumer's {@link OptionSource} request for the pill on screen — the
|
|
469
579
|
* active suggestion, or the completed param being re-edited. `type` is the
|
|
@@ -724,10 +834,23 @@ interface CoreOptions {
|
|
|
724
834
|
*/
|
|
725
835
|
submitButton?: HTMLElement | null;
|
|
726
836
|
/**
|
|
727
|
-
*
|
|
728
|
-
*
|
|
729
|
-
*
|
|
730
|
-
*
|
|
837
|
+
* When true (default), the dropdown renders a horizontal row of product
|
|
838
|
+
* cards below the options grid whenever it has products to show: by default
|
|
839
|
+
* the items the `/suggest` response reports as matching the query, or the
|
|
840
|
+
* results of a custom `products` search. Set to false to render no strip and
|
|
841
|
+
* run no custom search; `customFields` stays readable either way.
|
|
842
|
+
*
|
|
843
|
+
* Turning it back on restores the server's items at once — they are already
|
|
844
|
+
* in the store — while a custom `products` config repopulates on the next
|
|
845
|
+
* request, since its search rides the suggest cadence.
|
|
846
|
+
*/
|
|
847
|
+
showProducts?: boolean;
|
|
848
|
+
/**
|
|
849
|
+
* Custom source for the product strip. Omit it and the strip shows the items
|
|
850
|
+
* the `/suggest` response itself reports (`custom_fields.items`), with no
|
|
851
|
+
* extra request. Set it and the dropdown is fed by your own search endpoint
|
|
852
|
+
* on the SDK's existing fetch cadence instead; the server's items are then
|
|
853
|
+
* not rendered.
|
|
731
854
|
*/
|
|
732
855
|
products?: ProductsConfig;
|
|
733
856
|
/** Called when the user submits (Enter, or the submit button in Tier 1). */
|
|
@@ -1669,6 +1792,31 @@ declare function getFooterHint(optionHighlighted: boolean, isInputEmpty: boolean
|
|
|
1669
1792
|
*/
|
|
1670
1793
|
declare function toWireIdentifiedParams(params: IdentifiedParamState[]): IdentifiedParam[];
|
|
1671
1794
|
|
|
1795
|
+
/**
|
|
1796
|
+
* Where the product strip links a server-matched item to. The server ships a
|
|
1797
|
+
* bare `handle` on purpose: the only shop domain it holds is the internal one,
|
|
1798
|
+
* and an absolute link built from it would send a shopper off the storefront
|
|
1799
|
+
* the widget is running on. A relative path resolves against the page the
|
|
1800
|
+
* widget is on, which for a storefront embed is the shop itself.
|
|
1801
|
+
*/
|
|
1802
|
+
declare const PRODUCT_PATH_PREFIX = "/products/";
|
|
1803
|
+
/**
|
|
1804
|
+
* Maps one item the `/suggest` response reported onto the strip's `Product`
|
|
1805
|
+
* shape. Pure, so a Tier 3 consumer rendering its own strip from
|
|
1806
|
+
* `customFields` gets the same cards the built-in one draws.
|
|
1807
|
+
*
|
|
1808
|
+
* An item without a `handle` yields a card without a `url`: still activatable,
|
|
1809
|
+
* still emitting `onProductSelect`, just nothing for cmd-click to open.
|
|
1810
|
+
*/
|
|
1811
|
+
declare function productFromMatchedItem(item: MatchedItem): Product;
|
|
1812
|
+
/**
|
|
1813
|
+
* The strip's contents for a response's catalog report. `null` — no block on
|
|
1814
|
+
* the response — is an empty strip rather than "keep the previous one": the
|
|
1815
|
+
* previous items answered a previous query, and a strip must never show
|
|
1816
|
+
* results belonging to an older one.
|
|
1817
|
+
*/
|
|
1818
|
+
declare function productsFromCustomFields(report: CustomFieldsReport | null | undefined): Product[];
|
|
1819
|
+
|
|
1672
1820
|
declare class ModeController {
|
|
1673
1821
|
private container;
|
|
1674
1822
|
private mode;
|
|
@@ -1730,6 +1878,13 @@ interface SubmitResultExtras {
|
|
|
1730
1878
|
identifiedParams?: IdentifiedParamState[];
|
|
1731
1879
|
/** Server's "query is complete" verdict (`state.isReady`). Default: false. */
|
|
1732
1880
|
isReady?: boolean;
|
|
1881
|
+
/**
|
|
1882
|
+
* The catalog grounding report the latest response carried
|
|
1883
|
+
* (`state.customFields`). Default: none, and the result then has no
|
|
1884
|
+
* `custom_fields` key at all — mirroring the wire, where the block is absent
|
|
1885
|
+
* rather than null when no catalog was read.
|
|
1886
|
+
*/
|
|
1887
|
+
customFields?: CustomFieldsReport | null;
|
|
1733
1888
|
}
|
|
1734
1889
|
/**
|
|
1735
1890
|
* Builds the `AutocompleteResult` handed to `onSubmit` and `onResult`: the
|
|
@@ -1743,4 +1898,4 @@ interface SubmitResultExtras {
|
|
|
1743
1898
|
*/
|
|
1744
1899
|
declare function buildSubmitResult(text: string, completedParams: CompletedParamState[], skippedParams?: SkippedParamState[], extras?: SubmitResultExtras): AutocompleteResult;
|
|
1745
1900
|
|
|
1746
|
-
export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, DATE_RANGE_META_END, DATE_RANGE_META_START, type DateMonthView, type DateRange, type DateSelection, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, type Product, type ProductsConfig, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type TaskKind, WEEKDAY_LABELS, addMonths, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, computeOptionsGridLayout, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionEnterDelayMs, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };
|
|
1901
|
+
export { AIAutocomplete, type APIConfig, type APIKeyConfig, ATTRIBUTION_URL, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteRequest, type AutocompleteResponse, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type CustomFieldsReport, DATE_RANGE_META_END, DATE_RANGE_META_START, type DateMonthView, type DateRange, type DateSelection, type ExpressedFilter, type FilterOp, type FormatType, type IdentifiedParam, type IdentifiedParamState, type InputItem, type LooseDateOptions, type MatchedItem, type MatchedItems, ModeController, OPTIONS_GRID_MOBILE_QUERY, OPTION_ENTER_DELAY_VAR, OPTION_ENTER_FADE_MS, OPTION_ENTER_RISE_MS, OPTION_ENTER_RISE_PX, OPTION_ENTER_STAGGER_MS, type OptionOverride, type OptionOverrides, type OptionsGridLayout, type OptionsGridPlan, PLACEHOLDER_FADE_OUT_MS, PLACEHOLDER_LEAVING_ATTR, PLACEHOLDER_SWAP_GAP_MS, PLACEHOLDER_TYPE_MS, PLACEHOLDER_WORD_PAUSE_MS, PRODUCT_PATH_PREFIX, type Product, type ProductsConfig, RANGE_SEPARATOR, type RecentlySuggested, type RenderMode, SCROLL_ARROW_ATTR, SCROLL_ARROW_BOTTOM_VAR, SCROLL_ARROW_CLASS, SCROLL_ARROW_FADE_MS, SCROLL_ARROW_LABEL, SCROLL_ARROW_SCROLL_IDLE_MS, SCROLL_ARROW_VISIBLE_ATTR, SKIPPED_PARAM_TEXT, type ScrollArrowArgs, type ScrollArrowController, type Segment, type SkippedParamState, type Store, type SubmitResultExtras, type Suggestion, type SuggestionOption, type TaskKind, WEEKDAY_LABELS, addMonths, attachScrollArrow, buildAttributionUrl, buildDateOptions, buildQuery, buildSubmitResult, cellDay, cellIso, computeOptionsGridLayout, createStore, cursorIsAtEnd, dateCellMarks, dateSelectionFor, extractPlainText, formatAbsoluteDate, formatDate, formatDateRange, getCursorOffset, getFooterHint, identifiedParamLabel, isCalendarFormat, isOptionsGridMobileViewport, isoDate, measureOptionsGrid, monthLabel, needsOptionsGridMeasurement, optionEnterDelayMs, optionLabel, optionsEntranceDurationMs, optionsGridTemplateColumns, parseDate, parseLooseDate, parseLooseDateRange, plainTextLength, planOptionsGrid, previousGraphemeBoundary, productFromMatchedItem, productsFromCustomFields, renderEditableContent, resolveFormatType, resolveIdentifiedDate, sanitizeOptionIconSvg, scrollCaretIntoView, selectedIsoFromText, selectedRangeFor, setCursorOffset, toWireIdentifiedParams, visibleDateRange, withSkippedParams };
|