@patternfly/react-core 4.211.0 → 4.211.3

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 (72) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/dist/esm/components/Menu/Menu.js +1 -1
  3. package/dist/esm/components/Menu/Menu.js.map +1 -1
  4. package/dist/esm/components/Page/PageBreadcrumb.d.ts.map +1 -1
  5. package/dist/esm/components/Page/PageBreadcrumb.js +1 -1
  6. package/dist/esm/components/Page/PageBreadcrumb.js.map +1 -1
  7. package/dist/esm/components/Page/PageGroup.d.ts.map +1 -1
  8. package/dist/esm/components/Page/PageGroup.js +1 -1
  9. package/dist/esm/components/Page/PageGroup.js.map +1 -1
  10. package/dist/esm/components/Page/PageNavigation.d.ts.map +1 -1
  11. package/dist/esm/components/Page/PageNavigation.js +1 -1
  12. package/dist/esm/components/Page/PageNavigation.js.map +1 -1
  13. package/dist/esm/components/Page/PageSection.d.ts.map +1 -1
  14. package/dist/esm/components/Page/PageSection.js +1 -1
  15. package/dist/esm/components/Page/PageSection.js.map +1 -1
  16. package/dist/esm/components/Panel/Panel.d.ts +3 -1
  17. package/dist/esm/components/Panel/Panel.d.ts.map +1 -1
  18. package/dist/esm/components/Panel/Panel.js +4 -3
  19. package/dist/esm/components/Panel/Panel.js.map +1 -1
  20. package/dist/esm/components/Tooltip/Tooltip.d.ts +6 -0
  21. package/dist/esm/components/Tooltip/Tooltip.d.ts.map +1 -1
  22. package/dist/esm/components/Tooltip/Tooltip.js +2 -2
  23. package/dist/esm/components/Tooltip/Tooltip.js.map +1 -1
  24. package/dist/esm/helpers/KeyboardHandler.d.ts +2 -0
  25. package/dist/esm/helpers/KeyboardHandler.d.ts.map +1 -1
  26. package/dist/esm/helpers/KeyboardHandler.js +3 -2
  27. package/dist/esm/helpers/KeyboardHandler.js.map +1 -1
  28. package/dist/js/components/Menu/Menu.js +1 -1
  29. package/dist/js/components/Menu/Menu.js.map +1 -1
  30. package/dist/js/components/Page/PageBreadcrumb.d.ts.map +1 -1
  31. package/dist/js/components/Page/PageBreadcrumb.js +1 -1
  32. package/dist/js/components/Page/PageBreadcrumb.js.map +1 -1
  33. package/dist/js/components/Page/PageGroup.d.ts.map +1 -1
  34. package/dist/js/components/Page/PageGroup.js +1 -1
  35. package/dist/js/components/Page/PageGroup.js.map +1 -1
  36. package/dist/js/components/Page/PageNavigation.d.ts.map +1 -1
  37. package/dist/js/components/Page/PageNavigation.js +1 -1
  38. package/dist/js/components/Page/PageNavigation.js.map +1 -1
  39. package/dist/js/components/Page/PageSection.d.ts.map +1 -1
  40. package/dist/js/components/Page/PageSection.js +1 -1
  41. package/dist/js/components/Page/PageSection.js.map +1 -1
  42. package/dist/js/components/Panel/Panel.d.ts +3 -1
  43. package/dist/js/components/Panel/Panel.d.ts.map +1 -1
  44. package/dist/js/components/Panel/Panel.js +4 -4
  45. package/dist/js/components/Panel/Panel.js.map +1 -1
  46. package/dist/js/components/Tooltip/Tooltip.d.ts +6 -0
  47. package/dist/js/components/Tooltip/Tooltip.d.ts.map +1 -1
  48. package/dist/js/components/Tooltip/Tooltip.js +2 -2
  49. package/dist/js/components/Tooltip/Tooltip.js.map +1 -1
  50. package/dist/js/helpers/KeyboardHandler.d.ts +2 -0
  51. package/dist/js/helpers/KeyboardHandler.d.ts.map +1 -1
  52. package/dist/js/helpers/KeyboardHandler.js +3 -2
  53. package/dist/js/helpers/KeyboardHandler.js.map +1 -1
  54. package/dist/umd/react-core.js +14 -12
  55. package/dist/umd/react-core.min.js +4 -4
  56. package/package.json +6 -6
  57. package/src/components/Menu/Menu.tsx +1 -1
  58. package/src/components/Page/PageBreadcrumb.tsx +1 -0
  59. package/src/components/Page/PageGroup.tsx +1 -0
  60. package/src/components/Page/PageNavigation.tsx +1 -0
  61. package/src/components/Page/PageSection.tsx +1 -0
  62. package/src/components/Page/__tests__/__snapshots__/PageBreadcrumb.test.tsx.snap +1 -0
  63. package/src/components/Page/__tests__/__snapshots__/PageGroup.test.tsx.snap +1 -0
  64. package/src/components/Page/__tests__/__snapshots__/PageNavigation.test.tsx.snap +1 -0
  65. package/src/components/Page/__tests__/__snapshots__/PageSection.test.tsx.snap +1 -0
  66. package/src/components/Panel/Panel.tsx +8 -1
  67. package/src/components/Tabs/examples/Tabs.md +144 -25
  68. package/src/components/Tooltip/Tooltip.tsx +8 -0
  69. package/src/components/Tooltip/examples/Tooltip.md +86 -41
  70. package/src/demos/ComposableMenu/ComposableMenu.md +2 -0
  71. package/src/demos/ComposableMenu/examples/ComposableTreeViewMenu.tsx +62 -28
  72. package/src/helpers/KeyboardHandler.tsx +7 -2
