@magicx-eng/ai-autocomplete-vanilla 0.1.1 → 0.1.3

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/index.d.ts CHANGED
@@ -43,7 +43,7 @@ interface APIConfigBase {
43
43
  }
44
44
  interface APIKeyConfig extends APIConfigBase {
45
45
  type?: "apiKey";
46
- apiKey: string;
46
+ apiKey?: string;
47
47
  authScheme?: "Bearer" | "Basic";
48
48
  }
49
49
  interface AccessTokenConfig extends APIConfigBase {
@@ -64,14 +64,6 @@ interface AutocompleteResult {
64
64
  completed_params: CompletedParam[];
65
65
  }
66
66
 
67
- type Listener<S> = (next: S, prev: S) => void;
68
- interface Store<S> {
69
- get: () => S;
70
- set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;
71
- subscribe: (listener: Listener<S>) => () => void;
72
- }
73
- declare function createStore<S>(initial: S): Store<S>;
74
-
75
67
  /** Internal state managed by the store. */
76
68
  interface CoreState {
77
69
  text: string;
@@ -92,60 +84,67 @@ interface CoreState {
92
84
  pillTapped: boolean;
93
85
  skipNextFetch: boolean;
94
86
  lastRawQuery: string;
87
+ isFocused: boolean;
95
88
  }
89
+ /**
90
+ * Render mode:
91
+ * - "full" (default) — renders input + dropdown + pills. Tier 1.
92
+ * - "dropdown" — renders only the dropdown with pills. Consumer owns the input. Tier 2.
93
+ * - "headless" — no DOM. State + controllers only. For framework wrappers.
94
+ */
95
+ type RenderMode = "full" | "dropdown" | "headless";
96
96
  /** Options passed to the AIAutocomplete constructor. */
97
97
  interface CoreOptions {
98
98
  apiConfig?: APIConfig;
99
99
  optionOverrides?: OptionOverrides;
100
100
  maskCompletedText?: boolean;
101
- placeholder?: string;
102
101
  columns?: number;
103
- typewriterEffect?: boolean;
104
- pillPlacement?: "inline" | "dropdown";
102
+ /** Where pills render in "full" mode. Ignored in "dropdown" mode (always in dropdown). */
103
+ pillPlacement?: "inline" | "dropdown" | "hidden";
105
104
  mode?: AppearanceMode;
106
105
  optionsPosition?: "above" | "below";
107
106
  animations?: boolean;
107
+ /** When the dropdown appears. "auto" = shows when options available. "manual" = only on pill tap. "hidden" = never. Default: "auto". */
108
+ dropdownTrigger?: "auto" | "manual" | "hidden";
109
+ /** 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. */
110
+ closeDropdownOnBlur?: boolean;
111
+ /** Render mode. Default: "full". */
112
+ renderMode?: RenderMode;
113
+ /** Focus the input on mount (Tier 1 / "full" render mode only). Default: true. */
114
+ autoFocus?: boolean;
108
115
  onSubmit?: (result: AutocompleteResult) => void;
109
116
  onError?: (error: Error) => void;
110
117
  onChange?: (text: string) => void;
111
118
  onParamsChange?: (params: CompletedParamState[]) => void;
112
119
  onStateChange?: (state: CoreState) => void;
120
+ /** Called when the input gains focus (or `setFocused(true)` is called). */
121
+ onFocus?: () => void;
122
+ /** Called when the input loses focus (or `setFocused(false)` is called). */
123
+ onBlur?: () => void;
113
124
  value?: string;
114
125
  completedParams?: CompletedParamState[];
115
126
  }
116
127
 
117
- interface KeyboardContext {
118
- columns: number;
119
- listboxId: string;
120
- onSubmit?: (result: AutocompleteResult) => void;
121
- selectOption: (option: SuggestionOption) => void;
122
- }
123
- declare class KeyboardController {
124
- private store;
125
- private ctx;
126
- constructor(store: Store<CoreState>, ctx: KeyboardContext);
127
- handleKeyDown(e: KeyboardEvent): void;
128
- private getTappableIndices;
129
- private clickOrSelect;
130
- /** Delegate to pills controller logic inline (avoids circular dep) */
131
- private pillsSetActivePill;
132
- }
133
-
134
128
  declare class AIAutocomplete {
135
129
  private store;
136
- private listboxId;
130
+ private _listboxId;
137
131
  private opts;
138
132
  private fetchController;
139
- keyboardController: KeyboardController;
133
+ private keyboardController;
140
134
  private pillsController;
141
135
  private modeController;
142
136
  private container;
143
137
  private unsubscribers;
144
138
  private derivedInProgress;
139
+ private renderMode;
145
140
  private domRefs;
141
+ private dropdownRefs;
146
142
  private newParamTimer;
143
+ private suggestionRemovalTimer;
144
+ private externalListeners;
147
145
  constructor(container: HTMLElement, opts?: CoreOptions);
148
146
  focus(): void;
147
+ blur(): void;
149
148
  reset(): void;
150
149
  destroy(): void;
151
150
  setMode(mode: AppearanceMode): void;
@@ -154,15 +153,35 @@ declare class AIAutocomplete {
154
153
  setActivePill(index: number): void;
155
154
  removeLastParam(): void;
156
155
  clearNewParamId(): void;
156
+ setActiveDropdownIndex(index: number): void;
157
+ handleTextChange(value: string): void;
158
+ handleKeyDown(e: KeyboardEvent): void;
159
+ setFocused(focused: boolean): void;
160
+ /** Subscribe to state changes (fires after derived state is settled). Returns unsubscribe function. */
161
+ subscribe(listener: (state: CoreState) => void): () => void;
157
162
  getState(): CoreState;
163
+ get listboxId(): string;
158
164
  get isReady(): boolean;
159
165
  on(event: string, callback: (...args: unknown[]) => void): () => void;
160
166
  update(opts: Partial<CoreOptions>): void;
161
- private selectOption;
167
+ selectOption(option: SuggestionOption): void;
162
168
  private recomputeDerived;
163
169
  private setupContainer;
164
- private buildAndRender;
170
+ private buildAndRenderFull;
171
+ private buildAndRenderDropdown;
172
+ /** Batched render subscriber — coalesces multiple store.set calls into one DOM update. */
173
+ private subscribeBatchedRender;
174
+ /** Auto-clear newParamId after shimmer animation. */
175
+ private subscribeNewParamTimer;
165
176
  private handleChange;
166
177
  }
167
178
 
168
- export { AIAutocomplete, type APIConfig, type APIKeyConfig, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type Segment, type Store, type Suggestion, type SuggestionOption, createStore };
179
+ type Listener<S> = (next: S, prev: S) => void;
180
+ interface Store<S> {
181
+ get: () => S;
182
+ set: (patch: Partial<S> | ((s: S) => Partial<S>)) => void;
183
+ subscribe: (listener: Listener<S>) => () => void;
184
+ }
185
+ declare function createStore<S>(initial: S): Store<S>;
186
+
187
+ export { AIAutocomplete, type APIConfig, type APIKeyConfig, type AccessTokenConfig, type AccessTokenResult, type AppearanceMode, type AutocompleteResult, type CompletedParam, type CompletedParamState, type CoreOptions, type CoreState, type RenderMode, type Segment, type Store, type Suggestion, type SuggestionOption, createStore };