@coinbase/cds-mcp-server 8.52.2 → 8.53.1
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/Alert.txt +1 -1
- package/mcp-docs/mobile/components/AreaChart.txt +2 -0
- package/mcp-docs/mobile/components/BarChart.txt +33 -0
- package/mcp-docs/mobile/components/CartesianChart.txt +2 -0
- package/mcp-docs/mobile/components/Combobox.txt +380 -83
- package/mcp-docs/mobile/components/HeroSquare.txt +1 -1
- package/mcp-docs/mobile/components/InputChip.txt +75 -9
- package/mcp-docs/mobile/components/LineChart.txt +232 -112
- package/mcp-docs/mobile/components/MediaChip.txt +49 -26
- package/mcp-docs/mobile/components/NudgeCard.txt +1 -1
- package/mcp-docs/mobile/components/Pictogram.txt +1 -1
- package/mcp-docs/mobile/components/Scrubber.txt +2 -0
- package/mcp-docs/mobile/components/SelectChipAlpha.txt +52 -40
- package/mcp-docs/mobile/components/SpotIcon.txt +1 -1
- package/mcp-docs/mobile/components/SpotRectangle.txt +1 -1
- package/mcp-docs/mobile/components/SpotSquare.txt +1 -1
- package/mcp-docs/mobile/routes.txt +1 -1
- package/mcp-docs/web/components/Alert.txt +1 -1
- package/mcp-docs/web/components/Combobox.txt +422 -83
- package/mcp-docs/web/components/FullscreenAlert.txt +1 -1
- package/mcp-docs/web/components/HeroSquare.txt +1 -1
- package/mcp-docs/web/components/InputChip.txt +75 -9
- package/mcp-docs/web/components/Legend.txt +6 -6
- package/mcp-docs/web/components/LineChart.txt +16 -16
- package/mcp-docs/web/components/MediaChip.txt +49 -26
- package/mcp-docs/web/components/NudgeCard.txt +1 -1
- package/mcp-docs/web/components/Pictogram.txt +1 -1
- package/mcp-docs/web/components/SegmentedControl.txt +174 -0
- package/mcp-docs/web/components/SelectChipAlpha.txt +47 -13
- package/mcp-docs/web/components/SpotIcon.txt +1 -1
- package/mcp-docs/web/components/SpotRectangle.txt +1 -1
- package/mcp-docs/web/components/SpotSquare.txt +1 -1
- package/mcp-docs/web/components/TileButton.txt +1 -1
- package/mcp-docs/web/routes.txt +2 -1
- package/package.json +1 -1
|
@@ -10,13 +10,35 @@ import { Combobox } from '@coinbase/cds-mobile/alpha/combobox'
|
|
|
10
10
|
|
|
11
11
|
## Examples
|
|
12
12
|
|
|
13
|
-
###
|
|
13
|
+
### Basics
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
To start, you can provide a label, an array of options, control state.
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
```jsx
|
|
18
|
+
function SingleSelect() {
|
|
19
|
+
const singleSelectOptions = [
|
|
20
|
+
{ value: null, label: 'Remove selection' },
|
|
21
|
+
{ value: '1', label: 'Option 1' },
|
|
22
|
+
{ value: '2', label: 'Option 2' },
|
|
23
|
+
{ value: '3', label: 'Option 3' },
|
|
24
|
+
];
|
|
25
|
+
const [value, setValue] = useState(null);
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Combobox
|
|
29
|
+
label="Single Select"
|
|
30
|
+
onChange={setValue}
|
|
31
|
+
options={singleSelectOptions}
|
|
32
|
+
placeholder="Search..."
|
|
33
|
+
value={value}
|
|
34
|
+
/>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### Multiple Selections
|
|
18
40
|
|
|
19
|
-
|
|
41
|
+
You can also allow users to select multiple options with `type="multi"`.
|
|
20
42
|
|
|
21
43
|
```jsx
|
|
22
44
|
function MultiSelect() {
|
|
@@ -26,11 +48,6 @@ function MultiSelect() {
|
|
|
26
48
|
{ value: '3', label: 'Option 3' },
|
|
27
49
|
{ value: '4', label: 'Option 4' },
|
|
28
50
|
{ 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
51
|
];
|
|
35
52
|
const { value, onChange } = useMultiSelect({ initialValue: ['1'] });
|
|
36
53
|
|
|
@@ -47,56 +64,109 @@ function MultiSelect() {
|
|
|
47
64
|
}
|
|
48
65
|
```
|
|
49
66
|
|
|
50
|
-
###
|
|
67
|
+
### Search
|
|
51
68
|
|
|
52
|
-
|
|
69
|
+
We use [fuse.js](https://www.fusejs.io/) for fuzzy search by default. You can override with `filterFunction`.
|
|
53
70
|
|
|
54
71
|
```jsx
|
|
55
|
-
function
|
|
56
|
-
const
|
|
57
|
-
{ value:
|
|
58
|
-
{ value: '
|
|
59
|
-
{ value: '
|
|
60
|
-
{ value: '
|
|
72
|
+
function CustomFilter() {
|
|
73
|
+
const cryptoOptions = [
|
|
74
|
+
{ value: 'btc', label: 'Bitcoin', description: 'BTC • Digital Gold' },
|
|
75
|
+
{ value: 'eth', label: 'Ethereum', description: 'ETH • Smart Contracts' },
|
|
76
|
+
{ value: 'usdc', label: 'USD Coin', description: 'USDC • Stablecoin' },
|
|
77
|
+
{ value: 'sol', label: 'Solana', description: 'SOL • High Performance' },
|
|
61
78
|
];
|
|
62
|
-
const
|
|
79
|
+
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
80
|
+
|
|
81
|
+
const filterFunction = (options, searchText) => {
|
|
82
|
+
const search = searchText.toLowerCase().trim();
|
|
83
|
+
if (!search) return options;
|
|
84
|
+
return options.filter((option) => {
|
|
85
|
+
const label = typeof option.label === 'string' ? option.label.toLowerCase() : '';
|
|
86
|
+
const description =
|
|
87
|
+
typeof option.description === 'string' ? option.description.toLowerCase() : '';
|
|
88
|
+
return label.startsWith(search) || description.startsWith(search);
|
|
89
|
+
});
|
|
90
|
+
};
|
|
63
91
|
|
|
64
92
|
return (
|
|
65
93
|
<Combobox
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
94
|
+
filterFunction={filterFunction}
|
|
95
|
+
label="Custom filter (starts with)"
|
|
96
|
+
onChange={onChange}
|
|
97
|
+
options={cryptoOptions}
|
|
98
|
+
placeholder="Type to filter..."
|
|
99
|
+
type="multi"
|
|
70
100
|
value={value}
|
|
71
101
|
/>
|
|
72
102
|
);
|
|
73
103
|
}
|
|
74
104
|
```
|
|
75
105
|
|
|
76
|
-
###
|
|
106
|
+
### Grouped
|
|
77
107
|
|
|
78
|
-
|
|
108
|
+
Display options under headers using `label` and `options`. Sort options by the same dimension you group by.
|
|
79
109
|
|
|
80
110
|
```jsx
|
|
81
|
-
function
|
|
111
|
+
function GroupedOptions() {
|
|
112
|
+
const groupedOptions = [
|
|
113
|
+
{
|
|
114
|
+
label: 'Fruits',
|
|
115
|
+
options: [
|
|
116
|
+
{ value: 'apple', label: 'Apple' },
|
|
117
|
+
{ value: 'banana', label: 'Banana' },
|
|
118
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
119
|
+
],
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
label: 'Vegetables',
|
|
123
|
+
options: [
|
|
124
|
+
{ value: 'carrot', label: 'Carrot' },
|
|
125
|
+
{ value: 'broccoli', label: 'Broccoli' },
|
|
126
|
+
{ value: 'spinach', label: 'Spinach' },
|
|
127
|
+
],
|
|
128
|
+
},
|
|
129
|
+
];
|
|
82
130
|
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
83
|
-
const [searchText, setSearchText] = useState('');
|
|
84
131
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
132
|
+
return (
|
|
133
|
+
<Combobox
|
|
134
|
+
label="Category"
|
|
135
|
+
onChange={onChange}
|
|
136
|
+
options={groupedOptions}
|
|
137
|
+
placeholder="Search by category..."
|
|
138
|
+
type="multi"
|
|
139
|
+
value={value}
|
|
140
|
+
/>
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
### Accessibility
|
|
146
|
+
|
|
147
|
+
Use `accessibilityLabel` and `accessibilityHint` to describe purpose and additional context. For multi-select, add hidden-selection labels so screen readers can describe +X summaries.
|
|
148
|
+
|
|
149
|
+
```jsx
|
|
150
|
+
function AccessibilityProps() {
|
|
151
|
+
const priorityOptions = [
|
|
152
|
+
{ value: 'high', label: 'High Priority' },
|
|
153
|
+
{ value: 'medium', label: 'Medium Priority' },
|
|
154
|
+
{ value: 'low', label: 'Low Priority' },
|
|
90
155
|
];
|
|
91
156
|
|
|
157
|
+
const { value, onChange } = useMultiSelect({ initialValue: ['medium'] });
|
|
158
|
+
|
|
92
159
|
return (
|
|
93
160
|
<Combobox
|
|
94
|
-
|
|
161
|
+
accessibilityHint="Select one or more priorities"
|
|
162
|
+
accessibilityLabel="Task priority combobox"
|
|
163
|
+
accessibilityRoles={{ option: 'button' }}
|
|
164
|
+
hiddenSelectedOptionsLabel="priorities"
|
|
165
|
+
label="Task Priority"
|
|
166
|
+
maxSelectedOptionsToShow={1}
|
|
95
167
|
onChange={onChange}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
placeholder="Type to search..."
|
|
99
|
-
searchText={searchText}
|
|
168
|
+
options={priorityOptions}
|
|
169
|
+
placeholder="Choose priority..."
|
|
100
170
|
type="multi"
|
|
101
171
|
value={value}
|
|
102
172
|
/>
|
|
@@ -104,28 +174,34 @@ function ControlledSearch() {
|
|
|
104
174
|
}
|
|
105
175
|
```
|
|
106
176
|
|
|
107
|
-
###
|
|
177
|
+
### Styling
|
|
108
178
|
|
|
109
|
-
|
|
179
|
+
#### Selection Display Limit
|
|
110
180
|
|
|
111
|
-
|
|
112
|
-
function HelperTextExample() {
|
|
113
|
-
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
181
|
+
Cap visible chips with `maxSelectedOptionsToShow`; the rest show as +X more. Pair with `hiddenSelectedOptionsLabel` for screen readers.
|
|
114
182
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
{ value: '
|
|
119
|
-
{ value: '
|
|
183
|
+
```jsx
|
|
184
|
+
function LimitDisplayedSelections() {
|
|
185
|
+
const countryOptions = [
|
|
186
|
+
{ value: 'us', label: 'United States', description: 'North America' },
|
|
187
|
+
{ value: 'ca', label: 'Canada', description: 'North America' },
|
|
188
|
+
{ value: 'mx', label: 'Mexico', description: 'North America' },
|
|
189
|
+
{ value: 'uk', label: 'United Kingdom', description: 'Europe' },
|
|
190
|
+
{ value: 'fr', label: 'France', description: 'Europe' },
|
|
191
|
+
{ value: 'de', label: 'Germany', description: 'Europe' },
|
|
120
192
|
];
|
|
193
|
+
const { value, onChange } = useMultiSelect({
|
|
194
|
+
initialValue: ['us', 'ca', 'mx', 'uk'],
|
|
195
|
+
});
|
|
121
196
|
|
|
122
197
|
return (
|
|
123
198
|
<Combobox
|
|
124
|
-
|
|
125
|
-
label="
|
|
199
|
+
hiddenSelectedOptionsLabel="countries"
|
|
200
|
+
label="Countries"
|
|
201
|
+
maxSelectedOptionsToShow={2}
|
|
126
202
|
onChange={onChange}
|
|
127
|
-
options={
|
|
128
|
-
placeholder="
|
|
203
|
+
options={countryOptions}
|
|
204
|
+
placeholder="Select countries..."
|
|
129
205
|
type="multi"
|
|
130
206
|
value={value}
|
|
131
207
|
/>
|
|
@@ -133,13 +209,9 @@ function HelperTextExample() {
|
|
|
133
209
|
}
|
|
134
210
|
```
|
|
135
211
|
|
|
136
|
-
|
|
212
|
+
#### Alignment
|
|
137
213
|
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
::::note
|
|
141
|
-
Left / right alignment is preferred for styling.
|
|
142
|
-
::::
|
|
214
|
+
Align selected values with the `align` prop.
|
|
143
215
|
|
|
144
216
|
```jsx
|
|
145
217
|
function AlignmentExample() {
|
|
@@ -148,27 +220,26 @@ function AlignmentExample() {
|
|
|
148
220
|
{ value: 'banana', label: 'Banana' },
|
|
149
221
|
{ value: 'cherry', label: 'Cherry' },
|
|
150
222
|
{ value: 'date', label: 'Date' },
|
|
151
|
-
{ value: 'elderberry', label: 'Elderberry' },
|
|
152
223
|
];
|
|
153
|
-
|
|
154
|
-
const { value, onChange } = useMultiSelect({ initialValue: ['apple', 'banana', 'cherry'] });
|
|
224
|
+
const { value, onChange } = useMultiSelect({ initialValue: ['apple', 'banana'] });
|
|
155
225
|
|
|
156
226
|
return (
|
|
157
227
|
<VStack gap={2}>
|
|
158
228
|
<Combobox
|
|
159
|
-
|
|
229
|
+
align="start"
|
|
230
|
+
label="Align start"
|
|
160
231
|
onChange={onChange}
|
|
161
232
|
options={fruitOptions}
|
|
162
|
-
placeholder="Search
|
|
233
|
+
placeholder="Search..."
|
|
163
234
|
type="multi"
|
|
164
235
|
value={value}
|
|
165
236
|
/>
|
|
166
237
|
<Combobox
|
|
167
238
|
align="end"
|
|
168
|
-
label="
|
|
239
|
+
label="Align end"
|
|
169
240
|
onChange={onChange}
|
|
170
241
|
options={fruitOptions}
|
|
171
|
-
placeholder="Search
|
|
242
|
+
placeholder="Search..."
|
|
172
243
|
type="multi"
|
|
173
244
|
value={value}
|
|
174
245
|
/>
|
|
@@ -177,51 +248,277 @@ function AlignmentExample() {
|
|
|
177
248
|
}
|
|
178
249
|
```
|
|
179
250
|
|
|
180
|
-
|
|
251
|
+
#### Borderless
|
|
181
252
|
|
|
182
|
-
|
|
253
|
+
Remove the border with `bordered={false}`.
|
|
183
254
|
|
|
184
255
|
```jsx
|
|
185
256
|
function BorderlessExample() {
|
|
186
|
-
const
|
|
187
|
-
{ value:
|
|
257
|
+
const fruitOptions = [
|
|
258
|
+
{ value: 'apple', label: 'Apple' },
|
|
259
|
+
{ value: 'banana', label: 'Banana' },
|
|
260
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
261
|
+
];
|
|
262
|
+
const [value, setValue] = useState('apple');
|
|
263
|
+
|
|
264
|
+
return (
|
|
265
|
+
<Combobox
|
|
266
|
+
bordered={false}
|
|
267
|
+
label="Borderless"
|
|
268
|
+
onChange={setValue}
|
|
269
|
+
options={fruitOptions}
|
|
270
|
+
placeholder="Search..."
|
|
271
|
+
value={value}
|
|
272
|
+
/>
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
#### Compact
|
|
278
|
+
|
|
279
|
+
Use smaller sizing with `compact`.
|
|
280
|
+
|
|
281
|
+
```jsx
|
|
282
|
+
function CompactExample() {
|
|
283
|
+
const fruitOptions = [
|
|
284
|
+
{ value: 'apple', label: 'Apple' },
|
|
285
|
+
{ value: 'banana', label: 'Banana' },
|
|
286
|
+
{ value: 'cherry', label: 'Cherry' },
|
|
287
|
+
];
|
|
288
|
+
const { value, onChange } = useMultiSelect({ initialValue: ['apple'] });
|
|
289
|
+
|
|
290
|
+
return (
|
|
291
|
+
<Combobox
|
|
292
|
+
compact
|
|
293
|
+
label="Compact"
|
|
294
|
+
onChange={onChange}
|
|
295
|
+
options={fruitOptions}
|
|
296
|
+
placeholder="Compact combobox..."
|
|
297
|
+
type="multi"
|
|
298
|
+
value={value}
|
|
299
|
+
/>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
#### Helper Text
|
|
305
|
+
|
|
306
|
+
Add guidance with `helperText`.
|
|
307
|
+
|
|
308
|
+
```jsx
|
|
309
|
+
function HelperTextExample() {
|
|
310
|
+
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
311
|
+
const fruitOptions = [
|
|
188
312
|
{ value: 'apple', label: 'Apple' },
|
|
189
313
|
{ value: 'banana', label: 'Banana' },
|
|
190
314
|
{ value: 'cherry', label: 'Cherry' },
|
|
191
315
|
{ value: 'date', label: 'Date' },
|
|
192
316
|
];
|
|
193
317
|
|
|
318
|
+
return (
|
|
319
|
+
<Combobox
|
|
320
|
+
helperText="Choose more than one fruit"
|
|
321
|
+
label="Select fruits"
|
|
322
|
+
onChange={onChange}
|
|
323
|
+
options={fruitOptions}
|
|
324
|
+
placeholder="Search and select fruits..."
|
|
325
|
+
type="multi"
|
|
326
|
+
value={value}
|
|
327
|
+
/>
|
|
328
|
+
);
|
|
329
|
+
}
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Composed Examples
|
|
333
|
+
|
|
334
|
+
#### Country Selection
|
|
335
|
+
|
|
336
|
+
You can include flag emoji in labels to create a country selector.
|
|
337
|
+
|
|
338
|
+
```jsx
|
|
339
|
+
function CountrySelectionExample() {
|
|
340
|
+
const getFlagEmoji = (cc) =>
|
|
341
|
+
cc
|
|
342
|
+
.toUpperCase()
|
|
343
|
+
.split('')
|
|
344
|
+
.map((c) => String.fromCodePoint(0x1f1e6 - 65 + c.charCodeAt(0)))
|
|
345
|
+
.join('');
|
|
346
|
+
|
|
347
|
+
const countryOptions = [
|
|
348
|
+
{
|
|
349
|
+
label: 'North America',
|
|
350
|
+
options: [
|
|
351
|
+
{ value: 'us', label: `${getFlagEmoji('us')} United States` },
|
|
352
|
+
{ value: 'ca', label: `${getFlagEmoji('ca')} Canada` },
|
|
353
|
+
{ value: 'mx', label: `${getFlagEmoji('mx')} Mexico` },
|
|
354
|
+
],
|
|
355
|
+
},
|
|
356
|
+
{
|
|
357
|
+
label: 'Europe',
|
|
358
|
+
options: [
|
|
359
|
+
{ value: 'uk', label: `${getFlagEmoji('gb')} United Kingdom` },
|
|
360
|
+
{ value: 'fr', label: `${getFlagEmoji('fr')} France` },
|
|
361
|
+
{ value: 'de', label: `${getFlagEmoji('de')} Germany` },
|
|
362
|
+
],
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
label: 'Asia',
|
|
366
|
+
options: [
|
|
367
|
+
{ value: 'jp', label: `${getFlagEmoji('jp')} Japan` },
|
|
368
|
+
{ value: 'cn', label: `${getFlagEmoji('cn')} China` },
|
|
369
|
+
{ value: 'in', label: `${getFlagEmoji('in')} India` },
|
|
370
|
+
],
|
|
371
|
+
},
|
|
372
|
+
];
|
|
373
|
+
|
|
374
|
+
const { value, onChange } = useMultiSelect({ initialValue: [] });
|
|
375
|
+
|
|
376
|
+
return (
|
|
377
|
+
<Combobox
|
|
378
|
+
label="Country"
|
|
379
|
+
maxSelectedOptionsToShow={3}
|
|
380
|
+
onChange={onChange}
|
|
381
|
+
options={countryOptions}
|
|
382
|
+
placeholder="Select countries..."
|
|
383
|
+
type="multi"
|
|
384
|
+
value={value}
|
|
385
|
+
/>
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
#### Free Solo
|
|
391
|
+
|
|
392
|
+
You can add a dynamic option to Combobox to enable free solo where users can provide their own value.
|
|
393
|
+
|
|
394
|
+
```jsx
|
|
395
|
+
function FreeSoloComboboxExample() {
|
|
396
|
+
const CREATE_OPTION_PREFIX = '__create__';
|
|
397
|
+
|
|
398
|
+
function FreeSoloCombobox({
|
|
399
|
+
freeSolo = false,
|
|
400
|
+
options: initialOptions,
|
|
401
|
+
value,
|
|
402
|
+
onChange,
|
|
403
|
+
placeholder = 'Search or type to add...',
|
|
404
|
+
...comboboxProps
|
|
405
|
+
}) {
|
|
406
|
+
const [searchText, setSearchText] = useState('');
|
|
407
|
+
const [options, setOptions] = useState(initialOptions);
|
|
408
|
+
|
|
409
|
+
useEffect(() => {
|
|
410
|
+
if (!freeSolo) return;
|
|
411
|
+
const initialSet = new Set(initialOptions.map((o) => o.value));
|
|
412
|
+
const valueSet = new Set(Array.isArray(value) ? value : value != null ? [value] : []);
|
|
413
|
+
setOptions((prev) => {
|
|
414
|
+
const addedStillSelected = prev.filter(
|
|
415
|
+
(o) => !initialSet.has(o.value) && valueSet.has(o.value),
|
|
416
|
+
);
|
|
417
|
+
return [...initialOptions, ...addedStillSelected];
|
|
418
|
+
});
|
|
419
|
+
}, [value, freeSolo, initialOptions]);
|
|
420
|
+
|
|
421
|
+
const optionsWithCreate = useMemo(() => {
|
|
422
|
+
if (!freeSolo) return options;
|
|
423
|
+
const trimmed = searchText.trim();
|
|
424
|
+
if (!trimmed) return options;
|
|
425
|
+
const alreadyExists = options.some(
|
|
426
|
+
(o) => typeof o.label === 'string' && o.label.toLowerCase() === trimmed.toLowerCase(),
|
|
427
|
+
);
|
|
428
|
+
if (alreadyExists) return options;
|
|
429
|
+
return [
|
|
430
|
+
...options,
|
|
431
|
+
{ value: `${CREATE_OPTION_PREFIX}${trimmed}`, label: `Add "${trimmed}"` },
|
|
432
|
+
];
|
|
433
|
+
}, [options, searchText, freeSolo]);
|
|
434
|
+
|
|
435
|
+
const handleChange = useCallback(
|
|
436
|
+
(newValue) => {
|
|
437
|
+
if (!freeSolo) {
|
|
438
|
+
onChange(newValue);
|
|
439
|
+
return;
|
|
440
|
+
}
|
|
441
|
+
const values = Array.isArray(newValue) ? newValue : newValue ? [newValue] : [];
|
|
442
|
+
const createValue = values.find((v) => String(v).startsWith(CREATE_OPTION_PREFIX));
|
|
443
|
+
if (createValue) {
|
|
444
|
+
const newLabel = String(createValue).slice(CREATE_OPTION_PREFIX.length);
|
|
445
|
+
const newOption = { value: newLabel.toLowerCase(), label: newLabel };
|
|
446
|
+
setOptions((prev) => [...prev, newOption]);
|
|
447
|
+
const updatedValues = values
|
|
448
|
+
.filter((v) => !String(v).startsWith(CREATE_OPTION_PREFIX))
|
|
449
|
+
.concat(newOption.value);
|
|
450
|
+
onChange(comboboxProps.type === 'multi' ? updatedValues : newOption.value);
|
|
451
|
+
setSearchText('');
|
|
452
|
+
} else {
|
|
453
|
+
onChange(newValue);
|
|
454
|
+
}
|
|
455
|
+
},
|
|
456
|
+
[onChange, freeSolo, comboboxProps.type],
|
|
457
|
+
);
|
|
458
|
+
|
|
459
|
+
return (
|
|
460
|
+
<Combobox
|
|
461
|
+
{...comboboxProps}
|
|
462
|
+
{...(freeSolo ? { searchText, onSearch: setSearchText } : {})}
|
|
463
|
+
onChange={handleChange}
|
|
464
|
+
options={freeSolo ? optionsWithCreate : initialOptions}
|
|
465
|
+
placeholder={placeholder}
|
|
466
|
+
value={value}
|
|
467
|
+
/>
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const [standardSingleValue, setStandardSingle] = useState(null);
|
|
472
|
+
const [freeSoloSingleValue, setFreeSoloSingle] = useState(null);
|
|
473
|
+
const standardMulti = useMultiSelect({ initialValue: [] });
|
|
474
|
+
const freeSoloMulti = useMultiSelect({ initialValue: [] });
|
|
475
|
+
|
|
194
476
|
const fruitOptions = [
|
|
195
477
|
{ value: 'apple', label: 'Apple' },
|
|
196
478
|
{ value: 'banana', label: 'Banana' },
|
|
197
479
|
{ value: 'cherry', label: 'Cherry' },
|
|
198
480
|
{ value: 'date', label: 'Date' },
|
|
199
481
|
{ value: 'elderberry', label: 'Elderberry' },
|
|
482
|
+
{ value: 'fig', label: 'Fig' },
|
|
200
483
|
];
|
|
201
484
|
|
|
202
|
-
const [singleValue, setSingleValue] = useState('apple');
|
|
203
|
-
const { value: multiValue, onChange: multiOnChange } = useMultiSelect({
|
|
204
|
-
initialValue: ['apple'],
|
|
205
|
-
});
|
|
206
|
-
|
|
207
485
|
return (
|
|
208
486
|
<VStack gap={4}>
|
|
209
|
-
<
|
|
210
|
-
|
|
211
|
-
label="
|
|
212
|
-
onChange={
|
|
213
|
-
options={
|
|
487
|
+
<FreeSoloCombobox
|
|
488
|
+
freeSolo={false}
|
|
489
|
+
label="Standard single"
|
|
490
|
+
onChange={setStandardSingle}
|
|
491
|
+
options={fruitOptions}
|
|
214
492
|
placeholder="Search fruits..."
|
|
215
|
-
|
|
493
|
+
type="single"
|
|
494
|
+
value={standardSingleValue}
|
|
216
495
|
/>
|
|
217
|
-
<
|
|
218
|
-
|
|
219
|
-
label="
|
|
220
|
-
onChange={
|
|
496
|
+
<FreeSoloCombobox
|
|
497
|
+
freeSolo
|
|
498
|
+
label="FreeSolo single"
|
|
499
|
+
onChange={setFreeSoloSingle}
|
|
500
|
+
options={fruitOptions}
|
|
501
|
+
placeholder="Search or type to add..."
|
|
502
|
+
type="single"
|
|
503
|
+
value={freeSoloSingleValue}
|
|
504
|
+
/>
|
|
505
|
+
<FreeSoloCombobox
|
|
506
|
+
freeSolo={false}
|
|
507
|
+
label="Standard multi"
|
|
508
|
+
onChange={standardMulti.onChange}
|
|
221
509
|
options={fruitOptions}
|
|
222
510
|
placeholder="Search fruits..."
|
|
223
511
|
type="multi"
|
|
224
|
-
value={
|
|
512
|
+
value={standardMulti.value}
|
|
513
|
+
/>
|
|
514
|
+
<FreeSoloCombobox
|
|
515
|
+
freeSolo
|
|
516
|
+
label="FreeSolo multi"
|
|
517
|
+
onChange={freeSoloMulti.onChange}
|
|
518
|
+
options={fruitOptions}
|
|
519
|
+
placeholder="Search or type to add..."
|
|
520
|
+
type="multi"
|
|
521
|
+
value={freeSoloMulti.value}
|
|
225
522
|
/>
|
|
226
523
|
</VStack>
|
|
227
524
|
);
|
|
@@ -38,7 +38,7 @@ If `dimension` and `scaleMultiplier` are both provided the component will scale
|
|
|
38
38
|
|
|
39
39
|
| Prop | Type | Required | Default | Description |
|
|
40
40
|
| --- | --- | --- | --- | --- |
|
|
41
|
-
| `name` | `margin \| success \| pending \| airdrop \| blockchain \| camera \| cloud \| coinbaseOneLogo \| earn \| instantUnstakingClock \| options \| refresh \| rocket \| securityShield \| smartContract \| staking \| test \| baseCreatorCoin \| borrowCoins \| coinbaseOneEarn \| ethStakingRewards \| fiat \| futures \| globalTransactions \| governance \| lightningNetworkSend \| outage \| startToday \| walletWarning \| phoneNumber \| exchange \| accessToAdvancedCharts \| accountUnderReview \| add2Fa \| addBankAccount \| addCreditCard \| addMoreCrypto \| addPhoneNumber \| advancedTrading \| advancedTradingChartsIndicatorsCandles \| advancedTradingUi \| alienDonutSystemError \| anonymous \| appTrackingTransparency \| artFrameEmptyState \| automaticPayments \| backedByUsDollar \| baseChartLarge \| baseCheck \| baseCoinCryptoLarge \| baseCoinNetworkLarge \| baseConnectLarge \| baseCreatorCoinEmpty \| baseDecentralizationLarge \| basedInUsa \| baseEmptyLarge \| baseErrorButterfly \| baseErrorLarge \| baseLoadingLarge \| baseLocationLarge \| baseMintNftLarge \| baseNetworkLarge \| baseNftLarge \| basePaycoinLarge \| basePeopleLarge \| basePiechartLarge \| baseRewardsCalmLarge \| baseSecurityLarge \| baseSendLarge \| baseSocial \| baseTargetLarge \| bigBtc \| bigError \| bigWarning \| bitcoinAndOtherCrypto \| bitcoinGlobe \| borrow \| borrowCoinsBtc \| borrowWallet \| brdGift \| bridge \| browseDecentralizedApps \| browserExtension \| buy \| buyFirstCrypto \| cardAndPhone \| cardBoosted \| cardError \| cardErrorCB1 \| cardReloadFunds \| cashExcitement \| catHoldingWalletEmptyState \| catLostSystemError \| cbada \| cbbtc \| cbdoge \| cbltc \| cbxrp \| chickenFishSystemError \| claimCryptoUsername \| cloudBacking \| coinbaseCard \| coinbaseCardIssue \| coinbaseCardLock \| coinbaseCardPocket \| coinbaseCardSpend \| coinbaseCardSpendCrypto \| coinbaseFees \| coinbaseIsDown \| coinbaseIsDownMobile \| coinbaseOneAirdrop \| coinbaseOneCardWarning \| coinbaseOneDiscountedAmount \| coinbaseOneDocWarning \| coinbaseOneInsufficientWallet \| coinbaseOnePercentOff \| coinbaseOnePhoneLightning \| coinbaseOneProtectedCrypto \| coinbaseOneRewards \| coinbaseOneSavingFunds \| coinbaseOneTokenRewards \| coinbaseOneUSDCBig \| coinbaseOneUSDCIncentives \| coinbaseOneWaitlist \| coinbaseOneWalletWarning \| coinbaseOneWelcome \| coinbaseOneZeroPortal \| coinbaseOneZeroPromotion \| coinbaseRedesigned \| coinbaseWalletToTrade \| coinCheckmark \| coinFifty \| coinsInWallet \| collectableNfts \| collectingNfts \| commerceAccounting \| commerceInvoices \| communication \| completeAQuiz \| congratulationsOnEarningCrypto \| connectPeople \| contactsListWarning \| crossBorderPayments \| cryptoAndMore \| cryptoApps \| cryptoAppsWallet \| cryptoAssets \| cryptoEconomy \| cryptoForBeginners \| cryptoPortfolio \| cryptoWallet \| currencyPairs \| dappsArts \| dappsFinance \| dappsGaming \| dappsGeneral \| dappsL2Support \| dappsMusic \| decentralization \| decentralizedWebWeb3 \| defiDecentralizedBorrowingLending \| defiDecentralizedTradingExchange \| defiEarn \| defiEnrollBoost \| defiHow \| defiRisk \| desktopAuthorized \| desktopUnknown \| developer \| diamondHands \| didDecentralizedIdentity \| digitalCollectibles \| digitalGold \| directDepositPhone \| discardAssets \| docError \| documentCertified \| documentSuccess \| downloadCoinbaseWallet \| earnCryptoCard \| earnCryptoInterest \| earnGlobe \| earnGrowth \| earnIdVerification \| earnInterest \| earnMore \| earnNuxHome \| earnSuccess \| earnToLearn \| emailNotification \| emptyCollection \| emptyStateCheckBackLater \| emptyStateNft404Page \| emptyStateNftSoldOut \| enableBiometrics \| encryptedEverything \| engagement \| ensProfilePic \| error400 \| errorApp500 \| errorMoblie \| errorRefresh \| errorRefreshWeb \| errorWeb \| errorWeb400 \| errorWeb404 \| errorWeb404Mobile \| errorWeb500 \| estimatedAmount \| ethereumToWallet \| ethStakingUpsell \| exchangeEmptyState \| exploreDecentralizedApps \| faceMatchReal \| feeScale \| fileYourCryptoTaxes \| fileYourCryptoTaxesCheck \| focusLimitOrders \| freeBtc \| futuresAndPerps \| futuresExpire \| futuresVsPerps \| gainsAndLosses \| gamer \| gasFeesNetworkFees \| generative \| getStartedInMinutes \| governanceMallet \| graphChartTrading \| hardwareWallets \| hiddenCollection \| holdCrypto \| holdingCrypto \| iceCreamMeltingSystemError \| idAngles \| idBack \| idCard \| idFront \| idIssue \| idVerificationSecure \| indexer \| innovation \| insufficientBalance \| insuranceProtection \| invest \| invite \| japanVerifyId \| keyGeneration \| layeredNetworks \| layerOne \| layerThree \| layerTwo \| ledgerAccess \| ledgerPlugin \| lend \| leverage \| lightningNetwork \| lightningNetworkInvoice \| lightningNetworkTransfer \| limitOrders \| linkingYourWalletToYourCoinbaseAccount \| liquidationBufferGreen \| liquidationBufferRed \| liquidationBufferRedClose \| liquidationBufferYellow \| lowCost \| marginWarning \| mic \| mining \| minting \| moneyDecentralized \| moreGains \| multicoinSupport \| multiPlatformMobileAppBrowserExtension \| multipleAccountsWalletsForOneUser \| multiplePortfolios \| myNameIsSatoshi \| namePortfolio \| networkWarning \| noFees \| noFeesMotion \| noLongAddresses \| notificationsAlt \| notificationsAndUpdates \| offChain \| oilAndGold \| onChain \| onTheList \| openEmail \| optInPushNotificationsEmail \| oracle \| orderBooks \| p2pGifting \| p2pPayments \| paperHands \| payUpFront \| performance \| phoneUnknown \| platform \| polling \| portfolioPerformance \| poweredByEthereum \| powerOfCrypto \| predictionsMarkets \| primeDeFi \| primeEarn \| primeStaking \| private \| privateKey \| processing \| protocol \| public \| quest \| quickAndSimple \| quickBuy \| ratingsAndReviews \| readyToTrade \| realToUSDC \| receivedCard \| receiveGift \| recommendInvest \| recurringReward \| referralsAvatars \| referralsBitcoin \| referralsCoinbaseOne \| referralsGenericCoin \| referralsWalletPhones \| remittances \| requestSent \| restrictedCountry \| retailUSDCRewards \| reviewInfo \| rotatingRewards \| routingAccount \| scalable \| secureAndTrusted \| secureGlobalTransactions \| secureStorage \| selectCorrectCrypto \| selectReward \| selfCustody \| selfCustodyCrypto \| semiCustodial \| sendCryptoFaster \| sendToUsername \| serverCatSystemError \| settlement \| shareOnSocialMedia \| sidechain \| slippageTolerance \| spacedOutSystemError \| squidEmptyState \| stablecoin \| stableValue \| stakingMissedReturns \| stakingMissedReturnsUsdc \| stayInControlSelfHostedWalletsStorage \| stopLimitOrder \| stopLimitOrderDown \| storage \| stressTestedColdStorage \| supportAndMore \| sustainable \| switchAdvancedToSimpleTrading \| taxesDetails \| tools \| tradeGeneral \| tradeHistory \| tradeImmediately \| tradingWithLeverage \| transactionLimit \| trendingHotAssets \| twoIdVerify \| unlockKey \| usdAndUsdc \| usdtToUSDC \| verifyBankTransactions \| verifyCardTransactions \| verifyEmail \| verifyIdDetails \| verifyInfo \| videoRequest \| videoReview \| videoUpload \| vipBadge \| vote \| walletAsset \| walletConfirmation \| walletFlyEmptyState \| walletLoading \| walletNotifications \| walletSecurity \| walletUi \| watchVideos \| web3ActivityError \| web3ActivitySigned \| web3MobileSetupStart \| web3MobileSetupSuccess \| webRAT \| whyNotBoth \| yourContacts` | Yes | `-` | Name of illustration as defined in Figma |
|
|
41
|
+
| `name` | `margin \| success \| pending \| airdrop \| blockchain \| camera \| cloud \| coinbaseOneLogo \| earn \| instantUnstakingClock \| options \| refresh \| rocket \| securityShield \| smartContract \| staking \| test \| baseCreatorCoin \| borrowCoins \| coinbaseOneEarn \| ethStakingRewards \| fiat \| futures \| globalTransactions \| governance \| lightningNetworkSend \| outage \| startToday \| walletWarning \| phoneNumber \| exchange \| accessToAdvancedCharts \| accountUnderReview \| add2Fa \| addBankAccount \| addCreditCard \| addMoreCrypto \| addPhoneNumber \| advancedTrading \| advancedTradingChartsIndicatorsCandles \| advancedTradingUi \| alienDonutSystemError \| anonymous \| appTrackingTransparency \| artFrameEmptyState \| automaticPayments \| backedByUsDollar \| baseChartLarge \| baseCheck \| baseCoinCryptoLarge \| baseCoinNetworkLarge \| baseConnectLarge \| baseCreatorCoinEmpty \| baseDecentralizationLarge \| basedInUsa \| baseEmptyLarge \| baseErrorButterfly \| baseErrorLarge \| baseLoadingLarge \| baseLocationLarge \| baseMintNftLarge \| baseNetworkLarge \| baseNftLarge \| basePaycoinLarge \| basePeopleLarge \| basePiechartLarge \| baseRewardsCalmLarge \| baseSecurityLarge \| baseSendLarge \| baseSocial \| baseTargetLarge \| bigBtc \| bigError \| bigWarning \| bitcoinAndOtherCrypto \| bitcoinGlobe \| borrow \| borrowCoinsBtc \| borrowWallet \| brdGift \| bridge \| browseDecentralizedApps \| browserExtension \| buy \| buyFirstCrypto \| cardAndPhone \| cardBoosted \| cardError \| cardErrorCB1 \| cardReloadFunds \| cashExcitement \| catHoldingWalletEmptyState \| catLostSystemError \| cbada \| cbbtc \| cbdoge \| cbltc \| cbxrp \| chickenFishSystemError \| claimCryptoUsername \| cloudBacking \| coinbaseCard \| coinbaseCardIssue \| coinbaseCardLock \| coinbaseCardPocket \| coinbaseCardSpend \| coinbaseCardSpendCrypto \| coinbaseFees \| coinbaseIsDown \| coinbaseIsDownMobile \| coinbaseOneAirdrop \| coinbaseOneCardWarning \| coinbaseOneDiscountedAmount \| coinbaseOneDocWarning \| coinbaseOneInsufficientWallet \| coinbaseOnePercentOff \| coinbaseOnePhoneLightning \| coinbaseOneProtectedCrypto \| coinbaseOneRewards \| coinbaseOneSavingFunds \| coinbaseOneTokenRewards \| coinbaseOneUSDCBig \| coinbaseOneUSDCIncentives \| coinbaseOneWaitlist \| coinbaseOneWalletWarning \| coinbaseOneWelcome \| coinbaseOneZeroPortal \| coinbaseOneZeroPromotion \| coinbaseRedesigned \| coinbaseWalletToTrade \| coinCheckmark \| coinFifty \| coinsInWallet \| collectableNfts \| collectingNfts \| commerceAccounting \| commerceInvoices \| communication \| completeAQuiz \| congratulationsOnEarningCrypto \| connectPeople \| contactsListWarning \| crossBorderPayments \| cryptoAndMore \| cryptoApps \| cryptoAppsWallet \| cryptoAssets \| cryptoEconomy \| cryptoForBeginners \| cryptoPortfolio \| cryptoPortfolioUsdc \| cryptoWallet \| currencyPairs \| dappsArts \| dappsFinance \| dappsGaming \| dappsGeneral \| dappsL2Support \| dappsMusic \| decentralization \| decentralizedWebWeb3 \| defiDecentralizedBorrowingLending \| defiDecentralizedTradingExchange \| defiEarn \| defiEnrollBoost \| defiHow \| defiRisk \| desktopAuthorized \| desktopUnknown \| developer \| diamondHands \| didDecentralizedIdentity \| digitalCollectibles \| digitalGold \| directDepositPhone \| discardAssets \| docError \| documentCertified \| documentSuccess \| downloadCoinbaseWallet \| earnCryptoCard \| earnCryptoInterest \| earnGlobe \| earnGrowth \| earnIdVerification \| earnInterest \| earnMore \| earnNuxHome \| earnSuccess \| earnToLearn \| emailNotification \| emptyCollection \| emptyStateCheckBackLater \| emptyStateNft404Page \| emptyStateNftSoldOut \| enableBiometrics \| encryptedEverything \| engagement \| ensProfilePic \| error400 \| errorApp500 \| errorMoblie \| errorRefresh \| errorRefreshWeb \| errorWeb \| errorWeb400 \| errorWeb404 \| errorWeb404Mobile \| errorWeb500 \| estimatedAmount \| ethereumToWallet \| ethStakingUpsell \| exchangeEmptyState \| exploreDecentralizedApps \| faceMatchReal \| feeScale \| fileYourCryptoTaxes \| fileYourCryptoTaxesCheck \| focusLimitOrders \| freeBtc \| futuresAndPerps \| futuresExpire \| futuresVsPerps \| gainsAndLosses \| gamer \| gasFeesNetworkFees \| generative \| getStartedInMinutes \| governanceMallet \| graphChartTrading \| hardwareWallets \| hiddenCollection \| holdCrypto \| holdingCrypto \| iceCreamMeltingSystemError \| idAngles \| idBack \| idCard \| idFront \| idIssue \| idVerificationSecure \| indexer \| innovation \| instoAdd2Fa \| instoAddBankAccount \| instoCoinbaseOneProtectedCrypto \| instoDocumentSuccess \| instoEarnGlobe \| instoEnableBiometrics \| instoEthStakingRewards \| instoEthStakingUpsell \| instoGovernance \| instoKeyGenerationComplete \| instoKeyGenerationPending \| instoOnChain \| instoOpenEmail \| instoPhoneUnknown \| instoPrimeStaking \| instoPrivateKey \| instoRequestSent \| instoSecurityKeyAuth \| instoStaking \| instoStakingMissedReturns \| instoWallet \| instoWalletSecurity \| instoWeb3MobileSetupStart \| insufficientBalance \| insuranceProtection \| invest \| invite \| japanVerifyId \| keyGeneration \| layeredNetworks \| layerOne \| layerThree \| layerTwo \| ledgerAccess \| ledgerPlugin \| lend \| leverage \| lightningNetwork \| lightningNetworkInvoice \| lightningNetworkTransfer \| limitOrders \| linkingYourWalletToYourCoinbaseAccount \| liquidationBufferGreen \| liquidationBufferRed \| liquidationBufferRedClose \| liquidationBufferYellow \| lowCost \| marginWarning \| mic \| mining \| minting \| moneyDecentralized \| moreGains \| multicoinSupport \| multiPlatformMobileAppBrowserExtension \| multipleAccountsWalletsForOneUser \| multiplePortfolios \| myNameIsSatoshi \| namePortfolio \| networkWarning \| noFees \| noFeesMotion \| noLongAddresses \| notificationsAlt \| notificationsAndUpdates \| offChain \| oilAndGold \| onChain \| onTheList \| openEmail \| optInPushNotificationsEmail \| oracle \| orderBooks \| p2pGifting \| p2pPayments \| paperHands \| payUpFront \| performance \| phoneUnknown \| platform \| polling \| portfolioPerformance \| poweredByEthereum \| powerOfCrypto \| predictionsMarkets \| primeDeFi \| primeEarn \| primeStaking \| private \| privateKey \| processing \| protocol \| public \| quest \| quickAndSimple \| quickBuy \| ratingsAndReviews \| readyToTrade \| realToUSDC \| receivedCard \| receiveGift \| recommendInvest \| recurringReward \| referralsAvatars \| referralsBitcoin \| referralsCoinbaseOne \| referralsGenericCoin \| referralsWalletPhones \| remittances \| requestSent \| restrictedCountry \| retailUSDCRewards \| reviewInfo \| rotatingRewards \| routingAccount \| scalable \| secureAndTrusted \| secureGlobalTransactions \| secureStorage \| selectCorrectCrypto \| selectReward \| selfCustody \| selfCustodyCrypto \| semiCustodial \| sendCryptoFaster \| sendToUsername \| serverCatSystemError \| settlement \| shareOnSocialMedia \| sidechain \| slippageTolerance \| spacedOutSystemError \| squidEmptyState \| stablecoin \| stableValue \| stakingMissedReturns \| stakingMissedReturnsUsdc \| stayInControlSelfHostedWalletsStorage \| stopLimitOrder \| stopLimitOrderDown \| storage \| stressTestedColdStorage \| supportAndMore \| sustainable \| switchAdvancedToSimpleTrading \| taxesDetails \| tools \| tradeGeneral \| tradeHistory \| tradeImmediately \| tradingPerpetualsUsdc \| tradingWithLeverage \| transactionLimit \| trendingHotAssets \| twoIdVerify \| unlockKey \| usdAndUsdc \| usdtToUSDC \| verifyBankTransactions \| verifyCardTransactions \| verifyEmail \| verifyIdDetails \| verifyInfo \| videoRequest \| videoReview \| videoUpload \| vipBadge \| vote \| walletAsset \| walletConfirmation \| walletFlyEmptyState \| walletLoading \| walletNotifications \| walletSecurity \| walletUi \| watchVideos \| web3ActivityError \| web3ActivitySigned \| web3MobileSetupStart \| web3MobileSetupSuccess \| webRAT \| whyNotBoth \| yourContacts` | Yes | `-` | Name of illustration as defined in Figma |
|
|
42
42
|
| `dimension` | `240x240 \| 200x200` | No | `-` | HeroSquare Default: 240x240 SpotSquare Default: 96x96 Pictogram Default: 48x48 SpotRectangle Default: 240x120 |
|
|
43
43
|
| `fallback` | `ReactElement<any, string \| JSXElementConstructor<any>> \| null` | No | `null` | Fallback element to render if unable to find an illustration with the matching name |
|
|
44
44
|
| `scaleMultiplier` | `number` | No | `-` | Multiply the width & height while maintaining aspect ratio |
|