@pushwoosh/dumb-components 1.1.142 → 1.1.143
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/Combobox/Combobox.js +44 -18
- package/Combobox/index.d.ts +1 -1
- package/Combobox/types.d.ts +12 -5
- package/ComboboxMulti/ComboboxMulti.d.ts +1 -1
- package/ComboboxMulti/ComboboxMulti.js +15 -6
- package/ComboboxMulti/types.d.ts +4 -3
- package/index.d.ts +1 -1
- package/package.json +2 -2
- package/shared/dropdownField/FieldShell.d.ts +4 -1
- package/shared/dropdownField/FieldShell.js +7 -0
- package/shared/dropdownField/SuggestionsDropdown.d.ts +5 -1
- package/shared/dropdownField/SuggestionsDropdown.js +23 -5
- package/shared/dropdownField/index.d.ts +2 -2
- package/shared/dropdownField/index.js +1 -1
- package/shared/dropdownField/shared.d.ts +3 -1
- package/shared/dropdownField/shared.js +3 -0
- package/shared/dropdownField/styles.d.ts +1 -0
- package/shared/dropdownField/styles.js +5 -1
- package/shared/dropdownField/types.d.ts +9 -1
- package/shared/dropdownField/useAsyncItems.d.ts +7 -2
- package/shared/dropdownField/useAsyncItems.js +52 -20
- package/shared/dropdownField/useDropdownItems.d.ts +7 -2
- package/shared/dropdownField/useDropdownItems.js +9 -3
- package/shared/dropdownField/useListNavigation.d.ts +2 -1
- package/shared/dropdownField/useListNavigation.js +11 -2
package/Combobox/Combobox.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useId, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { DEFAULT_DEBOUNCE_MS, FieldInput, FieldShell, defaultGetKey, useActiveIndex, useDropdownItems, useFieldOpenEffects, useListNavigation, useShellMouseDown } from '../shared/dropdownField';
|
|
3
|
+
import { DEFAULT_DEBOUNCE_MS, FieldInput, FieldShell, defaultGetKey, resolveDropdownText, useActiveIndex, useDropdownItems, useFieldOpenEffects, useListNavigation, useShellMouseDown } from '../shared/dropdownField';
|
|
4
4
|
function FreeCombobox({
|
|
5
5
|
items,
|
|
6
6
|
loadItems,
|
|
7
7
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
8
|
+
minChars,
|
|
8
9
|
value,
|
|
9
10
|
onChange,
|
|
10
11
|
onClose,
|
|
@@ -12,13 +13,14 @@ function FreeCombobox({
|
|
|
12
13
|
getLabel: getLabelProp,
|
|
13
14
|
filter,
|
|
14
15
|
renderItem,
|
|
15
|
-
|
|
16
|
+
emptyText,
|
|
17
|
+
loadingText,
|
|
16
18
|
placeholder,
|
|
17
19
|
disabled,
|
|
18
20
|
loading,
|
|
19
21
|
clearable,
|
|
20
22
|
autosize,
|
|
21
|
-
|
|
23
|
+
hasError,
|
|
22
24
|
width,
|
|
23
25
|
minWidth
|
|
24
26
|
}) {
|
|
@@ -29,11 +31,14 @@ function FreeCombobox({
|
|
|
29
31
|
const [isOpen, setIsOpen] = useState(false);
|
|
30
32
|
const {
|
|
31
33
|
filteredItems,
|
|
32
|
-
loading: asyncLoading
|
|
34
|
+
loading: asyncLoading,
|
|
35
|
+
loadingMore,
|
|
36
|
+
loadMore
|
|
33
37
|
} = useDropdownItems({
|
|
34
38
|
items,
|
|
35
39
|
loadItems,
|
|
36
40
|
debounceMs,
|
|
41
|
+
minChars,
|
|
37
42
|
getLabel,
|
|
38
43
|
filter,
|
|
39
44
|
query: value,
|
|
@@ -46,7 +51,9 @@ function FreeCombobox({
|
|
|
46
51
|
setActiveIndex(-1);
|
|
47
52
|
}, [setActiveIndex]);
|
|
48
53
|
const pick = useCallback(item => {
|
|
49
|
-
onChange(getLabel(item)
|
|
54
|
+
onChange(getLabel(item), {
|
|
55
|
+
source: 'select'
|
|
56
|
+
});
|
|
50
57
|
setIsOpen(false);
|
|
51
58
|
setActiveIndex(-1);
|
|
52
59
|
}, [onChange, getLabel, setActiveIndex]);
|
|
@@ -57,7 +64,8 @@ function FreeCombobox({
|
|
|
57
64
|
activeIndex,
|
|
58
65
|
setActiveIndex,
|
|
59
66
|
onSelectIndex: index => pick(filteredItems[index]),
|
|
60
|
-
onEscape: close
|
|
67
|
+
onEscape: close,
|
|
68
|
+
onReachEnd: loadMore
|
|
61
69
|
});
|
|
62
70
|
const onShellMouseDown = useShellMouseDown(inputRef, isOpen, open);
|
|
63
71
|
useFieldOpenEffects({
|
|
@@ -82,18 +90,22 @@ function FreeCombobox({
|
|
|
82
90
|
onSelect: () => pick(item)
|
|
83
91
|
};
|
|
84
92
|
}), [filteredItems, activeIndex, value, getLabel, renderItem, pick, baseId]);
|
|
85
|
-
const
|
|
93
|
+
const isLoading = loading || asyncLoading;
|
|
94
|
+
const hasSource = items !== undefined || loadItems !== undefined;
|
|
95
|
+
const dropdownVisible = isOpen && (filteredItems.length > 0 || isLoading || hasSource);
|
|
86
96
|
const activeDescendant = activeIndex >= 0 && activeIndex < filteredItems.length ? `${baseId}-opt-${filteredItems[activeIndex]}` : undefined;
|
|
87
97
|
const onInputChange = event => {
|
|
88
|
-
onChange(event.target.value
|
|
98
|
+
onChange(event.target.value, {
|
|
99
|
+
source: 'input'
|
|
100
|
+
});
|
|
89
101
|
if (!isOpen) open();
|
|
90
102
|
};
|
|
91
103
|
return _jsx(FieldShell, {
|
|
92
104
|
isOpen: isOpen,
|
|
93
105
|
dropdownOpen: dropdownVisible,
|
|
94
|
-
isErrored:
|
|
106
|
+
isErrored: hasError,
|
|
95
107
|
disabled: disabled,
|
|
96
|
-
loading:
|
|
108
|
+
loading: isLoading,
|
|
97
109
|
width: width,
|
|
98
110
|
minWidth: minWidth,
|
|
99
111
|
autosize: autosize,
|
|
@@ -102,11 +114,16 @@ function FreeCombobox({
|
|
|
102
114
|
showClear: !!(clearable && value),
|
|
103
115
|
onClear: () => {
|
|
104
116
|
var _inputRef$current;
|
|
105
|
-
onChange(''
|
|
117
|
+
onChange('', {
|
|
118
|
+
source: 'input'
|
|
119
|
+
});
|
|
106
120
|
(_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 || _inputRef$current.focus();
|
|
107
121
|
},
|
|
108
122
|
dropdownItems: dropdownItems,
|
|
109
|
-
emptyText:
|
|
123
|
+
emptyText: resolveDropdownText(emptyText, value),
|
|
124
|
+
loadingText: resolveDropdownText(loadingText, value),
|
|
125
|
+
loadingMore: loadingMore,
|
|
126
|
+
onLoadMore: loadMore,
|
|
110
127
|
listboxId: listboxId,
|
|
111
128
|
children: _jsx(FieldInput, {
|
|
112
129
|
ref: inputRef,
|
|
@@ -129,6 +146,7 @@ function SelectCombobox({
|
|
|
129
146
|
items,
|
|
130
147
|
loadItems,
|
|
131
148
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
149
|
+
minChars,
|
|
132
150
|
value,
|
|
133
151
|
onChange,
|
|
134
152
|
onClose,
|
|
@@ -137,13 +155,14 @@ function SelectCombobox({
|
|
|
137
155
|
getKey: getKeyProp,
|
|
138
156
|
filter,
|
|
139
157
|
renderItem,
|
|
140
|
-
|
|
158
|
+
emptyText,
|
|
159
|
+
loadingText,
|
|
141
160
|
placeholder,
|
|
142
161
|
disabled,
|
|
143
162
|
loading,
|
|
144
163
|
clearable,
|
|
145
164
|
autosize,
|
|
146
|
-
|
|
165
|
+
hasError,
|
|
147
166
|
width,
|
|
148
167
|
minWidth
|
|
149
168
|
}) {
|
|
@@ -157,11 +176,14 @@ function SelectCombobox({
|
|
|
157
176
|
const {
|
|
158
177
|
sourceItems,
|
|
159
178
|
filteredItems,
|
|
160
|
-
loading: asyncLoading
|
|
179
|
+
loading: asyncLoading,
|
|
180
|
+
loadingMore,
|
|
181
|
+
loadMore
|
|
161
182
|
} = useDropdownItems({
|
|
162
183
|
items,
|
|
163
184
|
loadItems,
|
|
164
185
|
debounceMs,
|
|
186
|
+
minChars,
|
|
165
187
|
getLabel,
|
|
166
188
|
filter,
|
|
167
189
|
query,
|
|
@@ -198,7 +220,8 @@ function SelectCombobox({
|
|
|
198
220
|
activeIndex,
|
|
199
221
|
setActiveIndex,
|
|
200
222
|
onSelectIndex: index => commit(filteredItems[index]),
|
|
201
|
-
onEscape: close
|
|
223
|
+
onEscape: close,
|
|
224
|
+
onReachEnd: loadMore
|
|
202
225
|
});
|
|
203
226
|
const onShellMouseDown = useShellMouseDown(inputRef, isOpen, open);
|
|
204
227
|
useFieldOpenEffects({
|
|
@@ -228,7 +251,7 @@ function SelectCombobox({
|
|
|
228
251
|
return _jsx(FieldShell, {
|
|
229
252
|
isOpen: isOpen,
|
|
230
253
|
dropdownOpen: isOpen,
|
|
231
|
-
isErrored:
|
|
254
|
+
isErrored: hasError,
|
|
232
255
|
disabled: disabled,
|
|
233
256
|
loading: loading || asyncLoading,
|
|
234
257
|
width: width,
|
|
@@ -243,7 +266,10 @@ function SelectCombobox({
|
|
|
243
266
|
(_inputRef$current3 = inputRef.current) === null || _inputRef$current3 === void 0 || _inputRef$current3.focus();
|
|
244
267
|
},
|
|
245
268
|
dropdownItems: dropdownItems,
|
|
246
|
-
emptyText:
|
|
269
|
+
emptyText: resolveDropdownText(emptyText, query),
|
|
270
|
+
loadingText: resolveDropdownText(loadingText, query),
|
|
271
|
+
loadingMore: loadingMore,
|
|
272
|
+
onLoadMore: loadMore,
|
|
247
273
|
listboxId: listboxId,
|
|
248
274
|
children: _jsx(FieldInput, {
|
|
249
275
|
ref: inputRef,
|
package/Combobox/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { Combobox } from './Combobox';
|
|
2
|
-
export type { ComboboxProps, FreeComboboxProps, SelectComboboxProps, } from './types';
|
|
2
|
+
export type { ComboboxProps, ComboboxChangeSource, ComboboxChangeMeta, FreeComboboxProps, SelectComboboxProps, } from './types';
|
package/Combobox/types.d.ts
CHANGED
|
@@ -1,18 +1,25 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { GetKeyProp, ItemState } from '../shared/dropdownField';
|
|
2
|
+
import type { DropdownText, GetKeyProp, ItemState, LoadItems } from '../shared/dropdownField';
|
|
3
3
|
type ComboboxSource<T> = {
|
|
4
4
|
items?: T[];
|
|
5
5
|
loadItems?: never;
|
|
6
6
|
debounceMs?: never;
|
|
7
|
+
minChars?: never;
|
|
7
8
|
} | {
|
|
8
9
|
items?: never;
|
|
9
|
-
loadItems:
|
|
10
|
+
loadItems: LoadItems<T>;
|
|
10
11
|
debounceMs?: number;
|
|
12
|
+
minChars?: number;
|
|
13
|
+
};
|
|
14
|
+
export type ComboboxChangeSource = 'input' | 'select';
|
|
15
|
+
export type ComboboxChangeMeta = {
|
|
16
|
+
source: ComboboxChangeSource;
|
|
11
17
|
};
|
|
12
18
|
type CommonProps<T> = {
|
|
13
19
|
filter?: (item: T, query: string) => boolean;
|
|
14
20
|
renderItem?: (item: T, state: ItemState) => ReactNode;
|
|
15
|
-
|
|
21
|
+
emptyText?: DropdownText;
|
|
22
|
+
loadingText?: DropdownText;
|
|
16
23
|
onClose?: () => void;
|
|
17
24
|
autoFocus?: boolean;
|
|
18
25
|
placeholder?: string;
|
|
@@ -20,14 +27,14 @@ type CommonProps<T> = {
|
|
|
20
27
|
loading?: boolean;
|
|
21
28
|
clearable?: boolean;
|
|
22
29
|
autosize?: boolean;
|
|
23
|
-
|
|
30
|
+
hasError?: boolean;
|
|
24
31
|
width?: string;
|
|
25
32
|
minWidth?: string;
|
|
26
33
|
};
|
|
27
34
|
export type FreeComboboxProps = ComboboxSource<string> & CommonProps<string> & {
|
|
28
35
|
select?: false;
|
|
29
36
|
value: string;
|
|
30
|
-
onChange: (value: string) => void;
|
|
37
|
+
onChange: (value: string, meta: ComboboxChangeMeta) => void;
|
|
31
38
|
getLabel?: (item: string) => string;
|
|
32
39
|
};
|
|
33
40
|
export type SelectComboboxProps<T> = ComboboxSource<T> & GetKeyProp<T> & CommonProps<T> & {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { type ReactElement } from 'react';
|
|
2
2
|
import { type ComboboxMultiProps } from './types';
|
|
3
|
-
export declare function ComboboxMulti<T>({ items, loadItems, debounceMs, value, onChange, onClose, autoFocus, getLabel, getKey: getKeyProp, filter, renderItem,
|
|
3
|
+
export declare function ComboboxMulti<T>({ items, loadItems, debounceMs, minChars, value, onChange, onClose, autoFocus, getLabel, getKey: getKeyProp, filter, renderItem, emptyText, loadingText, creatable, onCreate, canCreate, renderCreateLabel, maxValues, placeholder, disabled, loading, clearable, autosize, hasError, width, minWidth, }: ComboboxMultiProps<T>): ReactElement;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useCallback, useId, useMemo, useRef, useState } from 'react';
|
|
3
3
|
import { Chip } from '../Chip';
|
|
4
|
-
import { DEFAULT_DEBOUNCE_MS, FieldInput, FieldShell, defaultGetKey, useActiveIndex, useDropdownItems, useFieldOpenEffects, useListNavigation, useShellMouseDown } from '../shared/dropdownField';
|
|
4
|
+
import { DEFAULT_DEBOUNCE_MS, FieldInput, FieldShell, defaultGetKey, resolveDropdownText, useActiveIndex, useDropdownItems, useFieldOpenEffects, useListNavigation, useShellMouseDown } from '../shared/dropdownField';
|
|
5
5
|
function defaultCanCreate(query, items, getLabel) {
|
|
6
6
|
const trimmed = query.trim();
|
|
7
7
|
if (!trimmed) return false;
|
|
@@ -12,6 +12,7 @@ export function ComboboxMulti({
|
|
|
12
12
|
items,
|
|
13
13
|
loadItems,
|
|
14
14
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
15
|
+
minChars,
|
|
15
16
|
value,
|
|
16
17
|
onChange,
|
|
17
18
|
onClose,
|
|
@@ -20,7 +21,8 @@ export function ComboboxMulti({
|
|
|
20
21
|
getKey: getKeyProp,
|
|
21
22
|
filter,
|
|
22
23
|
renderItem,
|
|
23
|
-
|
|
24
|
+
emptyText,
|
|
25
|
+
loadingText,
|
|
24
26
|
creatable,
|
|
25
27
|
onCreate,
|
|
26
28
|
canCreate,
|
|
@@ -31,7 +33,7 @@ export function ComboboxMulti({
|
|
|
31
33
|
loading,
|
|
32
34
|
clearable,
|
|
33
35
|
autosize,
|
|
34
|
-
|
|
36
|
+
hasError,
|
|
35
37
|
width,
|
|
36
38
|
minWidth
|
|
37
39
|
}) {
|
|
@@ -48,12 +50,15 @@ export function ComboboxMulti({
|
|
|
48
50
|
const {
|
|
49
51
|
sourceItems,
|
|
50
52
|
filteredItems,
|
|
51
|
-
loading: asyncLoading
|
|
53
|
+
loading: asyncLoading,
|
|
54
|
+
loadingMore,
|
|
55
|
+
loadMore
|
|
52
56
|
} = useDropdownItems({
|
|
53
57
|
items,
|
|
54
58
|
loadItems,
|
|
55
59
|
localItems: createdItems,
|
|
56
60
|
debounceMs,
|
|
61
|
+
minChars,
|
|
57
62
|
getLabel,
|
|
58
63
|
filter,
|
|
59
64
|
query,
|
|
@@ -103,6 +108,7 @@ export function ComboboxMulti({
|
|
|
103
108
|
setActiveIndex,
|
|
104
109
|
onSelectIndex: index => toggle(visibleItems[index]),
|
|
105
110
|
onEscape: close,
|
|
111
|
+
onReachEnd: loadMore,
|
|
106
112
|
hasExtraRow: canCreateNow,
|
|
107
113
|
onSelectExtra: create,
|
|
108
114
|
isQueryEmpty: !query && value.length > 0,
|
|
@@ -155,7 +161,7 @@ export function ComboboxMulti({
|
|
|
155
161
|
return _jsxs(FieldShell, {
|
|
156
162
|
isOpen: isOpen,
|
|
157
163
|
dropdownOpen: isOpen,
|
|
158
|
-
isErrored:
|
|
164
|
+
isErrored: hasError,
|
|
159
165
|
disabled: disabled,
|
|
160
166
|
loading: loading || asyncLoading,
|
|
161
167
|
width: width,
|
|
@@ -170,7 +176,10 @@ export function ComboboxMulti({
|
|
|
170
176
|
showChevron: true,
|
|
171
177
|
onToggle: toggleOpen,
|
|
172
178
|
dropdownItems: dropdownItems,
|
|
173
|
-
emptyText:
|
|
179
|
+
emptyText: resolveDropdownText(emptyText, query),
|
|
180
|
+
loadingText: resolveDropdownText(loadingText, query),
|
|
181
|
+
loadingMore: loadingMore,
|
|
182
|
+
onLoadMore: loadMore,
|
|
174
183
|
createLabel: createLabel,
|
|
175
184
|
createActive: createActive,
|
|
176
185
|
onCreate: create,
|
package/ComboboxMulti/types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import type { GetKeyProp, ItemState, ItemsSource } from '../shared/dropdownField';
|
|
2
|
+
import type { DropdownText, GetKeyProp, ItemState, ItemsSource } from '../shared/dropdownField';
|
|
3
3
|
type CreatableProp<T> = [T] extends [string] ? {
|
|
4
4
|
creatable?: boolean;
|
|
5
5
|
onCreate?: (query: string) => T;
|
|
@@ -18,7 +18,8 @@ export type ComboboxMultiProps<T> = ItemsSource<T> & GetKeyProp<T> & CreatablePr
|
|
|
18
18
|
getLabel: (item: T) => string;
|
|
19
19
|
filter?: (item: T, query: string) => boolean;
|
|
20
20
|
renderItem?: (item: T, state: ItemState) => ReactNode;
|
|
21
|
-
|
|
21
|
+
emptyText?: DropdownText;
|
|
22
|
+
loadingText?: DropdownText;
|
|
22
23
|
canCreate?: (query: string, items: T[]) => boolean;
|
|
23
24
|
renderCreateLabel?: (query: string) => ReactNode;
|
|
24
25
|
maxValues?: number;
|
|
@@ -27,7 +28,7 @@ export type ComboboxMultiProps<T> = ItemsSource<T> & GetKeyProp<T> & CreatablePr
|
|
|
27
28
|
loading?: boolean;
|
|
28
29
|
clearable?: boolean;
|
|
29
30
|
autosize?: boolean;
|
|
30
|
-
|
|
31
|
+
hasError?: boolean;
|
|
31
32
|
width?: string;
|
|
32
33
|
minWidth?: string;
|
|
33
34
|
};
|
package/index.d.ts
CHANGED
|
@@ -22,7 +22,7 @@ export { ReCaptcha, useRecaptcha, asyncScriptLoad } from './ReCaptcha';
|
|
|
22
22
|
export { Spinner } from './Spinner';
|
|
23
23
|
export { SortButton, type SortButtonParams } from './SortButton';
|
|
24
24
|
export { Select, SelectAsync, CreatableSelect, SelectComponents, CLASS_NAME_PREFIX, type SelectBase, type SelectOption, type MultiSelectOptions, type SingleValue, type MultiValue, } from './Select';
|
|
25
|
-
export { Combobox, type ComboboxProps, type FreeComboboxProps, type SelectComboboxProps, } from './Combobox';
|
|
25
|
+
export { Combobox, type ComboboxProps, type ComboboxChangeSource, type ComboboxChangeMeta, type FreeComboboxProps, type SelectComboboxProps, } from './Combobox';
|
|
26
26
|
export { ComboboxMulti, type ComboboxMultiProps } from './ComboboxMulti';
|
|
27
27
|
export { Switch } from './Switch';
|
|
28
28
|
export { TextSkeleton, RectangularSkeleton, CircularSkeleton } from './Skeleton';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pushwoosh/dumb-components",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.143",
|
|
4
4
|
"description": "React components to build Pushwoosh products",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"module": "index.js",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"@types/react": "^18.2.69",
|
|
32
32
|
"@types/react-dom": "^18.2.22",
|
|
33
33
|
"@types/react-transition-group": "^4.4.12",
|
|
34
|
-
"@types/styled-components": "^5.1.
|
|
34
|
+
"@types/styled-components": "^5.1.36",
|
|
35
35
|
"glob": "^11.0.3",
|
|
36
36
|
"jest": "^30.2.0",
|
|
37
37
|
"jest-environment-jsdom": "^30.2.0",
|
|
@@ -20,11 +20,14 @@ type FieldShellProps = {
|
|
|
20
20
|
onToggle?: () => void;
|
|
21
21
|
dropdownItems: DropdownItemDescriptor[];
|
|
22
22
|
emptyText?: ReactNode;
|
|
23
|
+
loadingText?: ReactNode;
|
|
24
|
+
loadingMore?: boolean;
|
|
25
|
+
onLoadMore?: () => void;
|
|
23
26
|
createLabel?: ReactNode;
|
|
24
27
|
createActive?: boolean;
|
|
25
28
|
onCreate?: () => void;
|
|
26
29
|
listboxId?: string;
|
|
27
30
|
createId?: string;
|
|
28
31
|
};
|
|
29
|
-
export declare function FieldShell({ children, isOpen, dropdownOpen, isErrored, disabled, loading, width, minWidth, autosize, tightLeft, onShellMouseDown, onClose, showClear, onClear, clearLabel, showChevron, onToggle, dropdownItems, emptyText, createLabel, createActive, onCreate, listboxId, createId, }: FieldShellProps): ReactElement;
|
|
32
|
+
export declare function FieldShell({ children, isOpen, dropdownOpen, isErrored, disabled, loading, width, minWidth, autosize, tightLeft, onShellMouseDown, onClose, showClear, onClear, clearLabel, showChevron, onToggle, dropdownItems, emptyText, loadingText, loadingMore, onLoadMore, createLabel, createActive, onCreate, listboxId, createId, }: FieldShellProps): ReactElement;
|
|
30
33
|
export {};
|
|
@@ -24,6 +24,9 @@ export function FieldShell({
|
|
|
24
24
|
onToggle,
|
|
25
25
|
dropdownItems,
|
|
26
26
|
emptyText,
|
|
27
|
+
loadingText,
|
|
28
|
+
loadingMore,
|
|
29
|
+
onLoadMore,
|
|
27
30
|
createLabel,
|
|
28
31
|
createActive,
|
|
29
32
|
onCreate,
|
|
@@ -99,6 +102,10 @@ export function FieldShell({
|
|
|
99
102
|
floatingStyles: floatingStyles,
|
|
100
103
|
items: dropdownItems,
|
|
101
104
|
emptyText: emptyText,
|
|
105
|
+
loading: loading,
|
|
106
|
+
loadingText: loadingText,
|
|
107
|
+
loadingMore: loadingMore,
|
|
108
|
+
onLoadMore: onLoadMore,
|
|
102
109
|
createLabel: createLabel,
|
|
103
110
|
createActive: createActive,
|
|
104
111
|
onCreate: onCreate,
|
|
@@ -5,6 +5,10 @@ type SuggestionsDropdownProps = {
|
|
|
5
5
|
floatingStyles: CSSProperties;
|
|
6
6
|
items: DropdownItemDescriptor[];
|
|
7
7
|
emptyText?: ReactNode;
|
|
8
|
+
loading?: boolean;
|
|
9
|
+
loadingText?: ReactNode;
|
|
10
|
+
loadingMore?: boolean;
|
|
11
|
+
onLoadMore?: () => void;
|
|
8
12
|
createLabel?: ReactNode;
|
|
9
13
|
createActive?: boolean;
|
|
10
14
|
onCreate?: () => void;
|
|
@@ -12,5 +16,5 @@ type SuggestionsDropdownProps = {
|
|
|
12
16
|
createId?: string;
|
|
13
17
|
zIndex?: number;
|
|
14
18
|
};
|
|
15
|
-
export declare function SuggestionsDropdown({ floatingRef, floatingStyles, items, emptyText, createLabel, createActive, onCreate, listboxId, createId, zIndex, }: SuggestionsDropdownProps): ReactElement | null;
|
|
19
|
+
export declare function SuggestionsDropdown({ floatingRef, floatingStyles, items, emptyText, loading, loadingText, loadingMore, onLoadMore, createLabel, createActive, onCreate, listboxId, createId, zIndex, }: SuggestionsDropdownProps): ReactElement | null;
|
|
16
20
|
export {};
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
import { createPortal } from 'react-dom';
|
|
4
|
-
import { CreateItemLabel, Dropdown, DropdownEmpty, DropdownItem } from './styles';
|
|
4
|
+
import { CreateItemLabel, Dropdown, DropdownEmpty, DropdownItem, DropdownLoadingMore } from './styles';
|
|
5
|
+
import { Spinner } from '../../Spinner';
|
|
6
|
+
const LOAD_MORE_THRESHOLD = 24;
|
|
5
7
|
const CREATE_KEY = '__create__';
|
|
6
8
|
export function SuggestionsDropdown({
|
|
7
9
|
floatingRef,
|
|
8
10
|
floatingStyles,
|
|
9
11
|
items,
|
|
10
12
|
emptyText = 'No options',
|
|
13
|
+
loading,
|
|
14
|
+
loadingText = 'Loading…',
|
|
15
|
+
loadingMore,
|
|
16
|
+
onLoadMore,
|
|
11
17
|
createLabel,
|
|
12
18
|
createActive,
|
|
13
19
|
onCreate,
|
|
@@ -16,6 +22,11 @@ export function SuggestionsDropdown({
|
|
|
16
22
|
zIndex
|
|
17
23
|
}) {
|
|
18
24
|
const activeItemRef = useRef(null);
|
|
25
|
+
const onScroll = event => {
|
|
26
|
+
if (!onLoadMore) return;
|
|
27
|
+
const el = event.currentTarget;
|
|
28
|
+
if (el.scrollHeight - el.scrollTop - el.clientHeight <= LOAD_MORE_THRESHOLD) onLoadMore();
|
|
29
|
+
};
|
|
19
30
|
const activeItem = items.find(item => item.active);
|
|
20
31
|
const activeKey = createActive ? CREATE_KEY : (activeItem === null || activeItem === void 0 ? void 0 : activeItem.key) ?? null;
|
|
21
32
|
useEffect(() => {
|
|
@@ -26,7 +37,7 @@ export function SuggestionsDropdown({
|
|
|
26
37
|
});
|
|
27
38
|
}, [activeKey]);
|
|
28
39
|
if (typeof document === 'undefined') return null;
|
|
29
|
-
const isEmpty = items.length === 0 && !createLabel;
|
|
40
|
+
const isEmpty = !loading && items.length === 0 && !createLabel;
|
|
30
41
|
return createPortal(_jsxs(Dropdown, {
|
|
31
42
|
ref: floatingRef,
|
|
32
43
|
style: {
|
|
@@ -35,7 +46,10 @@ export function SuggestionsDropdown({
|
|
|
35
46
|
},
|
|
36
47
|
id: listboxId,
|
|
37
48
|
role: "listbox",
|
|
38
|
-
|
|
49
|
+
onScroll: onScroll,
|
|
50
|
+
children: [loading && _jsx(DropdownEmpty, {
|
|
51
|
+
children: loadingText
|
|
52
|
+
}), !loading && createLabel && _jsx(DropdownItem, {
|
|
39
53
|
ref: createActive ? activeItemRef : undefined,
|
|
40
54
|
id: createId,
|
|
41
55
|
role: "option",
|
|
@@ -48,7 +62,7 @@ export function SuggestionsDropdown({
|
|
|
48
62
|
children: _jsx(CreateItemLabel, {
|
|
49
63
|
children: createLabel
|
|
50
64
|
})
|
|
51
|
-
}), items.map(item => _jsx(DropdownItem, {
|
|
65
|
+
}), !loading && items.map(item => _jsx(DropdownItem, {
|
|
52
66
|
ref: item.active ? activeItemRef : undefined,
|
|
53
67
|
id: item.id,
|
|
54
68
|
role: "option",
|
|
@@ -61,7 +75,11 @@ export function SuggestionsDropdown({
|
|
|
61
75
|
(_item$onSelect = item.onSelect) === null || _item$onSelect === void 0 || _item$onSelect.call(item);
|
|
62
76
|
},
|
|
63
77
|
children: item.label
|
|
64
|
-
}, item.key)),
|
|
78
|
+
}, item.key)), !loading && loadingMore && _jsx(DropdownLoadingMore, {
|
|
79
|
+
children: _jsx(Spinner, {
|
|
80
|
+
size: "small"
|
|
81
|
+
})
|
|
82
|
+
}), isEmpty && _jsx(DropdownEmpty, {
|
|
65
83
|
children: emptyText
|
|
66
84
|
})]
|
|
67
85
|
}), document.body);
|
|
@@ -8,6 +8,6 @@ export { useDropdownItems } from './useDropdownItems';
|
|
|
8
8
|
export { useActiveIndex } from './useActiveIndex';
|
|
9
9
|
export { useFieldOpenEffects } from './useFieldOpenEffects';
|
|
10
10
|
export { useListNavigation } from './useListNavigation';
|
|
11
|
-
export { defaultGetKey, defaultLabelFilter, useShellMouseDown } from './shared';
|
|
11
|
+
export { defaultGetKey, defaultLabelFilter, resolveDropdownText, useShellMouseDown, } from './shared';
|
|
12
12
|
export { DEFAULT_DEBOUNCE_MS } from './constants';
|
|
13
|
-
export type { ItemState, DropdownItemDescriptor, GetKeyProp, ItemsSource, } from './types';
|
|
13
|
+
export type { ItemState, DropdownItemDescriptor, DropdownText, GetKeyProp, ItemsSource, LoadItems, LoadItemsResult, } from './types';
|
|
@@ -8,5 +8,5 @@ export { useDropdownItems } from './useDropdownItems';
|
|
|
8
8
|
export { useActiveIndex } from './useActiveIndex';
|
|
9
9
|
export { useFieldOpenEffects } from './useFieldOpenEffects';
|
|
10
10
|
export { useListNavigation } from './useListNavigation';
|
|
11
|
-
export { defaultGetKey, defaultLabelFilter, useShellMouseDown } from './shared';
|
|
11
|
+
export { defaultGetKey, defaultLabelFilter, resolveDropdownText, useShellMouseDown } from './shared';
|
|
12
12
|
export { DEFAULT_DEBOUNCE_MS } from './constants';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { type MouseEvent, type RefObject } from 'react';
|
|
1
|
+
import { type MouseEvent, type ReactNode, type RefObject } from 'react';
|
|
2
|
+
import { type DropdownText } from './types';
|
|
3
|
+
export declare function resolveDropdownText(text: DropdownText, query: string): ReactNode;
|
|
2
4
|
export declare function defaultGetKey<T>(item: T): string | number;
|
|
3
5
|
export declare function defaultLabelFilter<T>(item: T, query: string, getLabel: (item: T) => string): boolean;
|
|
4
6
|
export declare function useShellMouseDown(inputRef: RefObject<HTMLInputElement>, isOpen: boolean, open: () => void): (event: MouseEvent<HTMLDivElement>) => void;
|
|
@@ -21,4 +21,5 @@ export declare const DropdownItem: import("styled-components").StyledComponent<"
|
|
|
21
21
|
$selected?: boolean;
|
|
22
22
|
}, never>;
|
|
23
23
|
export declare const DropdownEmpty: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
24
|
+
export declare const DropdownLoadingMore: import("styled-components").StyledComponent<"div", any, {}, never>;
|
|
24
25
|
export declare const CreateItemLabel: import("styled-components").StyledComponent<"span", any, {}, never>;
|
|
@@ -75,7 +75,11 @@ export const DropdownEmpty = styled.div.withConfig({
|
|
|
75
75
|
displayName: "DropdownEmpty",
|
|
76
76
|
componentId: "sc-1pvwhhw-8"
|
|
77
77
|
})(["padding:6px 12px;", ";color:", ";"], textBase, Color.PHANTOM);
|
|
78
|
+
export const DropdownLoadingMore = styled.div.withConfig({
|
|
79
|
+
displayName: "DropdownLoadingMore",
|
|
80
|
+
componentId: "sc-1pvwhhw-9"
|
|
81
|
+
})(["display:flex;align-items:center;justify-content:center;padding:8px 12px;"]);
|
|
78
82
|
export const CreateItemLabel = styled.span.withConfig({
|
|
79
83
|
displayName: "CreateItemLabel",
|
|
80
|
-
componentId: "sc-1pvwhhw-
|
|
84
|
+
componentId: "sc-1pvwhhw-10"
|
|
81
85
|
})(["color:", ";"], Color.PRIMARY);
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
+
export type DropdownText = ReactNode | ((query: string) => ReactNode);
|
|
2
3
|
export type ItemState = {
|
|
3
4
|
selected: boolean;
|
|
4
5
|
active: boolean;
|
|
@@ -8,14 +9,21 @@ export type GetKeyProp<T> = [T] extends [string | number] ? {
|
|
|
8
9
|
} : {
|
|
9
10
|
getKey: (item: T) => string | number;
|
|
10
11
|
};
|
|
12
|
+
export type LoadItemsResult<T> = {
|
|
13
|
+
items: T[];
|
|
14
|
+
hasMore?: boolean;
|
|
15
|
+
};
|
|
16
|
+
export type LoadItems<T> = (query: string, page: number) => Promise<LoadItemsResult<T>>;
|
|
11
17
|
export type ItemsSource<T> = {
|
|
12
18
|
items: T[];
|
|
13
19
|
loadItems?: never;
|
|
14
20
|
debounceMs?: never;
|
|
21
|
+
minChars?: never;
|
|
15
22
|
} | {
|
|
16
23
|
items?: never;
|
|
17
|
-
loadItems:
|
|
24
|
+
loadItems: LoadItems<T>;
|
|
18
25
|
debounceMs?: number;
|
|
26
|
+
minChars?: number;
|
|
19
27
|
};
|
|
20
28
|
export type DropdownItemDescriptor = {
|
|
21
29
|
key: string | number;
|
|
@@ -1,11 +1,16 @@
|
|
|
1
|
+
import { type LoadItems } from './types';
|
|
1
2
|
type Args<T> = {
|
|
2
|
-
loadItems?:
|
|
3
|
+
loadItems?: LoadItems<T>;
|
|
3
4
|
query: string;
|
|
4
5
|
isOpen: boolean;
|
|
5
6
|
debounceMs?: number;
|
|
7
|
+
minChars?: number;
|
|
6
8
|
};
|
|
7
|
-
|
|
9
|
+
type Result<T> = {
|
|
8
10
|
items: T[];
|
|
9
11
|
loading: boolean;
|
|
12
|
+
loadingMore: boolean;
|
|
13
|
+
loadMore: () => void;
|
|
10
14
|
};
|
|
15
|
+
export declare function useAsyncItems<T>({ loadItems, query, isOpen, debounceMs, minChars, }: Args<T>): Result<T>;
|
|
11
16
|
export {};
|
|
@@ -1,46 +1,78 @@
|
|
|
1
|
-
import { useEffect, useRef, useState } from 'react';
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { DEFAULT_DEBOUNCE_MS } from './constants';
|
|
3
3
|
import { useDebouncedValue } from './useDebouncedValue';
|
|
4
4
|
export function useAsyncItems({
|
|
5
5
|
loadItems,
|
|
6
6
|
query,
|
|
7
7
|
isOpen,
|
|
8
|
-
debounceMs = DEFAULT_DEBOUNCE_MS
|
|
8
|
+
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
9
|
+
minChars = 0
|
|
9
10
|
}) {
|
|
10
11
|
const [items, setItems] = useState([]);
|
|
11
12
|
const [loading, setLoading] = useState(false);
|
|
13
|
+
const [loadingMore, setLoadingMore] = useState(false);
|
|
12
14
|
const debouncedQuery = useDebouncedValue(query, debounceMs);
|
|
13
15
|
const loadItemsRef = useRef(loadItems);
|
|
14
16
|
loadItemsRef.current = loadItems;
|
|
15
|
-
const
|
|
17
|
+
const sessionRef = useRef(0);
|
|
18
|
+
const pageRef = useRef(0);
|
|
19
|
+
const queryRef = useRef('');
|
|
20
|
+
const loadingRef = useRef(false);
|
|
21
|
+
const hasMoreRef = useRef(false);
|
|
16
22
|
useEffect(() => {
|
|
17
23
|
const loader = loadItemsRef.current;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
24
|
+
const belowMin = debouncedQuery.trim().length < minChars;
|
|
25
|
+
sessionRef.current += 1;
|
|
26
|
+
pageRef.current = 0;
|
|
27
|
+
loadingRef.current = false;
|
|
28
|
+
hasMoreRef.current = false;
|
|
29
|
+
setLoadingMore(false);
|
|
30
|
+
if (!loader || !isOpen || belowMin) {
|
|
23
31
|
setLoading(false);
|
|
32
|
+
if (!loader || belowMin) setItems([]);
|
|
24
33
|
return undefined;
|
|
25
34
|
}
|
|
26
|
-
|
|
35
|
+
const session = sessionRef.current;
|
|
36
|
+
queryRef.current = debouncedQuery;
|
|
37
|
+
loadingRef.current = true;
|
|
27
38
|
setLoading(true);
|
|
28
|
-
Promise.resolve(loader(debouncedQuery)).then(result => {
|
|
29
|
-
if (
|
|
30
|
-
|
|
31
|
-
|
|
39
|
+
Promise.resolve(loader(debouncedQuery, 0)).then(result => {
|
|
40
|
+
if (session !== sessionRef.current) return;
|
|
41
|
+
setItems(result.items);
|
|
42
|
+
hasMoreRef.current = result.hasMore ?? false;
|
|
43
|
+
loadingRef.current = false;
|
|
32
44
|
setLoading(false);
|
|
33
45
|
}).catch(() => {
|
|
34
|
-
if (
|
|
46
|
+
if (session !== sessionRef.current) return;
|
|
47
|
+
loadingRef.current = false;
|
|
35
48
|
setLoading(false);
|
|
36
49
|
});
|
|
37
|
-
return
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
50
|
+
return undefined;
|
|
51
|
+
}, [debouncedQuery, isOpen, minChars]);
|
|
52
|
+
const loadMore = useCallback(() => {
|
|
53
|
+
const loader = loadItemsRef.current;
|
|
54
|
+
if (!loader || loadingRef.current || !hasMoreRef.current) return;
|
|
55
|
+
const session = sessionRef.current;
|
|
56
|
+
const nextPage = pageRef.current + 1;
|
|
57
|
+
loadingRef.current = true;
|
|
58
|
+
setLoadingMore(true);
|
|
59
|
+
Promise.resolve(loader(queryRef.current, nextPage)).then(result => {
|
|
60
|
+
if (session !== sessionRef.current) return;
|
|
61
|
+
pageRef.current = nextPage;
|
|
62
|
+
setItems(prev => [...prev, ...result.items]);
|
|
63
|
+
hasMoreRef.current = result.hasMore ?? false;
|
|
64
|
+
loadingRef.current = false;
|
|
65
|
+
setLoadingMore(false);
|
|
66
|
+
}).catch(() => {
|
|
67
|
+
if (session !== sessionRef.current) return;
|
|
68
|
+
loadingRef.current = false;
|
|
69
|
+
setLoadingMore(false);
|
|
70
|
+
});
|
|
71
|
+
}, []);
|
|
42
72
|
return {
|
|
43
73
|
items,
|
|
44
|
-
loading
|
|
74
|
+
loading,
|
|
75
|
+
loadingMore,
|
|
76
|
+
loadMore
|
|
45
77
|
};
|
|
46
78
|
}
|
|
@@ -1,16 +1,21 @@
|
|
|
1
|
+
import { type LoadItems } from './types';
|
|
1
2
|
type Args<T> = {
|
|
2
3
|
items?: T[];
|
|
3
|
-
loadItems?:
|
|
4
|
+
loadItems?: LoadItems<T>;
|
|
4
5
|
localItems?: T[];
|
|
5
6
|
debounceMs?: number;
|
|
7
|
+
minChars?: number;
|
|
6
8
|
getLabel: (item: T) => string;
|
|
7
9
|
filter?: (item: T, query: string) => boolean;
|
|
8
10
|
query: string;
|
|
9
11
|
isOpen: boolean;
|
|
10
12
|
};
|
|
11
|
-
|
|
13
|
+
type Result<T> = {
|
|
12
14
|
sourceItems: T[];
|
|
13
15
|
filteredItems: T[];
|
|
14
16
|
loading: boolean;
|
|
17
|
+
loadingMore: boolean;
|
|
18
|
+
loadMore: () => void;
|
|
15
19
|
};
|
|
20
|
+
export declare function useDropdownItems<T>({ items, loadItems, localItems, debounceMs, minChars, getLabel, filter, query, isOpen, }: Args<T>): Result<T>;
|
|
16
21
|
export {};
|
|
@@ -7,6 +7,7 @@ export function useDropdownItems({
|
|
|
7
7
|
loadItems,
|
|
8
8
|
localItems,
|
|
9
9
|
debounceMs = DEFAULT_DEBOUNCE_MS,
|
|
10
|
+
minChars,
|
|
10
11
|
getLabel,
|
|
11
12
|
filter,
|
|
12
13
|
query,
|
|
@@ -15,12 +16,15 @@ export function useDropdownItems({
|
|
|
15
16
|
const isAsync = !!loadItems;
|
|
16
17
|
const {
|
|
17
18
|
items: loadedItems,
|
|
18
|
-
loading
|
|
19
|
+
loading,
|
|
20
|
+
loadingMore,
|
|
21
|
+
loadMore
|
|
19
22
|
} = useAsyncItems({
|
|
20
23
|
loadItems,
|
|
21
24
|
query,
|
|
22
25
|
isOpen,
|
|
23
|
-
debounceMs
|
|
26
|
+
debounceMs,
|
|
27
|
+
minChars
|
|
24
28
|
});
|
|
25
29
|
const sourceItems = useMemo(() => isAsync ? loadedItems : [...(items ?? []), ...(localItems ?? [])], [isAsync, loadedItems, items, localItems]);
|
|
26
30
|
const filteredItems = useMemo(() => {
|
|
@@ -31,6 +35,8 @@ export function useDropdownItems({
|
|
|
31
35
|
return {
|
|
32
36
|
sourceItems,
|
|
33
37
|
filteredItems,
|
|
34
|
-
loading
|
|
38
|
+
loading,
|
|
39
|
+
loadingMore,
|
|
40
|
+
loadMore
|
|
35
41
|
};
|
|
36
42
|
}
|
|
@@ -7,10 +7,11 @@ type Args = {
|
|
|
7
7
|
setActiveIndex: Dispatch<SetStateAction<number>>;
|
|
8
8
|
onSelectIndex: (index: number) => void;
|
|
9
9
|
onEscape: () => void;
|
|
10
|
+
onReachEnd?: () => void;
|
|
10
11
|
hasExtraRow?: boolean;
|
|
11
12
|
onSelectExtra?: () => void;
|
|
12
13
|
isQueryEmpty?: boolean;
|
|
13
14
|
onBackspaceEmpty?: () => void;
|
|
14
15
|
};
|
|
15
|
-
export declare function useListNavigation({ isOpen, open, itemCount, activeIndex, setActiveIndex, onSelectIndex, onEscape, hasExtraRow, onSelectExtra, isQueryEmpty, onBackspaceEmpty, }: Args): (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
16
|
+
export declare function useListNavigation({ isOpen, open, itemCount, activeIndex, setActiveIndex, onSelectIndex, onEscape, onReachEnd, hasExtraRow, onSelectExtra, isQueryEmpty, onBackspaceEmpty, }: Args): (event: KeyboardEvent<HTMLInputElement>) => void;
|
|
16
17
|
export {};
|
|
@@ -7,6 +7,7 @@ export function useListNavigation({
|
|
|
7
7
|
setActiveIndex,
|
|
8
8
|
onSelectIndex,
|
|
9
9
|
onEscape,
|
|
10
|
+
onReachEnd,
|
|
10
11
|
hasExtraRow,
|
|
11
12
|
onSelectExtra,
|
|
12
13
|
isQueryEmpty,
|
|
@@ -16,7 +17,15 @@ export function useListNavigation({
|
|
|
16
17
|
return useCallback(event => {
|
|
17
18
|
if (event.key === 'ArrowDown') {
|
|
18
19
|
event.preventDefault();
|
|
19
|
-
if (!isOpen)
|
|
20
|
+
if (!isOpen) {
|
|
21
|
+
open();
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
if (total > 0) {
|
|
25
|
+
const next = activeIndex >= total - 1 ? 0 : activeIndex + 1;
|
|
26
|
+
setActiveIndex(next);
|
|
27
|
+
if (next > 0 && next >= total - 1) onReachEnd === null || onReachEnd === void 0 || onReachEnd();
|
|
28
|
+
}
|
|
20
29
|
return;
|
|
21
30
|
}
|
|
22
31
|
if (event.key === 'ArrowUp') {
|
|
@@ -41,5 +50,5 @@ export function useListNavigation({
|
|
|
41
50
|
if (event.key === 'Backspace' && isQueryEmpty && onBackspaceEmpty) {
|
|
42
51
|
onBackspaceEmpty();
|
|
43
52
|
}
|
|
44
|
-
}, [isOpen, open, total, activeIndex, setActiveIndex, onSelectIndex, onSelectExtra, onEscape, hasExtraRow, isQueryEmpty, onBackspaceEmpty]);
|
|
53
|
+
}, [isOpen, open, total, activeIndex, setActiveIndex, onSelectIndex, onSelectExtra, onEscape, onReachEnd, hasExtraRow, isQueryEmpty, onBackspaceEmpty]);
|
|
45
54
|
}
|