@coinbase/cds-mcp-server 8.30.0 → 8.31.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/DatePicker.txt +1 -0
- package/mcp-docs/mobile/components/TextInput.txt +1 -0
- package/mcp-docs/web/components/DatePicker.txt +1 -0
- package/mcp-docs/web/components/Sidebar.txt +490 -34
- package/mcp-docs/web/components/TextInput.txt +1 -0
- package/mcp-docs/web/routes.txt +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -8,6 +8,14 @@ All notable changes to this project will be documented in this file.
|
|
|
8
8
|
|
|
9
9
|
<!-- template-start -->
|
|
10
10
|
|
|
11
|
+
## 8.31.0 ((12/12/2025, 04:30 PM PST))
|
|
12
|
+
|
|
13
|
+
This is an artificial version bump with no new change.
|
|
14
|
+
|
|
15
|
+
## 8.30.1 ((12/12/2025, 03:00 PM PST))
|
|
16
|
+
|
|
17
|
+
This is an artificial version bump with no new change.
|
|
18
|
+
|
|
11
19
|
## 8.30.0 ((12/12/2025, 02:53 PM PST))
|
|
12
20
|
|
|
13
21
|
This is an artificial version bump with no new change.
|
|
@@ -448,6 +448,7 @@ function Example() {
|
|
|
448
448
|
| `inlineImageLeft` | `string` | No | `-` | If defined, the provided image resource will be rendered on the left. |
|
|
449
449
|
| `inlineImagePadding` | `number` | No | `-` | Padding between the inline image, if any, and the text input itself. |
|
|
450
450
|
| `inputAccessoryViewID` | `string` | No | `-` | Used to connect to an InputAccessoryView. Not part of react-natives documentation, but present in examples and code. See https://reactnative.dev/docs/inputaccessoryview for more information. |
|
|
451
|
+
| `inputBackground` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `'bg'` | Background color of the input |
|
|
451
452
|
| `inputMode` | `search \| none \| text \| email \| tel \| url \| numeric \| decimal` | No | `-` | Works like the inputmode attribute in HTML, it determines which keyboard to open, e.g. numeric and has precedence over keyboardType. |
|
|
452
453
|
| `invalidDateError` | `string` | No | `'Please enter a valid date'` | Error text to display when an impossible date is selected, e.g. 99/99/2000. This should always be defined for accessibility. Also displays when a date is selected that is more than 100 years before the minDate, or more than 100 years after the maxDate. |
|
|
453
454
|
| `key` | `Key \| null` | No | `-` | - |
|
|
@@ -668,6 +668,7 @@ function TextInputKeyboardExample() {
|
|
|
668
668
|
| `inlineImageLeft` | `string` | No | `-` | If defined, the provided image resource will be rendered on the left. |
|
|
669
669
|
| `inlineImagePadding` | `number` | No | `-` | Padding between the inline image, if any, and the text input itself. |
|
|
670
670
|
| `inputAccessoryViewID` | `string` | No | `-` | Used to connect to an InputAccessoryView. Not part of react-natives documentation, but present in examples and code. See https://reactnative.dev/docs/inputaccessoryview for more information. |
|
|
671
|
+
| `inputBackground` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `'bg'` | Background color of the input |
|
|
671
672
|
| `inputMode` | `search \| none \| text \| email \| tel \| url \| numeric \| decimal` | No | `-` | Works like the inputmode attribute in HTML, it determines which keyboard to open, e.g. numeric and has precedence over keyboardType. |
|
|
672
673
|
| `key` | `Key \| null` | No | `-` | - |
|
|
673
674
|
| `keyboardAppearance` | `light \| default \| dark` | No | `-` | Determines the color of the keyboard. |
|
|
@@ -506,6 +506,7 @@ function Example() {
|
|
|
506
506
|
| `helperText` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | For cases where label is not enough information to describe what the text input is for. Can also be used for showing positive/negative messages |
|
|
507
507
|
| `helperTextErrorIconAccessibilityLabel` | `string` | No | `'error'` | Accessibility label for helper text error icon when variant=negative |
|
|
508
508
|
| `highlightedDates` | `(Date \| [Date, Date])[]` | No | `-` | Array of highlighted dates, and date tuples for date ranges. A number is created for every individual date within a tuple range, so do not abuse this with massive ranges. |
|
|
509
|
+
| `inputBackground` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `'bg'` | Background color of the input. |
|
|
509
510
|
| `invalidDateError` | `string` | No | `'Please enter a valid date'` | Error text to display when an impossible date is selected, e.g. 99/99/2000. This should always be defined for accessibility. Also displays when a date is selected that is more than 100 years before the minDate, or more than 100 years after the maxDate. |
|
|
510
511
|
| `key` | `Key \| null` | No | `-` | - |
|
|
511
512
|
| `label` | `string` | No | `-` | Short messageArea indicating purpose of input |
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Sidebar
|
|
2
2
|
|
|
3
|
-
A vertical navigation
|
|
3
|
+
A composable and customizable vertical navigation component with support for multiple variants, collapsible states, and custom content areas.
|
|
4
4
|
|
|
5
5
|
## Import
|
|
6
6
|
|
|
@@ -10,12 +10,53 @@ import { Sidebar } from '@coinbase/cds-web/navigation/Sidebar'
|
|
|
10
10
|
|
|
11
11
|
## Examples
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
Sidebar is a vertical navigation component for accessing different sections of an application. It supports multiple variants, collapsible states, and custom content areas.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
### Basics
|
|
16
|
+
|
|
17
|
+
A Sidebar is composed of the following parts:
|
|
18
|
+
|
|
19
|
+
- `Sidebar` - The main container with logo and navigation items
|
|
20
|
+
- `SidebarItem` - Individual navigation items with icon and title
|
|
21
|
+
- `SidebarMoreMenu` - Overflow menu for additional navigation options
|
|
22
|
+
|
|
23
|
+
```jsx live
|
|
24
|
+
function BasicSidebar() {
|
|
25
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
26
|
+
const items = [
|
|
27
|
+
{ title: 'Home', icon: 'home' },
|
|
28
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
29
|
+
{ title: 'Trade', icon: 'trading' },
|
|
30
|
+
{ title: 'Settings', icon: 'cog' },
|
|
31
|
+
];
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
35
|
+
<Sidebar logo={<LogoMark />}>
|
|
36
|
+
{items.map((item, index) => (
|
|
37
|
+
<SidebarItem
|
|
38
|
+
key={item.title}
|
|
39
|
+
active={index === activeIndex}
|
|
40
|
+
icon={item.icon}
|
|
41
|
+
onClick={() => setActiveIndex(index)}
|
|
42
|
+
title={item.title}
|
|
43
|
+
tooltipContent={item.title}
|
|
44
|
+
/>
|
|
45
|
+
))}
|
|
46
|
+
</Sidebar>
|
|
47
|
+
</HStack>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### Variants
|
|
53
|
+
|
|
54
|
+
#### Default
|
|
55
|
+
|
|
56
|
+
Use the Default variant on standard consumer-facing surfaces like Retail where maximum navigation and content space is desired. This variant shows full labels alongside icons.
|
|
16
57
|
|
|
17
58
|
```jsx live
|
|
18
|
-
function
|
|
59
|
+
function DefaultVariant() {
|
|
19
60
|
const items = [
|
|
20
61
|
{ title: 'Home', icon: 'home' },
|
|
21
62
|
{ title: 'Assets', icon: 'chartPie' },
|
|
@@ -44,18 +85,13 @@ function Example() {
|
|
|
44
85
|
return (
|
|
45
86
|
<Pressable
|
|
46
87
|
as="button"
|
|
47
|
-
background="
|
|
88
|
+
background="bgPrimaryWash"
|
|
48
89
|
borderRadius={1000}
|
|
90
|
+
transparentWhileInactive
|
|
49
91
|
width="100%"
|
|
50
92
|
onClick={() => console.log}
|
|
51
93
|
>
|
|
52
|
-
<HStack
|
|
53
|
-
alignItems="center"
|
|
54
|
-
gap={2}
|
|
55
|
-
justifyContent="flex-start"
|
|
56
|
-
padding={2}
|
|
57
|
-
testID="sidebar-item-primary"
|
|
58
|
-
>
|
|
94
|
+
<HStack alignItems="center" gap={2} paddingX={2} paddingY={2}>
|
|
59
95
|
<Icon name="documentation" />
|
|
60
96
|
<Text as="span" font="headline" color="foreground">
|
|
61
97
|
End item
|
|
@@ -73,6 +109,11 @@ function Example() {
|
|
|
73
109
|
</Box>
|
|
74
110
|
}
|
|
75
111
|
renderEnd={renderEnd}
|
|
112
|
+
styles={{
|
|
113
|
+
end: {
|
|
114
|
+
width: '100%',
|
|
115
|
+
},
|
|
116
|
+
}}
|
|
76
117
|
>
|
|
77
118
|
{navItems.map((item, index) => (
|
|
78
119
|
<SidebarItem
|
|
@@ -104,12 +145,77 @@ function Example() {
|
|
|
104
145
|
}
|
|
105
146
|
```
|
|
106
147
|
|
|
107
|
-
|
|
148
|
+
#### Condensed
|
|
108
149
|
|
|
109
|
-
Use
|
|
150
|
+
Use in specialized workflows with complex data displays, such as Exchange and Advanced Trade, where navigation space is minimized to focus on core tasks. This variant displays icons with small labels below.
|
|
110
151
|
|
|
111
152
|
```jsx live
|
|
112
|
-
function
|
|
153
|
+
function CondensedVariant() {
|
|
154
|
+
const items = [
|
|
155
|
+
{ title: 'Spot', icon: 'chartCandles' },
|
|
156
|
+
{ title: 'Futures', icon: 'chartBar' },
|
|
157
|
+
{ title: 'Portfolio', icon: 'chartPie' },
|
|
158
|
+
{ title: 'Orders', icon: 'documentation' },
|
|
159
|
+
{ title: 'For you', icon: 'newsFeed' },
|
|
160
|
+
{ title: 'Earn', icon: 'giftBox' },
|
|
161
|
+
{ title: 'Borrow', icon: 'cash' },
|
|
162
|
+
{ title: 'DeFi', icon: 'defi' },
|
|
163
|
+
];
|
|
164
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
165
|
+
const [moreMenuValue, setMoreMenuValue] = useState();
|
|
166
|
+
const navItems = items.slice(0, 4);
|
|
167
|
+
const moreMenuOptions = items.slice(4);
|
|
168
|
+
const handleMoreMenuChange = (newValue) => {
|
|
169
|
+
const moreIndex =
|
|
170
|
+
moreMenuOptions.findIndex((option) => option.title === newValue) + navItems.length;
|
|
171
|
+
setActiveIndex(moreIndex);
|
|
172
|
+
setMoreMenuValue(newValue);
|
|
173
|
+
};
|
|
174
|
+
const handleItemClick = (index) => {
|
|
175
|
+
setActiveIndex(index);
|
|
176
|
+
setMoreMenuValue(undefined);
|
|
177
|
+
};
|
|
178
|
+
return (
|
|
179
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
180
|
+
<Sidebar logo={<LogoMark foreground />} variant="condensed">
|
|
181
|
+
{navItems.map((item, index) => (
|
|
182
|
+
<SidebarItem
|
|
183
|
+
key={`sidebar-item--${item.title}`}
|
|
184
|
+
active={index === activeIndex}
|
|
185
|
+
onClick={() => handleItemClick(index)}
|
|
186
|
+
tooltipContent={item.title}
|
|
187
|
+
{...item}
|
|
188
|
+
/>
|
|
189
|
+
))}
|
|
190
|
+
<SidebarMoreMenu
|
|
191
|
+
active={activeIndex >= navItems.length}
|
|
192
|
+
onChange={handleMoreMenuChange}
|
|
193
|
+
tooltipContent="More"
|
|
194
|
+
value={moreMenuValue}
|
|
195
|
+
>
|
|
196
|
+
{moreMenuOptions.map((item) => (
|
|
197
|
+
<SelectOption
|
|
198
|
+
key={`sidebar-more-menu-item--${item.title}`}
|
|
199
|
+
description={item.title}
|
|
200
|
+
media={<Icon name={item.icon} />}
|
|
201
|
+
value={item.title}
|
|
202
|
+
/>
|
|
203
|
+
))}
|
|
204
|
+
</SidebarMoreMenu>
|
|
205
|
+
</Sidebar>
|
|
206
|
+
</HStack>
|
|
207
|
+
);
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Collapsed State
|
|
212
|
+
|
|
213
|
+
#### Controlled Collapse
|
|
214
|
+
|
|
215
|
+
Use the `collapsed` prop to control the sidebar's collapsed state. When collapsed, only icons are shown with tooltips for labels.
|
|
216
|
+
|
|
217
|
+
```jsx live
|
|
218
|
+
function ControlledCollapse() {
|
|
113
219
|
const items = [
|
|
114
220
|
{ title: 'Home', icon: 'home' },
|
|
115
221
|
{ title: 'Assets', icon: 'chartPie' },
|
|
@@ -175,46 +281,331 @@ function Example() {
|
|
|
175
281
|
}
|
|
176
282
|
```
|
|
177
283
|
|
|
178
|
-
|
|
284
|
+
#### Auto Collapse
|
|
179
285
|
|
|
180
|
-
Use
|
|
286
|
+
Use the `autoCollapse` prop to automatically collapse the sidebar at or below the tablet breakpoint (768px). This is useful for responsive layouts where the sidebar should adapt to screen size.
|
|
181
287
|
|
|
182
288
|
```jsx live
|
|
183
|
-
function
|
|
289
|
+
function AutoCollapse() {
|
|
184
290
|
const items = [
|
|
185
|
-
{ title: '
|
|
186
|
-
{ title: '
|
|
187
|
-
{ title: '
|
|
188
|
-
{ title: '
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
291
|
+
{ title: 'Home', icon: 'home' },
|
|
292
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
293
|
+
{ title: 'Trade', icon: 'trading' },
|
|
294
|
+
{ title: 'Settings', icon: 'cog' },
|
|
295
|
+
];
|
|
296
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
297
|
+
|
|
298
|
+
return (
|
|
299
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
300
|
+
<Sidebar autoCollapse logo={<LogoMark />}>
|
|
301
|
+
{items.map((item, index) => (
|
|
302
|
+
<SidebarItem
|
|
303
|
+
key={item.title}
|
|
304
|
+
active={index === activeIndex}
|
|
305
|
+
icon={item.icon}
|
|
306
|
+
onClick={() => setActiveIndex(index)}
|
|
307
|
+
title={item.title}
|
|
308
|
+
tooltipContent={item.title}
|
|
309
|
+
/>
|
|
310
|
+
))}
|
|
311
|
+
</Sidebar>
|
|
312
|
+
<VStack flexGrow={1} padding={3}>
|
|
313
|
+
<Text color="fgMuted" font="label1">
|
|
314
|
+
Resize the browser window to see the sidebar auto-collapse at the tablet breakpoint.
|
|
315
|
+
</Text>
|
|
316
|
+
</VStack>
|
|
317
|
+
</HStack>
|
|
318
|
+
);
|
|
319
|
+
}
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### Custom Content
|
|
323
|
+
|
|
324
|
+
#### Logo
|
|
325
|
+
|
|
326
|
+
The `logo` prop accepts either a React element or a render function that receives the collapsed state. Use the render function when you need different logos for collapsed and expanded states.
|
|
327
|
+
|
|
328
|
+
```jsx live
|
|
329
|
+
function CustomLogo() {
|
|
330
|
+
const items = [
|
|
331
|
+
{ title: 'Home', icon: 'home' },
|
|
332
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
333
|
+
{ title: 'Trade', icon: 'trading' },
|
|
334
|
+
];
|
|
335
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
336
|
+
const [collapsed, setCollapsed] = useState(false);
|
|
337
|
+
|
|
338
|
+
const renderLogo = (isCollapsed) =>
|
|
339
|
+
isCollapsed ? (
|
|
340
|
+
<LogoMark />
|
|
341
|
+
) : (
|
|
342
|
+
<Box height={32}>
|
|
343
|
+
<SubBrandLogoMark type="commerce" />
|
|
344
|
+
</Box>
|
|
345
|
+
);
|
|
346
|
+
|
|
347
|
+
return (
|
|
348
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
349
|
+
<Sidebar
|
|
350
|
+
collapsed={collapsed}
|
|
351
|
+
logo={renderLogo}
|
|
352
|
+
renderEnd={() => (
|
|
353
|
+
<IconButton
|
|
354
|
+
name={collapsed ? 'caretRight' : 'caretLeft'}
|
|
355
|
+
onClick={() => setCollapsed(!collapsed)}
|
|
356
|
+
/>
|
|
357
|
+
)}
|
|
358
|
+
>
|
|
359
|
+
{items.map((item, index) => (
|
|
360
|
+
<SidebarItem
|
|
361
|
+
key={item.title}
|
|
362
|
+
active={index === activeIndex}
|
|
363
|
+
icon={item.icon}
|
|
364
|
+
onClick={() => setActiveIndex(index)}
|
|
365
|
+
title={item.title}
|
|
366
|
+
tooltipContent={item.title}
|
|
367
|
+
/>
|
|
368
|
+
))}
|
|
369
|
+
</Sidebar>
|
|
370
|
+
</HStack>
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
#### Render End
|
|
376
|
+
|
|
377
|
+
The `renderEnd` prop places content at the bottom of the sidebar. It receives the collapsed state as a parameter, allowing you to adapt the content based on the sidebar's state.
|
|
378
|
+
|
|
379
|
+
```jsx live
|
|
380
|
+
function RenderEndExample() {
|
|
381
|
+
const items = [
|
|
382
|
+
{ title: 'Home', icon: 'home' },
|
|
383
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
384
|
+
{ title: 'Trade', icon: 'trading' },
|
|
385
|
+
];
|
|
386
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
387
|
+
|
|
388
|
+
const renderEnd = (isCollapsed) => (
|
|
389
|
+
<Pressable
|
|
390
|
+
as="button"
|
|
391
|
+
background="bgPrimaryWash"
|
|
392
|
+
borderRadius={1000}
|
|
393
|
+
transparentWhileInactive
|
|
394
|
+
width="100%"
|
|
395
|
+
onClick={() => alert('Help clicked!')}
|
|
396
|
+
>
|
|
397
|
+
<HStack alignItems="center" gap={2} paddingX={2} paddingY={2}>
|
|
398
|
+
<Icon name="questionCircle" />
|
|
399
|
+
{!isCollapsed && (
|
|
400
|
+
<TextHeadline as="span" color="foreground">
|
|
401
|
+
Help & Support
|
|
402
|
+
</TextHeadline>
|
|
403
|
+
)}
|
|
404
|
+
</HStack>
|
|
405
|
+
</Pressable>
|
|
406
|
+
);
|
|
407
|
+
|
|
408
|
+
return (
|
|
409
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
410
|
+
<Sidebar
|
|
411
|
+
logo={<LogoMark />}
|
|
412
|
+
renderEnd={renderEnd}
|
|
413
|
+
styles={{
|
|
414
|
+
end: {
|
|
415
|
+
width: '100%',
|
|
416
|
+
},
|
|
417
|
+
}}
|
|
418
|
+
>
|
|
419
|
+
{items.map((item, index) => (
|
|
420
|
+
<SidebarItem
|
|
421
|
+
key={item.title}
|
|
422
|
+
active={index === activeIndex}
|
|
423
|
+
icon={item.icon}
|
|
424
|
+
onClick={() => setActiveIndex(index)}
|
|
425
|
+
title={item.title}
|
|
426
|
+
tooltipContent={item.title}
|
|
427
|
+
/>
|
|
428
|
+
))}
|
|
429
|
+
</Sidebar>
|
|
430
|
+
</HStack>
|
|
431
|
+
);
|
|
432
|
+
}
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### Styling
|
|
436
|
+
|
|
437
|
+
Use the `styles` prop to customize specific parts of the sidebar.
|
|
438
|
+
|
|
439
|
+
```jsx live
|
|
440
|
+
function CustomStyles() {
|
|
441
|
+
const items = [
|
|
442
|
+
{ title: 'Home', icon: 'home' },
|
|
443
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
444
|
+
{ title: 'Trade', icon: 'trading' },
|
|
445
|
+
{ title: 'Settings', icon: 'cog' },
|
|
446
|
+
];
|
|
447
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
448
|
+
|
|
449
|
+
return (
|
|
450
|
+
<HStack alignItems="flex-start" justifyContent="center" overflow="hidden">
|
|
451
|
+
<Sidebar
|
|
452
|
+
logo={<LogoMark />}
|
|
453
|
+
renderEnd={() => (
|
|
454
|
+
<Pressable
|
|
455
|
+
as="button"
|
|
456
|
+
background="bgPrimaryWash"
|
|
457
|
+
borderRadius={1000}
|
|
458
|
+
transparentWhileInactive
|
|
459
|
+
width="100%"
|
|
460
|
+
>
|
|
461
|
+
<HStack alignItems="center" gap={2} paddingX={2} paddingY={2}>
|
|
462
|
+
<Icon name="questionCircle" />
|
|
463
|
+
<TextHeadline as="span">Help</TextHeadline>
|
|
464
|
+
</HStack>
|
|
465
|
+
</Pressable>
|
|
466
|
+
)}
|
|
467
|
+
styles={{
|
|
468
|
+
root: {
|
|
469
|
+
background:
|
|
470
|
+
'linear-gradient(180deg, var(--color-bg) 0%, var(--color-bgAlternate) 100%)',
|
|
471
|
+
},
|
|
472
|
+
logo: { paddingBottom: 32 },
|
|
473
|
+
end: { width: '100%' },
|
|
474
|
+
}}
|
|
475
|
+
>
|
|
476
|
+
{items.map((item, index) => (
|
|
477
|
+
<SidebarItem
|
|
478
|
+
key={item.title}
|
|
479
|
+
active={index === activeIndex}
|
|
480
|
+
icon={item.icon}
|
|
481
|
+
onClick={() => setActiveIndex(index)}
|
|
482
|
+
title={item.title}
|
|
483
|
+
tooltipContent={item.title}
|
|
484
|
+
/>
|
|
485
|
+
))}
|
|
486
|
+
</Sidebar>
|
|
487
|
+
</HStack>
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
You can also use custom class names on the various subcomponents in Sidebar using the `classNames` prop.
|
|
493
|
+
|
|
494
|
+
```jsx
|
|
495
|
+
const customLogoStyles = css`
|
|
496
|
+
padding-bottom: var(--spacing-6);
|
|
497
|
+
`;
|
|
498
|
+
|
|
499
|
+
function CustomClassNamesExample() {
|
|
500
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
501
|
+
const items = [
|
|
502
|
+
{ title: 'Home', icon: 'home' },
|
|
503
|
+
{ title: 'Assets', icon: 'chartPie' },
|
|
504
|
+
{ title: 'Trade', icon: 'trading' },
|
|
505
|
+
{ title: 'Settings', icon: 'cog' },
|
|
506
|
+
];
|
|
507
|
+
|
|
508
|
+
return (
|
|
509
|
+
<Sidebar
|
|
510
|
+
logo={<LogoMark />}
|
|
511
|
+
classNames={{
|
|
512
|
+
logo: customLogoStyles,
|
|
513
|
+
}}
|
|
514
|
+
>
|
|
515
|
+
{items.map((item, index) => (
|
|
516
|
+
<SidebarItem
|
|
517
|
+
key={item.title}
|
|
518
|
+
active={index === activeIndex}
|
|
519
|
+
icon={item.icon}
|
|
520
|
+
onClick={() => setActiveIndex(index)}
|
|
521
|
+
title={item.title}
|
|
522
|
+
tooltipContent={item.title}
|
|
523
|
+
/>
|
|
524
|
+
))}
|
|
525
|
+
</Sidebar>
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
```
|
|
529
|
+
|
|
530
|
+
### Composed Examples
|
|
531
|
+
|
|
532
|
+
#### Application Shell
|
|
533
|
+
|
|
534
|
+
A complete application layout with sidebar navigation, main content area, and responsive behavior.
|
|
535
|
+
|
|
536
|
+
```jsx live
|
|
537
|
+
function ApplicationShell() {
|
|
538
|
+
const items = [
|
|
539
|
+
{ title: 'Dashboard', icon: 'home' },
|
|
540
|
+
{ title: 'Analytics', icon: 'chartPie' },
|
|
541
|
+
{ title: 'Transactions', icon: 'trading' },
|
|
542
|
+
{ title: 'Payments', icon: 'pay' },
|
|
543
|
+
{ title: 'News Feed', icon: 'newsFeed' },
|
|
544
|
+
{ title: 'Rewards', icon: 'giftBox' },
|
|
545
|
+
{ title: 'Lending', icon: 'cash' },
|
|
192
546
|
{ title: 'DeFi', icon: 'defi' },
|
|
193
547
|
];
|
|
194
548
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
195
549
|
const [moreMenuValue, setMoreMenuValue] = useState();
|
|
196
|
-
const navItems = items.slice(0,
|
|
197
|
-
const moreMenuOptions = items.slice(
|
|
550
|
+
const navItems = items.slice(0, 5);
|
|
551
|
+
const moreMenuOptions = items.slice(5);
|
|
552
|
+
|
|
198
553
|
const handleMoreMenuChange = (newValue) => {
|
|
199
554
|
const moreIndex =
|
|
200
555
|
moreMenuOptions.findIndex((option) => option.title === newValue) + navItems.length;
|
|
201
556
|
setActiveIndex(moreIndex);
|
|
202
557
|
setMoreMenuValue(newValue);
|
|
203
558
|
};
|
|
204
|
-
|
|
559
|
+
|
|
560
|
+
const handleItemPress = (index) => {
|
|
205
561
|
setActiveIndex(index);
|
|
206
562
|
setMoreMenuValue(undefined);
|
|
207
563
|
};
|
|
564
|
+
|
|
565
|
+
const currentPage = items[activeIndex]?.title || 'Dashboard';
|
|
566
|
+
|
|
208
567
|
return (
|
|
209
|
-
<HStack alignItems="
|
|
210
|
-
<Sidebar
|
|
568
|
+
<HStack alignItems="stretch" height={400} overflow="hidden">
|
|
569
|
+
<Sidebar
|
|
570
|
+
autoCollapse
|
|
571
|
+
logo={<LogoMark />}
|
|
572
|
+
renderEnd={(isCollapsed) => (
|
|
573
|
+
<VStack gap={1}>
|
|
574
|
+
<Pressable
|
|
575
|
+
as="button"
|
|
576
|
+
background="bgPrimaryWash"
|
|
577
|
+
borderRadius={1000}
|
|
578
|
+
transparentWhileInactive
|
|
579
|
+
width="100%"
|
|
580
|
+
>
|
|
581
|
+
<HStack alignItems="center" gap={2} paddingX={2} paddingY={2}>
|
|
582
|
+
<Icon name="cog" />
|
|
583
|
+
{!isCollapsed && <TextHeadline as="span">Settings</TextHeadline>}
|
|
584
|
+
</HStack>
|
|
585
|
+
</Pressable>
|
|
586
|
+
<Pressable
|
|
587
|
+
as="button"
|
|
588
|
+
background="bgPrimaryWash"
|
|
589
|
+
borderRadius={1000}
|
|
590
|
+
transparentWhileInactive
|
|
591
|
+
width="100%"
|
|
592
|
+
>
|
|
593
|
+
<HStack alignItems="center" gap={2} paddingX={2} paddingY={2}>
|
|
594
|
+
<Avatar size="s" />
|
|
595
|
+
{!isCollapsed && <TextHeadline as="span">Profile</TextHeadline>}
|
|
596
|
+
</HStack>
|
|
597
|
+
</Pressable>
|
|
598
|
+
</VStack>
|
|
599
|
+
)}
|
|
600
|
+
>
|
|
211
601
|
{navItems.map((item, index) => (
|
|
212
602
|
<SidebarItem
|
|
213
|
-
key={
|
|
603
|
+
key={item.title}
|
|
214
604
|
active={index === activeIndex}
|
|
215
|
-
|
|
605
|
+
icon={item.icon}
|
|
606
|
+
onClick={() => handleItemPress(index)}
|
|
607
|
+
title={item.title}
|
|
216
608
|
tooltipContent={item.title}
|
|
217
|
-
{...item}
|
|
218
609
|
/>
|
|
219
610
|
))}
|
|
220
611
|
<SidebarMoreMenu
|
|
@@ -225,7 +616,7 @@ function Example() {
|
|
|
225
616
|
>
|
|
226
617
|
{moreMenuOptions.map((item) => (
|
|
227
618
|
<SelectOption
|
|
228
|
-
key={
|
|
619
|
+
key={item.title}
|
|
229
620
|
description={item.title}
|
|
230
621
|
media={<Icon name={item.icon} />}
|
|
231
622
|
value={item.title}
|
|
@@ -233,6 +624,69 @@ function Example() {
|
|
|
233
624
|
))}
|
|
234
625
|
</SidebarMoreMenu>
|
|
235
626
|
</Sidebar>
|
|
627
|
+
<VStack background="bgAlternate" flexGrow={1} padding={3}>
|
|
628
|
+
<Text as="h1" font="title2">
|
|
629
|
+
{currentPage}
|
|
630
|
+
</Text>
|
|
631
|
+
<Text color="fgMuted" font="body">
|
|
632
|
+
Welcome to the {currentPage.toLowerCase()} page. This is a sample application shell
|
|
633
|
+
demonstrating the Sidebar component with responsive behavior.
|
|
634
|
+
</Text>
|
|
635
|
+
</VStack>
|
|
636
|
+
</HStack>
|
|
637
|
+
);
|
|
638
|
+
}
|
|
639
|
+
```
|
|
640
|
+
|
|
641
|
+
#### Condensed Trading Interface
|
|
642
|
+
|
|
643
|
+
A condensed sidebar optimized for professional trading interfaces with minimal visual footprint.
|
|
644
|
+
|
|
645
|
+
```jsx live
|
|
646
|
+
function TradingInterface() {
|
|
647
|
+
const items = [
|
|
648
|
+
{ title: 'Spot', icon: 'chartCandles' },
|
|
649
|
+
{ title: 'Futures', icon: 'chartBar' },
|
|
650
|
+
{ title: 'Portfolio', icon: 'chartPie' },
|
|
651
|
+
{ title: 'Orders', icon: 'documentation' },
|
|
652
|
+
];
|
|
653
|
+
const [activeIndex, setActiveIndex] = useState(0);
|
|
654
|
+
|
|
655
|
+
return (
|
|
656
|
+
<HStack>
|
|
657
|
+
<Sidebar logo={<LogoMark foreground />} variant="condensed">
|
|
658
|
+
{items.map((item, index) => (
|
|
659
|
+
<SidebarItem
|
|
660
|
+
key={item.title}
|
|
661
|
+
active={index === activeIndex}
|
|
662
|
+
icon={item.icon}
|
|
663
|
+
onClick={() => setActiveIndex(index)}
|
|
664
|
+
title={item.title}
|
|
665
|
+
/>
|
|
666
|
+
))}
|
|
667
|
+
</Sidebar>
|
|
668
|
+
<VStack background="bgAlternate" flexGrow={1} gap={2} padding={3}>
|
|
669
|
+
<HStack justifyContent="space-between">
|
|
670
|
+
<Text font="title3">BTC/USD</Text>
|
|
671
|
+
<Text color="fgPositive" font="title3">
|
|
672
|
+
$67,432.50
|
|
673
|
+
</Text>
|
|
674
|
+
</HStack>
|
|
675
|
+
<Box
|
|
676
|
+
background="bg"
|
|
677
|
+
borderRadius={200}
|
|
678
|
+
flexGrow={1}
|
|
679
|
+
style={{
|
|
680
|
+
display: 'flex',
|
|
681
|
+
alignItems: 'center',
|
|
682
|
+
justifyContent: 'center',
|
|
683
|
+
}}
|
|
684
|
+
>
|
|
685
|
+
<Text color="fgMuted" font="label1">
|
|
686
|
+
{items[activeIndex].title} Chart Area
|
|
687
|
+
</Text>
|
|
688
|
+
</Box>
|
|
689
|
+
</VStack>
|
|
236
690
|
</HStack>
|
|
237
691
|
);
|
|
238
692
|
}
|
|
@@ -269,6 +723,7 @@ function Example() {
|
|
|
269
723
|
| `borderedTop` | `boolean` | No | `-` | Add a border to the top side of the box. |
|
|
270
724
|
| `borderedVertical` | `boolean` | No | `-` | Add a border to the top and bottom sides of the box. |
|
|
271
725
|
| `bottom` | `ResponsiveProp<Bottom<string \| number>>` | No | `-` | - |
|
|
726
|
+
| `classNames` | `{ root?: string; logo?: string \| undefined; content?: string \| undefined; end?: string \| undefined; } \| undefined` | No | `-` | Custom class names for the sidebar components. |
|
|
272
727
|
| `collapsed` | `boolean` | No | `false` | Use collapsed to show only the logo |
|
|
273
728
|
| `color` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `-` | - |
|
|
274
729
|
| `columnGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
@@ -334,6 +789,7 @@ function Example() {
|
|
|
334
789
|
| `right` | `ResponsiveProp<Right<string \| number>>` | No | `-` | - |
|
|
335
790
|
| `rowGap` | `0 \| 1 \| 2 \| 0.25 \| 0.5 \| 0.75 \| 1.5 \| 3 \| 4 \| 5 \| 6 \| 7 \| 8 \| 9 \| 10` | No | `-` | - |
|
|
336
791
|
| `style` | `CSSProperties` | No | `-` | - |
|
|
792
|
+
| `styles` | `{ root?: CSSProperties; logo?: CSSProperties \| undefined; content?: CSSProperties \| undefined; end?: CSSProperties \| undefined; } \| undefined` | No | `-` | Custom styles for the sidebar components. |
|
|
337
793
|
| `testID` | `string` | No | `-` | Used to locate this element in unit and end-to-end tests. Under the hood, testID translates to data-testid on Web. On Mobile, testID stays the same - testID |
|
|
338
794
|
| `textAlign` | `ResponsiveProp<center \| start \| end \| justify>` | No | `-` | - |
|
|
339
795
|
| `textDecoration` | `ResponsiveProp<none \| underline \| overline \| line-through \| underline overline \| underline double>` | No | `-` | - |
|
|
@@ -660,6 +660,7 @@ function TextInputKeyboardExample() {
|
|
|
660
660
|
| `height` | `((Height<string \| number> \| { base?: Height<string \| number>; phone?: Height<string \| number> \| undefined; tablet?: Height<string \| number> \| undefined; desktop?: Height<string \| number> \| undefined; }) & (string \| number)) \| undefined` | No | `-` | Height of input |
|
|
661
661
|
| `helperText` | `null \| string \| number \| false \| true \| ReactElement<any, string \| JSXElementConstructor<any>> \| Iterable<ReactNode> \| ReactPortal` | No | `-` | For cases where label is not enough information to describe what the text input is for. Can also be used for showing positive/negative messages |
|
|
662
662
|
| `helperTextErrorIconAccessibilityLabel` | `string` | No | `'error'` | Accessibility label for helper text error icon when variant=negative |
|
|
663
|
+
| `inputBackground` | `currentColor \| fg \| fgMuted \| fgInverse \| fgPrimary \| fgWarning \| fgPositive \| fgNegative \| bg \| bgAlternate \| bgInverse \| bgOverlay \| bgElevation1 \| bgElevation2 \| bgPrimary \| bgPrimaryWash \| bgSecondary \| bgTertiary \| bgSecondaryWash \| bgNegative \| bgNegativeWash \| bgPositive \| bgPositiveWash \| bgWarning \| bgWarningWash \| bgLine \| bgLineHeavy \| bgLineInverse \| bgLinePrimary \| bgLinePrimarySubtle \| accentSubtleRed \| accentBoldRed \| accentSubtleGreen \| accentBoldGreen \| accentSubtleBlue \| accentBoldBlue \| accentSubtlePurple \| accentBoldPurple \| accentSubtleYellow \| accentBoldYellow \| accentSubtleGray \| accentBoldGray \| transparent` | No | `'bg'` | Background color of the input. |
|
|
663
664
|
| `inputNode` | `ReactElement` | No | `-` | Customize the element which the input area will be rendered as. Adds ability to render the input area as a <textarea />, <input /> etc... By default, the input area will be rendered as an <input />. |
|
|
664
665
|
| `key` | `Key \| null` | No | `-` | - |
|
|
665
666
|
| `label` | `string` | No | `-` | Short messageArea indicating purpose of input |
|
package/mcp-docs/web/routes.txt
CHANGED
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
- [Stepper](web/components/Stepper.txt): A component that visualizes states within a multi-step process.
|
|
48
48
|
- [SidebarMoreMenu](web/components/SidebarMoreMenu.txt): SidebarMoreMenu provides a dropdown menu for additional navigation options in the Sidebar.
|
|
49
49
|
- [SidebarItem](web/components/SidebarItem.txt): SidebarItem represents a single navigation item within the Sidebar component.
|
|
50
|
-
- [Sidebar](web/components/Sidebar.txt): A vertical navigation
|
|
50
|
+
- [Sidebar](web/components/Sidebar.txt): A composable and customizable vertical navigation component with support for multiple variants, collapsible states, and custom content areas.
|
|
51
51
|
- [SegmentedTabs](web/components/SegmentedTabs.txt): Switches between different views of content.
|
|
52
52
|
- [SectionHeader](web/components/SectionHeader.txt): A header component used to organize and label sections of content, with support for icons, descriptions, and additional content.
|
|
53
53
|
- [Pagination](web/components/Pagination.txt): Pagination is used to navigate through a list of items.
|