@patternfly/react-core 4.227.1 → 4.227.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/dist/esm/components/DataList/DataList.d.ts +0 -2
- package/dist/esm/components/DataList/DataList.d.ts.map +1 -1
- package/dist/esm/components/DataList/DataList.js.map +1 -1
- package/dist/esm/components/DataList/DataListItem.d.ts.map +1 -1
- package/dist/esm/components/DataList/DataListItem.js +1 -2
- package/dist/esm/components/DataList/DataListItem.js.map +1 -1
- package/dist/js/components/DataList/DataList.d.ts +0 -2
- package/dist/js/components/DataList/DataList.d.ts.map +1 -1
- package/dist/js/components/DataList/DataList.js.map +1 -1
- package/dist/js/components/DataList/DataListItem.d.ts.map +1 -1
- package/dist/js/components/DataList/DataListItem.js +1 -2
- package/dist/js/components/DataList/DataListItem.js.map +1 -1
- package/dist/umd/react-core.js +1 -2
- package/dist/umd/react-core.min.js +1 -1
- package/package.json +5 -5
- package/src/components/DataList/DataList.tsx +0 -2
- package/src/components/DataList/DataListItem.tsx +1 -3
- package/src/components/DataList/__tests__/DataList.test.tsx +14 -32
- package/src/components/DataList/examples/DataListSelectableRows.tsx +1 -1
- package/src/components/Menu/examples/Menu.md +19 -1290
- package/src/components/Menu/examples/MenuBasic.tsx +51 -0
- package/src/components/Menu/examples/MenuFilteringWithTextInput.tsx +52 -0
- package/src/components/Menu/examples/MenuOptionMultiSelect.tsx +30 -0
- package/src/components/Menu/examples/MenuOptionSingleSelect.tsx +27 -0
- package/src/components/Menu/examples/MenuScrollable.tsx +48 -0
- package/src/components/Menu/examples/MenuScrollableCustomMenuHeight.tsx +48 -0
- package/src/components/Menu/examples/MenuWithActions.tsx +75 -0
- package/src/components/Menu/examples/MenuWithCheckbox.tsx +2 -2
- package/src/components/Menu/examples/MenuWithDescription.tsx +35 -0
- package/src/components/Menu/examples/{MenuDrilldown.tsx → MenuWithDrilldown.tsx} +1 -1
- package/src/components/Menu/examples/MenuWithDrilldownBreadcrumbs.tsx +331 -0
- package/src/components/Menu/examples/{MenuDrilldownInitialState.tsx → MenuWithDrilldownInitialState.tsx} +0 -0
- package/src/components/Menu/examples/{MenuDrilldownSubmenuFunctions.tsx → MenuWithDrilldownSubmenuFunctions.tsx} +1 -1
- package/src/components/Menu/examples/MenuWithFavorites.tsx +104 -0
- package/src/components/Menu/examples/MenuWithFooter.tsx +40 -0
- package/src/components/Menu/examples/MenuWithIcons.tsx +33 -0
- package/src/components/Menu/examples/MenuWithLinks.tsx +30 -0
- package/src/components/Menu/examples/MenuWithSeparators.tsx +26 -0
- package/src/components/Menu/examples/MenuWithTitledGroups.tsx +46 -0
- package/src/components/Menu/examples/MenuWithViewMore.tsx +118 -0
- package/src/components/ProgressStepper/examples/ProgressStepper.md +13 -356
- package/src/components/ProgressStepper/examples/ProgressStepperBasic.tsx +21 -0
- package/src/components/ProgressStepper/examples/ProgressStepperBasicFailure.tsx +48 -0
- package/src/components/ProgressStepper/examples/ProgressStepperBasicIssue.tsx +48 -0
- package/src/components/ProgressStepper/examples/ProgressStepperBasicWithAlignment.tsx +59 -0
- package/src/components/ProgressStepper/examples/ProgressStepperBasicWithDescription.tsx +35 -0
- package/src/components/ProgressStepper/examples/ProgressStepperCompact.tsx +51 -0
- package/src/components/ProgressStepper/examples/ProgressStepperCustomIcons.tsx +35 -0
- package/src/components/ProgressStepper/examples/ProgressStepperHelpPopover.tsx +62 -0
|
@@ -20,112 +20,12 @@ import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-ico
|
|
|
20
20
|
|
|
21
21
|
### Basic
|
|
22
22
|
|
|
23
|
-
```
|
|
24
|
-
import React from 'react';
|
|
25
|
-
import { Menu, MenuContent, MenuList, MenuItem, Checkbox } from '@patternfly/react-core';
|
|
26
|
-
|
|
27
|
-
class MenuBasicList extends React.Component {
|
|
28
|
-
constructor(props) {
|
|
29
|
-
super(props);
|
|
30
|
-
this.state = {
|
|
31
|
-
activeItem: 0,
|
|
32
|
-
isPlain: false
|
|
33
|
-
};
|
|
34
|
-
this.onSelect = (event, itemId) => {
|
|
35
|
-
console.log(`clicked ${itemId}`);
|
|
36
|
-
this.setState({
|
|
37
|
-
activeItem: itemId
|
|
38
|
-
});
|
|
39
|
-
};
|
|
40
|
-
this.togglePlain = checked => {
|
|
41
|
-
this.setState({
|
|
42
|
-
isPlain: checked
|
|
43
|
-
});
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
render() {
|
|
48
|
-
const { activeItem, isPlain } = this.state;
|
|
49
|
-
return (
|
|
50
|
-
<React.Fragment>
|
|
51
|
-
<Menu activeItemId={activeItem} onSelect={this.onSelect} isPlain={isPlain}>
|
|
52
|
-
<MenuContent>
|
|
53
|
-
<MenuList>
|
|
54
|
-
<MenuItem itemId={0}>Action</MenuItem>
|
|
55
|
-
<MenuItem
|
|
56
|
-
itemId={1}
|
|
57
|
-
to="#default-link2"
|
|
58
|
-
// just for demo so that navigation is not triggered
|
|
59
|
-
onClick={event => event.preventDefault()}
|
|
60
|
-
>
|
|
61
|
-
Link
|
|
62
|
-
</MenuItem>
|
|
63
|
-
<MenuItem isDisabled>Disabled action</MenuItem>
|
|
64
|
-
<MenuItem isDisabled to="#default-link4">
|
|
65
|
-
Disabled link
|
|
66
|
-
</MenuItem>
|
|
67
|
-
</MenuList>
|
|
68
|
-
</MenuContent>
|
|
69
|
-
</Menu>
|
|
70
|
-
<div style={{ marginTop: 20 }}>
|
|
71
|
-
<Checkbox
|
|
72
|
-
label="Plain menu"
|
|
73
|
-
isChecked={isPlain}
|
|
74
|
-
onChange={this.togglePlain}
|
|
75
|
-
aria-label="plain menu checkbox"
|
|
76
|
-
id="toggle-plain"
|
|
77
|
-
name="toggle-plain"
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
</React.Fragment>
|
|
81
|
-
);
|
|
82
|
-
}
|
|
83
|
-
}
|
|
23
|
+
```ts file="MenuBasic.tsx"
|
|
84
24
|
```
|
|
85
25
|
|
|
86
26
|
### With icons
|
|
87
27
|
|
|
88
|
-
```
|
|
89
|
-
import React from 'react';
|
|
90
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
91
|
-
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
92
|
-
import LayerGroupIcon from '@patternfly/react-icons/dist/esm/icons/layer-group-icon';
|
|
93
|
-
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
94
|
-
|
|
95
|
-
class MenuIconsList extends React.Component {
|
|
96
|
-
constructor(props) {
|
|
97
|
-
super(props);
|
|
98
|
-
this.state = {
|
|
99
|
-
activeItem: 0
|
|
100
|
-
};
|
|
101
|
-
this.onSelect = (event, itemId) => {
|
|
102
|
-
this.setState({
|
|
103
|
-
activeItem: itemId
|
|
104
|
-
});
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
render() {
|
|
109
|
-
const { activeItem } = this.state;
|
|
110
|
-
return (
|
|
111
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
112
|
-
<MenuContent>
|
|
113
|
-
<MenuList>
|
|
114
|
-
<MenuItem icon={<CodeBranchIcon aria-hidden />} itemId={0}>
|
|
115
|
-
From git
|
|
116
|
-
</MenuItem>
|
|
117
|
-
<MenuItem icon={<LayerGroupIcon aria-hidden />} itemId={1}>
|
|
118
|
-
Container image
|
|
119
|
-
</MenuItem>
|
|
120
|
-
<MenuItem icon={<CubeIcon aria-hidden />} itemId={2}>
|
|
121
|
-
Docker file
|
|
122
|
-
</MenuItem>
|
|
123
|
-
</MenuList>
|
|
124
|
-
</MenuContent>
|
|
125
|
-
</Menu>
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
}
|
|
28
|
+
```ts file="MenuWithIcons.tsx"
|
|
129
29
|
```
|
|
130
30
|
|
|
131
31
|
### With checkbox
|
|
@@ -135,1258 +35,87 @@ class MenuIconsList extends React.Component {
|
|
|
135
35
|
|
|
136
36
|
### Filtering with text input
|
|
137
37
|
|
|
138
|
-
```
|
|
139
|
-
import React from 'react';
|
|
140
|
-
import { Menu, MenuList, MenuItem, MenuContent, MenuInput, TextInput, Divider } from '@patternfly/react-core';
|
|
141
|
-
|
|
142
|
-
class MenuWithFiltering extends React.Component {
|
|
143
|
-
constructor(props) {
|
|
144
|
-
super(props);
|
|
145
|
-
this.state = {
|
|
146
|
-
activeItem: 0,
|
|
147
|
-
input: ''
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
this.onSelect = (event, itemId) => {
|
|
151
|
-
this.setState({
|
|
152
|
-
activeItem: itemId
|
|
153
|
-
});
|
|
154
|
-
};
|
|
155
|
-
|
|
156
|
-
this.handleTextInputChange = (value, field) => {
|
|
157
|
-
this.setState({ [field]: value });
|
|
158
|
-
};
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
render() {
|
|
162
|
-
const { activeItem, input } = this.state;
|
|
163
|
-
const menuListItemsText = ['Action 1', 'Action 2', 'Action 3'];
|
|
164
|
-
|
|
165
|
-
const menuListItems = menuListItemsText
|
|
166
|
-
.filter(item => !input || item.toLowerCase().includes(input.toString().toLowerCase()))
|
|
167
|
-
.map((currentValue, index) => (
|
|
168
|
-
<MenuItem key={currentValue} itemId={index}>
|
|
169
|
-
{currentValue}
|
|
170
|
-
</MenuItem>
|
|
171
|
-
));
|
|
172
|
-
if (input && menuListItems.length === 0) {
|
|
173
|
-
menuListItems.push(
|
|
174
|
-
<MenuItem isDisabled key="no result">
|
|
175
|
-
No results found
|
|
176
|
-
</MenuItem>
|
|
177
|
-
);
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
return (
|
|
181
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
182
|
-
<MenuInput>
|
|
183
|
-
<TextInput
|
|
184
|
-
value={input}
|
|
185
|
-
aria-label="Filter menu items"
|
|
186
|
-
iconVariant="search"
|
|
187
|
-
type="search"
|
|
188
|
-
onChange={value => this.handleTextInputChange(value, 'input')}
|
|
189
|
-
/>
|
|
190
|
-
</MenuInput>
|
|
191
|
-
<Divider />
|
|
192
|
-
<MenuContent>
|
|
193
|
-
<MenuList>{menuListItems}</MenuList>
|
|
194
|
-
</MenuContent>
|
|
195
|
-
</Menu>
|
|
196
|
-
);
|
|
197
|
-
}
|
|
198
|
-
}
|
|
38
|
+
```ts file="MenuFilteringWithTextInput.tsx"
|
|
199
39
|
```
|
|
200
40
|
|
|
201
41
|
### With links
|
|
202
42
|
|
|
203
|
-
```
|
|
204
|
-
import React from 'react';
|
|
205
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
206
|
-
|
|
207
|
-
class MenuWithLinks extends React.Component {
|
|
208
|
-
constructor(props) {
|
|
209
|
-
super(props);
|
|
210
|
-
this.state = {
|
|
211
|
-
activeItem: 0
|
|
212
|
-
};
|
|
213
|
-
this.onSelect = (event, itemId) => {
|
|
214
|
-
this.setState({
|
|
215
|
-
activeItem: itemId
|
|
216
|
-
});
|
|
217
|
-
};
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
render() {
|
|
221
|
-
const { activeItem } = this.state;
|
|
222
|
-
return (
|
|
223
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
224
|
-
<MenuContent>
|
|
225
|
-
<MenuList>
|
|
226
|
-
<MenuItem isExternalLink to="#default-link1" itemId={0}>
|
|
227
|
-
Link 1
|
|
228
|
-
</MenuItem>
|
|
229
|
-
<MenuItem isExternalLink to="#default-link2" itemId={1}>
|
|
230
|
-
Link 2
|
|
231
|
-
</MenuItem>
|
|
232
|
-
<MenuItem to="#default-link3" itemId={2}>
|
|
233
|
-
Link 3
|
|
234
|
-
</MenuItem>
|
|
235
|
-
</MenuList>
|
|
236
|
-
</MenuContent>
|
|
237
|
-
</Menu>
|
|
238
|
-
);
|
|
239
|
-
}
|
|
240
|
-
}
|
|
43
|
+
```ts file="MenuWithLinks.tsx"
|
|
241
44
|
```
|
|
242
45
|
|
|
243
46
|
### With separator(s)
|
|
244
47
|
|
|
245
|
-
```
|
|
246
|
-
import React from 'react';
|
|
247
|
-
import { Divider, Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
248
|
-
|
|
249
|
-
class MenuWithSeparators extends React.Component {
|
|
250
|
-
constructor(props) {
|
|
251
|
-
super(props);
|
|
252
|
-
this.state = {
|
|
253
|
-
activeItem: 0
|
|
254
|
-
};
|
|
255
|
-
this.onSelect = (event, itemId) => {
|
|
256
|
-
this.setState({
|
|
257
|
-
activeItem: itemId
|
|
258
|
-
});
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
render() {
|
|
263
|
-
const { activeItem } = this.state;
|
|
264
|
-
return (
|
|
265
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
266
|
-
<MenuContent>
|
|
267
|
-
<MenuList>
|
|
268
|
-
<MenuItem itemId={0}>Action 1</MenuItem>
|
|
269
|
-
<MenuItem itemId={1}>Action 2</MenuItem>
|
|
270
|
-
<Divider component="li" />
|
|
271
|
-
<MenuItem itemId={2}>Action 3</MenuItem>
|
|
272
|
-
</MenuList>
|
|
273
|
-
</MenuContent>
|
|
274
|
-
</Menu>
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
48
|
+
```ts file="MenuWithSeparators.tsx"
|
|
278
49
|
```
|
|
279
50
|
|
|
280
51
|
### With titled groups
|
|
281
52
|
|
|
282
|
-
```
|
|
283
|
-
import React from 'react';
|
|
284
|
-
import { Menu, MenuContent, MenuGroup, MenuList, MenuItem, Divider } from '@patternfly/react-core';
|
|
285
|
-
|
|
286
|
-
class MenuWithTitledGroups extends React.Component {
|
|
287
|
-
constructor(props) {
|
|
288
|
-
super(props);
|
|
289
|
-
this.state = {
|
|
290
|
-
activeItem: 0
|
|
291
|
-
};
|
|
292
|
-
this.onSelect = (event, itemId) => {
|
|
293
|
-
this.setState({
|
|
294
|
-
activeItem: itemId
|
|
295
|
-
});
|
|
296
|
-
};
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
render() {
|
|
300
|
-
const { activeItem } = this.state;
|
|
301
|
-
return (
|
|
302
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
303
|
-
<MenuContent>
|
|
304
|
-
<MenuGroup>
|
|
305
|
-
<MenuList>
|
|
306
|
-
<MenuItem to="#" itemId={0}>
|
|
307
|
-
Link not in group
|
|
308
|
-
</MenuItem>
|
|
309
|
-
</MenuList>
|
|
310
|
-
</MenuGroup>
|
|
311
|
-
<Divider />
|
|
312
|
-
<MenuGroup label="Group 1" labelHeadingLevel="h3">
|
|
313
|
-
<MenuList>
|
|
314
|
-
<MenuItem to="#" itemId={1}>
|
|
315
|
-
Link 1
|
|
316
|
-
</MenuItem>
|
|
317
|
-
<MenuItem itemId={2}>Link 2</MenuItem>
|
|
318
|
-
</MenuList>
|
|
319
|
-
</MenuGroup>
|
|
320
|
-
<Divider />
|
|
321
|
-
<MenuGroup label="Group 2" labelHeadingLevel="h3">
|
|
322
|
-
<MenuList>
|
|
323
|
-
<MenuItem to="#" itemId={3}>
|
|
324
|
-
Link 1
|
|
325
|
-
</MenuItem>
|
|
326
|
-
<MenuItem to="#" itemId={4}>
|
|
327
|
-
Link 2
|
|
328
|
-
</MenuItem>
|
|
329
|
-
</MenuList>
|
|
330
|
-
</MenuGroup>
|
|
331
|
-
</MenuContent>
|
|
332
|
-
</Menu>
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
}
|
|
53
|
+
```ts file="MenuWithTitledGroups.tsx"
|
|
336
54
|
```
|
|
337
55
|
|
|
338
56
|
### With description
|
|
339
57
|
|
|
340
|
-
```
|
|
341
|
-
import React from 'react';
|
|
342
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
343
|
-
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
344
|
-
|
|
345
|
-
class MenuWithDescription extends React.Component {
|
|
346
|
-
constructor(props) {
|
|
347
|
-
super(props);
|
|
348
|
-
this.state = {
|
|
349
|
-
activeItem: 0
|
|
350
|
-
};
|
|
351
|
-
this.onSelect = (event, itemId) => {
|
|
352
|
-
this.setState({
|
|
353
|
-
activeItem: itemId
|
|
354
|
-
});
|
|
355
|
-
};
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
render() {
|
|
359
|
-
const { activeItem } = this.state;
|
|
360
|
-
return (
|
|
361
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem}>
|
|
362
|
-
<MenuContent>
|
|
363
|
-
<MenuList>
|
|
364
|
-
<MenuItem icon={<CodeBranchIcon aria-hidden />} description="Description" itemId={0}>
|
|
365
|
-
Action 1
|
|
366
|
-
</MenuItem>
|
|
367
|
-
<MenuItem isDisabled icon={<CodeBranchIcon aria-hidden />} description="Description" itemId={1}>
|
|
368
|
-
Action 2 disabled
|
|
369
|
-
</MenuItem>
|
|
370
|
-
<MenuItem
|
|
371
|
-
icon={<CodeBranchIcon aria-hidden />}
|
|
372
|
-
description="Nunc non ornare ex, et pretium dui. Duis nec augue at urna elementum blandit tincidunt eget metus. Aenean sed metus id urna dignissim interdum. Aenean vel nisl vitae arcu vehicula pulvinar eget nec turpis. Cras sit amet est est."
|
|
373
|
-
itemId={2}
|
|
374
|
-
>
|
|
375
|
-
Action 3
|
|
376
|
-
</MenuItem>
|
|
377
|
-
</MenuList>
|
|
378
|
-
</MenuContent>
|
|
379
|
-
</Menu>
|
|
380
|
-
);
|
|
381
|
-
}
|
|
382
|
-
}
|
|
58
|
+
```ts file="MenuWithDescription.tsx"
|
|
383
59
|
```
|
|
384
60
|
|
|
385
61
|
### With actions
|
|
386
62
|
|
|
387
|
-
```
|
|
388
|
-
import React from 'react';
|
|
389
|
-
import { Menu, MenuContent, MenuGroup, MenuList, MenuItem, MenuItemAction } from '@patternfly/react-core';
|
|
390
|
-
import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon';
|
|
391
|
-
import ClipboardIcon from '@patternfly/react-icons/dist/esm/icons/clipboard-icon';
|
|
392
|
-
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
393
|
-
import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
|
|
394
|
-
|
|
395
|
-
class MenuWithActions extends React.Component {
|
|
396
|
-
constructor(props) {
|
|
397
|
-
super(props);
|
|
398
|
-
this.state = {
|
|
399
|
-
activeItem: 0,
|
|
400
|
-
isActionMenuOpen: false,
|
|
401
|
-
selectedItems: [0, 2, 3]
|
|
402
|
-
};
|
|
403
|
-
|
|
404
|
-
this.onSelect = (event, itemId) => {
|
|
405
|
-
if (this.state.selectedItems.indexOf(itemId) !== -1) {
|
|
406
|
-
this.setState({
|
|
407
|
-
selectedItems: this.state.selectedItems.filter(id => id !== itemId)
|
|
408
|
-
});
|
|
409
|
-
} else {
|
|
410
|
-
this.setState({
|
|
411
|
-
selectedItems: [...this.state.selectedItems, itemId]
|
|
412
|
-
});
|
|
413
|
-
}
|
|
414
|
-
};
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
render() {
|
|
418
|
-
const { activeItem, selectedItems } = this.state;
|
|
419
|
-
|
|
420
|
-
return (
|
|
421
|
-
<Menu
|
|
422
|
-
onSelect={this.onSelect}
|
|
423
|
-
onActionClick={(event, itemId, actionId) => console.log(`clicked on ${itemId} - ${actionId}`)}
|
|
424
|
-
activeItemId={activeItem}
|
|
425
|
-
>
|
|
426
|
-
<MenuContent>
|
|
427
|
-
<MenuGroup label="Actions" labelHeadingLevel="h3">
|
|
428
|
-
<MenuList>
|
|
429
|
-
<MenuItem
|
|
430
|
-
isSelected={selectedItems.indexOf(0) !== -1}
|
|
431
|
-
actions={
|
|
432
|
-
<MenuItemAction
|
|
433
|
-
icon={<CodeBranchIcon aria-hidden />}
|
|
434
|
-
actionId="code"
|
|
435
|
-
onClick={() => console.log('clicked on code icon')}
|
|
436
|
-
aria-label="Code"
|
|
437
|
-
/>
|
|
438
|
-
}
|
|
439
|
-
description="This is a description"
|
|
440
|
-
itemId={0}
|
|
441
|
-
>
|
|
442
|
-
Item 1
|
|
443
|
-
</MenuItem>
|
|
444
|
-
<MenuItem
|
|
445
|
-
isDisabled
|
|
446
|
-
isSelected={selectedItems.indexOf(1) !== -1}
|
|
447
|
-
actions={<MenuItemAction icon={<BellIcon aria-hidden />} actionId="alert" aria-label="Alert" />}
|
|
448
|
-
description="This is a description"
|
|
449
|
-
itemId={1}
|
|
450
|
-
>
|
|
451
|
-
Item 2
|
|
452
|
-
</MenuItem>
|
|
453
|
-
<MenuItem
|
|
454
|
-
isSelected={selectedItems.indexOf(2) !== -1}
|
|
455
|
-
actions={<MenuItemAction icon={<ClipboardIcon aria-hidden />} actionId="copy" aria-label="Copy" />}
|
|
456
|
-
itemId={2}
|
|
457
|
-
>
|
|
458
|
-
Item 3
|
|
459
|
-
</MenuItem>
|
|
460
|
-
<MenuItem
|
|
461
|
-
isSelected={selectedItems.indexOf(3) !== -1}
|
|
462
|
-
actions={<MenuItemAction icon={<BarsIcon aria-hidden />} actionId="expand" aria-label="Expand" />}
|
|
463
|
-
description="This is a description"
|
|
464
|
-
itemId={3}
|
|
465
|
-
>
|
|
466
|
-
Item 4
|
|
467
|
-
</MenuItem>
|
|
468
|
-
</MenuList>
|
|
469
|
-
</MenuGroup>
|
|
470
|
-
</MenuContent>
|
|
471
|
-
</Menu>
|
|
472
|
-
);
|
|
473
|
-
}
|
|
474
|
-
}
|
|
63
|
+
```ts file="MenuWithActions.tsx"
|
|
475
64
|
```
|
|
476
65
|
|
|
477
66
|
### With favorites
|
|
478
67
|
|
|
479
|
-
```
|
|
480
|
-
import React from 'react';
|
|
481
|
-
import { Menu, MenuContent, MenuItem, MenuItemAction, MenuGroup, MenuList, Divider } from '@patternfly/react-core';
|
|
482
|
-
import BarsIcon from '@patternfly/react-icons/dist/esm/icons/bars-icon';
|
|
483
|
-
import ClipboardIcon from '@patternfly/react-icons/dist/esm/icons/clipboard-icon';
|
|
484
|
-
import BellIcon from '@patternfly/react-icons/dist/esm/icons/bell-icon';
|
|
485
|
-
|
|
486
|
-
class MenuWithFavorites extends React.Component {
|
|
487
|
-
constructor(props) {
|
|
488
|
-
super(props);
|
|
489
|
-
this.state = {
|
|
490
|
-
activeItem: 0,
|
|
491
|
-
favorites: []
|
|
492
|
-
};
|
|
493
|
-
|
|
494
|
-
this.onSelect = (event, itemId) => {
|
|
495
|
-
this.setState({
|
|
496
|
-
activeItem: itemId
|
|
497
|
-
});
|
|
498
|
-
};
|
|
499
|
-
this.onFavorite = (event, itemId, actionId) => {
|
|
500
|
-
console.log(`clicked ${itemId} - ${actionId}`);
|
|
501
|
-
if (actionId === 'fav') {
|
|
502
|
-
const isFavorite = this.state.favorites.includes(itemId);
|
|
503
|
-
if (isFavorite) {
|
|
504
|
-
this.setState({
|
|
505
|
-
favorites: this.state.favorites.filter(fav => fav !== itemId)
|
|
506
|
-
});
|
|
507
|
-
} else {
|
|
508
|
-
this.setState({
|
|
509
|
-
favorites: [...this.state.favorites, itemId]
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
}
|
|
513
|
-
};
|
|
514
|
-
}
|
|
515
|
-
|
|
516
|
-
render() {
|
|
517
|
-
const { activeItem, favorites } = this.state;
|
|
518
|
-
|
|
519
|
-
const items = [
|
|
520
|
-
{
|
|
521
|
-
text: 'Item 1',
|
|
522
|
-
description: 'Description 1',
|
|
523
|
-
itemId: 'item-1',
|
|
524
|
-
action: <BarsIcon aria-hidden />,
|
|
525
|
-
actionId: 'bars'
|
|
526
|
-
},
|
|
527
|
-
{
|
|
528
|
-
text: 'Item 2',
|
|
529
|
-
description: 'Description 2',
|
|
530
|
-
itemId: 'item-2',
|
|
531
|
-
action: <ClipboardIcon aria-hidden />,
|
|
532
|
-
actionId: 'clipboard'
|
|
533
|
-
},
|
|
534
|
-
{
|
|
535
|
-
text: 'Item 3',
|
|
536
|
-
description: 'Description 3',
|
|
537
|
-
itemId: 'item-3',
|
|
538
|
-
action: <BellIcon aria-hidden />,
|
|
539
|
-
actionId: 'bell'
|
|
540
|
-
}
|
|
541
|
-
];
|
|
542
|
-
|
|
543
|
-
return (
|
|
544
|
-
<Menu onSelect={this.onSelect} onActionClick={this.onFavorite} activeItemId={activeItem}>
|
|
545
|
-
<MenuContent>
|
|
546
|
-
{favorites.length > 0 && (
|
|
547
|
-
<React.Fragment>
|
|
548
|
-
<MenuGroup label="Favorites" labelHeadingLevel="h3">
|
|
549
|
-
<MenuList>
|
|
550
|
-
{items
|
|
551
|
-
// map the items into the favorites group that have been favorited
|
|
552
|
-
.filter(item => favorites.includes(item.itemId))
|
|
553
|
-
.map(item => {
|
|
554
|
-
const { text, description, itemId, action, actionId } = item;
|
|
555
|
-
return (
|
|
556
|
-
<MenuItem
|
|
557
|
-
key={`fav-${itemId}`}
|
|
558
|
-
isFavorited
|
|
559
|
-
description={description}
|
|
560
|
-
itemId={itemId}
|
|
561
|
-
actions={<MenuItemAction actionId={actionId} icon={action} aria-label={actionId} />}
|
|
562
|
-
>
|
|
563
|
-
{text}
|
|
564
|
-
</MenuItem>
|
|
565
|
-
);
|
|
566
|
-
})}
|
|
567
|
-
</MenuList>
|
|
568
|
-
</MenuGroup>
|
|
569
|
-
<Divider />
|
|
570
|
-
</React.Fragment>
|
|
571
|
-
)}
|
|
572
|
-
<MenuGroup label="All actions" labelHeadingLevel="h3">
|
|
573
|
-
<MenuList>
|
|
574
|
-
{items.map(item => {
|
|
575
|
-
const { text, description, itemId, action, actionId } = item;
|
|
576
|
-
const isFavorited = favorites.includes(item.itemId);
|
|
577
|
-
return (
|
|
578
|
-
<MenuItem
|
|
579
|
-
key={itemId}
|
|
580
|
-
isFavorited={isFavorited}
|
|
581
|
-
description={description}
|
|
582
|
-
itemId={itemId}
|
|
583
|
-
actions={<MenuItemAction actionId={actionId} icon={action} aria-label={actionId} />}
|
|
584
|
-
>
|
|
585
|
-
{text}
|
|
586
|
-
</MenuItem>
|
|
587
|
-
);
|
|
588
|
-
})}
|
|
589
|
-
</MenuList>
|
|
590
|
-
</MenuGroup>
|
|
591
|
-
</MenuContent>
|
|
592
|
-
</Menu>
|
|
593
|
-
);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
68
|
+
```ts file="MenuWithFavorites.tsx"
|
|
596
69
|
```
|
|
597
70
|
|
|
598
71
|
### Option single select
|
|
599
72
|
|
|
600
|
-
```
|
|
601
|
-
import React from 'react';
|
|
602
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
603
|
-
import TableIcon from '@patternfly/react-icons/dist/esm/icons/table-icon';
|
|
604
|
-
|
|
605
|
-
class MenuOptionSingleSelect extends React.Component {
|
|
606
|
-
constructor(props) {
|
|
607
|
-
super(props);
|
|
608
|
-
this.state = {
|
|
609
|
-
activeItem: 0,
|
|
610
|
-
selectedItem: 0
|
|
611
|
-
};
|
|
612
|
-
|
|
613
|
-
this.onSelect = (event, itemId) => {
|
|
614
|
-
this.setState({
|
|
615
|
-
activeItem: itemId,
|
|
616
|
-
selectedItem: itemId
|
|
617
|
-
});
|
|
618
|
-
};
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
render() {
|
|
622
|
-
const { activeItem, selectedItem } = this.state;
|
|
623
|
-
return (
|
|
624
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem} selected={selectedItem}>
|
|
625
|
-
<MenuContent>
|
|
626
|
-
<MenuList>
|
|
627
|
-
<MenuItem itemId={0}>Option 1</MenuItem>
|
|
628
|
-
<MenuItem itemId={1}>Option 2</MenuItem>
|
|
629
|
-
<MenuItem icon={<TableIcon aria-hidden />} itemId={2}>
|
|
630
|
-
Option 3
|
|
631
|
-
</MenuItem>
|
|
632
|
-
</MenuList>
|
|
633
|
-
</MenuContent>
|
|
634
|
-
</Menu>
|
|
635
|
-
);
|
|
636
|
-
}
|
|
637
|
-
}
|
|
73
|
+
```ts file="MenuOptionSingleSelect.tsx"
|
|
638
74
|
```
|
|
639
75
|
|
|
640
76
|
### Option multi select
|
|
641
77
|
|
|
642
|
-
```
|
|
643
|
-
import React from 'react';
|
|
644
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
645
|
-
import TableIcon from '@patternfly/react-icons/dist/esm/icons/table-icon';
|
|
646
|
-
|
|
647
|
-
class MenuOptionMultiSelect extends React.Component {
|
|
648
|
-
constructor(props) {
|
|
649
|
-
super(props);
|
|
650
|
-
this.state = {
|
|
651
|
-
activeItem: 0,
|
|
652
|
-
selectedItems: []
|
|
653
|
-
};
|
|
654
|
-
this.onSelect = (event, itemId) => {
|
|
655
|
-
if (this.state.selectedItems.indexOf(itemId) !== -1) {
|
|
656
|
-
this.setState({
|
|
657
|
-
selectedItems: this.state.selectedItems.filter(id => id !== itemId)
|
|
658
|
-
});
|
|
659
|
-
} else {
|
|
660
|
-
this.setState({
|
|
661
|
-
selectedItems: [...this.state.selectedItems, itemId]
|
|
662
|
-
});
|
|
663
|
-
}
|
|
664
|
-
};
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
render() {
|
|
668
|
-
const { activeItem, selectedItems } = this.state;
|
|
669
|
-
return (
|
|
670
|
-
<Menu onSelect={this.onSelect} activeItemId={activeItem} selected={selectedItems}>
|
|
671
|
-
<MenuContent>
|
|
672
|
-
<MenuList>
|
|
673
|
-
<MenuItem itemId={0}>Option 1</MenuItem>
|
|
674
|
-
<MenuItem itemId={1}>Option 2</MenuItem>
|
|
675
|
-
<MenuItem icon={<TableIcon aria-hidden />} itemId={2}>
|
|
676
|
-
Option 3
|
|
677
|
-
</MenuItem>
|
|
678
|
-
</MenuList>
|
|
679
|
-
</MenuContent>
|
|
680
|
-
</Menu>
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
}
|
|
78
|
+
```ts file="MenuOptionMultiSelect.tsx"
|
|
684
79
|
```
|
|
685
80
|
|
|
686
81
|
### With drilldown
|
|
687
82
|
|
|
688
|
-
```ts file="./
|
|
83
|
+
```ts file="./MenuWithDrilldown.tsx" isBeta
|
|
689
84
|
```
|
|
690
85
|
|
|
691
86
|
### With drilldown - initial drill in state
|
|
692
87
|
|
|
693
88
|
To render an initially drilled in menu, the `menuDrilledIn`, `drilldownPath`, and `activeMenu` states must be set to an initial state. The `menuHeights` state must also be set, defining the height of the root menu. The `setHeight` function passed into the `onGetMenuHeight` property must also account for updating heights, other than the root menu, as menus drill in and out of view.
|
|
694
89
|
|
|
695
|
-
```ts file="./
|
|
90
|
+
```ts file="./MenuWithDrilldownInitialState.tsx" isBeta
|
|
696
91
|
```
|
|
697
92
|
|
|
698
93
|
### With drilldown - submenu functions
|
|
699
94
|
|
|
700
|
-
```ts file="./
|
|
95
|
+
```ts file="./MenuWithDrilldownSubmenuFunctions.tsx" isBeta
|
|
701
96
|
```
|
|
702
97
|
|
|
703
98
|
### With drilldown breadcrumbs
|
|
704
99
|
|
|
705
|
-
```
|
|
706
|
-
import React from 'react';
|
|
707
|
-
import {
|
|
708
|
-
Menu,
|
|
709
|
-
MenuContent,
|
|
710
|
-
MenuList,
|
|
711
|
-
MenuItem,
|
|
712
|
-
Divider,
|
|
713
|
-
DrilldownMenu,
|
|
714
|
-
Breadcrumb,
|
|
715
|
-
BreadcrumbItem,
|
|
716
|
-
BreadcrumbHeading,
|
|
717
|
-
MenuBreadcrumb,
|
|
718
|
-
Dropdown,
|
|
719
|
-
DropdownItem,
|
|
720
|
-
BadgeToggle,
|
|
721
|
-
Checkbox
|
|
722
|
-
} from '@patternfly/react-core';
|
|
723
|
-
import StorageDomainIcon from '@patternfly/react-icons/dist/esm/icons/storage-domain-icon';
|
|
724
|
-
import CodeBranchIcon from '@patternfly/react-icons/dist/esm/icons/code-branch-icon';
|
|
725
|
-
import LayerGroupIcon from '@patternfly/react-icons/dist/esm/icons/layer-group-icon';
|
|
726
|
-
import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-icon';
|
|
727
|
-
import CubeIcon from '@patternfly/react-icons/dist/esm/icons/cube-icon';
|
|
728
|
-
|
|
729
|
-
class MenuWithDrilldownBreadcrumbs extends React.Component {
|
|
730
|
-
constructor(props) {
|
|
731
|
-
super(props);
|
|
732
|
-
this.state = {
|
|
733
|
-
menuDrilledIn: [],
|
|
734
|
-
drilldownPath: [],
|
|
735
|
-
menuHeights: {},
|
|
736
|
-
activeMenu: 'breadcrumbs-rootMenu',
|
|
737
|
-
breadcrumb: undefined,
|
|
738
|
-
withMaxMenuHeight: false
|
|
739
|
-
};
|
|
740
|
-
|
|
741
|
-
this.onToggle = (isOpen, key) => {
|
|
742
|
-
switch (key) {
|
|
743
|
-
case 'app':
|
|
744
|
-
this.setState({
|
|
745
|
-
breadcrumb: this.appGroupingBreadcrumb(isOpen)
|
|
746
|
-
});
|
|
747
|
-
break;
|
|
748
|
-
case 'label':
|
|
749
|
-
this.setState({
|
|
750
|
-
breadcrumb: this.labelsBreadcrumb(isOpen)
|
|
751
|
-
});
|
|
752
|
-
break;
|
|
753
|
-
default:
|
|
754
|
-
break;
|
|
755
|
-
}
|
|
756
|
-
};
|
|
757
|
-
|
|
758
|
-
this.onToggleMaxMenuHeight = checked => {
|
|
759
|
-
this.setState({
|
|
760
|
-
withMaxMenuHeight: checked
|
|
761
|
-
});
|
|
762
|
-
};
|
|
763
|
-
|
|
764
|
-
this.drillOut = (toMenuId, fromPathId, breadcrumb) => {
|
|
765
|
-
const indexOfMenuId = this.state.menuDrilledIn.indexOf(toMenuId);
|
|
766
|
-
const menuDrilledInSansLast = this.state.menuDrilledIn.slice(0, indexOfMenuId);
|
|
767
|
-
const indexOfMenuIdPath = this.state.drilldownPath.indexOf(fromPathId);
|
|
768
|
-
const pathSansLast = this.state.drilldownPath.slice(0, indexOfMenuIdPath);
|
|
769
|
-
this.setState({
|
|
770
|
-
menuDrilledIn: menuDrilledInSansLast,
|
|
771
|
-
drilldownPath: pathSansLast,
|
|
772
|
-
activeMenu: toMenuId,
|
|
773
|
-
breadcrumb
|
|
774
|
-
});
|
|
775
|
-
};
|
|
776
|
-
this.setHeight = (menuId, height) => {
|
|
777
|
-
if (!this.state.menuHeights[menuId]) {
|
|
778
|
-
this.setState({
|
|
779
|
-
menuHeights: {
|
|
780
|
-
...this.state.menuHeights,
|
|
781
|
-
[menuId]: height
|
|
782
|
-
}
|
|
783
|
-
});
|
|
784
|
-
}
|
|
785
|
-
};
|
|
786
|
-
this.drillIn = (fromMenuId, toMenuId, pathId) => {
|
|
787
|
-
this.setState({
|
|
788
|
-
menuDrilledIn: [...this.state.menuDrilledIn, fromMenuId],
|
|
789
|
-
drilldownPath: [...this.state.drilldownPath, pathId],
|
|
790
|
-
activeMenu: toMenuId
|
|
791
|
-
});
|
|
792
|
-
};
|
|
793
|
-
|
|
794
|
-
this.startRolloutBreadcrumb = (
|
|
795
|
-
<Breadcrumb>
|
|
796
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:start_rollout', null)}>
|
|
797
|
-
Root
|
|
798
|
-
</BreadcrumbItem>
|
|
799
|
-
<BreadcrumbHeading component="button">Start rollout</BreadcrumbHeading>
|
|
800
|
-
</Breadcrumb>
|
|
801
|
-
);
|
|
802
|
-
|
|
803
|
-
this.appGroupingBreadcrumb = isOpen => {
|
|
804
|
-
return (
|
|
805
|
-
<Breadcrumb>
|
|
806
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:start_rollout', null)}>
|
|
807
|
-
Root
|
|
808
|
-
</BreadcrumbItem>
|
|
809
|
-
<BreadcrumbItem isDropdown>
|
|
810
|
-
<Dropdown
|
|
811
|
-
toggle={
|
|
812
|
-
<BadgeToggle id="toggle-id" onToggle={open => this.onToggle(open, 'app')}>
|
|
813
|
-
1
|
|
814
|
-
</BadgeToggle>
|
|
815
|
-
}
|
|
816
|
-
isOpen={isOpen}
|
|
817
|
-
dropdownItems={[
|
|
818
|
-
<DropdownItem
|
|
819
|
-
key="dropdown-start"
|
|
820
|
-
component="button"
|
|
821
|
-
icon={<AngleLeftIcon />}
|
|
822
|
-
onClick={() =>
|
|
823
|
-
this.drillOut('breadcrumbs-drilldownMenuStart', 'group:app_grouping_start', this.startRolloutBreadcrumb)
|
|
824
|
-
}
|
|
825
|
-
>
|
|
826
|
-
Start rollout
|
|
827
|
-
</DropdownItem>
|
|
828
|
-
]}
|
|
829
|
-
/>
|
|
830
|
-
</BreadcrumbItem>
|
|
831
|
-
<BreadcrumbHeading component="button">Application Grouping</BreadcrumbHeading>
|
|
832
|
-
</Breadcrumb>
|
|
833
|
-
);
|
|
834
|
-
};
|
|
835
|
-
|
|
836
|
-
this.labelsBreadcrumb = isOpen => (
|
|
837
|
-
<Breadcrumb>
|
|
838
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:start_rollout', null)}>
|
|
839
|
-
Root
|
|
840
|
-
</BreadcrumbItem>
|
|
841
|
-
<BreadcrumbItem isDropdown>
|
|
842
|
-
<Dropdown
|
|
843
|
-
toggle={
|
|
844
|
-
<BadgeToggle id="toggle-id" onToggle={open => this.onToggle(open, 'label')}>
|
|
845
|
-
1
|
|
846
|
-
</BadgeToggle>
|
|
847
|
-
}
|
|
848
|
-
isOpen={isOpen}
|
|
849
|
-
dropdownItems={[
|
|
850
|
-
<DropdownItem
|
|
851
|
-
key="dropdown-start"
|
|
852
|
-
component="button"
|
|
853
|
-
icon={<AngleLeftIcon />}
|
|
854
|
-
onClick={() => this.drillOut('breadcrumbs-drilldownMenuStart', 'group:labels_start', this.startRolloutBreadcrumb)}
|
|
855
|
-
>
|
|
856
|
-
Start rollout
|
|
857
|
-
</DropdownItem>
|
|
858
|
-
]}
|
|
859
|
-
/>
|
|
860
|
-
</BreadcrumbItem>
|
|
861
|
-
<BreadcrumbHeading component="button">Labels</BreadcrumbHeading>
|
|
862
|
-
</Breadcrumb>
|
|
863
|
-
);
|
|
864
|
-
|
|
865
|
-
this.pauseRolloutsBreadcrumb = (
|
|
866
|
-
<Breadcrumb>
|
|
867
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:pause_rollout', null)}>
|
|
868
|
-
Root
|
|
869
|
-
</BreadcrumbItem>
|
|
870
|
-
<BreadcrumbHeading component="button">Pause rollouts</BreadcrumbHeading>
|
|
871
|
-
</Breadcrumb>
|
|
872
|
-
);
|
|
873
|
-
|
|
874
|
-
this.pauseRolloutsAppGrpBreadcrumb = (
|
|
875
|
-
<Breadcrumb>
|
|
876
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:pause_rollout', null)}>
|
|
877
|
-
Root
|
|
878
|
-
</BreadcrumbItem>
|
|
879
|
-
<BreadcrumbItem
|
|
880
|
-
component="button"
|
|
881
|
-
onClick={() => this.drillOut('breadcrumbs-drilldownMenuPause', 'group:app_grouping', this.pauseRolloutsBreadcrumb)}
|
|
882
|
-
>
|
|
883
|
-
Pause rollouts
|
|
884
|
-
</BreadcrumbItem>
|
|
885
|
-
<BreadcrumbHeading component="button">Application Grouping</BreadcrumbHeading>
|
|
886
|
-
</Breadcrumb>
|
|
887
|
-
);
|
|
888
|
-
|
|
889
|
-
this.pauseRolloutsLabelsBreadcrumb = (
|
|
890
|
-
<Breadcrumb>
|
|
891
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:pause_rollout', null)}>
|
|
892
|
-
Root
|
|
893
|
-
</BreadcrumbItem>
|
|
894
|
-
<BreadcrumbItem
|
|
895
|
-
component="button"
|
|
896
|
-
onClick={() => this.drillOut('breadcrumbs-drilldownMenuPause', 'group:labels', this.pauseRolloutsBreadcrumb)}
|
|
897
|
-
>
|
|
898
|
-
Pause rollouts
|
|
899
|
-
</BreadcrumbItem>
|
|
900
|
-
<BreadcrumbHeading component="button">Labels</BreadcrumbHeading>
|
|
901
|
-
</Breadcrumb>
|
|
902
|
-
);
|
|
903
|
-
|
|
904
|
-
this.addStorageBreadcrumb = (
|
|
905
|
-
<Breadcrumb>
|
|
906
|
-
<BreadcrumbItem component="button" onClick={() => this.drillOut('breadcrumbs-rootMenu', 'group:storage', null)}>
|
|
907
|
-
Root
|
|
908
|
-
</BreadcrumbItem>
|
|
909
|
-
<BreadcrumbHeading component="button">Add storage</BreadcrumbHeading>
|
|
910
|
-
</Breadcrumb>
|
|
911
|
-
);
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
render() {
|
|
915
|
-
const { menuDrilledIn, drilldownPath, activeMenu, menuHeights, breadcrumb, withMaxMenuHeight } = this.state;
|
|
916
|
-
|
|
917
|
-
return (
|
|
918
|
-
<>
|
|
919
|
-
<Checkbox
|
|
920
|
-
label="Set max menu height"
|
|
921
|
-
isChecked={withMaxMenuHeight}
|
|
922
|
-
onChange={this.onToggleMaxMenuHeight}
|
|
923
|
-
aria-label="Set max menu height checkbox"
|
|
924
|
-
id="toggle-max-menu-height"
|
|
925
|
-
name="toggle-max-menu-height"
|
|
926
|
-
/>
|
|
927
|
-
<br />
|
|
928
|
-
<Menu
|
|
929
|
-
id="breadcrumbs-rootMenu"
|
|
930
|
-
containsDrilldown
|
|
931
|
-
drilldownItemPath={drilldownPath}
|
|
932
|
-
drilledInMenus={menuDrilledIn}
|
|
933
|
-
activeMenu={activeMenu}
|
|
934
|
-
onDrillIn={this.drillIn}
|
|
935
|
-
onDrillOut={this.drillOut}
|
|
936
|
-
onGetMenuHeight={this.setHeight}
|
|
937
|
-
>
|
|
938
|
-
{breadcrumb && (
|
|
939
|
-
<>
|
|
940
|
-
<MenuBreadcrumb>{breadcrumb}</MenuBreadcrumb>
|
|
941
|
-
<Divider component="li" />
|
|
942
|
-
</>
|
|
943
|
-
)}
|
|
944
|
-
<MenuContent menuHeight={`${menuHeights[activeMenu]}px`} maxMenuHeight={withMaxMenuHeight ? '100px' : 'auto'}>
|
|
945
|
-
<MenuList>
|
|
946
|
-
<MenuItem
|
|
947
|
-
itemId="group:start_rollout"
|
|
948
|
-
direction="down"
|
|
949
|
-
onClick={() => this.setState({ breadcrumb: this.startRolloutBreadcrumb })}
|
|
950
|
-
drilldownMenu={
|
|
951
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuStart">
|
|
952
|
-
<MenuItem
|
|
953
|
-
itemId="group:app_grouping_start"
|
|
954
|
-
description="Groups A-G"
|
|
955
|
-
direction="down"
|
|
956
|
-
onClick={() => this.setState({ breadcrumb: this.appGroupingBreadcrumb(false) })}
|
|
957
|
-
drilldownMenu={
|
|
958
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuStartGrouping">
|
|
959
|
-
<MenuItem itemId="group_a">Group A</MenuItem>
|
|
960
|
-
<MenuItem itemId="group_b">Group B</MenuItem>
|
|
961
|
-
<MenuItem itemId="group_c">Group C</MenuItem>
|
|
962
|
-
<MenuItem itemId="group_d">Group D</MenuItem>
|
|
963
|
-
<MenuItem itemId="group_e">Group E</MenuItem>
|
|
964
|
-
<MenuItem itemId="group_f">Group F</MenuItem>
|
|
965
|
-
<MenuItem itemId="group_g">Group G</MenuItem>
|
|
966
|
-
</DrilldownMenu>
|
|
967
|
-
}
|
|
968
|
-
>
|
|
969
|
-
Application grouping
|
|
970
|
-
</MenuItem>
|
|
971
|
-
<MenuItem itemId="count">Count</MenuItem>
|
|
972
|
-
<MenuItem
|
|
973
|
-
itemId="group:labels_start"
|
|
974
|
-
direction="down"
|
|
975
|
-
onClick={() => this.setState({ breadcrumb: this.labelsBreadcrumb(false) })}
|
|
976
|
-
drilldownMenu={
|
|
977
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuStartLabels">
|
|
978
|
-
<MenuItem itemId="label_1">Label 1</MenuItem>
|
|
979
|
-
<MenuItem itemId="label_2">Label 2</MenuItem>
|
|
980
|
-
<MenuItem itemId="label_3">Label 3</MenuItem>
|
|
981
|
-
</DrilldownMenu>
|
|
982
|
-
}
|
|
983
|
-
>
|
|
984
|
-
Labels
|
|
985
|
-
</MenuItem>
|
|
986
|
-
<MenuItem itemId="annotations">Annotations</MenuItem>
|
|
987
|
-
</DrilldownMenu>
|
|
988
|
-
}
|
|
989
|
-
>
|
|
990
|
-
Start rollout
|
|
991
|
-
</MenuItem>
|
|
992
|
-
<MenuItem
|
|
993
|
-
itemId="group:pause_rollout"
|
|
994
|
-
direction="down"
|
|
995
|
-
onClick={() => this.setState({ breadcrumb: this.pauseRolloutsBreadcrumb })}
|
|
996
|
-
drilldownMenu={
|
|
997
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuPause">
|
|
998
|
-
<MenuItem
|
|
999
|
-
itemId="group:app_grouping"
|
|
1000
|
-
description="Groups A-C"
|
|
1001
|
-
direction="down"
|
|
1002
|
-
onClick={() => this.setState({ breadcrumb: this.pauseRolloutsAppGrpBreadcrumb })}
|
|
1003
|
-
drilldownMenu={
|
|
1004
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuGrouping">
|
|
1005
|
-
<MenuItem itemId="group_a">Group A</MenuItem>
|
|
1006
|
-
<MenuItem itemId="group_b">Group B</MenuItem>
|
|
1007
|
-
<MenuItem itemId="group_c">Group C</MenuItem>
|
|
1008
|
-
</DrilldownMenu>
|
|
1009
|
-
}
|
|
1010
|
-
>
|
|
1011
|
-
Application grouping
|
|
1012
|
-
</MenuItem>
|
|
1013
|
-
<MenuItem itemId="count">Count</MenuItem>
|
|
1014
|
-
<MenuItem
|
|
1015
|
-
itemId="group:labels"
|
|
1016
|
-
direction="down"
|
|
1017
|
-
onClick={() => this.setState({ breadcrumb: this.pauseRolloutsLabelsBreadcrumb })}
|
|
1018
|
-
drilldownMenu={
|
|
1019
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuLabels">
|
|
1020
|
-
<MenuItem itemId="label_1">Label 1</MenuItem>
|
|
1021
|
-
<MenuItem itemId="label_2">Label 2</MenuItem>
|
|
1022
|
-
<MenuItem itemId="label_3">Label 3</MenuItem>
|
|
1023
|
-
</DrilldownMenu>
|
|
1024
|
-
}
|
|
1025
|
-
>
|
|
1026
|
-
Labels
|
|
1027
|
-
</MenuItem>
|
|
1028
|
-
<MenuItem itemId="annotations">Annotations</MenuItem>
|
|
1029
|
-
</DrilldownMenu>
|
|
1030
|
-
}
|
|
1031
|
-
>
|
|
1032
|
-
Pause rollouts
|
|
1033
|
-
</MenuItem>
|
|
1034
|
-
<MenuItem
|
|
1035
|
-
itemId="group:storage"
|
|
1036
|
-
icon={<StorageDomainIcon aria-hidden />}
|
|
1037
|
-
direction="down"
|
|
1038
|
-
onClick={() => this.setState({ breadcrumb: this.addStorageBreadcrumb })}
|
|
1039
|
-
drilldownMenu={
|
|
1040
|
-
<DrilldownMenu id="breadcrumbs-drilldownMenuStorage">
|
|
1041
|
-
<MenuItem icon={<CodeBranchIcon aria-hidden />} itemId="git">
|
|
1042
|
-
From git
|
|
1043
|
-
</MenuItem>
|
|
1044
|
-
<MenuItem icon={<LayerGroupIcon aria-hidden />} itemId="container">
|
|
1045
|
-
Container image
|
|
1046
|
-
</MenuItem>
|
|
1047
|
-
<MenuItem icon={<CubeIcon aria-hidden />} itemId="docker">
|
|
1048
|
-
Docker file
|
|
1049
|
-
</MenuItem>
|
|
1050
|
-
</DrilldownMenu>
|
|
1051
|
-
}
|
|
1052
|
-
>
|
|
1053
|
-
Add storage
|
|
1054
|
-
</MenuItem>
|
|
1055
|
-
<MenuItem itemId="edit">Edit</MenuItem>
|
|
1056
|
-
<MenuItem itemId="delete_deployment">Delete deployment config</MenuItem>
|
|
1057
|
-
</MenuList>
|
|
1058
|
-
</MenuContent>
|
|
1059
|
-
</Menu>
|
|
1060
|
-
</>
|
|
1061
|
-
);
|
|
1062
|
-
}
|
|
1063
|
-
}
|
|
100
|
+
```ts file="MenuWithDrilldownBreadcrumbs.tsx" isBeta
|
|
1064
101
|
```
|
|
1065
102
|
|
|
1066
103
|
### Scrollable
|
|
1067
104
|
|
|
1068
|
-
```
|
|
1069
|
-
import React from 'react';
|
|
1070
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
1071
|
-
|
|
1072
|
-
class MenuBasicList extends React.Component {
|
|
1073
|
-
constructor(props) {
|
|
1074
|
-
super(props);
|
|
1075
|
-
this.state = {
|
|
1076
|
-
activeItem: 0
|
|
1077
|
-
};
|
|
1078
|
-
this.onSelect = (event, itemId) => {
|
|
1079
|
-
console.log(`clicked ${itemId}`);
|
|
1080
|
-
this.setState({
|
|
1081
|
-
activeItem: itemId
|
|
1082
|
-
});
|
|
1083
|
-
};
|
|
1084
|
-
}
|
|
1085
|
-
|
|
1086
|
-
render() {
|
|
1087
|
-
const { activeItem } = this.state;
|
|
1088
|
-
return (
|
|
1089
|
-
<Menu activeItemId={activeItem} onSelect={this.onSelect} isScrollable>
|
|
1090
|
-
<MenuContent>
|
|
1091
|
-
<MenuList>
|
|
1092
|
-
<MenuItem>Action 1</MenuItem>
|
|
1093
|
-
<MenuItem>Action 2</MenuItem>
|
|
1094
|
-
<MenuItem>Action 3</MenuItem>
|
|
1095
|
-
<MenuItem>Action 4</MenuItem>
|
|
1096
|
-
<MenuItem>Action 5</MenuItem>
|
|
1097
|
-
<MenuItem>Action 6</MenuItem>
|
|
1098
|
-
<MenuItem>Action 7</MenuItem>
|
|
1099
|
-
<MenuItem>Action 8</MenuItem>
|
|
1100
|
-
<MenuItem>Action 9</MenuItem>
|
|
1101
|
-
<MenuItem>Action 10</MenuItem>
|
|
1102
|
-
<MenuItem>Action 11</MenuItem>
|
|
1103
|
-
<MenuItem>Action 12</MenuItem>
|
|
1104
|
-
<MenuItem>Action 13</MenuItem>
|
|
1105
|
-
<MenuItem>Action 14</MenuItem>
|
|
1106
|
-
<MenuItem>Action 15</MenuItem>
|
|
1107
|
-
<MenuItem
|
|
1108
|
-
itemId={1}
|
|
1109
|
-
to="#default-link2"
|
|
1110
|
-
// just for demo so that navigation is not triggered
|
|
1111
|
-
onClick={event => event.preventDefault()}
|
|
1112
|
-
>
|
|
1113
|
-
Link
|
|
1114
|
-
</MenuItem>
|
|
1115
|
-
<MenuItem isDisabled>Disabled action</MenuItem>
|
|
1116
|
-
<MenuItem isDisabled to="#default-link4">
|
|
1117
|
-
Disabled link
|
|
1118
|
-
</MenuItem>
|
|
1119
|
-
</MenuList>
|
|
1120
|
-
</MenuContent>
|
|
1121
|
-
</Menu>
|
|
1122
|
-
);
|
|
1123
|
-
}
|
|
1124
|
-
}
|
|
105
|
+
```ts file="MenuScrollable.tsx"
|
|
1125
106
|
```
|
|
1126
107
|
|
|
1127
108
|
### Scrollable with custom menu height
|
|
1128
109
|
|
|
1129
|
-
```
|
|
1130
|
-
import React from 'react';
|
|
1131
|
-
import { Menu, MenuContent, MenuList, MenuItem } from '@patternfly/react-core';
|
|
1132
|
-
|
|
1133
|
-
class MenuBasicList extends React.Component {
|
|
1134
|
-
constructor(props) {
|
|
1135
|
-
super(props);
|
|
1136
|
-
this.state = {
|
|
1137
|
-
activeItem: 0
|
|
1138
|
-
};
|
|
1139
|
-
this.onSelect = (event, itemId) => {
|
|
1140
|
-
console.log(`clicked ${itemId}`);
|
|
1141
|
-
this.setState({
|
|
1142
|
-
activeItem: itemId
|
|
1143
|
-
});
|
|
1144
|
-
};
|
|
1145
|
-
}
|
|
1146
|
-
|
|
1147
|
-
render() {
|
|
1148
|
-
const { activeItem } = this.state;
|
|
1149
|
-
return (
|
|
1150
|
-
<Menu activeItemId={activeItem} onSelect={this.onSelect} isScrollable>
|
|
1151
|
-
<MenuContent menuHeight="200px">
|
|
1152
|
-
<MenuList>
|
|
1153
|
-
<MenuItem>Action 1</MenuItem>
|
|
1154
|
-
<MenuItem>Action 2</MenuItem>
|
|
1155
|
-
<MenuItem>Action 3</MenuItem>
|
|
1156
|
-
<MenuItem>Action 4</MenuItem>
|
|
1157
|
-
<MenuItem>Action 5</MenuItem>
|
|
1158
|
-
<MenuItem>Action 6</MenuItem>
|
|
1159
|
-
<MenuItem>Action 7</MenuItem>
|
|
1160
|
-
<MenuItem>Action 8</MenuItem>
|
|
1161
|
-
<MenuItem>Action 9</MenuItem>
|
|
1162
|
-
<MenuItem>Action 10</MenuItem>
|
|
1163
|
-
<MenuItem>Action 11</MenuItem>
|
|
1164
|
-
<MenuItem>Action 12</MenuItem>
|
|
1165
|
-
<MenuItem>Action 13</MenuItem>
|
|
1166
|
-
<MenuItem>Action 14</MenuItem>
|
|
1167
|
-
<MenuItem>Action 15</MenuItem>
|
|
1168
|
-
<MenuItem
|
|
1169
|
-
itemId={1}
|
|
1170
|
-
to="#default-link2"
|
|
1171
|
-
// just for demo so that navigation is not triggered
|
|
1172
|
-
onClick={event => event.preventDefault()}
|
|
1173
|
-
>
|
|
1174
|
-
Link
|
|
1175
|
-
</MenuItem>
|
|
1176
|
-
<MenuItem isDisabled>Disabled action</MenuItem>
|
|
1177
|
-
<MenuItem isDisabled to="#default-link4">
|
|
1178
|
-
Disabled link
|
|
1179
|
-
</MenuItem>
|
|
1180
|
-
</MenuList>
|
|
1181
|
-
</MenuContent>
|
|
1182
|
-
</Menu>
|
|
1183
|
-
);
|
|
1184
|
-
}
|
|
1185
|
-
}
|
|
110
|
+
```ts file="MenuScrollableCustomMenuHeight.tsx"
|
|
1186
111
|
```
|
|
1187
112
|
|
|
1188
113
|
### With footer
|
|
1189
114
|
|
|
1190
|
-
```
|
|
1191
|
-
import React from 'react';
|
|
1192
|
-
import { Menu, MenuList, MenuItem, MenuContent, MenuFooter, Button } from '@patternfly/react-core';
|
|
1193
|
-
|
|
1194
|
-
class FooterMenu extends React.Component {
|
|
1195
|
-
constructor(props) {
|
|
1196
|
-
super(props);
|
|
1197
|
-
this.state = {
|
|
1198
|
-
activeItem: 0
|
|
1199
|
-
};
|
|
1200
|
-
this.onSelect = (event, itemId) => {
|
|
1201
|
-
console.log(`clicked ${itemId}`);
|
|
1202
|
-
this.setState({
|
|
1203
|
-
activeItem: itemId
|
|
1204
|
-
});
|
|
1205
|
-
};
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
render() {
|
|
1209
|
-
const { activeItem } = this.state;
|
|
1210
|
-
return (
|
|
1211
|
-
<Menu activeItemId={activeItem} onSelect={this.onSelect}>
|
|
1212
|
-
<MenuContent>
|
|
1213
|
-
<MenuList>
|
|
1214
|
-
<MenuItem itemId={0}>Action</MenuItem>
|
|
1215
|
-
<MenuItem
|
|
1216
|
-
itemId={1}
|
|
1217
|
-
to="#default-link2"
|
|
1218
|
-
// just for demo so that navigation is not triggered
|
|
1219
|
-
onClick={event => event.preventDefault()}
|
|
1220
|
-
>
|
|
1221
|
-
Link
|
|
1222
|
-
</MenuItem>
|
|
1223
|
-
<MenuItem isDisabled>Disabled action</MenuItem>
|
|
1224
|
-
<MenuItem isDisabled to="#default-link4">
|
|
1225
|
-
Disabled link
|
|
1226
|
-
</MenuItem>
|
|
1227
|
-
</MenuList>
|
|
1228
|
-
</MenuContent>
|
|
1229
|
-
<MenuFooter>
|
|
1230
|
-
<Button variant="link" isInline>
|
|
1231
|
-
Action
|
|
1232
|
-
</Button>
|
|
1233
|
-
</MenuFooter>
|
|
1234
|
-
</Menu>
|
|
1235
|
-
);
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
115
|
+
```ts file="MenuWithFooter.tsx"
|
|
1238
116
|
```
|
|
1239
117
|
|
|
1240
118
|
### With view more
|
|
1241
119
|
|
|
1242
|
-
```
|
|
1243
|
-
import React from 'react';
|
|
1244
|
-
import { Menu, MenuList, MenuItem, MenuContent, MenuFooter, Spinner } from '@patternfly/react-core';
|
|
1245
|
-
|
|
1246
|
-
class ViewMoreMenu extends React.Component {
|
|
1247
|
-
constructor(props) {
|
|
1248
|
-
super(props);
|
|
1249
|
-
this.state = {
|
|
1250
|
-
activeItem: 0,
|
|
1251
|
-
isLoading: false,
|
|
1252
|
-
numOptions: 3
|
|
1253
|
-
};
|
|
1254
|
-
this.activeItemRef = React.createRef();
|
|
1255
|
-
this.viewMoreRef = React.createRef();
|
|
1256
|
-
|
|
1257
|
-
this.menuOptions = [
|
|
1258
|
-
<MenuItem key={0} itemId={'view-more-0'}>
|
|
1259
|
-
Action
|
|
1260
|
-
</MenuItem>,
|
|
1261
|
-
<MenuItem
|
|
1262
|
-
key={1}
|
|
1263
|
-
itemId={'view-more-1'}
|
|
1264
|
-
to="#default-link2"
|
|
1265
|
-
// just for demo so that navigation is not triggered
|
|
1266
|
-
onClick={event => event.preventDefault()}
|
|
1267
|
-
>
|
|
1268
|
-
Link
|
|
1269
|
-
</MenuItem>,
|
|
1270
|
-
<MenuItem key={2} itemId="view-more-2" isDisabled>
|
|
1271
|
-
Disabled action
|
|
1272
|
-
</MenuItem>,
|
|
1273
|
-
<MenuItem key={3} itemId="view-more-3" isDisabled to="#default-link4">
|
|
1274
|
-
Disabled link
|
|
1275
|
-
</MenuItem>,
|
|
1276
|
-
<MenuItem key={4} itemId="view-more-4" ref={this.activeItemRef}>
|
|
1277
|
-
Action 2
|
|
1278
|
-
</MenuItem>,
|
|
1279
|
-
<MenuItem key={5} itemId="view-more-5">
|
|
1280
|
-
Action 3
|
|
1281
|
-
</MenuItem>,
|
|
1282
|
-
<MenuItem key={6} itemId="view-more-6">
|
|
1283
|
-
Action 4
|
|
1284
|
-
</MenuItem>,
|
|
1285
|
-
<MenuItem key={7} itemId="view-more-7">
|
|
1286
|
-
Action 5
|
|
1287
|
-
</MenuItem>,
|
|
1288
|
-
<MenuItem key={8} itemId="view-more-8">
|
|
1289
|
-
Final option
|
|
1290
|
-
</MenuItem>
|
|
1291
|
-
];
|
|
1292
|
-
|
|
1293
|
-
this.onSelect = (event, itemId) => {
|
|
1294
|
-
console.log(`clicked ${itemId}`);
|
|
1295
|
-
this.setState({
|
|
1296
|
-
activeItem: itemId
|
|
1297
|
-
});
|
|
1298
|
-
};
|
|
1299
|
-
|
|
1300
|
-
this.simulateNetworkCall = networkCallback => {
|
|
1301
|
-
setTimeout(networkCallback, 2000);
|
|
1302
|
-
};
|
|
1303
|
-
|
|
1304
|
-
this.getNextValidItem = (startingIndex, maxLength) => {
|
|
1305
|
-
let validItem;
|
|
1306
|
-
for (let i = startingIndex; i < maxLength; i++) {
|
|
1307
|
-
if (this.menuOptions[i].props.isDisabled) {
|
|
1308
|
-
continue;
|
|
1309
|
-
} else {
|
|
1310
|
-
validItem = this.menuOptions[i];
|
|
1311
|
-
break;
|
|
1312
|
-
}
|
|
1313
|
-
}
|
|
1314
|
-
return validItem;
|
|
1315
|
-
};
|
|
1316
|
-
|
|
1317
|
-
this.loadMoreOptions = stateCallback => {
|
|
1318
|
-
const newLength =
|
|
1319
|
-
this.state.numOptions + 3 <= this.menuOptions.length ? this.state.numOptions + 3 : this.menuOptions.length;
|
|
1320
|
-
const prevPosition = this.state.numOptions;
|
|
1321
|
-
const nextValidItem = this.getNextValidItem(prevPosition, newLength);
|
|
1322
|
-
|
|
1323
|
-
this.setState({ numOptions: newLength, isLoading: false, activeItem: nextValidItem.props.itemId }, stateCallback);
|
|
1324
|
-
};
|
|
1325
|
-
|
|
1326
|
-
this.onViewMoreClick = event => {
|
|
1327
|
-
this.setState({ isLoading: true });
|
|
1328
|
-
this.simulateNetworkCall(() => {
|
|
1329
|
-
this.loadMoreOptions(() => {
|
|
1330
|
-
this.activeItemRef.current.focus();
|
|
1331
|
-
});
|
|
1332
|
-
});
|
|
1333
|
-
};
|
|
1334
|
-
|
|
1335
|
-
this.onViewMoreKeyDown = event => {
|
|
1336
|
-
if (!(event.key === ' ' || event.key === 'Enter')) {
|
|
1337
|
-
return;
|
|
1338
|
-
}
|
|
1339
|
-
event.stopPropagation();
|
|
1340
|
-
event.preventDefault();
|
|
1341
|
-
|
|
1342
|
-
this.setState({ isLoading: true });
|
|
1343
|
-
this.simulateNetworkCall(() => {
|
|
1344
|
-
this.loadMoreOptions(() => {
|
|
1345
|
-
if (this.viewMoreRef.current) {
|
|
1346
|
-
this.viewMoreRef.current.tabIndex = -1;
|
|
1347
|
-
}
|
|
1348
|
-
const firstMenuItem = this.activeItemRef.current.closest('ul').firstChild;
|
|
1349
|
-
firstMenuItem.querySelector('button, a').tabIndex = -1;
|
|
1350
|
-
this.activeItemRef.current.tabIndex = 0;
|
|
1351
|
-
this.activeItemRef.current.focus();
|
|
1352
|
-
});
|
|
1353
|
-
});
|
|
1354
|
-
};
|
|
1355
|
-
}
|
|
1356
|
-
|
|
1357
|
-
render() {
|
|
1358
|
-
const { activeItem, isLoading, numOptions } = this.state;
|
|
1359
|
-
return (
|
|
1360
|
-
<Menu activeItemId={activeItem} onSelect={this.onSelect}>
|
|
1361
|
-
<MenuContent>
|
|
1362
|
-
<MenuList>
|
|
1363
|
-
{this.menuOptions.slice(0, numOptions).map(option => {
|
|
1364
|
-
const props = option.props;
|
|
1365
|
-
|
|
1366
|
-
return (
|
|
1367
|
-
<MenuItem
|
|
1368
|
-
key={option.key}
|
|
1369
|
-
{...props}
|
|
1370
|
-
ref={props.itemId === this.state.activeItem ? this.activeItemRef : null}
|
|
1371
|
-
/>
|
|
1372
|
-
);
|
|
1373
|
-
})}
|
|
1374
|
-
{numOptions !== this.menuOptions.length && (
|
|
1375
|
-
<MenuItem
|
|
1376
|
-
{...(!isLoading && { isLoadButton: true })}
|
|
1377
|
-
{...(isLoading && { isLoading: true })}
|
|
1378
|
-
onKeyDown={this.onViewMoreKeyDown}
|
|
1379
|
-
onClick={this.onViewMoreClick}
|
|
1380
|
-
itemId="loader"
|
|
1381
|
-
ref={this.viewMoreRef}
|
|
1382
|
-
>
|
|
1383
|
-
{isLoading ? <Spinner size="lg" /> : 'View more'}
|
|
1384
|
-
</MenuItem>
|
|
1385
|
-
)}
|
|
1386
|
-
</MenuList>
|
|
1387
|
-
</MenuContent>
|
|
1388
|
-
</Menu>
|
|
1389
|
-
);
|
|
1390
|
-
}
|
|
1391
|
-
}
|
|
120
|
+
```ts file="MenuWithViewMore.tsx"
|
|
1392
121
|
```
|