@magicx-eng/ai-autocomplete-react 0.1.16 → 0.1.18
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 +157 -129
- package/dist/index.css +2 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.mts +40 -11
- package/dist/index.d.ts +40 -11
- package/dist/index.js +87 -72
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +87 -72
- package/dist/index.mjs.map +1 -1
- package/package.json +18 -18
package/README.md
CHANGED
|
@@ -1,19 +1,22 @@
|
|
|
1
1
|
# @magicx-eng/ai-autocomplete-react
|
|
2
2
|
|
|
3
|
-
A React/TypeScript SDK that provides a guided AI-powered autocomplete experience with pill-based input and dropdown suggestions.
|
|
3
|
+
A React/TypeScript SDK that provides a guided AI-powered autocomplete experience with pill-based input and dropdown suggestions. Powered by `@magicx-eng/ai-autocomplete-vanilla` under the hood.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- **Two tiers of integration** — use the full `<AIAutocomplete />` component or go headless with `useAIAutocomplete()` + `<AIAutocompleteDropdown />`
|
|
8
8
|
- **Pill-based input** — inline pills for unfilled parameters, bold text for completed ones
|
|
9
|
+
- **Pill placement** — render pills inline in the input or inside the dropdown
|
|
10
|
+
- **Light/dark mode** — built-in themes with `prefers-color-scheme` support, fully overridable via CSS variables
|
|
11
|
+
- **Access token auth** — short-lived tokens with automatic refresh, single-flight deduplication, and 401 retry
|
|
9
12
|
- **Keyboard navigation** — arrow keys, enter to submit, tab to autocomplete
|
|
10
13
|
- **Client-side filtering** — instant substring filtering on every keystroke
|
|
11
14
|
- **Option overrides** — inject or dynamically generate client-side options per suggestion type
|
|
12
15
|
- **Controlled & uncontrolled** — works out of the box or integrates with external state
|
|
13
|
-
- **Ref forwarding** — imperative `focus()` and `
|
|
16
|
+
- **Ref forwarding** — imperative `focus()`, `reset()`, and `setMode()` via ref
|
|
14
17
|
- **Accessible** — ARIA combobox pattern with `role="listbox"`, `aria-activedescendant`
|
|
15
|
-
- **Animations** — option selection streak animation, text shimmer on newly added params
|
|
16
|
-
- **Lightweight** —
|
|
18
|
+
- **Animations** — option selection streak animation, text shimmer on newly added params
|
|
19
|
+
- **Lightweight** — styles auto-injected at runtime
|
|
17
20
|
- **TypeScript first** — full type definitions shipped with the package
|
|
18
21
|
|
|
19
22
|
## Installation
|
|
@@ -30,9 +33,16 @@ React 17 or later:
|
|
|
30
33
|
pnpm add react react-dom
|
|
31
34
|
```
|
|
32
35
|
|
|
33
|
-
##
|
|
36
|
+
## Two Tiers
|
|
34
37
|
|
|
35
|
-
|
|
38
|
+
| Tier | What you get | What you own | Use when |
|
|
39
|
+
|---|---|---|---|
|
|
40
|
+
| **Tier 1: Full** | `<AIAutocomplete />` — input, dropdown, pills, state | Nothing — drop in and go | You want a complete widget with zero setup |
|
|
41
|
+
| **Tier 2: Headless** | `useAIAutocomplete()` — state, actions, spread props | The input and layout JSX | You need a custom input or want full control over rendering |
|
|
42
|
+
|
|
43
|
+
---
|
|
44
|
+
|
|
45
|
+
## Tier 1: Full Component
|
|
36
46
|
|
|
37
47
|
Drop-in component that owns the input, pills, dropdown, and all state:
|
|
38
48
|
|
|
@@ -55,7 +65,38 @@ function App() {
|
|
|
55
65
|
}
|
|
56
66
|
```
|
|
57
67
|
|
|
58
|
-
###
|
|
68
|
+
### Controlled Mode
|
|
69
|
+
|
|
70
|
+
```tsx
|
|
71
|
+
const [text, setText] = useState("");
|
|
72
|
+
const [params, setParams] = useState([]);
|
|
73
|
+
|
|
74
|
+
<AIAutocomplete
|
|
75
|
+
value={text}
|
|
76
|
+
onChange={setText}
|
|
77
|
+
completedParams={params}
|
|
78
|
+
onParamsChange={setParams}
|
|
79
|
+
onSubmit={(result) => console.log(result)}
|
|
80
|
+
/>
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Imperative Handle
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { useRef } from "react";
|
|
87
|
+
import { AIAutocomplete, type AIAutocompleteHandle } from "@magicx-eng/ai-autocomplete-react";
|
|
88
|
+
|
|
89
|
+
const ref = useRef<AIAutocompleteHandle>(null);
|
|
90
|
+
// ref.current?.focus()
|
|
91
|
+
// ref.current?.reset()
|
|
92
|
+
// ref.current?.setMode("dark")
|
|
93
|
+
|
|
94
|
+
<AIAutocomplete ref={ref} onSubmit={handleSubmit} />
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Tier 2: Headless
|
|
59
100
|
|
|
60
101
|
Use the hook and dropdown separately for full control over the input and rendering:
|
|
61
102
|
|
|
@@ -86,44 +127,12 @@ function App() {
|
|
|
86
127
|
}
|
|
87
128
|
```
|
|
88
129
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
Pass `value` and `onChange` to control the text externally:
|
|
92
|
-
|
|
93
|
-
```tsx
|
|
94
|
-
const [text, setText] = useState("");
|
|
95
|
-
const [params, setParams] = useState([]);
|
|
96
|
-
|
|
97
|
-
<AIAutocomplete
|
|
98
|
-
value={text}
|
|
99
|
-
onChange={setText}
|
|
100
|
-
completedParams={params}
|
|
101
|
-
onParamsChange={setParams}
|
|
102
|
-
onSubmit={(result) => console.log(result)}
|
|
103
|
-
/>
|
|
104
|
-
```
|
|
105
|
-
|
|
106
|
-
### Imperative Handle
|
|
107
|
-
|
|
108
|
-
Use a ref to focus or reset programmatically:
|
|
109
|
-
|
|
110
|
-
```tsx
|
|
111
|
-
import { useRef } from "react";
|
|
112
|
-
import { AIAutocomplete, type AIAutocompleteHandle } from "@magicx-eng/ai-autocomplete-react";
|
|
113
|
-
|
|
114
|
-
const ref = useRef<AIAutocompleteHandle>(null);
|
|
115
|
-
// ref.current?.focus()
|
|
116
|
-
// ref.current?.reset()
|
|
117
|
-
|
|
118
|
-
<AIAutocomplete ref={ref} onSubmit={handleSubmit} />
|
|
119
|
-
```
|
|
130
|
+
---
|
|
120
131
|
|
|
121
132
|
## API Reference
|
|
122
133
|
|
|
123
134
|
### `<AIAutocomplete />`
|
|
124
135
|
|
|
125
|
-
The full component. Owns the input, pills, dropdown, and keyboard navigation.
|
|
126
|
-
|
|
127
136
|
| Prop | Type | Default | Description |
|
|
128
137
|
|---|---|---|---|
|
|
129
138
|
| `onSubmit` | `(result: AutocompleteResult) => void` | **required** | Called on Enter or submit button. |
|
|
@@ -133,38 +142,66 @@ The full component. Owns the input, pills, dropdown, and keyboard navigation.
|
|
|
133
142
|
| `placeholder?` | `string` | — | Fallback placeholder when the server doesn't return one. |
|
|
134
143
|
| `className?` | `string` | — | CSS class applied to the container. |
|
|
135
144
|
| `columns?` | `number` | `2` | Number of columns in the dropdown grid. |
|
|
136
|
-
| `
|
|
145
|
+
| `pillPlacement?` | `"inline" \| "dropdown" \| "hidden"` | `"inline"` | Where to render unfilled pills. `"hidden"` hides pills entirely. |
|
|
146
|
+
| `mode?` | `"light" \| "dark" \| "auto"` | `"auto"` | Color mode. `"auto"` follows `prefers-color-scheme`. |
|
|
147
|
+
| `optionsPosition?` | `"above" \| "below"` | `"below"` | Where the dropdown opens relative to the input. |
|
|
148
|
+
| `animations?` | `boolean` | `true` | Enable/disable all SDK animations (streak + shimmer). |
|
|
149
|
+
| `dropdownTrigger?` | `"auto" \| "manual" \| "hidden"` | `"auto"` | When the dropdown appears. `"auto"` = when options available. `"manual"` = only on pill tap, closes after selection. `"hidden"` = never shows. |
|
|
137
150
|
| `value?` | `string` | — | Controlled text value. |
|
|
138
151
|
| `completedParams?` | `CompletedParamState[]` | — | Controlled completed params. |
|
|
139
152
|
| `onChange?` | `(value: string) => void` | — | Called when text changes (controlled mode). |
|
|
140
153
|
| `onParamsChange?` | `(params: CompletedParamState[]) => void` | — | Called when params change (controlled mode). |
|
|
141
|
-
| `ref?` | `Ref<AIAutocompleteHandle>` | — | Imperative handle with `focus()` and `
|
|
154
|
+
| `ref?` | `Ref<AIAutocompleteHandle>` | — | Imperative handle with `focus()`, `reset()`, and `setMode()`. |
|
|
142
155
|
|
|
143
156
|
### `APIConfig`
|
|
144
157
|
|
|
158
|
+
A discriminated union: `APIKeyConfig | AccessTokenConfig`.
|
|
159
|
+
|
|
160
|
+
#### API Key Mode (default)
|
|
161
|
+
|
|
162
|
+
```ts
|
|
163
|
+
{ apiKey: "your_api_key", authScheme: "Bearer", endpoint: "/ac/suggest" }
|
|
164
|
+
```
|
|
165
|
+
|
|
145
166
|
| Field | Type | Description |
|
|
146
167
|
|---|---|---|
|
|
147
|
-
| `
|
|
148
|
-
| `apiKey?` | `string` | API key for Authorization header.
|
|
168
|
+
| `type?` | `"apiKey"` | Optional discriminator. Default when omitted. |
|
|
169
|
+
| `apiKey?` | `string` | API key for Authorization header. |
|
|
149
170
|
| `authScheme?` | `"Bearer" \| "Basic"` | Auth header scheme. Default: `"Bearer"`. |
|
|
150
|
-
| `
|
|
171
|
+
| `endpoint?` | `string` | Full URL for the suggest endpoint. Default: `"/ac/suggest"`. |
|
|
172
|
+
| `appIdentifier?` | `string` | Value for the `X-App-Identifier` header. |
|
|
151
173
|
| `headers?` | `Record<string, string>` | Additional headers merged into every request. |
|
|
152
174
|
|
|
153
|
-
|
|
175
|
+
#### Access Token Mode
|
|
154
176
|
|
|
155
|
-
|
|
177
|
+
```tsx
|
|
178
|
+
<AIAutocomplete
|
|
179
|
+
apiConfig={{
|
|
180
|
+
type: "accessToken",
|
|
181
|
+
getAccessToken: async () => {
|
|
182
|
+
const res = await fetch("/api/ac-token");
|
|
183
|
+
const { access_token, expires_at } = await res.json();
|
|
184
|
+
return { accessToken: access_token, expiresAt: expires_at };
|
|
185
|
+
},
|
|
186
|
+
}}
|
|
187
|
+
onSubmit={handleSubmit}
|
|
188
|
+
/>
|
|
189
|
+
```
|
|
156
190
|
|
|
157
191
|
| Field | Type | Description |
|
|
158
192
|
|---|---|---|
|
|
159
|
-
| `
|
|
160
|
-
| `
|
|
161
|
-
| `
|
|
193
|
+
| `type` | `"accessToken"` | **Required** discriminator. |
|
|
194
|
+
| `getAccessToken` | `() => Promise<AccessTokenResult>` | **Required.** Called when the SDK needs a token. |
|
|
195
|
+
| `accessToken?` | `string` | Initial token. Avoids one round-trip on mount. |
|
|
196
|
+
| `endpoint?` | `string` | Suggest endpoint URL. Default: `"/ac/suggest"`. |
|
|
197
|
+
| `appIdentifier?` | `string` | Value for the `X-App-Identifier` header. |
|
|
198
|
+
| `headers?` | `Record<string, string>` | Additional headers merged into every request. |
|
|
162
199
|
|
|
163
|
-
|
|
200
|
+
The SDK handles token refresh transparently: 401 → `getAccessToken` → retry (once). Concurrent 401s share a single refresh. Tokens refresh proactively 30s before `expiresAt`.
|
|
164
201
|
|
|
165
|
-
|
|
202
|
+
### `useAIAutocomplete(options)`
|
|
166
203
|
|
|
167
|
-
Accepts the same props as `<AIAutocomplete />` (except `className` and `ref`)
|
|
204
|
+
The headless hook for Tier 2. Accepts the same props as `<AIAutocomplete />` (except `className` and `ref`).
|
|
168
205
|
|
|
169
206
|
#### Return Value
|
|
170
207
|
|
|
@@ -172,122 +209,113 @@ Accepts the same props as `<AIAutocomplete />` (except `className` and `ref`), w
|
|
|
172
209
|
|
|
173
210
|
| Field | Type | Description |
|
|
174
211
|
|---|---|---|
|
|
175
|
-
| `completedParams` | `CompletedParamState[]` |
|
|
176
|
-
| `suggestionPills` | `Suggestion[]` | Unfilled suggestions
|
|
177
|
-
| `segments` | `Segment[]` |
|
|
178
|
-
| `newParamId` | `string \| null` |
|
|
179
|
-
| `suggestions` | `Suggestion[]` | All suggestions from
|
|
180
|
-
| `activeIndex` | `number` |
|
|
181
|
-
| `isLoading` | `boolean` |
|
|
182
|
-
| `isReady` | `boolean` |
|
|
183
|
-
| `error` | `Error \| null` |
|
|
212
|
+
| `completedParams` | `CompletedParamState[]` | Filled parameters. |
|
|
213
|
+
| `suggestionPills` | `Suggestion[]` | Unfilled suggestions (pills). First item is the active pill. |
|
|
214
|
+
| `segments` | `Segment[]` | Input text split into text vs completed segments for overlay rendering. |
|
|
215
|
+
| `newParamId` | `string \| null` | ID of the most recently added param (for shimmer animation). |
|
|
216
|
+
| `suggestions` | `Suggestion[]` | All suggestions from server (including placeholder type). |
|
|
217
|
+
| `activeIndex` | `number` | Highlighted option index. `-1` = none. |
|
|
218
|
+
| `isLoading` | `boolean` | Fetch in progress. |
|
|
219
|
+
| `isReady` | `boolean` | Server indicates query is complete. |
|
|
220
|
+
| `error` | `Error \| null` | Last fetch error. |
|
|
184
221
|
|
|
185
222
|
**Actions**
|
|
186
223
|
|
|
187
224
|
| Field | Type | Description |
|
|
188
225
|
|---|---|---|
|
|
189
|
-
| `setActivePill` | `(index: number) => void` |
|
|
190
|
-
| `removeLastParam` | `() => void` | Remove
|
|
191
|
-
| `
|
|
192
|
-
| `
|
|
193
|
-
| `reset` | `() => void` | Clear all text, completed params, and suggestions, then re-fetch initial suggestions from the server. Returns the component to its mount state. |
|
|
226
|
+
| `setActivePill` | `(index: number) => void` | Move pill at `index` to front (active). |
|
|
227
|
+
| `removeLastParam` | `() => void` | Remove last completed param, restore as pill. |
|
|
228
|
+
| `clearNewParamId` | `() => void` | Clear shimmer animation state. |
|
|
229
|
+
| `reset` | `() => void` | Clear all state, re-fetch. |
|
|
194
230
|
|
|
195
231
|
**Spread Props**
|
|
196
232
|
|
|
197
233
|
| Field | Type | Description |
|
|
198
234
|
|---|---|---|
|
|
199
|
-
| `inputProps` | `object` | Spread onto a `<textarea
|
|
200
|
-
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Includes
|
|
235
|
+
| `inputProps` | `object` | Spread onto a `<textarea>`. Includes `value`, `placeholder`, `onChange`, `onKeyDown`, and ARIA attributes. |
|
|
236
|
+
| `dropdownProps` | `AIAutocompleteDropdownProps` | Spread onto `<AIAutocompleteDropdown />`. Includes options, highlight, selection, pills, and open state. |
|
|
201
237
|
|
|
202
238
|
### `<AIAutocompleteDropdown />`
|
|
203
239
|
|
|
204
|
-
The dropdown component for Tier 2
|
|
240
|
+
The dropdown component for Tier 2. Spread `dropdownProps` from the hook.
|
|
205
241
|
|
|
206
242
|
| Prop | Type | Description |
|
|
207
243
|
|---|---|---|
|
|
208
|
-
| `suggestions` | `Suggestion[]` | Suggestions to display
|
|
209
|
-
| `activeIndex` | `number` |
|
|
244
|
+
| `suggestions` | `Suggestion[]` | Suggestions to display. |
|
|
245
|
+
| `activeIndex` | `number` | Highlighted option index. |
|
|
210
246
|
| `onSelect` | `(option: SuggestionOption) => void` | Called when an option is selected. |
|
|
211
|
-
| `onHighlight` | `(index: number) => void` | Called
|
|
247
|
+
| `onHighlight` | `(index: number) => void` | Called on mouse hover. |
|
|
212
248
|
| `isOpen` | `boolean` | Whether the dropdown is visible. |
|
|
213
249
|
| `id` | `string` | Listbox ID for ARIA. |
|
|
214
250
|
| `className?` | `string` | CSS class applied to the dropdown. |
|
|
251
|
+
| `pills?` | `Suggestion[]` | Pills to render inside the dropdown. |
|
|
252
|
+
| `onPillClick?` | `(index: number) => void` | Called when a pill is clicked. |
|
|
253
|
+
| `showPills?` | `boolean` | Whether to render pills. Default: `true`. |
|
|
215
254
|
|
|
216
|
-
### `
|
|
217
|
-
|
|
218
|
-
Represents an unfilled parameter slot. Rendered as a pill in Tier 1, or available via `suggestionPills` in Tier 2.
|
|
255
|
+
### `AutocompleteResult`
|
|
219
256
|
|
|
220
257
|
| Field | Type | Description |
|
|
221
258
|
|---|---|---|
|
|
222
|
-
| `
|
|
223
|
-
| `
|
|
224
|
-
| `
|
|
225
|
-
| `options?` | `SuggestionOption[]` | Available options the user can select from. May be `undefined` if the server omits it. |
|
|
259
|
+
| `query` | `string` | Plain text as the user sees it. |
|
|
260
|
+
| `raw_query` | `string` | Text with placeholder tokens (e.g. `"Create a {{TASK_1}}"`). |
|
|
261
|
+
| `completed_params` | `CompletedParam[]` | Filled parameter values. |
|
|
226
262
|
|
|
227
|
-
|
|
263
|
+
---
|
|
228
264
|
|
|
229
|
-
|
|
265
|
+
## CSS Customization
|
|
230
266
|
|
|
231
|
-
|
|
232
|
-
|---|---|---|
|
|
233
|
-
| `text` | `string` | Display text for the option. |
|
|
234
|
-
| `icon?` | `string` | Icon shown before the text (e.g. emoji). |
|
|
235
|
-
| `tag?` | `string` | Label shown after the text in smaller, muted style. |
|
|
236
|
-
| `is_tappable` | `boolean` | Whether the option can be selected. Non-tappable options are always-visible hints that cannot be chosen. |
|
|
237
|
-
| `kind` | `string \| null` | Category of the option (e.g. `"automation"`, `"email"`), or `null`. Passed through to `CompletedParam` on selection. |
|
|
238
|
-
| `metadata?` | `Record<string, unknown>` | Arbitrary metadata passed through with the selection. Available on the completed param after the user selects this option. |
|
|
267
|
+
Styles are auto-injected at runtime — no CSS import needed. Built-in light and dark defaults apply automatically based on `mode`.
|
|
239
268
|
|
|
240
|
-
|
|
269
|
+
### CSS Variables
|
|
270
|
+
|
|
271
|
+
Override on the container (via `className`). All defaults use `:where()` (zero specificity) — your overrides always win.
|
|
272
|
+
|
|
273
|
+
| Variable | Light | Dark | Description |
|
|
274
|
+
|---|---|---|---|
|
|
275
|
+
| `--aia-pill-bg` | `#bdbdbd` | `#bdbdbd` | Pill background |
|
|
276
|
+
| `--aia-pill-color` | `#000000` | `#ffffff` | Pill text |
|
|
277
|
+
| `--aia-pill-font-size` | `19px` | `19px` | Pill font size |
|
|
278
|
+
| `--aia-option-bg` | `transparent` | `transparent` | Highlighted option background |
|
|
279
|
+
| `--aia-option-color` | `#000000` | `#ffffff` | Option text |
|
|
280
|
+
| `--aia-option-color-selected` | `#000000` | `#ffffff` | Highlighted option text |
|
|
281
|
+
| `--aia-option-font-size` | `19px` | `19px` | Option font size |
|
|
282
|
+
| `--aia-written-text-color` | `#000000` | `#ffffff` | Input text |
|
|
283
|
+
| `--aia-written-text-font-size` | `19px` | `19px` | Input text font size |
|
|
284
|
+
|
|
285
|
+
Legacy `--aia-color-*` variables are still supported as fallbacks.
|
|
241
286
|
|
|
242
|
-
|
|
287
|
+
### Per-mode Overrides
|
|
243
288
|
|
|
244
289
|
```css
|
|
245
|
-
.my-autocomplete {
|
|
246
|
-
--
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
--
|
|
250
|
-
--ac-color-background-default: #fff; /* Dropdown background */
|
|
251
|
-
--ac-color-background-supportive: #eee; /* Pill background */
|
|
290
|
+
.my-autocomplete[data-mode="light"] {
|
|
291
|
+
--aia-pill-bg: #e2e8f0;
|
|
292
|
+
}
|
|
293
|
+
.my-autocomplete[data-mode="dark"] {
|
|
294
|
+
--aia-pill-bg: #334155;
|
|
252
295
|
}
|
|
253
296
|
```
|
|
254
297
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
| Key | Behavior |
|
|
258
|
-
|---|---|
|
|
259
|
-
| **Arrow Down** | Open dropdown (if closed and cursor at end) and select first option, or navigate to next option. |
|
|
260
|
-
| **Arrow Up** | Navigate to previous option. Deselects if on the first row. Does nothing if no option is selected. |
|
|
261
|
-
| **Arrow Right** | Jump to next column when an option is highlighted. Cycles to the next suggestion pill when cursor is at the end and no option is selected. |
|
|
262
|
-
| **Arrow Left** | Jump to previous column when an option is highlighted. |
|
|
263
|
-
| **Tab** | Select the first tappable option (or highlighted one). Accepts placeholder when input is empty. |
|
|
264
|
-
| **Enter** | Select highlighted option if one is highlighted. Otherwise submits the query. |
|
|
265
|
-
| **Escape** | Deselect the highlighted option. |
|
|
298
|
+
---
|
|
266
299
|
|
|
267
300
|
## Option Overrides
|
|
268
301
|
|
|
269
|
-
Use `optionOverrides` to inject client-side options per suggestion type:
|
|
270
|
-
|
|
271
302
|
```tsx
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
|
|
286
|
-
<AIAutocomplete optionOverrides={overrides} onSubmit={handleSubmit} />
|
|
303
|
+
<AIAutocomplete
|
|
304
|
+
optionOverrides={{
|
|
305
|
+
account: () => [
|
|
306
|
+
{ text: "Savings", is_tappable: true, kind: null },
|
|
307
|
+
{ text: "Checking", is_tappable: true, kind: null },
|
|
308
|
+
],
|
|
309
|
+
value: (query) => {
|
|
310
|
+
const digits = query.replace(/\D/g, "");
|
|
311
|
+
if (!digits) return [{ text: "$100", is_tappable: true, kind: null }];
|
|
312
|
+
return [{ text: `$${digits}`, is_tappable: true, kind: null }];
|
|
313
|
+
},
|
|
314
|
+
}}
|
|
315
|
+
onSubmit={handleSubmit}
|
|
316
|
+
/>
|
|
287
317
|
```
|
|
288
318
|
|
|
289
|
-
Override options are prepended to server options (deduplicated by `text`). When a filter query is active and an override function exists, it replaces the default client-side filtering entirely.
|
|
290
|
-
|
|
291
319
|
## License
|
|
292
320
|
|
|
293
321
|
Private package. All rights reserved.
|
package/dist/index.css
ADDED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
:where(.magicx-aia),:where(.magicx-aia[data-mode=light]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #000000;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #000000;--aia-option-color-selected: #000000;--aia-option-font-size: 19px;--aia-written-text-color: #000000;--aia-written-text-font-size: 19px}:where(.magicx-aia[data-mode=dark]){--aia-pill-bg: #bdbdbd;--aia-pill-color: #ffffff;--aia-pill-font-size: 19px;--aia-option-bg: transparent;--aia-option-color: #ffffff;--aia-option-color-selected: #ffffff;--aia-option-font-size: 19px;--aia-written-text-color: #ffffff;--aia-written-text-font-size: 19px}:where(.magicx-aia[data-options-position=above]) [data-aia-dropdown]{top:auto;bottom:100%;margin-top:0;margin-bottom:6px}:where(.magicx-aia[data-animations=off]) *,:where(.magicx-aia[data-animations=off]) *:before,:where(.magicx-aia[data-animations=off]) *:after{animation-duration:0s!important;transition-duration:0s!important}
|
|
2
|
+
/*# sourceMappingURL=index.css.map */
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/appearance.css"],"sourcesContent":["/*\n * Built-in appearance defaults — zero specificity via :where().\n * Consumer CSS always wins without !important.\n *\n * Resolution priority (highest wins):\n * 1. Consumer CSS targeting new vars (--aia-pill-bg, etc.)\n * 2. Consumer CSS targeting legacy vars (--aia-color-*, via fallback chain)\n * 3. These built-in defaults\n */\n\n/* Light mode defaults (base) */\n:where(.magicx-aia),\n:where(.magicx-aia[data-mode=\"light\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #000000;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #000000;\n --aia-option-color-selected: #000000;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #000000;\n --aia-written-text-font-size: 19px;\n}\n\n/* Dark mode defaults */\n:where(.magicx-aia[data-mode=\"dark\"]) {\n --aia-pill-bg: #bdbdbd;\n --aia-pill-color: #ffffff;\n --aia-pill-font-size: 19px;\n\n --aia-option-bg: transparent;\n --aia-option-color: #ffffff;\n --aia-option-color-selected: #ffffff;\n --aia-option-font-size: 19px;\n\n --aia-written-text-color: #ffffff;\n --aia-written-text-font-size: 19px;\n}\n\n/* optionsPosition: dropdown above the input */\n:where(.magicx-aia[data-options-position=\"above\"]) [data-aia-dropdown] {\n top: auto;\n bottom: 100%;\n margin-top: 0;\n margin-bottom: 6px;\n}\n\n/* Disable all animations when data-animations=\"off\" */\n:where(.magicx-aia[data-animations=\"off\"]) *,\n:where(.magicx-aia[data-animations=\"off\"]) *::before,\n:where(.magicx-aia[data-animations=\"off\"]) *::after {\n animation-duration: 0s !important;\n transition-duration: 0s !important;\n}\n"],"mappings":"AAWA,OAAO,CAAC,YACR,OAAO,CADC,UACU,CAAC,kBACjB,eAAe,QACf,kBAAkB,QAClB,sBAAsB,KAEtB,iBAAiB,YACjB,oBAAoB,QACpB,6BAA6B,QAC7B,wBAAwB,KAExB,0BAA0B,QAC1B,8BAA8B,IAChC,CAGA,OAAO,CAhBC,UAgBU,CAAC,iBACjB,eAAe,QACf,kBAAkB,QAClB,sBAAsB,KAEtB,iBAAiB,YACjB,oBAAoB,QACpB,6BAA6B,QAC7B,wBAAwB,KAExB,0BAA0B,QAC1B,8BAA8B,IAChC,CAGA,OAAO,CA/BC,UA+BU,CAAC,8BAAgC,CAAC,mBAClD,IAAK,KACL,OAAQ,KACR,WAAY,EACZ,cAAe,GACjB,CAGA,OAAO,CAvCC,UAuCU,CAAC,sBAAwB,EAC3C,OAAO,CAxCC,UAwCU,CAAC,sBAAwB,CAAC,QAC5C,OAAO,CAzCC,UAyCU,CAAC,sBAAwB,CAAC,OAC1C,mBAAoB,aACpB,oBAAqB,YACvB","names":[]}
|
package/dist/index.d.mts
CHANGED
|
@@ -39,17 +39,33 @@ type Segment = {
|
|
|
39
39
|
value: string;
|
|
40
40
|
param: CompletedParamState;
|
|
41
41
|
};
|
|
42
|
+
type AppearanceMode = "light" | "dark" | "auto";
|
|
42
43
|
interface AIAutocompleteHandle {
|
|
43
44
|
focus: () => void;
|
|
44
45
|
reset: () => void;
|
|
46
|
+
setMode: (mode: AppearanceMode) => void;
|
|
45
47
|
}
|
|
46
|
-
interface
|
|
48
|
+
interface APIConfigBase {
|
|
47
49
|
endpoint?: string;
|
|
48
|
-
apiKey?: string;
|
|
49
|
-
authScheme?: "Bearer" | "Basic";
|
|
50
50
|
appIdentifier?: string;
|
|
51
51
|
headers?: Record<string, string>;
|
|
52
52
|
}
|
|
53
|
+
interface APIKeyConfig extends APIConfigBase {
|
|
54
|
+
type?: "apiKey";
|
|
55
|
+
apiKey?: string;
|
|
56
|
+
authScheme?: "Bearer" | "Basic";
|
|
57
|
+
}
|
|
58
|
+
interface AccessTokenConfig extends APIConfigBase {
|
|
59
|
+
type: "accessToken";
|
|
60
|
+
accessToken?: string;
|
|
61
|
+
getAccessToken: () => Promise<AccessTokenResult>;
|
|
62
|
+
}
|
|
63
|
+
interface AccessTokenResult {
|
|
64
|
+
accessToken: string;
|
|
65
|
+
/** UNIX ms. If provided, SDK refreshes proactively 30s before expiry. */
|
|
66
|
+
expiresAt?: number;
|
|
67
|
+
}
|
|
68
|
+
type APIConfig = APIKeyConfig | AccessTokenConfig;
|
|
53
69
|
type OptionOverrides = Record<string, (query: string) => SuggestionOption[]>;
|
|
54
70
|
interface AIAutocompleteProps {
|
|
55
71
|
onSubmit: (result: AutocompleteResult) => void;
|
|
@@ -60,8 +76,16 @@ interface AIAutocompleteProps {
|
|
|
60
76
|
className?: string;
|
|
61
77
|
apiConfig?: APIConfig;
|
|
62
78
|
columns?: number;
|
|
63
|
-
/**
|
|
64
|
-
|
|
79
|
+
/** Where to render unfilled pills. "inline" (default) renders them in the input; "dropdown" renders them above the options grid. */
|
|
80
|
+
pillPlacement?: "inline" | "dropdown" | "hidden";
|
|
81
|
+
/** Color mode. "auto" listens to prefers-color-scheme. Default: "auto" */
|
|
82
|
+
mode?: AppearanceMode;
|
|
83
|
+
/** Where the dropdown opens relative to the input. Default: "below" */
|
|
84
|
+
optionsPosition?: "above" | "below";
|
|
85
|
+
/** Enable all SDK animations (streak + shimmer). Default: true */
|
|
86
|
+
animations?: boolean;
|
|
87
|
+
/** When the dropdown appears. "auto" (default) = shows when options available. "manual" = only on pill tap, closes after selection. "hidden" = never shows. */
|
|
88
|
+
dropdownTrigger?: "auto" | "manual" | "hidden";
|
|
65
89
|
value?: string;
|
|
66
90
|
completedParams?: CompletedParamState[];
|
|
67
91
|
onChange?: (value: string) => void;
|
|
@@ -80,8 +104,8 @@ interface UseAIAutocompleteOptions {
|
|
|
80
104
|
placeholder?: string;
|
|
81
105
|
apiConfig?: APIConfig;
|
|
82
106
|
columns?: number;
|
|
83
|
-
/** When
|
|
84
|
-
|
|
107
|
+
/** When the dropdown appears. Default: "auto". */
|
|
108
|
+
dropdownTrigger?: "auto" | "manual" | "hidden";
|
|
85
109
|
value?: string;
|
|
86
110
|
completedParams?: CompletedParamState[];
|
|
87
111
|
onChange?: (value: string) => void;
|
|
@@ -92,7 +116,6 @@ interface UseAIAutocompleteReturn {
|
|
|
92
116
|
suggestionPills: Suggestion[];
|
|
93
117
|
setActivePill: (index: number) => void;
|
|
94
118
|
removeLastParam: () => void;
|
|
95
|
-
reEditParam: (param: CompletedParamState) => void;
|
|
96
119
|
reset: () => void;
|
|
97
120
|
segments: Segment[];
|
|
98
121
|
newParamId: string | null;
|
|
@@ -123,12 +146,18 @@ interface AIAutocompleteDropdownProps {
|
|
|
123
146
|
isOpen: boolean;
|
|
124
147
|
id: string;
|
|
125
148
|
className?: string;
|
|
149
|
+
/** Pills to render inside the dropdown. Provided by `dropdownProps` from the hook. */
|
|
150
|
+
pills?: Suggestion[];
|
|
151
|
+
/** Called when a pill inside the dropdown is clicked. Provided by `dropdownProps` from the hook. */
|
|
152
|
+
onPillClick?: (index: number) => void;
|
|
153
|
+
/** Whether to render pills inside the dropdown. Default: true. Tier 2 consumers who render their own pills should set this to false. */
|
|
154
|
+
showPills?: boolean;
|
|
126
155
|
}
|
|
127
156
|
|
|
128
157
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
129
158
|
|
|
130
|
-
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
159
|
+
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
131
160
|
|
|
132
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
161
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, dropdownTrigger, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
133
162
|
|
|
134
|
-
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
|
163
|
+
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type APIKeyConfig, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
package/dist/index.d.ts
CHANGED
|
@@ -39,17 +39,33 @@ type Segment = {
|
|
|
39
39
|
value: string;
|
|
40
40
|
param: CompletedParamState;
|
|
41
41
|
};
|
|
42
|
+
type AppearanceMode = "light" | "dark" | "auto";
|
|
42
43
|
interface AIAutocompleteHandle {
|
|
43
44
|
focus: () => void;
|
|
44
45
|
reset: () => void;
|
|
46
|
+
setMode: (mode: AppearanceMode) => void;
|
|
45
47
|
}
|
|
46
|
-
interface
|
|
48
|
+
interface APIConfigBase {
|
|
47
49
|
endpoint?: string;
|
|
48
|
-
apiKey?: string;
|
|
49
|
-
authScheme?: "Bearer" | "Basic";
|
|
50
50
|
appIdentifier?: string;
|
|
51
51
|
headers?: Record<string, string>;
|
|
52
52
|
}
|
|
53
|
+
interface APIKeyConfig extends APIConfigBase {
|
|
54
|
+
type?: "apiKey";
|
|
55
|
+
apiKey?: string;
|
|
56
|
+
authScheme?: "Bearer" | "Basic";
|
|
57
|
+
}
|
|
58
|
+
interface AccessTokenConfig extends APIConfigBase {
|
|
59
|
+
type: "accessToken";
|
|
60
|
+
accessToken?: string;
|
|
61
|
+
getAccessToken: () => Promise<AccessTokenResult>;
|
|
62
|
+
}
|
|
63
|
+
interface AccessTokenResult {
|
|
64
|
+
accessToken: string;
|
|
65
|
+
/** UNIX ms. If provided, SDK refreshes proactively 30s before expiry. */
|
|
66
|
+
expiresAt?: number;
|
|
67
|
+
}
|
|
68
|
+
type APIConfig = APIKeyConfig | AccessTokenConfig;
|
|
53
69
|
type OptionOverrides = Record<string, (query: string) => SuggestionOption[]>;
|
|
54
70
|
interface AIAutocompleteProps {
|
|
55
71
|
onSubmit: (result: AutocompleteResult) => void;
|
|
@@ -60,8 +76,16 @@ interface AIAutocompleteProps {
|
|
|
60
76
|
className?: string;
|
|
61
77
|
apiConfig?: APIConfig;
|
|
62
78
|
columns?: number;
|
|
63
|
-
/**
|
|
64
|
-
|
|
79
|
+
/** Where to render unfilled pills. "inline" (default) renders them in the input; "dropdown" renders them above the options grid. */
|
|
80
|
+
pillPlacement?: "inline" | "dropdown" | "hidden";
|
|
81
|
+
/** Color mode. "auto" listens to prefers-color-scheme. Default: "auto" */
|
|
82
|
+
mode?: AppearanceMode;
|
|
83
|
+
/** Where the dropdown opens relative to the input. Default: "below" */
|
|
84
|
+
optionsPosition?: "above" | "below";
|
|
85
|
+
/** Enable all SDK animations (streak + shimmer). Default: true */
|
|
86
|
+
animations?: boolean;
|
|
87
|
+
/** When the dropdown appears. "auto" (default) = shows when options available. "manual" = only on pill tap, closes after selection. "hidden" = never shows. */
|
|
88
|
+
dropdownTrigger?: "auto" | "manual" | "hidden";
|
|
65
89
|
value?: string;
|
|
66
90
|
completedParams?: CompletedParamState[];
|
|
67
91
|
onChange?: (value: string) => void;
|
|
@@ -80,8 +104,8 @@ interface UseAIAutocompleteOptions {
|
|
|
80
104
|
placeholder?: string;
|
|
81
105
|
apiConfig?: APIConfig;
|
|
82
106
|
columns?: number;
|
|
83
|
-
/** When
|
|
84
|
-
|
|
107
|
+
/** When the dropdown appears. Default: "auto". */
|
|
108
|
+
dropdownTrigger?: "auto" | "manual" | "hidden";
|
|
85
109
|
value?: string;
|
|
86
110
|
completedParams?: CompletedParamState[];
|
|
87
111
|
onChange?: (value: string) => void;
|
|
@@ -92,7 +116,6 @@ interface UseAIAutocompleteReturn {
|
|
|
92
116
|
suggestionPills: Suggestion[];
|
|
93
117
|
setActivePill: (index: number) => void;
|
|
94
118
|
removeLastParam: () => void;
|
|
95
|
-
reEditParam: (param: CompletedParamState) => void;
|
|
96
119
|
reset: () => void;
|
|
97
120
|
segments: Segment[];
|
|
98
121
|
newParamId: string | null;
|
|
@@ -123,12 +146,18 @@ interface AIAutocompleteDropdownProps {
|
|
|
123
146
|
isOpen: boolean;
|
|
124
147
|
id: string;
|
|
125
148
|
className?: string;
|
|
149
|
+
/** Pills to render inside the dropdown. Provided by `dropdownProps` from the hook. */
|
|
150
|
+
pills?: Suggestion[];
|
|
151
|
+
/** Called when a pill inside the dropdown is clicked. Provided by `dropdownProps` from the hook. */
|
|
152
|
+
onPillClick?: (index: number) => void;
|
|
153
|
+
/** Whether to render pills inside the dropdown. Default: true. Tier 2 consumers who render their own pills should set this to false. */
|
|
154
|
+
showPills?: boolean;
|
|
126
155
|
}
|
|
127
156
|
|
|
128
157
|
declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProps & react.RefAttributes<AIAutocompleteHandle>>;
|
|
129
158
|
|
|
130
|
-
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
159
|
+
declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
|
|
131
160
|
|
|
132
|
-
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
161
|
+
declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, dropdownTrigger, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
|
|
133
162
|
|
|
134
|
-
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|
|
163
|
+
export { AIAutocomplete, AIAutocompleteDropdown, type AIAutocompleteDropdownProps, type AIAutocompleteHandle, type AIAutocompleteProps, type APIConfig, type APIKeyConfig, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteResult, type CompletedParam, type CompletedParamState, type OptionOverrides, type Segment, type Suggestion, type SuggestionOption, type TaskKind, type UseAIAutocompleteOptions, type UseAIAutocompleteReturn, useAIAutocomplete };
|