@magicx-eng/ai-autocomplete-react 0.1.25 → 0.1.27

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,7 +13,7 @@ A React/TypeScript SDK that provides a guided AI-powered autocomplete experience
13
13
  - **Client-side filtering** — instant substring filtering on every keystroke
14
14
  - **Option overrides** — inject or dynamically generate client-side options per suggestion type
15
15
  - **Controlled & uncontrolled** — works out of the box or integrates with external state
16
- - **Ref forwarding** — imperative `focus()`, `reset()`, and `setMode()` via ref
16
+ - **Ref forwarding** — imperative `focus()`, `blur()`, `reset()`, and `setMode()` via ref
17
17
  - **Accessible** — ARIA combobox pattern with `role="listbox"`, `aria-activedescendant`
18
18
  - **Animations** — option selection streak animation, text shimmer on newly added params
19
19
  - **Lightweight** — styles auto-injected at runtime
@@ -58,7 +58,6 @@ function App() {
58
58
  console.log(result.raw_query); // "Create a {{TASK_1}}"
59
59
  console.log(result.completed_params); // [{ placeholder: "{{TASK_1}}", type: "task", ... }]
60
60
  }}
61
- placeholder="Create a"
62
61
  className="my-autocomplete"
63
62
  />
64
63
  );
@@ -88,12 +87,26 @@ import { AIAutocomplete, type AIAutocompleteHandle } from "@magicx-eng/ai-autoco
88
87
 
89
88
  const ref = useRef<AIAutocompleteHandle>(null);
90
89
  // ref.current?.focus()
90
+ // ref.current?.blur()
91
91
  // ref.current?.reset()
92
92
  // ref.current?.setMode("dark")
93
93
 
94
94
  <AIAutocomplete ref={ref} onSubmit={handleSubmit} />
