@coinbase/cds-mobile 8.28.2 → 8.30.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 +15 -0
- package/dts/alpha/combobox/Combobox.d.ts +73 -0
- package/dts/alpha/combobox/Combobox.d.ts.map +1 -0
- package/dts/alpha/combobox/DefaultComboboxControl.d.ts +20 -0
- package/dts/alpha/combobox/DefaultComboboxControl.d.ts.map +1 -0
- package/dts/alpha/select/DefaultSelectControl.d.ts +1 -0
- package/dts/alpha/select/DefaultSelectControl.d.ts.map +1 -1
- package/dts/alpha/select/DefaultSelectDropdown.d.ts.map +1 -1
- package/dts/alpha/select/types.d.ts +4 -1
- package/dts/alpha/select/types.d.ts.map +1 -1
- package/dts/alpha/select-chip/SelectChip.d.ts +12 -6
- package/dts/alpha/select-chip/SelectChip.d.ts.map +1 -1
- package/dts/alpha/select-chip/SelectChipControl.d.ts +1 -0
- package/dts/alpha/select-chip/SelectChipControl.d.ts.map +1 -1
- package/dts/alpha/tabbed-chips/TabbedChips.d.ts +5 -0
- package/dts/alpha/tabbed-chips/TabbedChips.d.ts.map +1 -1
- package/dts/chips/Chip.d.ts +1 -1
- package/dts/chips/Chip.d.ts.map +1 -1
- package/dts/chips/ChipProps.d.ts +1 -1
- package/dts/chips/ChipProps.d.ts.map +1 -1
- package/dts/chips/InputChip.d.ts +1 -1
- package/dts/chips/InputChip.d.ts.map +1 -1
- package/dts/chips/MediaChip.d.ts +1 -1
- package/dts/chips/MediaChip.d.ts.map +1 -1
- package/dts/hooks/useHorizontalScrollToTarget.d.ts +10 -0
- package/dts/hooks/useHorizontalScrollToTarget.d.ts.map +1 -1
- package/dts/overlays/drawer/Drawer.d.ts.map +1 -1
- package/dts/overlays/tray/Tray.d.ts +8 -0
- package/dts/overlays/tray/Tray.d.ts.map +1 -1
- package/esm/alpha/combobox/Combobox.js +194 -0
- package/esm/alpha/combobox/DefaultComboboxControl.js +80 -0
- package/esm/alpha/combobox/__stories__/Combobox.stories.js +1019 -0
- package/esm/alpha/select/DefaultSelectControl.js +25 -23
- package/esm/alpha/select/DefaultSelectDropdown.js +80 -75
- package/esm/alpha/select/__stories__/AlphaSelect.stories.js +24 -4
- package/esm/alpha/select-chip/SelectChip.js +8 -5
- package/esm/alpha/select-chip/SelectChipControl.js +6 -2
- package/esm/alpha/select-chip/__stories__/{SelectChip.stories.js → AlphaSelectChip.stories.js} +42 -0
- package/esm/alpha/tabbed-chips/TabbedChips.js +12 -5
- package/esm/alpha/tabbed-chips/__stories__/AlphaTabbedChips.stories.js +9 -1
- package/esm/buttons/__stories__/SlideButton.stories.js +11 -6
- package/esm/carousel/__stories__/Carousel.stories.js +5 -4
- package/esm/hooks/useHorizontalScrollToTarget.js +16 -5
- package/esm/overlays/drawer/Drawer.js +14 -3
- package/esm/overlays/tray/Tray.js +17 -5
- package/esm/visualizations/__stories__/ProgressCircle.stories.js +3 -3
- package/package.json +2 -2
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
const _excluded = ["ComboboxControlComponent"],
|
|
2
|
+
_excluded2 = ["type", "value", "onChange", "options", "open", "setOpen", "label", "placeholder", "disabled", "variant", "startNode", "endNode", "accessibilityLabel", "defaultOpen", "searchText", "onSearch", "defaultSearchText", "closeButtonLabel", "filterFunction", "SelectControlComponent", "ComboboxControlComponent", "SelectDropdownComponent", "hideSearchInput"];
|
|
3
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
4
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
5
|
+
import { createContext, forwardRef, memo, useCallback, useContext, useImperativeHandle, useMemo, useRef, useState } from 'react';
|
|
6
|
+
import { KeyboardAvoidingView, Platform, View } from 'react-native';
|
|
7
|
+
import Fuse from 'fuse.js';
|
|
8
|
+
import { Button } from '../../buttons/Button';
|
|
9
|
+
import { Box } from '../../layout';
|
|
10
|
+
import { StickyFooter } from '../../sticky-footer/StickyFooter';
|
|
11
|
+
import { DefaultSelectControl } from '../select/DefaultSelectControl';
|
|
12
|
+
import { DefaultSelectDropdown } from '../select/DefaultSelectDropdown';
|
|
13
|
+
import { Select } from '../select/Select';
|
|
14
|
+
import { DefaultComboboxControl } from './DefaultComboboxControl';
|
|
15
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
16
|
+
/**
|
|
17
|
+
* Context used for Combobox props needed to render to the ComboboxControlComponent.
|
|
18
|
+
* We use the any type here because the concrete type is not known at this point.
|
|
19
|
+
* The unknown type does not satisfy the SelectType type.
|
|
20
|
+
*/
|
|
21
|
+
const ComboboxContext = /*#__PURE__*/createContext(null);
|
|
22
|
+
const useComboboxContext = () => {
|
|
23
|
+
const context = useContext(ComboboxContext);
|
|
24
|
+
if (!context) {
|
|
25
|
+
throw new Error('Combobox components must be used within ComboboxContext.Provider');
|
|
26
|
+
}
|
|
27
|
+
return context;
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Wraps the ComboboxControlComponent with passed in props and the ComboboxContext values.
|
|
31
|
+
* This allows the usage of all props when wanting to use a custom SelectControlComponent in Combobox.
|
|
32
|
+
* Otherwise, a customer using a custom component would need to use props and context to get the
|
|
33
|
+
* <ComboboxControlComponent> rendering correctly.
|
|
34
|
+
*/
|
|
35
|
+
const ComboboxControlContextAdapter = /*#__PURE__*/memo(_ref => {
|
|
36
|
+
let {
|
|
37
|
+
ComboboxControlComponent
|
|
38
|
+
} = _ref,
|
|
39
|
+
props = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
40
|
+
const {
|
|
41
|
+
searchText,
|
|
42
|
+
onSearch,
|
|
43
|
+
hideSearchInput,
|
|
44
|
+
options
|
|
45
|
+
} = useComboboxContext();
|
|
46
|
+
return /*#__PURE__*/_jsx(ComboboxControlComponent, _extends({}, props, {
|
|
47
|
+
hideSearchInput: hideSearchInput,
|
|
48
|
+
onSearch: onSearch,
|
|
49
|
+
options: options,
|
|
50
|
+
searchText: searchText
|
|
51
|
+
}));
|
|
52
|
+
});
|
|
53
|
+
const ComboboxBase = /*#__PURE__*/memo(/*#__PURE__*/forwardRef((_ref2, ref) => {
|
|
54
|
+
let {
|
|
55
|
+
type = 'single',
|
|
56
|
+
value,
|
|
57
|
+
onChange,
|
|
58
|
+
options,
|
|
59
|
+
open: openProp,
|
|
60
|
+
setOpen: setOpenProp,
|
|
61
|
+
label,
|
|
62
|
+
placeholder,
|
|
63
|
+
disabled,
|
|
64
|
+
variant,
|
|
65
|
+
startNode,
|
|
66
|
+
endNode,
|
|
67
|
+
accessibilityLabel = 'Combobox control',
|
|
68
|
+
defaultOpen,
|
|
69
|
+
searchText: searchTextProp,
|
|
70
|
+
onSearch: onSearchProp,
|
|
71
|
+
defaultSearchText = '',
|
|
72
|
+
closeButtonLabel = 'Done',
|
|
73
|
+
filterFunction,
|
|
74
|
+
SelectControlComponent = DefaultSelectControl,
|
|
75
|
+
ComboboxControlComponent = DefaultComboboxControl,
|
|
76
|
+
SelectDropdownComponent = DefaultSelectDropdown,
|
|
77
|
+
hideSearchInput
|
|
78
|
+
} = _ref2,
|
|
79
|
+
props = _objectWithoutPropertiesLoose(_ref2, _excluded2);
|
|
80
|
+
const [searchTextInternal, setSearchTextInternal] = useState(defaultSearchText);
|
|
81
|
+
const searchText = searchTextProp != null ? searchTextProp : searchTextInternal;
|
|
82
|
+
const setSearchText = onSearchProp != null ? onSearchProp : setSearchTextInternal;
|
|
83
|
+
if (typeof searchTextProp === 'undefined' !== (typeof onSearchProp === 'undefined')) {
|
|
84
|
+
throw Error('Combobox component must be fully controlled or uncontrolled: "searchText" and "onSearch" props must be provided together or not at all');
|
|
85
|
+
}
|
|
86
|
+
const [openInternal, setOpenInternal] = useState(defaultOpen != null ? defaultOpen : false);
|
|
87
|
+
const open = openProp != null ? openProp : openInternal;
|
|
88
|
+
const setOpen = setOpenProp != null ? setOpenProp : setOpenInternal;
|
|
89
|
+
if (typeof openProp === 'undefined' !== (typeof setOpenProp === 'undefined')) throw Error('Combobox component must be fully controlled or uncontrolled: "open" and "setOpen" props must be provided together or not at all');
|
|
90
|
+
const fuse = useMemo(() => new Fuse(options, {
|
|
91
|
+
keys: ['label', 'description'],
|
|
92
|
+
threshold: 0.3
|
|
93
|
+
}), [options]);
|
|
94
|
+
const filteredOptions = useMemo(() => {
|
|
95
|
+
if (searchText.length === 0) return options;
|
|
96
|
+
if (filterFunction) return filterFunction(options, searchText);
|
|
97
|
+
return fuse.search(searchText).map(result => result.item);
|
|
98
|
+
}, [filterFunction, fuse, options, searchText]);
|
|
99
|
+
const handleChange = useCallback(value => {
|
|
100
|
+
onChange == null || onChange(value);
|
|
101
|
+
}, [onChange]);
|
|
102
|
+
const controlRef = useRef(null);
|
|
103
|
+
useImperativeHandle(ref, () => Object.assign(controlRef.current, {
|
|
104
|
+
open,
|
|
105
|
+
setOpen
|
|
106
|
+
}));
|
|
107
|
+
const searchInputRef = useRef(null);
|
|
108
|
+
const handleTrayVisibilityChange = useCallback(visibility => {
|
|
109
|
+
if (visibility === 'visible') {
|
|
110
|
+
var _searchInputRef$curre;
|
|
111
|
+
(_searchInputRef$curre = searchInputRef.current) == null || _searchInputRef$curre.focus();
|
|
112
|
+
}
|
|
113
|
+
}, []);
|
|
114
|
+
const ComboboxControl = useCallback(props => {
|
|
115
|
+
return /*#__PURE__*/_jsx(ComboboxControlContextAdapter, _extends({}, props, {
|
|
116
|
+
ComboboxControlComponent: ComboboxControlComponent,
|
|
117
|
+
SelectControlComponent: SelectControlComponent,
|
|
118
|
+
controlRef: controlRef,
|
|
119
|
+
searchInputRef: searchInputRef
|
|
120
|
+
}));
|
|
121
|
+
}, [ComboboxControlComponent, SelectControlComponent, searchInputRef]);
|
|
122
|
+
const ComboboxDropdown = useCallback(props => /*#__PURE__*/_jsx(SelectDropdownComponent, _extends({
|
|
123
|
+
label: label,
|
|
124
|
+
minHeight: 500
|
|
125
|
+
}, props, {
|
|
126
|
+
footer: /*#__PURE__*/_jsx(KeyboardAvoidingView, {
|
|
127
|
+
behavior: "padding",
|
|
128
|
+
keyboardVerticalOffset: Platform.OS === 'ios' ? 86 : 0,
|
|
129
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
130
|
+
style: Platform.OS === 'android' ? {
|
|
131
|
+
overflow: 'hidden',
|
|
132
|
+
paddingTop: 4
|
|
133
|
+
} : undefined,
|
|
134
|
+
children: /*#__PURE__*/_jsx(StickyFooter, {
|
|
135
|
+
background: "bg",
|
|
136
|
+
elevation: 2,
|
|
137
|
+
style: {
|
|
138
|
+
shadowOffset: {
|
|
139
|
+
width: 0,
|
|
140
|
+
height: -32
|
|
141
|
+
},
|
|
142
|
+
shadowOpacity: 0.05
|
|
143
|
+
},
|
|
144
|
+
children: /*#__PURE__*/_jsx(Button, {
|
|
145
|
+
compact: true,
|
|
146
|
+
onPress: () => setOpen(false),
|
|
147
|
+
children: closeButtonLabel
|
|
148
|
+
})
|
|
149
|
+
})
|
|
150
|
+
})
|
|
151
|
+
}),
|
|
152
|
+
header: /*#__PURE__*/_jsx(Box, {
|
|
153
|
+
paddingX: 3,
|
|
154
|
+
children: /*#__PURE__*/_jsx(ComboboxControl, _extends({
|
|
155
|
+
endNode: endNode,
|
|
156
|
+
placeholder: placeholder,
|
|
157
|
+
startNode: startNode,
|
|
158
|
+
variant: variant
|
|
159
|
+
}, props, {
|
|
160
|
+
label: null,
|
|
161
|
+
styles: undefined
|
|
162
|
+
}))
|
|
163
|
+
}),
|
|
164
|
+
onVisibilityChange: handleTrayVisibilityChange
|
|
165
|
+
})), [ComboboxControl, SelectDropdownComponent, closeButtonLabel, endNode, handleTrayVisibilityChange, label, placeholder, setOpen, startNode, variant]);
|
|
166
|
+
return /*#__PURE__*/_jsx(ComboboxContext.Provider, {
|
|
167
|
+
value: {
|
|
168
|
+
searchText,
|
|
169
|
+
onSearch: setSearchText,
|
|
170
|
+
hideSearchInput: hideSearchInput != null ? hideSearchInput : false,
|
|
171
|
+
options
|
|
172
|
+
},
|
|
173
|
+
children: /*#__PURE__*/_jsx(Select, _extends({
|
|
174
|
+
ref: controlRef,
|
|
175
|
+
SelectControlComponent: ComboboxControl,
|
|
176
|
+
SelectDropdownComponent: ComboboxDropdown,
|
|
177
|
+
accessibilityLabel: accessibilityLabel,
|
|
178
|
+
defaultOpen: defaultOpen,
|
|
179
|
+
disabled: disabled,
|
|
180
|
+
endNode: endNode,
|
|
181
|
+
label: label,
|
|
182
|
+
onChange: handleChange,
|
|
183
|
+
open: open,
|
|
184
|
+
options: filteredOptions,
|
|
185
|
+
placeholder: placeholder,
|
|
186
|
+
setOpen: setOpen,
|
|
187
|
+
startNode: startNode,
|
|
188
|
+
type: type,
|
|
189
|
+
value: value,
|
|
190
|
+
variant: variant
|
|
191
|
+
}, props))
|
|
192
|
+
});
|
|
193
|
+
}));
|
|
194
|
+
export const Combobox = ComboboxBase;
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
const _excluded = ["SelectControlComponent", "value", "placeholder", "open", "setOpen", "disabled", "options", "searchText", "onSearch", "searchInputRef", "hideSearchInput"];
|
|
2
|
+
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
3
|
+
function _objectWithoutPropertiesLoose(r, e) { if (null == r) return {}; var t = {}; for (var n in r) if ({}.hasOwnProperty.call(r, n)) { if (-1 !== e.indexOf(n)) continue; t[n] = r[n]; } return t; }
|
|
4
|
+
import { StyleSheet } from 'react-native';
|
|
5
|
+
import { NativeInput } from '../../controls/NativeInput';
|
|
6
|
+
import { useTheme } from '../../hooks/useTheme';
|
|
7
|
+
import { HStack } from '../../layout';
|
|
8
|
+
import { Text } from '../../typography/Text';
|
|
9
|
+
import { DefaultSelectControl } from '../select/DefaultSelectControl';
|
|
10
|
+
import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
|
|
11
|
+
const hasSelectedValue = currentValue => currentValue !== null && typeof currentValue !== 'undefined' && !(Array.isArray(currentValue) && currentValue.length === 0);
|
|
12
|
+
export const DefaultComboboxControl = _ref => {
|
|
13
|
+
var _props$styles, _props$styles2;
|
|
14
|
+
let {
|
|
15
|
+
SelectControlComponent = DefaultSelectControl,
|
|
16
|
+
value,
|
|
17
|
+
placeholder,
|
|
18
|
+
open,
|
|
19
|
+
setOpen,
|
|
20
|
+
disabled,
|
|
21
|
+
options,
|
|
22
|
+
searchText,
|
|
23
|
+
onSearch,
|
|
24
|
+
searchInputRef,
|
|
25
|
+
hideSearchInput
|
|
26
|
+
} = _ref,
|
|
27
|
+
props = _objectWithoutPropertiesLoose(_ref, _excluded);
|
|
28
|
+
const theme = useTheme();
|
|
29
|
+
const hasValue = hasSelectedValue(value);
|
|
30
|
+
const shouldRenderSearchInput = !hideSearchInput && (!hasValue || open);
|
|
31
|
+
return /*#__PURE__*/_jsx(SelectControlComponent, _extends({
|
|
32
|
+
disabled: disabled,
|
|
33
|
+
open: open,
|
|
34
|
+
options: options,
|
|
35
|
+
setOpen: setOpen,
|
|
36
|
+
value: value
|
|
37
|
+
}, props, {
|
|
38
|
+
contentNode: shouldRenderSearchInput ? /*#__PURE__*/_jsx(HStack, {
|
|
39
|
+
flexWrap: "wrap",
|
|
40
|
+
children: /*#__PURE__*/_jsx(NativeInput, {
|
|
41
|
+
ref: searchInputRef,
|
|
42
|
+
disabled: disabled || !open,
|
|
43
|
+
onChangeText: onSearch,
|
|
44
|
+
onPress: () => !disabled && setOpen(true),
|
|
45
|
+
placeholder: typeof placeholder === 'string' ? placeholder : undefined,
|
|
46
|
+
style: {
|
|
47
|
+
flex: 0,
|
|
48
|
+
flexGrow: 1,
|
|
49
|
+
flexShrink: 1,
|
|
50
|
+
minWidth: 0,
|
|
51
|
+
padding: 0,
|
|
52
|
+
height: hasValue ? 24 : 48,
|
|
53
|
+
marginTop: hasValue ? 0 : -24,
|
|
54
|
+
marginBottom: hasValue ? -12 : -24,
|
|
55
|
+
paddingTop: hasValue ? 8 : 0,
|
|
56
|
+
// This is constrained by the parent container's width. The width is large
|
|
57
|
+
// to ensure it grows to fill the control
|
|
58
|
+
width: open ? '100%' : undefined
|
|
59
|
+
},
|
|
60
|
+
value: searchText
|
|
61
|
+
})
|
|
62
|
+
}) : /*#__PURE__*/_jsx(_Fragment, {
|
|
63
|
+
children: hasValue ? null : /*#__PURE__*/_jsx(Text, {
|
|
64
|
+
color: "fgMuted",
|
|
65
|
+
font: "body",
|
|
66
|
+
paddingY: 0,
|
|
67
|
+
children: typeof placeholder === 'string' ? placeholder : ''
|
|
68
|
+
})
|
|
69
|
+
}),
|
|
70
|
+
placeholder: null,
|
|
71
|
+
styles: _extends({}, props.styles, {
|
|
72
|
+
controlEndNode: _extends({}, StyleSheet.flatten((_props$styles = props.styles) == null ? void 0 : _props$styles.controlEndNode), {
|
|
73
|
+
alignItems: hasValue && shouldRenderSearchInput ? 'flex-end' : 'center'
|
|
74
|
+
}),
|
|
75
|
+
controlValueNode: _extends({}, StyleSheet.flatten((_props$styles2 = props.styles) == null ? void 0 : _props$styles2.controlValueNode), {
|
|
76
|
+
paddingBottom: hasValue && shouldRenderSearchInput ? theme.space[1.5] : 0
|
|
77
|
+
})
|
|
78
|
+
})
|
|
79
|
+
}));
|
|
80
|
+
};
|