@magicx-eng/ai-autocomplete-vanilla 0.36.1 → 0.38.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 +8 -13
- package/dist/index.d.mts +36 -24
- package/dist/index.d.ts +36 -24
- 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
|
@@ -14,7 +14,7 @@ A framework-agnostic vanilla JS/TypeScript library that provides a guided AI-pow
|
|
|
14
14
|
- **Access token auth** — short-lived tokens with automatic refresh, single-flight deduplication, and 401 retry
|
|
15
15
|
- **Keyboard navigation** — arrow keys, enter to submit, tab to autocomplete, backspace to un-bold the last completed param
|
|
16
16
|
- **Client-side filtering** — instant substring filtering on every keystroke
|
|
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
|
|
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 date-range parameter 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
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
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`
|
|
@@ -78,6 +78,7 @@ const ac = new AIAutocomplete(container, {
|
|
|
78
78
|
optionOverrides: { location: async (query, signal) => [...] }, // see "Option Overrides"
|
|
79
79
|
columns: 2,
|
|
80
80
|
maskCompletedText: false, // when true, omits completed params' text from API requests (PII masking)
|
|
81
|
+
commitOnWordEnd: false, // true = a word still being typed never becomes a chip until a space, Enter, or Tab ends it (exact matches and server identified params). Picking an option is unchanged.
|
|
81
82
|
additionalContext: { tier: "gold" }, // optional user context, to personalize suggestions and options
|
|
82
83
|
|
|
83
84
|
// Appearance
|
|
@@ -431,11 +432,9 @@ new AIAutocomplete(container, { ..., submitButton: null });
|
|
|
431
432
|
### Datepicker
|
|
432
433
|
|
|
433
434
|
When the next parameter is a date, the dropdown shows a calendar instead of a
|
|
434
|
-
list of options.
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
relative phrases (`today`, `next week`) are not read as dates; a parameter
|
|
438
|
-
offering those needs a name that says date.
|
|
435
|
+
list of options. Which parameters are dates is the server's call: one whose
|
|
436
|
+
`type` is `date` gets a calendar, and one without a date type keeps its option
|
|
437
|
+
list, however date-like its name or options look.
|
|
439
438
|
|
|
440
439
|
Nothing is required to switch it on — a date parameter renders this way
|
|
441
440
|
automatically, and every other parameter is unaffected. Tier 1 and Tier 2 render
|
|
@@ -503,19 +502,15 @@ say which, and phrases like `next friday`. Those still open the calendar, just
|
|
|
503
502
|
on the current month with nothing marked, so the user picks rather than being
|
|
504
503
|
shown a guess that might be wrong.
|
|
505
504
|
|
|
506
|
-
**Date ranges.** A parameter whose
|
|
507
|
-
|
|
508
|
-
in two clicks: the first sets the start, the second the end, and the pair
|
|
505
|
+
**Date ranges.** A parameter whose `type` is `date_range` is answered by the
|
|
506
|
+
same calendar in two clicks: the first sets the start, the second the end, and the pair
|
|
509
507
|
commits as one answer. The days between them band as the user moves across the
|
|
510
508
|
calendar, so the span being chosen is visible before it is committed. Paging the
|
|
511
509
|
month between the two clicks is expected — that is how a span crosses months —
|
|
512
510
|
and <kbd>Esc</kbd> drops the start and lets them begin again. Clicking the end
|
|
513
511
|
before the start is fine; the two are ordered on the way in.
|
|
514
512
|
|
|
515
|
-
|
|
516
|
-
either separator (`-`, `–`, `—`, `to`, `through`, `until`), either half in any
|
|
517
|
-
date format the SDK reads, and a name that says so (`date_range`, `dateRange`)
|
|
518
|
-
counts too. It commits as one parameter, written the way it was offered —
|
|
513
|
+
It commits as one parameter, written as a span —
|
|
519
514
|
`September 11 - October 13`, with the year on whichever end needs it — and both
|
|
520
515
|
ends are also recorded on the completed parameter's `metadata` as `YYYY-MM-DD`,
|
|
521
516
|
under the `DATE_RANGE_META_START` / `DATE_RANGE_META_END` keys this package
|
package/dist/index.d.mts
CHANGED
|
@@ -57,8 +57,9 @@ interface SuggestionOption {
|
|
|
57
57
|
parameter?: string;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* The value type of a
|
|
61
|
-
*
|
|
60
|
+
* The value type of a parameter — which picker it needs. The server sends it
|
|
61
|
+
* for every date or date-range parameter; a parameter without one is answered
|
|
62
|
+
* from its options.
|
|
62
63
|
*/
|
|
63
64
|
interface SuggestionType {
|
|
64
65
|
kind: "string" | "numeric" | "date" | "date_range" | "boolean";
|
|
@@ -81,6 +82,11 @@ interface InputItem {
|
|
|
81
82
|
state: "completed" | "in_progress";
|
|
82
83
|
/** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
|
|
83
84
|
source?: "selected" | "identified";
|
|
85
|
+
/**
|
|
86
|
+
* The value type of the parameter this span was identified as. A span whose
|
|
87
|
+
* type names a date or date range opens a calendar when tapped.
|
|
88
|
+
*/
|
|
89
|
+
type?: SuggestionType;
|
|
84
90
|
}
|
|
85
91
|
/** Wire shape for an LLM-identified param echoed back to the server. */
|
|
86
92
|
interface IdentifiedParam {
|
|
@@ -295,6 +301,8 @@ interface IdentifiedParamState {
|
|
|
295
301
|
id: string;
|
|
296
302
|
parameter: string;
|
|
297
303
|
text: string;
|
|
304
|
+
/** The span's value type, from its `input` item. */
|
|
305
|
+
type?: SuggestionType;
|
|
298
306
|
}
|
|
299
307
|
type Segment = {
|
|
300
308
|
type: "text";
|
|
@@ -592,30 +600,20 @@ type FormatType = "options" | "date" | "date-range";
|
|
|
592
600
|
/** Whether this format is answered by a calendar rather than by a list. */
|
|
593
601
|
declare function isCalendarFormat(format: FormatType): boolean;
|
|
594
602
|
/**
|
|
595
|
-
* Decide how a
|
|
596
|
-
*
|
|
597
|
-
* The server cannot send a `formatType` yet, so a suggestion that holds a date
|
|
598
|
-
* is detected here — by the options it offers, and failing that by its name —
|
|
599
|
-
* and rendered as a calendar with those options ignored.
|
|
603
|
+
* Decide how a parameter should be answered — from the value type the server
|
|
604
|
+
* names on it, and nothing else.
|
|
600
605
|
*
|
|
601
|
-
* The
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
606
|
+
* The server sets `type` on every date and date-range parameter, so one
|
|
607
|
+
* without it is an option list, whatever its name, options or text look like.
|
|
608
|
+
* The SDK never guesses: guessing from options read a "Ring size" offering
|
|
609
|
+
* "4.75", "7.25" and "8.5" as three dates and replaced its sizes with a
|
|
610
|
+
* calendar.
|
|
605
611
|
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
* parameter, whatever its name says.
|
|
610
|
-
*
|
|
611
|
-
* Accepts anything with a `parameter`, not a `Suggestion`, so re-edit can ask
|
|
612
|
-
* the same question about a completed param via its `suggestionParameter`.
|
|
613
|
-
* A suggestion whose `type` names a date or date-range parameter is that,
|
|
614
|
-
* whatever its options and name say.
|
|
612
|
+
* Accepts anything with a `type`, not a `Suggestion`, so re-edit can ask the
|
|
613
|
+
* same question about a completed param via its `suggestionValueType`, and an
|
|
614
|
+
* identified span via its own `type`.
|
|
615
615
|
*/
|
|
616
616
|
declare function resolveFormatType(source: {
|
|
617
|
-
parameter: string;
|
|
618
|
-
options?: SuggestionOption[];
|
|
619
617
|
type?: SuggestionType;
|
|
620
618
|
} | undefined | null): FormatType;
|
|
621
619
|
|
|
@@ -925,6 +923,8 @@ interface CoreOptions {
|
|
|
925
923
|
apiConfig?: APIConfig;
|
|
926
924
|
optionOverrides?: OptionOverrides;
|
|
927
925
|
maskCompletedText?: boolean;
|
|
926
|
+
/** When true, a word the user is still typing never becomes a chip. The word becomes a chip when it ends: a space, Enter, or Tab. Default: false. */
|
|
927
|
+
commitOnWordEnd?: boolean;
|
|
928
928
|
/**
|
|
929
929
|
* Optional user context. Include whatever you know about the user — a
|
|
930
930
|
* profile, preferences, workspace, anything — to personalize suggested
|
|
@@ -1136,6 +1136,10 @@ declare class AIAutocomplete {
|
|
|
1136
1136
|
private funnelTelemetry;
|
|
1137
1137
|
/** A `search_started` that happened before any response said whether to send it. */
|
|
1138
1138
|
private pendingSearchStarted;
|
|
1139
|
+
/** The text at the last user keystroke, while its last word is still open. */
|
|
1140
|
+
private openWordText;
|
|
1141
|
+
/** Identified params held back until the word they end ends. */
|
|
1142
|
+
private heldIdentified;
|
|
1139
1143
|
/** What the last `impression` showed, so an identical response doesn't resend it. */
|
|
1140
1144
|
private lastImpressionKey;
|
|
1141
1145
|
private readonly emitSubmit;
|
|
@@ -1231,8 +1235,8 @@ declare class AIAutocomplete {
|
|
|
1231
1235
|
/**
|
|
1232
1236
|
* Open the calendar for a span the server identified as a date.
|
|
1233
1237
|
*
|
|
1234
|
-
* Returns false for anything else — an identified span whose type
|
|
1235
|
-
*
|
|
1238
|
+
* Returns false for anything else — an identified span whose `type` the
|
|
1239
|
+
* server didn't name as a date or date range stays inert.
|
|
1236
1240
|
*
|
|
1237
1241
|
* The span's own text is read for a starting month (`parseLooseDate`), but
|
|
1238
1242
|
* failing to read it is not a failure: the calendar opens either way, and
|
|
@@ -1382,6 +1386,14 @@ declare class AIAutocomplete {
|
|
|
1382
1386
|
private subscribeSkeletonMirror;
|
|
1383
1387
|
private subscribeNewParamTimer;
|
|
1384
1388
|
private handleChange;
|
|
1389
|
+
/** True while commitOnWordEnd is on and the user still types the last word. */
|
|
1390
|
+
private isWordOpen;
|
|
1391
|
+
private admitIdentified;
|
|
1392
|
+
/**
|
|
1393
|
+
* Ends the word the user is typing. Makes the chip for an exact match and
|
|
1394
|
+
* admits the held identified params. Returns true when it changed anything.
|
|
1395
|
+
*/
|
|
1396
|
+
private endTypedWord;
|
|
1385
1397
|
/**
|
|
1386
1398
|
* Opens the pending span on the first keystroke past covered text: there is
|
|
1387
1399
|
* unresolved trailing text beyond the covered offset (filterBase / last pill
|
package/dist/index.d.ts
CHANGED
|
@@ -57,8 +57,9 @@ interface SuggestionOption {
|
|
|
57
57
|
parameter?: string;
|
|
58
58
|
}
|
|
59
59
|
/**
|
|
60
|
-
* The value type of a
|
|
61
|
-
*
|
|
60
|
+
* The value type of a parameter — which picker it needs. The server sends it
|
|
61
|
+
* for every date or date-range parameter; a parameter without one is answered
|
|
62
|
+
* from its options.
|
|
62
63
|
*/
|
|
63
64
|
interface SuggestionType {
|
|
64
65
|
kind: "string" | "numeric" | "date" | "date_range" | "boolean";
|
|
@@ -81,6 +82,11 @@ interface InputItem {
|
|
|
81
82
|
state: "completed" | "in_progress";
|
|
82
83
|
/** Absent or "selected" = echo of client params; "identified" = LLM-inferred. */
|
|
83
84
|
source?: "selected" | "identified";
|
|
85
|
+
/**
|
|
86
|
+
* The value type of the parameter this span was identified as. A span whose
|
|
87
|
+
* type names a date or date range opens a calendar when tapped.
|
|
88
|
+
*/
|
|
89
|
+
type?: SuggestionType;
|
|
84
90
|
}
|
|
85
91
|
/** Wire shape for an LLM-identified param echoed back to the server. */
|
|
86
92
|
interface IdentifiedParam {
|
|
@@ -295,6 +301,8 @@ interface IdentifiedParamState {
|
|
|
295
301
|
id: string;
|
|
296
302
|
parameter: string;
|
|
297
303
|
text: string;
|
|
304
|
+
/** The span's value type, from its `input` item. */
|
|
305
|
+
type?: SuggestionType;
|
|
298
306
|
}
|
|
299
307
|
type Segment = {
|
|
300
308
|
type: "text";
|
|
@@ -592,30 +600,20 @@ type FormatType = "options" | "date" | "date-range";
|
|
|
592
600
|
/** Whether this format is answered by a calendar rather than by a list. */
|
|
593
601
|
declare function isCalendarFormat(format: FormatType): boolean;
|
|
594
602
|
/**
|
|
595
|
-
* Decide how a
|
|
596
|
-
*
|
|
597
|
-
* The server cannot send a `formatType` yet, so a suggestion that holds a date
|
|
598
|
-
* is detected here — by the options it offers, and failing that by its name —
|
|
599
|
-
* and rendered as a calendar with those options ignored.
|
|
603
|
+
* Decide how a parameter should be answered — from the value type the server
|
|
604
|
+
* names on it, and nothing else.
|
|
600
605
|
*
|
|
601
|
-
* The
|
|
602
|
-
*
|
|
603
|
-
*
|
|
604
|
-
*
|
|
606
|
+
* The server sets `type` on every date and date-range parameter, so one
|
|
607
|
+
* without it is an option list, whatever its name, options or text look like.
|
|
608
|
+
* The SDK never guesses: guessing from options read a "Ring size" offering
|
|
609
|
+
* "4.75", "7.25" and "8.5" as three dates and replaced its sizes with a
|
|
610
|
+
* calendar.
|
|
605
611
|
*
|
|
606
|
-
*
|
|
607
|
-
*
|
|
608
|
-
*
|
|
609
|
-
* parameter, whatever its name says.
|
|
610
|
-
*
|
|
611
|
-
* Accepts anything with a `parameter`, not a `Suggestion`, so re-edit can ask
|
|
612
|
-
* the same question about a completed param via its `suggestionParameter`.
|
|
613
|
-
* A suggestion whose `type` names a date or date-range parameter is that,
|
|
614
|
-
* whatever its options and name say.
|
|
612
|
+
* Accepts anything with a `type`, not a `Suggestion`, so re-edit can ask the
|
|
613
|
+
* same question about a completed param via its `suggestionValueType`, and an
|
|
614
|
+
* identified span via its own `type`.
|
|
615
615
|
*/
|
|
616
616
|
declare function resolveFormatType(source: {
|
|
617
|
-
parameter: string;
|
|
618
|
-
options?: SuggestionOption[];
|
|
619
617
|
type?: SuggestionType;
|
|
620
618
|
} | undefined | null): FormatType;
|
|
621
619
|
|
|
@@ -925,6 +923,8 @@ interface CoreOptions {
|
|
|
925
923
|
apiConfig?: APIConfig;
|
|
926
924
|
optionOverrides?: OptionOverrides;
|
|
927
925
|
maskCompletedText?: boolean;
|
|
926
|
+
/** When true, a word the user is still typing never becomes a chip. The word becomes a chip when it ends: a space, Enter, or Tab. Default: false. */
|
|
927
|
+
commitOnWordEnd?: boolean;
|
|
928
928
|
/**
|
|
929
929
|
* Optional user context. Include whatever you know about the user — a
|
|
930
930
|
* profile, preferences, workspace, anything — to personalize suggested
|
|
@@ -1136,6 +1136,10 @@ declare class AIAutocomplete {
|
|
|
1136
1136
|
private funnelTelemetry;
|
|
1137
1137
|
/** A `search_started` that happened before any response said whether to send it. */
|
|
1138
1138
|
private pendingSearchStarted;
|
|
1139
|
+
/** The text at the last user keystroke, while its last word is still open. */
|
|
1140
|
+
private openWordText;
|
|
1141
|
+
/** Identified params held back until the word they end ends. */
|
|
1142
|
+
private heldIdentified;
|
|
1139
1143
|
/** What the last `impression` showed, so an identical response doesn't resend it. */
|
|
1140
1144
|
private lastImpressionKey;
|
|
1141
1145
|
private readonly emitSubmit;
|
|
@@ -1231,8 +1235,8 @@ declare class AIAutocomplete {
|
|
|
1231
1235
|
/**
|
|
1232
1236
|
* Open the calendar for a span the server identified as a date.
|
|
1233
1237
|
*
|
|
1234
|
-
* Returns false for anything else — an identified span whose type
|
|
1235
|
-
*
|
|
1238
|
+
* Returns false for anything else — an identified span whose `type` the
|
|
1239
|
+
* server didn't name as a date or date range stays inert.
|
|
1236
1240
|
*
|
|
1237
1241
|
* The span's own text is read for a starting month (`parseLooseDate`), but
|
|
1238
1242
|
* failing to read it is not a failure: the calendar opens either way, and
|
|
@@ -1382,6 +1386,14 @@ declare class AIAutocomplete {
|
|
|
1382
1386
|
private subscribeSkeletonMirror;
|
|
1383
1387
|
private subscribeNewParamTimer;
|
|
1384
1388
|
private handleChange;
|
|
1389
|
+
/** True while commitOnWordEnd is on and the user still types the last word. */
|
|
1390
|
+
private isWordOpen;
|
|
1391
|
+
private admitIdentified;
|
|
1392
|
+
/**
|
|
1393
|
+
* Ends the word the user is typing. Makes the chip for an exact match and
|
|
1394
|
+
* admits the held identified params. Returns true when it changed anything.
|
|
1395
|
+
*/
|
|
1396
|
+
private endTypedWord;
|
|
1385
1397
|
/**
|
|
1386
1398
|
* Opens the pending span on the first keystroke past covered text: there is
|
|
1387
1399
|
* unresolved trailing text beyond the covered offset (filterBase / last pill
|