@patternfly/react-core 5.1.1-prerelease.2 → 5.1.1-prerelease.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 +10 -0
- package/components/package.json +1 -1
- package/deprecated/package.json +1 -1
- package/dist/dynamic/components/AboutModal/package.json +1 -1
- package/dist/dynamic/components/Accordion/package.json +1 -1
- package/dist/dynamic/components/ActionList/package.json +1 -1
- package/dist/dynamic/components/Alert/package.json +1 -1
- package/dist/dynamic/components/Avatar/package.json +1 -1
- package/dist/dynamic/components/BackToTop/package.json +1 -1
- package/dist/dynamic/components/Backdrop/package.json +1 -1
- package/dist/dynamic/components/BackgroundImage/package.json +1 -1
- package/dist/dynamic/components/Badge/package.json +1 -1
- package/dist/dynamic/components/Banner/package.json +1 -1
- package/dist/dynamic/components/Brand/package.json +1 -1
- package/dist/dynamic/components/Breadcrumb/package.json +1 -1
- package/dist/dynamic/components/Button/package.json +1 -1
- package/dist/dynamic/components/CalendarMonth/package.json +1 -1
- package/dist/dynamic/components/Card/package.json +1 -1
- package/dist/dynamic/components/Checkbox/package.json +1 -1
- package/dist/dynamic/components/Chip/package.json +1 -1
- package/dist/dynamic/components/ClipboardCopy/package.json +1 -1
- package/dist/dynamic/components/CodeBlock/package.json +1 -1
- package/dist/dynamic/components/DataList/package.json +1 -1
- package/dist/dynamic/components/DatePicker/package.json +1 -1
- package/dist/dynamic/components/DescriptionList/package.json +1 -1
- package/dist/dynamic/components/Divider/package.json +1 -1
- package/dist/dynamic/components/DragDrop/package.json +1 -1
- package/dist/dynamic/components/Drawer/package.json +1 -1
- package/dist/dynamic/components/Dropdown/package.json +1 -1
- package/dist/dynamic/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/components/EmptyState/package.json +1 -1
- package/dist/dynamic/components/ExpandableSection/package.json +1 -1
- package/dist/dynamic/components/FileUpload/package.json +1 -1
- package/dist/dynamic/components/Form/package.json +1 -1
- package/dist/dynamic/components/FormSelect/package.json +1 -1
- package/dist/dynamic/components/HelperText/package.json +1 -1
- package/dist/dynamic/components/Hint/package.json +1 -1
- package/dist/dynamic/components/Icon/package.json +1 -1
- package/dist/dynamic/components/InputGroup/package.json +1 -1
- package/dist/dynamic/components/JumpLinks/package.json +1 -1
- package/dist/dynamic/components/Label/package.json +1 -1
- package/dist/dynamic/components/List/package.json +1 -1
- package/dist/dynamic/components/LoginPage/package.json +1 -1
- package/dist/dynamic/components/Masthead/package.json +1 -1
- package/dist/dynamic/components/Menu/package.json +1 -1
- package/dist/dynamic/components/MenuToggle/package.json +1 -1
- package/dist/dynamic/components/Modal/package.json +1 -1
- package/dist/dynamic/components/MultipleFileUpload/package.json +1 -1
- package/dist/dynamic/components/Nav/package.json +1 -1
- package/dist/dynamic/components/NotificationBadge/package.json +1 -1
- package/dist/dynamic/components/NotificationDrawer/package.json +1 -1
- package/dist/dynamic/components/NumberInput/package.json +1 -1
- package/dist/dynamic/components/OverflowMenu/package.json +1 -1
- package/dist/dynamic/components/Page/package.json +1 -1
- package/dist/dynamic/components/Pagination/package.json +1 -1
- package/dist/dynamic/components/Panel/package.json +1 -1
- package/dist/dynamic/components/Popover/package.json +1 -1
- package/dist/dynamic/components/Progress/package.json +1 -1
- package/dist/dynamic/components/ProgressStepper/package.json +1 -1
- package/dist/dynamic/components/Radio/package.json +1 -1
- package/dist/dynamic/components/SearchInput/package.json +1 -1
- package/dist/dynamic/components/Select/package.json +1 -1
- package/dist/dynamic/components/Sidebar/package.json +1 -1
- package/dist/dynamic/components/SimpleList/package.json +1 -1
- package/dist/dynamic/components/Skeleton/package.json +1 -1
- package/dist/dynamic/components/SkipToContent/package.json +1 -1
- package/dist/dynamic/components/Slider/package.json +1 -1
- package/dist/dynamic/components/Spinner/package.json +1 -1
- package/dist/dynamic/components/Switch/package.json +1 -1
- package/dist/dynamic/components/Tabs/package.json +1 -1
- package/dist/dynamic/components/Text/package.json +1 -1
- package/dist/dynamic/components/TextArea/package.json +1 -1
- package/dist/dynamic/components/TextInput/package.json +1 -1
- package/dist/dynamic/components/TextInputGroup/package.json +1 -1
- package/dist/dynamic/components/Tile/package.json +1 -1
- package/dist/dynamic/components/TimePicker/package.json +1 -1
- package/dist/dynamic/components/Timestamp/package.json +1 -1
- package/dist/dynamic/components/Title/package.json +1 -1
- package/dist/dynamic/components/ToggleGroup/package.json +1 -1
- package/dist/dynamic/components/Toolbar/package.json +1 -1
- package/dist/dynamic/components/Tooltip/package.json +1 -1
- package/dist/dynamic/components/TreeView/package.json +1 -1
- package/dist/dynamic/components/Truncate/package.json +1 -1
- package/dist/dynamic/components/Wizard/hooks/package.json +1 -1
- package/dist/dynamic/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/ApplicationLauncher/package.json +1 -1
- package/dist/dynamic/deprecated/components/ContextSelector/package.json +1 -1
- package/dist/dynamic/deprecated/components/Dropdown/package.json +1 -1
- package/dist/dynamic/deprecated/components/OptionsMenu/package.json +1 -1
- package/dist/dynamic/deprecated/components/PageHeader/package.json +1 -1
- package/dist/dynamic/deprecated/components/Select/package.json +1 -1
- package/dist/dynamic/deprecated/components/Wizard/package.json +1 -1
- package/dist/dynamic/deprecated/components/package.json +1 -1
- package/dist/dynamic/helpers/FocusTrap/FocusTrap/package.json +1 -1
- package/dist/dynamic/helpers/GenerateId/GenerateId/package.json +1 -1
- package/dist/dynamic/helpers/KeyboardHandler/package.json +1 -1
- package/dist/dynamic/helpers/OUIA/ouia/package.json +1 -1
- package/dist/dynamic/helpers/Popper/Popper/package.json +1 -1
- package/dist/dynamic/helpers/constants/package.json +1 -1
- package/dist/dynamic/helpers/datetimeUtils/package.json +1 -1
- package/dist/dynamic/helpers/favorites/package.json +1 -1
- package/dist/dynamic/helpers/fileUtils/package.json +1 -1
- package/dist/dynamic/helpers/htmlConstants/package.json +1 -1
- package/dist/dynamic/helpers/package.json +1 -1
- package/dist/dynamic/helpers/resizeObserver/package.json +1 -1
- package/dist/dynamic/helpers/typeUtils/package.json +1 -1
- package/dist/dynamic/helpers/useInterval/package.json +1 -1
- package/dist/dynamic/helpers/useIsomorphicLayout/package.json +1 -1
- package/dist/dynamic/helpers/useUnmountEffect/package.json +1 -1
- package/dist/dynamic/helpers/util/package.json +1 -1
- package/dist/dynamic/layouts/Bullseye/package.json +1 -1
- package/dist/dynamic/layouts/Flex/package.json +1 -1
- package/dist/dynamic/layouts/Gallery/package.json +1 -1
- package/dist/dynamic/layouts/Grid/package.json +1 -1
- package/dist/dynamic/layouts/Level/package.json +1 -1
- package/dist/dynamic/layouts/Split/package.json +1 -1
- package/dist/dynamic/layouts/Stack/package.json +1 -1
- package/dist/dynamic/next/components/package.json +1 -1
- package/dist/esm/components/Drawer/DrawerPanelContent.d.ts +16 -0
- package/dist/esm/components/Drawer/DrawerPanelContent.d.ts.map +1 -1
- package/dist/esm/components/Drawer/DrawerPanelContent.js +55 -15
- package/dist/esm/components/Drawer/DrawerPanelContent.js.map +1 -1
- package/dist/js/components/Drawer/DrawerPanelContent.d.ts +16 -0
- package/dist/js/components/Drawer/DrawerPanelContent.d.ts.map +1 -1
- package/dist/js/components/Drawer/DrawerPanelContent.js +55 -15
- package/dist/js/components/Drawer/DrawerPanelContent.js.map +1 -1
- package/dist/umd/react-core.min.js +1 -1
- package/helpers/package.json +1 -1
- package/layouts/package.json +1 -1
- package/next/package.json +1 -1
- package/package.json +2 -2
- package/src/components/Drawer/DrawerPanelContent.tsx +120 -55
- package/src/components/Drawer/__tests__/DrawerPanelContent.test.tsx +89 -0
- package/src/components/Drawer/examples/Drawer.md +31 -0
- package/src/components/Drawer/examples/DrawerFocusTrap.tsx +58 -0
- package/src/demos/NotificationDrawer/NotificationDrawer.md +2 -1435
- package/src/demos/NotificationDrawer/examples/NotificationDrawerBasic.tsx +557 -0
- package/src/demos/NotificationDrawer/examples/NotificationDrawerGrouped.tsx +796 -0
package/helpers/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"5.1.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-helpers","main":"../dist/js/helpers/index.js","module":"../dist/esm/helpers/index.js","typings":"../dist/esm/helpers/index.d.ts","version":"5.1.1-prerelease.3","private":true}
|
package/layouts/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"5.1.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-layouts","main":"../dist/js/layouts/index.js","module":"../dist/esm/layouts/index.js","typings":"../dist/esm/layouts/index.d.ts","version":"5.1.1-prerelease.3","private":true}
|
package/next/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"5.1.1-prerelease.
|
|
1
|
+
{"name":"@patternfly/react-core-next","main":"../dist/js/next/index.js","module":"../dist/esm/next/index.js","typings":"../dist/esm/next/index.d.ts","version":"5.1.1-prerelease.3","private":true}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "5.1.1-prerelease.
|
|
3
|
+
"version": "5.1.1-prerelease.4",
|
|
4
4
|
"description": "This library provides a set of common React components for use with the PatternFly reference implementation.",
|
|
5
5
|
"main": "dist/js/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -70,5 +70,5 @@
|
|
|
70
70
|
"react": "^17 || ^18",
|
|
71
71
|
"react-dom": "^17 || ^18"
|
|
72
72
|
},
|
|
73
|
-
"gitHead": "
|
|
73
|
+
"gitHead": "12ac5fc7a5280fd5f3fc1ad9bb6134ca028f2ed9"
|
|
74
74
|
}
|
|
@@ -4,6 +4,22 @@ import { css } from '@patternfly/react-styles';
|
|
|
4
4
|
import { DrawerColorVariant, DrawerContext } from './Drawer';
|
|
5
5
|
import { formatBreakpointMods } from '../../helpers/util';
|
|
6
6
|
import { GenerateId } from '../../helpers/GenerateId/GenerateId';
|
|
7
|
+
import { FocusTrap } from '../../helpers/FocusTrap/FocusTrap';
|
|
8
|
+
|
|
9
|
+
export interface DrawerPanelFocusTrapObject {
|
|
10
|
+
/** Enables a focus trap on the drawer panel content. This will also automatically
|
|
11
|
+
* handle focus management when the panel expands and when it collapses. Do not pass
|
|
12
|
+
* this prop if the isStatic prop on the drawer component is true.
|
|
13
|
+
*/
|
|
14
|
+
enabled?: boolean;
|
|
15
|
+
/** The element to focus when the drawer panel content expands. By default the
|
|
16
|
+
* first focusable element will receive focus. If there are no focusable elements, the
|
|
17
|
+
* panel itself will receive focus.
|
|
18
|
+
*/
|
|
19
|
+
elementToFocusOnExpand?: HTMLElement | SVGElement | string;
|
|
20
|
+
/** One or more id's to use for the drawer panel content's accessible label. */
|
|
21
|
+
'aria-labelledby'?: string;
|
|
22
|
+
}
|
|
7
23
|
|
|
8
24
|
export interface DrawerPanelContentProps extends React.HTMLProps<HTMLDivElement> {
|
|
9
25
|
/** Additional classes added to the drawer. */
|
|
@@ -37,6 +53,8 @@ export interface DrawerPanelContentProps extends React.HTMLProps<HTMLDivElement>
|
|
|
37
53
|
};
|
|
38
54
|
/** Color variant of the background of the drawer panel */
|
|
39
55
|
colorVariant?: DrawerColorVariant | 'light-200' | 'no-background' | 'default';
|
|
56
|
+
/** Adds and customizes a focus trap on the drawer panel content. */
|
|
57
|
+
focusTrap?: DrawerPanelFocusTrapObject;
|
|
40
58
|
}
|
|
41
59
|
let isResizing: boolean = null;
|
|
42
60
|
let newSize: number = 0;
|
|
@@ -55,6 +73,7 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
|
|
|
55
73
|
resizeAriaLabel = 'Resize',
|
|
56
74
|
widths,
|
|
57
75
|
colorVariant = DrawerColorVariant.default,
|
|
76
|
+
focusTrap,
|
|
58
77
|
...props
|
|
59
78
|
}: DrawerPanelContentProps) => {
|
|
60
79
|
const panel = React.useRef<HTMLDivElement>();
|
|
@@ -64,6 +83,8 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
|
|
|
64
83
|
React.useContext(DrawerContext);
|
|
65
84
|
const hidden = isStatic ? false : !isExpanded;
|
|
66
85
|
const [isExpandedInternal, setIsExpandedInternal] = React.useState(!hidden);
|
|
86
|
+
const [isFocusTrapActive, setIsFocusTrapActive] = React.useState(false);
|
|
87
|
+
const previouslyFocusedElement = React.useRef(null);
|
|
67
88
|
let currWidth: number = 0;
|
|
68
89
|
let panelRect: DOMRect;
|
|
69
90
|
let right: number;
|
|
@@ -71,6 +92,13 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
|
|
|
71
92
|
let bottom: number;
|
|
72
93
|
let setInitialVals: boolean = true;
|
|
73
94
|
|
|
95
|
+
if (isStatic && focusTrap?.enabled) {
|
|
96
|
+
// eslint-disable-next-line no-console
|
|
97
|
+
console.warn(
|
|
98
|
+
`DrawerPanelContent: The focusTrap.enabled prop cannot be true if the Drawer's isStatic prop is true. This will cause a permanent focus trap.`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
|
|
74
102
|
React.useEffect(() => {
|
|
75
103
|
if (!isStatic && isExpanded) {
|
|
76
104
|
setIsExpandedInternal(isExpanded);
|
|
@@ -246,64 +274,101 @@ export const DrawerPanelContent: React.FunctionComponent<DrawerPanelContentProps
|
|
|
246
274
|
if (maxSize) {
|
|
247
275
|
boundaryCssVars['--pf-v5-c-drawer__panel--md--FlexBasis--max'] = maxSize;
|
|
248
276
|
}
|
|
277
|
+
|
|
278
|
+
const isValidFocusTrap = focusTrap?.enabled && !isStatic;
|
|
279
|
+
const Component = isValidFocusTrap ? FocusTrap : 'div';
|
|
280
|
+
|
|
249
281
|
return (
|
|
250
282
|
<GenerateId prefix="pf-drawer-panel-">
|
|
251
|
-
{(panelId) =>
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
283
|
+
{(panelId) => {
|
|
284
|
+
const focusTrapProps = {
|
|
285
|
+
tabIndex: -1,
|
|
286
|
+
'aria-modal': true,
|
|
287
|
+
role: 'dialog',
|
|
288
|
+
active: isFocusTrapActive,
|
|
289
|
+
'aria-labelledby': focusTrap?.['aria-labelledby'] || id || panelId,
|
|
290
|
+
focusTrapOptions: {
|
|
291
|
+
fallbackFocus: () => panel.current,
|
|
292
|
+
onActivate: () => {
|
|
293
|
+
if (previouslyFocusedElement.current !== document.activeElement) {
|
|
294
|
+
previouslyFocusedElement.current = document.activeElement;
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
onDeactivate: () => {
|
|
298
|
+
previouslyFocusedElement.current &&
|
|
299
|
+
previouslyFocusedElement.current.focus &&
|
|
300
|
+
previouslyFocusedElement.current.focus();
|
|
301
|
+
},
|
|
302
|
+
clickOutsideDeactivates: true,
|
|
303
|
+
returnFocusOnDeactivate: false,
|
|
304
|
+
// FocusTrap's initialFocus can accept false as a value to prevent initial focus.
|
|
305
|
+
// We want to prevent this in case false is ever passed in.
|
|
306
|
+
initialFocus: focusTrap?.elementToFocusOnExpand || undefined,
|
|
307
|
+
escapeDeactivates: false
|
|
308
|
+
}
|
|
309
|
+
};
|
|
310
|
+
|
|
311
|
+
return (
|
|
312
|
+
<Component
|
|
313
|
+
{...(isValidFocusTrap && focusTrapProps)}
|
|
314
|
+
id={id || panelId}
|
|
315
|
+
className={css(
|
|
316
|
+
styles.drawerPanel,
|
|
317
|
+
isResizable && styles.modifiers.resizable,
|
|
318
|
+
hasNoBorder && styles.modifiers.noBorder,
|
|
319
|
+
formatBreakpointMods(widths, styles),
|
|
320
|
+
colorVariant === DrawerColorVariant.light200 && styles.modifiers.light_200,
|
|
321
|
+
colorVariant === DrawerColorVariant.noBackground && styles.modifiers.noBackground,
|
|
322
|
+
className
|
|
323
|
+
)}
|
|
324
|
+
onTransitionEnd={(ev) => {
|
|
325
|
+
if ((ev.target as HTMLElement) === panel.current) {
|
|
326
|
+
if (!hidden && ev.nativeEvent.propertyName === 'transform') {
|
|
327
|
+
onExpand(ev);
|
|
328
|
+
}
|
|
329
|
+
setIsExpandedInternal(!hidden);
|
|
330
|
+
if (isValidFocusTrap && ev.nativeEvent.propertyName === 'transform') {
|
|
331
|
+
setIsFocusTrapActive((prevIsFocusTrapActive) => !prevIsFocusTrapActive);
|
|
332
|
+
}
|
|
268
333
|
}
|
|
269
|
-
|
|
270
|
-
}
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
334
|
+
}}
|
|
335
|
+
hidden={hidden}
|
|
336
|
+
{...((defaultSize || minSize || maxSize) && {
|
|
337
|
+
style: boundaryCssVars as React.CSSProperties
|
|
338
|
+
})}
|
|
339
|
+
{...props}
|
|
340
|
+
ref={panel}
|
|
341
|
+
>
|
|
342
|
+
{isExpandedInternal && (
|
|
343
|
+
<React.Fragment>
|
|
344
|
+
{isResizable && (
|
|
345
|
+
<React.Fragment>
|
|
346
|
+
<div
|
|
347
|
+
className={css(styles.drawerSplitter, position !== 'bottom' && styles.modifiers.vertical)}
|
|
348
|
+
role="separator"
|
|
349
|
+
tabIndex={0}
|
|
350
|
+
aria-orientation={position === 'bottom' ? 'horizontal' : 'vertical'}
|
|
351
|
+
aria-label={resizeAriaLabel}
|
|
352
|
+
aria-valuenow={separatorValue}
|
|
353
|
+
aria-valuemin={0}
|
|
354
|
+
aria-valuemax={100}
|
|
355
|
+
aria-controls={id || panelId}
|
|
356
|
+
onMouseDown={handleMousedown}
|
|
357
|
+
onKeyDown={handleKeys}
|
|
358
|
+
onTouchStart={handleTouchStart}
|
|
359
|
+
ref={splitterRef}
|
|
360
|
+
>
|
|
361
|
+
<div className={css(styles.drawerSplitterHandle)} aria-hidden></div>
|
|
362
|
+
</div>
|
|
363
|
+
<div className={css(styles.drawerPanelMain)}>{children}</div>
|
|
364
|
+
</React.Fragment>
|
|
365
|
+
)}
|
|
366
|
+
{!isResizable && children}
|
|
367
|
+
</React.Fragment>
|
|
368
|
+
)}
|
|
369
|
+
</Component>
|
|
370
|
+
);
|
|
371
|
+
}}
|
|
307
372
|
</GenerateId>
|
|
308
373
|
);
|
|
309
374
|
};
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { DrawerPanelContent } from '../DrawerPanelContent';
|
|
4
|
+
import { Drawer } from '../Drawer';
|
|
5
|
+
|
|
6
|
+
test('Does not render with aria-labelledby by default', () => {
|
|
7
|
+
render(
|
|
8
|
+
<Drawer isExpanded>
|
|
9
|
+
<DrawerPanelContent>Drawer panel content</DrawerPanelContent>
|
|
10
|
+
</Drawer>
|
|
11
|
+
);
|
|
12
|
+
|
|
13
|
+
expect(screen.getByText('Drawer panel content')).not.toHaveAccessibleName();
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test('Renders with aria-labelledby when focusTrap.enabled is true', () => {
|
|
17
|
+
render(
|
|
18
|
+
<Drawer isExpanded>
|
|
19
|
+
<DrawerPanelContent focusTrap={{ enabled: true }}>Drawer panel content</DrawerPanelContent>
|
|
20
|
+
</Drawer>
|
|
21
|
+
);
|
|
22
|
+
|
|
23
|
+
expect(screen.getByText('Drawer panel content')).toHaveAccessibleName('Drawer panel content');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test('Renders with aria-labelledby when id is passed in', () => {
|
|
27
|
+
render(
|
|
28
|
+
<Drawer isExpanded>
|
|
29
|
+
<DrawerPanelContent id="drawer-panel-content" focusTrap={{ enabled: true }}>
|
|
30
|
+
Drawer panel content
|
|
31
|
+
</DrawerPanelContent>
|
|
32
|
+
</Drawer>
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
expect(screen.getByText('Drawer panel content')).toHaveAccessibleName('Drawer panel content');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test('Renders with custom aria-labelledby', () => {
|
|
39
|
+
render(
|
|
40
|
+
<Drawer isExpanded>
|
|
41
|
+
<DrawerPanelContent focusTrap={{ enabled: true, 'aria-labelledby': 'drawer-panel-title' }}>
|
|
42
|
+
<span id="drawer-panel-title">Title</span>
|
|
43
|
+
<span>Drawer panel content</span>
|
|
44
|
+
</DrawerPanelContent>
|
|
45
|
+
</Drawer>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(screen.getByText('Drawer panel content').parentElement).toHaveAccessibleName('Title');
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test('Does not render with aria-modal="true" by default', () => {
|
|
52
|
+
render(
|
|
53
|
+
<Drawer isExpanded>
|
|
54
|
+
<DrawerPanelContent>Drawer panel content</DrawerPanelContent>
|
|
55
|
+
</Drawer>
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
expect(screen.getByText('Drawer panel content')).not.toHaveAttribute('aria-modal');
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test('Renders with aria-modal="true" when focusTrap.enabled is true', () => {
|
|
62
|
+
render(
|
|
63
|
+
<Drawer isExpanded>
|
|
64
|
+
<DrawerPanelContent focusTrap={{ enabled: true }}>Drawer panel content</DrawerPanelContent>
|
|
65
|
+
</Drawer>
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
expect(screen.getByText('Drawer panel content')).toHaveAttribute('aria-modal', 'true');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test('Does not render with role="dialog" by default', () => {
|
|
72
|
+
render(
|
|
73
|
+
<Drawer isExpanded>
|
|
74
|
+
<DrawerPanelContent>Drawer panel content</DrawerPanelContent>
|
|
75
|
+
</Drawer>
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(screen.queryByRole('dialog')).not.toBeInTheDocument();
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test('Renders with role="dialog" when focusTrap.enabled is true', () => {
|
|
82
|
+
render(
|
|
83
|
+
<Drawer isExpanded>
|
|
84
|
+
<DrawerPanelContent focusTrap={{ enabled: true }}>Drawer panel content</DrawerPanelContent>
|
|
85
|
+
</Drawer>
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
89
|
+
});
|
|
@@ -13,6 +13,7 @@ propComponents:
|
|
|
13
13
|
DrawerActions,
|
|
14
14
|
DrawerCloseButton,
|
|
15
15
|
DrawerColorVariant,
|
|
16
|
+
DrawerPanelFocusTrapObject
|
|
16
17
|
]
|
|
17
18
|
section: components
|
|
18
19
|
---
|
|
@@ -22,56 +23,67 @@ section: components
|
|
|
22
23
|
### Basic
|
|
23
24
|
|
|
24
25
|
```ts file="./DrawerBasic.tsx"
|
|
26
|
+
|
|
25
27
|
```
|
|
26
28
|
|
|
27
29
|
### Panel on right
|
|
28
30
|
|
|
29
31
|
```ts file="./DrawerPanelRight.tsx"
|
|
32
|
+
|
|
30
33
|
```
|
|
31
34
|
|
|
32
35
|
### Panel on left
|
|
33
36
|
|
|
34
37
|
```ts file="./DrawerPanelLeft.tsx"
|
|
38
|
+
|
|
35
39
|
```
|
|
36
40
|
|
|
37
41
|
### Panel on bottom
|
|
38
42
|
|
|
39
43
|
```ts file="./DrawerPanelBottom.tsx"
|
|
44
|
+
|
|
40
45
|
```
|
|
41
46
|
|
|
42
47
|
### Basic inline
|
|
43
48
|
|
|
44
49
|
```ts file="./DrawerBasicInline.tsx"
|
|
50
|
+
|
|
45
51
|
```
|
|
46
52
|
|
|
47
53
|
### Inline panel on right
|
|
48
54
|
|
|
49
55
|
```ts file="./DrawerInlinePanelRight.tsx"
|
|
56
|
+
|
|
50
57
|
```
|
|
51
58
|
|
|
52
59
|
### Inline panel on left
|
|
53
60
|
|
|
54
61
|
```ts file="./DrawerInlinePanelLeft.tsx"
|
|
62
|
+
|
|
55
63
|
```
|
|
56
64
|
|
|
57
65
|
### Stacked content body elements
|
|
58
66
|
|
|
59
67
|
```ts file="./DrawerStackedContentBodyElements.tsx"
|
|
68
|
+
|
|
60
69
|
```
|
|
61
70
|
|
|
62
71
|
### Modified content padding
|
|
63
72
|
|
|
64
73
|
```ts file="DrawerModifiedContentPadding.tsx"
|
|
74
|
+
|
|
65
75
|
```
|
|
66
76
|
|
|
67
77
|
### Modified panel padding
|
|
68
78
|
|
|
69
79
|
```ts file="DrawerModifiedPanelPadding.tsx"
|
|
80
|
+
|
|
70
81
|
```
|
|
71
82
|
|
|
72
83
|
### Additional section above drawer content
|
|
73
84
|
|
|
74
85
|
```ts file="DrawerAdditionalSectionAboveContent.tsx"
|
|
86
|
+
|
|
75
87
|
```
|
|
76
88
|
|
|
77
89
|
### Static drawer
|
|
@@ -79,34 +91,53 @@ section: components
|
|
|
79
91
|
**Note:** For mobile viewports, all drawer variants behave the same way. At the `md` breakpoint, or where `.pf-m-static{-on-[lg, xl, 2xl]}` is applied, the `static drawer` variant’s `close button` is automatically hidden because the drawer panel doesn’t close by design.
|
|
80
92
|
|
|
81
93
|
```ts file="DrawerStatic.tsx"
|
|
94
|
+
|
|
82
95
|
```
|
|
83
96
|
|
|
84
97
|
### Breakpoint
|
|
85
98
|
|
|
86
99
|
```ts file="DrawerBreakpoint.tsx"
|
|
100
|
+
|
|
87
101
|
```
|
|
88
102
|
|
|
89
103
|
### Resizable on right
|
|
90
104
|
|
|
91
105
|
```ts file="DrawerResizableOnRight.tsx"
|
|
106
|
+
|
|
92
107
|
```
|
|
93
108
|
|
|
94
109
|
### Resizable on left
|
|
95
110
|
|
|
96
111
|
```ts file="DrawerResizableOnLeft.tsx"
|
|
112
|
+
|
|
97
113
|
```
|
|
98
114
|
|
|
99
115
|
### Resizable on bottom
|
|
100
116
|
|
|
101
117
|
```ts file="DrawerResizableOnBottom.tsx"
|
|
118
|
+
|
|
102
119
|
```
|
|
103
120
|
|
|
104
121
|
### Resizable on inline
|
|
105
122
|
|
|
106
123
|
```ts file="DrawerResizableOnInline.tsx"
|
|
124
|
+
|
|
107
125
|
```
|
|
108
126
|
|
|
109
127
|
### Panel with secondary background
|
|
110
128
|
|
|
111
129
|
```ts file="DrawerSecondaryBackground.tsx"
|
|
130
|
+
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
### With focus trap
|
|
134
|
+
|
|
135
|
+
When a [focus trap](/accessibility/product-development-guide#trapping-focus) is enabled on an element, a user will only be able to interact with the contents of that element until the focus trap is closed or deactivated.
|
|
136
|
+
|
|
137
|
+
To enable and customize a focus trap on a drawer panel, apply the `focusTrap` property to the `<DrawerPanelContent>` component. Enabling a focus trap with `focusTrap.enabled` will also automatically place focus on the first focusable element when the drawer panel expands, and return focus to the previously focused element when it collapses.
|
|
138
|
+
|
|
139
|
+
To customize which element receives focus when the drawer panel expands, use the `focusTrap.elementToFocusOnExpand` property.
|
|
140
|
+
|
|
141
|
+
```ts file="./DrawerFocusTrap.tsx"
|
|
142
|
+
|
|
112
143
|
```
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
Drawer,
|
|
4
|
+
DrawerPanelContent,
|
|
5
|
+
DrawerContent,
|
|
6
|
+
DrawerContentBody,
|
|
7
|
+
DrawerHead,
|
|
8
|
+
DrawerActions,
|
|
9
|
+
DrawerCloseButton,
|
|
10
|
+
Button
|
|
11
|
+
} from '@patternfly/react-core';
|
|
12
|
+
|
|
13
|
+
export const DrawerFocusTrap: React.FunctionComponent = () => {
|
|
14
|
+
const [isExpanded, setIsExpanded] = React.useState(false);
|
|
15
|
+
|
|
16
|
+
const onClick = () => {
|
|
17
|
+
setIsExpanded(!isExpanded);
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
const onCloseClick = () => {
|
|
21
|
+
setIsExpanded(false);
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
// An onKeyDown property must be passed to the Drawer component to handle closing
|
|
25
|
+
// the drawer panel and deactivating the focus trap via the Escape key.
|
|
26
|
+
const onEscape = (event: React.KeyboardEvent) => {
|
|
27
|
+
if (event.key === 'Escape') {
|
|
28
|
+
setIsExpanded(false);
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
const panelContent = (
|
|
33
|
+
<DrawerPanelContent focusTrap={{ enabled: true }}>
|
|
34
|
+
<DrawerHead>
|
|
35
|
+
<span>drawer-panel</span>
|
|
36
|
+
<DrawerActions>
|
|
37
|
+
<DrawerCloseButton onClick={onCloseClick} />
|
|
38
|
+
</DrawerActions>
|
|
39
|
+
</DrawerHead>
|
|
40
|
+
</DrawerPanelContent>
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
const drawerContent =
|
|
44
|
+
'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Phasellus pretium est a porttitor vehicula. Quisque vel commodo urna. Morbi mattis rutrum ante, id vehicula ex accumsan ut. Morbi viverra, eros vel porttitor facilisis, eros purus aliquet erat,nec lobortis felis elit pulvinar sem. Vivamus vulputate, risus eget commodo eleifend, eros nibh porta quam, vitae lacinia leo libero at magna. Maecenas aliquam sagittis orci, et posuere nisi ultrices sit amet. Aliquam ex odio, malesuada sed posuere quis, pellentesque at mauris. Phasellus venenatis massa ex, eget pulvinar libero auctor pretium. Aliquam erat volutpat. Duis euismod justo in quam ullamcorper, in commodo massa vulputate.';
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<React.Fragment>
|
|
48
|
+
<Button aria-expanded={isExpanded} onClick={onClick}>
|
|
49
|
+
Toggle drawer with focus trap
|
|
50
|
+
</Button>
|
|
51
|
+
<Drawer onKeyDown={onEscape} isExpanded={isExpanded}>
|
|
52
|
+
<DrawerContent panelContent={panelContent}>
|
|
53
|
+
<DrawerContentBody>{drawerContent}</DrawerContentBody>
|
|
54
|
+
</DrawerContent>
|
|
55
|
+
</Drawer>
|
|
56
|
+
</React.Fragment>
|
|
57
|
+
);
|
|
58
|
+
};
|