@czi-sds/mcp 0.16.0 → 0.18.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/README.md +2 -1
- package/data/component-docs/Accordion.md +291 -0
- package/data/component-docs/Autocomplete.md +525 -0
- package/data/component-docs/Banner.md +231 -0
- package/data/component-docs/Button.md +224 -0
- package/data/component-docs/ButtonDropdown.md +256 -0
- package/data/component-docs/ButtonGroup.md +320 -0
- package/data/component-docs/ButtonToggle.md +397 -0
- package/data/component-docs/Callout.md +268 -0
- package/data/component-docs/CellBasic.md +122 -0
- package/data/component-docs/CellComponent.md +63 -0
- package/data/component-docs/CellHeader.md +128 -0
- package/data/component-docs/ComplexFilter.md +294 -0
- package/data/component-docs/ContentCard.md +406 -0
- package/data/component-docs/Dialog.md +651 -0
- package/data/component-docs/Dropdown.md +155 -0
- package/data/component-docs/DropdownMenu.md +949 -0
- package/data/component-docs/HeatmapChart.md +782 -0
- package/data/component-docs/Hero.md +363 -0
- package/data/component-docs/Icon.md +283 -0
- package/data/component-docs/InputCheckbox.md +205 -0
- package/data/component-docs/InputDropdown.md +482 -0
- package/data/component-docs/InputRadio.md +173 -0
- package/data/component-docs/InputSearch.md +81 -0
- package/data/component-docs/InputSlider.md +189 -0
- package/data/component-docs/InputText.md +110 -0
- package/data/component-docs/InputToggle.md +141 -0
- package/data/component-docs/IntentMessage.md +293 -0
- package/data/component-docs/Legend.md +442 -0
- package/data/component-docs/Link.md +23 -0
- package/data/component-docs/List.md +300 -0
- package/data/component-docs/LoadingIndicator.md +198 -0
- package/data/component-docs/Menu.md +298 -0
- package/data/component-docs/MenuItem.md +100 -0
- package/data/component-docs/NavigationFooter.md +165 -0
- package/data/component-docs/NavigationHeader.md +500 -0
- package/data/component-docs/NavigationJumpTo.md +414 -0
- package/data/component-docs/Notification.md +288 -0
- package/data/component-docs/Pagination.md +67 -0
- package/data/component-docs/Panel.md +636 -0
- package/data/component-docs/Popover.md +448 -0
- package/data/component-docs/PreComposedTable.md +2947 -0
- package/data/component-docs/ProteinStructureViewer.md +1044 -0
- package/data/component-docs/SegmentedControl.md +396 -0
- package/data/component-docs/StackedBarChart.md +475 -0
- package/data/component-docs/Table.md +2000 -0
- package/data/component-docs/TableHeader.md +53 -0
- package/data/component-docs/TableRow.md +74 -0
- package/data/component-docs/Tabs.md +455 -0
- package/data/component-docs/Tag.md +647 -0
- package/data/component-docs/TagFilter.md +131 -0
- package/data/component-docs/Tooltip.md +561 -0
- package/data/component-docs/TooltipCondensed.md +203 -0
- package/data/component-docs/TooltipTable.md +145 -0
- package/data/component-docs/index.json +267 -0
- package/data/component-list.json +2 -5
- package/data/component-props/Accordion.json +31 -11
- package/data/component-props/Alert.json +3 -3
- package/data/component-props/Autocomplete.json +150 -15
- package/data/component-props/Banner.json +31 -17
- package/data/component-props/Button.json +45 -20
- package/data/component-props/ButtonDropdown.json +36 -17
- package/data/component-props/ButtonDropdownLegacy.json +11 -11
- package/data/component-props/ButtonGroup.json +32 -11
- package/data/component-props/ButtonIcon.json +10 -10
- package/data/component-props/ButtonLegacy.json +19 -19
- package/data/component-props/ButtonToggle.json +32 -19
- package/data/component-props/ButtonToggleLegacy.json +11 -11
- package/data/component-props/Callout.json +58 -17
- package/data/component-props/CellBasic.json +94 -41
- package/data/component-props/CellComponent.json +23 -7
- package/data/component-props/CellHeader.json +62 -19
- package/data/component-props/ComplexFilter.json +52 -21
- package/data/component-props/ContentCard.json +70 -47
- package/data/component-props/Dialog.json +47 -14
- package/data/component-props/Dropdown.json +68 -31
- package/data/component-props/DropdownMenu.json +128 -23
- package/data/component-props/HeatmapChart.json +88 -12
- package/data/component-props/Hero.json +80 -39
- package/data/component-props/Icon.json +20 -9
- package/data/component-props/InputCheckbox.json +36 -14
- package/data/component-props/InputDropdown.json +75 -27
- package/data/component-props/InputRadio.json +31 -13
- package/data/component-props/InputSearch.json +41 -18
- package/data/component-props/InputSlider.json +46 -19
- package/data/component-props/InputText.json +26 -19
- package/data/component-props/InputToggle.json +26 -9
- package/data/component-props/IntentMessage.json +38 -9
- package/data/component-props/Link.json +13 -7
- package/data/component-props/LoadingIndicator.json +11 -3
- package/data/component-props/MenuItem.json +38 -19
- package/data/component-props/MenuSelect.json +8 -8
- package/data/component-props/NavigationFooter.json +49 -19
- package/data/component-props/NavigationHeader.json +150 -37
- package/data/component-props/NavigationJumpTo.json +33 -7
- package/data/component-props/Notification.json +39 -21
- package/data/component-props/Pagination.json +39 -11
- package/data/component-props/Panel.json +62 -9
- package/data/component-props/Popover.json +80 -7
- package/data/component-props/PreComposedTable.json +99 -27
- package/data/component-props/ProteinStructureViewer.json +117 -0
- package/data/component-props/SegmentedControl.json +42 -3
- package/data/component-props/StackedBarChart.json +116 -42
- package/data/component-props/TableRow.json +38 -19
- package/data/component-props/Tabs.json +66 -9
- package/data/component-props/Tag.json +34 -17
- package/data/component-props/TagFilter.json +10 -3
- package/data/component-props/Tooltip.json +49 -18
- package/data/component-props/TooltipCondensed.json +18 -9
- package/data/component-props/TooltipTable.json +17 -7
- package/data/resources/{zeroheight-rules.md → documentation-rules.md} +43 -30
- package/data/resources/figma-rules.md +2 -2
- package/data/tailwind.json +20 -14
- package/dist/stdio.js +112 -208
- package/package.json +9 -5
- package/data/component-props/ButtonDropdownV2.json +0 -34
- package/data/component-props/ButtonNew.json +0 -47
- package/data/component-props/ButtonToggleV2.json +0 -44
- package/data/component-props/ButtonV2.json +0 -43
- package/data/zeroheight-cache.json +0 -10259
- package/data/zeroheight-exports/Accordion.md +0 -774
- package/data/zeroheight-exports/Banner.md +0 -691
- package/data/zeroheight-exports/Borders.md +0 -117
- package/data/zeroheight-exports/Buttons.md +0 -1854
- package/data/zeroheight-exports/Callout.md +0 -931
- package/data/zeroheight-exports/Colors.md +0 -1755
- package/data/zeroheight-exports/Content-Card.md +0 -309
- package/data/zeroheight-exports/Contributing-to-SDS.md +0 -98
- package/data/zeroheight-exports/Control-Inputs.md +0 -2818
- package/data/zeroheight-exports/Corners.md +0 -104
- package/data/zeroheight-exports/Cover-page.md +0 -3
- package/data/zeroheight-exports/Dialog.md +0 -1367
- package/data/zeroheight-exports/Downloads.md +0 -236
- package/data/zeroheight-exports/Drop-Shadows.md +0 -79
- package/data/zeroheight-exports/Dropdown-Input.md +0 -1776
- package/data/zeroheight-exports/Dropdown-Menus.md +0 -913
- package/data/zeroheight-exports/Element-Status-Tracker.md +0 -267
- package/data/zeroheight-exports/Field-Inputs.md +0 -1405
- package/data/zeroheight-exports/Filters.md +0 -1111
- package/data/zeroheight-exports/Getting-Started.md +0 -1157
- package/data/zeroheight-exports/Hero.md +0 -414
- package/data/zeroheight-exports/Icons.md +0 -2067
- package/data/zeroheight-exports/Intent.md +0 -86
- package/data/zeroheight-exports/Introduction-to-Bases.md +0 -35
- package/data/zeroheight-exports/Introduction-to-Cells.md +0 -35
- package/data/zeroheight-exports/Introduction-to-DNA.md +0 -35
- package/data/zeroheight-exports/Introduction-to-Genes.md +0 -35
- package/data/zeroheight-exports/Introduction.md +0 -115
- package/data/zeroheight-exports/Link.md +0 -432
- package/data/zeroheight-exports/Lists.md +0 -986
- package/data/zeroheight-exports/Loading-Indicator.md +0 -41
- package/data/zeroheight-exports/Navigation.md +0 -1190
- package/data/zeroheight-exports/Notification.md +0 -1038
- package/data/zeroheight-exports/Panel.md +0 -1030
- package/data/zeroheight-exports/README.md +0 -122
- package/data/zeroheight-exports/Responsive-Design.md +0 -330
- package/data/zeroheight-exports/Search-Input.md +0 -91
- package/data/zeroheight-exports/Search.md +0 -822
- package/data/zeroheight-exports/Segmented-Control.md +0 -609
- package/data/zeroheight-exports/Spacing.md +0 -297
- package/data/zeroheight-exports/Table.md +0 -5345
- package/data/zeroheight-exports/Tabs.md +0 -1324
- package/data/zeroheight-exports/Tags.md +0 -1545
- package/data/zeroheight-exports/Text-Link.md +0 -268
- package/data/zeroheight-exports/Theming.md +0 -362
- package/data/zeroheight-exports/Tooltips.md +0 -2015
- package/data/zeroheight-exports/Typography.md +0 -800
|
@@ -0,0 +1,396 @@
|
|
|
1
|
+
# SegmentedControl
|
|
2
|
+
|
|
3
|
+
## Source Code
|
|
4
|
+
|
|
5
|
+
The component's source code in the SDS codebase can be found [here](https://github.com/chanzuckerberg/sci-components/blob/main/packages/components/src/core/SegmentedControl/index.tsx).
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
**React TypeScript**
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { SegmentedControl } from "@czi-sds/components";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Code examples
|
|
16
|
+
|
|
17
|
+
### Default SegmentedControl
|
|
18
|
+
|
|
19
|
+
Three icon segments, left uncontrolled so the control tracks the selection itself. No tooltip text is set, so each segment falls back to its value.
|
|
20
|
+
|
|
21
|
+
**Example: DefaultSegmentedControl**
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import {
|
|
25
|
+
SegmentedControl,
|
|
26
|
+
type SingleButtonDefinition,
|
|
27
|
+
} from "@czi-sds/components";
|
|
28
|
+
|
|
29
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
30
|
+
{ icon: "List", value: "List" },
|
|
31
|
+
{ icon: "Table", value: "Table" },
|
|
32
|
+
{ icon: "TreeVertical", value: "Tree" },
|
|
33
|
+
];
|
|
34
|
+
|
|
35
|
+
function App() {
|
|
36
|
+
return (
|
|
37
|
+
<div className="app">
|
|
38
|
+
<SegmentedControl buttonDefinition={VIEWS} />
|
|
39
|
+
</div>
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default App;
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Segments with labels
|
|
47
|
+
|
|
48
|
+
A label replaces the icon on a segment. These have their tooltips turned off, since the text is already on screen.
|
|
49
|
+
|
|
50
|
+
**Example: SegmentedControlWithLabels**
|
|
51
|
+
|
|
52
|
+
```tsx
|
|
53
|
+
// A segment shows text instead of an icon when it is given a label. Setting both
|
|
54
|
+
// on one segment is a mistake: the label wins, the icon never renders, and the
|
|
55
|
+
// console carries a warning.
|
|
56
|
+
//
|
|
57
|
+
// A labelled segment already says what it is, so the tooltip would only repeat
|
|
58
|
+
// it. shouldShowTooltip turns that off. The label is also the accessible name
|
|
59
|
+
// here, so the value is free to stay a plain identifier.
|
|
60
|
+
|
|
61
|
+
import {
|
|
62
|
+
SegmentedControl,
|
|
63
|
+
type SingleButtonDefinition,
|
|
64
|
+
} from "@czi-sds/components";
|
|
65
|
+
|
|
66
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
67
|
+
{ label: "Explorer", shouldShowTooltip: false, value: "explorer" },
|
|
68
|
+
{ label: "All data", shouldShowTooltip: false, value: "all-data" },
|
|
69
|
+
{ label: "Summary", shouldShowTooltip: false, value: "summary" },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
function App() {
|
|
73
|
+
return (
|
|
74
|
+
<div className="app">
|
|
75
|
+
<SegmentedControl buttonDefinition={VIEWS} />
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default App;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### Controlled SegmentedControl
|
|
84
|
+
|
|
85
|
+
The selection is held in the page's state and written back from `onChange`, which also ignores the `null` that a click on the selected segment reports, so the control always shows a view.
|
|
86
|
+
|
|
87
|
+
**Example: ControlledSegmentedControl**
|
|
88
|
+
|
|
89
|
+
```tsx
|
|
90
|
+
// Passing value makes the control controlled: it shows the segment you name and
|
|
91
|
+
// stops tracking clicks on its own, so onChange has to write the new value back.
|
|
92
|
+
//
|
|
93
|
+
// Clicking the selected segment again reports null, which would leave the control
|
|
94
|
+
// with nothing selected. A view switcher has to show something, so this handler
|
|
95
|
+
// ignores null and keeps the current view.
|
|
96
|
+
|
|
97
|
+
import {
|
|
98
|
+
SegmentedControl,
|
|
99
|
+
fontBodyXs,
|
|
100
|
+
getSemanticColors,
|
|
101
|
+
getSpaces,
|
|
102
|
+
type CommonThemeProps,
|
|
103
|
+
type SingleButtonDefinition,
|
|
104
|
+
} from "@czi-sds/components";
|
|
105
|
+
import styled from "@emotion/styled";
|
|
106
|
+
import { useState } from "react";
|
|
107
|
+
|
|
108
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
109
|
+
{ icon: "List", value: "List" },
|
|
110
|
+
{ icon: "Table", value: "Table" },
|
|
111
|
+
{ icon: "TreeVertical", value: "Tree" },
|
|
112
|
+
];
|
|
113
|
+
|
|
114
|
+
const Readout = styled.p<CommonThemeProps>`
|
|
115
|
+
${fontBodyXs}
|
|
116
|
+
|
|
117
|
+
${(props) => {
|
|
118
|
+
const semanticColors = getSemanticColors(props);
|
|
119
|
+
const spaces = getSpaces(props);
|
|
120
|
+
|
|
121
|
+
return `
|
|
122
|
+
color: ${semanticColors?.base?.textSecondary};
|
|
123
|
+
margin: ${spaces?.m}px 0 0;
|
|
124
|
+
`;
|
|
125
|
+
}}
|
|
126
|
+
`;
|
|
127
|
+
|
|
128
|
+
function App() {
|
|
129
|
+
const [view, setView] = useState("Table");
|
|
130
|
+
|
|
131
|
+
return (
|
|
132
|
+
<div className="app">
|
|
133
|
+
<SegmentedControl
|
|
134
|
+
buttonDefinition={VIEWS}
|
|
135
|
+
onChange={(_event, newView: string | null) => {
|
|
136
|
+
if (newView !== null) {
|
|
137
|
+
setView(newView);
|
|
138
|
+
}
|
|
139
|
+
}}
|
|
140
|
+
value={view}
|
|
141
|
+
/>
|
|
142
|
+
|
|
143
|
+
<Readout>Showing the {view.toLowerCase()} view</Readout>
|
|
144
|
+
</div>
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export default App;
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
### Disabled segments
|
|
152
|
+
|
|
153
|
+
A single segment turned off, next to a control turned off as a whole. The first control opens on its second segment, because an uncontrolled control skips the disabled one.
|
|
154
|
+
|
|
155
|
+
**Example: SegmentedControlWithDisabledItems**
|
|
156
|
+
|
|
157
|
+
```tsx
|
|
158
|
+
// A disabled segment cannot be clicked and shows no tooltip, since a control that
|
|
159
|
+
// will not respond has nothing to explain. The uncontrolled starting selection
|
|
160
|
+
// skips it too, so the first control below opens on Table rather than on List.
|
|
161
|
+
//
|
|
162
|
+
// The disabled prop on the control itself, rather than on a segment, turns every
|
|
163
|
+
// segment off at once while leaving the current selection visible.
|
|
164
|
+
|
|
165
|
+
import {
|
|
166
|
+
SegmentedControl,
|
|
167
|
+
fontBodyXs,
|
|
168
|
+
getSemanticColors,
|
|
169
|
+
getSpaces,
|
|
170
|
+
type CommonThemeProps,
|
|
171
|
+
type SingleButtonDefinition,
|
|
172
|
+
} from "@czi-sds/components";
|
|
173
|
+
import styled from "@emotion/styled";
|
|
174
|
+
|
|
175
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
176
|
+
{ disabled: true, icon: "List", value: "List" },
|
|
177
|
+
{ icon: "Table", value: "Table" },
|
|
178
|
+
{ icon: "TreeVertical", value: "Tree" },
|
|
179
|
+
];
|
|
180
|
+
|
|
181
|
+
const Row = styled.div<CommonThemeProps>`
|
|
182
|
+
${(props) => {
|
|
183
|
+
const spaces = getSpaces(props);
|
|
184
|
+
|
|
185
|
+
return `
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
gap: ${spaces?.xxs}px;
|
|
189
|
+
`;
|
|
190
|
+
}}
|
|
191
|
+
`;
|
|
192
|
+
|
|
193
|
+
const Stack = styled.div<CommonThemeProps>`
|
|
194
|
+
${(props) => {
|
|
195
|
+
const spaces = getSpaces(props);
|
|
196
|
+
|
|
197
|
+
return `
|
|
198
|
+
display: flex;
|
|
199
|
+
flex-wrap: wrap;
|
|
200
|
+
gap: ${spaces?.xxl}px;
|
|
201
|
+
`;
|
|
202
|
+
}}
|
|
203
|
+
`;
|
|
204
|
+
|
|
205
|
+
const Caption = styled.p<CommonThemeProps>`
|
|
206
|
+
${fontBodyXs}
|
|
207
|
+
|
|
208
|
+
${(props) => {
|
|
209
|
+
const semanticColors = getSemanticColors(props);
|
|
210
|
+
|
|
211
|
+
return `
|
|
212
|
+
color: ${semanticColors?.base?.textSecondary};
|
|
213
|
+
margin: 0;
|
|
214
|
+
`;
|
|
215
|
+
}}
|
|
216
|
+
`;
|
|
217
|
+
|
|
218
|
+
function App() {
|
|
219
|
+
return (
|
|
220
|
+
<div className="app">
|
|
221
|
+
<Stack>
|
|
222
|
+
<Row>
|
|
223
|
+
<SegmentedControl buttonDefinition={VIEWS} />
|
|
224
|
+
<Caption>One segment disabled</Caption>
|
|
225
|
+
</Row>
|
|
226
|
+
|
|
227
|
+
<Row>
|
|
228
|
+
<SegmentedControl buttonDefinition={VIEWS} disabled />
|
|
229
|
+
<Caption>The whole control disabled</Caption>
|
|
230
|
+
</Row>
|
|
231
|
+
</Stack>
|
|
232
|
+
</div>
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
export default App;
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### Richer tooltips
|
|
240
|
+
|
|
241
|
+
`tooltipProps` reaches the Tooltip behind each segment, for a subtitle under the title or a placement other than above the control.
|
|
242
|
+
|
|
243
|
+
**Example: SegmentedControlTooltips**
|
|
244
|
+
|
|
245
|
+
```tsx
|
|
246
|
+
// Each segment builds its own tooltip, so tooltipProps is set per segment rather
|
|
247
|
+
// than on the control. Anything the SDS Tooltip takes belongs there: a title, a
|
|
248
|
+
// subtitle underneath it, a placement other than the default above the control.
|
|
249
|
+
//
|
|
250
|
+
// Only the tooltip changes. The accessible name still comes from the segment's
|
|
251
|
+
// value, not from tooltipProps.title, so the values here stay readable.
|
|
252
|
+
//
|
|
253
|
+
// tooltipText is the older way to set a bare title. It is deprecated, warns in
|
|
254
|
+
// the console, and overrides tooltipProps.title when both are set.
|
|
255
|
+
|
|
256
|
+
import {
|
|
257
|
+
SegmentedControl,
|
|
258
|
+
type SingleButtonDefinition,
|
|
259
|
+
} from "@czi-sds/components";
|
|
260
|
+
|
|
261
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
262
|
+
{
|
|
263
|
+
icon: "List",
|
|
264
|
+
tooltipProps: {
|
|
265
|
+
subtitle: "One row per sample, sorted by collection date",
|
|
266
|
+
title: "List",
|
|
267
|
+
},
|
|
268
|
+
value: "List",
|
|
269
|
+
},
|
|
270
|
+
{
|
|
271
|
+
icon: "Table",
|
|
272
|
+
tooltipProps: {
|
|
273
|
+
subtitle: "Every measured field, side by side",
|
|
274
|
+
title: "Table",
|
|
275
|
+
},
|
|
276
|
+
value: "Table",
|
|
277
|
+
},
|
|
278
|
+
{
|
|
279
|
+
icon: "TreeVertical",
|
|
280
|
+
tooltipProps: { placement: "bottom", title: "Tree, explained below" },
|
|
281
|
+
value: "Tree",
|
|
282
|
+
},
|
|
283
|
+
];
|
|
284
|
+
|
|
285
|
+
function App() {
|
|
286
|
+
return (
|
|
287
|
+
<div className="app">
|
|
288
|
+
<SegmentedControl buttonDefinition={VIEWS} />
|
|
289
|
+
</div>
|
|
290
|
+
);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
export default App;
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### A segment with its own artwork
|
|
297
|
+
|
|
298
|
+
`icon` takes an SVG element as well as an SDS icon name, which covers artwork the SDS set does not carry.
|
|
299
|
+
|
|
300
|
+
**Example: SegmentedControlCustomIcon**
|
|
301
|
+
|
|
302
|
+
```tsx
|
|
303
|
+
// icon takes an SVG element as well as an SDS icon name, which covers artwork the
|
|
304
|
+
// SDS set does not carry and icons it only draws at 24px. The element is rendered
|
|
305
|
+
// as it is given, so size it to 16px yourself and fill it with currentColor so it
|
|
306
|
+
// picks up the segment's colour as the selection moves.
|
|
307
|
+
|
|
308
|
+
import {
|
|
309
|
+
SegmentedControl,
|
|
310
|
+
type SingleButtonDefinition,
|
|
311
|
+
} from "@czi-sds/components";
|
|
312
|
+
|
|
313
|
+
const HexagonIcon = (
|
|
314
|
+
<svg fill="currentColor" height={16} viewBox="0 0 16 16" width={16}>
|
|
315
|
+
<path d="M8 1.5l5.5 3.25v6.5L8 14.5 2.5 11.25v-6.5L8 1.5z" />
|
|
316
|
+
</svg>
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
const VIEWS: SingleButtonDefinition[] = [
|
|
320
|
+
{ icon: "List", value: "List" },
|
|
321
|
+
{ icon: "Table", value: "Table" },
|
|
322
|
+
{ icon: HexagonIcon, value: "Cells" },
|
|
323
|
+
];
|
|
324
|
+
|
|
325
|
+
function App() {
|
|
326
|
+
return (
|
|
327
|
+
<div className="app">
|
|
328
|
+
<SegmentedControl buttonDefinition={VIEWS} />
|
|
329
|
+
</div>
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export default App;
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## SDS vs MUI
|
|
337
|
+
|
|
338
|
+
The SDS SegmentedControl wraps MUI's ToggleButtonGroup, with these differences:
|
|
339
|
+
|
|
340
|
+
- **buttonDefinition instead of children:** MUI expects you to write a ToggleButton per segment. SDS builds them from an array instead, one entry per segment in array order, and the segments it builds are the control's only children. Anything you nest inside a SegmentedControl is dropped without a warning.
|
|
341
|
+
|
|
342
|
+
- **Tooltips are built in:** each segment is wrapped in an SDS Tooltip unless you turn it off with `shouldShowTooltip`, which is what carries the meaning of an icon-only segment. In MUI you would add the tooltip yourself.
|
|
343
|
+
|
|
344
|
+
- **It works uncontrolled:** MUI's ToggleButtonGroup only renders the `value` you hand it. SDS keeps its own state until you pass `value`, so a control left alone still responds to clicks, starting on the first segment that is not disabled.
|
|
345
|
+
|
|
346
|
+
- **exclusive is set for you:** the control selects one segment at a time and reports a single string. Multi-select is not available: passing `exclusive={false}` reaches MUI, which then treats that string as a list and joins the values together, so the control reports something like "ListTable" and shows nothing as selected. Leave it as it is.
|
|
347
|
+
|
|
348
|
+
- **Sizing and colour props do nothing:** `size`, `color`, `fullWidth` and `orientation` all reach MUI and set their classes, but SDS pins the padding, typography, palette, width and direction, so the control looks the same either way. It is always horizontal, always sized to its content, and never fills its container.
|
|
349
|
+
|
|
350
|
+
## MUI Documentation
|
|
351
|
+
|
|
352
|
+
Documentation for the underlying MUI component can be found [here](https://mui.com/material-ui/react-toggle-button/).
|
|
353
|
+
|
|
354
|
+
## Behavior and accessibility
|
|
355
|
+
|
|
356
|
+
- A control left uncontrolled opens on the first segment that is not disabled. Pass `value` to control it instead, and write the new value back from `onChange`, or the control will render the same segment no matter what is clicked.
|
|
357
|
+
|
|
358
|
+
- Clicking the selected segment deselects it. The control reports `null` and draws nothing as selected, which suits a filter that can be cleared but not a view switcher that must always show something. A controlled handler that ignores `null` keeps the current selection instead.
|
|
359
|
+
|
|
360
|
+
- Every segment needs either an `icon` or a `label`. A segment with both draws only the label; a segment with neither draws its value as text. Both cases log a warning.
|
|
361
|
+
|
|
362
|
+
- A segment's accessible name is its `label`, or its `value` when it carries an icon instead. It is not taken from `tooltipProps.title`, so an icon-only segment with a value like `"a"` or `"1"` is announced that way. Give icon-only segments values that read as words.
|
|
363
|
+
|
|
364
|
+
- Icons are drawn at the small size, so only icons that SDS carries at 16px can be named here. A large-only icon leaves the segment empty and logs an error; pass your own SVG element instead.
|
|
365
|
+
|
|
366
|
+
- Tooltips appear on hover and on keyboard focus, which is what makes an icon-only control usable from the keyboard. Disabled segments show no tooltip at all.
|
|
367
|
+
|
|
368
|
+
- The control is sized to its segments and does not wrap or shrink, so a long set of labels overflows a narrow container rather than reflowing. The design guidance above (two to four segments) keeps that from happening.
|
|
369
|
+
|
|
370
|
+
- Segments are ordinary buttons, so Tab moves through them one at a time rather than treating the group as a single stop, and Space or Enter selects.
|
|
371
|
+
|
|
372
|
+
## Props
|
|
373
|
+
|
|
374
|
+
Any custom SDS props and MUI props required for implementation are found on the table below. See the MUI documentation for additional optional props.
|
|
375
|
+
|
|
376
|
+
| Name | Type | Default | Description |
|
|
377
|
+
| ------------------ | ---------------------------------------- | --------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
378
|
+
| `buttonDefinition` | `SingleButtonDefinition[]` | - (required) | One entry per segment, in the order they appear. The shape is described in the table below. |
|
|
379
|
+
| `value` | `string \| null` | - | The selected segment's value. Passing it makes the control controlled; leaving it out lets the control track the selection itself, starting on the first segment that is not disabled. |
|
|
380
|
+
| `onChange` | `(event, value: string \| null) => void` | - | Runs on every click that changes the selection, with the newly selected value, or `null` when the selected segment was clicked again. Required when `value` is set. |
|
|
381
|
+
| `disabled` | `boolean` | `false` | MUI's group-level prop. Disables every segment at once while leaving the selection visible; per-segment control is on `buttonDefinition`. |
|
|
382
|
+
| `aria-label` | `string` | `"Segmented Control"` | Names the group. Replace it with something that says what is being switched, since the default describes the widget rather than its purpose. |
|
|
383
|
+
|
|
384
|
+
### SingleButtonDefinition
|
|
385
|
+
|
|
386
|
+
The shape of each entry in `buttonDefinition`.
|
|
387
|
+
|
|
388
|
+
| Name | Type | Default | Description |
|
|
389
|
+
| ------------------- | ----------------------------------------------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
390
|
+
| `value` | `string` | - (required) | Identifies the segment in `value` and `onChange`. On an icon-only segment it is also the accessible name and the tooltip's fallback text, so keep it readable. |
|
|
391
|
+
| `icon` | `keyof IconNameToSizes` \| `React.ReactElement` | - | An SDS icon name, drawn at the small size, or an SVG element of your own for artwork SDS does not carry. Size an element you pass to 16px and fill it with currentColor so it follows the selection. |
|
|
392
|
+
| `label` | `string` | - | Text for the segment, used instead of an icon. It becomes the segment's accessible name and the tooltip's fallback text. |
|
|
393
|
+
| `disabled` | `boolean` | `false` | Turns the segment off. Disabled segments show no tooltip and are skipped when an uncontrolled control picks its starting selection. |
|
|
394
|
+
| `shouldShowTooltip` | `boolean` | `true` | Whether the segment has a tooltip. Worth turning off for a labelled segment, whose tooltip would only repeat the label. |
|
|
395
|
+
| `tooltipProps` | `Partial<Omit<TooltipProps, "children">>` | - | Passed to the segment's Tooltip, so it takes a title, a subtitle, a placement, and the rest of the Tooltip API. Without a title, the tooltip falls back to the label or the value. Note that the title is not used as the segment's accessible name. |
|
|
396
|
+
| `tooltipText` | `string` | - | Deprecated in favour of `tooltipProps`, and logs a warning. It sets the tooltip's title, overriding `tooltipProps.title` when both are given, and it is the one tooltip prop that also sets the segment's accessible name. |
|