@@ -12,6 +12,7 @@ import './TooltipExamples.css';
12
12
  ## Examples
13
13
 
14
14
  ### Basic
15
+
15
16
  ```js
16
17
  import React from 'react';
17
18
  import { Tooltip } from '@patternfly/react-core';
@@ -22,12 +23,15 @@ import { Tooltip } from '@patternfly/react-core';
22
23
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
23
24
  }
24
25
  >
25
- <span tabIndex="0" style={{ border: '1px dashed' }}>I have a tooltip!</span>
26
+ <span tabIndex="0" style={{ border: '1px dashed' }}>
27
+ I have a tooltip!
28
+ </span>
26
29
  </Tooltip>
27
- </div>
30
+ </div>;
28
31
  ```
29
32
 
30
33
  ### Tooltip react ref
34
+
31
35
  ```js
32
36
  import React from 'react';
33
37
  import { Tooltip } from '@patternfly/react-core';
@@ -36,35 +40,49 @@ TooltipReactRef = () => {
36
40
  const tooltipRef = React.useRef();
37
41
  return (
38
42
  <div style={{ margin: '100px' }}>
39
- <button ref={tooltipRef}>Tooltip attached via react ref</button>
43
+ <button aria-describedby="tooltip-ref1" ref={tooltipRef}>
44
+ Tooltip attached via react ref
45
+ </button>
40
46
  <Tooltip
47
+ id="tooltip-ref1"
41
48
  content={
42
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
49
+ <div>
50
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
51
+ </div>
43
52
  }
44
53
  reference={tooltipRef}
45
54
  />
46
55
  </div>
47
56
  );
48
- }
57
+ };
49
58
  ```
50
59
 
51
60
  ### Tooltip selector ref
