@bloomreach/react-banana-ui 1.43.0 → 1.44.0

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,6 @@
1
+ import { FilterOptionsState } from '@mui/base';
2
+ /**
3
+ * A `filterOptions` implementation that returns all options unchanged.
4
+ * Used to bypass client-side filtering when options are already filtered by a server/API.
5
+ */
6
+ export declare function passthroughFilter<AutocompleteOption>(options: AutocompleteOption[], _state: FilterOptionsState<AutocompleteOption>): AutocompleteOption[];
@@ -1,5 +1,5 @@
1
1
  import { default as Autocomplete } from './autocomplete';
2
- import { ControlledMultipleValue as ControlledMultipleValueStory, ControlledSingleValue as ControlledSingleValueStory, CustomOptionLabel as CustomOptionLabelStory, FreeSoloMultiple as FreeSoloMultipleStory, FreeSoloSingle as FreeSoloSingleStory, HideSelectedOptions as HideSelectedOptionsStory, Multiple as MultipleStory, PasteMultipleValues as PasteMultipleValuesStory, PasteWithFreeSolo as PasteWithFreeSoloStory, Story } from './autocomplete.stories';
2
+ import { AsyncLoadOptionsFreeSolo as AsyncLoadOptionsFreeSoloStory, AsyncLoadOptionsMinInputLength as AsyncLoadOptionsMinInputLengthStory, AsyncLoadOptionsMultiple as AsyncLoadOptionsMultipleStory, AsyncLoadOptions as AsyncLoadOptionsStory, AsyncLoadOptionsWithPostFilter as AsyncLoadOptionsWithPostFilterStory, ControlledMultipleValue as ControlledMultipleValueStory, ControlledSingleValue as ControlledSingleValueStory, CustomOptionLabel as CustomOptionLabelStory, DisableClientFilter as DisableClientFilterStory, FreeSoloMultiple as FreeSoloMultipleStory, FreeSoloSingle as FreeSoloSingleStory, HideSelectedOptions as HideSelectedOptionsStory, Multiple as MultipleStory, PasteMultipleValues as PasteMultipleValuesStory, PasteWithFreeSolo as PasteWithFreeSoloStory, Story } from './autocomplete.stories';
3
3
  import { Meta } from '@storybook/react-vite';
4
4
  declare const meta: Meta<typeof Autocomplete>;
5
5
  export default meta;
@@ -27,3 +27,9 @@ export declare const CustomOptionRendering: Story<{
27
27
  }, true, true>;
28
28
  export declare const PasteMultipleValues: typeof PasteMultipleValuesStory;
29
29
  export declare const PasteWithFreeSolo: typeof PasteWithFreeSoloStory;
30
+ export declare const DisableClientFilter: typeof DisableClientFilterStory;
31
+ export declare const AsyncLoadOptions: typeof AsyncLoadOptionsStory;
32
+ export declare const AsyncLoadOptionsMultiple: typeof AsyncLoadOptionsMultipleStory;
33
+ export declare const AsyncLoadOptionsMinInputLength: typeof AsyncLoadOptionsMinInputLengthStory;
34
+ export declare const AsyncLoadOptionsWithPostFilter: typeof AsyncLoadOptionsWithPostFilterStory;
35
+ export declare const AsyncLoadOptionsFreeSolo: typeof AsyncLoadOptionsFreeSoloStory;
@@ -61,3 +61,18 @@ export declare const PasteWithRegexDelimiter: Story<string, true>;
61
61
  export declare const WithLeftElement: Story;
62
62
  export declare const WithRightElement: Story;
63
63
  export declare const WithBothElements: Story;