95
95
  ```
96
96
 
97
+ ### Focus Control
98
+
99
+ The component auto-focuses the input on mount. To opt out, pass `autoFocus={false}`. Listen to focus changes with `onFocus` / `onBlur`:
100
+
101
+ ```tsx
102
+ <AIAutocomplete
103
+ autoFocus={false}
104
+ onFocus={() => setIsActive(true)}
105
+ onBlur={() => setIsActive(false)}
106
+ onSubmit={handleSubmit}
107
+ />
108
+ ```
109
+
97
110
  ---
98
111
 
99
112
  ## Tier 2: Headless
@@ -140,7 +153,6 @@ function App() {
140
153
  | `apiConfig?` | `APIConfig` | — | Runtime API configuration (see below). |
141
154
  | `optionOverrides?` | `Record<string, (query: string) => SuggestionOption[]>` | — | Override options per suggestion type. |
142
155
  | `maskCompletedText?` | `boolean` | `false` | When `true`, omits completed params' literal text from API requests (for masking PII/sensitive values from the server). |
143
- | `placeholder?` | `string` | — | Fallback placeholder when the server doesn't return one. |
144
156
  | `className?` | `string` | — | CSS class applied to the container. |
145
157
  | `columns?` | `number` | `2` | Number of columns in the dropdown grid. |
146
158
  | `pillPlacement?` | `"inline" \| "dropdown" \| "hidden"` | `"inline"` | Where to render unfilled pills. `"hidden"` hides pills entirely. |
@@ -148,11 +160,15 @@ function App() {
148
160
  | `optionsPosition?` | `"above" \| "below"` | `"below"` | Where the dropdown opens relative to the input. |
149
161
  | `animations?` | `boolean` | `true` | Enable/disable all SDK animations (streak + shimmer). |
150
162
  | `dropdownTrigger?` | `"auto" \| "manual" \| "hidden"` | `"auto"` | When the dropdown appears. `"auto"` = when options available. `"manual"` = only on pill tap, closes after selection. `"hidden"` = never shows. |
163
+ | `closeDropdownOnBlur?` | `boolean` | `true` | When `true`, the dropdown closes if the input loses focus. Set to `false` to keep it open whenever options are available, regardless of focus. |
164
+ | `autoFocus?` | `boolean` | `true` | Focus the input on mount. Set to `false` to leave focus to the consumer. |
165
+ | `onFocus?` | `() => void` | — | Called when the input gains focus. |
166
+ | `onBlur?` | `() => void` | — | Called when the input loses focus. |
151
167
  | `value?` | `string` | — | Controlled text value. |
152
168
  | `completedParams?` | `CompletedParamState[]` | — | Controlled completed params. |
153
169
  | `onChange?` | `(value: string) => void` | — | Called when text changes (controlled mode). |
154
170
  | `onParamsChange?` | `(params: CompletedParamState[]) => void` | — | Called when params change (controlled mode). |
155
- | `ref?` | `Ref<AIAutocompleteHandle>` | — | Imperative handle with `focus()`, `reset()`, and `setMode()`. |
171
+ | `ref?` | `Ref<AIAutocompleteHandle>` | — | Imperative handle with `focus()`, `blur()`, `reset()`, and `setMode()`. |
156
172
 
157
173
  ### `APIConfig`
158
174
 
@@ -202,7 +218,7 @@ The SDK handles token refresh transparently: 401 → `getAccessToken` → retry
202
218
 
203
219
  ### `useAIAutocomplete(options)`
204
220
 
205
- The headless hook for Tier 2. Accepts the same props as `<AIAutocomplete />` except for the rendering-only ones: `className`, `ref`, `pillPlacement`, `mode`, `optionsPosition`, and `animations` (those belong to the wrapping component).
221
+ The headless hook for Tier 2. Accepts the same props as `<AIAutocomplete />` except for the rendering-only ones: `className`, `ref`, `pillPlacement`, `mode`, `optionsPosition`, `animations`, and `autoFocus` (those belong to the wrapping component — the hook doesn't own the input element). `onFocus` and `onBlur` are forwarded and fire whenever the consumer-owned textarea's focus changes (they're driven by `inputProps.onFocus` / `inputProps.onBlur`).
206
222
 
207
223
  #### Return Value
208
224
 
@@ -282,8 +298,13 @@ Override on the container (via `className`). All defaults use `:where()` (zero s
282
298
  | `--aia-option-font-size` | `19px` | `19px` | Option font size |
283
299
  | `--aia-written-text-color` | `#000000` | `#ffffff` | Input text |
284
300
  | `--aia-written-text-font-size` | `19px` | `19px` | Input text font size |
301
+ | `--aia-caret-color` | `--aia-written-text-color` | `--aia-written-text-color` | Textarea caret color. Override independently of input text color. |
302
+ | `--aia-submit-bg` | `#000000` | `#ffffff` | Submit button background |
303
+ | `--aia-submit-color` | `#ffffff` | `#000000` | Submit button icon color |
285
304
  | `--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. |
286
305
  | `--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). |
306
+ | `--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), …)`). |
307
+ | `--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. |
287
308
 
288
309
  Legacy `--aia-color-*` variables are still supported as fallbacks.
289
310
 
@@ -298,6 +319,29 @@ Legacy `--aia-color-*` variables are still supported as fallbacks.
298
319
  }
299
320
  ```
300
321
 
322
+ ### Selector Hooks
323
+
324
+ For styling beyond the CSS variables, target these stable `data-aia-*` attributes (CSS-module class hashes are not part of the public API):
325
+
326
+ | Attribute | Element |
327
+ |---|---|
328
+ | `[data-aia-editor]` | Editor area wrapping the textarea + overlay |
329
+ | `[data-aia-textarea]` | The `<textarea>` |
330
+ | `[data-aia-submit]` | Submit button |
331
+ | `[data-aia-pill]` | Each unfilled-suggestion pill |
332
+ | `[data-aia-pillbar]` | Pill bar container inside the dropdown |
333
+ | `[data-aia-option]` | Each suggestion option |
334
+ | `[data-aia-dropdown]` | The dropdown root (listbox) |
335
+
336
+ ```css
337
+ /* Solid (non-glass) dropdown */
338
+ .my-autocomplete [data-aia-dropdown] {
339
+ background: #fff;
340
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
341
+ backdrop-filter: none;
342
+ }
343
+ ```
344
+
301
345
  ---
