@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.
Files changed (167) hide show
  1. package/README.md +2 -1
  2. package/data/component-docs/Accordion.md +291 -0
  3. package/data/component-docs/Autocomplete.md +525 -0
  4. package/data/component-docs/Banner.md +231 -0
  5. package/data/component-docs/Button.md +224 -0
  6. package/data/component-docs/ButtonDropdown.md +256 -0
  7. package/data/component-docs/ButtonGroup.md +320 -0
  8. package/data/component-docs/ButtonToggle.md +397 -0
  9. package/data/component-docs/Callout.md +268 -0
  10. package/data/component-docs/CellBasic.md +122 -0
  11. package/data/component-docs/CellComponent.md +63 -0
  12. package/data/component-docs/CellHeader.md +128 -0
  13. package/data/component-docs/ComplexFilter.md +294 -0
  14. package/data/component-docs/ContentCard.md +406 -0
  15. package/data/component-docs/Dialog.md +651 -0
  16. package/data/component-docs/Dropdown.md +155 -0
  17. package/data/component-docs/DropdownMenu.md +949 -0
  18. package/data/component-docs/HeatmapChart.md +782 -0
  19. package/data/component-docs/Hero.md +363 -0
  20. package/data/component-docs/Icon.md +283 -0
  21. package/data/component-docs/InputCheckbox.md +205 -0
  22. package/data/component-docs/InputDropdown.md +482 -0
  23. package/data/component-docs/InputRadio.md +173 -0
  24. package/data/component-docs/InputSearch.md +81 -0
  25. package/data/component-docs/InputSlider.md +189 -0
  26. package/data/component-docs/InputText.md +110 -0
  27. package/data/component-docs/InputToggle.md +141 -0
  28. package/data/component-docs/IntentMessage.md +293 -0
  29. package/data/component-docs/Legend.md +442 -0
  30. package/data/component-docs/Link.md +23 -0
  31. package/data/component-docs/List.md +300 -0
  32. package/data/component-docs/LoadingIndicator.md +198 -0
  33. package/data/component-docs/Menu.md +298 -0
  34. package/data/component-docs/MenuItem.md +100 -0
  35. package/data/component-docs/NavigationFooter.md +165 -0
  36. package/data/component-docs/NavigationHeader.md +500 -0
  37. package/data/component-docs/NavigationJumpTo.md +414 -0
  38. package/data/component-docs/Notification.md +288 -0
  39. package/data/component-docs/Pagination.md +67 -0
  40. package/data/component-docs/Panel.md +636 -0
  41. package/data/component-docs/Popover.md +448 -0
  42. package/data/component-docs/PreComposedTable.md +2947 -0
  43. package/data/component-docs/ProteinStructureViewer.md +1044 -0
  44. package/data/component-docs/SegmentedControl.md +396 -0
  45. package/data/component-docs/StackedBarChart.md +475 -0
  46. package/data/component-docs/Table.md +2000 -0
  47. package/data/component-docs/TableHeader.md +53 -0
  48. package/data/component-docs/TableRow.md +74 -0
  49. package/data/component-docs/Tabs.md +455 -0
  50. package/data/component-docs/Tag.md +647 -0
  51. package/data/component-docs/TagFilter.md +131 -0
  52. package/data/component-docs/Tooltip.md +561 -0
  53. package/data/component-docs/TooltipCondensed.md +203 -0
  54. package/data/component-docs/TooltipTable.md +145 -0
  55. package/data/component-docs/index.json +267 -0
  56. package/data/component-list.json +2 -5
  57. package/data/component-props/Accordion.json +31 -11
  58. package/data/component-props/Alert.json +3 -3
  59. package/data/component-props/Autocomplete.json +150 -15
  60. package/data/component-props/Banner.json +31 -17
  61. package/data/component-props/Button.json +45 -20
  62. package/data/component-props/ButtonDropdown.json +36 -17
  63. package/data/component-props/ButtonDropdownLegacy.json +11 -11
  64. package/data/component-props/ButtonGroup.json +32 -11
  65. package/data/component-props/ButtonIcon.json +10 -10
  66. package/data/component-props/ButtonLegacy.json +19 -19
  67. package/data/component-props/ButtonToggle.json +32 -19
  68. package/data/component-props/ButtonToggleLegacy.json +11 -11
  69. package/data/component-props/Callout.json +58 -17
  70. package/data/component-props/CellBasic.json +94 -41
  71. package/data/component-props/CellComponent.json +23 -7
  72. package/data/component-props/CellHeader.json +62 -19
  73. package/data/component-props/ComplexFilter.json +52 -21
  74. package/data/component-props/ContentCard.json +70 -47
  75. package/data/component-props/Dialog.json +47 -14
  76. package/data/component-props/Dropdown.json +68 -31
  77. package/data/component-props/DropdownMenu.json +128 -23
  78. package/data/component-props/HeatmapChart.json +88 -12
  79. package/data/component-props/Hero.json +80 -39
  80. package/data/component-props/Icon.json +20 -9
  81. package/data/component-props/InputCheckbox.json +36 -14
  82. package/data/component-props/InputDropdown.json +75 -27
  83. package/data/component-props/InputRadio.json +31 -13
  84. package/data/component-props/InputSearch.json +41 -18
  85. package/data/component-props/InputSlider.json +46 -19
  86. package/data/component-props/InputText.json +26 -19
  87. package/data/component-props/InputToggle.json +26 -9
  88. package/data/component-props/IntentMessage.json +38 -9
  89. package/data/component-props/Link.json +13 -7
  90. package/data/component-props/LoadingIndicator.json +11 -3
  91. package/data/component-props/MenuItem.json +38 -19
  92. package/data/component-props/MenuSelect.json +8 -8
  93. package/data/component-props/NavigationFooter.json +49 -19
  94. package/data/component-props/NavigationHeader.json +150 -37
  95. package/data/component-props/NavigationJumpTo.json +33 -7
  96. package/data/component-props/Notification.json +39 -21
  97. package/data/component-props/Pagination.json +39 -11
  98. package/data/component-props/Panel.json +62 -9
  99. package/data/component-props/Popover.json +80 -7
  100. package/data/component-props/PreComposedTable.json +99 -27
  101. package/data/component-props/ProteinStructureViewer.json +117 -0
  102. package/data/component-props/SegmentedControl.json +42 -3
  103. package/data/component-props/StackedBarChart.json +116 -42
  104. package/data/component-props/TableRow.json +38 -19
  105. package/data/component-props/Tabs.json +66 -9
  106. package/data/component-props/Tag.json +34 -17
  107. package/data/component-props/TagFilter.json +10 -3
  108. package/data/component-props/Tooltip.json +49 -18
  109. package/data/component-props/TooltipCondensed.json +18 -9
  110. package/data/component-props/TooltipTable.json +17 -7
  111. package/data/resources/{zeroheight-rules.md → documentation-rules.md} +43 -30
  112. package/data/resources/figma-rules.md +2 -2
  113. package/data/tailwind.json +20 -14
  114. package/dist/stdio.js +112 -208
  115. package/package.json +9 -5
  116. package/data/component-props/ButtonDropdownV2.json +0 -34
  117. package/data/component-props/ButtonNew.json +0 -47
  118. package/data/component-props/ButtonToggleV2.json +0 -44
  119. package/data/component-props/ButtonV2.json +0 -43
  120. package/data/zeroheight-cache.json +0 -10259
  121. package/data/zeroheight-exports/Accordion.md +0 -774
  122. package/data/zeroheight-exports/Banner.md +0 -691
  123. package/data/zeroheight-exports/Borders.md +0 -117
  124. package/data/zeroheight-exports/Buttons.md +0 -1854
  125. package/data/zeroheight-exports/Callout.md +0 -931
  126. package/data/zeroheight-exports/Colors.md +0 -1755
  127. package/data/zeroheight-exports/Content-Card.md +0 -309
  128. package/data/zeroheight-exports/Contributing-to-SDS.md +0 -98
  129. package/data/zeroheight-exports/Control-Inputs.md +0 -2818
  130. package/data/zeroheight-exports/Corners.md +0 -104
  131. package/data/zeroheight-exports/Cover-page.md +0 -3
  132. package/data/zeroheight-exports/Dialog.md +0 -1367
  133. package/data/zeroheight-exports/Downloads.md +0 -236
  134. package/data/zeroheight-exports/Drop-Shadows.md +0 -79
  135. package/data/zeroheight-exports/Dropdown-Input.md +0 -1776
  136. package/data/zeroheight-exports/Dropdown-Menus.md +0 -913
  137. package/data/zeroheight-exports/Element-Status-Tracker.md +0 -267
  138. package/data/zeroheight-exports/Field-Inputs.md +0 -1405
  139. package/data/zeroheight-exports/Filters.md +0 -1111
  140. package/data/zeroheight-exports/Getting-Started.md +0 -1157
  141. package/data/zeroheight-exports/Hero.md +0 -414
  142. package/data/zeroheight-exports/Icons.md +0 -2067
  143. package/data/zeroheight-exports/Intent.md +0 -86
  144. package/data/zeroheight-exports/Introduction-to-Bases.md +0 -35
  145. package/data/zeroheight-exports/Introduction-to-Cells.md +0 -35
  146. package/data/zeroheight-exports/Introduction-to-DNA.md +0 -35
  147. package/data/zeroheight-exports/Introduction-to-Genes.md +0 -35
  148. package/data/zeroheight-exports/Introduction.md +0 -115
  149. package/data/zeroheight-exports/Link.md +0 -432
  150. package/data/zeroheight-exports/Lists.md +0 -986
  151. package/data/zeroheight-exports/Loading-Indicator.md +0 -41
  152. package/data/zeroheight-exports/Navigation.md +0 -1190
  153. package/data/zeroheight-exports/Notification.md +0 -1038
  154. package/data/zeroheight-exports/Panel.md +0 -1030
  155. package/data/zeroheight-exports/README.md +0 -122
  156. package/data/zeroheight-exports/Responsive-Design.md +0 -330
  157. package/data/zeroheight-exports/Search-Input.md +0 -91
  158. package/data/zeroheight-exports/Search.md +0 -822
  159. package/data/zeroheight-exports/Segmented-Control.md +0 -609
  160. package/data/zeroheight-exports/Spacing.md +0 -297
  161. package/data/zeroheight-exports/Table.md +0 -5345
  162. package/data/zeroheight-exports/Tabs.md +0 -1324
  163. package/data/zeroheight-exports/Tags.md +0 -1545
  164. package/data/zeroheight-exports/Text-Link.md +0 -268
  165. package/data/zeroheight-exports/Theming.md +0 -362
  166. package/data/zeroheight-exports/Tooltips.md +0 -2015
  167. package/data/zeroheight-exports/Typography.md +0 -800