64
+ /**
65
+ * Server returns valid options for "india kar", but default client filter hides them
66
+ * because labels don't contain "kar".
67
+ */
68
+ export declare const ServerFilterComparison: Story;
69
+ /**
70
+ * Consumer-managed API fetch with disableClientFilter.
71
+ */
72
+ export declare const ConsumerManagedApiFetch: Story;
73
+ export declare const DisableClientFilter: Story;
74
+ export declare const AsyncLoadOptions: Story;
75
+ export declare const AsyncLoadOptionsMultiple: Story<string, true>;
76
+ export declare const AsyncLoadOptionsMinInputLength: Story;
77
+ export declare const AsyncLoadOptionsWithPostFilter: Story;
78
+ export declare const AsyncLoadOptionsFreeSolo: Story<string, false, true>;
@@ -29,18 +29,38 @@ export interface AutocompleteProps<AutocompleteOption extends NonNullable<unknow
29
29
  * It is `false` by default when `multiple` is `true`.
30
30
  */
31
31
  closeOnSelect?: boolean;
32
+ /**
33
+ * Milliseconds to debounce `loadOptions` calls after the user types.
34
+ * Only applies when `loadOptions` is provided.
35
+ * @default 300
36
+ */
37
+ debounceMs?: number;
32
38
  /**
33
39
  * The default selected value. Use when the component is not controlled.
34
40
  * The value must be an array when `multiple` is `true`.
35
41
  */
36
42
  defaultValue?: AutocompleteValue<AutocompleteOption, Multiple, FreeSolo>;
43
+ /**
44
+ * If `true`, client-side filtering is disabled and all provided options are shown.
45
+ * Use when options are already filtered by a server/API.
46
+ * Automatically enabled when `loadOptions` is provided unless `filterOptions` is set.
47
+ * @default false
48
+ */
49
+ disableClientFilter?: boolean;
37
50
  /**
38
51
  * If `true`, the component is disabled.
39
52
  * @default false
40
53
  */
41
54
  disabled?: boolean;
55
+ /**
56
+ * Text shown in the dropdown when `loadOptions` rejects.
57
+ * @default "Failed to load options"
58
+ */
59
+ errorText?: string;
42
60
  /**
43
61
  * Filter function to determine which options to show based on user input.
62
+ * When `disableClientFilter` is `true` or `loadOptions` is provided, defaults to showing all options.
63
+ * Use this to post-process options returned from an API.
44
64
  * @param options The array of options to filter
45
65
  * @param state The current state of the autocomplete
46
66
  */
@@ -111,11 +131,24 @@ export interface AutocompleteProps<AutocompleteOption extends NonNullable<unknow
111
131
  * @default "Loading..."
112
132
  */
113
133
  loadingText?: string;
134
+ /**
135
+ * Async callback to load options based on the current input value.
136
+ * When provided, the component manages debouncing, loading state, and request cancellation.
137
+ * Client-side filtering is disabled by default; use `filterOptions` to post-process API results.
138
+ */
139
+ loadOptions?: (inputValue: string, context: AutocompleteLoadOptionsContext) => Promise<AutocompleteOption[]>;
114
140
  /**
115
141
  * The maximum number of visible tag rows before the tag area becomes scrollable while the popup is closed.
116
142
  * Only works when `multiple` is `true`.
117
143
  */
118
144
  maxRows?: number;
145
+ /**
146
+ * Minimum number of trimmed characters required before `loadOptions` is called.
147
+ * Set to `0` to load on popup open / empty input (e.g. to show default suggestions).
148
+ * Only applies when `loadOptions` is provided.
149
+ * @default 1
150
+ */
151
+ minInputLength?: number;
119
152
  /**
120
153
  * If `true`, the component allows multiple selections.
121
154
  * @default false
@@ -141,6 +174,10 @@ export interface AutocompleteProps<AutocompleteOption extends NonNullable<unknow
141
174
  * @param reason The reason for the input change ('input' | 'reset' | 'clear')
142
175
  */
143
176
  onInputChange?: (event: SyntheticEvent, value: string, reason?: string) => void;
177
+ /**
178
+ * Callback fired when `loadOptions` rejects.
179
+ */
180
+ onLoadOptionsError?: (error: unknown) => void;
144
181
  /**
145
182
  * Callback fired when the popup opens.
146
183
  */
