@patternfly/react-core 4.276.0 → 4.276.2
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 +20 -0
- package/components/ExpandableSection/ExpandableSection.d.ts +7 -0
- package/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
- package/components/ExpandableSection/ExpandableSection.js +39 -4
- package/components/ExpandableSection/ExpandableSection.js.map +1 -1
- package/components/Menu/Menu.d.ts +3 -0
- package/components/Menu/Menu.d.ts.map +1 -1
- package/components/Menu/Menu.js +6 -4
- package/components/Menu/Menu.js.map +1 -1
- package/components/Menu/MenuContext.d.ts +1 -0
- package/components/Menu/MenuContext.d.ts.map +1 -1
- package/components/Menu/MenuContext.js +2 -1
- package/components/Menu/MenuContext.js.map +1 -1
- package/components/Menu/MenuItem.d.ts.map +1 -1
- package/components/Menu/MenuItem.js +3 -2
- package/components/Menu/MenuItem.js.map +1 -1
- package/components/Menu/MenuList.d.ts +4 -0
- package/components/Menu/MenuList.d.ts.map +1 -1
- package/components/Menu/MenuList.js +4 -2
- package/components/Menu/MenuList.js.map +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts +7 -0
- package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSection.js +39 -4
- package/dist/esm/components/ExpandableSection/ExpandableSection.js.map +1 -1
- package/dist/esm/components/Menu/Menu.d.ts +3 -0
- package/dist/esm/components/Menu/Menu.d.ts.map +1 -1
- package/dist/esm/components/Menu/Menu.js +6 -4
- package/dist/esm/components/Menu/Menu.js.map +1 -1
- package/dist/esm/components/Menu/MenuContext.d.ts +1 -0
- package/dist/esm/components/Menu/MenuContext.d.ts.map +1 -1
- package/dist/esm/components/Menu/MenuContext.js +2 -1
- package/dist/esm/components/Menu/MenuContext.js.map +1 -1
- package/dist/esm/components/Menu/MenuItem.d.ts.map +1 -1
- package/dist/esm/components/Menu/MenuItem.js +3 -2
- package/dist/esm/components/Menu/MenuItem.js.map +1 -1
- package/dist/esm/components/Menu/MenuList.d.ts +4 -0
- package/dist/esm/components/Menu/MenuList.d.ts.map +1 -1
- package/dist/esm/components/Menu/MenuList.js +4 -2
- package/dist/esm/components/Menu/MenuList.js.map +1 -1
- package/dist/esm/next/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/esm/next/components/Dropdown/Dropdown.js +19 -20
- package/dist/esm/next/components/Dropdown/Dropdown.js.map +1 -1
- package/dist/esm/next/components/Select/Select.d.ts +2 -0
- package/dist/esm/next/components/Select/Select.d.ts.map +1 -1
- package/dist/esm/next/components/Select/Select.js +21 -23
- package/dist/esm/next/components/Select/Select.js.map +1 -1
- package/dist/esm/next/components/Select/SelectList.d.ts +4 -0
- package/dist/esm/next/components/Select/SelectList.d.ts.map +1 -1
- package/dist/esm/next/components/Select/SelectList.js +2 -2
- package/dist/esm/next/components/Select/SelectList.js.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSection.d.ts +7 -0
- package/dist/js/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSection.js +39 -4
- package/dist/js/components/ExpandableSection/ExpandableSection.js.map +1 -1
- package/dist/js/components/Menu/Menu.d.ts +3 -0
- package/dist/js/components/Menu/Menu.d.ts.map +1 -1
- package/dist/js/components/Menu/Menu.js +6 -4
- package/dist/js/components/Menu/Menu.js.map +1 -1
- package/dist/js/components/Menu/MenuContext.d.ts +1 -0
- package/dist/js/components/Menu/MenuContext.d.ts.map +1 -1
- package/dist/js/components/Menu/MenuContext.js +2 -1
- package/dist/js/components/Menu/MenuContext.js.map +1 -1
- package/dist/js/components/Menu/MenuItem.d.ts.map +1 -1
- package/dist/js/components/Menu/MenuItem.js +3 -2
- package/dist/js/components/Menu/MenuItem.js.map +1 -1
- package/dist/js/components/Menu/MenuList.d.ts +4 -0
- package/dist/js/components/Menu/MenuList.d.ts.map +1 -1
- package/dist/js/components/Menu/MenuList.js +4 -2
- package/dist/js/components/Menu/MenuList.js.map +1 -1
- package/dist/js/next/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/dist/js/next/components/Dropdown/Dropdown.js +19 -20
- package/dist/js/next/components/Dropdown/Dropdown.js.map +1 -1
- package/dist/js/next/components/Select/Select.d.ts +2 -0
- package/dist/js/next/components/Select/Select.d.ts.map +1 -1
- package/dist/js/next/components/Select/Select.js +21 -23
- package/dist/js/next/components/Select/Select.js.map +1 -1
- package/dist/js/next/components/Select/SelectList.d.ts +4 -0
- package/dist/js/next/components/Select/SelectList.d.ts.map +1 -1
- package/dist/js/next/components/Select/SelectList.js +2 -2
- package/dist/js/next/components/Select/SelectList.js.map +1 -1
- package/dist/umd/react-core.min.js +2 -2
- package/next/components/Dropdown/Dropdown.d.ts.map +1 -1
- package/next/components/Dropdown/Dropdown.js +19 -20
- package/next/components/Dropdown/Dropdown.js.map +1 -1
- package/next/components/Select/Select.d.ts +2 -0
- package/next/components/Select/Select.d.ts.map +1 -1
- package/next/components/Select/Select.js +21 -23
- package/next/components/Select/Select.js.map +1 -1
- package/next/components/Select/SelectList.d.ts +4 -0
- package/next/components/Select/SelectList.d.ts.map +1 -1
- package/next/components/Select/SelectList.js +2 -2
- package/next/components/Select/SelectList.js.map +1 -1
- package/package.json +2 -2
- package/src/components/ExpandableSection/ExpandableSection.tsx +48 -4
- package/src/components/Menu/Menu.tsx +8 -2
- package/src/components/Menu/MenuContext.ts +3 -1
- package/src/components/Menu/MenuItem.tsx +5 -2
- package/src/components/Menu/MenuList.tsx +20 -5
- package/src/components/Menu/examples/Menu.md +99 -36
- package/src/components/Menu/examples/MenuOptionMultiSelect.tsx +2 -2
- package/src/components/Menu/examples/MenuOptionSingleSelect.tsx +2 -2
- package/src/next/components/Dropdown/Dropdown.tsx +12 -13
- package/src/next/components/Select/Select.tsx +16 -13
- package/src/next/components/Select/SelectList.tsx +6 -1
- package/src/next/components/Select/examples/SelectCheckbox.tsx +1 -0
- package/src/next/components/Select/examples/SelectMultiTypeahead.tsx +1 -1
|
@@ -18,114 +18,177 @@ import AngleLeftIcon from '@patternfly/react-icons/dist/esm/icons/angle-left-ico
|
|
|
18
18
|
|
|
19
19
|
## Examples
|
|
20
20
|
|
|
21
|
-
### Basic
|
|
21
|
+
### Basic menus
|
|
22
|
+
|
|
23
|
+
A menu may contain multiple variations of `<MenuItem>` components. The following example shows a few different states of menu items, where they may:
|
|
24
|
+
|
|
25
|
+
- Use the `itemId` property to link to callbacks. In this example, the `onSelect` property logs information to the console when a menu item is selected. In practice, specific actions can be linked to `onSelect` callbacks.
|
|
26
|
+
- Use the `to` property to direct users to other resources or webpages after selecting a menu item, and the `onClick` property to pass in a callback for specific menu items.
|
|
27
|
+
- Use the `isDisabled` property to disable a menu item.
|
|
28
|
+
- Use the `isPlain` property to remove the outer box shadow and style the menu plainly instead.
|
|
22
29
|
|
|
23
30
|
```ts file="MenuBasic.tsx"
|
|
24
31
|
```
|
|
25
32
|
|
|
26
33
|
### Danger menu item
|
|
27
34
|
|
|
35
|
+
To indicate that a `<MenuItem>` is connected to a potentially destructive action, use the `isDanger` property. The "Delete" item in the following example demonstrates how danger items look.
|
|
36
|
+
|
|
28
37
|
```ts file="MenuDangerMenuItem.tsx"
|
|
29
38
|
```
|
|
30
39
|
|
|
31
40
|
### With icons
|
|
32
41
|
|
|
42
|
+
Use the `icon` property to add a familiar icon before a `<MenuItem>` to accelerate text label recognition.
|
|
43
|
+
|
|
33
44
|
```ts file="MenuWithIcons.tsx"
|
|
34
45
|
```
|
|
35
46
|
|
|
36
|
-
### With
|
|
47
|
+
### With actions
|
|
48
|
+
|
|
49
|
+
To connect a menu item to an action icon, add a `<MenuItemAction>` to a `<MenuItem>`, and use the `icon` property to load an easily recognizable icon.
|
|
37
50
|
|
|
38
|
-
|
|
39
|
-
```
|
|
51
|
+
To trigger an action when any menu action icon is selected, pass a callback to the `onActionClick` property of the `<Menu>`. The following example logs to the console any time any action icon is selected.
|
|
40
52
|
|
|
41
|
-
|
|
53
|
+
To trigger an action when a specific item's action icon is selected, pass in the `onClick` property to that `<MenuItemAction>`. The following example logs "clicked on code icon" to the console when the "code" icon is selected.
|
|
42
54
|
|
|
43
|
-
```ts file="
|
|
55
|
+
```ts file="MenuWithActions.tsx"
|
|
44
56
|
```
|
|
45
57
|
|
|
46
58
|
### With links
|
|
47
59
|
|
|
60
|
+
Use the `to` property to add a link to a `<MenuItem>` that directs users to a new page when the item is selected. Use the `isExternalLink` property when linking to external resources. This will annotate a menu item link with an external link icon when they navigate to the link or hover over it.
|
|
61
|
+
|
|
48
62
|
```ts file="MenuWithLinks.tsx"
|
|
49
63
|
```
|
|
50
64
|
|
|
51
|
-
### With
|
|
65
|
+
### With descriptions
|
|
52
66
|
|
|
53
|
-
|
|
67
|
+
Use the `description` property to add short descriptive text below any menu item that needs additional context.
|
|
68
|
+
|
|
69
|
+
```ts file="MenuWithDescription.tsx"
|
|
54
70
|
```
|
|
55
71
|
|
|
56
|
-
###
|
|
72
|
+
### Item checkbox
|
|
57
73
|
|
|
58
|
-
|
|
74
|
+
Use the `hasCheck` property to add a checkbox to a `<MenuItem>`. Use the `isSelected` property to indicate when a `<MenuItem>` is selected.
|
|
75
|
+
|
|
76
|
+
```ts file="./MenuWithCheckbox.tsx" isBeta
|
|
59
77
|
```
|
|
60
78
|
|
|
61
|
-
###
|
|
79
|
+
### Menu footer
|
|
62
80
|
|
|
63
|
-
|
|
81
|
+
Add a `<MenuFooter>` that contains separate, but related actions at the bottom of a menu.
|
|
82
|
+
|
|
83
|
+
```ts file="MenuWithFooter.tsx"
|
|
64
84
|
```
|
|
65
85
|
|
|
66
|
-
###
|
|
86
|
+
### Separated items
|
|
67
87
|
|
|
68
|
-
|
|
88
|
+
Use a [divider](/components/divider) to visually separate `<MenuContent>`. Use the `component` property to specify the type of divider component to use.
|
|
89
|
+
|
|
90
|
+
```ts file="MenuWithSeparators.tsx"
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
### Titled groups of items
|
|
94
|
+
|
|
95
|
+
Add a `<MenuGroup>` to organize `<MenuContent>` and use the `label` property to title a group of menu items. Use the `labelHeadingLevel` property to assign a heading level to the menu group label.
|
|
96
|
+
|
|
97
|
+
```ts file="MenuWithTitledGroups.tsx"
|
|
69
98
|
```
|
|
70
99
|
|
|
71
100
|
### With favorites
|
|
72
101
|
|
|
102
|
+
The following menu example allows users to favorite menu items, an action that duplicates a menu item and places it in a separate group at the top of the menu. The `isFavorited` property identifies items that a user has favorited.
|
|
103
|
+
|
|
73
104
|
```ts file="MenuWithFavorites.tsx"
|
|
74
105
|
```
|
|
75
106
|
|
|
76
|
-
###
|
|
107
|
+
### Filtering with search input
|
|
108
|
+
|
|
109
|
+
A [search input](/components/search-input) component can be placed within `<MenuInput>` to render a search input at the top of the menu. In the following example, the `onChange` property of the text input is passed a callback that filters menu items as a user types.
|
|
110
|
+
|
|
111
|
+
```ts file="MenuFilteringWithSearchInput.tsx"
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### Option single select menu
|
|
115
|
+
|
|
116
|
+
The following example demonstrates a single option select menu that persists a selected menu item. Use the `selected` property on the `<Menu>` to label a selected item with a checkmark. You can also use the `isSelected` property on a `<MenuItem>` to indicate that it is selected.
|
|
117
|
+
|
|
118
|
+
You must also use the `role` property on the `<Menu>` with a value of `"listbox"` when using a non-checkbox select menu.
|
|
77
119
|
|
|
78
120
|
```ts file="MenuOptionSingleSelect.tsx"
|
|
79
121
|
```
|
|
80
122
|
|
|
81
|
-
### Option multi select
|
|
123
|
+
### Option multi select menu
|
|
124
|
+
|
|
125
|
+
To persist multiple selections that a user makes, use a multiple option select menu. To enable multi select, pass an array containing each selected `itemId` to the `selected` property on the `<Menu>`, and pass the `isAriaMultiselectable` property on the `<MenuList>`.
|
|
126
|
+
|
|
127
|
+
Similar to a single select menu, you must also pass `role="listbox"` to the `<Menu>`.
|
|
82
128
|
|
|
83
129
|
```ts file="MenuOptionMultiSelect.tsx"
|
|
84
130
|
```
|
|
85
131
|
|
|
86
|
-
###
|
|
132
|
+
### Scrollable menus
|
|
87
133
|
|
|
88
|
-
|
|
134
|
+
Use the `isScrollable` property to make a long `<Menu>` scrollable and visually condensed.
|
|
135
|
+
|
|
136
|
+
```ts file="MenuScrollable.tsx"
|
|
89
137
|
```
|
|
90
138
|
|
|
91
|
-
###
|
|
139
|
+
### Scrollable menu with custom height
|
|
92
140
|
|
|
93
|
-
|
|
141
|
+
Adjust the visual size of a scrollable menu by using the `menuHeight` property within `<MenuContent>`. This example adjusts the height to 200px.
|
|
94
142
|
|
|
95
|
-
```ts file="
|
|
143
|
+
```ts file="MenuScrollableCustomMenuHeight.tsx"
|
|
96
144
|
```
|
|
97
145
|
|
|
98
|
-
### With
|
|
146
|
+
### With view more
|
|
99
147
|
|
|
100
|
-
|
|
101
|
-
```
|
|
148
|
+
If you want to initially render only a certain number of menu items within a large menu, you can add a "view more" menu item with a callback passed into its `onClick` property that will render additional menu items.
|
|
102
149
|
|
|
103
|
-
|
|
150
|
+
In this example, 3 additional menu items are revealed each time the "view more" option is selected, with a loading icon simulating a network call to fetch more items. After all items are visible, the "view more" link disappears.
|
|
104
151
|
|
|
105
|
-
```ts file="
|
|
152
|
+
```ts file="MenuWithViewMore.tsx"
|
|
106
153
|
```
|
|
107
154
|
|
|
108
|
-
### With drilldown
|
|
155
|
+
### With drilldown
|
|
109
156
|
|
|
110
|
-
|
|
157
|
+
Use a drilldown menu to contain different levels of menu items. When a parent menu item (an item that has a submenu of children) is selected, the menu is replaced with the children items.
|
|
158
|
+
|
|
159
|
+
- To indicate that a menu contains a drilldown, use the `containsDrilldown` property.
|
|
160
|
+
- To indicate the path of drilled-in menu item ids, use the `drilldownItemPath` property.
|
|
161
|
+
- Pass in an array of drilled-in menus with the `drilledInMenus` property.
|
|
162
|
+
- Use the `onDrillIn` and `onDrillOut` properties to contain callbacks for drilling into and drilling out of a submenu, respectively.
|
|
163
|
+
- To account for updated heights as menus drill in and out of use, use the `onGetMenuHeight` property. When starting from a drilled-in state, the `onGetMenuHeight` property must define the height of the root menu.
|
|
164
|
+
|
|
165
|
+
```ts file="./MenuWithDrilldown.tsx" isBeta
|
|
111
166
|
```
|
|
112
167
|
|
|
113
|
-
###
|
|
168
|
+
### Initially drilled-in menu
|
|
114
169
|
|
|
115
|
-
|
|
170
|
+
To render an initially drilled-in menu, the `drilldownItemPath`, `drilledInMenus`, and `activeMenu` properties must be set to default values.
|
|
171
|
+
|
|
172
|
+
```ts file="./MenuWithDrilldownInitialState.tsx" isBeta
|
|
116
173
|
```
|
|
117
174
|
|
|
118
|
-
###
|
|
175
|
+
### With drilldown - submenu functions
|
|
119
176
|
|
|
120
|
-
|
|
177
|
+
For added flexibility with large menus, you may create a menu by passing a function to `drilldownMenu`. This approach allows you to create menu items dynamically, rather than creating everything up front.
|
|
178
|
+
|
|
179
|
+
```ts file="./MenuWithDrilldownSubmenuFunctions.tsx" isBeta
|
|
121
180
|
```
|
|
122
181
|
|
|
123
|
-
### With
|
|
182
|
+
### With drilldown breadcrumbs
|
|
124
183
|
|
|
125
|
-
|
|
184
|
+
Use [breadcrumbs](/components/breadcrumb) when a drilldown menu has more than 2 levels to offer users better navigation.
|
|
185
|
+
|
|
186
|
+
To control the height of a menu, use the `maxMenuHeight` property. Selecting the "Set max menu height" checkbox in the following example sets the menu height to "100px" and makes the menu scrollable.
|
|
187
|
+
|
|
188
|
+
```ts file="MenuWithDrilldownBreadcrumbs.tsx" isBeta
|
|
126
189
|
```
|
|
127
190
|
|
|
128
|
-
### With
|
|
191
|
+
### With drilldown and inline filter
|
|
129
192
|
|
|
130
|
-
```ts file="
|
|
193
|
+
```ts file="MenuFilterDrilldown.tsx"
|
|
131
194
|
```
|
|
@@ -15,9 +15,9 @@ export const MenuOptionMultiSelect: React.FunctionComponent = () => {
|
|
|
15
15
|
};
|
|
16
16
|
|
|
17
17
|
return (
|
|
18
|
-
<Menu onSelect={onSelect} activeItemId={0} selected={selectedItems}>
|
|
18
|
+
<Menu role="listbox" onSelect={onSelect} activeItemId={0} selected={selectedItems}>
|
|
19
19
|
<MenuContent>
|
|
20
|
-
<MenuList>
|
|
20
|
+
<MenuList isAriaMultiselectable aria-label="Menu multi select example">
|
|
21
21
|
<MenuItem itemId={0}>Option 1</MenuItem>
|
|
22
22
|
<MenuItem itemId={1}>Option 2</MenuItem>
|
|
23
23
|
<MenuItem icon={<TableIcon aria-hidden />} itemId={2}>
|
|
@@ -12,9 +12,9 @@ export const MenuOptionSingleSelect: React.FunctionComponent = () => {
|
|
|
12
12
|
};
|
|
13
13
|
|
|
14
14
|
return (
|
|
15
|
-
<Menu onSelect={onSelect} activeItemId={activeItem} selected={selectedItem}>
|
|
15
|
+
<Menu role="listbox" onSelect={onSelect} activeItemId={activeItem} selected={selectedItem}>
|
|
16
16
|
<MenuContent>
|
|
17
|
-
<MenuList>
|
|
17
|
+
<MenuList aria-label="Menu single select example">
|
|
18
18
|
<MenuItem itemId={0}>Option 1</MenuItem>
|
|
19
19
|
<MenuItem itemId={1}>Option 2</MenuItem>
|
|
20
20
|
<MenuItem icon={<TableIcon aria-hidden />} itemId={2}>
|
|
@@ -58,28 +58,27 @@ const DropdownBase: React.FunctionComponent<DropdownProps> = ({
|
|
|
58
58
|
const menuRef = (innerRef as React.RefObject<HTMLDivElement>) || localMenuRef;
|
|
59
59
|
React.useEffect(() => {
|
|
60
60
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
61
|
-
if (!isOpen && toggleRef.current?.contains(event.target as Node)) {
|
|
62
|
-
// toggle was clicked open, focus on first menu item
|
|
63
|
-
if (event.key === 'Enter') {
|
|
64
|
-
setTimeout(() => {
|
|
65
|
-
const firstElement = menuRef.current.querySelector('li > button:not(:disabled)');
|
|
66
|
-
firstElement && (firstElement as HTMLElement).focus();
|
|
67
|
-
}, 0);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
61
|
// Close the menu on tab or escape if onOpenChange is provided
|
|
71
62
|
if (
|
|
72
63
|
(isOpen && onOpenChange && menuRef.current?.contains(event.target as Node)) ||
|
|
73
64
|
toggleRef.current?.contains(event.target as Node)
|
|
74
65
|
) {
|
|
75
66
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
76
|
-
onOpenChange(
|
|
67
|
+
onOpenChange(false);
|
|
77
68
|
toggleRef.current?.focus();
|
|
78
69
|
}
|
|
79
70
|
}
|
|
80
71
|
};
|
|
81
72
|
|
|
82
|
-
const
|
|
73
|
+
const handleClick = (event: MouseEvent) => {
|
|
74
|
+
// toggle was clicked open via keyboard, focus on first menu item
|
|
75
|
+
if (isOpen && toggleRef.current?.contains(event.target as Node) && event.detail === 0) {
|
|
76
|
+
setTimeout(() => {
|
|
77
|
+
const firstElement = menuRef?.current?.querySelector('li button:not(:disabled),li input:not(:disabled)');
|
|
78
|
+
firstElement && (firstElement as HTMLElement).focus();
|
|
79
|
+
}, 0);
|
|
80
|
+
}
|
|
81
|
+
|
|
83
82
|
// If the event is not on the toggle and onOpenChange callback is provided, close the menu
|
|
84
83
|
if (isOpen && onOpenChange && !toggleRef?.current?.contains(event.target as Node)) {
|
|
85
84
|
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
@@ -89,11 +88,11 @@ const DropdownBase: React.FunctionComponent<DropdownProps> = ({
|
|
|
89
88
|
};
|
|
90
89
|
|
|
91
90
|
window.addEventListener('keydown', handleMenuKeys);
|
|
92
|
-
window.addEventListener('click',
|
|
91
|
+
window.addEventListener('click', handleClick);
|
|
93
92
|
|
|
94
93
|
return () => {
|
|
95
94
|
window.removeEventListener('keydown', handleMenuKeys);
|
|
96
|
-
window.removeEventListener('click',
|
|
95
|
+
window.removeEventListener('click', handleClick);
|
|
97
96
|
};
|
|
98
97
|
}, [isOpen, menuRef, onOpenChange]);
|
|
99
98
|
|
|
@@ -28,6 +28,8 @@ export interface SelectProps extends MenuProps, OUIAProps {
|
|
|
28
28
|
innerRef?: React.Ref<HTMLDivElement>;
|
|
29
29
|
/** z-index of the select menu */
|
|
30
30
|
zIndex?: number;
|
|
31
|
+
/** @beta Determines the accessible role of the select. For a checkbox select pass in "menu". */
|
|
32
|
+
role?: string;
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
|
|
@@ -42,6 +44,7 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
|
|
|
42
44
|
minWidth,
|
|
43
45
|
innerRef,
|
|
44
46
|
zIndex = 9999,
|
|
47
|
+
role = 'listbox',
|
|
45
48
|
...props
|
|
46
49
|
}: SelectProps & OUIAProps) => {
|
|
47
50
|
const localMenuRef = React.useRef<HTMLDivElement>();
|
|
@@ -51,28 +54,27 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
|
|
|
51
54
|
const menuRef = (innerRef as React.RefObject<HTMLDivElement>) || localMenuRef;
|
|
52
55
|
React.useEffect(() => {
|
|
53
56
|
const handleMenuKeys = (event: KeyboardEvent) => {
|
|
54
|
-
if (!isOpen && toggleRef.current?.contains(event.target as Node)) {
|
|
55
|
-
// toggle was clicked open, focus on first menu item
|
|
56
|
-
if (event.key === 'Enter' || event.key === 'Space') {
|
|
57
|
-
setTimeout(() => {
|
|
58
|
-
const firstElement = menuRef?.current?.querySelector('li button:not(:disabled),li input:not(:disabled)');
|
|
59
|
-
firstElement && (firstElement as HTMLElement).focus();
|
|
60
|
-
}, 0);
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
57
|
// Close the menu on tab or escape if onOpenChange is provided
|
|
64
58
|
if (
|
|
65
59
|
(isOpen && onOpenChange && menuRef.current?.contains(event.target as Node)) ||
|
|
66
60
|
toggleRef.current?.contains(event.target as Node)
|
|
67
61
|
) {
|
|
68
62
|
if (event.key === 'Escape' || event.key === 'Tab') {
|
|
69
|
-
onOpenChange(
|
|
63
|
+
onOpenChange(false);
|
|
70
64
|
toggleRef.current?.focus();
|
|
71
65
|
}
|
|
72
66
|
}
|
|
73
67
|
};
|
|
74
68
|
|
|
75
|
-
const
|
|
69
|
+
const handleClick = (event: MouseEvent) => {
|
|
70
|
+
// toggle was clicked open via keyboard, focus on first menu item
|
|
71
|
+
if (isOpen && toggleRef.current?.contains(event.target as Node) && event.detail === 0) {
|
|
72
|
+
setTimeout(() => {
|
|
73
|
+
const firstElement = menuRef?.current?.querySelector('li button:not(:disabled),li input:not(:disabled)');
|
|
74
|
+
firstElement && (firstElement as HTMLElement).focus();
|
|
75
|
+
}, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
76
78
|
// If the event is not on the toggle and onOpenChange callback is provided, close the menu
|
|
77
79
|
if (isOpen && onOpenChange && !toggleRef?.current?.contains(event.target as Node)) {
|
|
78
80
|
if (isOpen && !menuRef.current?.contains(event.target as Node)) {
|
|
@@ -82,16 +84,17 @@ const SelectBase: React.FunctionComponent<SelectProps & OUIAProps> = ({
|
|
|
82
84
|
};
|
|
83
85
|
|
|
84
86
|
window.addEventListener('keydown', handleMenuKeys);
|
|
85
|
-
window.addEventListener('click',
|
|
87
|
+
window.addEventListener('click', handleClick);
|
|
86
88
|
|
|
87
89
|
return () => {
|
|
88
90
|
window.removeEventListener('keydown', handleMenuKeys);
|
|
89
|
-
window.removeEventListener('click',
|
|
91
|
+
window.removeEventListener('click', handleClick);
|
|
90
92
|
};
|
|
91
93
|
}, [isOpen, menuRef, onOpenChange]);
|
|
92
94
|
|
|
93
95
|
const menu = (
|
|
94
96
|
<Menu
|
|
97
|
+
role={role}
|
|
95
98
|
className={css(className)}
|
|
96
99
|
ref={menuRef}
|
|
97
100
|
onSelect={(event, itemId) => onSelect(event, itemId)}
|
|
@@ -7,14 +7,19 @@ export interface SelectListProps extends MenuListProps {
|
|
|
7
7
|
children: React.ReactNode;
|
|
8
8
|
/** Classes applied to root element of select list */
|
|
9
9
|
className?: string;
|
|
10
|
+
/** @beta Indicates to assistive technologies whether more than one item can be selected
|
|
11
|
+
* for a non-checkbox select.
|
|
12
|
+
*/
|
|
13
|
+
isAriaMultiselectable?: boolean;
|
|
10
14
|
}
|
|
11
15
|
|
|
12
16
|
export const SelectList: React.FunctionComponent<MenuListProps> = ({
|
|
13
17
|
children,
|
|
14
18
|
className,
|
|
19
|
+
isAriaMultiselectable = false,
|
|
15
20
|
...props
|
|
16
21
|
}: SelectListProps) => (
|
|
17
|
-
<MenuList className={css(className)} {...props}>
|
|
22
|
+
<MenuList isAriaMultiselectable={isAriaMultiselectable} className={css(className)} {...props}>
|
|
18
23
|
{children}
|
|
19
24
|
</MenuList>
|
|
20
25
|
);
|
|
@@ -179,7 +179,7 @@ export const SelectMultiTypeahead: React.FunctionComponent = () => {
|
|
|
179
179
|
onOpenChange={() => setIsOpen(false)}
|
|
180
180
|
toggle={toggle}
|
|
181
181
|
>
|
|
182
|
-
<SelectList>
|
|
182
|
+
<SelectList isAriaMultiselectable>
|
|
183
183
|
{selectOptions.map((option, index) => (
|
|
184
184
|
<SelectOption
|
|
185
185
|
key={option.itemId || option.children}
|