react-native-molecules 0.5.0-beta.3 → 0.5.0-beta.5
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/components/Button/Button.tsx +5 -20
- package/components/Button/utils.ts +0 -1
- package/components/Chip/Chip.tsx +39 -51
- package/components/Chip/utils.ts +3 -7
- package/components/IconButton/IconButton.tsx +42 -57
- package/components/IconButton/utils.ts +4 -5
- package/components/Select/Select.tsx +360 -501
- package/components/Select/index.ts +7 -14
- package/components/Select/types.ts +2 -4
- package/components/Select/utils.ts +215 -0
- package/components/Slot/Slot.tsx +244 -0
- package/components/Slot/compose-refs.tsx +60 -0
- package/components/Slot/index.tsx +8 -0
- package/components/Surface/Surface.android.tsx +20 -7
- package/components/Surface/Surface.ios.tsx +22 -29
- package/components/Surface/Surface.tsx +14 -4
- package/components/Surface/utils.ts +44 -6
- package/components/Switch/Switch.tsx +8 -2
- package/components/TextInput/TextInput.tsx +4 -4
- package/components/Tooltip/TooltipTrigger.tsx +25 -16
- package/components/TouchableRipple/TouchableRipple.native.tsx +35 -13
- package/components/TouchableRipple/TouchableRipple.tsx +119 -46
- package/hooks/useControlledValue.tsx +20 -4
- package/hooks/useWhatHasUpdated.tsx +48 -0
- package/package.json +1 -10
- package/shortcuts-manager/ShortcutsManager/ShortcutsManager.tsx +5 -2
- package/styles/shadow.ts +2 -1
- package/utils/lodash.ts +77 -5
|
@@ -1,13 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createContext,
|
|
3
|
-
memo,
|
|
4
|
-
useCallback,
|
|
5
|
-
useContext,
|
|
6
|
-
useEffect,
|
|
7
|
-
useMemo,
|
|
8
|
-
useRef,
|
|
9
|
-
useState,
|
|
10
|
-
} from 'react';
|
|
1
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
11
2
|
import {
|
|
12
3
|
type AccessibilityRole,
|
|
13
4
|
type GestureResponderEvent,
|
|
@@ -17,281 +8,236 @@ import {
|
|
|
17
8
|
ScrollView,
|
|
18
9
|
View,
|
|
19
10
|
} from 'react-native';
|
|
20
|
-
import { StyleSheet } from 'react-native-unistyles';
|
|
21
11
|
|
|
22
|
-
import {
|
|
12
|
+
import { typedMemo } from '../../hocs';
|
|
13
|
+
import { useActionState, useControlledValue, useLatest } from '../../hooks';
|
|
23
14
|
import { useToggle } from '../../hooks';
|
|
24
15
|
import { resolveStateVariant } from '../../utils';
|
|
25
16
|
import { Chip } from '../Chip';
|
|
26
17
|
import { Icon } from '../Icon';
|
|
27
18
|
import { IconButton } from '../IconButton';
|
|
28
19
|
import { Popover } from '../Popover';
|
|
29
|
-
import { registerPortalContext } from '../Portal';
|
|
30
20
|
import { Text } from '../Text';
|
|
31
21
|
import { TextInput, type TextInputHandles, type TextInputProps } from '../TextInput';
|
|
32
22
|
import type {
|
|
33
23
|
DefaultItemT,
|
|
34
24
|
SelectContentProps,
|
|
35
25
|
SelectContextValue,
|
|
36
|
-
SelectDropdownContextValue,
|
|
37
26
|
SelectDropdownProps,
|
|
38
27
|
SelectGroupProps,
|
|
39
28
|
SelectOptionProps,
|
|
40
|
-
|
|
29
|
+
SelectProps,
|
|
41
30
|
SelectSearchInputProps,
|
|
42
31
|
SelectTriggerProps,
|
|
43
32
|
SelectValueProps,
|
|
44
33
|
} from './types';
|
|
34
|
+
import {
|
|
35
|
+
SelectContextProvider,
|
|
36
|
+
SelectDropdownContextProvider,
|
|
37
|
+
styles,
|
|
38
|
+
triggerStyles,
|
|
39
|
+
useSelectContextValue,
|
|
40
|
+
useSelectDropdownContextValue,
|
|
41
|
+
} from './utils';
|
|
45
42
|
|
|
46
|
-
|
|
47
|
-
export const SelectContext = createContext<SelectContextValue<DefaultItemT>>({
|
|
48
|
-
value: null,
|
|
49
|
-
multiple: false,
|
|
50
|
-
onAdd: () => {},
|
|
51
|
-
onRemove: () => {},
|
|
52
|
-
disabled: false,
|
|
53
|
-
error: false,
|
|
54
|
-
labelKey: 'label',
|
|
55
|
-
options: [],
|
|
56
|
-
searchQuery: '',
|
|
57
|
-
setSearchQuery: () => {},
|
|
58
|
-
filteredOptions: [],
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
export const useSelectContext = <Option extends DefaultItemT = DefaultItemT>() => {
|
|
62
|
-
return useContext(SelectContext) as unknown as SelectContextValue<Option>;
|
|
63
|
-
};
|
|
64
|
-
|
|
65
|
-
export const useSelectContextValue = <Option extends DefaultItemT = DefaultItemT, T = any>(
|
|
66
|
-
selector: (state: SelectContextValue<Option>) => T,
|
|
67
|
-
): T => {
|
|
68
|
-
const context = useContext(SelectContext) as unknown as SelectContextValue<Option>;
|
|
69
|
-
return selector(context);
|
|
70
|
-
};
|
|
71
|
-
|
|
72
|
-
// SelectDropdownContext - holds isOpen, onClose, triggerRef
|
|
73
|
-
export type SelectDropdownContextType = SelectDropdownContextValue & {
|
|
74
|
-
triggerRef: React.RefObject<View> | null;
|
|
75
|
-
contentRef: React.RefObject<any> | null;
|
|
76
|
-
triggerLayout: { width: number; height: number } | null;
|
|
77
|
-
setTriggerLayout: (layout: { width: number; height: number }) => void;
|
|
78
|
-
};
|
|
43
|
+
const emptyArr: unknown[] = [];
|
|
79
44
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
45
|
+
// SelectProvider - manages controlled/uncontrolled state
|
|
46
|
+
const SelectProvider = typedMemo(
|
|
47
|
+
<Option extends DefaultItemT = DefaultItemT>({
|
|
48
|
+
children,
|
|
49
|
+
value: valueProp,
|
|
50
|
+
defaultValue,
|
|
51
|
+
onChange,
|
|
52
|
+
multiple = false,
|
|
53
|
+
disabled = false,
|
|
54
|
+
error = false,
|
|
55
|
+
labelKey = 'label',
|
|
56
|
+
options = emptyArr as Option[],
|
|
57
|
+
searchKey,
|
|
58
|
+
onSearchChange,
|
|
59
|
+
hideSelected: hideSelectedProp,
|
|
60
|
+
}: SelectProps<Option>) => {
|
|
61
|
+
const [value, onValueChange] = useControlledValue<Option['id'] | Option['id'][] | null>({
|
|
62
|
+
value: valueProp,
|
|
63
|
+
defaultValue: defaultValue ?? (multiple ? (emptyArr as Option['id'][]) : null),
|
|
64
|
+
onChange,
|
|
65
|
+
});
|
|
66
|
+
const valueRef = useLatest(value);
|
|
89
67
|
|
|
90
|
-
|
|
68
|
+
const [searchQuery, setSearchQuery] = useState('');
|
|
91
69
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
70
|
+
const handleSearchQueryChange = useCallback(
|
|
71
|
+
(query: string) => {
|
|
72
|
+
setSearchQuery(query);
|
|
73
|
+
onSearchChange?.(query);
|
|
74
|
+
},
|
|
75
|
+
[onSearchChange],
|
|
76
|
+
);
|
|
95
77
|
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
): T => {
|
|
99
|
-
const context = useContext(SelectDropdownContext);
|
|
100
|
-
return selector(context);
|
|
101
|
-
};
|
|
78
|
+
// Default hideSelected to multiple (true for multi-select, false for single select)
|
|
79
|
+
const hideSelected = hideSelectedProp !== undefined ? hideSelectedProp : multiple;
|
|
102
80
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
children,
|
|
106
|
-
value: valueProp,
|
|
107
|
-
defaultValue,
|
|
108
|
-
onChange,
|
|
109
|
-
multiple = false,
|
|
110
|
-
disabled = false,
|
|
111
|
-
error = false,
|
|
112
|
-
labelKey = 'label',
|
|
113
|
-
options = [],
|
|
114
|
-
searchKey,
|
|
115
|
-
onSearchChange,
|
|
116
|
-
hideSelected: hideSelectedProp,
|
|
117
|
-
}: SelectProviderProps<Option>) => {
|
|
118
|
-
const [value, onValueChange] = useControlledValue<Option['id'] | Option['id'][] | null>({
|
|
119
|
-
value: valueProp,
|
|
120
|
-
defaultValue: defaultValue ?? (multiple ? [] : null),
|
|
121
|
-
onChange: (newValue, item, event) => {
|
|
122
|
-
onChange?.(newValue, item as Option, event);
|
|
123
|
-
},
|
|
124
|
-
});
|
|
81
|
+
const filteredOptions = useMemo(() => {
|
|
82
|
+
let result = options;
|
|
125
83
|
|
|
126
|
-
|
|
84
|
+
// Filter out selected items if hideSelected is true
|
|
85
|
+
if (hideSelected) {
|
|
86
|
+
result = result.filter(item => {
|
|
87
|
+
if (multiple) {
|
|
88
|
+
const values = (value as Option['id'][]) || [];
|
|
89
|
+
return !values.some(v => v === item.id);
|
|
90
|
+
} else {
|
|
91
|
+
const singleValue = value as Option['id'] | null;
|
|
92
|
+
return singleValue !== item.id;
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
}
|
|
127
96
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
97
|
+
// Apply search filter if there's a search query
|
|
98
|
+
if (searchQuery) {
|
|
99
|
+
const key = searchKey || labelKey || 'label';
|
|
100
|
+
const lowerQuery = searchQuery.toLowerCase();
|
|
101
|
+
result = result.filter(item => {
|
|
102
|
+
const itemValue = item[key];
|
|
103
|
+
return String(itemValue || '')
|
|
104
|
+
.toLowerCase()
|
|
105
|
+
.includes(lowerQuery);
|
|
106
|
+
});
|
|
107
|
+
}
|
|
135
108
|
|
|
136
|
-
|
|
137
|
-
|
|
109
|
+
return result;
|
|
110
|
+
}, [options, searchQuery, searchKey, labelKey, hideSelected, multiple, value]);
|
|
138
111
|
|
|
139
|
-
|
|
140
|
-
|
|
112
|
+
const onAdd = useCallback(
|
|
113
|
+
(item: Option) => {
|
|
114
|
+
if (multiple) {
|
|
115
|
+
const currentValue = (valueRef.current as Option['id'][]) || [];
|
|
116
|
+
if (!currentValue.find(v => v === item.id)) {
|
|
117
|
+
onValueChange([...currentValue, item.id] as Option['id'][], item);
|
|
118
|
+
}
|
|
119
|
+
} else {
|
|
120
|
+
onValueChange(item.id, item);
|
|
121
|
+
}
|
|
122
|
+
},
|
|
123
|
+
[multiple, valueRef, onValueChange],
|
|
124
|
+
);
|
|
141
125
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
result = result.filter(item => {
|
|
126
|
+
const onRemove = useCallback(
|
|
127
|
+
(item: Option) => {
|
|
145
128
|
if (multiple) {
|
|
146
|
-
const
|
|
147
|
-
|
|
129
|
+
const currentValue = (valueRef.current as Option['id'][]) || [];
|
|
130
|
+
onValueChange(currentValue.filter(v => v !== item.id) as Option['id'][], item);
|
|
148
131
|
} else {
|
|
149
|
-
|
|
150
|
-
return singleValue !== item.id;
|
|
132
|
+
onValueChange(null, item);
|
|
151
133
|
}
|
|
152
|
-
}
|
|
153
|
-
|
|
134
|
+
},
|
|
135
|
+
[multiple, valueRef, onValueChange],
|
|
136
|
+
);
|
|
154
137
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
138
|
+
const contextValue = useMemo(
|
|
139
|
+
() => ({
|
|
140
|
+
value: value,
|
|
141
|
+
multiple,
|
|
142
|
+
onAdd: onAdd as (item: DefaultItemT) => void,
|
|
143
|
+
onRemove: onRemove as (item: DefaultItemT) => void,
|
|
144
|
+
disabled,
|
|
145
|
+
error,
|
|
146
|
+
labelKey,
|
|
147
|
+
options,
|
|
148
|
+
searchQuery,
|
|
149
|
+
setSearchQuery: handleSearchQueryChange,
|
|
150
|
+
filteredOptions,
|
|
151
|
+
}),
|
|
152
|
+
[
|
|
153
|
+
value,
|
|
154
|
+
multiple,
|
|
155
|
+
onAdd,
|
|
156
|
+
onRemove,
|
|
157
|
+
disabled,
|
|
158
|
+
error,
|
|
159
|
+
labelKey,
|
|
160
|
+
options,
|
|
161
|
+
searchQuery,
|
|
162
|
+
handleSearchQueryChange,
|
|
163
|
+
filteredOptions,
|
|
164
|
+
],
|
|
165
|
+
);
|
|
166
166
|
|
|
167
|
-
return
|
|
168
|
-
|
|
167
|
+
return (
|
|
168
|
+
<SelectContextProvider
|
|
169
|
+
value={contextValue as unknown as SelectContextValue<DefaultItemT>}>
|
|
170
|
+
{children}
|
|
171
|
+
</SelectContextProvider>
|
|
172
|
+
);
|
|
173
|
+
},
|
|
174
|
+
);
|
|
169
175
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
176
|
+
// SelectDropdownProvider - manages dropdown state
|
|
177
|
+
const SelectDropdownProvider = memo(
|
|
178
|
+
({
|
|
179
|
+
children,
|
|
180
|
+
isOpen: isOpenProp,
|
|
181
|
+
onClose: onCloseProp,
|
|
182
|
+
}: {
|
|
183
|
+
children: React.ReactNode;
|
|
184
|
+
isOpen?: boolean;
|
|
185
|
+
onClose?: () => void;
|
|
186
|
+
}) => {
|
|
187
|
+
const { state: isOpen, handleOpen, handleClose } = useToggle(false);
|
|
188
|
+
const triggerRef = useRef<View>(null);
|
|
189
|
+
const contentRef = useRef<any>(null);
|
|
190
|
+
const [triggerLayout, setTriggerLayout] = useState<{
|
|
191
|
+
width: number;
|
|
192
|
+
height: number;
|
|
193
|
+
} | null>(null);
|
|
194
|
+
const isControlled = isOpenProp !== undefined;
|
|
195
|
+
|
|
196
|
+
const onClose = useCallback(() => {
|
|
197
|
+
if (isControlled) {
|
|
198
|
+
onCloseProp?.();
|
|
177
199
|
} else {
|
|
178
|
-
|
|
200
|
+
handleClose();
|
|
179
201
|
}
|
|
180
|
-
},
|
|
181
|
-
[multiple, value, onValueChange],
|
|
182
|
-
);
|
|
202
|
+
}, [isControlled, onCloseProp, handleClose]);
|
|
183
203
|
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const currentValue = (value as Option['id'][]) || [];
|
|
188
|
-
onValueChange(currentValue.filter(v => v !== item.id) as Option['id'][], item);
|
|
189
|
-
} else {
|
|
190
|
-
onValueChange(null, item);
|
|
204
|
+
const onOpen = useCallback(() => {
|
|
205
|
+
if (!isControlled) {
|
|
206
|
+
handleOpen();
|
|
191
207
|
}
|
|
192
|
-
},
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
searchQuery,
|
|
207
|
-
setSearchQuery: handleSearchQueryChange,
|
|
208
|
-
filteredOptions,
|
|
209
|
-
}),
|
|
210
|
-
[
|
|
211
|
-
value,
|
|
212
|
-
multiple,
|
|
213
|
-
onAdd,
|
|
214
|
-
onRemove,
|
|
215
|
-
disabled,
|
|
216
|
-
error,
|
|
217
|
-
labelKey,
|
|
218
|
-
options,
|
|
219
|
-
searchQuery,
|
|
220
|
-
handleSearchQueryChange,
|
|
221
|
-
filteredOptions,
|
|
222
|
-
],
|
|
223
|
-
);
|
|
224
|
-
|
|
225
|
-
return (
|
|
226
|
-
<SelectContext.Provider value={contextValue as unknown as SelectContextValue<DefaultItemT>}>
|
|
227
|
-
{children}
|
|
228
|
-
</SelectContext.Provider>
|
|
229
|
-
);
|
|
230
|
-
};
|
|
231
|
-
|
|
232
|
-
// SelectDropdownProvider - manages dropdown state
|
|
233
|
-
const SelectDropdownProvider = ({
|
|
234
|
-
children,
|
|
235
|
-
isOpen: isOpenProp,
|
|
236
|
-
onClose: onCloseProp,
|
|
237
|
-
}: {
|
|
238
|
-
children: React.ReactNode;
|
|
239
|
-
isOpen?: boolean;
|
|
240
|
-
onClose?: () => void;
|
|
241
|
-
}) => {
|
|
242
|
-
const { state: isOpen, handleOpen, handleClose } = useToggle(false);
|
|
243
|
-
const triggerRef = useRef<View>(null);
|
|
244
|
-
const contentRef = useRef<any>(null);
|
|
245
|
-
const [triggerLayout, setTriggerLayout] = useState<{ width: number; height: number } | null>(
|
|
246
|
-
null,
|
|
247
|
-
);
|
|
248
|
-
const isControlled = isOpenProp !== undefined;
|
|
249
|
-
|
|
250
|
-
const onClose = useCallback(() => {
|
|
251
|
-
if (isControlled) {
|
|
252
|
-
onCloseProp?.();
|
|
253
|
-
} else {
|
|
254
|
-
handleClose();
|
|
255
|
-
}
|
|
256
|
-
}, [isControlled, onCloseProp, handleClose]);
|
|
257
|
-
|
|
258
|
-
const onOpen = useCallback(() => {
|
|
259
|
-
if (!isControlled) {
|
|
260
|
-
handleOpen();
|
|
261
|
-
}
|
|
262
|
-
}, [handleOpen, isControlled]);
|
|
263
|
-
|
|
264
|
-
const contextValue = useMemo(
|
|
265
|
-
() => ({
|
|
266
|
-
isOpen: isControlled ? isOpenProp! : isOpen,
|
|
267
|
-
onClose,
|
|
268
|
-
onOpen,
|
|
269
|
-
triggerRef: triggerRef as React.RefObject<View>,
|
|
270
|
-
contentRef,
|
|
271
|
-
triggerLayout,
|
|
272
|
-
setTriggerLayout,
|
|
273
|
-
}),
|
|
274
|
-
[isControlled, isOpenProp, isOpen, onClose, onOpen, triggerLayout],
|
|
275
|
-
);
|
|
208
|
+
}, [handleOpen, isControlled]);
|
|
209
|
+
|
|
210
|
+
const contextValue = useMemo(
|
|
211
|
+
() => ({
|
|
212
|
+
isOpen: isControlled ? isOpenProp! : isOpen,
|
|
213
|
+
onClose,
|
|
214
|
+
onOpen,
|
|
215
|
+
triggerRef: triggerRef as React.RefObject<View>,
|
|
216
|
+
contentRef,
|
|
217
|
+
triggerLayout,
|
|
218
|
+
setTriggerLayout,
|
|
219
|
+
}),
|
|
220
|
+
[isControlled, isOpenProp, isOpen, onClose, onOpen, triggerLayout],
|
|
221
|
+
);
|
|
276
222
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
223
|
+
return (
|
|
224
|
+
<SelectDropdownContextProvider value={contextValue}>
|
|
225
|
+
{children}
|
|
226
|
+
</SelectDropdownContextProvider>
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
);
|
|
283
230
|
|
|
284
231
|
// Select - wrapper component
|
|
285
|
-
const Select =
|
|
286
|
-
children,
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
};
|
|
232
|
+
const Select = typedMemo(
|
|
233
|
+
<Option extends DefaultItemT = DefaultItemT>({ children, ...props }: SelectProps<Option>) => {
|
|
234
|
+
return (
|
|
235
|
+
<SelectProvider<Option> {...props}>
|
|
236
|
+
<SelectDropdownProvider>{children}</SelectDropdownProvider>
|
|
237
|
+
</SelectProvider>
|
|
238
|
+
);
|
|
239
|
+
},
|
|
240
|
+
);
|
|
295
241
|
|
|
296
242
|
// Select.Trigger - opens the dropdown
|
|
297
243
|
const SelectTrigger = ({ children, style, ...rest }: SelectTriggerProps) => {
|
|
@@ -363,7 +309,7 @@ const SelectTrigger = ({ children, style, ...rest }: SelectTriggerProps) => {
|
|
|
363
309
|
SelectTrigger.displayName = 'Select_Trigger';
|
|
364
310
|
|
|
365
311
|
// Select.Value - displays the value
|
|
366
|
-
const SelectValue = ({ placeholder, renderValue, style, ...rest }: SelectValueProps) => {
|
|
312
|
+
const SelectValue = memo(({ placeholder, renderValue, style, ...rest }: SelectValueProps) => {
|
|
367
313
|
const { value, multiple, labelKey, onRemove, options } = useSelectContextValue(state => ({
|
|
368
314
|
value: state.value,
|
|
369
315
|
multiple: state.multiple,
|
|
@@ -409,13 +355,10 @@ const SelectValue = ({ placeholder, renderValue, style, ...rest }: SelectValuePr
|
|
|
409
355
|
return (
|
|
410
356
|
<View style={[styles.chipContainer, style]} {...rest}>
|
|
411
357
|
{(resolvedValue as DefaultItemT[]).map(item => (
|
|
412
|
-
<
|
|
358
|
+
<SelectValueItem
|
|
413
359
|
key={item.id || String(item)}
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
selected
|
|
417
|
-
left={<></>}
|
|
418
|
-
onClose={() => onRemove(item)}
|
|
360
|
+
item={item}
|
|
361
|
+
onRemoveItem={onRemove}
|
|
419
362
|
/>
|
|
420
363
|
))}
|
|
421
364
|
</View>
|
|
@@ -427,67 +370,95 @@ const SelectValue = ({ placeholder, renderValue, style, ...rest }: SelectValuePr
|
|
|
427
370
|
{displayValue}
|
|
428
371
|
</Text>
|
|
429
372
|
);
|
|
430
|
-
};
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
const SelectValueItem = typedMemo(
|
|
376
|
+
({
|
|
377
|
+
item,
|
|
378
|
+
onRemoveItem,
|
|
379
|
+
}: {
|
|
380
|
+
item: DefaultItemT;
|
|
381
|
+
onRemoveItem: (item: DefaultItemT) => void;
|
|
382
|
+
}) => {
|
|
383
|
+
const onRemove = useCallback(() => {
|
|
384
|
+
onRemoveItem(item);
|
|
385
|
+
}, [item, onRemoveItem]);
|
|
386
|
+
|
|
387
|
+
return (
|
|
388
|
+
<Chip.Input
|
|
389
|
+
label={item[item.labelKey || 'label'] || String(item.id || item)}
|
|
390
|
+
size="sm"
|
|
391
|
+
selected
|
|
392
|
+
left={<></>}
|
|
393
|
+
onClose={onRemove}
|
|
394
|
+
/>
|
|
395
|
+
);
|
|
396
|
+
},
|
|
397
|
+
);
|
|
431
398
|
|
|
432
399
|
SelectValue.displayName = 'Select_Value';
|
|
433
400
|
|
|
434
401
|
// Select.Dropdown - popover with keyboard navigation
|
|
435
|
-
const SelectDropdown = (
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
402
|
+
const SelectDropdown = memo(
|
|
403
|
+
({
|
|
404
|
+
children,
|
|
405
|
+
WrapperComponent,
|
|
406
|
+
wrapperComponentProps,
|
|
407
|
+
enableKeyboardNavigation = true,
|
|
408
|
+
style: popoverStyleProp,
|
|
409
|
+
...popoverProps
|
|
410
|
+
}: SelectDropdownProps & { enableKeyboardNavigation?: boolean }) => {
|
|
411
|
+
const { isOpen, onClose, triggerRef, triggerLayout } = useSelectDropdownContextValue(
|
|
412
|
+
state => ({
|
|
413
|
+
isOpen: state.isOpen,
|
|
414
|
+
onClose: state.onClose,
|
|
415
|
+
triggerRef: state.triggerRef,
|
|
416
|
+
triggerLayout: state.triggerLayout,
|
|
417
|
+
}),
|
|
418
|
+
);
|
|
449
419
|
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
420
|
+
const popoverStyle = useMemo(() => {
|
|
421
|
+
const baseStyle = popoverStyleProp ? [popoverStyleProp] : [];
|
|
422
|
+
if (triggerLayout) {
|
|
423
|
+
return [{ width: triggerLayout.width }, ...baseStyle];
|
|
424
|
+
}
|
|
425
|
+
return baseStyle;
|
|
426
|
+
}, [triggerLayout, popoverStyleProp]);
|
|
427
|
+
|
|
428
|
+
if (!triggerLayout) return null;
|
|
457
429
|
|
|
458
|
-
|
|
430
|
+
if (WrapperComponent) {
|
|
431
|
+
return (
|
|
432
|
+
<WrapperComponent isOpen={isOpen} onClose={onClose} {...wrapperComponentProps}>
|
|
433
|
+
{enableKeyboardNavigation && Platform.OS === 'web' ? (
|
|
434
|
+
<KeyboardNavigationWrapper>{children}</KeyboardNavigationWrapper>
|
|
435
|
+
) : (
|
|
436
|
+
children
|
|
437
|
+
)}
|
|
438
|
+
</WrapperComponent>
|
|
439
|
+
);
|
|
440
|
+
}
|
|
459
441
|
|
|
460
|
-
if (WrapperComponent) {
|
|
461
442
|
return (
|
|
462
|
-
<
|
|
443
|
+
<Popover
|
|
444
|
+
triggerRef={triggerRef as React.RefObject<View>}
|
|
445
|
+
isOpen={isOpen}
|
|
446
|
+
onClose={onClose}
|
|
447
|
+
style={popoverStyle}
|
|
448
|
+
triggerDimensions={triggerLayout}
|
|
449
|
+
{...popoverProps}>
|
|
463
450
|
{enableKeyboardNavigation && Platform.OS === 'web' ? (
|
|
464
451
|
<KeyboardNavigationWrapper>{children}</KeyboardNavigationWrapper>
|
|
465
452
|
) : (
|
|
466
453
|
children
|
|
467
454
|
)}
|
|
468
|
-
</
|
|
455
|
+
</Popover>
|
|
469
456
|
);
|
|
470
|
-
}
|
|
471
|
-
|
|
472
|
-
return (
|
|
473
|
-
<Popover
|
|
474
|
-
triggerRef={triggerRef as React.RefObject<View>}
|
|
475
|
-
isOpen={isOpen}
|
|
476
|
-
onClose={onClose}
|
|
477
|
-
style={popoverStyle}
|
|
478
|
-
triggerDimensions={triggerLayout}
|
|
479
|
-
{...popoverProps}>
|
|
480
|
-
{enableKeyboardNavigation && Platform.OS === 'web' ? (
|
|
481
|
-
<KeyboardNavigationWrapper>{children}</KeyboardNavigationWrapper>
|
|
482
|
-
) : (
|
|
483
|
-
children
|
|
484
|
-
)}
|
|
485
|
-
</Popover>
|
|
486
|
-
);
|
|
487
|
-
};
|
|
457
|
+
},
|
|
458
|
+
);
|
|
488
459
|
|
|
489
460
|
// Keyboard navigation wrapper for web
|
|
490
|
-
const KeyboardNavigationWrapper = ({ children }: { children: React.ReactNode }) => {
|
|
461
|
+
const KeyboardNavigationWrapper = memo(({ children }: { children: React.ReactNode }) => {
|
|
491
462
|
const { onClose, contentRef, isOpen } = useSelectDropdownContextValue(state => ({
|
|
492
463
|
onClose: state.onClose,
|
|
493
464
|
contentRef: state.contentRef,
|
|
@@ -533,8 +504,14 @@ const KeyboardNavigationWrapper = ({ children }: { children: React.ReactNode })
|
|
|
533
504
|
break;
|
|
534
505
|
case 'Enter':
|
|
535
506
|
e.preventDefault();
|
|
507
|
+
e.stopImmediatePropagation();
|
|
536
508
|
if (currentIndex !== -1) {
|
|
537
|
-
|
|
509
|
+
// Store reference to the focused element before triggering click
|
|
510
|
+
// to prevent issues with DOM updates during the click handler
|
|
511
|
+
const focusedOption = options[currentIndex];
|
|
512
|
+
if (focusedOption) {
|
|
513
|
+
focusedOption.click();
|
|
514
|
+
}
|
|
538
515
|
}
|
|
539
516
|
break;
|
|
540
517
|
case 'Escape':
|
|
@@ -599,75 +576,81 @@ const KeyboardNavigationWrapper = ({ children }: { children: React.ReactNode })
|
|
|
599
576
|
}, [handleKeyDown, contentRef, isOpen]);
|
|
600
577
|
|
|
601
578
|
return <>{children}</>;
|
|
602
|
-
};
|
|
579
|
+
});
|
|
603
580
|
|
|
604
581
|
SelectDropdown.displayName = 'Select_Dropdown';
|
|
605
582
|
|
|
606
583
|
// Select.Content - ScrollView that renders children
|
|
607
|
-
const SelectContent = (
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
contentRef
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
const { filteredOptions, value, multiple, searchQuery, options } = useSelectContextValue(
|
|
619
|
-
state => ({
|
|
620
|
-
filteredOptions: state.filteredOptions,
|
|
621
|
-
value: state.value,
|
|
622
|
-
multiple: state.multiple,
|
|
623
|
-
searchQuery: state.searchQuery,
|
|
624
|
-
options: state.options,
|
|
625
|
-
}),
|
|
626
|
-
);
|
|
584
|
+
const SelectContent = memo(
|
|
585
|
+
({
|
|
586
|
+
children,
|
|
587
|
+
ContainerComponent = ScrollView,
|
|
588
|
+
style,
|
|
589
|
+
emptyState,
|
|
590
|
+
...rest
|
|
591
|
+
}: SelectContentProps) => {
|
|
592
|
+
const { contentRef } = useSelectDropdownContextValue(state => ({
|
|
593
|
+
contentRef: state.contentRef,
|
|
594
|
+
}));
|
|
627
595
|
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
:
|
|
596
|
+
const { filteredOptions, value, multiple, searchQuery, options } = useSelectContextValue(
|
|
597
|
+
state => ({
|
|
598
|
+
filteredOptions: state.filteredOptions,
|
|
599
|
+
value: state.value,
|
|
600
|
+
multiple: state.multiple,
|
|
601
|
+
searchQuery: state.searchQuery,
|
|
602
|
+
options: state.options,
|
|
603
|
+
}),
|
|
604
|
+
);
|
|
633
605
|
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
606
|
+
const content = useMemo(() => {
|
|
607
|
+
return filteredOptions.map(option => {
|
|
608
|
+
const isSelected = multiple
|
|
609
|
+
? (value as any[])?.some(v => (v?.id ?? v) === option.id)
|
|
610
|
+
: (value as any)?.id === option.id || (value as any) === option.id;
|
|
637
611
|
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
612
|
+
return children(option, !!isSelected);
|
|
613
|
+
});
|
|
614
|
+
}, [filteredOptions, value, multiple, children]);
|
|
615
|
+
|
|
616
|
+
const defaultEmptyState = useMemo(() => {
|
|
617
|
+
const hasSearchQuery = searchQuery && searchQuery.trim().length > 0;
|
|
618
|
+
const hasNoOptions = options.length === 0;
|
|
619
|
+
|
|
620
|
+
if (hasNoOptions) {
|
|
621
|
+
return (
|
|
622
|
+
<View style={styles.emptyState}>
|
|
623
|
+
<Text style={styles.emptyStateText}>No options available</Text>
|
|
624
|
+
</View>
|
|
625
|
+
);
|
|
626
|
+
}
|
|
641
627
|
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
628
|
+
if (hasSearchQuery) {
|
|
629
|
+
return (
|
|
630
|
+
<View style={styles.emptyState}>
|
|
631
|
+
<Text style={styles.emptyStateText}>No results found</Text>
|
|
632
|
+
</View>
|
|
633
|
+
);
|
|
634
|
+
}
|
|
649
635
|
|
|
650
|
-
if (hasSearchQuery) {
|
|
651
636
|
return (
|
|
652
637
|
<View style={styles.emptyState}>
|
|
653
|
-
<Text style={styles.emptyStateText}>No
|
|
638
|
+
<Text style={styles.emptyStateText}>No options</Text>
|
|
654
639
|
</View>
|
|
655
640
|
);
|
|
656
|
-
}
|
|
641
|
+
}, [searchQuery, options.length]);
|
|
657
642
|
|
|
658
643
|
return (
|
|
659
|
-
<
|
|
660
|
-
|
|
661
|
-
|
|
644
|
+
<ContainerComponent
|
|
645
|
+
ref={contentRef}
|
|
646
|
+
style={style}
|
|
647
|
+
{...rest}
|
|
648
|
+
accessibilityRole="listbox">
|
|
649
|
+
{filteredOptions.length === 0 ? emptyState ?? defaultEmptyState : content}
|
|
650
|
+
</ContainerComponent>
|
|
662
651
|
);
|
|
663
|
-
},
|
|
664
|
-
|
|
665
|
-
return (
|
|
666
|
-
<ContainerComponent ref={contentRef} style={style} {...rest} accessibilityRole="listbox">
|
|
667
|
-
{filteredOptions.length === 0 ? emptyState ?? defaultEmptyState : content}
|
|
668
|
-
</ContainerComponent>
|
|
669
|
-
);
|
|
670
|
-
};
|
|
652
|
+
},
|
|
653
|
+
);
|
|
671
654
|
|
|
672
655
|
SelectContent.displayName = 'Select_Content';
|
|
673
656
|
|
|
@@ -695,23 +678,17 @@ const SelectOption = memo(
|
|
|
695
678
|
...rest
|
|
696
679
|
}: SelectOptionProps<Option>) => {
|
|
697
680
|
const {
|
|
698
|
-
value: selectionValue,
|
|
699
681
|
multiple,
|
|
700
682
|
onAdd,
|
|
701
683
|
onRemove,
|
|
702
684
|
disabled: selectDisabled,
|
|
703
|
-
} = useSelectContextValue
|
|
704
|
-
value: state.value,
|
|
685
|
+
} = useSelectContextValue(state => ({
|
|
705
686
|
multiple: state.multiple,
|
|
706
687
|
onAdd: state.onAdd,
|
|
707
688
|
onRemove: state.onRemove,
|
|
708
689
|
disabled: state.disabled,
|
|
709
690
|
}));
|
|
710
691
|
|
|
711
|
-
const { onClose } = useSelectDropdownContextValue(state => ({
|
|
712
|
-
onClose: state.onClose,
|
|
713
|
-
}));
|
|
714
|
-
|
|
715
692
|
const option = useMemo(() => {
|
|
716
693
|
return {
|
|
717
694
|
id: value,
|
|
@@ -720,15 +697,19 @@ const SelectOption = memo(
|
|
|
720
697
|
} as Option;
|
|
721
698
|
}, [children, optionDisabledProp, value]);
|
|
722
699
|
|
|
723
|
-
const isSelected =
|
|
700
|
+
const isSelected = useSelectContextValue(state => {
|
|
724
701
|
if (multiple) {
|
|
725
|
-
const values =
|
|
702
|
+
const values = state.value as any[];
|
|
726
703
|
return values?.some(v => (v?.id ?? v) === option.id) || false;
|
|
727
704
|
} else {
|
|
728
|
-
const singleValue =
|
|
705
|
+
const singleValue = state.value as any;
|
|
729
706
|
return (singleValue?.id ?? singleValue) === option.id || false;
|
|
730
707
|
}
|
|
731
|
-
}
|
|
708
|
+
});
|
|
709
|
+
|
|
710
|
+
const { onClose } = useSelectDropdownContextValue(state => ({
|
|
711
|
+
onClose: state.onClose,
|
|
712
|
+
}));
|
|
732
713
|
|
|
733
714
|
const isOptionDisabled = Boolean(
|
|
734
715
|
selectDisabled || optionDisabledProp || option.selectable === false,
|
|
@@ -779,6 +760,14 @@ const SelectOption = memo(
|
|
|
779
760
|
tabIndex: -1 as 0 | -1 | undefined,
|
|
780
761
|
// Use a dataset attribute to help the keyboard navigator find this
|
|
781
762
|
'data-option-id': String(option.id),
|
|
763
|
+
// Prevent Pressable's native Enter key handling since we handle it in KeyboardNavigationWrapper
|
|
764
|
+
// This prevents double-triggering of onPress when Enter is pressed
|
|
765
|
+
onKeyDown: (e: React.KeyboardEvent) => {
|
|
766
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
767
|
+
e.preventDefault();
|
|
768
|
+
e.stopPropagation();
|
|
769
|
+
}
|
|
770
|
+
},
|
|
782
771
|
},
|
|
783
772
|
}),
|
|
784
773
|
};
|
|
@@ -818,7 +807,7 @@ SelectOption.displayName = 'Select_Option';
|
|
|
818
807
|
|
|
819
808
|
// Select.SearchInput - handles search
|
|
820
809
|
const SelectSearchInput = memo(
|
|
821
|
-
({
|
|
810
|
+
({ autoFocus = true, ...textInputProps }: SelectSearchInputProps) => {
|
|
822
811
|
const { searchQuery, setSearchQuery } = useSelectContextValue(state => ({
|
|
823
812
|
searchQuery: state.searchQuery,
|
|
824
813
|
setSearchQuery: state.setSearchQuery,
|
|
@@ -828,15 +817,13 @@ const SelectSearchInput = memo(
|
|
|
828
817
|
const handleChangeText = useCallback(
|
|
829
818
|
(text: string) => {
|
|
830
819
|
setSearchQuery(text);
|
|
831
|
-
onQueryChange?.(text);
|
|
832
|
-
textInputProps.onChangeText?.(text);
|
|
833
820
|
},
|
|
834
|
-
[
|
|
821
|
+
[setSearchQuery],
|
|
835
822
|
);
|
|
836
823
|
|
|
837
824
|
const inputProps = {
|
|
838
825
|
...textInputProps,
|
|
839
|
-
value:
|
|
826
|
+
value: searchQuery,
|
|
840
827
|
onChangeText: handleChangeText,
|
|
841
828
|
placeholder: textInputProps.placeholder || 'Search...',
|
|
842
829
|
inputStyle: styles.searchInputInput,
|
|
@@ -866,17 +853,23 @@ const SelectSearchInput = memo(
|
|
|
866
853
|
requestAnimationFrame(focusField);
|
|
867
854
|
}, [autoFocus]);
|
|
868
855
|
|
|
856
|
+
const onPressLeftIcon = useCallback(() => {
|
|
857
|
+
textInputRef.current?.focus();
|
|
858
|
+
}, []);
|
|
859
|
+
|
|
860
|
+
const onClearSearchQuery = useCallback(() => {
|
|
861
|
+
handleChangeText('');
|
|
862
|
+
}, [handleChangeText]);
|
|
863
|
+
|
|
869
864
|
return (
|
|
870
865
|
<TextInput
|
|
871
866
|
ref={textInputRef}
|
|
872
867
|
autoFocus={Platform.OS !== 'web' && autoFocus}
|
|
873
868
|
style={styles.searchInput}
|
|
874
|
-
left={
|
|
875
|
-
<Icon onPress={() => textInputRef.current?.focus()} name="magnify" size={20} />
|
|
876
|
-
}
|
|
869
|
+
left={<Icon onPress={onPressLeftIcon} name="magnify" size={20} />}
|
|
877
870
|
right={
|
|
878
871
|
searchQuery ? (
|
|
879
|
-
<IconButton name="close" size={20} onPress={
|
|
872
|
+
<IconButton name="close" size={20} onPress={onClearSearchQuery} />
|
|
880
873
|
) : undefined
|
|
881
874
|
}
|
|
882
875
|
size="sm"
|
|
@@ -900,139 +893,5 @@ const SelectWithSubcomponents = Object.assign(Select, {
|
|
|
900
893
|
SearchInput: SelectSearchInput,
|
|
901
894
|
});
|
|
902
895
|
|
|
903
|
-
const triggerStyles = StyleSheet.create(theme => ({
|
|
904
|
-
trigger: {
|
|
905
|
-
borderRadius: theme.shapes.corner.extraSmall,
|
|
906
|
-
paddingHorizontal: theme.spacings['3'],
|
|
907
|
-
paddingVertical: theme.spacings['2'],
|
|
908
|
-
minHeight: 56,
|
|
909
|
-
flexDirection: 'row',
|
|
910
|
-
alignItems: 'center',
|
|
911
|
-
justifyContent: 'space-between',
|
|
912
|
-
width: '100%',
|
|
913
|
-
variants: {
|
|
914
|
-
state: {
|
|
915
|
-
disabled: {
|
|
916
|
-
opacity: 0.38,
|
|
917
|
-
backgroundColor: theme.colors.surfaceVariant,
|
|
918
|
-
},
|
|
919
|
-
errorDisabled: {
|
|
920
|
-
opacity: 0.38,
|
|
921
|
-
},
|
|
922
|
-
},
|
|
923
|
-
},
|
|
924
|
-
},
|
|
925
|
-
outline: {
|
|
926
|
-
position: 'absolute',
|
|
927
|
-
top: 0,
|
|
928
|
-
left: 0,
|
|
929
|
-
right: 0,
|
|
930
|
-
bottom: 0,
|
|
931
|
-
borderRadius: theme.shapes.corner.extraSmall,
|
|
932
|
-
borderWidth: 1,
|
|
933
|
-
borderColor: theme.colors.outline,
|
|
934
|
-
pointerEvents: 'none',
|
|
935
|
-
variants: {
|
|
936
|
-
state: {
|
|
937
|
-
focused: {
|
|
938
|
-
borderWidth: 2,
|
|
939
|
-
borderColor: theme.colors.primary,
|
|
940
|
-
},
|
|
941
|
-
hovered: {
|
|
942
|
-
borderColor: theme.colors.onSurface,
|
|
943
|
-
},
|
|
944
|
-
hoveredAndFocused: {
|
|
945
|
-
borderWidth: 2,
|
|
946
|
-
borderColor: theme.colors.primary,
|
|
947
|
-
},
|
|
948
|
-
disabled: {
|
|
949
|
-
borderColor: theme.colors.onSurface,
|
|
950
|
-
},
|
|
951
|
-
error: {
|
|
952
|
-
borderColor: theme.colors.error,
|
|
953
|
-
},
|
|
954
|
-
errorFocused: {
|
|
955
|
-
borderWidth: 2,
|
|
956
|
-
borderColor: theme.colors.error,
|
|
957
|
-
},
|
|
958
|
-
errorHovered: {
|
|
959
|
-
borderColor: theme.colors.onErrorContainer,
|
|
960
|
-
},
|
|
961
|
-
errorFocusedAndHovered: {
|
|
962
|
-
borderWidth: 2,
|
|
963
|
-
borderColor: theme.colors.error,
|
|
964
|
-
},
|
|
965
|
-
errorDisabled: {
|
|
966
|
-
borderColor: theme.colors.error,
|
|
967
|
-
},
|
|
968
|
-
},
|
|
969
|
-
},
|
|
970
|
-
},
|
|
971
|
-
triggerIcon: {
|
|
972
|
-
marginLeft: theme.spacings['2'],
|
|
973
|
-
color: theme.colors.onSurfaceVariant,
|
|
974
|
-
},
|
|
975
|
-
}));
|
|
976
|
-
|
|
977
|
-
const styles = StyleSheet.create(theme => ({
|
|
978
|
-
chipContainer: {
|
|
979
|
-
flexDirection: 'row',
|
|
980
|
-
flexWrap: 'wrap',
|
|
981
|
-
gap: 6,
|
|
982
|
-
maxWidth: '90%',
|
|
983
|
-
},
|
|
984
|
-
groupLabel: {
|
|
985
|
-
paddingHorizontal: theme.spacings['4'],
|
|
986
|
-
paddingVertical: theme.spacings['2'],
|
|
987
|
-
fontWeight: '600',
|
|
988
|
-
color: theme.colors.onSurface,
|
|
989
|
-
},
|
|
990
|
-
item: {
|
|
991
|
-
paddingHorizontal: theme.spacings['4'],
|
|
992
|
-
paddingVertical: theme.spacings['3'],
|
|
993
|
-
backgroundColor: 'transparent',
|
|
994
|
-
|
|
995
|
-
_web: {
|
|
996
|
-
cursor: 'pointer',
|
|
997
|
-
outlineStyle: 'none',
|
|
998
|
-
_hover: {
|
|
999
|
-
backgroundColor: theme.colors.stateLayer.hover.primary,
|
|
1000
|
-
},
|
|
1001
|
-
_focus: {
|
|
1002
|
-
backgroundColor: theme.colors.stateLayer.hover.primary,
|
|
1003
|
-
},
|
|
1004
|
-
},
|
|
1005
|
-
},
|
|
1006
|
-
itemSelected: {
|
|
1007
|
-
backgroundColor: theme.colors.stateLayer.hover.primary,
|
|
1008
|
-
},
|
|
1009
|
-
itemDisabled: {
|
|
1010
|
-
opacity: 0.38,
|
|
1011
|
-
_web: {
|
|
1012
|
-
cursor: 'not-allowed',
|
|
1013
|
-
},
|
|
1014
|
-
},
|
|
1015
|
-
itemDisabledText: {
|
|
1016
|
-
color: theme.colors.onSurfaceVariant,
|
|
1017
|
-
},
|
|
1018
|
-
searchInput: {
|
|
1019
|
-
marginHorizontal: theme.spacings['2'],
|
|
1020
|
-
marginVertical: theme.spacings['3'],
|
|
1021
|
-
},
|
|
1022
|
-
searchInputInput: {
|
|
1023
|
-
height: 42,
|
|
1024
|
-
},
|
|
1025
|
-
emptyState: {
|
|
1026
|
-
paddingHorizontal: theme.spacings['4'],
|
|
1027
|
-
paddingVertical: theme.spacings['6'],
|
|
1028
|
-
alignItems: 'center',
|
|
1029
|
-
justifyContent: 'center',
|
|
1030
|
-
},
|
|
1031
|
-
emptyStateText: {
|
|
1032
|
-
color: theme.colors.onSurfaceVariant,
|
|
1033
|
-
fontSize: 14,
|
|
1034
|
-
},
|
|
1035
|
-
}));
|
|
1036
|
-
|
|
1037
896
|
export default SelectWithSubcomponents;
|
|
1038
897
|
export { SelectDropdownProvider, SelectProvider };
|