@@ -0,0 +1,949 @@
1
+ # DropdownMenu
2
+
3
+ > **DropdownMenu is not Menu.** This is the menu half of Dropdown: a list built from an `options` array, for choosing a value your app then keeps, with search and sections and several selections at once. Menu is for commands, whose rows you write yourself and which leave nothing behind once one is picked. Use this one when you need Dropdown's list but not its trigger, and see the Dropdowns overview for the rest of the family.
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/DropdownMenu/index.tsx).
8
+
9
+ ## Import
10
+
11
+ **React TypeScript**
12
+
13
+ ```tsx
14
+ import { DropdownMenu } from "@czi-sds/components";
15
+ ```
16
+
17
+ ## Code examples
18
+
19
+ ### Default
20
+
21
+ This example has the minimum props and menu item metadata needed for the DropdownMenu. The examples that follow build on it.
22
+
23
+ Menu item metadata is stored as an array of objects (one per menu item) passed to the DropdownMenu component’s `options` prop. At minimum each MenuItem needs a `name` property, which is the text it displays. MenuItems can display more metadata, though; see the “Grouped sections” and “Menu items with count, icon, and details” examples below. Alternatively, a custom component can be displayed instead of a MenuItem component; see the “Components in place of menu items” example below.
24
+
25
+ The menu is 160px wide by default and never narrower, whatever `width` asks for. Options laid out in columns are the exception: those size themselves to their content and ignore `width` altogether.
26
+
27
+ **Example: Default**
28
+
29
+ ```tsx
30
+ // Most minimal DropdownMenu (just has the basic requirements)
31
+
32
+ import { useEffect, useRef, useState } from "react";
33
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
34
+ import styled from "@emotion/styled";
35
+
36
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
37
+ {
38
+ name: "Menu item 1",
39
+ },
40
+ {
41
+ name: "Menu item 2",
42
+ },
43
+ {
44
+ name: "Menu item 3",
45
+ },
46
+ {
47
+ name: "Longer menu item than the others",
48
+ },
49
+ ];
50
+
51
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
52
+
53
+ const Anchor = styled.div`
54
+ position: absolute;
55
+ top: 12px;
56
+ left: 20px;
57
+ `;
58
+
59
+ function handleClickAway() {}
60
+
61
+ function App() {
62
+ const ref = useRef(null);
63
+ const [open, setOpen] = useState(false);
64
+
65
+ useEffect(() => {
66
+ if (ref.current) setOpen(true);
67
+ }, [ref.current]);
68
+
69
+ return (
70
+ <div className="app">
71
+ <Anchor ref={ref} />
72
+ {open && (
73
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
74
+ <DropdownMenu
75
+ PopperBaseProps={POPPER_BASE_PROPS}
76
+ anchorEl={ref.current}
77
+ onClickAway={handleClickAway}
78
+ open={open}
79
+ options={MENU_ITEMS}
80
+ />
81
+ )}
82
+ </div>
83
+ );
84
+ }
85
+
86
+ export default App;
87
+ ```
88
+
89
+ ### Custom click target
90
+
91
+ The example below shows how DropdownMenu can be used in conjunction with a click target component (in this case, the InputDropdown component). When the click target is clicked, the DropdownMenu opens, and when a MenuItem is clicked, the DropdownMenu closes.
92
+
93
+ **Example: CustomClickTarget**
94
+
95
+ ```tsx
96
+ // DropdownMenu with custom click target
97
+
98
+ import { SyntheticEvent, useState } from "react";
99
+ import {
100
+ DropdownMenu,
101
+ DefaultAutocompleteOption,
102
+ InputDropdown,
103
+ } from "@czi-sds/components";
104
+
105
+ function App() {
106
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
107
+ {
108
+ name: "Menu item 1",
109
+ },
110
+ {
111
+ name: "Menu item 2",
112
+ },
113
+ {
114
+ name: "Menu item 3",
115
+ },
116
+ ];
117
+
118
+ const [anchorEl, setAnchorEl] = useState<HTMLElement | null>(null);
119
+ const [open, setOpen] = useState(false);
120
+ const [value, setValue] = useState<DefaultAutocompleteOption | null>(null);
121
+
122
+ function handleClick(event: SyntheticEvent<HTMLElement>) {
123
+ if (open) {
124
+ setOpen(false);
125
+ if (anchorEl) {
126
+ anchorEl.focus();
127
+ }
128
+ setAnchorEl(null);
129
+ } else {
130
+ setAnchorEl(event.currentTarget);
131
+ setOpen(true);
132
+ }
133
+ }
134
+
135
+ function handleChange(
136
+ _: SyntheticEvent,
137
+ newValue: DefaultAutocompleteOption | null
138
+ ) {
139
+ setOpen(false);
140
+ setValue(newValue);
141
+ }
142
+
143
+ function handleClickAway() {
144
+ return open && setOpen(false);
145
+ }
146
+
147
+ return (
148
+ <div className="app">
149
+ <InputDropdown
150
+ onClick={handleClick}
151
+ label="Click Target"
152
+ sdsType="label"
153
+ sdsStyle="minimal"
154
+ />
155
+ <DropdownMenu<DefaultAutocompleteOption, false, false, false>
156
+ options={MENU_ITEMS}
157
+ anchorEl={anchorEl}
158
+ open={!!open}
159
+ onChange={handleChange}
160
+ value={value}
161
+ onClickAway={handleClickAway}
162
+ />
163
+ </div>
164
+ );
165
+ }
166
+
167
+ export default App;
168
+ ```
169
+
170
+ ### Search
171
+
172
+ An InputSearch component can be incorporated into the DropdownMenu component by passing it the `search` prop.
173
+
174
+ The search functions by filtering out non-matches as the user types, leaving only menu items with text that match the input. If no matches are found, the DropdownMenu displays “No options” below the InputSearch by default. This text can be changed via the `noOptionsText` prop as shown below.
175
+
176
+ By default, the search’s input text is maintained even when a user selects a MenuItem (if multiple selections are allowed; otherwise the dropdown closes upon selection). This way users can select multiple MenuItems that match the searched term without needing to re-enter it each time. However, this can be changed so that the search input clears upon making a selection; see the “Search cleared on select” example below.
177
+
178
+ 1. In the search box, type in "fruit"
179
+
180
+ 2. DropdownMenu will display "Fruit: Apple" and "Fruit: Orange"
181
+
182
+ 3. Select "Fruit: Apple"
183
+
184
+ 4. Note that the search text is maintained along with the limited list of items
185
+
186
+ **Example: Search**
187
+
188
+ ```tsx
189
+ // DropdownMenu with search
190
+
191
+ import { useEffect, useRef, useState } from "react";
192
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
193
+ import styled from "@emotion/styled";
194
+
195
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
196
+ {
197
+ name: "Fruit: Apple",
198
+ },
199
+ {
200
+ name: "Fruit: Orange",
201
+ },
202
+ {
203
+ name: "Vegetable: Carrot",
204
+ },
205
+ {
206
+ name: "Vegetable: Kale",
207
+ },
208
+ ];
209
+
210
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
211
+
212
+ const Anchor = styled.div`
213
+ position: absolute;
214
+ top: 12px;
215
+ left: 20px;
216
+ `;
217
+
218
+ function handleClickAway() {}
219
+
220
+ function App() {
221
+ const ref = useRef(null);
222
+ const [open, setOpen] = useState(false);
223
+
224
+ useEffect(() => {
225
+ if (ref.current) setOpen(true);
226
+ }, [ref.current]);
227
+
228
+ return (
229
+ <div className="app">
230
+ <Anchor ref={ref} />
231
+ {open && (
232
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
233
+ <DropdownMenu
234
+ PopperBaseProps={POPPER_BASE_PROPS}
235
+ anchorEl={ref.current}
236
+ noOptionsText="No matches found, try again!"
237
+ onClickAway={handleClickAway}
238
+ open
239
+ options={MENU_ITEMS}
240
+ search
241
+ />
242
+ )}
243
+ </div>
244
+ );
245
+ }
246
+
247
+ export default App;
248
+ ```
249
+
250
+ ### Multi-select
251
+
252
+ You can allow users to select multiple menu items by passing the DropdownMenu component the `multiple` prop. MenuItems will be shifted further to the right to make room for checkmarks displayed upon selection.
253
+
254
+ If the `multiple` prop is not `true`, the DropdownMenu allows just one selection. It closes and applies the selection once a menu item is selected.
255
+
256
+ **Example: MultiSelect**
257
+
258
+ ```tsx
259
+ // DropdownMenu with multi-select
260
+
261
+ import { useEffect, useRef, useState } from "react";
262
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
263
+ import styled from "@emotion/styled";
264
+
265
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
266
+ {
267
+ name: "Menu item 1",
268
+ },
269
+ {
270
+ name: "Menu item 2",
271
+ },
272
+ {
273
+ name: "Menu item 3",
274
+ },
275
+ ];
276
+
277
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
278
+
279
+ const Anchor = styled.div`
280
+ position: absolute;
281
+ top: 12px;
282
+ left: 20px;
283
+ `;
284
+
285
+ function handleClickAway() {}
286
+
287
+ function App() {
288
+ const ref = useRef(null);
289
+ const [open, setOpen] = useState(false);
290
+
291
+ useEffect(() => {
292
+ if (ref.current) setOpen(true);
293
+ }, [ref.current]);
294
+
295
+ return (
296
+ <div className="app">
297
+ <Anchor ref={ref} />
298
+ {open && (
299
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
300
+ <DropdownMenu
301
+ PopperBaseProps={POPPER_BASE_PROPS}
302
+ anchorEl={ref.current}
303
+ multiple
304
+ onClickAway={handleClickAway}
305
+ open
306
+ options={MENU_ITEMS}
307
+ />
308
+ )}
309
+ </div>
310
+ );
311
+ }
312
+
313
+ export default App;
314
+ ```
315
+
316
+ ### Search cleared on select
317
+
318
+ If search is included in the DropdownMenu, by default the search input will be maintained when a user selects a MenuItem (if multiple selections are allowed; otherwise the dropdown menu closes upon selection). However, the search input can be set to close upon selection by setting the optional `keepSearchOnSelect` prop to `false`.
319
+
320
+ This setting is intended to be used only when `search` and `multiple` are both set to `true` (otherwise it will have no noticeable affect since the dropdown menu closes upon selection if multi-select is not allowed, hiding the search bar).
321
+
322
+ To see how this works:
323
+
324
+ 1. In the search box, type in "fruit"
325
+
326
+ 2. DropdownMenu will display "Fruit: Apple" and "Fruit: Orange"
327
+
328
+ 3. Select "Fruit: Apple"
329
+
330
+ 4. Note that the search text is now cleared and all dropdown items reappear
331
+
332
+ Compare this to the default behavior in the " Search " example above, or change the `keepSearchOnSelect` prop in the example below to `true`.
333
+
334
+ **Example: ClearSearchOnSelect**
335
+
336
+ ```tsx
337
+ // Dropdown with multi-select that does not maintain searched query upon selection of a menu item
338
+
339
+ import { useEffect, useRef, useState } from "react";
340
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
341
+ import styled from "@emotion/styled";
342
+
343
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
344
+ {
345
+ name: "Fruit: Apple",
346
+ },
347
+ {
348
+ name: "Fruit: Orange",
349
+ },
350
+ {
351
+ name: "Vegetable: Carrot",
352
+ },
353
+ {
354
+ name: "Vegetable: Kale",
355
+ },
356
+ ];
357
+
358
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
359
+
360
+ const Anchor = styled.div`
361
+ position: absolute;
362
+ top: 12px;
363
+ left: 20px;
364
+ `;
365
+
366
+ function App() {
367
+ const ref = useRef(null);
368
+ const [open, setOpen] = useState(false);
369
+
370
+ useEffect(() => {
371
+ if (ref.current) setOpen(true);
372
+ }, [ref.current]);
373
+
374
+ return (
375
+ <div className="app">
376
+ <Anchor ref={ref} />
377
+ {open && (
378
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
379
+ <DropdownMenu
380
+ PopperBaseProps={POPPER_BASE_PROPS}
381
+ anchorEl={ref.current}
382
+ keepSearchOnSelect={false}
383
+ multiple
384
+ onClickAway={function handleClickAway() {}}
385
+ open
386
+ options={MENU_ITEMS}
387
+ search
388
+ />
389
+ )}
390
+ </div>
391
+ );
392
+ }
393
+
394
+ export default App;
395
+ ```
396
+
397
+ ### Grouped sections
398
+
399
+ MenuItems can be displayed in groups with a label.
400
+
401
+ This requires passing DropdownMenu the `groupBy` prop to group options under the returned string. The `groupBy` value is also used as the text for group headings when [MUI Autocomplete renderGroup](https://mui.com/material-ui/api/autocomplete/#props) is not provided. For example:
402
+
403
+ **React TypeScript**
404
+
405
+ ```tsx
406
+ // group items by section
407
+ groupBy={(option) => option.section}
408
+
409
+ // group items by the last character of their names
410
+ groupBy={(option) => option.name.at(-1)}
411
+ ```
412
+
413
+ This `groupBy` prop must be provided or the groups will not render, even if all menu items have `section` properties (see below).
414
+
415
+ > **Warning:** To avoid duplicate headers, please make sure that the options are also sorted with the same dimension that they are grouped by. (See: [Issue](https://github.com/mui/material-ui/issues/21967#issuecomment-665006321) and example below)
416
+
417
+ **Example: GroupedSections**
418
+
419
+ ```tsx
420
+ // Dropdown with grouped sections
421
+
422
+ import { useEffect, useRef, useState } from "react";
423
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
424
+ import styled from "@emotion/styled";
425
+
426
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
427
+ {
428
+ name: "Menu item A.1",
429
+ section: "Section A",
430
+ },
431
+ {
432
+ name: "Menu item A.2",
433
+ section: "Section A",
434
+ },
435
+ {
436
+ name: "Menu item without a specified section",
437
+ },
438
+ {
439
+ name: "Menu item B.1",
440
+ section: "Section B",
441
+ },
442
+ {
443
+ name: "Menu item C.1",
444
+ section: "Section C",
445
+ },
446
+ {
447
+ name: "Menu item C.2",
448
+ section: "Section C",
449
+ },
450
+ {
451
+ name: "Menu item C.3",
452
+ section: "Section C",
453
+ },
454
+ {
455
+ name: "Menu item B.2",
456
+ section: "Section B",
457
+ },
458
+ ];
459
+
460
+ /**
461
+ * Items need to be sorted by the same groupBy dimension
462
+ * In this example, we're grouping by the last character of the item name
463
+ */
464
+ const SORTED_ITEMS = [...MENU_ITEMS].sort((a, b) => {
465
+ const aLastLetter = a.name.slice(-1);
466
+ const bLastLetter = b.name.slice(-1);
467
+
468
+ if (aLastLetter < bLastLetter) {
469
+ return -1;
470
+ }
471
+ if (aLastLetter > bLastLetter) {
472
+ return 1;
473
+ }
474
+ return 0;
475
+ });
476
+
477
+ function groupBy(option: DefaultAutocompleteOption) {
478
+ return option.name.slice(-1);
479
+ }
480
+
481
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
482
+
483
+ const Anchor = styled.div`
484
+ position: absolute;
485
+ top: 12px;
486
+ left: 20px;
487
+ `;
488
+
489
+ function handleClickAway() {}
490
+
491
+ function App() {
492
+ const ref = useRef(null);
493
+ const [open, setOpen] = useState(false);
494
+
495
+ useEffect(() => {
496
+ if (ref.current) setOpen(true);
497
+ }, [ref.current]);
498
+
499
+ return (
500
+ <div className="app">
501
+ <Anchor ref={ref} />
502
+ {open && (
503
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
504
+ <DropdownMenu
505
+ PopperBaseProps={POPPER_BASE_PROPS}
506
+ anchorEl={ref.current}
507
+ groupBy={groupBy}
508
+ onClickAway={handleClickAway}
509
+ open
510
+ options={SORTED_ITEMS}
511
+ />
512
+ )}
513
+ </div>
514
+ );
515
+ }
516
+
517
+ export default App;
518
+ ```
519
+
520
+ ## Recipes
521
+
522
+ These recipes show a few of the more complex approaches available for customizing Dropdown Menus.
523
+
524
+ ### Custom isOptionEqualToValue
525
+
526
+ The `isOptionEqualToValue` prop changes how a selected value is compared against the available options. By default `option.name === val.name` is used. In the custom example below, the `id` property is used instead of the `name` property.
527
+
528
+ This is a MUI prop; learn more in the [Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props).
529
+
530
+ **Example: CustomIsOptionEqualToValue**
531
+
532
+ ```tsx
533
+ // DropdownMenu with customized `isOptionEqualToValue`
534
+
535
+ import { useEffect, useRef, useState } from "react";
536
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
537
+ import styled from "@emotion/styled";
538
+
539
+ type MenuItem = DefaultAutocompleteOption & { id: string };
540
+
541
+ function optionIdEqualToValueId(option: MenuItem, value: MenuItem) {
542
+ return option.id === value.id;
543
+ }
544
+
545
+ const MENU_ITEMS: MenuItem[] = [
546
+ {
547
+ name: "Menu item 1",
548
+ id: "one",
549
+ },
550
+ {
551
+ name: "Menu item 2",
552
+ id: "two",
553
+ },
554
+ {
555
+ name: "Menu item 3",
556
+ id: "three",
557
+ },
558
+ {
559
+ name: "Longer menu item than the others",
560
+ id: "four",
561
+ },
562
+ ];
563
+
564
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
565
+
566
+ const Anchor = styled.div`
567
+ position: absolute;
568
+ top: 12px;
569
+ left: 20px;
570
+ `;
571
+
572
+ function handleClickAway() {}
573
+
574
+ function App() {
575
+ const ref = useRef(null);
576
+ const [open, setOpen] = useState(false);
577
+
578
+ useEffect(() => {
579
+ if (ref.current) setOpen(true);
580
+ }, [ref.current]);
581
+
582
+ return (
583
+ <div className="app">
584
+ <Anchor ref={ref} />
585
+ {open && (
586
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
587
+ <DropdownMenu<MenuItem, false, false, false>
588
+ PopperBaseProps={POPPER_BASE_PROPS}
589
+ anchorEl={ref.current}
590
+ isOptionEqualToValue={optionIdEqualToValueId}
591
+ onClickAway={handleClickAway}
592
+ open
593
+ options={MENU_ITEMS}
594
+ />
595
+ )}
596
+ </div>
597
+ );
598
+ }
599
+
600
+ export default App;
601
+ ```
602
+
603
+ ### Custom onChange
604
+
605
+ The optional `onChange` prop specifies what happens when a new selection is made.
606
+
607
+ In the example below, `onChange` has been modified such that making a new selection logs the value and reason to the console.
608
+
609
+ This is a MUI prop; learn more in the [Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props).
610
+
611
+ **Example: CustomOnChange**
612
+
613
+ ```tsx
614
+ // DropdownMenu with customized `onInputChange`
615
+
616
+ import { SyntheticEvent, useEffect, useRef, useState } from "react";
617
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
618
+ import styled from "@emotion/styled";
619
+
620
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
621
+ {
622
+ name: "Menu item 1",
623
+ },
624
+ {
625
+ name: "Menu item 2",
626
+ },
627
+ {
628
+ name: "Menu item 3",
629
+ },
630
+ {
631
+ name: "Longer menu item than the others",
632
+ },
633
+ ];
634
+
635
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
636
+
637
+ const Anchor = styled.div`
638
+ position: absolute;
639
+ top: 12px;
640
+ left: 20px;
641
+ `;
642
+
643
+ function handleClickAway() {}
644
+
645
+ type ChangeMessage = { reason: string; value: unknown };
646
+
647
+ function Message({ message }: { message?: ChangeMessage }) {
648
+ return (
649
+ <div
650
+ style={{ position: "absolute", top: "170px", fontFamily: "sans-serif" }}
651
+ >
652
+ <p>{JSON.stringify(message)}</p>
653
+ </div>
654
+ );
655
+ }
656
+
657
+ function App() {
658
+ const [message, setMessage] = useState<ChangeMessage>();
659
+
660
+ const ref = useRef(null);
661
+ const [open, setOpen] = useState(false);
662
+
663
+ useEffect(() => {
664
+ if (ref.current) setOpen(true);
665
+ }, [ref.current]);
666
+
667
+ return (
668
+ <div className="app">
669
+ <Anchor ref={ref} />
670
+ {open && (
671
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
672
+ <>
673
+ <DropdownMenu
674
+ PopperBaseProps={POPPER_BASE_PROPS}
675
+ anchorEl={ref.current}
676
+ keepSearchOnSelect
677
+ onClickAway={handleClickAway}
678
+ onChange={(_: SyntheticEvent, value: unknown, reason: string) =>
679
+ setMessage({ reason, value })
680
+ }
681
+ open
682
+ options={MENU_ITEMS}
683
+ />
684
+ <Message message={message} />
685
+ </>
686
+ )}
687
+ </div>
688
+ );
689
+ }
690
+
691
+ export default App;
692
+ ```
693
+
694
+ ### Custom PopperBaseProps
695
+
696
+ `PopperBaseProps` is an SDS-specific prop made for passing custom props to the Popper component, which is included as part of the DropdownMenu component.
697
+
698
+ The Popper component is part of MUI; learn more in the [Popper documentation](https://mui.com/material-ui/api/popper/), and see all the props available to pass to it on the [Popper API page](https://mui.com/material-ui/api/popper/).
699
+
700
+ The example below passes the Popper a `className` prop and additionally uses the `sx` prop to make style changes (learn more on the [MUI sx documentation page](https://mui.com/system/getting-started/the-sx-prop/)).
701
+
702
+ **Example: CustomPopperBaseProps**
703
+
704
+ ```tsx
705
+ // DropdownMenu with custom `PopperBaseProps`
706
+
707
+ import { useEffect, useRef, useState } from "react";
708
+ import { DropdownMenu, DefaultAutocompleteOption } from "@czi-sds/components";
709
+ import styled from "@emotion/styled";
710
+
711
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
712
+ {
713
+ name: "Menu item 1",
714
+ },
715
+ {
716
+ name: "Menu item 2",
717
+ },
718
+ {
719
+ name: "Menu item 3",
720
+ },
721
+ {
722
+ name: "Longer menu item than the others",
723
+ },
724
+ ];
725
+
726
+ const POPPER_BASE_PROPS = {
727
+ className: "popper",
728
+ sx: {
729
+ width: 500,
730
+ borderColor: "salmon",
731
+ borderWidth: 10,
732
+ },
733
+ popperOptions: { strategy: "absolute" as const },
734
+ };
735
+
736
+ const Anchor = styled.div`
737
+ position: absolute;
738
+ top: 12px;
739
+ left: 20px;
740
+ `;
741
+
742
+ function App() {
743
+ const ref = useRef(null);
744
+ const [open, setOpen] = useState(false);
745
+
746
+ useEffect(() => {
747
+ if (ref.current) setOpen(true);
748
+ }, [ref.current]);
749
+
750
+ return (
751
+ <div className="app">
752
+ <Anchor ref={ref} />
753
+ {open && (
754
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
755
+ <DropdownMenu
756
+ PopperBaseProps={POPPER_BASE_PROPS}
757
+ anchorEl={ref.current}
758
+ onClickAway={function handleClickAway() {}}
759
+ open
760
+ options={MENU_ITEMS}
761
+ />
762
+ )}
763
+ </div>
764
+ );
765
+ }
766
+
767
+ export default App;
768
+ ```
769
+
770
+ ### Custom Popper component
771
+
772
+ In addition to modifying the Popper's styles via `PopperBaseProps` above, the styles for the Popper component can be overwritten more directly with `styled()`.
773
+
774
+ To get all the default SDS styles used for Popper, first copy them into a custom-styled Popper (from within `sci-components/packages/components/src/core/DropdownMenu/style.ts` file). Then replace and / or follow up those styles with custom styles. The example below includes comments for each of these steps within `CustomPopper`.
775
+
776
+ **Example: CustomPopperComponent**
777
+
778
+ ```tsx
779
+ // DropdownMenu with custom Popper component
780
+
781
+ import { useEffect, useRef, useState } from "react";
782
+ import { Popper, styled } from "@mui/material";
783
+ import {
784
+ DropdownMenu,
785
+ DefaultAutocompleteOption,
786
+ Borders,
787
+ CommonThemeProps,
788
+ Corners,
789
+ Shadows,
790
+ Spaces,
791
+ } from "@czi-sds/components";
792
+
793
+ const MENU_ITEMS: DefaultAutocompleteOption[] = [
794
+ {
795
+ name: "Menu item 1",
796
+ },
797
+ {
798
+ name: "Menu item 2",
799
+ },
800
+ {
801
+ name: "Menu item 3",
802
+ },
803
+ {
804
+ name: "Longer menu item than the others",
805
+ },
806
+ ];
807
+
808
+ // Step 1/3: Copy existing base styles for the Popper component from
809
+ // sci-components/packages/components/src/core/DropdownMenu/style.ts, ~lines 206-229:
810
+ const getBorders = ({ theme }: CommonThemeProps): Borders | null => {
811
+ return theme?.app?.borders || null;
812
+ };
813
+
814
+ const getCorners = ({ theme }: CommonThemeProps): Corners | null => {
815
+ return theme?.app?.corners || null;
816
+ };
817
+
818
+ const getShadows = ({ theme }: CommonThemeProps): Shadows | null => {
819
+ return theme?.app?.shadows || null;
820
+ };
821
+
822
+ const getSpaces = ({ theme }: CommonThemeProps): Spaces | null => {
823
+ return theme?.app?.spacing || null;
824
+ };
825
+
826
+ const CustomPopper = styled(Popper)`
827
+ .MuiAutocomplete-popperDisablePortal {
828
+ position: relative;
829
+ width: 100% !important;
830
+ box-shadow: none;
831
+ padding: 0;
832
+ border: none;
833
+ }
834
+
835
+ ${(props) => {
836
+ const borders = getBorders(props);
837
+ const corners = getCorners(props);
838
+ const shadows = getShadows(props);
839
+ const spacings = getSpaces(props);
840
+
841
+ return `
842
+ background-color: white;
843
+ border: ${borders?.base?.divider};
844
+ border-radius: ${corners?.m}px;
845
+ box-shadow: ${shadows?.m};
846
+ padding: ${spacings?.xs}px;
847
+ box-sizing: border-box;
848
+ z-index: 1400;
849
+ `;
850
+ }}
851
+
852
+ border-color: purple;
853
+ border-style: dotted;
854
+ border-width: 15px !important;
855
+ `;
856
+
857
+ const POPPER_BASE_PROPS = { popperOptions: { strategy: "absolute" as const } };
858
+
859
+ const Anchor = styled("div")`
860
+ position: absolute;
861
+ top: 12px;
862
+ left: 20px;
863
+ `;
864
+
865
+ function App() {
866
+ const ref = useRef(null);
867
+ const [open, setOpen] = useState(false);
868
+
869
+ useEffect(() => {
870
+ if (ref.current) setOpen(true);
871
+ }, [ref.current]);
872
+
873
+ return (
874
+ <div className="app">
875
+ <Anchor ref={ref} />
876
+ {open && (
877
+ // 👇 Only pay attention to the props here, everything else is just glue to mount the example
878
+ <DropdownMenu
879
+ PopperBaseProps={POPPER_BASE_PROPS}
880
+ anchorEl={ref.current}
881
+ onClickAway={function handleClickAway() {}}
882
+ open
883
+ options={MENU_ITEMS}
884
+ // Step 3/3: Pass the new CustomPopper to PopperComponent prop
885
+ PopperComponent={CustomPopper}
886
+ />
887
+ )}
888
+ </div>
889
+ );
890
+ }
891
+
892
+ export default App;
893
+ ```
894
+
895
+ ---
896
+
897
+ ## SDS vs MUI
898
+
899
+ Both SDS's DropdownMenu and MUI's Autocomplete have huge API surfaces, so it is not practical to list every way in which they differ (in part because the list would likely become obsolete quickly!). In summary, these are a few of the most relevant ways in which DropdownMenu integrates with Autocomplete and other MUI components:
900
+
901
+ - SDS DropdownMenu uses [MUI Autocomplete](https://mui.com/material-ui/react-autocomplete/) under the hood, so all props passed to DropdownMenu are ultimately passed to the Autocomplete component as well. This means MUI's Autocomplete props can be used on SDS's DropdownMenu if needed.
902
+
903
+ - SDS DropdownMenu uses [MUI Popper](https://mui.com/material-ui/react-popper/). A custom Popper component can be passed via `props.PopperComponent` and/or `props.PopperBaseProps` to control the popper component.
904
+
905
+ - Similarly, SDS DropdownMenu uses [MUI Paper](https://mui.com/material-ui/react-paper/). A custom Paper component can be passed via `props.PaperComponent` to enable custom styling.
906
+
907
+ ## MUI Documentation
908
+
909
+ Documentation for the underlying MUI Autocomplete component can be found [here](https://mui.com/material-ui/react-autocomplete/).
910
+
911
+ ## Props
912
+
913
+ Any custom SDS props and MUI props required for implementation are found on the table below. See the MUI documentation for additional optional props.
914
+
915
+ | **Name** | **Type** | **Default** | **Description** |
916
+ | ------------------------ | ------------------------------------ | ------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
917
+ | `anchorEl` | `HTMLElement` \| `null` | - | Required. The element the menu is positioned against, usually the control that opens it. Until it is set the menu renders an empty container: the list is only mounted once there is something to anchor it to. See the [MUI Popper API](https://mui.com/material-ui/api/popper/). |
918
+ | `open` | `boolean` | `false` | Whether the menu is showing. The menu holds no open state of its own, so this and `anchorEl` are what the opening control sets. |
919
+ | `options` | `T[]` | - | Required. One object per menu item, each needing at least a `name`. An option that itself has an `options` array turns the menu into columns, which changes how it is sized. |
920
+ | `children` | `JSX.Element` \| `null` | - | Rendered inside the menu below the list, for footers such as an apply button. |
921
+ | `ClickAwayListenerProps` | `Partial<ClickAwayListenerProps>` | - | Passes props to the [MUI ClickAwayListener](https://mui.com/base-ui/react-click-away-listener/components-api/). |
922
+ | `groupBy` | `function` | - | Groups menu items according to their assigned section. |
923
+ | `headerComponentSlot` | `JSX.Element` | - | Rendered in the menu's header, below `title`. Either one is enough to give the menu a header. |
924
+ | `InputBaseProps` | `Partial<InputSearchProps>` | - | Passed to the InputSearch the `search` prop renders. The menu sets `autoFocus` from `isSearchAutoFocus` and `onClick` to a no-op after these, so those two are the menu's to decide. |
925
+ | `isOptionEqualToValue` | `function` | `(option, val) => option.name === val.name` | Changes how a selected value is compared against the available options; see more in the [MUI Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props) or in the Recipes section. |
926
+ | `isSearchAutoFocus` | `boolean` | `true` | Puts the cursor in the search input as the menu opens. It overrides any `autoFocus` given through `InputBaseProps`. |
927
+ | `keepSearchOnSelect` | `boolean` | `true` | Maintains a search input when a user selects a menu item (only if multiple selections are allowed via the `multiple` prop; otherwise the dropdown closes upon selection). |
928
+ | `label` | `string` | `"Search"` | The placeholder text of the search input. |
929
+ | `multiple` | `boolean` | `false` | Allows user to select multiple menu items; see more in the [MUI Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props). |
930
+ | `noOptionsText` | `string` | `"No options"` | Sets the text that displays if there are no matching search results; see more in the [MUI Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props). |
931
+ | `onClickAway` | `function` | `noop` | Sets what happens when a user clicks outside of the DropdownMenu. This is where a menu is normally closed. **Signature:** `function(event: MouseEvent \| TouchEvent) => void` |
932
+ | `onClose` | `function` | - | Called when the list asks to close, such as on selecting an option in a single-select menu. Closing is still yours to carry out through `open`. **Signature:** `function(event: SyntheticEvent, reason: AutocompleteCloseReason) => void` |
933
+ | `onInputChange` | `function` | - | Called as the search text changes; see more in the [MUI Autocomplete API](https://mui.com/material-ui/api/autocomplete/#props) or in the Recipes section. **Signature:** `function(event: SyntheticEvent, value: string, reason: AutocompleteInputChangeReason) => void` |
934
+ | `onOpen` | `function` | - | Called when the list asks to open. **Signature:** `function(event: SyntheticEvent) => void` |
935
+ | `PaperComponent` | `JSXElementConstructor<PaperProps>` | SDS's `StyledPaper` | The surface the menu is drawn on. Replace it to restyle the menu's background, border and shadow. |
936
+ | `PopperBaseProps` | `Partial<PopperProps>` | `{}` | Passes custom props to the MUI Popper the menu is placed with. Learn more in the [Popper documentation](https://mui.com/material-ui/react-popper/), and see all the props available to pass to it on the [Popper API page](https://mui.com/material-ui/api/popper/). See an example of `PopperBaseProps` in use in the Recipes section. Its `sx` is merged over the menu's own sizing, so this is also how the 160px minimum width is lifted. |
937
+ | `PopperComponent` | `JSXElementConstructor<PopperProps>` | SDS's `StyledPopper` | The [MUI Popper component](https://mui.com/material-ui/react-popper/) is included as part of the SDS DropdownMenu component, and its styles can be changed or added to. |
938
+ | `PopperPlacement` | `PopperProps["placement"]` | `"bottom-start"` | Where the menu sits relative to its anchor, as MUI's Popper understands it: one of `"auto"`, `"top"`, `"bottom"`, `"left"`, `"right"`, each also available with a `-start` or `-end` suffix. |
939
+ | `renderInput` | `function` | - | Replaces the search input entirely. Most menus want `InputBaseProps` instead, which keeps the SDS input. **Signature:** `function(params: AutocompleteRenderInputParams) => ReactNode` |
940
+ | `search` | `boolean` | `false` | Provides a search bar at the top of the menu from which users can narrow the list of menu items. |
941
+ | `subTitle` | `ReactNode` | - | A second line below the header's title. It is only rendered when `title` is set as well. |
942
+ | `title` | `ReactNode` | - | Sets a heading for the menu. |
943
+ | `width` | `number` \| `string` | `160` | The width of the menu, as a number of pixels or any CSS width. The 160px minimum still applies underneath it, and a menu whose options are laid out in columns ignores this and sizes itself to its content. |
944
+
945
+ There are many more props that can be used with the DropdownMenu component, via those available to [MUI's Autocomplete component](https://mui.com/material-ui/api/autocomplete/#props).
946
+
947
+ > **Note for use with SDS** **Table** **and other components:**
948
+ >
949
+ > Each time a table column is shown/hidden a new table object is created. This causes components within the table to remount. _This can be a problem with_ _DropdownMenu_ _if the menu is supposed to stay open while the columns are hidden/shown because the anchor element also gets recreated._ To resolve this, move the DropdownMenu anchor element outside of the table or use the `pendingState` and only show/hide the columns when closing the dropdown.