@@ -166,7 +203,7 @@ export interface AutocompleteProps<AutocompleteOption extends NonNullable<unknow
166
203
  */
167
204
  onTagClick?: (event: SyntheticEvent, option: AutocompleteOption, index: number) => void;
168
205
  /**
169
- * Array ot options to display.
206
+ * Array of options to display.
170
207
  */
171
208
  options: AutocompleteOption[];
172
209
  /**
@@ -246,6 +283,12 @@ export interface AutocompleteProps<AutocompleteOption extends NonNullable<unknow
246
283
  */
247
284
  width?: number | string;
248
285
  }
286
+ export interface AutocompleteLoadOptionsContext {
287
+ /**
288
+ * AbortSignal to cancel the request when the input changes or the component unmounts.
289
+ */
290
+ signal: AbortSignal;
291
+ }
249
292
  export interface AutocompleteRenderGroupParams extends AutocompleteGroupedOption<object> {
250
293
  children: ReactNode;
251
294
  }
@@ -1,2 +1,2 @@
1
1
  export { default as Autocomplete } from './autocomplete';
2
- export type { AutocompleteProps } from './autocomplete.types';
2
+ export type { AutocompleteLoadOptionsContext, AutocompleteProps } from './autocomplete.types';
@@ -0,0 +1,22 @@
1
+ import { AutocompleteLoadOptionsContext } from './autocomplete.types';
2
+ export interface UseLoadOptionsParams<AutocompleteOption> {
3
+ debounceMs?: number;
4
+ loadOptions?: (inputValue: string, context: AutocompleteLoadOptionsContext) => Promise<AutocompleteOption[]>;
5
+ minInputLength?: number;
6
+ onLoadOptionsError?: (error: unknown) => void;
7
+ }
8
+ export interface TriggerLoadOptions {
9
+ /**
10
+ * When `true`, reuse the last successful fetch for the same input instead of calling `loadOptions` again.
11
+ * Used when the popup opens on refocus.
12
+ */
13
+ useCache?: boolean;
14
+ }
15
+ export interface UseLoadOptionsResult<AutocompleteOption> {
16
+ asyncOptions: AutocompleteOption[];
17
+ clearCache: () => void;
18
+ internalLoading: boolean;
19
+ loadError: boolean;
20
+ triggerLoad: (inputValue: string, options?: TriggerLoadOptions) => void;
21
+ }
22
+ export declare function useLoadOptions<AutocompleteOption>(params: UseLoadOptionsParams<AutocompleteOption>): UseLoadOptionsResult<AutocompleteOption>;
@@ -16,6 +16,7 @@ export declare const ControlledSingleValue: Story;
16
16
  export declare const Multiple: Story<(typeof fruits)[0], true>;
17
17
  export declare const DefaultValueMultiple: Story<(typeof fruits)[0], true>;
18
18
  export declare const ControlledMultipleValue: Story<(typeof fruits)[0], true>;
19
+ export declare const SelectableTags: Story<(typeof fruits)[0], true>;
19
20
  export declare const Clearable: Story;
20
21
  export declare const Disabled: Story;
21
22
  export declare const DisabledMultiple: Story<(typeof fruits)[0], true>;
@@ -42,3 +43,8 @@ export declare const CustomOptionRendering: Story<{
42
43
  export declare const FieldsInColumn: Story;
43
44
  export declare const FieldsInRow: Story;
44
45
  export declare const PasteWithRegexDelimiter: Story<string, true>;
46
+ export declare const DisableClientFilter: Story;
47
+ export declare const ConsumerManagedApiFetch: Story;
48
+ export declare const AsyncLoadOptions: Story;
49
+ export declare const AsyncLoadOptionsMultiple: Story<string, true>;
50
+ export declare const AsyncLoadOptionsFreeSolo: Story<string, false, true>;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@bloomreach/react-banana-ui",
3
3
  "type": "module",
4
- "version": "1.43.0",
4
+ "version": "1.44.0",
5
5
  "private": false,
6
6
  "repository": {
7
7
  "type": "git",