@rovula/ui 0.1.41 → 0.1.42

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.
@@ -0,0 +1,74 @@
1
+ import React, { ReactNode } from "react";
2
+ import { type InputProps } from "../TextInput/TextInput";
3
+ export type AutoCompleteOption = {
4
+ value: string;
5
+ label: string;
6
+ };
7
+ /**
8
+ * InputProps that AutoComplete manages internally.
9
+ * These are excluded from the public API so callers cannot accidentally
10
+ * override internal event wiring or ARIA attributes.
11
+ */
12
+ type OmittedInputProps = "value" | "onChange" | "onKeyDown" | "onSelect" | "role" | "aria-expanded" | "aria-haspopup" | "aria-autocomplete" | "aria-activedescendant" | "aria-controls" | "autoComplete" | "hasClearIcon";
13
+ export type AutoCompleteProps<T extends AutoCompleteOption = AutoCompleteOption> = {
14
+ /** Options provided by caller (already filtered/fetched externally) */
15
+ options: T[];
16
+ /** Controlled value — the current input text */
17
+ value?: string;
18
+ /**
19
+ * Called on every change: typing or clearing.
20
+ * Parent should update `value` from this.
21
+ */
22
+ onChange?: (value: string) => void;
23
+ /**
24
+ * Called only when user explicitly selects an option from the list.
25
+ * Receives the full option object (including any domain-specific fields).
26
+ */
27
+ onSelect?: (option: T) => void;
28
+ onBlur?: () => void;
29
+ /** Called with the current query when the user types */
30
+ onSearch?: (query: string) => void;
31
+ /** Show a loading spinner inside the dropdown */
32
+ loading?: boolean;
33
+ /** Text shown when options is empty and not loading */
34
+ noOptionsText?: string;
35
+ /**
36
+ * When true, show the noOptionsText message when options is empty.
37
+ * Defaults to false (popover stays closed when no options).
38
+ */
39
+ showNoOptions?: boolean;
40
+ /**
41
+ * Custom render for each option item.
42
+ * Receives the option and whether it is currently selected.
43
+ * The wrapper button (styles + click handler) is provided by AutoComplete.
44
+ */
45
+ renderOption?: (option: T, isSelected: boolean) => ReactNode;
46
+ /**
47
+ * Override client-side filtering.
48
+ * Pass `(x) => x` to disable filtering entirely (when results come from an API).
49
+ * Defaults to identity (no filtering).
50
+ */
51
+ filterOptions?: (options: T[]) => T[];
52
+ /**
53
+ * Render the options list via a React portal so it escapes containers
54
+ * with `overflow: hidden/auto`.
55
+ * Set to false when inside a Dialog — portal content is blocked by
56
+ * Radix Dialog's focus trap and aria-modal, making items unclickable.
57
+ * Defaults to true.
58
+ */
59
+ portal?: boolean;
60
+ /** Extra className applied to the options list container */
61
+ listboxClassName?: string;
62
+ /** Extra inline styles applied to the options list container */
63
+ listboxStyle?: React.CSSProperties;
64
+ /** Extra className applied to each option item */
65
+ optionClassName?: string;
66
+ /** Extra inline styles applied to each option item */
67
+ optionStyle?: React.CSSProperties;
68
+ "data-testid"?: string;
69
+ } & Omit<InputProps, OmittedInputProps>;
70
+ declare function AutoCompleteInner<T extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: AutoCompleteProps<T>, ref: React.ForwardedRef<HTMLInputElement>): import("react/jsx-runtime").JSX.Element;
71
+ declare const AutoComplete: <T extends AutoCompleteOption = AutoCompleteOption>(props: AutoCompleteProps<T> & {
72
+ ref?: React.ForwardedRef<HTMLInputElement>;
73
+ }) => ReturnType<typeof AutoCompleteInner>;
74
+ export default AutoComplete;
@@ -0,0 +1,361 @@
1
+ import React from "react";
2
+ import type { StoryObj } from "@storybook/react";
3
+ import AutoComplete, { type AutoCompleteOption } from "./AutoComplete";
4
+ declare const meta: {
5
+ title: string;
6
+ component: <T extends AutoCompleteOption = AutoCompleteOption>(props: import("./AutoComplete").AutoCompleteProps<T> & {
7
+ ref?: React.ForwardedRef<HTMLInputElement>;
8
+ }) => ReturnType<(<T_1 extends AutoCompleteOption = AutoCompleteOption>({ options, value, onChange, onSelect, onBlur, onSearch, loading, noOptionsText, showNoOptions, renderOption, filterOptions, portal, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId, id, label, fullwidth, size, rounded, variant, disabled, ...rest }: import("./AutoComplete").AutoCompleteProps<T_1>, ref: React.ForwardedRef<HTMLInputElement>) => import("react/jsx-runtime").JSX.Element)>;
9
+ tags: string[];
10
+ parameters: {
11
+ layout: string;
12
+ };
13
+ decorators: ((Story: import("@storybook/csf").PartialStoryFn<import("@storybook/react").ReactRenderer, {
14
+ options: AutoCompleteOption[];
15
+ value?: string | undefined;
16
+ onChange?: ((value: string) => void) | undefined;
17
+ onSelect?: ((option: AutoCompleteOption) => void) | undefined;
18
+ onBlur?: ((() => void) & React.FocusEventHandler<HTMLInputElement>) | undefined;
19
+ onSearch?: ((query: string) => void) | undefined;
20
+ loading?: boolean | undefined;
21
+ noOptionsText?: string | undefined;
22
+ showNoOptions?: boolean | undefined;
23
+ renderOption?: ((option: AutoCompleteOption, isSelected: boolean) => React.ReactNode) | undefined;
24
+ filterOptions?: ((options: AutoCompleteOption[]) => AutoCompleteOption[]) | undefined;
25
+ portal?: boolean | undefined;
26
+ listboxClassName?: string | undefined;
27
+ listboxStyle?: React.CSSProperties | undefined;
28
+ optionClassName?: string | undefined;
29
+ optionStyle?: React.CSSProperties | undefined;
30
+ "data-testid"?: string | undefined;
31
+ variant?: "flat" | "outline" | "underline" | undefined;
32
+ suppressHydrationWarning?: boolean | undefined | undefined;
33
+ className?: string | undefined;
34
+ color?: string | undefined | undefined;
35
+ height?: number | string | undefined | undefined;
36
+ id?: string | undefined;
37
+ lang?: string | undefined | undefined;
38
+ max?: number | string | undefined | undefined;
39
+ min?: number | string | undefined | undefined;
40
+ name?: string | undefined | undefined;
41
+ style?: React.CSSProperties | undefined;
42
+ type?: React.HTMLInputTypeAttribute | undefined;
43
+ width?: number | string | undefined | undefined;
44
+ tabIndex?: number | undefined | undefined;
45
+ format?: ((value: string) => string) | undefined;
46
+ "aria-atomic"?: (boolean | "true" | "false") | undefined;
47
+ "aria-braillelabel"?: string | undefined | undefined;
48
+ "aria-brailleroledescription"?: string | undefined | undefined;
49
+ "aria-busy"?: (boolean | "true" | "false") | undefined;
50
+ "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
51
+ "aria-colcount"?: number | undefined | undefined;
52
+ "aria-colindex"?: number | undefined | undefined;
53
+ "aria-colindextext"?: string | undefined | undefined;
54
+ "aria-colspan"?: number | undefined | undefined;
55
+ "aria-current"?: boolean | "false" | "true" | "page" | "step" | "location" | "date" | "time" | undefined | undefined;
56
+ "aria-describedby"?: string | undefined | undefined;
57
+ "aria-description"?: string | undefined | undefined;
58
+ "aria-details"?: string | undefined | undefined;
59
+ "aria-disabled"?: (boolean | "true" | "false") | undefined;
60
+ "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined | undefined;
61
+ "aria-errormessage"?: string | undefined | undefined;
62
+ "aria-flowto"?: string | undefined | undefined;
63
+ "aria-grabbed"?: (boolean | "true" | "false") | undefined;
64
+ "aria-hidden"?: (boolean | "true" | "false") | undefined;
65
+ "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined | undefined;
66
+ "aria-keyshortcuts"?: string | undefined | undefined;
67
+ "aria-label"?: string | undefined | undefined;
68
+ "aria-labelledby"?: string | undefined | undefined;
69
+ "aria-level"?: number | undefined | undefined;
70
+ "aria-live"?: "off" | "assertive" | "polite" | undefined | undefined;
71
+ "aria-modal"?: (boolean | "true" | "false") | undefined;
72
+ "aria-multiline"?: (boolean | "true" | "false") | undefined;
73
+ "aria-multiselectable"?: (boolean | "true" | "false") | undefined;
74
+ "aria-orientation"?: "horizontal" | "vertical" | undefined | undefined;
75
+ "aria-owns"?: string | undefined | undefined;
76
+ "aria-placeholder"?: string | undefined | undefined;
77
+ "aria-posinset"?: number | undefined | undefined;
78
+ "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined | undefined;
79
+ "aria-readonly"?: (boolean | "true" | "false") | undefined;
80
+ "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined | undefined;
81
+ "aria-required"?: (boolean | "true" | "false") | undefined;
82
+ "aria-roledescription"?: string | undefined | undefined;
83
+ "aria-rowcount"?: number | undefined | undefined;
84
+ "aria-rowindex"?: number | undefined | undefined;
85
+ "aria-rowindextext"?: string | undefined | undefined;
86
+ "aria-rowspan"?: number | undefined | undefined;
87
+ "aria-selected"?: (boolean | "true" | "false") | undefined;
88
+ "aria-setsize"?: number | undefined | undefined;
89
+ "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined | undefined;
90
+ "aria-valuemax"?: number | undefined | undefined;
91
+ "aria-valuemin"?: number | undefined | undefined;
92
+ "aria-valuenow"?: number | undefined | undefined;
93
+ "aria-valuetext"?: string | undefined | undefined;
94
+ children?: React.ReactNode;
95
+ dangerouslySetInnerHTML?: {
96
+ __html: string | TrustedHTML;
97
+ } | undefined | undefined;
98
+ onCopy?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
99
+ onCopyCapture?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
100
+ onCut?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
101
+ onCutCapture?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
102
+ onPaste?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
103
+ onPasteCapture?: React.ClipboardEventHandler<HTMLInputElement> | undefined;
104
+ onCompositionEnd?: React.CompositionEventHandler<HTMLInputElement> | undefined;
105
+ onCompositionEndCapture?: React.CompositionEventHandler<HTMLInputElement> | undefined;
106
+ onCompositionStart?: React.CompositionEventHandler<HTMLInputElement> | undefined;
107
+ onCompositionStartCapture?: React.CompositionEventHandler<HTMLInputElement> | undefined;
108
+ onCompositionUpdate?: React.CompositionEventHandler<HTMLInputElement> | undefined;
109
+ onCompositionUpdateCapture?: React.CompositionEventHandler<HTMLInputElement> | undefined;
110
+ onFocus?: React.FocusEventHandler<HTMLInputElement> | undefined;
111
+ onFocusCapture?: React.FocusEventHandler<HTMLInputElement> | undefined;
112
+ onBlurCapture?: React.FocusEventHandler<HTMLInputElement> | undefined;
113
+ onChangeCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
114
+ onBeforeInput?: React.FormEventHandler<HTMLInputElement> | undefined;
115
+ onBeforeInputCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
116
+ onInput?: React.FormEventHandler<HTMLInputElement> | undefined;
117
+ onInputCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
118
+ onReset?: React.FormEventHandler<HTMLInputElement> | undefined;
119
+ onResetCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
120
+ onSubmit?: React.FormEventHandler<HTMLInputElement> | undefined;
121
+ onSubmitCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
122
+ onInvalid?: React.FormEventHandler<HTMLInputElement> | undefined;
123
+ onInvalidCapture?: React.FormEventHandler<HTMLInputElement> | undefined;
124
+ onLoad?: React.ReactEventHandler<HTMLInputElement> | undefined;
125
+ onLoadCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
126
+ onError?: React.ReactEventHandler<HTMLInputElement> | undefined;
127
+ onErrorCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
128
+ onKeyDownCapture?: React.KeyboardEventHandler<HTMLInputElement> | undefined;
129
+ onKeyPress?: React.KeyboardEventHandler<HTMLInputElement> | undefined;
130
+ onKeyPressCapture?: React.KeyboardEventHandler<HTMLInputElement> | undefined;
131
+ onKeyUp?: React.KeyboardEventHandler<HTMLInputElement> | undefined;
132
+ onKeyUpCapture?: React.KeyboardEventHandler<HTMLInputElement> | undefined;
133
+ onAbort?: React.ReactEventHandler<HTMLInputElement> | undefined;
134
+ onAbortCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
135
+ onCanPlay?: React.ReactEventHandler<HTMLInputElement> | undefined;
136
+ onCanPlayCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
137
+ onCanPlayThrough?: React.ReactEventHandler<HTMLInputElement> | undefined;
138
+ onCanPlayThroughCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
139
+ onDurationChange?: React.ReactEventHandler<HTMLInputElement> | undefined;
140
+ onDurationChangeCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
141
+ onEmptied?: React.ReactEventHandler<HTMLInputElement> | undefined;
142
+ onEmptiedCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
143
+ onEncrypted?: React.ReactEventHandler<HTMLInputElement> | undefined;
144
+ onEncryptedCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
145
+ onEnded?: React.ReactEventHandler<HTMLInputElement> | undefined;
146
+ onEndedCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
147
+ onLoadedData?: React.ReactEventHandler<HTMLInputElement> | undefined;
148
+ onLoadedDataCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
149
+ onLoadedMetadata?: React.ReactEventHandler<HTMLInputElement> | undefined;
150
+ onLoadedMetadataCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
151
+ onLoadStart?: React.ReactEventHandler<HTMLInputElement> | undefined;
152
+ onLoadStartCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
153
+ onPause?: React.ReactEventHandler<HTMLInputElement> | undefined;
154
+ onPauseCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
155
+ onPlay?: React.ReactEventHandler<HTMLInputElement> | undefined;
156
+ onPlayCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
157
+ onPlaying?: React.ReactEventHandler<HTMLInputElement> | undefined;
158
+ onPlayingCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
159
+ onProgress?: React.ReactEventHandler<HTMLInputElement> | undefined;
160
+ onProgressCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
161
+ onRateChange?: React.ReactEventHandler<HTMLInputElement> | undefined;
162
+ onRateChangeCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
163
+ onResize?: React.ReactEventHandler<HTMLInputElement> | undefined;
164
+ onResizeCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
165
+ onSeeked?: React.ReactEventHandler<HTMLInputElement> | undefined;
166
+ onSeekedCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
167
+ onSeeking?: React.ReactEventHandler<HTMLInputElement> | undefined;
168
+ onSeekingCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
169
+ onStalled?: React.ReactEventHandler<HTMLInputElement> | undefined;
170
+ onStalledCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
171
+ onSuspend?: React.ReactEventHandler<HTMLInputElement> | undefined;
172
+ onSuspendCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
173
+ onTimeUpdate?: React.ReactEventHandler<HTMLInputElement> | undefined;
174
+ onTimeUpdateCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
175
+ onVolumeChange?: React.ReactEventHandler<HTMLInputElement> | undefined;
176
+ onVolumeChangeCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
177
+ onWaiting?: React.ReactEventHandler<HTMLInputElement> | undefined;
178
+ onWaitingCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
179
+ onAuxClick?: React.MouseEventHandler<HTMLInputElement> | undefined;
180
+ onAuxClickCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
181
+ onClick?: React.MouseEventHandler<HTMLInputElement> | undefined;
182
+ onClickCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
183
+ onContextMenu?: React.MouseEventHandler<HTMLInputElement> | undefined;
184
+ onContextMenuCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
185
+ onDoubleClick?: React.MouseEventHandler<HTMLInputElement> | undefined;
186
+ onDoubleClickCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
187
+ onDrag?: React.DragEventHandler<HTMLInputElement> | undefined;
188
+ onDragCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
189
+ onDragEnd?: React.DragEventHandler<HTMLInputElement> | undefined;
190
+ onDragEndCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
191
+ onDragEnter?: React.DragEventHandler<HTMLInputElement> | undefined;
192
+ onDragEnterCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
193
+ onDragExit?: React.DragEventHandler<HTMLInputElement> | undefined;
194
+ onDragExitCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
195
+ onDragLeave?: React.DragEventHandler<HTMLInputElement> | undefined;
196
+ onDragLeaveCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
197
+ onDragOver?: React.DragEventHandler<HTMLInputElement> | undefined;
198
+ onDragOverCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
199
+ onDragStart?: React.DragEventHandler<HTMLInputElement> | undefined;
200
+ onDragStartCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
201
+ onDrop?: React.DragEventHandler<HTMLInputElement> | undefined;
202
+ onDropCapture?: React.DragEventHandler<HTMLInputElement> | undefined;
203
+ onMouseDown?: React.MouseEventHandler<HTMLInputElement> | undefined;
204
+ onMouseDownCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
205
+ onMouseEnter?: React.MouseEventHandler<HTMLInputElement> | undefined;
206
+ onMouseLeave?: React.MouseEventHandler<HTMLInputElement> | undefined;
207
+ onMouseMove?: React.MouseEventHandler<HTMLInputElement> | undefined;
208
+ onMouseMoveCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
209
+ onMouseOut?: React.MouseEventHandler<HTMLInputElement> | undefined;
210
+ onMouseOutCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
211
+ onMouseOver?: React.MouseEventHandler<HTMLInputElement> | undefined;
212
+ onMouseOverCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
213
+ onMouseUp?: React.MouseEventHandler<HTMLInputElement> | undefined;
214
+ onMouseUpCapture?: React.MouseEventHandler<HTMLInputElement> | undefined;
215
+ onSelectCapture?: React.ReactEventHandler<HTMLInputElement> | undefined;
216
+ onTouchCancel?: React.TouchEventHandler<HTMLInputElement> | undefined;
217
+ onTouchCancelCapture?: React.TouchEventHandler<HTMLInputElement> | undefined;
218
+ onTouchEnd?: React.TouchEventHandler<HTMLInputElement> | undefined;
219
+ onTouchEndCapture?: React.TouchEventHandler<HTMLInputElement> | undefined;
220
+ onTouchMove?: React.TouchEventHandler<HTMLInputElement> | undefined;
221
+ onTouchMoveCapture?: React.TouchEventHandler<HTMLInputElement> | undefined;
222
+ onTouchStart?: React.TouchEventHandler<HTMLInputElement> | undefined;
223
+ onTouchStartCapture?: React.TouchEventHandler<HTMLInputElement> | undefined;
224
+ onPointerDown?: React.PointerEventHandler<HTMLInputElement> | undefined;
225
+ onPointerDownCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
226
+ onPointerMove?: React.PointerEventHandler<HTMLInputElement> | undefined;
227
+ onPointerMoveCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
228
+ onPointerUp?: React.PointerEventHandler<HTMLInputElement> | undefined;
229
+ onPointerUpCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
230
+ onPointerCancel?: React.PointerEventHandler<HTMLInputElement> | undefined;
231
+ onPointerCancelCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
232
+ onPointerEnter?: React.PointerEventHandler<HTMLInputElement> | undefined;
233
+ onPointerLeave?: React.PointerEventHandler<HTMLInputElement> | undefined;
234
+ onPointerOver?: React.PointerEventHandler<HTMLInputElement> | undefined;
235
+ onPointerOverCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
236
+ onPointerOut?: React.PointerEventHandler<HTMLInputElement> | undefined;
237
+ onPointerOutCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
238
+ onGotPointerCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
239
+ onGotPointerCaptureCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
240
+ onLostPointerCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
241
+ onLostPointerCaptureCapture?: React.PointerEventHandler<HTMLInputElement> | undefined;
242
+ onScroll?: React.UIEventHandler<HTMLInputElement> | undefined;
243
+ onScrollCapture?: React.UIEventHandler<HTMLInputElement> | undefined;
244
+ onWheel?: React.WheelEventHandler<HTMLInputElement> | undefined;
245
+ onWheelCapture?: React.WheelEventHandler<HTMLInputElement> | undefined;
246
+ onAnimationStart?: React.AnimationEventHandler<HTMLInputElement> | undefined;
247
+ onAnimationStartCapture?: React.AnimationEventHandler<HTMLInputElement> | undefined;
248
+ onAnimationEnd?: React.AnimationEventHandler<HTMLInputElement> | undefined;
249
+ onAnimationEndCapture?: React.AnimationEventHandler<HTMLInputElement> | undefined;
250
+ onAnimationIteration?: React.AnimationEventHandler<HTMLInputElement> | undefined;
251
+ onAnimationIterationCapture?: React.AnimationEventHandler<HTMLInputElement> | undefined;
252
+ onTransitionEnd?: React.TransitionEventHandler<HTMLInputElement> | undefined;
253
+ onTransitionEndCapture?: React.TransitionEventHandler<HTMLInputElement> | undefined;
254
+ form?: string | undefined | undefined;
255
+ list?: string | undefined | undefined;
256
+ status?: "default" | "warning" | "error" | undefined;
257
+ step?: number | string | undefined | undefined;
258
+ normalize?: ((value: string) => string) | undefined;
259
+ warning?: boolean | undefined;
260
+ error?: boolean | undefined;
261
+ size?: "sm" | "md" | "lg" | undefined;
262
+ disabled?: boolean | undefined;
263
+ fullwidth?: boolean | undefined;
264
+ title?: string | undefined | undefined;
265
+ startIcon?: React.ReactNode;
266
+ endIcon?: React.ReactNode;
267
+ formAction?: string | undefined;
268
+ formEncType?: string | undefined | undefined;
269
+ formMethod?: string | undefined | undefined;
270
+ formNoValidate?: boolean | undefined | undefined;
271
+ formTarget?: string | undefined | undefined;
272
+ defaultChecked?: boolean | undefined | undefined;
273
+ defaultValue?: string | number | readonly string[] | undefined;
274
+ suppressContentEditableWarning?: boolean | undefined | undefined;
275
+ accessKey?: string | undefined | undefined;
276
+ autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {}) | undefined;
277
+ autoFocus?: boolean | undefined | undefined;
278
+ contentEditable?: "inherit" | (boolean | "true" | "false") | "plaintext-only" | undefined;
279
+ contextMenu?: string | undefined | undefined;
280
+ dir?: string | undefined | undefined;
281
+ draggable?: (boolean | "true" | "false") | undefined;
282
+ enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined | undefined;
283
+ hidden?: boolean | undefined | undefined;
284
+ nonce?: string | undefined | undefined;
285
+ slot?: string | undefined | undefined;
286
+ spellCheck?: (boolean | "true" | "false") | undefined;
287
+ translate?: "yes" | "no" | undefined | undefined;
288
+ radioGroup?: string | undefined | undefined;
289
+ about?: string | undefined | undefined;
290
+ content?: string | undefined | undefined;
291
+ datatype?: string | undefined | undefined;
292
+ inlist?: any;
293
+ prefix?: string | undefined | undefined;
294
+ property?: string | undefined | undefined;
295
+ rel?: string | undefined | undefined;
296
+ resource?: string | undefined | undefined;
297
+ rev?: string | undefined | undefined;
298
+ typeof?: string | undefined | undefined;
299
+ vocab?: string | undefined | undefined;
300
+ autoCorrect?: string | undefined | undefined;
301
+ autoSave?: string | undefined | undefined;
302
+ itemProp?: string | undefined | undefined;
303
+ itemScope?: boolean | undefined | undefined;
304
+ itemType?: string | undefined | undefined;
305
+ itemID?: string | undefined | undefined;
306
+ itemRef?: string | undefined | undefined;
307
+ results?: number | undefined | undefined;
308
+ security?: string | undefined | undefined;
309
+ unselectable?: "on" | "off" | undefined | undefined;
310
+ inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined | undefined;
311
+ is?: string | undefined | undefined;
312
+ rounded?: "none" | "normal" | "full" | undefined;
313
+ hasSearchIcon?: boolean | undefined;
314
+ isFloatingLabel?: boolean | undefined;
315
+ accept?: string | undefined | undefined;
316
+ alt?: string | undefined | undefined;
317
+ capture?: boolean | "user" | "environment" | undefined | undefined;
318
+ checked?: boolean | undefined | undefined;
319
+ maxLength?: number | undefined | undefined;
320
+ minLength?: number | undefined | undefined;
321
+ multiple?: boolean | undefined | undefined;
322
+ pattern?: string | undefined | undefined;
323
+ placeholder?: string | undefined | undefined;
324
+ readOnly?: boolean | undefined | undefined;
325
+ required?: boolean | undefined;
326
+ src?: string | undefined | undefined;
327
+ label?: string | undefined;
328
+ iconMode?: "flat" | "solid" | undefined;
329
+ helperText?: string | undefined;
330
+ errorMessage?: string | undefined;
331
+ warningMessage?: string | undefined;
332
+ keepCloseIconOnValue?: boolean | undefined;
333
+ keepFooterSpace?: boolean | undefined;
334
+ labelClassName?: string | undefined;
335
+ classes?: {
336
+ iconWrapper?: string;
337
+ iconSearchWrapper?: string;
338
+ icon?: string;
339
+ startIconWrapper?: string;
340
+ endIconWrapper?: string;
341
+ } | undefined;
342
+ onClickStartIcon?: (() => void) | undefined;
343
+ onClickEndIcon?: (() => void) | undefined;
344
+ renderStartIcon?: (() => React.ReactNode) | undefined;
345
+ renderEndIcon?: (() => React.ReactNode) | undefined;
346
+ trimOnCommit?: boolean | undefined;
347
+ normalizeOnCommit?: ((value: string) => string) | undefined;
348
+ ref?: React.ForwardedRef<HTMLInputElement> | undefined;
349
+ }>) => import("react/jsx-runtime").JSX.Element)[];
350
+ };
351
+ export default meta;
352
+ export declare const Default: StoryObj<typeof AutoComplete>;
353
+ export declare const ShowNoOptionsMessage: StoryObj;
354
+ export declare const FreeSolo: StoryObj;
355
+ export declare const Async: StoryObj;
356
+ export declare const WithFormValidation: StoryObj;
357
+ export declare const InsideDialog: StoryObj;
358
+ export declare const Sizes: StoryObj;
359
+ export declare const States: StoryObj;
360
+ export declare const LoadingState: StoryObj;
361
+ export declare const KeyboardNavigation: StoryObj;
@@ -0,0 +1,2 @@
1
+ export { default } from "./AutoComplete";
2
+ export type { AutoCompleteProps, AutoCompleteOption } from "./AutoComplete";
@@ -9,6 +9,9 @@ export { default as TextArea } from "./components/TextArea/TextArea";
9
9
  export { default as Text } from "./components/Text/Text";