61
+
52
62
  ```js
53
63
  import React from 'react';
54
64
  import { Tooltip } from '@patternfly/react-core';
55
65
 
56
66
  <div style={{ margin: '100px' }}>
57
- <button id="tooltip-selector">Tooltip attached via selector ref</button>
67
+ <button aria-describedby="tooltip-ref2" id="tooltip-selector">
68
+ Tooltip attached via selector ref
69
+ </button>
58
70
  <Tooltip
71
+ id="tooltip-ref2"
59
72
  content={
60
73
  <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
61
74
  }
62
75
  reference={() => document.getElementById('tooltip-selector')}
63
76
  />
64
- </div>
77
+ </div>;
65
78
  ```
66
79
 
67
- ### On icon
80
+ ### On icon with dynamic content
81
+
82
+ When the tooltip is used as a wrapper and its content will dynamically update, the `aria` prop should have a value of "none" passed in. This prevents assistive technologies from announcing the tooltip contents more than once. Additionally, the `aria-live` prop should have a value of "polite" passed in, in order for assistive technologies to announce when the tooltip contents gets updated.
83
+
84
+ When using a React or selector ref with a tooltip that has dynamic content, the `aria` and `aria-live` props do not need to be manually passed in.
85
+
68
86
  ```js
69
87
  import React from 'react';
70
88
  import { Tooltip, Button } from '@patternfly/react-core';
@@ -77,8 +95,13 @@ IconExample = () => {
77
95
  const [content, setContent] = React.useState(copyText);
78
96
  return (
79
97
  <div style={{ margin: '100px' }}>
80
- <Tooltip content={showSuccessContent ? doneCopyText : copyText}>
81
- <Button variant="plain" aria-label="Icon with tooltip attached" id="tt-ref" onClick={() => setShowSuccessContent(!showSuccessContent)}>
98
+ <Tooltip aria="none" aria-live="polite" content={showSuccessContent ? doneCopyText : copyText}>
99
+ <Button
100
+ aria-label="Clipboard"
101
+ variant="plain"
102
+ id="tt-ref"
103
+ onClick={() => setShowSuccessContent(!showSuccessContent)}
104
+ >
82
105
  <CopyIcon />
83
106
  </Button>
84
107
  </Tooltip>
@@ -88,6 +111,7 @@ IconExample = () => {
88
111
  ```
89
112
 
90
113
  ### Options
