@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,482 @@
|
|
|
1
|
+
# InputDropdown
|
|
2
|
+
|
|
3
|
+
> **InputDropdown is the trigger, not the menu.** It draws the field a dropdown opens from and reports the selection back, and it opens nothing by itself. Most applications want Dropdown, which is this component already paired with a menu; reach for this one to anchor a DropdownMenu you are driving yourself. It is filed under Inputs, but it belongs to the family the Dropdowns overview describes.
|
|
4
|
+
|
|
5
|
+
## Source Code
|
|
6
|
+
|
|
7
|
+
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/InputDropdown/index.tsx).
|
|
8
|
+
|
|
9
|
+
## Import
|
|
10
|
+
|
|
11
|
+
**React TypeScript**
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { InputDropdown } from "@czi-sds/components";
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Code examples
|
|
18
|
+
|
|
19
|
+
### Default
|
|
20
|
+
|
|
21
|
+
This example has the minimum props needed for the InputDropdown component.
|
|
22
|
+
|
|
23
|
+
**Example: Default**
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
// Most minimal InputDropdown (just has the basic requirements)
|
|
27
|
+
|
|
28
|
+
import { InputDropdown } from "@czi-sds/components";
|
|
29
|
+
|
|
30
|
+
function App() {
|
|
31
|
+
return (
|
|
32
|
+
<div className="app">
|
|
33
|
+
<InputDropdown label="Label" onClick={() => {}} />
|
|
34
|
+
</div>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export default App;
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Controlling the width
|
|
42
|
+
|
|
43
|
+
Left alone, the input is as wide as the text inside it, which means a row of them comes out ragged and the width jumps around as the selection changes. `width` fixes that. A bare number is read as pixels, and any other value is used as the CSS width, so `"100%"` fills the container and `"20rem"` works as written.
|
|
44
|
+
|
|
45
|
+
**Example: ControllingTheWidth**
|
|
46
|
+
|
|
47
|
+
```tsx
|
|
48
|
+
// The InputDropdown is as wide as its own content until `width` says otherwise.
|
|
49
|
+
// A bare number is read as pixels; anything else is used as the CSS width, so a
|
|
50
|
+
// percentage sizes the input against whatever contains it. The dashed box below
|
|
51
|
+
// is the container the percentages are measured against.
|
|
52
|
+
|
|
53
|
+
import { InputDropdown } from "@czi-sds/components";
|
|
54
|
+
|
|
55
|
+
function App() {
|
|
56
|
+
return (
|
|
57
|
+
<div className="app">
|
|
58
|
+
<div
|
|
59
|
+
style={{
|
|
60
|
+
// Without this the column would stretch every input to its full width,
|
|
61
|
+
// which is the one thing this example is trying to show a difference in.
|
|
62
|
+
alignItems: "flex-start",
|
|
63
|
+
border: "1px dashed #a9a9a9",
|
|
64
|
+
display: "flex",
|
|
65
|
+
flexDirection: "column",
|
|
66
|
+
gap: "16px",
|
|
67
|
+
padding: "16px",
|
|
68
|
+
width: "400px",
|
|
69
|
+
}}
|
|
70
|
+
>
|
|
71
|
+
<InputDropdown label="Auto" onClick={() => {}} />
|
|
72
|
+
<InputDropdown label="240px" onClick={() => {}} width="240" />
|
|
73
|
+
<InputDropdown label="50%" onClick={() => {}} width="50%" />
|
|
74
|
+
<InputDropdown label="100%" onClick={() => {}} width="100%" />
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export default App;
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
> **MUI Tip:** MUI's `fullWidth` prop works here too and does the same thing as `width="100%"`. Pass both and `width` is the one that counts. Either way the input keeps a minimum width of 90px, so a smaller value leaves it at 90px rather than shrinking it.
|
|
84
|
+
|
|
85
|
+
### Anchoring a menu
|
|
86
|
+
|
|
87
|
+
A DropdownMenu is a popper: it is positioned against an element rather than rendered inside one, so it needs the input's DOM node as its `anchorEl`. InputDropdown forwards its `ref` to the button it renders, and a callback ref keeps that node in state so the menu re-renders once the anchor exists. Reach for this when the Dropdown component below is more than you need, or when the menu has to be driven from state you already own.
|
|
88
|
+
|
|
89
|
+
**Example: AnchoringAMenu**
|
|
90
|
+
|
|
91
|
+
```tsx
|
|
92
|
+
// A DropdownMenu is positioned against an element rather than nested inside
|
|
93
|
+
// one, so it needs the input's DOM node. InputDropdown forwards its ref to the
|
|
94
|
+
// button it renders, and a callback ref stores that node in state, which is
|
|
95
|
+
// what makes the menu re-render once the anchor exists.
|
|
96
|
+
|
|
97
|
+
import {
|
|
98
|
+
DropdownMenu,
|
|
99
|
+
InputDropdown,
|
|
100
|
+
type DefaultAutocompleteOption,
|
|
101
|
+
} from "@czi-sds/components";
|
|
102
|
+
import { useState, type SyntheticEvent } from "react";
|
|
103
|
+
|
|
104
|
+
const OPTIONS: DefaultAutocompleteOption[] = [
|
|
105
|
+
{ name: "Chromosome 1" },
|
|
106
|
+
{ name: "Chromosome 2" },
|
|
107
|
+
{ name: "Chromosome 3" },
|
|
108
|
+
];
|
|
109
|
+
|
|
110
|
+
function App() {
|
|
111
|
+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
112
|
+
const [open, setOpen] = useState(false);
|
|
113
|
+
const [value, setValue] = useState<DefaultAutocompleteOption | null>(null);
|
|
114
|
+
|
|
115
|
+
return (
|
|
116
|
+
<div className="app">
|
|
117
|
+
<InputDropdown
|
|
118
|
+
label="Chromosome"
|
|
119
|
+
onClick={() => setOpen((wasOpen) => !wasOpen)}
|
|
120
|
+
ref={setAnchorEl}
|
|
121
|
+
sdsStyle="square"
|
|
122
|
+
sdsType="value"
|
|
123
|
+
state={open ? "open" : "default"}
|
|
124
|
+
value={value?.name}
|
|
125
|
+
/>
|
|
126
|
+
|
|
127
|
+
<DropdownMenu<DefaultAutocompleteOption, false, false, false>
|
|
128
|
+
anchorEl={anchorEl}
|
|
129
|
+
onChange={(
|
|
130
|
+
_event: SyntheticEvent,
|
|
131
|
+
newValue: DefaultAutocompleteOption | null
|
|
132
|
+
) => {
|
|
133
|
+
setValue(newValue);
|
|
134
|
+
setOpen(false);
|
|
135
|
+
}}
|
|
136
|
+
onClickAway={() => setOpen(false)}
|
|
137
|
+
open={open}
|
|
138
|
+
options={OPTIONS}
|
|
139
|
+
search={false}
|
|
140
|
+
value={value}
|
|
141
|
+
/>
|
|
142
|
+
</div>
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export default App;
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Square with multi-select
|
|
150
|
+
|
|
151
|
+
Below is an example demonstrating the combined utilization of the InputDropdown component and a multi-select Dropdown component. The Dropdown allows multiple selections, while the InputDropdown features a square variant.
|
|
152
|
+
|
|
153
|
+
**Example: SquareWithMultiSelect**
|
|
154
|
+
|
|
155
|
+
```tsx
|
|
156
|
+
import { MouseEvent, SyntheticEvent, useState } from "react";
|
|
157
|
+
import {
|
|
158
|
+
InputDropdown,
|
|
159
|
+
DropdownMenu,
|
|
160
|
+
DefaultAutocompleteOption,
|
|
161
|
+
} from "@czi-sds/components";
|
|
162
|
+
|
|
163
|
+
const options = [
|
|
164
|
+
{
|
|
165
|
+
details: "Details",
|
|
166
|
+
name: "Menu Item 1",
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
details: "A very long Details for the second Menu Item",
|
|
170
|
+
name: "Menu Item 2",
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: "Menu Item 3",
|
|
174
|
+
},
|
|
175
|
+
];
|
|
176
|
+
|
|
177
|
+
function App() {
|
|
178
|
+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
179
|
+
const [open, setOpen] = useState(false);
|
|
180
|
+
const [counter, setCounter] = useState<string>();
|
|
181
|
+
const [value, setValue] = useState<DefaultAutocompleteOption[]>([]);
|
|
182
|
+
|
|
183
|
+
return (
|
|
184
|
+
<div className="app">
|
|
185
|
+
<InputDropdown
|
|
186
|
+
label="Label"
|
|
187
|
+
onClick={handleClick}
|
|
188
|
+
sdsStyle="square"
|
|
189
|
+
multiple
|
|
190
|
+
counter={counter}
|
|
191
|
+
/>
|
|
192
|
+
<DropdownMenu<DefaultAutocompleteOption, true, false, false>
|
|
193
|
+
open={open}
|
|
194
|
+
anchorEl={anchorEl}
|
|
195
|
+
onClose={() => {}}
|
|
196
|
+
onChange={handleChange}
|
|
197
|
+
search={false}
|
|
198
|
+
multiple
|
|
199
|
+
disableCloseOnSelect
|
|
200
|
+
options={options}
|
|
201
|
+
value={value}
|
|
202
|
+
onClickAway={handleClickAway}
|
|
203
|
+
/>
|
|
204
|
+
</div>
|
|
205
|
+
);
|
|
206
|
+
|
|
207
|
+
function handleClick(event: MouseEvent<HTMLElement>) {
|
|
208
|
+
if (open) {
|
|
209
|
+
setOpen(false);
|
|
210
|
+
|
|
211
|
+
if (anchorEl) {
|
|
212
|
+
anchorEl.focus();
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
setAnchorEl(null);
|
|
216
|
+
} else {
|
|
217
|
+
setAnchorEl(event.currentTarget);
|
|
218
|
+
setOpen(true);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function handleChange(
|
|
223
|
+
_: SyntheticEvent<Element, Event>,
|
|
224
|
+
newValue: DefaultAutocompleteOption[]
|
|
225
|
+
) {
|
|
226
|
+
setValue(newValue);
|
|
227
|
+
setCounter(newValue.length.toString());
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function handleClickAway() {
|
|
231
|
+
if (open) {
|
|
232
|
+
setOpen(false);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export default App;
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
### Rounded with single-select
|
|
241
|
+
|
|
242
|
+
Below is an example demonstrating the combined utilization of the default label variant InputDropdown component and a single-select Dropdown component.
|
|
243
|
+
|
|
244
|
+
**Example: RoundedWithSingleSelect**
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { MouseEvent, SyntheticEvent, useState } from "react";
|
|
248
|
+
import {
|
|
249
|
+
InputDropdown,
|
|
250
|
+
DropdownMenu,
|
|
251
|
+
DefaultAutocompleteOption,
|
|
252
|
+
} from "@czi-sds/components";
|
|
253
|
+
|
|
254
|
+
const options = [
|
|
255
|
+
{
|
|
256
|
+
details: "Details",
|
|
257
|
+
name: "Menu Item 1",
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
details: "A very long Details for the second Menu Item",
|
|
261
|
+
name: "Menu Item 2",
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
name: "Menu Item 3",
|
|
265
|
+
},
|
|
266
|
+
];
|
|
267
|
+
|
|
268
|
+
function App() {
|
|
269
|
+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
270
|
+
const [open, setOpen] = useState(false);
|
|
271
|
+
const [inputDropdownValue, setInputDropdownValue] = useState<string>();
|
|
272
|
+
const [value, setValue] = useState<DefaultAutocompleteOption | null>(null);
|
|
273
|
+
|
|
274
|
+
return (
|
|
275
|
+
<div className="app">
|
|
276
|
+
<InputDropdown
|
|
277
|
+
label="Label"
|
|
278
|
+
onClick={handleClick}
|
|
279
|
+
sdsStyle="rounded"
|
|
280
|
+
multiple={false}
|
|
281
|
+
value={inputDropdownValue}
|
|
282
|
+
/>
|
|
283
|
+
<DropdownMenu<DefaultAutocompleteOption, false, false, false>
|
|
284
|
+
open={open}
|
|
285
|
+
anchorEl={anchorEl}
|
|
286
|
+
onClose={() => {}}
|
|
287
|
+
onChange={handleChange}
|
|
288
|
+
search={false}
|
|
289
|
+
multiple={false}
|
|
290
|
+
disableCloseOnSelect
|
|
291
|
+
options={options}
|
|
292
|
+
value={value}
|
|
293
|
+
onClickAway={handleClickAway}
|
|
294
|
+
/>
|
|
295
|
+
</div>
|
|
296
|
+
);
|
|
297
|
+
|
|
298
|
+
function handleClick(event: MouseEvent<HTMLElement>) {
|
|
299
|
+
if (open) {
|
|
300
|
+
setOpen(false);
|
|
301
|
+
|
|
302
|
+
if (anchorEl) {
|
|
303
|
+
anchorEl.focus();
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
setAnchorEl(null);
|
|
307
|
+
} else {
|
|
308
|
+
setAnchorEl(event.currentTarget);
|
|
309
|
+
setOpen(true);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
function handleChange(
|
|
314
|
+
_: SyntheticEvent<Element, Event>,
|
|
315
|
+
newValue: DefaultAutocompleteOption | null
|
|
316
|
+
) {
|
|
317
|
+
setOpen(false);
|
|
318
|
+
setValue(newValue);
|
|
319
|
+
setInputDropdownValue(newValue?.name);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
function handleClickAway() {
|
|
323
|
+
if (open) {
|
|
324
|
+
setOpen(false);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export default App;
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Minimal with single-select
|
|
333
|
+
|
|
334
|
+
An example of the combined use of the value variation InputDropdown component and a single-select Dropdown component is shown below.
|
|
335
|
+
|
|
336
|
+
> **Warning:** The value variant can not be used in conjunction with the multi-select Dropdowns. If you set `sdsType="value"` and `multiple="true"`, the component will default to showing a label and a counter instead.
|
|
337
|
+
|
|
338
|
+
**Example: MinimalWithSingleSelect**
|
|
339
|
+
|
|
340
|
+
```tsx
|
|
341
|
+
import { MouseEvent, SyntheticEvent, useState } from "react";
|
|
342
|
+
import {
|
|
343
|
+
InputDropdown,
|
|
344
|
+
DropdownMenu,
|
|
345
|
+
DefaultAutocompleteOption,
|
|
346
|
+
} from "@czi-sds/components";
|
|
347
|
+
|
|
348
|
+
const options = [
|
|
349
|
+
{
|
|
350
|
+
details: "Details",
|
|
351
|
+
name: "Menu Item 1",
|
|
352
|
+
},
|
|
353
|
+
{
|
|
354
|
+
details: "A very long Details for the second Menu Item",
|
|
355
|
+
name: "Menu Item 2",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
name: "Menu Item 3",
|
|
359
|
+
},
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
function App() {
|
|
363
|
+
const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
|
|
364
|
+
const [open, setOpen] = useState(false);
|
|
365
|
+
const [details, setDetails] = useState<string>();
|
|
366
|
+
const [inputDropdownValue, setInputDropdownValue] = useState<string>();
|
|
367
|
+
const [value, setValue] = useState<DefaultAutocompleteOption | null>(null);
|
|
368
|
+
|
|
369
|
+
return (
|
|
370
|
+
<div className="app">
|
|
371
|
+
<InputDropdown
|
|
372
|
+
label="Label"
|
|
373
|
+
onClick={handleClick}
|
|
374
|
+
sdsType="value"
|
|
375
|
+
sdsStyle="minimal"
|
|
376
|
+
multiple={false}
|
|
377
|
+
details={details}
|
|
378
|
+
value={inputDropdownValue}
|
|
379
|
+
style={{ maxWidth: 250 }}
|
|
380
|
+
/>
|
|
381
|
+
<DropdownMenu<DefaultAutocompleteOption, false, false, false>
|
|
382
|
+
open={open}
|
|
383
|
+
anchorEl={anchorEl}
|
|
384
|
+
onClose={() => {}}
|
|
385
|
+
onChange={handleChange}
|
|
386
|
+
search={false}
|
|
387
|
+
multiple={false}
|
|
388
|
+
disableCloseOnSelect
|
|
389
|
+
options={options}
|
|
390
|
+
value={value}
|
|
391
|
+
onClickAway={handleClickAway}
|
|
392
|
+
/>
|
|
393
|
+
</div>
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
function handleClick(event: MouseEvent<HTMLElement>) {
|
|
397
|
+
if (open) {
|
|
398
|
+
setOpen(false);
|
|
399
|
+
|
|
400
|
+
if (anchorEl) {
|
|
401
|
+
anchorEl.focus();
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
setAnchorEl(null);
|
|
405
|
+
} else {
|
|
406
|
+
setAnchorEl(event.currentTarget);
|
|
407
|
+
setOpen(true);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function handleChange(
|
|
412
|
+
_: SyntheticEvent<Element, Event>,
|
|
413
|
+
newValue: DefaultAutocompleteOption | null
|
|
414
|
+
) {
|
|
415
|
+
setOpen(false);
|
|
416
|
+
setValue(newValue);
|
|
417
|
+
|
|
418
|
+
if (newValue) {
|
|
419
|
+
setInputDropdownValue(newValue.name);
|
|
420
|
+
|
|
421
|
+
if (newValue?.details) setDetails(newValue?.details);
|
|
422
|
+
else setDetails(undefined);
|
|
423
|
+
} else {
|
|
424
|
+
setDetails(undefined);
|
|
425
|
+
setInputDropdownValue(undefined);
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
function handleClickAway() {
|
|
430
|
+
if (open) {
|
|
431
|
+
setOpen(false);
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
export default App;
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
## SDS vs MUI
|
|
440
|
+
|
|
441
|
+
The SDS's InputDropdown component utilizes MUI's Button component as its foundation but introduces some SDS-specific enhancements. Below, the key distinctions between the SDS's InputDropdown and MUI's Button are outlined:
|
|
442
|
+
|
|
443
|
+
- **Variation**: MUI's Button offers a `variant` prop to define different visual styles for buttons. SDS's InputDropdown, however, uses the `sdsStyle` prop instead, providing the ability to select between three variants: `"square"`, `"rounded"`, or `"minimal"`.
|
|
444
|
+
|
|
445
|
+
- **Color**: In MUI's Button, the button's color can be modified using the `color` prop. SDS's InputDropdown deviates from this and introduces the `intent` prop. This prop provides the ability to choose between default, warning, and error colors, depending on the state of the InputDropdown.
|
|
446
|
+
|
|
447
|
+
- **Size**: While MUI's Button provides a `size` prop for adjusting the button's size, SDS's InputDropdown does not offer this capability. The size of the InputDropdown component remains fixed and cannot be altered through props.
|
|
448
|
+
|
|
449
|
+
- **Icon**: Unlike MUI's Button, which supports custom icons, SDS's InputDropdown does not accept external icon components. Instead, SDS's InputDropdown incorporates a built-in Chevron icon, which is an integral part of the component and cannot be replaced.
|
|
450
|
+
|
|
451
|
+
- **Ref**: Like MUI's Button, InputDropdown forwards a `ref` to the button it renders. That is how it becomes the `anchorEl` a DropdownMenu is positioned against, as in "Anchoring a menu" above.
|
|
452
|
+
|
|
453
|
+
## MUI Documentation
|
|
454
|
+
|
|
455
|
+
Documentation for the underlying MUI component can be found [here](https://mui.com/material-ui/react-button/).
|
|
456
|
+
|
|
457
|
+
## Props
|
|
458
|
+
|
|
459
|
+
Any custom SDS props and MUI props required for implementation are found on the table below. See the MUI documentation for additional optional props.
|
|
460
|
+
|
|
461
|
+
| Name | Type | Default | Description |
|
|
462
|
+
| ------------------------------ | --------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
463
|
+
| `classes` | `object` | - | A class name for each part of the input, for styling one of them without reaching through the DOM: `root`, `label`, `labelDetailsWrapper`, `contentWrapper`, `details`, `counter`, `iconWrapper`, `chevronIcon` and `minimalDetails`. |
|
|
464
|
+
| `className` | `string` | - | Added to the input's root element, alongside anything `classes.root` puts there. |
|
|
465
|
+
| `counter` | `ReactNode` | - | If `multiple` set to `true`, this number shows the number of selected menu items. |
|
|
466
|
+
| `details` | `ReactNode` | - | A text showing details for the selected menu item. |
|
|
467
|
+
| `disabled` | `boolean` | `false` | If `true`, the component is disabled. |
|
|
468
|
+
| `intent` | `"default"` \| `"negative"` \| `"notice"` \| `"positive"` | `"default"` | The color of the component. |
|
|
469
|
+
| `label` | `ReactNode` | - | The label of the Input Button. |
|
|
470
|
+
| `multiple` | `boolean` | `false` | Allows users to select multiple menu items.`multiple=true` cannot be used with the minimum variant. |
|
|
471
|
+
| `onClick` | `function` | `(event: React.MouseEvent<HTMLElement>) => void` | Sets what happens when a user clicks on the component. |
|
|
472
|
+
| `sdsStyle` | `"minimal"` \| `"square"` \| `"rounded"` | `"square"` | The visual appearance of the component. |
|
|
473
|
+
| `sdsType` | `"label"` \| `"value"` | `"label"` | The label variant includes the label within the input field and showcases the selected menu item as additional details or sets the counter when in multi-select mode. The value variant replaces the label with the selected value directly within the input field. The detailed information is then displayed in a separate section dedicated to displaying additional details. However, it's important to note that the value variant cannot be used in conjunction with multi-select mode. |
|
|
474
|
+
| `shouldPutAColonAfterLabel` | `boolean` | `true` | If `true`, a colon (:) will be added after the label or value. |
|
|
475
|
+
| `shouldTruncateMinimalDetails` | `boolean` | `false` | If `true`, the details section of the minimal variant displays a truncated one-liner with an ellipsis (...), if `false` the details section expands to multiple lines for a comprehensive display. |
|
|
476
|
+
| `startIcon` | `ReactNode` | - | An element placed before the label, passed straight through to the underlying MUI Button. |
|
|
477
|
+
| `state` | `"default"` \| `"open"` | `"default"` | Draws the input in its open state. The input has no idea whether its menu is showing, so set this from whatever holds that state. |
|
|
478
|
+
| `style` | `CSSProperties` | - | Inline styles for the input's root element. |
|
|
479
|
+
| `value` | `ReactNode` | - | The value that will be displayed in the component for the value variant. |
|
|
480
|
+
| `width` | `string` | `"auto"` | How wide the input is. A bare number is read as pixels, so `"240"` means 240px, and any other value is used as the CSS width, such as `"100%"` or `"20rem"`. Values below 90px are ignored, since the input keeps that as its minimum. Left unset, the input is as wide as its content, or as wide as its container if MUI's `fullWidth` is set. |
|
|
481
|
+
|
|
482
|
+
There are more props that can be used with the InputDropdown component, via those available to [MUI's Button component](https://mui.com/material-ui/api/autocomplete/#props).
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# InputRadio
|
|
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/InputRadio/index.tsx).
|
|
6
|
+
|
|
7
|
+
## Import
|
|
8
|
+
|
|
9
|
+
**React TypeScript**
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { InputRadio } from "@czi-sds/components";
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Code examples
|
|
16
|
+
|
|
17
|
+
### **Default InputRadio**
|
|
18
|
+
|
|
19
|
+
This example has the minimum props needed for the InputRadio component.
|
|
20
|
+
|
|
21
|
+
**Example: DefaultInputRadio**
|
|
22
|
+
|
|
23
|
+
```tsx
|
|
24
|
+
import { InputRadio } from "@czi-sds/components";
|
|
25
|
+
|
|
26
|
+
function App() {
|
|
27
|
+
return (
|
|
28
|
+
<div className="app">
|
|
29
|
+
<InputRadio label="Label" value="label" />
|
|
30
|
+
</div>
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export default App;
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### InputRadio + Caption
|
|
38
|
+
|
|
39
|
+
This example shows the InputRadio with an additional caption beneath the label, presented in a lighter text color.
|
|
40
|
+
|
|
41
|
+
**Example: InputRadioCaption**
|
|
42
|
+
|
|
43
|
+
```tsx
|
|
44
|
+
import { InputRadio } from "@czi-sds/components";
|
|
45
|
+
|
|
46
|
+
function App() {
|
|
47
|
+
return (
|
|
48
|
+
<div className="app">
|
|
49
|
+
<InputRadio caption="Caption" label="Label" value="label" />
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default App;
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### InputRadio group
|
|
58
|
+
|
|
59
|
+
Radios are meant to be used as a set. Wrap them in MUI's RadioGroup, which selects the radio whose value matches the group's and handles arrow-key navigation. Add `row` to lay the options out horizontally.
|
|
60
|
+
|
|
61
|
+
**Example: InputRadioGroup**
|
|
62
|
+
|
|
63
|
+
```tsx
|
|
64
|
+
// MUI's RadioGroup owns the selection: each InputRadio is checked when its
|
|
65
|
+
// `value` matches the group's. `row` lays the options out horizontally.
|
|
66
|
+
import { useState } from "react";
|
|
67
|
+
import { InputRadio } from "@czi-sds/components";
|
|
68
|
+
import { RadioGroup } from "@mui/material";
|
|
69
|
+
|
|
70
|
+
const OPTIONS = ["Option 1", "Option 2", "Option 3"];
|
|
71
|
+
|
|
72
|
+
function App() {
|
|
73
|
+
const [value, setValue] = useState(OPTIONS[0]);
|
|
74
|
+
|
|
75
|
+
return (
|
|
76
|
+
<div
|
|
77
|
+
className="app"
|
|
78
|
+
style={{ display: "flex", flexDirection: "column", gap: "24px" }}
|
|
79
|
+
>
|
|
80
|
+
<RadioGroup
|
|
81
|
+
name="vertical-options"
|
|
82
|
+
value={value}
|
|
83
|
+
onChange={(event) => setValue(event.target.value)}
|
|
84
|
+
>
|
|
85
|
+
{OPTIONS.map((option) => (
|
|
86
|
+
<InputRadio key={option} label={option} value={option} />
|
|
87
|
+
))}
|
|
88
|
+
</RadioGroup>
|
|
89
|
+
|
|
90
|
+
{/* SDS removes the side margin MUI puts on labels, so a row needs its
|
|
91
|
+
own gap. */}
|
|
92
|
+
<RadioGroup
|
|
93
|
+
row
|
|
94
|
+
name="row-options"
|
|
95
|
+
value={value}
|
|
96
|
+
onChange={(event) => setValue(event.target.value)}
|
|
97
|
+
sx={{ gap: "24px" }}
|
|
98
|
+
>
|
|
99
|
+
{OPTIONS.map((option) => (
|
|
100
|
+
<InputRadio key={option} label={option} value={option} />
|
|
101
|
+
))}
|
|
102
|
+
</RadioGroup>
|
|
103
|
+
</div>
|
|
104
|
+
);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export default App;
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### InputRadio intents
|
|
111
|
+
|
|
112
|
+
Intent colors the border of the empty circle. Select any of these and the dot turns the same accent color.
|
|
113
|
+
|
|
114
|
+
**Example: InputRadioIntents**
|
|
115
|
+
|
|
116
|
+
```tsx
|
|
117
|
+
// `intent` colors the empty circle only; a selected radio always uses the
|
|
118
|
+
// accent color.
|
|
119
|
+
import { InputRadio } from "@czi-sds/components";
|
|
120
|
+
|
|
121
|
+
function App() {
|
|
122
|
+
return (
|
|
123
|
+
<div className="app" style={{ display: "flex", gap: "24px" }}>
|
|
124
|
+
<InputRadio label="Default" value="default" intent="default" />
|
|
125
|
+
<InputRadio label="Positive" value="positive" intent="positive" />
|
|
126
|
+
<InputRadio label="Notice" value="notice" intent="notice" />
|
|
127
|
+
<InputRadio label="Negative" value="negative" intent="negative" />
|
|
128
|
+
<InputRadio label="Disabled" value="disabled" disabled />
|
|
129
|
+
</div>
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
export default App;
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## SDS vs MUI
|
|
137
|
+
|
|
138
|
+
The following props and options differ in whether and how they function across MUI versus SDS's InputRadio component:
|
|
139
|
+
|
|
140
|
+
- `size`: Has no effect in SDS
|
|
141
|
+
|
|
142
|
+
- `color`: Has no effect in SDS
|
|
143
|
+
|
|
144
|
+
- `labelPlacement`: Has no effect in SDS
|
|
145
|
+
|
|
146
|
+
- `intent`: This is an SDS-specific prop that colors the border of the empty circle (`"default"`, `"positive"`, `"notice"`, or `"negative"`). It does not change the selected radio, which always uses the accent color.
|
|
147
|
+
|
|
148
|
+
- `caption`: This is an SDS-specific prop, which takes text that is displayed below the primary label text.
|
|
149
|
+
|
|
150
|
+
- `stage`: This SDS prop sets the radio as `"checked"` or `"unchecked"` and overrides `checked`. Inside a RadioGroup, leave it out and let the group drive the selection from each radio's `value`.
|
|
151
|
+
|
|
152
|
+
- `value`: Required in practice: a RadioGroup matches it against its own value to decide which radio is selected, and SDS also derives the label and caption element ids from it for screen readers.
|
|
153
|
+
|
|
154
|
+
- `row`: This boolean prop functions the same for both MUI and SDS's InputRadio component: its presence reformats the radio buttons (and their labels) within the RadioGroup parent component into a horizontal row.
|
|
155
|
+
|
|
156
|
+
## MUI Documentation
|
|
157
|
+
|
|
158
|
+
Documentation for the underlying MUI component can be found [here](https://mui.com/material-ui/react-radio-button/).
|
|
159
|
+
|
|
160
|
+
## Props
|
|
161
|
+
|
|
162
|
+
Any custom SDS props and MUI props required for implementation are found on the table below. See the MUI documentation for additional optional props.
|
|
163
|
+
|
|
164
|
+
| Name | Type | Default | Description |
|
|
165
|
+
| ------------ | --------------------------------------------------------- | ----------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
166
|
+
| `caption` | `ReactNode` | - | The caption of the InputRadio appears beneath the label in a lighter text color. |
|
|
167
|
+
| `label` | `ReactNode` | - | The label of the InputRadio. |
|
|
168
|
+
| `value` | `string` | - | The value a RadioGroup compares against to decide whether this radio is selected. It also backs the label and caption element ids, so give every radio a unique one. |
|
|
169
|
+
| `radioProps` | `Partial<MUIRadioProps>` | `{}` | Directly pass these props to the underlying MUI radio. |
|
|
170
|
+
| `stage` | `"checked" \| "unchecked"` | - | Sets the radio as `"checked"` or `"unchecked"`, overriding `checked`. Omit it inside a RadioGroup, which drives the selection itself. |
|
|
171
|
+
| `intent` | `"default"` \| `"notice"` \| `"negative"` \| `"positive"` | `"default"` | Colors the border of the empty circle. The selected radio always uses the accent color. |
|
|
172
|
+
| `disabled` | `boolean` | `false` | If `true`, the component is disabled. |
|
|
173
|
+
| `classes` | `object` | `{}` | Class names for the internal elements: `root`, `labelCaptionContainer`, `label`, `caption`, `radioButton`, `radioCheckedIcon`, `radioCheckedIconDot`, and `radioDefaultIcon`. |
|