@patternfly/react-core 6.4.1-prerelease.0 → 6.4.1-prerelease.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 +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/ClipboardCopy/package.json +1 -1
- package/dist/dynamic/components/CodeBlock/package.json +1 -1
- package/dist/dynamic/components/Content/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/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/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/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/Chip/package.json +1 -1
- package/dist/dynamic/deprecated/components/DragDrop/package.json +1 -1
- package/dist/dynamic/deprecated/components/DualListSelector/package.json +1 -1
- package/dist/dynamic/deprecated/components/Modal/package.json +1 -1
- package/dist/dynamic/deprecated/components/Tile/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/AnimationsProvider/AnimationsProvider/package.json +1 -1
- package/dist/dynamic/helpers/AnimationsProvider/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/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/styles/package.json +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts +4 -0
- package/dist/esm/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSection.js +5 -3
- package/dist/esm/components/ExpandableSection/ExpandableSection.js.map +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.d.ts +4 -0
- package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.d.ts.map +1 -1
- package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.js +2 -2
- package/dist/esm/components/ExpandableSection/ExpandableSectionToggle.js.map +1 -1
- package/dist/esm/components/Modal/Modal.d.ts +2 -0
- package/dist/esm/components/Modal/Modal.d.ts.map +1 -1
- package/dist/esm/components/Modal/Modal.js.map +1 -1
- package/dist/esm/components/Modal/ModalContent.d.ts +2 -0
- package/dist/esm/components/Modal/ModalContent.d.ts.map +1 -1
- package/dist/esm/components/Modal/ModalContent.js +2 -2
- package/dist/esm/components/Modal/ModalContent.js.map +1 -1
- package/dist/esm/helpers/FocusTrap/FocusTrap.d.ts +2 -0
- package/dist/esm/helpers/FocusTrap/FocusTrap.d.ts.map +1 -1
- package/dist/esm/helpers/FocusTrap/FocusTrap.js.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSection.d.ts +4 -0
- package/dist/js/components/ExpandableSection/ExpandableSection.d.ts.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSection.js +5 -3
- package/dist/js/components/ExpandableSection/ExpandableSection.js.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSectionToggle.d.ts +4 -0
- package/dist/js/components/ExpandableSection/ExpandableSectionToggle.d.ts.map +1 -1
- package/dist/js/components/ExpandableSection/ExpandableSectionToggle.js +2 -2
- package/dist/js/components/ExpandableSection/ExpandableSectionToggle.js.map +1 -1
- package/dist/js/components/Modal/Modal.d.ts +2 -0
- package/dist/js/components/Modal/Modal.d.ts.map +1 -1
- package/dist/js/components/Modal/Modal.js.map +1 -1
- package/dist/js/components/Modal/ModalContent.d.ts +2 -0
- package/dist/js/components/Modal/ModalContent.d.ts.map +1 -1
- package/dist/js/components/Modal/ModalContent.js +2 -2
- package/dist/js/components/Modal/ModalContent.js.map +1 -1
- package/dist/js/helpers/FocusTrap/FocusTrap.d.ts +2 -0
- package/dist/js/helpers/FocusTrap/FocusTrap.d.ts.map +1 -1
- package/dist/js/helpers/FocusTrap/FocusTrap.js.map +1 -1
- package/dist/umd/assets/{output-CSllYx5z.css → output-LI8hocVw.css} +18858 -18858
- 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/ExpandableSection/ExpandableSection.tsx +10 -0
- package/src/components/ExpandableSection/ExpandableSectionToggle.tsx +8 -0
- package/src/components/ExpandableSection/__tests__/ExpandableSection.test.tsx +17 -0
- package/src/components/ExpandableSection/__tests__/ExpandableSectionToggle.test.tsx +17 -0
- package/src/components/Modal/Modal.tsx +2 -0
- package/src/components/Modal/ModalContent.tsx +4 -0
- package/src/components/Modal/__tests__/Modal.test.tsx +9 -0
- package/src/components/Modal/__tests__/ModalContent.test.tsx +17 -1
- package/src/components/Modal/examples/Modal.md +14 -5
- package/src/components/Modal/examples/ModalWithDropdown.tsx +34 -7
- package/src/demos/SearchInput/SearchInput.md +2 -487
- package/src/demos/SearchInput/examples/SearchInputAdvancedComposable.tsx +322 -0
- package/src/demos/SearchInput/examples/SearchInputAutocomplete.tsx +165 -0
- package/src/helpers/FocusTrap/FocusTrap.tsx +2 -0
- package/src/helpers/FocusTrap/__tests__/FocusTrap.test.tsx +17 -0
- package/src/helpers/FocusTrap/__tests__/Generated/FocusTrap.test.tsx +3 -3
- package/src/helpers/OUIA/OUIA.md +2 -10
- package/src/helpers/OUIA/examples/OuiaExample.tsx +11 -0
- package/src/layouts/Bullseye/examples/Bullseye.md +1 -5
- package/src/layouts/Bullseye/examples/BullseyeBasic.tsx +7 -0
- package/src/layouts/Flex/examples/Flex.md +17 -209
- package/src/layouts/Flex/examples/FlexAdjustingWidth.tsx +18 -0
- package/src/layouts/Flex/examples/FlexBasic.tsx +11 -0
- package/src/layouts/Flex/examples/FlexCanGrow.tsx +18 -0
- package/src/layouts/Flex/examples/FlexColumnGap.tsx +16 -0
- package/src/layouts/Flex/examples/FlexColumnLayout.tsx +9 -0
- package/src/layouts/Flex/examples/FlexColumnWidths.tsx +18 -0
- package/src/layouts/Flex/examples/FlexDefaultLayout.tsx +11 -0
- package/src/layouts/Flex/examples/FlexGap.tsx +16 -0
- package/src/layouts/Flex/examples/FlexIndividuallySpaced.tsx +14 -0
- package/src/layouts/Flex/examples/FlexInline.tsx +11 -0
- package/src/layouts/Flex/examples/FlexNestedItems.tsx +15 -0
- package/src/layouts/Flex/examples/FlexNesting.tsx +15 -0
- package/src/layouts/Flex/examples/FlexNestingInColumns.tsx +15 -0
- package/src/layouts/Flex/examples/FlexRowGap.tsx +16 -0
- package/src/layouts/Flex/examples/FlexSpacingNone.tsx +11 -0
- package/src/layouts/Flex/examples/FlexSpacingXl.tsx +11 -0
- package/src/layouts/Flex/examples/FlexStackingElements.tsx +18 -0
- package/src/layouts/Level/examples/Level.md +3 -15
- package/src/layouts/Level/examples/LevelBasic.tsx +9 -0
- package/src/layouts/Level/examples/LevelWithGutters.tsx +9 -0
- package/src/layouts/Split/examples/Split.md +4 -34
- package/src/layouts/Split/examples/SplitBasic.tsx +9 -0
- package/src/layouts/Split/examples/SplitWithGutter.tsx +9 -0
- package/src/layouts/Split/examples/SplitWrappable.tsx +20 -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":"6.4.
|
|
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":"6.4.1-prerelease.1","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":"6.4.
|
|
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":"6.4.1-prerelease.1","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":"6.4.
|
|
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":"6.4.1-prerelease.1","private":true}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@patternfly/react-core",
|
|
3
|
-
"version": "6.4.1-prerelease.
|
|
3
|
+
"version": "6.4.1-prerelease.2",
|
|
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",
|
|
@@ -63,5 +63,5 @@
|
|
|
63
63
|
"react": "^17 || ^18 || ^19",
|
|
64
64
|
"react-dom": "^17 || ^18 || ^19"
|
|
65
65
|
},
|
|
66
|
-
"gitHead": "
|
|
66
|
+
"gitHead": "e78f9c42128c8500e478eef554711ddf4b73fe00"
|
|
67
67
|
}
|
|
@@ -56,6 +56,10 @@ export interface ExpandableSectionProps extends Omit<React.HTMLProps<HTMLDivElem
|
|
|
56
56
|
* both are specified; used for uncontrolled expandable with dynamic toggle text).
|
|
57
57
|
*/
|
|
58
58
|
toggleTextExpanded?: string;
|
|
59
|
+
/** Accessible name via human readable string for the expandable section toggle. */
|
|
60
|
+
toggleAriaLabel?: string;
|
|
61
|
+
/** Accessible name via space delimtted list of IDs for the expandable section toggle. */
|
|
62
|
+
toggleAriaLabelledBy?: string;
|
|
59
63
|
/** Truncates the expandable content to the specified number of lines when using the
|
|
60
64
|
* "truncate" variant.
|
|
61
65
|
*/
|
|
@@ -109,6 +113,8 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
|
|
|
109
113
|
toggleText: '',
|
|
110
114
|
toggleTextExpanded: '',
|
|
111
115
|
toggleTextCollapsed: '',
|
|
116
|
+
toggleAriaLabel: undefined,
|
|
117
|
+
toggleAriaLabelledBy: undefined,
|
|
112
118
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
113
119
|
onToggle: (event, isExpanded): void => undefined,
|
|
114
120
|
isDetached: false,
|
|
@@ -196,6 +202,8 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
|
|
|
196
202
|
toggleTextExpanded,
|
|
197
203
|
toggleTextCollapsed,
|
|
198
204
|
toggleContent,
|
|
205
|
+
toggleAriaLabel,
|
|
206
|
+
toggleAriaLabelledBy,
|
|
199
207
|
children,
|
|
200
208
|
isExpanded,
|
|
201
209
|
isDetached,
|
|
@@ -254,6 +262,8 @@ class ExpandableSection extends Component<ExpandableSectionProps, ExpandableSect
|
|
|
254
262
|
</span>
|
|
255
263
|
)
|
|
256
264
|
})}
|
|
265
|
+
aria-label={toggleAriaLabel}
|
|
266
|
+
aria-labelledby={toggleAriaLabelledBy}
|
|
257
267
|
>
|
|
258
268
|
{toggleContent || computedToggleText}
|
|
259
269
|
</Button>
|
|
@@ -30,6 +30,10 @@ export interface ExpandableSectionToggleProps extends Omit<React.HTMLProps<HTMLD
|
|
|
30
30
|
onToggle?: (isExpanded: boolean) => void;
|
|
31
31
|
/** Flag indicating that the expandable section and expandable toggle are detached from one another. */
|
|
32
32
|
isDetached?: boolean;
|
|
33
|
+
/** Accessible name via human readable string for the expandable section toggle. */
|
|
34
|
+
toggleAriaLabel?: string;
|
|
35
|
+
/** Accessible name via space delimtted list of IDs for the expandable section toggle. */
|
|
36
|
+
toggleAriaLabelledBy?: string;
|
|
33
37
|
}
|
|
34
38
|
|
|
35
39
|
export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionToggleProps> = ({
|
|
@@ -42,6 +46,8 @@ export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionT
|
|
|
42
46
|
direction = 'down',
|
|
43
47
|
hasTruncatedContent = false,
|
|
44
48
|
isDetached,
|
|
49
|
+
toggleAriaLabel,
|
|
50
|
+
toggleAriaLabelledBy,
|
|
45
51
|
...props
|
|
46
52
|
}: ExpandableSectionToggleProps) => (
|
|
47
53
|
<div
|
|
@@ -74,6 +80,8 @@ export const ExpandableSectionToggle: React.FunctionComponent<ExpandableSectionT
|
|
|
74
80
|
</span>
|
|
75
81
|
)
|
|
76
82
|
})}
|
|
83
|
+
aria-label={toggleAriaLabel}
|
|
84
|
+
aria-labelledby={toggleAriaLabelledBy}
|
|
77
85
|
>
|
|
78
86
|
{children}
|
|
79
87
|
</Button>
|
|
@@ -191,3 +191,20 @@ test('Renders with class pf-m-detached when isDetached is true and direction is
|
|
|
191
191
|
|
|
192
192
|
expect(screen.getByText('Test content').parentElement).toHaveClass('pf-m-detached');
|
|
193
193
|
});
|
|
194
|
+
|
|
195
|
+
test('Renders with aria-label when toggleAriaLabel is passed', () => {
|
|
196
|
+
render(<ExpandableSection toggleAriaLabel="Test label"></ExpandableSection>);
|
|
197
|
+
|
|
198
|
+
expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => {
|
|
202
|
+
render(
|
|
203
|
+
<>
|
|
204
|
+
<div id="test-id">Test label</div>
|
|
205
|
+
<ExpandableSection toggleAriaLabelledBy="test-id"></ExpandableSection>
|
|
206
|
+
</>
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
|
|
210
|
+
});
|
|
@@ -30,3 +30,20 @@ test('Renders with class pf-m-detached when isDetached is true', () => {
|
|
|
30
30
|
|
|
31
31
|
expect(screen.getByTestId('test-id')).toHaveClass('pf-m-detached');
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
test('Renders with aria-label when toggleAriaLabel is passed', () => {
|
|
35
|
+
render(<ExpandableSectionToggle toggleAriaLabel="Test label"></ExpandableSectionToggle>);
|
|
36
|
+
|
|
37
|
+
expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('Renders with aria-labelledby when toggleAriaLabelledBy is passed', () => {
|
|
41
|
+
render(
|
|
42
|
+
<>
|
|
43
|
+
<div id="test-id">Test label</div>
|
|
44
|
+
<ExpandableSectionToggle toggleAriaLabelledBy="test-id"></ExpandableSectionToggle>
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(screen.getByRole('button')).toHaveAccessibleName('Test label');
|
|
49
|
+
});
|
|
@@ -27,6 +27,8 @@ export interface ModalProps extends React.HTMLProps<HTMLDivElement>, OUIAProps {
|
|
|
27
27
|
* focusable element will receive focus.
|
|
28
28
|
*/
|
|
29
29
|
elementToFocus?: HTMLElement | SVGElement | string;
|
|
30
|
+
/** Id of the focus trap in the ModalContent component */
|
|
31
|
+
focusTrapId?: string;
|
|
30
32
|
/** An id to use for the modal box container. */
|
|
31
33
|
id?: string;
|
|
32
34
|
/** Flag to show the modal. */
|
|
@@ -29,6 +29,8 @@ export interface ModalContentProps extends OUIAProps {
|
|
|
29
29
|
* focusable element will receive focus.
|
|
30
30
|
*/
|
|
31
31
|
elementToFocus?: HTMLElement | SVGElement | string;
|
|
32
|
+
/** Id of the focus trap */
|
|
33
|
+
focusTrapId?: string;
|
|
32
34
|
/** Flag to show the modal. */
|
|
33
35
|
isOpen?: boolean;
|
|
34
36
|
/** A callback for when the close button is clicked. */
|
|
@@ -69,6 +71,7 @@ export const ModalContent: React.FunctionComponent<ModalContentProps> = ({
|
|
|
69
71
|
ouiaId,
|
|
70
72
|
ouiaSafe = true,
|
|
71
73
|
elementToFocus,
|
|
74
|
+
focusTrapId,
|
|
72
75
|
...props
|
|
73
76
|
}: ModalContentProps) => {
|
|
74
77
|
if (!isOpen) {
|
|
@@ -122,6 +125,7 @@ export const ModalContent: React.FunctionComponent<ModalContentProps> = ({
|
|
|
122
125
|
initialFocus: elementToFocus || undefined
|
|
123
126
|
}}
|
|
124
127
|
className={css(bullsEyeStyles.bullseye)}
|
|
128
|
+
id={focusTrapId}
|
|
125
129
|
>
|
|
126
130
|
{modalBox}
|
|
127
131
|
</FocusTrap>
|
|
@@ -172,4 +172,13 @@ describe('Modal', () => {
|
|
|
172
172
|
expect(asideSibling).not.toHaveAttribute('aria-hidden');
|
|
173
173
|
expect(articleSibling).not.toHaveAttribute('aria-hidden');
|
|
174
174
|
});
|
|
175
|
+
|
|
176
|
+
test('Modal can add id to focus trap correctly for use with dropdowns', () => {
|
|
177
|
+
render(<Modal focusTrapId="focus-trap" isOpen onClose={jest.fn()} children="modal content" />);
|
|
178
|
+
expect(screen.getByRole('dialog', { name: /modal content/i }).parentElement).toHaveAttribute('id', 'focus-trap');
|
|
179
|
+
expect(screen.getByRole('dialog', { name: /modal content/i }).parentElement).toHaveAttribute(
|
|
180
|
+
'class',
|
|
181
|
+
'pf-v6-l-bullseye'
|
|
182
|
+
);
|
|
183
|
+
});
|
|
175
184
|
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render } from '@testing-library/react';
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
2
|
|
|
3
3
|
import { ModalContent } from '../ModalContent';
|
|
4
4
|
|
|
@@ -43,3 +43,19 @@ test('Modal Content Test with onclose', () => {
|
|
|
43
43
|
);
|
|
44
44
|
expect(asFragment()).toMatchSnapshot();
|
|
45
45
|
});
|
|
46
|
+
|
|
47
|
+
test('Modal content can add id to focus trap correctly for use with dropdowns', () => {
|
|
48
|
+
render(
|
|
49
|
+
<ModalContent focusTrapId="focus-trap" isOpen {...modalContentProps}>
|
|
50
|
+
This is a ModalBox header
|
|
51
|
+
</ModalContent>
|
|
52
|
+
);
|
|
53
|
+
expect(screen.getByRole('dialog', { name: /This is a ModalBox header/i }).parentElement).toHaveAttribute(
|
|
54
|
+
'id',
|
|
55
|
+
'focus-trap'
|
|
56
|
+
);
|
|
57
|
+
expect(screen.getByRole('dialog', { name: /This is a ModalBox header/i }).parentElement).toHaveAttribute(
|
|
58
|
+
'class',
|
|
59
|
+
'pf-v6-l-bullseye'
|
|
60
|
+
);
|
|
61
|
+
});
|
|
@@ -17,7 +17,7 @@ import formStyles from '@patternfly/react-styles/css/components/Form/form';
|
|
|
17
17
|
|
|
18
18
|
### Basic modals
|
|
19
19
|
|
|
20
|
-
Basic modals give users the option to either confirm or cancel an action.
|
|
20
|
+
Basic modals give users the option to either confirm or cancel an action.
|
|
21
21
|
|
|
22
22
|
To flag an open modal, use the `isOpen` property. To execute a callback when a modal is closed, use the `onClose` property.
|
|
23
23
|
|
|
@@ -71,7 +71,7 @@ To choose a specific width for a modal, use the `width` property. The following
|
|
|
71
71
|
|
|
72
72
|
### Custom header
|
|
73
73
|
|
|
74
|
-
To add a custom header to a modal, your custom content must be passed as a child of the `<ModalHeader>` component. Do not pass the `title` property to `<ModalHeader>` when using a custom header.
|
|
74
|
+
To add a custom header to a modal, your custom content must be passed as a child of the `<ModalHeader>` component. Do not pass the `title` property to `<ModalHeader>` when using a custom header.
|
|
75
75
|
|
|
76
76
|
```ts file="./ModalCustomHeader.tsx"
|
|
77
77
|
|
|
@@ -113,9 +113,18 @@ To guide users through a series of steps in a modal, you can add a [wizard](/com
|
|
|
113
113
|
|
|
114
114
|
### With dropdown
|
|
115
115
|
|
|
116
|
-
To present a menu of actions or links to a user, you can add a [dropdown](/components/menus/dropdown) to a modal.
|
|
116
|
+
To present a menu of actions or links to a user, you can add a [dropdown](/components/menus/dropdown) to a modal.
|
|
117
117
|
|
|
118
|
-
|
|
118
|
+
Using the Dropdown's default append location will interfere with keyboard accessibility due to the modal's
|
|
119
|
+
built-in focus trap. To allow the dropdown to visually break out of the modal container, set the Dropdown's
|
|
120
|
+
`popperProps appendTo` property to id of the focus trap for the modal. This can be done by adding prop
|
|
121
|
+
`focusTrapId` to the modal, and then setting the append location to that as per this example. Otherwise you
|
|
122
|
+
can use `inline` to allow it to scroll within the modal itself. Appending to the focus trap should allow the
|
|
123
|
+
menu to expand visually outside the Modal (no scrollbar created in the Modal itself), and still allow
|
|
124
|
+
focusing the content within that menu via keyboard. You should also handle the modal's closing behavior by
|
|
125
|
+
listening to the
|
|
126
|
+
`onEscapePress` callback on the `<Modal>` component. This allows the "escape" key to collapse the
|
|
127
|
+
dropdown without closing the entire modal.
|
|
119
128
|
|
|
120
129
|
```ts file="./ModalWithDropdown.tsx"
|
|
121
130
|
|
|
@@ -141,7 +150,7 @@ To enable form submission from a button in the modal's footer (outside of the `<
|
|
|
141
150
|
|
|
142
151
|
### Custom focus
|
|
143
152
|
|
|
144
|
-
To customize which element inside the modal receives focus when initially opened, use the `elementToFocus` property`.
|
|
153
|
+
To customize which element inside the modal receives focus when initially opened, use the `elementToFocus` property`.
|
|
145
154
|
|
|
146
155
|
```ts file="./ModalCustomFocus.tsx"
|
|
147
156
|
|
|
@@ -32,8 +32,10 @@ export const ModalWithDropdown: React.FunctionComponent = () => {
|
|
|
32
32
|
};
|
|
33
33
|
|
|
34
34
|
const onFocus = () => {
|
|
35
|
-
|
|
36
|
-
|
|
35
|
+
if (typeof document !== 'undefined') {
|
|
36
|
+
const element = document.getElementById('modal-dropdown-toggle');
|
|
37
|
+
(element as HTMLElement)?.focus();
|
|
38
|
+
}
|
|
37
39
|
};
|
|
38
40
|
|
|
39
41
|
const onEscapePress = (event: KeyboardEvent) => {
|
|
@@ -45,6 +47,16 @@ export const ModalWithDropdown: React.FunctionComponent = () => {
|
|
|
45
47
|
}
|
|
46
48
|
};
|
|
47
49
|
|
|
50
|
+
const getAppendLocation = () => {
|
|
51
|
+
// document doesn't exist when PatternFly website docs framework gets pre-rendered
|
|
52
|
+
// this is just to avoid that issue - works fine at runtime without it
|
|
53
|
+
if (typeof document !== 'undefined' && document.getElementById) {
|
|
54
|
+
return document.getElementById('modal-with-dropdown-focus-trap');
|
|
55
|
+
} else {
|
|
56
|
+
return 'inline';
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
|
|
48
60
|
return (
|
|
49
61
|
<Fragment>
|
|
50
62
|
<Button variant="primary" onClick={handleModalToggle}>
|
|
@@ -57,14 +69,21 @@ export const ModalWithDropdown: React.FunctionComponent = () => {
|
|
|
57
69
|
onEscapePress={onEscapePress}
|
|
58
70
|
aria-labelledby="modal-with-dropdown"
|
|
59
71
|
aria-describedby="modal-box-body-with-dropdown"
|
|
72
|
+
focusTrapId="modal-with-dropdown-focus-trap"
|
|
60
73
|
>
|
|
61
74
|
<ModalHeader title="Dropdown modal" labelId="modal-with-dropdown" />
|
|
62
75
|
<ModalBody id="modal-box-body-with-dropdown">
|
|
63
76
|
<div>
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
77
|
+
Using the Dropdown's default append location will interfere with keyboard accessibility due to the modal's
|
|
78
|
+
built-in focus trap. To allow the dropdown to visually break out of the modal container, set the Dropdown's
|
|
79
|
+
popperProps appendTo property to id of the focus trap for the modal. This can be done by adding prop
|
|
80
|
+
focusTrapId to the modal, and then setting the append location to that as per this example. Otherwise you
|
|
81
|
+
can use "inline" to allow it to scroll within the modal itself. Appending to the focus trap should allow the
|
|
82
|
+
menu to expand visually outside the Modal (no scrollbar created in the Modal itself), and still allow
|
|
83
|
+
focusing the content within that menu via keyboard. You should also handle the modal's closing behavior by
|
|
84
|
+
listening to the
|
|
85
|
+
<em>onEscapePress</em> callback on the Modal component. This allows the "escape" key to collapse the
|
|
86
|
+
dropdown without closing the entire modal.
|
|
68
87
|
</div>
|
|
69
88
|
<br />
|
|
70
89
|
<div>
|
|
@@ -73,10 +92,18 @@ export const ModalWithDropdown: React.FunctionComponent = () => {
|
|
|
73
92
|
onSelect={onSelect}
|
|
74
93
|
onOpenChange={(isOpen: boolean) => setIsDropdownOpen(isOpen)}
|
|
75
94
|
toggle={(toggleRef: React.Ref<MenuToggleElement>) => (
|
|
76
|
-
<MenuToggle
|
|
95
|
+
<MenuToggle
|
|
96
|
+
id="modal-dropdown-toggle"
|
|
97
|
+
ref={toggleRef}
|
|
98
|
+
onClick={handleDropdownToggle}
|
|
99
|
+
isExpanded={isDropdownOpen}
|
|
100
|
+
>
|
|
77
101
|
Dropdown
|
|
78
102
|
</MenuToggle>
|
|
79
103
|
)}
|
|
104
|
+
popperProps={{
|
|
105
|
+
appendTo: getAppendLocation()
|
|
106
|
+
}}
|
|
80
107
|
>
|
|
81
108
|
<DropdownList>
|
|
82
109
|
<DropdownItem value={0} key="action">
|