114
+
91
115
  ```js
92
116
  import React from 'react';
93
117
  import { Button, Tooltip, Checkbox, Select, SelectOption, TextInput } from '@patternfly/react-core';
@@ -105,26 +129,26 @@ OptionsTooltip = () => {
105
129
  const [exitDelayInput, setExitDelayInput] = React.useState(0);
106
130
  const [animationDuration, setAnimationDuration] = React.useState(300);
107
131
  const tipBoxRef = React.useRef(null);
108
-
132
+
109
133
  const scrollToRef = ref => {
110
134
  if (ref && ref.current) {
111
135
  ref.current.scrollTop = 400;
112
136
  ref.current.scrollLeft = 300;
113
137
  }
114
- }
115
-
138
+ };
139
+
116
140
  React.useEffect(() => {
117
141
  scrollToRef(tipBoxRef);
118
142
  }, []);
119
-
143
+
120
144
  return (
121
145
  <>
122
146
  <div>
123
- <div style={{ border: '1px solid'}}>
147
+ <div style={{ border: '1px solid' }}>
124
148
  <Checkbox
125
149
  label="trigger: mouseenter"
126
150
  isChecked={trigger.includes('mouseenter')}
127
- onChange={(checked) => {
151
+ onChange={checked => {
128
152
  let updatedTrigger;
129
153
  checked && (updatedTrigger = trigger.concat('mouseenter'));
130
154
  !checked && (updatedTrigger = trigger.filter(t => t !== 'mouseenter'));
@@ -137,7 +161,7 @@ OptionsTooltip = () => {
137
161
  <Checkbox
138
162
  label="trigger: focus"
139
163
  isChecked={trigger.includes('focus')}
140
- onChange={(checked) => {
164
+ onChange={checked => {
141
165
  let updatedTrigger;
142
166
  checked && (updatedTrigger = trigger.concat('focus'));
143
167
  !checked && (updatedTrigger = trigger.filter(t => t !== 'focus'));
@@ -150,7 +174,7 @@ OptionsTooltip = () => {
150
174
  <Checkbox
151
175
  label="trigger: click"
152
176
  isChecked={trigger.includes('click')}
153
- onChange={(checked) => {
177
+ onChange={checked => {
154
178
  let updatedTrigger;
155
179
  checked && (updatedTrigger = trigger.concat('click'));
156
180
  !checked && (updatedTrigger = trigger.filter(t => t !== 'click'));
@@ -163,36 +187,36 @@ OptionsTooltip = () => {
163
187
  <Checkbox
164
188
  label="trigger: manual"
165
189
  isChecked={trigger.includes('manual')}
166
- onChange={(checked) => {
190
+ onChange={checked => {
167
191
  let updatedTrigger;
168
192
  checked && (updatedTrigger = trigger.concat('manual'));
169
193
  !checked && (updatedTrigger = trigger.filter(t => t !== 'manual'));
170
194
  setIsVisible(false);
171
195
  setTrigger(updatedTrigger);
172
196
  }}
173
- aria-label="trigger: manual"
174
- id="trigger_manual"
197
+ aria-label="trigger: manual"
198
+ id="trigger_manual"
175
199
  />
176
200
  </div>
177
- <div style={{ border: '1px solid'}}>
201
+ <div style={{ border: '1px solid' }}>
178
202
  <Checkbox
179
203
  label="content left-aligned"
180
204
  isChecked={contentLeftAligned}
181
- onChange={(checked) => setContentLeftAligned(checked)}
205
+ onChange={checked => setContentLeftAligned(checked)}
182
206
  aria-label="content left-aligned"
183
- id="content_left_aligned"
207
+ id="content_left_aligned"
184
208
  />
185
209
  </div>
186
- <div style={{ border: '1px solid'}}>
210
+ <div style={{ border: '1px solid' }}>
187
211
  <Checkbox
188
212
  label="enableFlip"
189
213
  isChecked={enableFlip}
190
- onChange={(checked) => setEnableFlip(checked)}
191
- aria-label="enableFlip"
192
- id="enable_flip"
214
+ onChange={checked => setEnableFlip(checked)}
215
+ aria-label="enableFlip"
216
+ id="enable_flip"
193
217
  />
194
218
  </div>
195
- <div style={{ border: '1px solid'}}>
219
+ <div style={{ border: '1px solid' }}>
196
220
  position (will flip if enableFlip is true). The 'auto' position requires enableFlip to be set to true.
197
221
  <Select
198
222
  onToggle={() => setPositionSelectOpen(!positionSelectOpen)}
@@ -219,22 +243,41 @@ OptionsTooltip = () => {
219
243
  <SelectOption value="right-end" />
220
244
  </Select>
221
245
  </div>
222
- <div style={{ border: '1px solid'}}>
246
+ <div style={{ border: '1px solid' }}>
223
247
  <Checkbox
224
248
  label="isVisible (also set trigger to only manual to programmatically control it)"
225
249
  isChecked={isVisible}
226
- onChange={(checked) => setIsVisible(checked)}
227
- aria-label="isVisible"
228
- id="is_visible"
250
+ onChange={checked => setIsVisible(checked)}
251
+ aria-label="isVisible"
252
+ id="is_visible"
229
253
  />
230
254
  </div>
231
- <div style={{ border: '1px solid'}}>
232
- Entry delay (ms) <TextInput value={entryDelayInput} type="number" onChange={val => setEntryDelayInput(val)} aria-label="entry delay" />
233
- Exit delay (ms) <TextInput value={exitDelayInput} type="number" onChange={val => setExitDelayInput(val)} aria-label="exit delay" />
234
- Animation duration (ms) <TextInput value={animationDuration} type="number" onChange={val => setAnimationDuration(val)} aria-label="animation duration" />
255
+ <div style={{ border: '1px solid' }}>
256
+ Entry delay (ms){' '}
257
+ <TextInput
258
+ value={entryDelayInput}
259
+ type="number"
260
+ onChange={val => setEntryDelayInput(val)}
261
+ aria-label="entry delay"
262
+ />
263
+ Exit delay (ms) <TextInput
264
+ value={exitDelayInput}
265
+ type="number"
266
+ onChange={val => setExitDelayInput(val)}
267
+ aria-label="exit delay"
268
+ />
269
+ Animation duration (ms){' '}
270
+ <TextInput
271
+ value={animationDuration}
272
+ type="number"
273
+ onChange={val => setAnimationDuration(val)}
274
+ aria-label="animation duration"
275
+ />
235
276
  </div>
236
- <div style={{ border: '1px solid'}}>
237
- flip behavior examples (enableFlip has to be true). "flip" will try to flip the tooltip to the opposite of the starting position. The second option ensures that there are 3 escape positions for every possible starting position (default). This setting is ignored if position prop is set to 'auto'.
277
+ <div style={{ border: '1px solid' }}>
278
+ flip behavior examples (enableFlip has to be true). "flip" will try to flip the tooltip to the opposite of the
279
+ starting position. The second option ensures that there are 3 escape positions for every possible starting
280
+ position (default). This setting is ignored if position prop is set to 'auto'.
238
281
  <Select
239
282
  onToggle={() => setFlipSelectOpen(!flipSelectOpen)}
240
283
  onSelect={(event, selection) => {
@@ -254,7 +297,9 @@ OptionsTooltip = () => {
254
297
  <div id="tooltip-boundary" className="tooltip-box" ref={tipBoxRef}>
255
298
  <Tooltip
256
299
  content={
257
- <div>Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.</div>
300
+ <div>
301
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam id feugiat augue, nec fringilla turpis.
302
+ </div>
258
303
  }
259
304
  trigger={trigger.join(' ')}
260
305
  enableFlip={enableFlip}
@@ -272,5 +317,5 @@ OptionsTooltip = () => {
272
317
  </div>
273
318
  </>
274
319
  );
275
- }
320
+ };
276
321
  ```
