@dhis2-ui/modal 9.9.0-alpha.1 → 9.9.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.
|
@@ -15,6 +15,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
|
15
15
|
|
|
16
16
|
var _react = _interopRequireDefault(require("react"));
|
|
17
17
|
|
|
18
|
+
var _index = _interopRequireDefault(require("../locales/index.js"));
|
|
19
|
+
|
|
18
20
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
19
21
|
|
|
20
22
|
const createClickHandler = onClick => event => {
|
|
@@ -26,8 +28,10 @@ const CloseButton = _ref => {
|
|
|
26
28
|
onClick
|
|
27
29
|
} = _ref;
|
|
28
30
|
return /*#__PURE__*/_react.default.createElement("button", {
|
|
31
|
+
title: _index.default.t('Close modal dialog'),
|
|
29
32
|
"data-test": "dhis2-modal-close-button",
|
|
30
33
|
onClick: createClickHandler(onClick),
|
|
34
|
+
"aria-label": _index.default.t('Close modal dialog'),
|
|
31
35
|
className: _style.default.dynamic([["80232614", [_uiConstants.colors.grey700, _uiConstants.colors.grey200, _uiConstants.colors.grey900, _uiConstants.colors.grey200, _uiConstants.theme.focus, _uiConstants.colors.grey300]]])
|
|
32
36
|
}, /*#__PURE__*/_react.default.createElement(_uiIcons.IconCross16, null), /*#__PURE__*/_react.default.createElement(_style.default, {
|
|
33
37
|
id: "80232614",
|
package/build/cjs/modal/modal.js
CHANGED
|
@@ -19,10 +19,14 @@ var _classnames = _interopRequireDefault(require("classnames"));
|
|
|
19
19
|
|
|
20
20
|
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
21
21
|
|
|
22
|
-
var _react =
|
|
22
|
+
var _react = _interopRequireWildcard(require("react"));
|
|
23
23
|
|
|
24
24
|
var _closeButton = require("./close-button.js");
|
|
25
25
|
|
|
26
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
27
|
+
|
|
28
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
29
|
+
|
|
26
30
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
27
31
|
|
|
28
32
|
const resolveLayerStyles = hide => ({
|
|
@@ -46,6 +50,24 @@ const Modal = _ref => {
|
|
|
46
50
|
small
|
|
47
51
|
} = _ref;
|
|
48
52
|
const layerStyles = resolveLayerStyles(hide);
|
|
53
|
+
(0, _react.useEffect)(() => {
|
|
54
|
+
if (hide) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const handleKeyDown = event => {
|
|
59
|
+
if (event.key === 'Escape' && onClose) {
|
|
60
|
+
event.preventDefault();
|
|
61
|
+
event.stopPropagation();
|
|
62
|
+
onClose();
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
67
|
+
return () => {
|
|
68
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
69
|
+
};
|
|
70
|
+
}, [hide, onClose]);
|
|
49
71
|
return /*#__PURE__*/_react.default.createElement(_layer.Layer, {
|
|
50
72
|
onBackdropClick: onClose,
|
|
51
73
|
className: layerStyles.className,
|
|
@@ -4,11 +4,66 @@ var _react = require("@testing-library/react");
|
|
|
4
4
|
|
|
5
5
|
var _react2 = _interopRequireDefault(require("react"));
|
|
6
6
|
|
|
7
|
+
var _closeButton = require("./close-button.js");
|
|
8
|
+
|
|
7
9
|
var _modal = require("./modal.js");
|
|
8
10
|
|
|
9
11
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
10
12
|
|
|
11
13
|
describe('Modal', () => {
|
|
14
|
+
describe('Modal Accessibility', () => {
|
|
15
|
+
it('closes when ESC key is pressed', () => {
|
|
16
|
+
const onCloseMock = jest.fn();
|
|
17
|
+
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(_modal.Modal, {
|
|
18
|
+
onClose: onCloseMock
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
const modalElement = _react.screen.getByRole('dialog');
|
|
22
|
+
|
|
23
|
+
_react.fireEvent.keyDown(modalElement, {
|
|
24
|
+
key: 'Escape',
|
|
25
|
+
code: 'Escape'
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
expect(onCloseMock).toHaveBeenCalled();
|
|
29
|
+
});
|
|
30
|
+
it('does not close when "Enter" is pressed', () => {
|
|
31
|
+
const onCloseMock = jest.fn();
|
|
32
|
+
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(_modal.Modal, {
|
|
33
|
+
onClose: onCloseMock
|
|
34
|
+
}));
|
|
35
|
+
|
|
36
|
+
const modalElement = _react.screen.getByRole('dialog');
|
|
37
|
+
|
|
38
|
+
_react.fireEvent.keyDown(modalElement, {
|
|
39
|
+
key: 'Enter',
|
|
40
|
+
code: 'Enter'
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
expect(onCloseMock).not.toHaveBeenCalled();
|
|
44
|
+
});
|
|
45
|
+
it('does not close when "SpaceBar" is pressed', () => {
|
|
46
|
+
const onCloseMock = jest.fn();
|
|
47
|
+
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(_modal.Modal, {
|
|
48
|
+
onClose: onCloseMock
|
|
49
|
+
}));
|
|
50
|
+
|
|
51
|
+
const modalElement = _react.screen.getByRole('dialog');
|
|
52
|
+
|
|
53
|
+
_react.fireEvent.keyDown(modalElement, {
|
|
54
|
+
key: ' ',
|
|
55
|
+
code: ' '
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
expect(onCloseMock).not.toHaveBeenCalled();
|
|
59
|
+
});
|
|
60
|
+
it('has a close button with proper accessibility attributes', async () => {
|
|
61
|
+
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(_closeButton.CloseButton, null));
|
|
62
|
+
const closeButton = await _react.screen.findByLabelText(/Close modal dialog/);
|
|
63
|
+
expect(closeButton).toBeInTheDocument();
|
|
64
|
+
expect(closeButton.tagName).toBe('BUTTON');
|
|
65
|
+
});
|
|
66
|
+
});
|
|
12
67
|
describe('Regular dimensions', () => {
|
|
13
68
|
it('has the correct dimension styles in its default state', () => {
|
|
14
69
|
(0, _react.render)( /*#__PURE__*/_react2.default.createElement(_modal.Modal, null));
|
|
@@ -3,6 +3,7 @@ import { colors, theme } from '@dhis2/ui-constants';
|
|
|
3
3
|
import { IconCross16 } from '@dhis2/ui-icons';
|
|
4
4
|
import PropTypes from 'prop-types';
|
|
5
5
|
import React from 'react';
|
|
6
|
+
import i18n from '../locales/index.js';
|
|
6
7
|
|
|
7
8
|
const createClickHandler = onClick => event => {
|
|
8
9
|
onClick({}, event);
|
|
@@ -13,8 +14,10 @@ export const CloseButton = _ref => {
|
|
|
13
14
|
onClick
|
|
14
15
|
} = _ref;
|
|
15
16
|
return /*#__PURE__*/React.createElement("button", {
|
|
17
|
+
title: i18n.t('Close modal dialog'),
|
|
16
18
|
"data-test": "dhis2-modal-close-button",
|
|
17
19
|
onClick: createClickHandler(onClick),
|
|
20
|
+
"aria-label": i18n.t('Close modal dialog'),
|
|
18
21
|
className: _JSXStyle.dynamic([["80232614", [colors.grey700, colors.grey200, colors.grey900, colors.grey200, theme.focus, colors.grey300]]])
|
|
19
22
|
}, /*#__PURE__*/React.createElement(IconCross16, null), /*#__PURE__*/React.createElement(_JSXStyle, {
|
|
20
23
|
id: "80232614",
|
package/build/es/modal/modal.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Layer } from '@dhis2-ui/layer';
|
|
|
5
5
|
import { spacers, spacersNum, sharedPropTypes } from '@dhis2/ui-constants';
|
|
6
6
|
import cx from 'classnames';
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
8
|
-
import React from 'react';
|
|
8
|
+
import React, { useEffect } from 'react';
|
|
9
9
|
import { CloseButton } from './close-button.js';
|
|
10
10
|
|
|
11
11
|
const resolveLayerStyles = hide => ({
|
|
@@ -29,6 +29,24 @@ export const Modal = _ref => {
|
|
|
29
29
|
small
|
|
30
30
|
} = _ref;
|
|
31
31
|
const layerStyles = resolveLayerStyles(hide);
|
|
32
|
+
useEffect(() => {
|
|
33
|
+
if (hide) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const handleKeyDown = event => {
|
|
38
|
+
if (event.key === 'Escape' && onClose) {
|
|
39
|
+
event.preventDefault();
|
|
40
|
+
event.stopPropagation();
|
|
41
|
+
onClose();
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
document.addEventListener('keydown', handleKeyDown);
|
|
46
|
+
return () => {
|
|
47
|
+
document.removeEventListener('keydown', handleKeyDown);
|
|
48
|
+
};
|
|
49
|
+
}, [hide, onClose]);
|
|
32
50
|
return /*#__PURE__*/React.createElement(Layer, {
|
|
33
51
|
onBackdropClick: onClose,
|
|
34
52
|
className: layerStyles.className,
|
|
@@ -1,7 +1,52 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
1
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
2
2
|
import React from 'react';
|
|
3
|
+
import { CloseButton } from './close-button.js';
|
|
3
4
|
import { Modal } from './modal.js';
|
|
4
5
|
describe('Modal', () => {
|
|
6
|
+
describe('Modal Accessibility', () => {
|
|
7
|
+
it('closes when ESC key is pressed', () => {
|
|
8
|
+
const onCloseMock = jest.fn();
|
|
9
|
+
render( /*#__PURE__*/React.createElement(Modal, {
|
|
10
|
+
onClose: onCloseMock
|
|
11
|
+
}));
|
|
12
|
+
const modalElement = screen.getByRole('dialog');
|
|
13
|
+
fireEvent.keyDown(modalElement, {
|
|
14
|
+
key: 'Escape',
|
|
15
|
+
code: 'Escape'
|
|
16
|
+
});
|
|
17
|
+
expect(onCloseMock).toHaveBeenCalled();
|
|
18
|
+
});
|
|
19
|
+
it('does not close when "Enter" is pressed', () => {
|
|
20
|
+
const onCloseMock = jest.fn();
|
|
21
|
+
render( /*#__PURE__*/React.createElement(Modal, {
|
|
22
|
+
onClose: onCloseMock
|
|
23
|
+
}));
|
|
24
|
+
const modalElement = screen.getByRole('dialog');
|
|
25
|
+
fireEvent.keyDown(modalElement, {
|
|
26
|
+
key: 'Enter',
|
|
27
|
+
code: 'Enter'
|
|
28
|
+
});
|
|
29
|
+
expect(onCloseMock).not.toHaveBeenCalled();
|
|
30
|
+
});
|
|
31
|
+
it('does not close when "SpaceBar" is pressed', () => {
|
|
32
|
+
const onCloseMock = jest.fn();
|
|
33
|
+
render( /*#__PURE__*/React.createElement(Modal, {
|
|
34
|
+
onClose: onCloseMock
|
|
35
|
+
}));
|
|
36
|
+
const modalElement = screen.getByRole('dialog');
|
|
37
|
+
fireEvent.keyDown(modalElement, {
|
|
38
|
+
key: ' ',
|
|
39
|
+
code: ' '
|
|
40
|
+
});
|
|
41
|
+
expect(onCloseMock).not.toHaveBeenCalled();
|
|
42
|
+
});
|
|
43
|
+
it('has a close button with proper accessibility attributes', async () => {
|
|
44
|
+
render( /*#__PURE__*/React.createElement(CloseButton, null));
|
|
45
|
+
const closeButton = await screen.findByLabelText(/Close modal dialog/);
|
|
46
|
+
expect(closeButton).toBeInTheDocument();
|
|
47
|
+
expect(closeButton.tagName).toBe('BUTTON');
|
|
48
|
+
});
|
|
49
|
+
});
|
|
5
50
|
describe('Regular dimensions', () => {
|
|
6
51
|
it('has the correct dimension styles in its default state', () => {
|
|
7
52
|
render( /*#__PURE__*/React.createElement(Modal, null));
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dhis2-ui/modal",
|
|
3
|
-
"version": "9.9.0
|
|
3
|
+
"version": "9.9.0",
|
|
4
4
|
"description": "UI Modal",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -33,12 +33,12 @@
|
|
|
33
33
|
},
|
|
34
34
|
"dependencies": {
|
|
35
35
|
"@dhis2/prop-types": "^3.1.2",
|
|
36
|
-
"@dhis2-ui/card": "9.9.0
|
|
37
|
-
"@dhis2-ui/center": "9.9.0
|
|
38
|
-
"@dhis2-ui/layer": "9.9.0
|
|
39
|
-
"@dhis2-ui/portal": "9.9.0
|
|
40
|
-
"@dhis2/ui-constants": "9.9.0
|
|
41
|
-
"@dhis2/ui-icons": "9.9.0
|
|
36
|
+
"@dhis2-ui/card": "9.9.0",
|
|
37
|
+
"@dhis2-ui/center": "9.9.0",
|
|
38
|
+
"@dhis2-ui/layer": "9.9.0",
|
|
39
|
+
"@dhis2-ui/portal": "9.9.0",
|
|
40
|
+
"@dhis2/ui-constants": "9.9.0",
|
|
41
|
+
"@dhis2/ui-icons": "9.9.0",
|
|
42
42
|
"classnames": "^2.3.1",
|
|
43
43
|
"prop-types": "^15.7.2"
|
|
44
44
|
},
|