@khanacademy/wonder-blocks-modal 2.3.11 → 3.0.0
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 +6 -0
- package/dist/es/index.js +5 -3
- package/dist/index.js +10 -3
- package/package.json +1 -1
- package/src/components/__docs__/modal-launcher.stories.js +2 -1
- package/src/components/__docs__/one-pane-dialog.argtypes.js +6 -0
- package/src/components/__tests__/one-pane-dialog.test.js +17 -0
- package/src/components/modal-dialog.js +16 -4
- package/src/components/one-pane-dialog.js +8 -3
package/CHANGELOG.md
CHANGED
package/dist/es/index.js
CHANGED
|
@@ -21,7 +21,7 @@ class ModalDialog extends React.Component {
|
|
|
21
21
|
children,
|
|
22
22
|
testId,
|
|
23
23
|
"aria-labelledby": ariaLabelledBy,
|
|
24
|
-
"aria-
|
|
24
|
+
"aria-describedby": ariaDescribedBy
|
|
25
25
|
} = this.props;
|
|
26
26
|
const contextValue = {
|
|
27
27
|
ssrSize: "large",
|
|
@@ -41,7 +41,7 @@ class ModalDialog extends React.Component {
|
|
|
41
41
|
role: role,
|
|
42
42
|
"aria-modal": "true",
|
|
43
43
|
"aria-labelledby": ariaLabelledBy,
|
|
44
|
-
"aria-
|
|
44
|
+
"aria-describedby": ariaDescribedBy,
|
|
45
45
|
style: styles.dialog,
|
|
46
46
|
testId: testId
|
|
47
47
|
}, children), above && React.createElement(View, {
|
|
@@ -806,7 +806,8 @@ class OnePaneDialog extends React.Component {
|
|
|
806
806
|
closeButtonVisible,
|
|
807
807
|
testId,
|
|
808
808
|
titleId,
|
|
809
|
-
role
|
|
809
|
+
role,
|
|
810
|
+
"aria-describedby": ariaDescribedBy
|
|
810
811
|
} = this.props;
|
|
811
812
|
return React.createElement(MediaLayout, {
|
|
812
813
|
styleSheets: styleSheets
|
|
@@ -821,6 +822,7 @@ class OnePaneDialog extends React.Component {
|
|
|
821
822
|
below: below,
|
|
822
823
|
testId: testId,
|
|
823
824
|
"aria-labelledby": uniqueId,
|
|
825
|
+
"aria-describedby": ariaDescribedBy,
|
|
824
826
|
role: role
|
|
825
827
|
}, React.createElement(ModalPanel, {
|
|
826
828
|
onClose: onClose,
|
package/dist/index.js
CHANGED
|
@@ -388,8 +388,13 @@ class ModalDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
388
388
|
style,
|
|
389
389
|
children,
|
|
390
390
|
testId,
|
|
391
|
+
|
|
392
|
+
/* eslint-disable react/prop-types */
|
|
393
|
+
// the react/prop-types plugin does not like these
|
|
391
394
|
"aria-labelledby": ariaLabelledBy,
|
|
392
|
-
"aria-
|
|
395
|
+
"aria-describedby": ariaDescribedBy
|
|
396
|
+
/* eslint-enable react/prop-types */
|
|
397
|
+
|
|
393
398
|
} = this.props;
|
|
394
399
|
const contextValue = {
|
|
395
400
|
ssrSize: "large",
|
|
@@ -409,7 +414,7 @@ class ModalDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
409
414
|
role: role,
|
|
410
415
|
"aria-modal": "true",
|
|
411
416
|
"aria-labelledby": ariaLabelledBy,
|
|
412
|
-
"aria-
|
|
417
|
+
"aria-describedby": ariaDescribedBy,
|
|
413
418
|
style: styles.dialog,
|
|
414
419
|
testId: testId
|
|
415
420
|
}, children), above && /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_3__["View"], {
|
|
@@ -1043,7 +1048,8 @@ class OnePaneDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
1043
1048
|
closeButtonVisible,
|
|
1044
1049
|
testId,
|
|
1045
1050
|
titleId,
|
|
1046
|
-
role
|
|
1051
|
+
role,
|
|
1052
|
+
"aria-describedby": ariaDescribedBy
|
|
1047
1053
|
} = this.props;
|
|
1048
1054
|
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_khanacademy_wonder_blocks_layout__WEBPACK_IMPORTED_MODULE_2__["MediaLayout"], {
|
|
1049
1055
|
styleSheets: styleSheets
|
|
@@ -1058,6 +1064,7 @@ class OnePaneDialog extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
|
1058
1064
|
below: below,
|
|
1059
1065
|
testId: testId,
|
|
1060
1066
|
"aria-labelledby": uniqueId,
|
|
1067
|
+
"aria-describedby": ariaDescribedBy,
|
|
1061
1068
|
role: role
|
|
1062
1069
|
}, /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_modal_panel_js__WEBPACK_IMPORTED_MODULE_5__[/* default */ "a"], {
|
|
1063
1070
|
onClose: onClose,
|
package/package.json
CHANGED
|
@@ -433,7 +433,7 @@ export const FocusTrap: StoryComponentType = () => {
|
|
|
433
433
|
closeButtonVisible={false}
|
|
434
434
|
content={
|
|
435
435
|
<>
|
|
436
|
-
<Body>
|
|
436
|
+
<Body id="focus-trap-story-body-text">
|
|
437
437
|
This modal demonstrates how the focus trap works with
|
|
438
438
|
form elements (or focusable elements). Also demonstrates
|
|
439
439
|
how the focus trap is moved to the next modal when it is
|
|
@@ -467,6 +467,7 @@ export const FocusTrap: StoryComponentType = () => {
|
|
|
467
467
|
</Button>
|
|
468
468
|
</>
|
|
469
469
|
}
|
|
470
|
+
aria-describedby="focus-trap-story-body-text"
|
|
470
471
|
/>
|
|
471
472
|
);
|
|
472
473
|
|
|
@@ -99,4 +99,10 @@ export default {
|
|
|
99
99
|
not provided, a unique id will be generated.`,
|
|
100
100
|
table: {type: {summary: "string"}},
|
|
101
101
|
},
|
|
102
|
+
"aria-describedby": {
|
|
103
|
+
control: {type: "text"},
|
|
104
|
+
description:
|
|
105
|
+
"The ID of the content describing this dialog, if applicable",
|
|
106
|
+
table: {type: {summary: "string"}},
|
|
107
|
+
},
|
|
102
108
|
};
|
|
@@ -68,4 +68,21 @@ describe("OnePaneDialog", () => {
|
|
|
68
68
|
// Assert
|
|
69
69
|
expect(screen.getByLabelText("Breadcrumbs")).toBeInTheDocument();
|
|
70
70
|
});
|
|
71
|
+
|
|
72
|
+
it("applies aria-describedby to the modal", () => {
|
|
73
|
+
// Arrange
|
|
74
|
+
render(
|
|
75
|
+
<OnePaneDialog
|
|
76
|
+
title="unused"
|
|
77
|
+
content={<p id="description">cool dialog</p>}
|
|
78
|
+
aria-describedby="description"
|
|
79
|
+
/>,
|
|
80
|
+
);
|
|
81
|
+
|
|
82
|
+
// Act
|
|
83
|
+
const modal = screen.getByRole("dialog");
|
|
84
|
+
|
|
85
|
+
// Assert
|
|
86
|
+
expect(modal).toHaveDescription(/cool dialog/i);
|
|
87
|
+
});
|
|
71
88
|
});
|
|
@@ -7,12 +7,11 @@ import {
|
|
|
7
7
|
MEDIA_MODAL_SPEC,
|
|
8
8
|
} from "@khanacademy/wonder-blocks-layout";
|
|
9
9
|
import {View} from "@khanacademy/wonder-blocks-core";
|
|
10
|
-
import type {
|
|
10
|
+
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
11
11
|
import type {MediaLayoutContextValue} from "@khanacademy/wonder-blocks-layout";
|
|
12
12
|
import Spacing from "@khanacademy/wonder-blocks-spacing";
|
|
13
13
|
|
|
14
14
|
type Props = {|
|
|
15
|
-
...AriaProps,
|
|
16
15
|
/**
|
|
17
16
|
* The dialog content
|
|
18
17
|
*/
|
|
@@ -48,6 +47,16 @@ type Props = {|
|
|
|
48
47
|
* Test ID used for e2e testing.
|
|
49
48
|
*/
|
|
50
49
|
testId?: string,
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* The ID of the content labelling this dialog, if applicable.
|
|
53
|
+
*/
|
|
54
|
+
"aria-labelledby"?: string,
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* The ID of the content describing this dialog, if applicable.
|
|
58
|
+
*/
|
|
59
|
+
"aria-describedby"?: string,
|
|
51
60
|
|};
|
|
52
61
|
|
|
53
62
|
type DefaultProps = {|
|
|
@@ -77,8 +86,11 @@ export default class ModalDialog extends React.Component<Props> {
|
|
|
77
86
|
style,
|
|
78
87
|
children,
|
|
79
88
|
testId,
|
|
89
|
+
/* eslint-disable react/prop-types */
|
|
90
|
+
// the react/prop-types plugin does not like these
|
|
80
91
|
"aria-labelledby": ariaLabelledBy,
|
|
81
|
-
"aria-
|
|
92
|
+
"aria-describedby": ariaDescribedBy,
|
|
93
|
+
/* eslint-enable react/prop-types */
|
|
82
94
|
} = this.props;
|
|
83
95
|
|
|
84
96
|
const contextValue: MediaLayoutContextValue = {
|
|
@@ -96,7 +108,7 @@ export default class ModalDialog extends React.Component<Props> {
|
|
|
96
108
|
role={role}
|
|
97
109
|
aria-modal="true"
|
|
98
110
|
aria-labelledby={ariaLabelledBy}
|
|
99
|
-
aria-
|
|
111
|
+
aria-describedby={ariaDescribedBy}
|
|
100
112
|
style={styles.dialog}
|
|
101
113
|
testId={testId}
|
|
102
114
|
>
|
|
@@ -3,7 +3,7 @@ import * as React from "react";
|
|
|
3
3
|
import {StyleSheet} from "aphrodite";
|
|
4
4
|
import {typeof Breadcrumbs} from "@khanacademy/wonder-blocks-breadcrumbs";
|
|
5
5
|
import {MediaLayout} from "@khanacademy/wonder-blocks-layout";
|
|
6
|
-
import type {
|
|
6
|
+
import type {StyleType} from "@khanacademy/wonder-blocks-core";
|
|
7
7
|
|
|
8
8
|
import {IDProvider} from "@khanacademy/wonder-blocks-core";
|
|
9
9
|
import ModalDialog from "./modal-dialog.js";
|
|
@@ -11,8 +11,6 @@ import ModalPanel from "./modal-panel.js";
|
|
|
11
11
|
import ModalHeader from "./modal-header.js";
|
|
12
12
|
|
|
13
13
|
type Common = {|
|
|
14
|
-
...AriaProps,
|
|
15
|
-
|
|
16
14
|
/**
|
|
17
15
|
* The content of the modal, appearing between the titlebar and footer.
|
|
18
16
|
*/
|
|
@@ -84,6 +82,11 @@ type Common = {|
|
|
|
84
82
|
* not provided, a unique id will be generated.
|
|
85
83
|
*/
|
|
86
84
|
titleId?: string,
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The ID of the content describing this dialog, if applicable.
|
|
88
|
+
*/
|
|
89
|
+
"aria-describedby"?: string,
|
|
87
90
|
|};
|
|
88
91
|
|
|
89
92
|
type WithSubtitle = {|
|
|
@@ -195,6 +198,7 @@ export default class OnePaneDialog extends React.Component<Props> {
|
|
|
195
198
|
testId,
|
|
196
199
|
titleId,
|
|
197
200
|
role,
|
|
201
|
+
"aria-describedby": ariaDescribedBy,
|
|
198
202
|
} = this.props;
|
|
199
203
|
|
|
200
204
|
return (
|
|
@@ -208,6 +212,7 @@ export default class OnePaneDialog extends React.Component<Props> {
|
|
|
208
212
|
below={below}
|
|
209
213
|
testId={testId}
|
|
210
214
|
aria-labelledby={uniqueId}
|
|
215
|
+
aria-describedby={ariaDescribedBy}
|
|
211
216
|
role={role}
|
|
212
217
|
>
|
|
213
218
|
<ModalPanel
|