@@ -47,6 +47,8 @@ Composable menus currently require consumer keyboard handling and use of our und
47
47
 
48
48
  ### Composable tree view menu
49
49
 
50
+ When rendering a menu-like element that does not contain MenuItem components, [Panel](/components/panel) allows more flexible control and customization.
51
+
50
52
  ```ts file="./examples/ComposableTreeViewMenu.tsx"
51
53
  ```
52
54
 
@@ -1,10 +1,10 @@
1
1
  import React from 'react';
2
2
  import {
3
3
  MenuToggle,
4
- Menu,
5
- MenuContent,
6
- MenuGroup,
7
- MenuList,
4
+ Panel,
5
+ PanelMain,
6
+ PanelMainBody,
7
+ Title,
8
8
  Popper,
9
9
  TreeView,
10
10
  TreeViewDataItem
@@ -14,6 +14,7 @@ export const ComposableTreeViewMenu: React.FunctionComponent = () => {
14
14
  const [isOpen, setIsOpen] = React.useState<boolean>(false);
15
15
  const [checkedItems, setCheckedItems] = React.useState<TreeViewDataItem[]>([]);
16
16
  const toggleRef = React.useRef<HTMLButtonElement>();
17
+ const containerRef = React.useRef<HTMLDivElement>();
17
18
  const menuRef = React.useRef<HTMLDivElement>();
18
19
 
19
20
  const statusOptions: TreeViewDataItem[] = [
@@ -85,7 +86,7 @@ export const ComposableTreeViewMenu: React.FunctionComponent = () => {
85
86
  customBadgeContent: 0
86
87
  }
87
88
  ];
88
- // Helper functions
89
+ // Helper functions for tree
89
90
  const isChecked = (dataItem: TreeViewDataItem) => checkedItems.some(item => item.id === dataItem.id);
90
91
  const areAllDescendantsChecked = (dataItem: TreeViewDataItem) =>
91
92
  dataItem.children ? dataItem.children.every(child => areAllDescendantsChecked(child)) : isChecked(dataItem);
@@ -163,18 +164,32 @@ export const ComposableTreeViewMenu: React.FunctionComponent = () => {
163
164
  );
164
165
  };
165
166
 
167
+ // Controls keys that should open/close the menu
166
168
  const handleMenuKeys = (event: KeyboardEvent) => {
167
169
  if (!isOpen) {
168
170
  return;
169
171
  }
170
172
  if (menuRef.current.contains(event.target as Node) || toggleRef.current.contains(event.target as Node)) {
171
- if (event.key === 'Escape' || event.key === 'Tab') {
173
+ // The escape key when pressed while inside the menu should close the menu and refocus the toggle
174
+ if (event.key === 'Escape') {
172
175
  setIsOpen(!isOpen);
173
176
  toggleRef.current.focus();
174
177
  }
178
+
179
+ // The tab key when pressed while inside the menu and on the contained last tree view should close the menu and refocus the toggle
180
+ // Shift tab should keep the default behavior to return to a previous tree view
181
+ if (event.key === 'Tab' && !event.shiftKey) {
182
+ const treeList = menuRef.current.querySelectorAll('.pf-c-tree-view');
183
+ if (treeList[treeList.length - 1].contains(event.target as Node)) {
184
+ event.preventDefault();
185
+ setIsOpen(!isOpen);
186
+ toggleRef.current.focus();
187
+ }
188
+ }
175
189
  }
176
190
  };
177
191
 
192
+ // Controls that a click outside the menu while the menu is open should close the menu
178
193
  const handleClickOutside = (event: MouseEvent) => {
179
194
  if (isOpen && !menuRef.current.contains(event.target as Node)) {
180
195
  setIsOpen(false);
@@ -194,7 +209,7 @@ export const ComposableTreeViewMenu: React.FunctionComponent = () => {
194
209
  ev.stopPropagation(); // Stop handleClickOutside from handling
195
210
  setTimeout(() => {
196
211
  if (menuRef.current) {
197
- const firstElement = menuRef.current.querySelector('li > button:not(:disabled)');
212
+ const firstElement = menuRef.current.querySelector('li button:not(:disabled)');
198
213
  firstElement && (firstElement as HTMLElement).focus();
199
214
  }
200
215
  }, 0);
@@ -202,39 +217,58 @@ export const ComposableTreeViewMenu: React.FunctionComponent = () => {
202
217
  };
203
218
 
204
219
  const toggle = (
205
- <MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
206
- {isOpen ? 'Expanded' : 'Collapsed'}
207
- </MenuToggle>
220
+ <div ref={containerRef}>
221
+ <MenuToggle ref={toggleRef} onClick={onToggleClick} isExpanded={isOpen}>
222
+ {isOpen ? 'Expanded' : 'Collapsed'}
223
+ </MenuToggle>
224
+ </div>
208
225
  );
209
226
  const statusMapped = statusOptions.map(mapTree);
210
227
  const roleMapped = roleOptions.map(mapTree);
211
228
  const menu = (
212
- <Menu
229
+ <Panel
213
230
  ref={menuRef}
214
- // eslint-disable-next-line no-console
215
- onSelect={(_ev, itemId) => console.log('selected', itemId)}
216
- style={
217
- {
218
- '--pf-c-menu--Width': '300px'
219
- } as React.CSSProperties
220
- }
231
+ variant="raised"
232
+ style={{
233
+ width: '300px'
234
+ }}
221
235
  >
222
- <MenuContent>
223
- <MenuList>
224
- <MenuGroup label="Status">
236
+ <PanelMain>
237
+ <section>
238
+ <PanelMainBody style={{ paddingBottom: 0 }}>
239
+ <Title headingLevel="h1" size={'md'}>
240
+ Status
241
+ </Title>
242
+ </PanelMainBody>
243
+ <PanelMainBody style={{ padding: 0 }}>
225
244
  <TreeView
226
245
  data={statusMapped}
227
246
  hasBadges
228
247
  hasChecks
229
248
  onCheck={(event, item) => onCheck(event, item, 'status')}
230
249
  />
231
- </MenuGroup>
232
- <MenuGroup label="Role">
250
+ </PanelMainBody>
251
+ </section>
252
+ <section>
253
+ <PanelMainBody style={{ paddingBottom: 0, paddingTop: 0 }}>
254
+ <Title headingLevel="h1" size={'md'}>
255
+ Roles
256
+ </Title>
257
+ </PanelMainBody>
258
+ <PanelMainBody style={{ padding: 0 }}>
233
259
  <TreeView data={roleMapped} hasBadges hasChecks onCheck={(event, item) => onCheck(event, item, 'role')} />
234
- </MenuGroup>
235
- </MenuList>
236
- </MenuContent>
237
- </Menu>
260
+ </PanelMainBody>
261
+ </section>
262
+ </PanelMain>
263
+ </Panel>
264
+ );
265
+ return (
266
+ <Popper
267
+ trigger={toggle}
268
+ popper={menu}
269
+ isVisible={isOpen}
270
+ appendTo={containerRef.current}
271
+ popperMatchesTriggerWidth={false}
272
+ />
238
273
  );
239
- return <Popper trigger={toggle} popper={menu} isVisible={isOpen} popperMatchesTriggerWidth={false} />;
240
274
  };
@@ -18,6 +18,8 @@ export interface KeyboardHandlerProps {
18
18
  validSiblingTags?: string[];
19
19
  /** Flag indicating that the tabIndex of the currently focused element and next focused element should be updated, in the case of using a roving tabIndex */
20
20
  updateTabIndex?: boolean;
21
+ /** Flag indicating that next focusable element of a horizontal movement will be this element's sibling */
22
+ onlyTraverseSiblings?: boolean;
21
23
  /** Flag indicating that the included vertical arrow key handling should be ignored */
22
24
  noVerticalArrowHandling?: boolean;
23
25
  /** Flag indicating that the included horizontal arrow key handling should be ignored */
@@ -176,6 +178,7 @@ export class KeyboardHandler extends React.Component<KeyboardHandlerProps> {
176
178
  isActiveElement: (navigableElement: Element) => document.activeElement === navigableElement,
177
179
  getFocusableElement: (navigableElement: Element) => navigableElement,
178
180
  validSiblingTags: ['BUTTON', 'A'],
181
+ onlyTraverseSiblings: true,
179
182
  updateTabIndex: true,
180
183
  noHorizontalArrowHandling: false,
181
184
  noVerticalArrowHandling: false,
@@ -212,7 +215,8 @@ export class KeyboardHandler extends React.Component<KeyboardHandlerProps> {
212
215
  updateTabIndex,
213
216
  validSiblingTags,
214
217
  additionalKeyHandler,
215
- createNavigableElements
218
+ createNavigableElements,
219
+ onlyTraverseSiblings
216
220
  } = this.props;
217
221
 
218
222
  // Pass the event off to be handled by any custom handler
@@ -256,7 +260,8 @@ export class KeyboardHandler extends React.Component<KeyboardHandlerProps> {
256
260
  validSiblingTags,
257
261
  noVerticalArrowHandling,
258
262
  noHorizontalArrowHandling,
259
- updateTabIndex
263
+ updateTabIndex,
264
+ onlyTraverseSiblings
260
265
  );
261
266
  };
262
267