@availity/mui-autocomplete 2.0.1 → 2.1.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.
- package/CHANGELOG.md +13 -0
- package/dist/index.d.mts +7 -5
- package/dist/index.d.ts +7 -5
- package/dist/index.js +13 -3
- package/dist/index.mjs +13 -3
- package/package.json +7 -7
- package/src/lib/AsyncAutocomplete.test.tsx +79 -0
- package/src/lib/AsyncAutocomplete.tsx +17 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
This file was generated using [@jscutlery/semver](https://github.com/jscutlery/semver).
|
|
4
4
|
|
|
5
|
+
## [2.1.0](https://github.com/Availity/element/compare/@availity/mui-autocomplete@2.0.2...@availity/mui-autocomplete@2.1.0) (2025-12-23)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
### Features
|
|
9
|
+
|
|
10
|
+
* prependOptions functionality for AsyncAutocompletes ([532b8b6](https://github.com/Availity/element/commit/532b8b6dc7a165ed37feb885fcea9cdf8007ae41))
|
|
11
|
+
|
|
12
|
+
## [2.0.2](https://github.com/Availity/element/compare/@availity/mui-autocomplete@2.0.1...@availity/mui-autocomplete@2.0.2) (2025-12-09)
|
|
13
|
+
|
|
14
|
+
### Dependency Updates
|
|
15
|
+
|
|
16
|
+
* `mui-form-utils` updated to version `2.0.1`
|
|
17
|
+
* `mui-textfield` updated to version `2.0.1`
|
|
5
18
|
## [2.0.1](https://github.com/Availity/element/compare/@availity/mui-autocomplete@2.0.0...@availity/mui-autocomplete@2.0.1) (2025-12-03)
|
|
6
19
|
|
|
7
20
|
### Dependency Updates
|
package/dist/index.d.mts
CHANGED
|
@@ -11,7 +11,7 @@ interface AutocompleteProps<T, Multiple extends boolean | undefined, DisableClea
|
|
|
11
11
|
FieldProps?: TextFieldProps;
|
|
12
12
|
name?: string;
|
|
13
13
|
}
|
|
14
|
-
declare const Autocomplete: <T, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
14
|
+
declare const Autocomplete: <T, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ FieldProps, ...props }: AutocompleteProps<T, Multiple, DisableClearable, FreeSolo, ChipComponent>) => React.JSX.Element;
|
|
15
15
|
|
|
16
16
|
interface AsyncAutocompleteProps<Option, Multiple extends boolean | undefined, DisableClearable extends boolean | undefined, FreeSolo extends boolean | undefined, ChipComponent extends React.ElementType = ChipTypeMap['defaultComponent']> extends Omit<AutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>, 'options' | 'disableListWrap' | 'loading'> {
|
|
17
17
|
/** Function that is called to fetch the options for the list. Returns a promise with options, hasMore, and offset */
|
|
@@ -35,8 +35,10 @@ interface AsyncAutocompleteProps<Option, Multiple extends boolean | undefined, D
|
|
|
35
35
|
watchParams?: Record<string, unknown>;
|
|
36
36
|
/** Time to wait before searching with the input value typed into the component */
|
|
37
37
|
debounceTimeout?: number;
|
|
38
|
+
/** Options to prepend to the list (e.g., frequently used items). These will be filtered from loadOptions results to avoid duplicates. */
|
|
39
|
+
prependOptions?: Option[];
|
|
38
40
|
}
|
|
39
|
-
declare const AsyncAutocomplete: <Option, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
41
|
+
declare const AsyncAutocomplete: <Option, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ loadOptions, limit, queryKey, ListboxProps, queryOptions, watchParams, debounceTimeout, FieldProps, onInputChange, prependOptions, ...rest }: AsyncAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
40
42
|
|
|
41
43
|
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
|
42
44
|
|
|
@@ -56,7 +58,7 @@ interface CodesAutocompleteProps<Option = Code, Multiple extends boolean | undef
|
|
|
56
58
|
apiConfig?: ApiConfig;
|
|
57
59
|
}
|
|
58
60
|
declare const handleGetCodesOptionLabel: (option: Code) => string;
|
|
59
|
-
declare const CodesAutocomplete: <Option = Code, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
61
|
+
declare const CodesAutocomplete: <Option = Code, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, queryOptions, queryKey, list, watchParams, ...rest }: CodesAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
60
62
|
|
|
61
63
|
type Organization = {
|
|
62
64
|
customerId: string;
|
|
@@ -75,7 +77,7 @@ interface OrgAutocompleteProps<Option = Organization, Multiple extends boolean |
|
|
|
75
77
|
apiConfig?: ApiConfig;
|
|
76
78
|
}
|
|
77
79
|
declare const handleGetOrgOptionLabel: (org: Organization) => string;
|
|
78
|
-
declare const OrganizationAutocomplete: <Option = Organization, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
80
|
+
declare const OrganizationAutocomplete: <Option = Organization, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, queryKey, ...rest }: OrgAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
79
81
|
|
|
80
82
|
type Provider = {
|
|
81
83
|
id: string;
|
|
@@ -134,6 +136,6 @@ interface ProviderAutocompleteProps<Option = Provider, Multiple extends boolean
|
|
|
134
136
|
apiConfig?: ApiConfig;
|
|
135
137
|
}
|
|
136
138
|
declare const handleGetProviderOptionLabel: (option: Provider) => string;
|
|
137
|
-
declare const ProviderAutocomplete: <Option = Provider, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
139
|
+
declare const ProviderAutocomplete: <Option = Provider, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, customerId, queryKey, ...rest }: ProviderAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
138
140
|
|
|
139
141
|
export { AsyncAutocomplete, type AsyncAutocompleteProps, Autocomplete, type AutocompleteProps, type Code, CodesAutocomplete, type CodesAutocompleteProps, type OrgAutocompleteProps, type Organization, OrganizationAutocomplete, type Provider, ProviderAutocomplete, type ProviderAutocompleteProps, fetchCodes, fetchOrgs, fetchProviders, handleGetCodesOptionLabel, handleGetOrgOptionLabel, handleGetProviderOptionLabel };
|
package/dist/index.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface AutocompleteProps<T, Multiple extends boolean | undefined, DisableClea
|
|
|
11
11
|
FieldProps?: TextFieldProps;
|
|
12
12
|
name?: string;
|
|
13
13
|
}
|
|
14
|
-
declare const Autocomplete: <T, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
14
|
+
declare const Autocomplete: <T, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ FieldProps, ...props }: AutocompleteProps<T, Multiple, DisableClearable, FreeSolo, ChipComponent>) => React.JSX.Element;
|
|
15
15
|
|
|
16
16
|
interface AsyncAutocompleteProps<Option, Multiple extends boolean | undefined, DisableClearable extends boolean | undefined, FreeSolo extends boolean | undefined, ChipComponent extends React.ElementType = ChipTypeMap['defaultComponent']> extends Omit<AutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>, 'options' | 'disableListWrap' | 'loading'> {
|
|
17
17
|
/** Function that is called to fetch the options for the list. Returns a promise with options, hasMore, and offset */
|
|
@@ -35,8 +35,10 @@ interface AsyncAutocompleteProps<Option, Multiple extends boolean | undefined, D
|
|
|
35
35
|
watchParams?: Record<string, unknown>;
|
|
36
36
|
/** Time to wait before searching with the input value typed into the component */
|
|
37
37
|
debounceTimeout?: number;
|
|
38
|
+
/** Options to prepend to the list (e.g., frequently used items). These will be filtered from loadOptions results to avoid duplicates. */
|
|
39
|
+
prependOptions?: Option[];
|
|
38
40
|
}
|
|
39
|
-
declare const AsyncAutocomplete: <Option, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
41
|
+
declare const AsyncAutocomplete: <Option, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ loadOptions, limit, queryKey, ListboxProps, queryOptions, watchParams, debounceTimeout, FieldProps, onInputChange, prependOptions, ...rest }: AsyncAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
40
42
|
|
|
41
43
|
type Optional<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;
|
|
42
44
|
|
|
@@ -56,7 +58,7 @@ interface CodesAutocompleteProps<Option = Code, Multiple extends boolean | undef
|
|
|
56
58
|
apiConfig?: ApiConfig;
|
|
57
59
|
}
|
|
58
60
|
declare const handleGetCodesOptionLabel: (option: Code) => string;
|
|
59
|
-
declare const CodesAutocomplete: <Option = Code, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
61
|
+
declare const CodesAutocomplete: <Option = Code, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, queryOptions, queryKey, list, watchParams, ...rest }: CodesAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
60
62
|
|
|
61
63
|
type Organization = {
|
|
62
64
|
customerId: string;
|
|
@@ -75,7 +77,7 @@ interface OrgAutocompleteProps<Option = Organization, Multiple extends boolean |
|
|
|
75
77
|
apiConfig?: ApiConfig;
|
|
76
78
|
}
|
|
77
79
|
declare const handleGetOrgOptionLabel: (org: Organization) => string;
|
|
78
|
-
declare const OrganizationAutocomplete: <Option = Organization, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
80
|
+
declare const OrganizationAutocomplete: <Option = Organization, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, queryKey, ...rest }: OrgAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
79
81
|
|
|
80
82
|
type Provider = {
|
|
81
83
|
id: string;
|
|
@@ -134,6 +136,6 @@ interface ProviderAutocompleteProps<Option = Provider, Multiple extends boolean
|
|
|
134
136
|
apiConfig?: ApiConfig;
|
|
135
137
|
}
|
|
136
138
|
declare const handleGetProviderOptionLabel: (option: Provider) => string;
|
|
137
|
-
declare const ProviderAutocomplete: <Option = Provider, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = "
|
|
139
|
+
declare const ProviderAutocomplete: <Option = Provider, Multiple extends boolean | undefined = false, DisableClearable extends boolean | undefined = false, FreeSolo extends boolean | undefined = false, ChipComponent extends React.ElementType = ChipTypeMap["defaultComponent"]>({ apiConfig, customerId, queryKey, ...rest }: ProviderAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => react_jsx_runtime.JSX.Element;
|
|
138
140
|
|
|
139
141
|
export { AsyncAutocomplete, type AsyncAutocompleteProps, Autocomplete, type AutocompleteProps, type Code, CodesAutocomplete, type CodesAutocompleteProps, type OrgAutocompleteProps, type Organization, OrganizationAutocomplete, type Provider, ProviderAutocomplete, type ProviderAutocompleteProps, fetchCodes, fetchOrgs, fetchProviders, handleGetCodesOptionLabel, handleGetOrgOptionLabel, handleGetProviderOptionLabel };
|
package/dist/index.js
CHANGED
|
@@ -174,7 +174,8 @@ var AsyncAutocomplete = (_a) => {
|
|
|
174
174
|
watchParams,
|
|
175
175
|
debounceTimeout = 350,
|
|
176
176
|
FieldProps,
|
|
177
|
-
onInputChange
|
|
177
|
+
onInputChange,
|
|
178
|
+
prependOptions = []
|
|
178
179
|
} = _b, rest = __objRest(_b, [
|
|
179
180
|
"loadOptions",
|
|
180
181
|
"limit",
|
|
@@ -184,7 +185,8 @@ var AsyncAutocomplete = (_a) => {
|
|
|
184
185
|
"watchParams",
|
|
185
186
|
"debounceTimeout",
|
|
186
187
|
"FieldProps",
|
|
187
|
-
"onInputChange"
|
|
188
|
+
"onInputChange",
|
|
189
|
+
"prependOptions"
|
|
188
190
|
]);
|
|
189
191
|
const [inputValue, setInputValue] = (0, import_react3.useState)("");
|
|
190
192
|
const handleInputPropsOnChange = (event) => {
|
|
@@ -202,6 +204,14 @@ var AsyncAutocomplete = (_a) => {
|
|
|
202
204
|
getNextPageParam: (lastPage) => lastPage.hasMore ? lastPage.offset + limit : void 0
|
|
203
205
|
}, queryOptions));
|
|
204
206
|
const options = (data == null ? void 0 : data.pages) ? data.pages.map((page) => page.options).flat() : [];
|
|
207
|
+
const finalOptions = prependOptions.length > 0 ? [
|
|
208
|
+
...prependOptions,
|
|
209
|
+
...options.filter(
|
|
210
|
+
(option) => !prependOptions.some(
|
|
211
|
+
(prepended) => rest.isOptionEqualToValue ? rest.isOptionEqualToValue(option, prepended) : option === prepended
|
|
212
|
+
)
|
|
213
|
+
)
|
|
214
|
+
] : options;
|
|
205
215
|
const handleOnInputChange = (event, value, reason) => {
|
|
206
216
|
if (reason === "clear") {
|
|
207
217
|
setInputValue(event.target.value);
|
|
@@ -220,7 +230,7 @@ var AsyncAutocomplete = (_a) => {
|
|
|
220
230
|
})
|
|
221
231
|
}),
|
|
222
232
|
loading: isFetching,
|
|
223
|
-
options,
|
|
233
|
+
options: finalOptions,
|
|
224
234
|
ListboxProps: __spreadProps(__spreadValues({}, ListboxProps), {
|
|
225
235
|
onScroll: (event) => __async(null, null, function* () {
|
|
226
236
|
const listboxNode = event.currentTarget;
|
package/dist/index.mjs
CHANGED
|
@@ -132,7 +132,8 @@ var AsyncAutocomplete = (_a) => {
|
|
|
132
132
|
watchParams,
|
|
133
133
|
debounceTimeout = 350,
|
|
134
134
|
FieldProps,
|
|
135
|
-
onInputChange
|
|
135
|
+
onInputChange,
|
|
136
|
+
prependOptions = []
|
|
136
137
|
} = _b, rest = __objRest(_b, [
|
|
137
138
|
"loadOptions",
|
|
138
139
|
"limit",
|
|
@@ -142,7 +143,8 @@ var AsyncAutocomplete = (_a) => {
|
|
|
142
143
|
"watchParams",
|
|
143
144
|
"debounceTimeout",
|
|
144
145
|
"FieldProps",
|
|
145
|
-
"onInputChange"
|
|
146
|
+
"onInputChange",
|
|
147
|
+
"prependOptions"
|
|
146
148
|
]);
|
|
147
149
|
const [inputValue, setInputValue] = useState2("");
|
|
148
150
|
const handleInputPropsOnChange = (event) => {
|
|
@@ -160,6 +162,14 @@ var AsyncAutocomplete = (_a) => {
|
|
|
160
162
|
getNextPageParam: (lastPage) => lastPage.hasMore ? lastPage.offset + limit : void 0
|
|
161
163
|
}, queryOptions));
|
|
162
164
|
const options = (data == null ? void 0 : data.pages) ? data.pages.map((page) => page.options).flat() : [];
|
|
165
|
+
const finalOptions = prependOptions.length > 0 ? [
|
|
166
|
+
...prependOptions,
|
|
167
|
+
...options.filter(
|
|
168
|
+
(option) => !prependOptions.some(
|
|
169
|
+
(prepended) => rest.isOptionEqualToValue ? rest.isOptionEqualToValue(option, prepended) : option === prepended
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
] : options;
|
|
163
173
|
const handleOnInputChange = (event, value, reason) => {
|
|
164
174
|
if (reason === "clear") {
|
|
165
175
|
setInputValue(event.target.value);
|
|
@@ -178,7 +188,7 @@ var AsyncAutocomplete = (_a) => {
|
|
|
178
188
|
})
|
|
179
189
|
}),
|
|
180
190
|
loading: isFetching,
|
|
181
|
-
options,
|
|
191
|
+
options: finalOptions,
|
|
182
192
|
ListboxProps: __spreadProps(__spreadValues({}, ListboxProps), {
|
|
183
193
|
onScroll: (event) => __async(null, null, function* () {
|
|
184
194
|
const listboxNode = event.currentTarget;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@availity/mui-autocomplete",
|
|
3
|
-
"version": "2.0
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "Availity MUI Autocomplete Component - part of the @availity/element design system",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -45,10 +45,10 @@
|
|
|
45
45
|
"qs": "^6.14.0"
|
|
46
46
|
},
|
|
47
47
|
"devDependencies": {
|
|
48
|
-
"@availity/api-axios": "^
|
|
49
|
-
"@availity/mui-form-utils": "^2.0.
|
|
48
|
+
"@availity/api-axios": "^12.0.0",
|
|
49
|
+
"@availity/mui-form-utils": "^2.0.2",
|
|
50
50
|
"@availity/mui-icon": "^2.0.1",
|
|
51
|
-
"@availity/mui-textfield": "^2.0.
|
|
51
|
+
"@availity/mui-textfield": "^2.0.2",
|
|
52
52
|
"@mui/material": "^7.3.4",
|
|
53
53
|
"@tanstack/react-query": "^4.36.1",
|
|
54
54
|
"react": "19.2.0",
|
|
@@ -57,9 +57,9 @@
|
|
|
57
57
|
"typescript": "^5.4.5"
|
|
58
58
|
},
|
|
59
59
|
"peerDependencies": {
|
|
60
|
-
"@availity/api-axios": "^
|
|
61
|
-
"@availity/mui-form-utils": "^2.0.
|
|
62
|
-
"@availity/mui-textfield": "^2.0.
|
|
60
|
+
"@availity/api-axios": "^12.0.0",
|
|
61
|
+
"@availity/mui-form-utils": "^2.0.2",
|
|
62
|
+
"@availity/mui-textfield": "^2.0.2",
|
|
63
63
|
"@mui/material": "^7.0.0",
|
|
64
64
|
"@tanstack/react-query": "^4.36.1",
|
|
65
65
|
"react": ">=17.0.0"
|
|
@@ -103,6 +103,85 @@ describe('AsyncAutocomplete', () => {
|
|
|
103
103
|
});
|
|
104
104
|
});
|
|
105
105
|
|
|
106
|
+
test('prependedOptions should be available', async () => {
|
|
107
|
+
const client = new QueryClient();
|
|
108
|
+
|
|
109
|
+
render(
|
|
110
|
+
<QueryClientProvider client={client}>
|
|
111
|
+
<AsyncAutocomplete
|
|
112
|
+
queryKey="prepended-options"
|
|
113
|
+
prependOptions={[{ label: 'Option 0', value: 0 }]}
|
|
114
|
+
loadOptions={loadOptions}
|
|
115
|
+
FieldProps={{ label: 'Test' }}
|
|
116
|
+
/>
|
|
117
|
+
</QueryClientProvider>
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
const input = screen.getByRole('combobox');
|
|
121
|
+
fireEvent.click(input);
|
|
122
|
+
fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
123
|
+
|
|
124
|
+
waitFor(() => {
|
|
125
|
+
expect(screen.getByText('Option 0')).toBeDefined();
|
|
126
|
+
expect(screen.getByText('Option 1')).toBeDefined();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
fireEvent.click(await screen.findByText('Option 0'));
|
|
130
|
+
|
|
131
|
+
waitFor(() => {
|
|
132
|
+
expect(screen.getByText('Option 0')).toBeDefined();
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test('prependedOptions should not be duplicative', async () => {
|
|
137
|
+
const client = new QueryClient();
|
|
138
|
+
|
|
139
|
+
render(
|
|
140
|
+
<QueryClientProvider client={client}>
|
|
141
|
+
<AsyncAutocomplete
|
|
142
|
+
queryKey="prepended-options-unique"
|
|
143
|
+
prependOptions={[{ label: 'Option 1', value: 1 }]}
|
|
144
|
+
loadOptions={loadOptions}
|
|
145
|
+
FieldProps={{ label: 'Test' }}
|
|
146
|
+
/>
|
|
147
|
+
</QueryClientProvider>
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const input = screen.getByRole('combobox');
|
|
151
|
+
fireEvent.click(input);
|
|
152
|
+
fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
153
|
+
|
|
154
|
+
waitFor(() => {
|
|
155
|
+
expect(screen.getAllByText('Option 1').length).toBe(1);
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
test('should filter duplicates using custom isOptionEqualToValue', async () => {
|
|
160
|
+
const client = new QueryClient();
|
|
161
|
+
|
|
162
|
+
render(
|
|
163
|
+
<QueryClientProvider client={client}>
|
|
164
|
+
<AsyncAutocomplete
|
|
165
|
+
queryKey="test-duplicates"
|
|
166
|
+
prependOptions={[{ label: 'Option 1', value: 1 }]}
|
|
167
|
+
isOptionEqualToValue={(option, value) => option.value === value.value}
|
|
168
|
+
loadOptions={loadOptions}
|
|
169
|
+
FieldProps={{ label: 'Test' }}
|
|
170
|
+
/>
|
|
171
|
+
</QueryClientProvider>
|
|
172
|
+
);
|
|
173
|
+
|
|
174
|
+
const input = screen.getByRole('combobox');
|
|
175
|
+
fireEvent.click(input);
|
|
176
|
+
fireEvent.keyDown(input, { key: 'ArrowDown' });
|
|
177
|
+
|
|
178
|
+
await waitFor(() => {
|
|
179
|
+
expect(screen.getByText('Option 1')).toBeDefined();
|
|
180
|
+
expect(screen.getByText('Option 2')).toBeDefined();
|
|
181
|
+
expect(screen.getAllByText('Option 1')).toHaveLength(1);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
106
185
|
test('should call loadOptions when scroll to the bottom', async () => {
|
|
107
186
|
const client = new QueryClient();
|
|
108
187
|
|
|
@@ -33,6 +33,8 @@ export interface AsyncAutocompleteProps<
|
|
|
33
33
|
watchParams?: Record<string, unknown>;
|
|
34
34
|
/** Time to wait before searching with the input value typed into the component */
|
|
35
35
|
debounceTimeout?: number;
|
|
36
|
+
/** Options to prepend to the list (e.g., frequently used items). These will be filtered from loadOptions results to avoid duplicates. */
|
|
37
|
+
prependOptions?: Option[];
|
|
36
38
|
}
|
|
37
39
|
|
|
38
40
|
export const AsyncAutocomplete = <
|
|
@@ -51,6 +53,7 @@ export const AsyncAutocomplete = <
|
|
|
51
53
|
debounceTimeout = 350,
|
|
52
54
|
FieldProps,
|
|
53
55
|
onInputChange,
|
|
56
|
+
prependOptions = [],
|
|
54
57
|
...rest
|
|
55
58
|
}: AsyncAutocompleteProps<Option, Multiple, DisableClearable, FreeSolo, ChipComponent>) => {
|
|
56
59
|
const [inputValue, setInputValue] = useState('');
|
|
@@ -73,6 +76,19 @@ export const AsyncAutocomplete = <
|
|
|
73
76
|
|
|
74
77
|
const options = data?.pages ? data.pages.map((page) => page.options).flat() : [];
|
|
75
78
|
|
|
79
|
+
const finalOptions =
|
|
80
|
+
prependOptions.length > 0
|
|
81
|
+
? [
|
|
82
|
+
...prependOptions,
|
|
83
|
+
...options.filter(
|
|
84
|
+
(option) =>
|
|
85
|
+
!prependOptions.some((prepended) =>
|
|
86
|
+
rest.isOptionEqualToValue ? rest.isOptionEqualToValue(option, prepended) : option === prepended
|
|
87
|
+
)
|
|
88
|
+
),
|
|
89
|
+
]
|
|
90
|
+
: options;
|
|
91
|
+
|
|
76
92
|
const handleOnInputChange = (
|
|
77
93
|
event: React.ChangeEvent<HTMLInputElement>,
|
|
78
94
|
value: string,
|
|
@@ -99,7 +115,7 @@ export const AsyncAutocomplete = <
|
|
|
99
115
|
},
|
|
100
116
|
}}
|
|
101
117
|
loading={isFetching}
|
|
102
|
-
options={
|
|
118
|
+
options={finalOptions}
|
|
103
119
|
ListboxProps={{
|
|
104
120
|
...ListboxProps,
|
|
105
121
|
onScroll: async (event: React.SyntheticEvent) => {
|