@coinbase/cds-mcp-server 8.28.1 → 8.29.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 +8 -0
- package/mcp-docs/mobile/components/Accordion.txt +3 -1
- package/mcp-docs/mobile/components/Alert.txt +3 -1
- package/mcp-docs/mobile/components/Banner.txt +14 -14
- package/mcp-docs/mobile/components/Button.txt +173 -30
- package/mcp-docs/mobile/components/Carousel.txt +24 -24
- package/mcp-docs/mobile/components/Combobox.txt +187 -0
- package/mcp-docs/mobile/components/ContainedAssetCard.txt +4 -4
- package/mcp-docs/mobile/components/ContentCard.txt +29 -27
- package/mcp-docs/mobile/components/ContentCardBody.txt +4 -4
- package/mcp-docs/mobile/components/ContentCardHeader.txt +2 -2
- package/mcp-docs/mobile/components/FloatingAssetCard.txt +6 -6
- package/mcp-docs/mobile/components/IconButton.txt +126 -51
- package/mcp-docs/mobile/components/LineChart.txt +3 -2
- package/mcp-docs/mobile/components/MultiContentModule.txt +6 -6
- package/mcp-docs/mobile/components/Numpad.txt +2 -2
- package/mcp-docs/mobile/components/PageHeader.txt +3 -1
- package/mcp-docs/mobile/components/PeriodSelector.txt +4 -4
- package/mcp-docs/mobile/components/Pressable.txt +6 -2
- package/mcp-docs/mobile/components/ProgressBarWithFixedLabels.txt +4 -4
- package/mcp-docs/mobile/components/ProgressBarWithFloatLabel.txt +2 -2
- package/mcp-docs/mobile/components/ProgressCircle.txt +5 -1
- package/mcp-docs/mobile/components/SelectChip.txt +2 -0
- package/mcp-docs/mobile/components/SelectChipAlpha.txt +1 -1
- package/mcp-docs/mobile/components/SlideButton.txt +2 -2
- package/mcp-docs/mobile/components/Sparkline.txt +3 -1
- package/mcp-docs/mobile/components/SparklineGradient.txt +3 -1
- package/mcp-docs/mobile/components/SparklineInteractiveHeader.txt +3 -1
- package/mcp-docs/mobile/components/TabbedChips.txt +3 -1
- package/mcp-docs/mobile/components/Tag.txt +19 -9
- package/mcp-docs/mobile/components/TextInput.txt +9 -3
- package/mcp-docs/mobile/components/Tray.txt +2 -0
- package/mcp-docs/mobile/components/UpsellCard.txt +16 -16
- package/mcp-docs/mobile/hooks/useDimensions.txt +4 -4
- package/mcp-docs/mobile/hooks/useMergeRefs.txt +4 -4
- package/mcp-docs/mobile/hooks/usePreviousValue.txt +5 -5
- package/mcp-docs/mobile/hooks/useRefMap.txt +6 -6
- package/mcp-docs/mobile/routes.txt +1 -0
- package/mcp-docs/web/components/Accordion.txt +3 -1
- package/mcp-docs/web/components/Alert.txt +3 -1
- package/mcp-docs/web/components/Banner.txt +14 -14
- package/mcp-docs/web/components/Button.txt +188 -34
- package/mcp-docs/web/components/Carousel.txt +71 -65
- package/mcp-docs/web/components/Combobox.txt +176 -0
- package/mcp-docs/web/components/ContainedAssetCard.txt +4 -4
- package/mcp-docs/web/components/ContentCard.txt +29 -27
- package/mcp-docs/web/components/ContentCardBody.txt +4 -4
- package/mcp-docs/web/components/ContentCardHeader.txt +2 -2
- package/mcp-docs/web/components/FloatingAssetCard.txt +6 -6
- package/mcp-docs/web/components/FullscreenModal.txt +12 -4
- package/mcp-docs/web/components/GridColumn.txt +12 -4
- package/mcp-docs/web/components/IconButton.txt +164 -189
- package/mcp-docs/web/components/LineChart.txt +3 -2
- package/mcp-docs/web/components/MultiContentModule.txt +6 -6
- package/mcp-docs/web/components/PageHeader.txt +11 -9
- package/mcp-docs/web/components/ProgressBarWithFixedLabels.txt +4 -4
- package/mcp-docs/web/components/ProgressBarWithFloatLabel.txt +2 -2
- package/mcp-docs/web/components/ProgressCircle.txt +5 -1
- package/mcp-docs/web/components/SelectChipAlpha.txt +1 -1
- package/mcp-docs/web/components/Sidebar.txt +2 -2
- package/mcp-docs/web/components/Sparkline.txt +3 -1
- package/mcp-docs/web/components/SparklineGradient.txt +3 -1
- package/mcp-docs/web/components/SparklineInteractiveHeader.txt +3 -1
- package/mcp-docs/web/components/TabbedChips.txt +3 -1
- package/mcp-docs/web/components/TableBody.txt +2 -2
- package/mcp-docs/web/components/TableCaption.txt +2 -2
- package/mcp-docs/web/components/TableCell.txt +6 -6
- package/mcp-docs/web/components/Tag.txt +19 -9
- package/mcp-docs/web/components/TextInput.txt +9 -3
- package/mcp-docs/web/components/Tray.txt +2 -1
- package/mcp-docs/web/components/UpsellCard.txt +16 -16
- package/mcp-docs/web/hooks/useDimensions.txt +4 -4
- package/mcp-docs/web/hooks/useHasMounted.txt +7 -3
- package/mcp-docs/web/hooks/useIsoEffect.txt +1 -1
- package/mcp-docs/web/hooks/useMergeRefs.txt +4 -4
- package/mcp-docs/web/hooks/useOverlayContentContext.txt +8 -8
- package/mcp-docs/web/hooks/usePreviousValue.txt +5 -5
- package/mcp-docs/web/hooks/useRefMap.txt +6 -6
- package/mcp-docs/web/hooks/useScrollBlocker.txt +1 -1
- package/mcp-docs/web/hooks/useTheme.txt +3 -3
- package/mcp-docs/web/routes.txt +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
# Combobox
|
|
2
|
+
|
|
3
|
+
A flexible combobox component for both single and multi-selection, built for mobile applications with comprehensive accessibility support.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Combobox } from '@coinbase/cds-mobile/alpha/combobox'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Examples
|
|
12
|
+
|
|
13
|
+
### A note on search logic
|
|
14
|
+
|
|
15
|
+
We use [fuse.js](https://www.fusejs.io/) to power the fuzzy search logic for Combobox. You can override this search logic with your own using the `filterFunction` prop.
|
|
16
|
+
|
|
17
|
+
### Multi-Select
|
|
18
|
+
|
|
19
|
+
Basic multi-selection combobox with search.
|
|
20
|
+
|
|
21
|
+
```jsx
|
|
22
|
+
function MultiSelect() {
|
|
23
|
+
const multiSelectOptions = [
|
|
24
|
+
{ value: '1', label: 'Option 1' },
|
|
25
|
+
{ value: '2', label: 'Option 2' },
|
|
26
|
+
{ value: '3', label: 'Option 3' },
|
|
27
|
+
{ value: '4', label: 'Option 4' },
|
|
28
|
+
{ value: '5', label: 'Option 5' },
|
|
29
|
+
{ value: '6', label: 'Option 6' },
|
|
30
|
+
{ value: '7', label: 'Option 7' },
|
|
31
|
+
{ value: '8', label: 'Option 8' },
|
|
32
|
+
{ value: '9', label: 'Option 9' },
|
|
33
|
+
{ value: '10', label: 'Option 10' },
|
|
34
|
+
];
|
|
35
|
+
const { value, onChange } = useMultiSelect({ initialValue: ['1'] });
|
|
36
|
+
|
|
37
|
+
return (
|
|
38
|
+
<Combobox
|
|
39
|
+
label="Multi Select"
|
|
40
|
+
onChange={onChange}
|
|
41
|
+
options={multiSelectOptions}
|
|
42
|
+
placeholder="Search..."
|
|
43
|
+
type="multi"
|
|
44
|
+
value={value}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Single Select
|
|
51
|
+
|
|
52
|
+
Single selection combobox with an option to clear the current choice.
|
|
53
|
+
|
|
54
|
+
```jsx
|
|
55
|
+
function SingleSelect() {
|
|
56
|
+
const singleSelectOptions = [
|
|
57
|
+
{ value: null, label: 'Remove selection' },
|
|
58
|
+
{ value: '1', label: 'Option 1' },
|
|
59
|
+
{ value: '2', label: 'Option 2' },
|
|
60
|
+
{ value: '3', label: 'Option 3' },
|
|
61
|
+
];
|
|
62
|
+
const [value, setValue] = useState(null);
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<Combobox
|
|
66
|
+
label="Single Select"
|
|
67
|
+
onChange={setValue}
|
|
68
|
+
options={singleSelectOptions}
|
|
69
|
+
placeholder="Search..."
|
|
70
|
+
value={value}
|
|
71
|
+
/>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Controlled Search
|
|
77
|
+
|
|
78
|
+
Manage the search text externally while letting the combobox stay in sync.
|
|
79
|
+
|
|
80
|
+
```jsx
|
|
81
|
+
function ControlledSearch() {
|
|
82
|
+
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
83
|
+
const [searchText, setSearchText] = useState('');
|
|
84
|
+
|
|
85
|
+
const fruitOptions = [
|
|
86
|
+
{ value: 'apple', label: 'Apple' },
|
|
87
|
+
{ value: 'banana', label: 'Banana' },
|
|
88
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
89
|
+
{ value: 'date', label: 'Date' },
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
return (
|
|
93
|
+
<Combobox
|
|
94
|
+
label="Controlled search"
|
|
95
|
+
onChange={onChange}
|
|
96
|
+
onSearch={setSearchText}
|
|
97
|
+
options={fruitOptions}
|
|
98
|
+
placeholder="Type to search..."
|
|
99
|
+
searchText={searchText}
|
|
100
|
+
type="multi"
|
|
101
|
+
value={value}
|
|
102
|
+
/>
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Helper Text
|
|
108
|
+
|
|
109
|
+
Use helper text to guide how many selections a user should make.
|
|
110
|
+
|
|
111
|
+
```jsx
|
|
112
|
+
function HelperTextExample() {
|
|
113
|
+
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
114
|
+
|
|
115
|
+
const teamOptions = [
|
|
116
|
+
{ value: 'john', label: 'John Smith', description: 'Engineering' },
|
|
117
|
+
{ value: 'jane', label: 'Jane Doe', description: 'Design' },
|
|
118
|
+
{ value: 'bob', label: 'Bob Johnson', description: 'Product' },
|
|
119
|
+
{ value: 'alice', label: 'Alice Williams', description: 'Engineering' },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<Combobox
|
|
124
|
+
helperText="Select up to 4 team members"
|
|
125
|
+
label="Team members"
|
|
126
|
+
onChange={onChange}
|
|
127
|
+
options={teamOptions}
|
|
128
|
+
placeholder="Search team members..."
|
|
129
|
+
type="multi"
|
|
130
|
+
value={value}
|
|
131
|
+
/>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Props
|
|
137
|
+
|
|
138
|
+
| Prop | Type | Required | Default | Description |
|
|
139
|
+
| --- | --- | --- | --- | --- |
|
|
140
|
+
| `onChange` | `(value: Type extends multi ? SelectOptionValue \| SelectOptionValue[] \| null : SelectOptionValue \| null) => void` | Yes | `-` | - |
|
|
141
|
+
| `options` | `SelectOptionList<Type, SelectOptionValue>` | Yes | `-` | Array of options to display in the select dropdown. Can be individual options or groups with label and options |
|
|
142
|
+
| `value` | `string \| SelectOptionValue[] \| null` | Yes | `-` | - |
|
|
143
|
+
| `ComboboxControlComponent` | `ComboboxControlComponent` | No | `-` | - |
|
|
144
|
+
| `ComboboxDropdownComponent` | `SelectDropdownComponent` | No | `-` | - |
|
|
145
|
+
| `SelectAllOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the Select All option |
|
|
146
|
+
| `SelectControlComponent` | `SelectControlComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the select control |
|
|
147
|
+
| `SelectDropdownComponent` | `SelectDropdownComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render the dropdown container |
|
|
148
|
+
| `SelectEmptyDropdownContentsComponent` | `SelectEmptyDropdownContentComponent` | No | `-` | Custom component to render when no options are available |
|
|
149
|
+
| `SelectOptionComponent` | `SelectOptionComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render individual options |
|
|
150
|
+
| `SelectOptionGroupComponent` | `SelectOptionGroupComponent<Type, SelectOptionValue>` | No | `-` | Custom component to render group headers |
|
|
151
|
+
| `accessibilityRoles` | `{ option?: AccessibilityRole; } \| undefined` | No | `-` | Accessibility roles for dropdown elements |
|
|
152
|
+
| `accessory` | `ReactElement<CellAccessoryProps, string \| JSXElementConstructor<any>>` | No | `-` | - |
|
|
153
|
+
| `clearAllLabel` | `string` | No | `-` | Label for the Clear All option in multi-select mode |
|
|
154
|
+
| `closeButtonLabel` | `string` | No | `-` | Label for close button when combobox is open (mobile only) |
|
|
155
|
+
| `compact` | `boolean` | No | `-` | Whether to use compact styling for the select |
|
|
156
|
+
| `defaultOpen` | `boolean` | No | `-` | Initial open state when component mounts (uncontrolled mode) |
|
|
157
|
+
| `defaultSearchText` | `string` | No | `-` | Default search text value for uncontrolled mode |
|
|
158
|
+
| `disableClickOutsideClose` | `boolean` | No | `-` | Whether clicking outside the dropdown should close it |
|
|
159
|
+
| `disabled` | `boolean` | No | `false` | Toggles input interactability and opacity |
|
|
160
|
+
| `emptyOptionsLabel` | `string` | No | `-` | Label displayed when there are no options available |
|
|
161
|
+
| `end` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | End-aligned content (e.g., value, status). Replaces the deprecated detail prop. |
|
|
162
|
+
| `endNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the end of the inner input. Refer to diagram for location of endNode in InputStack component |
|
|
163
|
+
| `filterFunction` | `((options: SelectOptionList<Type, SelectOptionValue>, searchText: string) => SelectOption<SelectOptionValue>[])` | No | `-` | Custom filter function for searching options |
|
|
164
|
+
| `helperText` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Helper text displayed below the select |
|
|
165
|
+
| `hiddenSelectedOptionsLabel` | `string` | No | `-` | Label to show for showcasing count of hidden selected options |
|
|
166
|
+
| `hideSearchInput` | `boolean` | No | `-` | Hide the search input |
|
|
167
|
+
| `hideSelectAll` | `boolean` | No | `-` | Whether to hide the Select All option in multi-select mode |
|
|
168
|
+
| `label` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Label displayed above the control |
|
|
169
|
+
| `labelVariant` | `inside \| outside` | No | `'outside'` | The variant of the label. Only used when compact is not true. |
|
|
170
|
+
| `maxSelectedOptionsToShow` | `number` | No | `-` | Maximum number of selected options to show before truncating |
|
|
171
|
+
| `media` | `ReactElement` | No | `-` | Media rendered at the start of the cell (icon, avatar, image, etc). |
|
|
172
|
+
| `onSearch` | `((searchText: string) => void)` | No | `-` | Search text change handler |
|
|
173
|
+
| `open` | `boolean` | No | `-` | Controlled open state of the dropdown |
|
|
174
|
+
| `placeholder` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Placeholder text displayed when no option is selected |
|
|
175
|
+
| `ref` | `null \| (instance: SelectRef \| null) => void \| RefObject<SelectRef>` | No | `-` | - |
|
|
176
|
+
| `removeSelectedOptionAccessibilityLabel` | `string` | No | `-` | Accessibility label for each chip in a multi-select |
|
|
177
|
+
| `searchText` | `string` | No | `-` | Controlled search text value |
|
|
178
|
+
| `selectAllLabel` | `string` | No | `-` | Label for the Select All option in multi-select mode |
|
|
179
|
+
| `setOpen` | `((open: boolean \| ((open: boolean) => boolean)) => void)` | No | `-` | Callback to update the open state |
|
|
180
|
+
| `startNode` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | Adds content to the start of the inner input. Refer to diagram for location of startNode in InputStack component |
|
|
181
|
+
| `style` | `null \| false \| ViewStyle \| RegisteredStyle<ViewStyle> \| RecursiveArray<ViewStyle \| Falsy \| RegisteredStyle<ViewStyle>>` | No | `-` | Inline styles for the root element |
|
|
182
|
+
| `styles` | `{ root?: StyleProp<ViewStyle>; control?: StyleProp<ViewStyle>; controlStartNode?: StyleProp<ViewStyle>; controlInputNode?: StyleProp<ViewStyle>; controlValueNode?: StyleProp<ViewStyle>; controlLabelNode?: StyleProp<ViewStyle>; controlHelperTextNode?: StyleProp<ViewStyle>; controlEndNode?: StyleProp<ViewStyle>; controlBlendStyles?: InteractableBlendStyles; dropdown?: StyleProp<ViewStyle>; option?: StyleProp<ViewStyle>; optionCell?: StyleProp<ViewStyle>; optionContent?: StyleProp<ViewStyle>; optionLabel?: StyleProp<ViewStyle>; optionDescription?: StyleProp<ViewStyle>; optionBlendStyles?: InteractableBlendStyles \| undefined; selectAllDivider?: StyleProp<ViewStyle>; emptyContentsContainer?: StyleProp<ViewStyle>; emptyContentsText?: StyleProp<ViewStyle>; optionGroup?: StyleProp<ViewStyle>; } \| undefined` | No | `-` | Custom styles for different parts of the select |
|
|
183
|
+
| `testID` | `string` | No | `-` | Test ID for the root element |
|
|
184
|
+
| `type` | `multi \| single` | No | `-` | Whether the select allows single or multiple selections |
|
|
185
|
+
| `variant` | `primary \| secondary \| positive \| negative \| foregroundMuted \| foreground` | No | `-` | Determines the sentiment of the input. Because we allow startContent and endContent to be custom ReactNode, the content placed inside these slots will not change colors according to the variant. You will have to add that yourself |
|
|
186
|
+
|
|
187
|
+
|
|
@@ -23,9 +23,9 @@ function Example() {
|
|
|
23
23
|
{
|
|
24
24
|
title: '$4.15',
|
|
25
25
|
description: (
|
|
26
|
-
<
|
|
26
|
+
<Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
|
|
27
27
|
↗73.37%
|
|
28
|
-
</
|
|
28
|
+
</Text>
|
|
29
29
|
),
|
|
30
30
|
subtitle: 'ETH',
|
|
31
31
|
onPress: NoopFn,
|
|
@@ -55,9 +55,9 @@ function Example() {
|
|
|
55
55
|
{
|
|
56
56
|
title: '$309.43',
|
|
57
57
|
description: (
|
|
58
|
-
<
|
|
58
|
+
<Text as="p" font="label2" color="fgPositive" numberOfLines={2}>
|
|
59
59
|
↗3.37%
|
|
60
|
-
</
|
|
60
|
+
</Text>
|
|
61
61
|
),
|
|
62
62
|
subtitle: 'Bitcoin',
|
|
63
63
|
onPress: NoopFn,
|
|
@@ -30,9 +30,9 @@ function Example() {
|
|
|
30
30
|
}
|
|
31
31
|
meta={
|
|
32
32
|
<Box marginLeft={-1}>
|
|
33
|
-
<
|
|
33
|
+
<Text as="span" font="label2" color="fgMuted" marginLeft={-1} numberOfLines={1}>
|
|
34
34
|
・News・5 hrs
|
|
35
|
-
</
|
|
35
|
+
</Text>
|
|
36
36
|
</Box>
|
|
37
37
|
}
|
|
38
38
|
title="Description"
|
|
@@ -41,12 +41,12 @@ function Example() {
|
|
|
41
41
|
body="Bitcoin Network Shatters Records With Hashrate Climbing to 464 EH/s"
|
|
42
42
|
label={
|
|
43
43
|
<HStack alignItems="flex-end" flexWrap="wrap" gap={0.5}>
|
|
44
|
-
<
|
|
44
|
+
<Text as="p" font="label2" color="fgMuted" numberOfLines={1}>
|
|
45
45
|
BTC
|
|
46
|
-
</
|
|
47
|
-
<
|
|
46
|
+
</Text>
|
|
47
|
+
<Text font="label2" accessibilityLabel="Up 5.12%" as="p" color="fgPositive">
|
|
48
48
|
↗ 5.12%
|
|
49
|
-
</
|
|
49
|
+
</Text>
|
|
50
50
|
</HStack>
|
|
51
51
|
}
|
|
52
52
|
/>
|
|
@@ -55,9 +55,9 @@ function Example() {
|
|
|
55
55
|
<ContentCardHeader
|
|
56
56
|
meta={
|
|
57
57
|
<Box marginLeft={-1}>
|
|
58
|
-
<
|
|
58
|
+
<Text as="span" font="label2" color="fgMuted" numberOfLines={1}>
|
|
59
59
|
・News・5 hrs
|
|
60
|
-
</
|
|
60
|
+
</Text>
|
|
61
61
|
</Box>
|
|
62
62
|
}
|
|
63
63
|
title="Brian Armstrong"
|
|
@@ -66,12 +66,12 @@ function Example() {
|
|
|
66
66
|
body="Bitcoin Network Shatters Records With Hashrate Climbing to 464 EH/s"
|
|
67
67
|
label={
|
|
68
68
|
<HStack alignItems="flex-end" flexWrap="wrap" gap={0.5}>
|
|
69
|
-
<
|
|
69
|
+
<Text as="p" font="label2" color="fgMuted" numberOfLines={1}>
|
|
70
70
|
BTC
|
|
71
|
-
</
|
|
72
|
-
<
|
|
71
|
+
</Text>
|
|
72
|
+
<Text font="label2" accessibilityLabel="Up 5.12%" as="p" color="fgPositive">
|
|
73
73
|
↗ 5.12%
|
|
74
|
-
</
|
|
74
|
+
</Text>
|
|
75
75
|
</HStack>
|
|
76
76
|
}
|
|
77
77
|
media={
|
|
@@ -130,18 +130,18 @@ function Example() {
|
|
|
130
130
|
<ContentCard gap={3}>
|
|
131
131
|
<ContentCardBody
|
|
132
132
|
body={
|
|
133
|
-
<
|
|
133
|
+
<Text as="p" font="body" paddingTop={0.5}>
|
|
134
134
|
Bitcoin Network Shatters Records With Hashrate Climbing to 464 EH/s
|
|
135
|
-
</
|
|
135
|
+
</Text>
|
|
136
136
|
}
|
|
137
137
|
label={
|
|
138
138
|
<HStack alignItems="flex-end" flexWrap="wrap" gap={0.5}>
|
|
139
|
-
<
|
|
139
|
+
<Text as="p" font="label2" color="fgMuted" numberOfLines={1}>
|
|
140
140
|
BTC
|
|
141
|
-
</
|
|
142
|
-
<
|
|
141
|
+
</Text>
|
|
142
|
+
<Text font="label2" accessibilityLabel="Up 5.12%" as="p" color="fgPositive">
|
|
143
143
|
↗ 5.12%
|
|
144
|
-
</
|
|
144
|
+
</Text>
|
|
145
145
|
</HStack>
|
|
146
146
|
}
|
|
147
147
|
media={
|
|
@@ -165,7 +165,9 @@ function Example() {
|
|
|
165
165
|
<TextLegal as="span" color="fgMuted">
|
|
166
166
|
Reward
|
|
167
167
|
</TextLegal>
|
|
168
|
-
<
|
|
168
|
+
<Text as="span" font="headline">
|
|
169
|
+
+$15 ACS
|
|
170
|
+
</Text>
|
|
169
171
|
</VStack>
|
|
170
172
|
</HStack>
|
|
171
173
|
<Button compact accessibilityLabel="Claim now" variant="secondary">
|
|
@@ -203,9 +205,9 @@ function Example() {
|
|
|
203
205
|
}
|
|
204
206
|
meta={
|
|
205
207
|
<Box marginLeft={-1}>
|
|
206
|
-
<
|
|
208
|
+
<Text as="span" font="label2" color="fgMuted" numberOfLines={1}>
|
|
207
209
|
@matdryhurst・7 mo
|
|
208
|
-
</
|
|
210
|
+
</Text>
|
|
209
211
|
</Box>
|
|
210
212
|
}
|
|
211
213
|
title="Mat Dryhurst"
|
|
@@ -220,9 +222,9 @@ function Example() {
|
|
|
220
222
|
avatar="/img/card/content_card_custom_avatar_1.png"
|
|
221
223
|
meta={
|
|
222
224
|
<Box marginLeft={-1}>
|
|
223
|
-
<
|
|
225
|
+
<Text as="span" font="label2" color="fgMuted" numberOfLines={1}>
|
|
224
226
|
・News・5 hrs
|
|
225
|
-
</
|
|
227
|
+
</Text>
|
|
226
228
|
</Box>
|
|
227
229
|
}
|
|
228
230
|
title="Description"
|
|
@@ -240,12 +242,12 @@ function Example() {
|
|
|
240
242
|
gap={1.5}
|
|
241
243
|
label={
|
|
242
244
|
<HStack alignItems="flex-end" flexWrap="wrap" gap={0.5}>
|
|
243
|
-
<
|
|
245
|
+
<Text as="p" font="label2" color="fgMuted" numberOfLines={1}>
|
|
244
246
|
BTC
|
|
245
|
-
</
|
|
246
|
-
<
|
|
247
|
+
</Text>
|
|
248
|
+
<Text font="label2" accessibilityLabel="Up 5.12%" as="p" color="fgPositive">
|
|
247
249
|
↗ 5.12%
|
|
248
|
-
</
|
|
250
|
+
</Text>
|
|
249
251
|
</HStack>
|
|
250
252
|
}
|
|
251
253
|
paddingBottom={3}
|
|
@@ -18,12 +18,12 @@ import { ContentCardBody } from '@coinbase/cds-mobile/cards/ContentCard'
|
|
|
18
18
|
body="Bitcoin Network Shatters Records With Hashrate Climbing to 464 EH/s"
|
|
19
19
|
label={
|
|
20
20
|
<HStack alignItems="flex-end" flexWrap="wrap" gap={0.5}>
|
|
21
|
-
<
|
|
21
|
+
<Text as="p" font="label2" color="fgMuted" numberOfLines={1}>
|
|
22
22
|
BTC
|
|
23
|
-
</
|
|
24
|
-
<
|
|
23
|
+
</Text>
|
|
24
|
+
<Text font="label2" accessibilityLabel="Up 5.12%" as="p" color="fgPositive">
|
|
25
25
|
↗ 5.12%
|
|
26
|
-
</
|
|
26
|
+
</Text>
|
|
27
27
|
</HStack>
|
|
28
28
|
}
|
|
29
29
|
/>
|
|
@@ -20,9 +20,9 @@ function Example() {
|
|
|
20
20
|
avatar="/img/card/content_card_custom_avatar_1.png"
|
|
21
21
|
meta={
|
|
22
22
|
<Box marginLeft={-1}>
|
|
23
|
-
<
|
|
23
|
+
<Text as="span" font="label2" color="fgMuted" numberOfLines={1}>
|
|
24
24
|
・News・5 hrs
|
|
25
|
-
</
|
|
25
|
+
</Text>
|
|
26
26
|
</Box>
|
|
27
27
|
}
|
|
28
28
|
title="Description"
|
|
@@ -58,9 +58,9 @@ function Example() {
|
|
|
58
58
|
{
|
|
59
59
|
title: '#7560',
|
|
60
60
|
description: (
|
|
61
|
-
<
|
|
61
|
+
<Text font="label2" color="fgPositive" numberOfLines={2}>
|
|
62
62
|
↗6.37%
|
|
63
|
-
</
|
|
63
|
+
</Text>
|
|
64
64
|
),
|
|
65
65
|
subtitle: 'Bored Ape',
|
|
66
66
|
onPress: NoopFn,
|
|
@@ -76,9 +76,9 @@ function Example() {
|
|
|
76
76
|
{
|
|
77
77
|
title: '#2015',
|
|
78
78
|
description: (
|
|
79
|
-
<
|
|
79
|
+
<Text font="label2" color="fgNegative" numberOfLines={2}>
|
|
80
80
|
↘6.37%
|
|
81
|
-
</
|
|
81
|
+
</Text>
|
|
82
82
|
),
|
|
83
83
|
subtitle: 'Pudgy Penguins',
|
|
84
84
|
onPress: NoopFn,
|
|
@@ -115,9 +115,9 @@ function Example() {
|
|
|
115
115
|
{
|
|
116
116
|
title: 'Parallel',
|
|
117
117
|
description: (
|
|
118
|
-
<
|
|
118
|
+
<Text font="label2" color="fgMuted" numberOfLines={2}>
|
|
119
119
|
★4.5
|
|
120
|
-
</
|
|
120
|
+
</Text>
|
|
121
121
|
),
|
|
122
122
|
onPress: NoopFn,
|
|
123
123
|
media: (
|
|
@@ -10,19 +10,23 @@ import { IconButton } from '@coinbase/cds-mobile/buttons/IconButton'
|
|
|
10
10
|
|
|
11
11
|
## Examples
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
IconButton is a compact button that displays only an icon. Use it for actions where the icon alone clearly communicates the purpose.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### Basics
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
The only required props are `name` (which determines the icon) and `accessibilityLabel` (for screen readers).
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
```jsx
|
|
20
|
+
<HStack gap={2}>
|
|
21
|
+
<IconButton name="gear" accessibilityLabel="Open settings" onPress={console.log} />
|
|
22
|
+
<IconButton name="close" accessibilityLabel="Close modal" onPress={console.log} />
|
|
23
|
+
<IconButton name="refresh" accessibilityLabel="Refresh data" onPress={console.log} />
|
|
24
|
+
</HStack>
|
|
25
|
+
```
|
|
20
26
|
|
|
21
|
-
|
|
22
|
-
action, you can setup your system using `accessibilityLabelledBy` prop mapping to the `id` on the
|
|
23
|
-
label node (See [Composed example](#composed-example)).
|
|
27
|
+
### Variants
|
|
24
28
|
|
|
25
|
-
|
|
29
|
+
Use variants to denote intent and importance. The `active` prop fills the icon when enabled.
|
|
26
30
|
|
|
27
31
|
```jsx
|
|
28
32
|
<HStack gap={2}>
|
|
@@ -42,7 +46,7 @@ label node (See [Composed example](#composed-example)).
|
|
|
42
46
|
/>
|
|
43
47
|
<IconButton
|
|
44
48
|
name="phone"
|
|
45
|
-
accessibilityLabel="
|
|
49
|
+
accessibilityLabel="Call support"
|
|
46
50
|
variant="tertiary"
|
|
47
51
|
onPress={console.log}
|
|
48
52
|
/>
|
|
@@ -55,54 +59,107 @@ label node (See [Composed example](#composed-example)).
|
|
|
55
59
|
</HStack>
|
|
56
60
|
```
|
|
57
61
|
|
|
58
|
-
|
|
62
|
+
#### Transparent
|
|
59
63
|
|
|
60
|
-
Use the `transparent` prop to
|
|
64
|
+
Use the `transparent` prop to remove the background until the user interacts with the button.
|
|
61
65
|
|
|
62
66
|
```jsx
|
|
63
|
-
<
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
<HStack gap={2}>
|
|
68
|
+
<IconButton
|
|
69
|
+
active
|
|
70
|
+
name="orderHistory"
|
|
71
|
+
accessibilityLabel="View past order history"
|
|
72
|
+
variant="primary"
|
|
73
|
+
transparent
|
|
74
|
+
onPress={console.log}
|
|
75
|
+
/>
|
|
76
|
+
<IconButton
|
|
77
|
+
active
|
|
78
|
+
name="gear"
|
|
79
|
+
accessibilityLabel="Update settings"
|
|
80
|
+
variant="secondary"
|
|
81
|
+
transparent
|
|
82
|
+
onPress={console.log}
|
|
83
|
+
/>
|
|
84
|
+
<IconButton
|
|
85
|
+
name="phone"
|
|
86
|
+
accessibilityLabel="Call support"
|
|
87
|
+
variant="tertiary"
|
|
88
|
+
transparent
|
|
89
|
+
onPress={console.log}
|
|
90
|
+
/>
|
|
91
|
+
<IconButton
|
|
92
|
+
name="checkmark"
|
|
93
|
+
accessibilityLabel="Verify your identity"
|
|
94
|
+
variant="foregroundMuted"
|
|
95
|
+
transparent
|
|
96
|
+
onPress={console.log}
|
|
97
|
+
/>
|
|
98
|
+
</HStack>
|
|
71
99
|
```
|
|
72
100
|
|
|
73
|
-
###
|
|
101
|
+
### States
|
|
102
|
+
|
|
103
|
+
#### Loading
|
|
74
104
|
|
|
75
|
-
Use the `loading` prop to show a spinner
|
|
105
|
+
Use the `loading` prop to show a spinner when an action is in progress. The button becomes non-interactive and displays a loading spinner instead of the icon.
|
|
76
106
|
|
|
77
107
|
```jsx
|
|
78
|
-
<
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
108
|
+
<HStack gap={2}>
|
|
109
|
+
<IconButton
|
|
110
|
+
active
|
|
111
|
+
name="orderHistory"
|
|
112
|
+
accessibilityLabel="Loading transaction history"
|
|
113
|
+
variant="primary"
|
|
114
|
+
loading
|
|
115
|
+
onPress={console.log}
|
|
116
|
+
/>
|
|
117
|
+
<IconButton
|
|
118
|
+
active
|
|
119
|
+
name="gear"
|
|
120
|
+
accessibilityLabel="Loading settings"
|
|
121
|
+
variant="secondary"
|
|
122
|
+
loading
|
|
123
|
+
onPress={console.log}
|
|
124
|
+
/>
|
|
125
|
+
</HStack>
|
|
86
126
|
```
|
|
87
127
|
|
|
88
|
-
|
|
128
|
+
#### Disabled
|
|
89
129
|
|
|
90
130
|
Use the `disabled` prop to prevent interaction and show a disabled visual state.
|
|
91
131
|
|
|
92
132
|
```jsx
|
|
93
|
-
<
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
133
|
+
<HStack gap={2}>
|
|
134
|
+
<IconButton
|
|
135
|
+
active
|
|
136
|
+
name="orderHistory"
|
|
137
|
+
accessibilityLabel="View transaction history"
|
|
138
|
+
variant="primary"
|
|
139
|
+
disabled
|
|
140
|
+
onPress={console.log}
|
|
141
|
+
/>
|
|
142
|
+
<IconButton
|
|
143
|
+
active
|
|
144
|
+
name="gear"
|
|
145
|
+
accessibilityLabel="View settings"
|
|
146
|
+
variant="secondary"
|
|
147
|
+
disabled
|
|
148
|
+
onPress={console.log}
|
|
149
|
+
/>
|
|
150
|
+
<IconButton
|
|
151
|
+
name="checkmark"
|
|
152
|
+
accessibilityLabel="Approve transaction"
|
|
153
|
+
variant="foregroundMuted"
|
|
154
|
+
disabled
|
|
155
|
+
onPress={console.log}
|
|
156
|
+
/>
|
|
157
|
+
</HStack>
|
|
101
158
|
```
|
|
102
159
|
|
|
103
160
|
### Sizing
|
|
104
161
|
|
|
105
|
-
IconButtons are compact by default.
|
|
162
|
+
IconButtons are compact by default. Use `compact={false}` for larger touch targets.
|
|
106
163
|
|
|
107
164
|
```jsx
|
|
108
165
|
<HStack gap={2} alignItems="center">
|
|
@@ -125,28 +182,39 @@ IconButtons are compact by default. Set the `compact` prop to `false` for larger
|
|
|
125
182
|
</HStack>
|
|
126
183
|
```
|
|
127
184
|
|
|
128
|
-
###
|
|
185
|
+
### Accessibility
|
|
129
186
|
|
|
130
|
-
|
|
187
|
+
Since icon buttons have no visible text, an `accessibilityLabel` is required to describe the button's purpose for screen readers.
|
|
131
188
|
|
|
132
189
|
```jsx
|
|
133
|
-
|
|
190
|
+
<IconButton name="close" accessibilityLabel="Close trade modal" />
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
When composing a button with a visible label, use `accessibilityLabelledBy` to reference the label's `id` instead. See the [Claim Drop example](#claim-drop) below.
|
|
194
|
+
|
|
195
|
+
### Composed Examples
|
|
196
|
+
|
|
197
|
+
#### Claim Drop
|
|
198
|
+
|
|
199
|
+
A toggleable icon button with an adjacent label. Uses `accessibilityLabelledBy` to associate the button with its visible label.
|
|
200
|
+
|
|
201
|
+
```jsx
|
|
202
|
+
function ClaimDropExample() {
|
|
134
203
|
const [active, setActive] = useState(false);
|
|
135
|
-
const name = useMemo(() => (active ? 'dropsActive' : 'dropsInactive'), [active]);
|
|
136
204
|
const variant = useMemo(() => (active ? 'primary' : 'foregroundMuted'), [active]);
|
|
137
205
|
const label = useMemo(() => (active ? 'Reject drop' : 'Claim drop'), [active]);
|
|
138
206
|
|
|
139
207
|
return (
|
|
140
208
|
<HStack gap={2} alignItems="center">
|
|
141
209
|
<IconButton
|
|
142
|
-
name=
|
|
210
|
+
name="drops"
|
|
211
|
+
active={active}
|
|
143
212
|
variant={variant}
|
|
144
213
|
onPress={() => setActive((active) => !active)}
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
accessibilityLabelledBy="my-label--id"
|
|
214
|
+
id="claim-drop-button"
|
|
215
|
+
accessibilityLabelledBy="claim-drop-label"
|
|
148
216
|
/>
|
|
149
|
-
<Text font="label1"
|
|
217
|
+
<Text font="label1" id="claim-drop-label">
|
|
150
218
|
{label}
|
|
151
219
|
</Text>
|
|
152
220
|
</HStack>
|
|
@@ -154,12 +222,19 @@ function composedExample() {
|
|
|
154
222
|
}
|
|
155
223
|
```
|
|
156
224
|
|
|
157
|
-
|
|
225
|
+
#### Notification Bell
|
|
158
226
|
|
|
159
|
-
|
|
227
|
+
An icon button with a badge showing the notification count. Uses `DotCount` to display the number of unread notifications.
|
|
160
228
|
|
|
161
229
|
```jsx
|
|
162
|
-
<
|
|
230
|
+
<DotCount count={3} overlap="circular" pin="top-end">
|
|
231
|
+
<IconButton
|
|
232
|
+
name="bell"
|
|
233
|
+
accessibilityLabel="Notifications, 3 unread"
|
|
234
|
+
variant="secondary"
|
|
235
|
+
onPress={console.log}
|
|
236
|
+
/>
|
|
237
|
+
</DotCount>
|
|
163
238
|
```
|
|
164
239
|
|
|
165
240
|
## Props
|