10
10
  export { default as Tabs } from "./components/Tabs/Tabs";
11
11
  export { default as Dropdown } from "./components/Dropdown/Dropdown";
12
+ export { menuItemBaseStyles } from "./components/Dropdown/Dropdown";
13
+ export { default as AutoComplete } from "./components/AutoComplete/AutoComplete";
14
+ export type { AutoCompleteProps, AutoCompleteOption } from "./components/AutoComplete/AutoComplete";
12
15
  export { Checkbox } from "./components/Checkbox/Checkbox";
13
16
  export { Label } from "./components/Label/Label";
14
17
  export { Input } from "./components/Input/Input";
@@ -0,0 +1,103 @@
1
+ "use client";
2
+ var __rest = (this && this.__rest) || function (s, e) {
3
+ var t = {};
4
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
5
+ t[p] = s[p];
6
+ if (s != null && typeof Object.getOwnPropertySymbols === "function")
7
+ for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
8
+ if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
9
+ t[p[i]] = s[p[i]];
10
+ }
11
+ return t;
12
+ };
13
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
14
+ import { forwardRef, useCallback, useRef, useState, } from "react";
15
+ import * as PopoverPrimitive from "@radix-ui/react-popover";
16
+ import TextInput from "../TextInput/TextInput";
17
+ import Loading from "../Loading/Loading";
18
+ import Text from "../Text/Text";
19
+ import Icon from "../Icon/Icon";
20
+ import { cn } from "@/utils/cn";
21
+ import { menuItemBaseStyles } from "../Dropdown/Dropdown";
22
+ // ---------------------------------------------------------------------------
23
+ // AutoComplete
24
+ // ---------------------------------------------------------------------------
25
+ function AutoCompleteInner(_a, ref) {
26
+ var _b;
27
+ var {
28
+ // AutoComplete-specific props
29
+ options, value = "", onChange, onSelect, onBlur, onSearch, loading = false, noOptionsText = "No results", showNoOptions = false, renderOption, filterOptions = (x) => x, portal = true, listboxClassName, listboxStyle, optionClassName, optionStyle, "data-testid": testId,
30
+ // InputProps with explicit defaults (rest passes everything else through)
31
+ id, label, fullwidth = true, size = "md", rounded = "normal", variant = "outline", disabled } = _a, rest = __rest(_a, ["options", "value", "onChange", "onSelect", "onBlur", "onSearch", "loading", "noOptionsText", "showNoOptions", "renderOption", "filterOptions", "portal", "listboxClassName", "listboxStyle", "optionClassName", "optionStyle", "data-testid", "id", "label", "fullwidth", "size", "rounded", "variant", "disabled"]);
32
+ const [open, setOpen] = useState(false);
33
+ const [activeIndex, setActiveIndex] = useState(-1);
34
+ const inputRef = useRef(null);
35
+ const filteredOptions = filterOptions(options);
36
+ const showPopover = open && (loading || filteredOptions.length > 0 || showNoOptions);
37
+ const commitSelection = useCallback((option) => {
38
+ onChange === null || onChange === void 0 ? void 0 : onChange(option.value);
39
+ onSelect === null || onSelect === void 0 ? void 0 : onSelect(option);
40
+ setOpen(false);
41
+ setActiveIndex(-1);
42
+ }, [onChange, onSelect]);
43
+ const handleInputChange = useCallback((e) => {
44
+ const query = e.target.value;
45
+ onChange === null || onChange === void 0 ? void 0 : onChange(query);
46
+ onSearch === null || onSearch === void 0 ? void 0 : onSearch(query);
47
+ setOpen(true);
48
+ setActiveIndex(-1);
49
+ }, [onChange, onSearch]);
50
+ const handleFocus = useCallback((e) => {
51
+ var _a;
52
+ setOpen(true);
53
+ (_a = rest === null || rest === void 0 ? void 0 : rest.onFocus) === null || _a === void 0 ? void 0 : _a.call(rest, e);
54
+ }, [rest === null || rest === void 0 ? void 0 : rest.onFocus]);
55
+ const handleBlur = useCallback(() => {
56
+ // Delay so option button onClick fires before popover closes
57
+ setTimeout(() => {
58
+ setOpen(false);
59
+ setActiveIndex(-1);
60
+ onBlur === null || onBlur === void 0 ? void 0 : onBlur();
61
+ }, 150);
62
+ }, [onBlur]);
63
+ const handleKeyDown = useCallback((e) => {
64
+ if (!open) {
65
+ if (e.key === "ArrowDown" || e.key === "ArrowUp")
66
+ setOpen(true);
67
+ return;
68
+ }
69
+ if (e.key === "ArrowDown") {
70
+ e.preventDefault();
71
+ setActiveIndex((i) => Math.min(i + 1, filteredOptions.length - 1));
72
+ }
73
+ else if (e.key === "ArrowUp") {
74
+ e.preventDefault();
75
+ setActiveIndex((i) => Math.max(i - 1, 0));
76
+ }
77
+ else if (e.key === "Enter") {
78
+ e.preventDefault();
79
+ if (activeIndex >= 0 && filteredOptions[activeIndex]) {
80
+ commitSelection(filteredOptions[activeIndex]);
81
+ }
82
+ }
83
+ else if (e.key === "Escape") {
84
+ setOpen(false);
85
+ setActiveIndex(-1);
86
+ }
87
+ }, [open, activeIndex, filteredOptions, commitSelection]);
88
+ const listContent = (_jsx("div", { role: "listbox", style: Object.assign({ boxShadow: "var(--dropdown-menu-shadow)" }, listboxStyle), className: cn("rounded-md border border-bg-stroke3 overflow-hidden", "bg-modal-dropdown-surface text-text-g-contrast-high", !portal && "absolute top-full left-0 w-full -mt-3 z-[51]", portal && "z-[51]", listboxClassName), "data-testid": testId ? `${testId}-listbox` : undefined, children: loading ? (_jsx("div", { className: "flex items-center justify-center py-6", children: _jsx(Loading, { size: 20 }) })) : filteredOptions.length === 0 ? (_jsx("div", { className: "px-4 py-6 text-center", children: _jsx(Text, { variant: "small1", className: "text-[var(--dropdown-menu-default-text)]", children: noOptionsText }) })) : (filteredOptions.map((option, index) => {
89
+ const isSelected = option.value === value;
90
+ const isActive = index === activeIndex;
91
+ return (_jsxs("button", { id: `autocomplete-option-${option.value}`, type: "button", role: "option", "aria-selected": isSelected, style: optionStyle, className: cn(menuItemBaseStyles, "w-full", isSelected &&
92
+ "bg-[var(--dropdown-menu-selected-bg)] text-[var(--dropdown-menu-selected-text)]", isActive &&
93
+ !isSelected &&
94
+ "bg-[var(--dropdown-menu-hover-bg)] text-[var(--dropdown-menu-hover-text)]", optionClassName), onMouseDown: (e) => e.preventDefault(), onClick: () => commitSelection(option), "data-testid": `autocomplete-option-${option.value}`, children: [_jsx("span", { className: "shrink-0 size-4 flex items-center justify-center", children: isSelected && (_jsx(Icon, { type: "heroicons", name: "check", className: "size-4 text-[var(--dropdown-menu-selected-text)]" })) }), renderOption ? renderOption(option, isSelected) : option.label] }, option.value));
95
+ })) }));
96
+ return (_jsxs(PopoverPrimitive.Root, { open: showPopover, children: [_jsx(PopoverPrimitive.Anchor, { asChild: true, children: _jsxs("div", { className: cn("relative", fullwidth && "w-full"), children: [_jsx(TextInput, Object.assign({}, rest, { ref: ref !== null && ref !== void 0 ? ref : inputRef, id: id, label: label, value: value, size: size, rounded: rounded, variant: variant, disabled: disabled, fullwidth: fullwidth, autoComplete: "off", role: "combobox", "aria-expanded": showPopover, "aria-autocomplete": "list", "aria-activedescendant": activeIndex >= 0
97
+ ? `autocomplete-option-${(_b = filteredOptions[activeIndex]) === null || _b === void 0 ? void 0 : _b.value}`
98
+ : undefined, hasClearIcon: true, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, onKeyDown: handleKeyDown, "data-testid": testId })), showPopover && !portal && listContent] }) }), portal && (_jsx(PopoverPrimitive.Portal, { children: _jsx(PopoverPrimitive.Content, { onOpenAutoFocus: (e) => e.preventDefault(), onInteractOutside: (e) => e.preventDefault(), onFocusOutside: (e) => e.preventDefault(), side: "bottom", align: "start", sideOffset: -12, style: { width: "var(--radix-popover-trigger-width)" }, children: listContent }) }))] }));
99
+ }
100
+ // forwardRef with generics requires a manual cast
101
+ const AutoComplete = forwardRef(AutoCompleteInner);
102
+ AutoComplete.displayName = "AutoComplete";
103
+ export default AutoComplete;