@magicx-eng/ai-autocomplete-vanilla 0.1.14 → 0.1.16
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 +28 -11
- package/index.d.mts +96 -0
- package/index.d.ts +96 -0
- package/index.js +194 -65
- package/index.js.map +1 -1
- package/index.mjs +194 -65
- package/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,16 +6,20 @@ A framework-agnostic vanilla JS/TypeScript library that provides a guided AI-pow
|
|
|
6
6
|
|
|
7
7
|
- **Three tiers of integration** — full drop-in component, dropdown-only, or fully headless
|
|
8
8
|
- **Zero dependencies** — no React, no framework, no virtual DOM
|
|
9
|
-
- **
|
|
10
|
-
- **Pill
|
|
9
|
+
- **Rich inline input** — a single `contentEditable` surface: typed text, bold completed params, and inline pills all share one editing context
|
|
10
|
+
- **Pill-based input** — non-editable inline pills for unfilled parameters, bold inline text for completed ones
|
|
11
|
+
- **Instant exact-match bolding** — typing the full text of an option immediately promotes it to a completed param (no debounced fetch wait). Works in the normal typing flow *and* while re-editing an existing completed param.
|
|
12
|
+
- **Re-edit completed params** — tap a bold completed param to replace it; the dropdown re-opens with the cached options the server originally returned for that param
|
|
11
13
|
- **Light/dark mode** — built-in themes with `prefers-color-scheme` support, fully overridable via CSS variables
|
|
12
14
|
- **Access token auth** — short-lived tokens with automatic refresh, single-flight deduplication, and 401 retry
|
|
13
|
-
- **Keyboard navigation** — arrow keys, enter to submit, tab to autocomplete
|
|
15
|
+
- **Keyboard navigation** — arrow keys, enter to submit, tab to autocomplete, backspace to un-bold the last completed param
|
|
14
16
|
- **Client-side filtering** — instant substring filtering on every keystroke
|
|
15
17
|
- **Option overrides** — inject or dynamically generate client-side options per suggestion type
|
|
16
18
|
- **Controlled & uncontrolled** — works out of the box or integrates with external state
|
|
17
|
-
- **Accessible** — ARIA combobox pattern with `role="listbox"`, `aria-activedescendant`
|
|
19
|
+
- **Accessible** — ARIA combobox 1.2 pattern with `role="listbox"`, `aria-activedescendant`
|
|
20
|
+
- **IME-safe** — composition events are buffered so input text is committed once, after composition ends
|
|
18
21
|
- **Animations** — option selection streak animation, text shimmer on newly added params
|
|
22
|
+
- **Loading skeleton** — while a fetch is in flight, the dropdown and inline pills keep the previous layout (same count and widths) with their text masked and a shimmer pulse. The skeleton is held back until the selection streak animation finishes, so taps don't visually "stutter" into loading.
|
|
19
23
|
- **Lightweight** — ~10 KB gzipped, styles auto-injected at runtime
|
|
20
24
|
- **TypeScript first** — full type definitions shipped with the package
|
|
21
25
|
- **SSR-safe** — no top-level `document`/`window` access
|
|
@@ -115,7 +119,13 @@ ac.update({ animations: false, optionsPosition: "above" });
|
|
|
115
119
|
|
|
116
120
|
> **Tier 1 auto-resets** after both Enter key and built-in submit-button clicks — your `onSubmit` runs, then the SDK clears the input and starts a new session. You don't need to call `ac.reset()` yourself in Tier 1.
|
|
117
121
|
|
|
118
|
-
> `autoFocus`, `focus()`, and `blur()` only operate on the
|
|
122
|
+
> `autoFocus`, `focus()`, and `blur()` only operate on the contentEditable editor the library owns (Tier 1 / `renderMode: "full"`). In Tier 2/3, the consumer owns the input and calls `.focus()` / `.blur()` on their own element; the `onFocus` / `onBlur` callbacks still fire whenever `setFocused()` is called.
|
|
123
|
+
|
|
124
|
+
> **Backspace into a completed param** — pressing Backspace while the caret is inside (or immediately after) a bold completed param drops the param's "completed" status and removes one grapheme before the caret. The remaining text stays in the editor as plain (un-bold) text so the user can keep editing instead of losing the whole phrase.
|
|
125
|
+
|
|
126
|
+
> **Re-edit a completed param** — tapping a bold completed param enters *re-edit mode*. The dropdown re-opens with the cached options the server originally returned for that param. Typing atomically replaces the bold (and re-promotes it to bold if what you type exactly matches one of the cached options); clicking an option replaces it with the new selection; pressing Escape or moving the caret out exits without changes.
|
|
127
|
+
|
|
128
|
+
> **Caret placement after a completion** — whenever a completed param is added (by any means — option click, exact-match typing, or re-edit), the caret lands right after the trailing space following the bold so typing can continue immediately. A space is inserted if one wasn't already there.
|
|
119
129
|
|
|
120
130
|
#### Custom submit button
|
|
121
131
|
|
|
@@ -221,12 +231,14 @@ unsub();
|
|
|
221
231
|
| `suggestions` | `Suggestion[]` | All suggestions from server (including placeholder type) |
|
|
222
232
|
| `actionableSuggestions` | `Suggestion[]` | Non-placeholder suggestions (the pills) |
|
|
223
233
|
| `filteredOptions` | `SuggestionOption[]` | Options for the active suggestion, filtered by current query |
|
|
224
|
-
| `segments` | `Segment[]` | Input text split into typed text vs completed params —
|
|
234
|
+
| `segments` | `Segment[]` | Input text split into typed text vs completed params — completed segments render as bold `<strong>` runs inside the editor |
|
|
225
235
|
| `placeholderText` | `string` | Placeholder text from server suggestions (joined `placeholder`-type suggestion texts) |
|
|
226
236
|
| `activeDropdownIndex` | `number` | Highlighted option index (-1 = none) |
|
|
227
237
|
| `isDropdownOpen` | `boolean` | Whether the dropdown should be visible |
|
|
228
238
|
| `newParamId` | `string \| null` | ID of the most recently added param (for shimmer animation) |
|
|
229
|
-
| `isLoading` | `boolean` | Fetch in progress |
|
|
239
|
+
| `isLoading` | `boolean` | Fetch in progress. The Tier 1 / Tier 2 renderers gate the loading skeleton additionally on `!inSelectionAnimation` and `!editingParam`. |
|
|
240
|
+
| `inSelectionAnimation` | `boolean` | True for the 500 ms after a user-initiated option tap so the streak animation can finish before the dropdown switches to the loading skeleton. |
|
|
241
|
+
| `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. |
|
|
230
242
|
| `isReady` | `boolean` | Server indicates query is complete |
|
|
231
243
|
| `error` | `Error \| null` | Last fetch error |
|
|
232
244
|
|
|
@@ -240,7 +252,7 @@ unsub();
|
|
|
240
252
|
| `selectOption(option)` | Select a dropdown option. Updates text, creates completed param, triggers shimmer. |
|
|
241
253
|
| `setActiveDropdownIndex(index)` | Set the highlighted option (for mouse hover). |
|
|
242
254
|
| `setActivePill(index)` | Reorder pills — moves pill at `index` to front (active). |
|
|
243
|
-
| `removeLastParam()` | Remove last completed param
|
|
255
|
+
| `removeLastParam()` | Remove the last completed param from state. The text stays in the input as plain text. |
|
|
244
256
|
| `clearNewParamId()` | Clear shimmer animation state. |
|
|
245
257
|
| `reset()` | Clear all state, re-fetch initial suggestions, and start a new session (rotates `session_id`). Call this after handling submit. |
|
|
246
258
|
| `setValue(text)` | Set text (controlled mode). |
|
|
@@ -332,6 +344,7 @@ Override these on the container element. All built-in defaults use `:where()` (z
|
|
|
332
344
|
|
|
333
345
|
| Variable | Default (light) | Default (dark) | Description |
|
|
334
346
|
|---|---|---|---|
|
|
347
|
+
| `--aia-font-family` | `inherit` | `inherit` | Font used by the library. Defaults to `inherit` so the library picks up your page's font automatically. Set this to pin a specific font on the library without changing the surrounding page. |
|
|
335
348
|
| `--aia-pill-bg` | `#bdbdbd` | `#bdbdbd` | Pill background |
|
|
336
349
|
| `--aia-pill-color` | `#000000` | `#ffffff` | Pill text |
|
|
337
350
|
| `--aia-pill-font-size` | `19px` | `19px` | Pill font size |
|
|
@@ -341,13 +354,14 @@ Override these on the container element. All built-in defaults use `:where()` (z
|
|
|
341
354
|
| `--aia-option-font-size` | `19px` | `19px` | Option font size |
|
|
342
355
|
| `--aia-written-text-color` | `#000000` | `#ffffff` | Input text |
|
|
343
356
|
| `--aia-written-text-font-size` | `19px` | `19px` | Input text font size |
|
|
344
|
-
| `--aia-caret-color` | `--aia-written-text-color` | `--aia-written-text-color` |
|
|
357
|
+
| `--aia-caret-color` | `--aia-written-text-color` | `--aia-written-text-color` | Editor caret color. Override independently of input text color. |
|
|
345
358
|
| `--aia-submit-bg` | `#000000` | `#ffffff` | Submit button background |
|
|
346
359
|
| `--aia-submit-color` | `#ffffff` | `#000000` | Submit button icon color |
|
|
347
360
|
| `--aia-dropdown-bg` | — | — | Optional bg color the dropdown's "glass" rim shadow tints toward. Set this to the page background behind the dropdown so the bottom-corner glow blends seamlessly. |
|
|
348
361
|
| `--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). |
|
|
349
362
|
| `--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), …)`). |
|
|
350
363
|
| `--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. |
|
|
364
|
+
| `--aia-skeleton-bg` | `rgba(189, 189, 189, 0.51)` | `#333539` | Fill color for the loading skeleton bars and the masked text in cached pills/options. |
|
|
351
365
|
|
|
352
366
|
### Per-mode Overrides
|
|
353
367
|
|
|
@@ -373,14 +387,17 @@ For styling beyond the CSS variables, target these stable `data-aia-*` attribute
|
|
|
373
387
|
|
|
374
388
|
| Attribute | Element |
|
|
375
389
|
|---|---|
|
|
376
|
-
| `[data-aia-editor]` | Editor area wrapping the
|
|
377
|
-
| `[data-aia-
|
|
390
|
+
| `[data-aia-editor]` | Editor area wrapping the contentEditable + inline pill list |
|
|
391
|
+
| `[data-aia-input]` | The contentEditable `<div>` that owns typed text and bold completed params. Replaces the previous `[data-aia-textarea]` selector. |
|
|
392
|
+
| `[data-aia-pill-list-container]` | Inline sibling of the editor that holds unfilled-suggestion pills |
|
|
378
393
|
| `[data-aia-submit]` | Submit button |
|
|
379
394
|
| `[data-aia-pill]` | Each unfilled-suggestion pill |
|
|
380
395
|
| `[data-aia-pillbar]` | Pill bar container inside the dropdown |
|
|
381
396
|
| `[data-aia-option]` | Each suggestion option |
|
|
382
397
|
| `[data-aia-dropdown]` | The dropdown root (listbox) |
|
|
383
398
|
|
|
399
|
+
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`).
|
|
400
|
+
|
|
384
401
|
The vanilla core also exposes stable BEM class names (`magicx-aia-*`); both can be used.
|
|
385
402
|
|
|
386
403
|
```css
|
package/index.d.mts
CHANGED
|
@@ -22,8 +22,11 @@ interface Suggestion {
|
|
|
22
22
|
interface CompletedParamState extends CompletedParam {
|
|
23
23
|
id: string;
|
|
24
24
|
text: string;
|
|
25
|
+
/** Source suggestion's `type` — used by re-edit mode to render the dropdown pill. */
|
|
25
26
|
suggestionType: string;
|
|
27
|
+
/** Source suggestion's `text` — used by re-edit mode to render the dropdown pill. */
|
|
26
28
|
suggestionPlaceholder: string;
|
|
29
|
+
/** Cached options from the suggestion that produced this param — re-edit shows these. */
|
|
27
30
|
options: SuggestionOption[];
|
|
28
31
|
metadata?: Record<string, unknown>;
|
|
29
32
|
}
|
|
@@ -85,6 +88,25 @@ interface CoreState {
|
|
|
85
88
|
skipNextFetch: boolean;
|
|
86
89
|
lastRawQuery: string;
|
|
87
90
|
isFocused: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Re-edit state: while non-null, the user is editing a bold completed param.
|
|
93
|
+
* The snapshot stays here even after the param is removed from
|
|
94
|
+
* `completedParams` (when typing/backspace replaces its text), so the
|
|
95
|
+
* dropdown can keep filtering the cached options.
|
|
96
|
+
*/
|
|
97
|
+
editingParam: CompletedParamState | null;
|
|
98
|
+
/** Plain-text offset where the edited param started (anchor for the edit region). */
|
|
99
|
+
editingAnchor: number | null;
|
|
100
|
+
/** Plain-text offset of the right edge of the edit region. Caret outside [anchor, tail] exits edit mode. */
|
|
101
|
+
editingTail: number | null;
|
|
102
|
+
/** Current caret offset within the editor. Tracked via DOM `selectionchange`. */
|
|
103
|
+
caretOffset: number | null;
|
|
104
|
+
/**
|
|
105
|
+
* True for ~500ms after a user-initiated option selection so the streak
|
|
106
|
+
* animation can finish before the dropdown switches to its loading skeleton.
|
|
107
|
+
* Set by selectOption / selectOptionInEditMode, cleared by a timer.
|
|
108
|
+
*/
|
|
109
|
+
inSelectionAnimation: boolean;
|
|
88
110
|
}
|
|
89
111
|
/**
|
|
90
112
|
* Render mode:
|
|
@@ -136,6 +158,14 @@ interface CoreOptions {
|
|
|
136
158
|
onBlur?: () => void;
|
|
137
159
|
value?: string;
|
|
138
160
|
completedParams?: CompletedParamState[];
|
|
161
|
+
/**
|
|
162
|
+
* Headless-mode caret setter. The core invokes this in place of writing to
|
|
163
|
+
* its own `domRefs.input` when re-edit / Backspace flows need to park the
|
|
164
|
+
* caret at a specific plain-text offset. Wrappers that own the DOM (React,
|
|
165
|
+
* etc.) must provide this — vanilla "full" mode falls back to `domRefs`.
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
setCursor?: (offset: number) => void;
|
|
139
169
|
}
|
|
140
170
|
|
|
141
171
|
declare class AIAutocomplete {
|
|
@@ -154,6 +184,7 @@ declare class AIAutocomplete {
|
|
|
154
184
|
private dropdownRefs;
|
|
155
185
|
private newParamTimer;
|
|
156
186
|
private suggestionRemovalTimer;
|
|
187
|
+
private selectionAnimationTimer;
|
|
157
188
|
private externalListeners;
|
|
158
189
|
private sessionId;
|
|
159
190
|
constructor(container: HTMLElement, opts?: CoreOptions);
|
|
@@ -166,7 +197,54 @@ declare class AIAutocomplete {
|
|
|
166
197
|
setCompletedParams(params: CompletedParamState[]): void;
|
|
167
198
|
setActivePill(index: number): void;
|
|
168
199
|
removeLastParam(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Backspace inside a completed param: drop the param's "completed" status so
|
|
202
|
+
* it renders as plain (un-bold) text, AND remove one grapheme before the
|
|
203
|
+
* caret — same single-character delete a normal Backspace would do. The
|
|
204
|
+
* remaining text stays in the input so the user can continue editing what
|
|
205
|
+
* they had typed instead of losing the whole phrase.
|
|
206
|
+
*
|
|
207
|
+
* Returns true when a param was reconciled (caller should `preventDefault`).
|
|
208
|
+
*/
|
|
209
|
+
removeParamAtCaret(offset: number): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Set the editor caret at the given plain-text offset. Uses the core's own
|
|
212
|
+
* `domRefs.input` in "full" mode; falls back to the wrapper-provided
|
|
213
|
+
* `setCursor` callback in "headless" mode where the wrapper owns the DOM.
|
|
214
|
+
*/
|
|
215
|
+
private scheduleSetCursor;
|
|
169
216
|
clearNewParamId(): void;
|
|
217
|
+
/**
|
|
218
|
+
* Enter re-edit mode for the bold completed param with the given id. The
|
|
219
|
+
* caller is responsible for highlighting the param via the Selection API
|
|
220
|
+
* (DOM concern). This method just sets the state snapshot so the dropdown
|
|
221
|
+
* starts filtering the param's cached options.
|
|
222
|
+
*/
|
|
223
|
+
startEditingParam(paramId: string): void;
|
|
224
|
+
/**
|
|
225
|
+
* Replace the editing range (`text[editingAnchor..editingTail]`) with the
|
|
226
|
+
* given replacement. Used by the DOM layer's `beforeinput` intercept: while
|
|
227
|
+
* the edited param's strong still exists in `completedParams`, typing or
|
|
228
|
+
* backspace should swap the WHOLE param atomically (instead of inserting
|
|
229
|
+
* one char into the bold span). Returns true when the replacement was
|
|
230
|
+
* applied — callers should `preventDefault` only in that case.
|
|
231
|
+
*/
|
|
232
|
+
replaceEditingRange(replacement: string): boolean;
|
|
233
|
+
/** Clear re-edit state. Selection collapsing is a DOM concern handled by the caller. */
|
|
234
|
+
exitEditMode(): void;
|
|
235
|
+
/**
|
|
236
|
+
* Update caret offset after a text-input event. While in edit mode, extends
|
|
237
|
+
* `editingTail` to keep up with the user typing past the previous tail.
|
|
238
|
+
* Exits edit mode if the user backspaced past `editingAnchor` (deleting a
|
|
239
|
+
* character before where the edit started).
|
|
240
|
+
*/
|
|
241
|
+
handleCaretAfterInput(offset: number | null): void;
|
|
242
|
+
/**
|
|
243
|
+
* Update caret offset from a selection-move event that was NOT preceded by
|
|
244
|
+
* an input event (so the user moved the cursor by click or arrows, not by
|
|
245
|
+
* typing). Exits edit mode if the caret moved outside the edit region.
|
|
246
|
+
*/
|
|
247
|
+
handleCaretMove(offset: number | null): void;
|
|
170
248
|
setActiveDropdownIndex(index: number): void;
|
|
171
249
|
handleTextChange(value: string): void;
|
|
172
250
|
handleKeyDown(e: KeyboardEvent): void;
|
|
@@ -179,6 +257,8 @@ declare class AIAutocomplete {
|
|
|
179
257
|
on(event: string, callback: (...args: unknown[]) => void): () => void;
|
|
180
258
|
update(opts: Partial<CoreOptions>): void;
|
|
181
259
|
selectOption(option: SuggestionOption): void;
|
|
260
|
+
private startSelectionAnimationTimer;
|
|
261
|
+
private selectOptionInEditMode;
|
|
182
262
|
private fireTelemetry;
|
|
183
263
|
private recomputeDerived;
|
|
184
264
|
private setupContainer;
|
|
@@ -189,6 +269,22 @@ declare class AIAutocomplete {
|
|
|
189
269
|
/** Auto-clear newParamId after shimmer animation. */
|
|
190
270
|
private subscribeNewParamTimer;
|
|
191
271
|
private handleChange;
|
|
272
|
+
/**
|
|
273
|
+
* When the user has typed text that exactly matches (case-insensitive) one
|
|
274
|
+
* of the active suggestion's options, promote it to a completed param right
|
|
275
|
+
* away. The fetchController does the same check when the debounced fetch
|
|
276
|
+
* lands; doing it instantly here means bold styling appears as soon as the
|
|
277
|
+
* option is fully typed, without waiting 100–300ms for the round-trip.
|
|
278
|
+
*/
|
|
279
|
+
private maybePromoteExactMatch;
|
|
280
|
+
/**
|
|
281
|
+
* Edit-mode counterpart to {@link maybePromoteExactMatch}. When the user is
|
|
282
|
+
* editing a bold completed param and the typed text exactly matches one of
|
|
283
|
+
* that param's cached options, promote it back to a completed param (bold)
|
|
284
|
+
* — same instant-bold affordance as the normal typing flow, just driven by
|
|
285
|
+
* the edited param's cached options instead of the active suggestion.
|
|
286
|
+
*/
|
|
287
|
+
private maybePromoteEditExactMatch;
|
|
192
288
|
}
|
|
193
289
|
|
|
194
290
|
type Listener<S> = (next: S, prev: S) => void;
|
package/index.d.ts
CHANGED
|
@@ -22,8 +22,11 @@ interface Suggestion {
|
|
|
22
22
|
interface CompletedParamState extends CompletedParam {
|
|
23
23
|
id: string;
|
|
24
24
|
text: string;
|
|
25
|
+
/** Source suggestion's `type` — used by re-edit mode to render the dropdown pill. */
|
|
25
26
|
suggestionType: string;
|
|
27
|
+
/** Source suggestion's `text` — used by re-edit mode to render the dropdown pill. */
|
|
26
28
|
suggestionPlaceholder: string;
|
|
29
|
+
/** Cached options from the suggestion that produced this param — re-edit shows these. */
|
|
27
30
|
options: SuggestionOption[];
|
|
28
31
|
metadata?: Record<string, unknown>;
|
|
29
32
|
}
|
|
@@ -85,6 +88,25 @@ interface CoreState {
|
|
|
85
88
|
skipNextFetch: boolean;
|
|
86
89
|
lastRawQuery: string;
|
|
87
90
|
isFocused: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Re-edit state: while non-null, the user is editing a bold completed param.
|
|
93
|
+
* The snapshot stays here even after the param is removed from
|
|
94
|
+
* `completedParams` (when typing/backspace replaces its text), so the
|
|
95
|
+
* dropdown can keep filtering the cached options.
|
|
96
|
+
*/
|
|
97
|
+
editingParam: CompletedParamState | null;
|
|
98
|
+
/** Plain-text offset where the edited param started (anchor for the edit region). */
|
|
99
|
+
editingAnchor: number | null;
|
|
100
|
+
/** Plain-text offset of the right edge of the edit region. Caret outside [anchor, tail] exits edit mode. */
|
|
101
|
+
editingTail: number | null;
|
|
102
|
+
/** Current caret offset within the editor. Tracked via DOM `selectionchange`. */
|
|
103
|
+
caretOffset: number | null;
|
|
104
|
+
/**
|
|
105
|
+
* True for ~500ms after a user-initiated option selection so the streak
|
|
106
|
+
* animation can finish before the dropdown switches to its loading skeleton.
|
|
107
|
+
* Set by selectOption / selectOptionInEditMode, cleared by a timer.
|
|
108
|
+
*/
|
|
109
|
+
inSelectionAnimation: boolean;
|
|
88
110
|
}
|
|
89
111
|
/**
|
|
90
112
|
* Render mode:
|
|
@@ -136,6 +158,14 @@ interface CoreOptions {
|
|
|
136
158
|
onBlur?: () => void;
|
|
137
159
|
value?: string;
|
|
138
160
|
completedParams?: CompletedParamState[];
|
|
161
|
+
/**
|
|
162
|
+
* Headless-mode caret setter. The core invokes this in place of writing to
|
|
163
|
+
* its own `domRefs.input` when re-edit / Backspace flows need to park the
|
|
164
|
+
* caret at a specific plain-text offset. Wrappers that own the DOM (React,
|
|
165
|
+
* etc.) must provide this — vanilla "full" mode falls back to `domRefs`.
|
|
166
|
+
* @internal
|
|
167
|
+
*/
|
|
168
|
+
setCursor?: (offset: number) => void;
|
|
139
169
|
}
|
|
140
170
|
|
|
141
171
|
declare class AIAutocomplete {
|
|
@@ -154,6 +184,7 @@ declare class AIAutocomplete {
|
|
|
154
184
|
private dropdownRefs;
|
|
155
185
|
private newParamTimer;
|
|
156
186
|
private suggestionRemovalTimer;
|
|
187
|
+
private selectionAnimationTimer;
|
|
157
188
|
private externalListeners;
|
|
158
189
|
private sessionId;
|
|
159
190
|
constructor(container: HTMLElement, opts?: CoreOptions);
|
|
@@ -166,7 +197,54 @@ declare class AIAutocomplete {
|
|
|
166
197
|
setCompletedParams(params: CompletedParamState[]): void;
|
|
167
198
|
setActivePill(index: number): void;
|
|
168
199
|
removeLastParam(): void;
|
|
200
|
+
/**
|
|
201
|
+
* Backspace inside a completed param: drop the param's "completed" status so
|
|
202
|
+
* it renders as plain (un-bold) text, AND remove one grapheme before the
|
|
203
|
+
* caret — same single-character delete a normal Backspace would do. The
|
|
204
|
+
* remaining text stays in the input so the user can continue editing what
|
|
205
|
+
* they had typed instead of losing the whole phrase.
|
|
206
|
+
*
|
|
207
|
+
* Returns true when a param was reconciled (caller should `preventDefault`).
|
|
208
|
+
*/
|
|
209
|
+
removeParamAtCaret(offset: number): boolean;
|
|
210
|
+
/**
|
|
211
|
+
* Set the editor caret at the given plain-text offset. Uses the core's own
|
|
212
|
+
* `domRefs.input` in "full" mode; falls back to the wrapper-provided
|
|
213
|
+
* `setCursor` callback in "headless" mode where the wrapper owns the DOM.
|
|
214
|
+
*/
|
|
215
|
+
private scheduleSetCursor;
|
|
169
216
|
clearNewParamId(): void;
|
|
217
|
+
/**
|
|
218
|
+
* Enter re-edit mode for the bold completed param with the given id. The
|
|
219
|
+
* caller is responsible for highlighting the param via the Selection API
|
|
220
|
+
* (DOM concern). This method just sets the state snapshot so the dropdown
|
|
221
|
+
* starts filtering the param's cached options.
|
|
222
|
+
*/
|
|
223
|
+
startEditingParam(paramId: string): void;
|
|
224
|
+
/**
|
|
225
|
+
* Replace the editing range (`text[editingAnchor..editingTail]`) with the
|
|
226
|
+
* given replacement. Used by the DOM layer's `beforeinput` intercept: while
|
|
227
|
+
* the edited param's strong still exists in `completedParams`, typing or
|
|
228
|
+
* backspace should swap the WHOLE param atomically (instead of inserting
|
|
229
|
+
* one char into the bold span). Returns true when the replacement was
|
|
230
|
+
* applied — callers should `preventDefault` only in that case.
|
|
231
|
+
*/
|
|
232
|
+
replaceEditingRange(replacement: string): boolean;
|
|
233
|
+
/** Clear re-edit state. Selection collapsing is a DOM concern handled by the caller. */
|
|
234
|
+
exitEditMode(): void;
|
|
235
|
+
/**
|
|
236
|
+
* Update caret offset after a text-input event. While in edit mode, extends
|
|
237
|
+
* `editingTail` to keep up with the user typing past the previous tail.
|
|
238
|
+
* Exits edit mode if the user backspaced past `editingAnchor` (deleting a
|
|
239
|
+
* character before where the edit started).
|
|
240
|
+
*/
|
|
241
|
+
handleCaretAfterInput(offset: number | null): void;
|
|
242
|
+
/**
|
|
243
|
+
* Update caret offset from a selection-move event that was NOT preceded by
|
|
244
|
+
* an input event (so the user moved the cursor by click or arrows, not by
|
|
245
|
+
* typing). Exits edit mode if the caret moved outside the edit region.
|
|
246
|
+
*/
|
|
247
|
+
handleCaretMove(offset: number | null): void;
|
|
170
248
|
setActiveDropdownIndex(index: number): void;
|
|
171
249
|
handleTextChange(value: string): void;
|
|
172
250
|
handleKeyDown(e: KeyboardEvent): void;
|
|
@@ -179,6 +257,8 @@ declare class AIAutocomplete {
|
|
|
179
257
|
on(event: string, callback: (...args: unknown[]) => void): () => void;
|
|
180
258
|
update(opts: Partial<CoreOptions>): void;
|
|
181
259
|
selectOption(option: SuggestionOption): void;
|
|
260
|
+
private startSelectionAnimationTimer;
|
|
261
|
+
private selectOptionInEditMode;
|
|
182
262
|
private fireTelemetry;
|
|
183
263
|
private recomputeDerived;
|
|
184
264
|
private setupContainer;
|
|
@@ -189,6 +269,22 @@ declare class AIAutocomplete {
|
|
|
189
269
|
/** Auto-clear newParamId after shimmer animation. */
|
|
190
270
|
private subscribeNewParamTimer;
|
|
191
271
|
private handleChange;
|
|
272
|
+
/**
|
|
273
|
+
* When the user has typed text that exactly matches (case-insensitive) one
|
|
274
|
+
* of the active suggestion's options, promote it to a completed param right
|
|
275
|
+
* away. The fetchController does the same check when the debounced fetch
|
|
276
|
+
* lands; doing it instantly here means bold styling appears as soon as the
|
|
277
|
+
* option is fully typed, without waiting 100–300ms for the round-trip.
|
|
278
|
+
*/
|
|
279
|
+
private maybePromoteExactMatch;
|
|
280
|
+
/**
|
|
281
|
+
* Edit-mode counterpart to {@link maybePromoteExactMatch}. When the user is
|
|
282
|
+
* editing a bold completed param and the typed text exactly matches one of
|
|
283
|
+
* that param's cached options, promote it back to a completed param (bold)
|
|
284
|
+
* — same instant-bold affordance as the normal typing flow, just driven by
|
|
285
|
+
* the edited param's cached options instead of the active suggestion.
|
|
286
|
+
*/
|
|
287
|
+
private maybePromoteEditExactMatch;
|
|
192
288
|
}
|
|
193
289
|
|
|
194
290
|
type Listener<S> = (next: S, prev: S) => void;
|