302
346
 
303
347
  ## Option Overrides
package/dist/index.d.mts CHANGED
@@ -42,6 +42,7 @@ type Segment = {
42
42
  type AppearanceMode = "light" | "dark" | "auto";
43
43
  interface AIAutocompleteHandle {
44
44
  focus: () => void;
45
+ blur: () => void;
45
46
  reset: () => void;
46
47
  setMode: (mode: AppearanceMode) => void;
47
48
  }
@@ -72,7 +73,6 @@ interface AIAutocompleteProps {
72
73
  onError?: (error: Error) => void;
73
74
  optionOverrides?: OptionOverrides;
74
75
  maskCompletedText?: boolean;
75
- placeholder?: string;
76
76
  className?: string;
77
77
  apiConfig?: APIConfig;
78
78
  columns?: number;
@@ -86,6 +86,14 @@ interface AIAutocompleteProps {
86
86
  animations?: boolean;
87
87
  /** When the dropdown appears. "auto" (default) = shows when options available. "manual" = only on pill tap, closes after selection. "hidden" = never shows. */
88
88
  dropdownTrigger?: "auto" | "manual" | "hidden";
89
+ /** When true (default), the dropdown closes when the input loses focus. Set to false to keep it open whenever options are available, regardless of focus. */
90
+ closeDropdownOnBlur?: boolean;
91
+ /** Focus the input on mount. Default: true. */
92
+ autoFocus?: boolean;
93
+ /** Called when the input gains focus. */
94
+ onFocus?: () => void;
95
+ /** Called when the input loses focus. */
96
+ onBlur?: () => void;
89
97
  value?: string;
90
98
  completedParams?: CompletedParamState[];
91
99
  onChange?: (value: string) => void;
@@ -101,11 +109,16 @@ interface UseAIAutocompleteOptions {
101
109
  onError?: (error: Error) => void;
102
110
  optionOverrides?: OptionOverrides;
103
111
  maskCompletedText?: boolean;
104
- placeholder?: string;
105
112
  apiConfig?: APIConfig;
106
113
  columns?: number;
107
114
  /** When the dropdown appears. Default: "auto". */
108
115
  dropdownTrigger?: "auto" | "manual" | "hidden";
116
+ /** When true (default), the dropdown closes when the input loses focus. Set to false to keep it open whenever options are available. */
117
+ closeDropdownOnBlur?: boolean;
118
+ /** Called when the input gains focus. */
119
+ onFocus?: () => void;
120
+ /** Called when the input loses focus. */
121
+ onBlur?: () => void;
109
122
  value?: string;
110
123
  completedParams?: CompletedParamState[];
111
124
  onChange?: (value: string) => void;
@@ -130,6 +143,8 @@ interface UseAIAutocompleteReturn {
130
143
  placeholder: string | undefined;
131
144
  onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
132
145
  onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => void;
146
+ onFocus: () => void;
147
+ onBlur: () => void;
133
148
  role: "combobox";
134
149
  "aria-expanded": boolean;
135
150
  "aria-activedescendant": string | undefined;
@@ -158,6 +173,6 @@ declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProp
158
173
 
159
174
  declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
160
175
 
161
- declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, dropdownTrigger, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
176
+ declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, closeDropdownOnBlur, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
162
177
 
163
178
  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
@@ -42,6 +42,7 @@ type Segment = {
42
42
  type AppearanceMode = "light" | "dark" | "auto";
43
43
  interface AIAutocompleteHandle {
44
44
  focus: () => void;
45
+ blur: () => void;
45
46
  reset: () => void;
46
47
  setMode: (mode: AppearanceMode) => void;
47
48
  }
@@ -72,7 +73,6 @@ interface AIAutocompleteProps {
72
73
  onError?: (error: Error) => void;
73
74
  optionOverrides?: OptionOverrides;
74
75
  maskCompletedText?: boolean;
75
- placeholder?: string;
76
76
  className?: string;
77
77
  apiConfig?: APIConfig;
78
78
  columns?: number;
@@ -86,6 +86,14 @@ interface AIAutocompleteProps {
86
86
  animations?: boolean;
87
87
  /** When the dropdown appears. "auto" (default) = shows when options available. "manual" = only on pill tap, closes after selection. "hidden" = never shows. */
88
88
  dropdownTrigger?: "auto" | "manual" | "hidden";
89
+ /** When true (default), the dropdown closes when the input loses focus. Set to false to keep it open whenever options are available, regardless of focus. */
90
+ closeDropdownOnBlur?: boolean;
91
+ /** Focus the input on mount. Default: true. */
92
+ autoFocus?: boolean;
93
+ /** Called when the input gains focus. */
94
+ onFocus?: () => void;
95
+ /** Called when the input loses focus. */
96
+ onBlur?: () => void;
89
97
  value?: string;
90
98
  completedParams?: CompletedParamState[];
91
99
  onChange?: (value: string) => void;
@@ -101,11 +109,16 @@ interface UseAIAutocompleteOptions {
101
109
  onError?: (error: Error) => void;
102
110
  optionOverrides?: OptionOverrides;
103
111
  maskCompletedText?: boolean;
104
- placeholder?: string;
105
112
  apiConfig?: APIConfig;
106
113
  columns?: number;
107
114
  /** When the dropdown appears. Default: "auto". */
108
115
  dropdownTrigger?: "auto" | "manual" | "hidden";
116
+ /** When true (default), the dropdown closes when the input loses focus. Set to false to keep it open whenever options are available. */
117
+ closeDropdownOnBlur?: boolean;
118
+ /** Called when the input gains focus. */
119
+ onFocus?: () => void;
120
+ /** Called when the input loses focus. */
121
+ onBlur?: () => void;
109
122
  value?: string;
110
123
  completedParams?: CompletedParamState[];
111
124
  onChange?: (value: string) => void;
@@ -130,6 +143,8 @@ interface UseAIAutocompleteReturn {
130
143
  placeholder: string | undefined;
131
144
  onChange: (e: ChangeEvent<HTMLTextAreaElement>) => void;
132
145
  onKeyDown: (e: KeyboardEvent<HTMLTextAreaElement>) => void;
146
+ onFocus: () => void;
147
+ onBlur: () => void;
133
148
  role: "combobox";
134
149
  "aria-expanded": boolean;
135
150
  "aria-activedescendant": string | undefined;
@@ -158,6 +173,6 @@ declare const AIAutocomplete: react.ForwardRefExoticComponent<AIAutocompleteProp
158
173
 
159
174
  declare function AIAutocompleteDropdown({ suggestions, activeIndex, onSelect, onHighlight, isOpen, id, className, pills, onPillClick, showPills, }: AIAutocompleteDropdownProps): react_jsx_runtime.JSX.Element;
160
175
 
161
- declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, placeholder: customPlaceholder, apiConfig, columns, dropdownTrigger, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
176
+ declare function useAIAutocomplete({ onSubmit, onError, optionOverrides, maskCompletedText, apiConfig, columns, dropdownTrigger, closeDropdownOnBlur, onFocus, onBlur, value: controlledValue, completedParams: controlledParams, onChange: onChangeProp, onParamsChange, }: UseAIAutocompleteOptions): UseAIAutocompleteReturn;
162
177
 
163
178
  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 };