carbon-react 125.12.1 → 125.13.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/esm/components/date/__internal__/date-picker/date-picker.component.js +9 -3
- package/esm/components/date/date.component.js +8 -3
- package/esm/components/portal/portal.d.ts +7 -1
- package/esm/components/portal/portal.js +18 -2
- package/esm/components/toast/toast.style.d.ts +1 -1
- package/esm/hooks/__internal__/useModalAria/useModalAria.js +12 -3
- package/lib/components/date/__internal__/date-picker/date-picker.component.js +8 -2
- package/lib/components/date/date.component.js +8 -3
- package/lib/components/portal/portal.d.ts +7 -1
- package/lib/components/portal/portal.js +18 -2
- package/lib/components/toast/toast.style.d.ts +1 -1
- package/lib/hooks/__internal__/useModalAria/useModalAria.js +12 -3
- package/package.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
|
|
2
|
-
import React, { useEffect, useMemo, useRef } from "react";
|
|
2
|
+
import React, { useCallback, useEffect, useMemo, useRef } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import DayPicker from "react-day-picker";
|
|
5
5
|
import { flip, offset } from "@floating-ui/dom";
|
|
@@ -98,11 +98,16 @@ export const DatePicker = ({
|
|
|
98
98
|
onDayClick?.(date, ev);
|
|
99
99
|
}
|
|
100
100
|
};
|
|
101
|
-
const
|
|
102
|
-
|
|
101
|
+
const handleKeyUp = useCallback(ev => {
|
|
102
|
+
/* istanbul ignore else */
|
|
103
|
+
if (open && Events.isEscKey(ev)) {
|
|
103
104
|
inputElement.current?.querySelector("input")?.focus();
|
|
104
105
|
setOpen(false);
|
|
106
|
+
ev.stopPropagation();
|
|
105
107
|
}
|
|
108
|
+
}, [inputElement, open, setOpen]);
|
|
109
|
+
const handleOnKeyDown = ev => {
|
|
110
|
+
/* istanbul ignore else */
|
|
106
111
|
if (ref.current?.querySelector(".DayPicker-NavBar button") === document.activeElement && Events.isTabKey(ev) && Events.isShiftKey(ev)) {
|
|
107
112
|
ev.preventDefault();
|
|
108
113
|
setOpen(false);
|
|
@@ -145,6 +150,7 @@ export const DatePicker = ({
|
|
|
145
150
|
}, /*#__PURE__*/React.createElement(StyledDayPicker, {
|
|
146
151
|
ref: ref,
|
|
147
152
|
onMouseDown: pickerMouseDown,
|
|
153
|
+
onKeyUp: handleKeyUp,
|
|
148
154
|
onKeyDown: handleOnKeyDown
|
|
149
155
|
}, /*#__PURE__*/React.createElement("div", {
|
|
150
156
|
id: pickerTabGuardId
|
|
@@ -180,13 +180,17 @@ const DateInput = /*#__PURE__*/React.forwardRef(({
|
|
|
180
180
|
onFocus(ev);
|
|
181
181
|
}
|
|
182
182
|
};
|
|
183
|
+
const handleKeyUp = useCallback(ev => {
|
|
184
|
+
/* istanbul ignore else */
|
|
185
|
+
if (open && Events.isEscKey(ev)) {
|
|
186
|
+
setOpen(false);
|
|
187
|
+
ev.stopPropagation();
|
|
188
|
+
}
|
|
189
|
+
}, [open]);
|
|
183
190
|
const handleKeyDown = ev => {
|
|
184
191
|
if (onKeyDown) {
|
|
185
192
|
onKeyDown(ev);
|
|
186
193
|
}
|
|
187
|
-
if (Events.isEscKey(ev)) {
|
|
188
|
-
setOpen(false);
|
|
189
|
-
}
|
|
190
194
|
if (open && Events.isTabKey(ev)) {
|
|
191
195
|
if (Events.isShiftKey(ev)) {
|
|
192
196
|
setOpen(false);
|
|
@@ -288,6 +292,7 @@ const DateInput = /*#__PURE__*/React.forwardRef(({
|
|
|
288
292
|
onChange: handleChange,
|
|
289
293
|
onClick: handleClick,
|
|
290
294
|
onFocus: handleFocus,
|
|
295
|
+
onKeyUp: handleKeyUp,
|
|
291
296
|
onKeyDown: handleKeyDown,
|
|
292
297
|
iconOnClick: handleClick,
|
|
293
298
|
onMouseDown: handleMouseDown,
|
|
@@ -12,6 +12,12 @@ export interface PortalProps {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
/** Callback function triggered when parent element is scrolled or window resized. */
|
|
14
14
|
onReposition?: () => void;
|
|
15
|
+
/** A flag to ensure the portal content will remain interactive with by both mouse
|
|
16
|
+
* users and screenreader users, even if a modal is opened outside of or on top of
|
|
17
|
+
* the portal.
|
|
18
|
+
* To be used with caution.
|
|
19
|
+
*/
|
|
20
|
+
inertOptOut?: boolean;
|
|
15
21
|
}
|
|
16
|
-
declare const Portal: ({ children, className, id, onReposition }: PortalProps) => React.JSX.Element;
|
|
22
|
+
declare const Portal: ({ children, className, id, onReposition, inertOptOut, }: PortalProps) => React.JSX.Element;
|
|
17
23
|
export default Portal;
|
|
@@ -1,14 +1,26 @@
|
|
|
1
1
|
import React, { useContext, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import ReactDOM from "react-dom";
|
|
3
|
+
import styled, { css } from "styled-components";
|
|
3
4
|
import guid from "../../__internal__/utils/helpers/guid";
|
|
4
5
|
import CarbonScopedTokensProvider from "../../style/design-tokens/carbon-scoped-tokens-provider/carbon-scoped-tokens-provider.component";
|
|
5
6
|
import StyledPortalEntrance from "./portal.style";
|
|
6
7
|
export const PortalContext = /*#__PURE__*/React.createContext({});
|
|
8
|
+
const Container = styled.div`
|
|
9
|
+
${({
|
|
10
|
+
theme
|
|
11
|
+
}) => css`
|
|
12
|
+
{
|
|
13
|
+
position: relative;
|
|
14
|
+
z-index: ${theme.zIndex.aboveAll};
|
|
15
|
+
}
|
|
16
|
+
`}
|
|
17
|
+
`;
|
|
7
18
|
const Portal = ({
|
|
8
19
|
children,
|
|
9
20
|
className,
|
|
10
21
|
id,
|
|
11
|
-
onReposition
|
|
22
|
+
onReposition,
|
|
23
|
+
inertOptOut
|
|
12
24
|
}) => {
|
|
13
25
|
const [portalNode, setPortalNode] = useState(null);
|
|
14
26
|
const uniqueId = useMemo(() => guid(), []);
|
|
@@ -51,6 +63,9 @@ const Portal = ({
|
|
|
51
63
|
if (id !== undefined) {
|
|
52
64
|
node.setAttribute("id", id);
|
|
53
65
|
}
|
|
66
|
+
if (inertOptOut) {
|
|
67
|
+
node.setAttribute("data-not-inert", "true");
|
|
68
|
+
}
|
|
54
69
|
setPortalNode(node);
|
|
55
70
|
let mainNode = document.body;
|
|
56
71
|
const rootDiv = document.getElementById("root");
|
|
@@ -64,8 +79,9 @@ const Portal = ({
|
|
|
64
79
|
}
|
|
65
80
|
return node;
|
|
66
81
|
};
|
|
82
|
+
const portalContent = inertOptOut ? /*#__PURE__*/React.createElement(Container, null, children) : children;
|
|
67
83
|
return /*#__PURE__*/React.createElement(StyledPortalEntrance, {
|
|
68
84
|
"data-portal-entrance": uniqueId
|
|
69
|
-
}, /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(CarbonScopedTokensProvider, null,
|
|
85
|
+
}, /*#__PURE__*/ReactDOM.createPortal( /*#__PURE__*/React.createElement(CarbonScopedTokensProvider, null, portalContent), getPortalContainer()));
|
|
70
86
|
};
|
|
71
87
|
export default Portal;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import TypeIcon from "../message/type-icon/type-icon.style";
|
|
3
3
|
import { MessageVariant } from "../message/message.component";
|
|
4
|
-
declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
|
|
4
|
+
declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition, inertOptOut, }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
|
|
5
5
|
align?: "left" | "right" | "center" | undefined;
|
|
6
6
|
alignY?: "bottom" | "top" | "center" | undefined;
|
|
7
7
|
isCenter?: boolean | undefined;
|
|
@@ -8,6 +8,10 @@ export default function useModalAria(containerRef) {
|
|
|
8
8
|
useEffect(() => {
|
|
9
9
|
const originalValues = [];
|
|
10
10
|
const hideNonTopModalElements = rootElement => {
|
|
11
|
+
if (rootElement.dataset.notInert === "true") {
|
|
12
|
+
// stop recursing, and do nothing, if the container has the "data-not-inert" flag
|
|
13
|
+
return;
|
|
14
|
+
}
|
|
11
15
|
if (!rootElement.contains(topModal)) {
|
|
12
16
|
originalValues.push({
|
|
13
17
|
element: rootElement,
|
|
@@ -17,13 +21,18 @@ export default function useModalAria(containerRef) {
|
|
|
17
21
|
// need to manually call the blur event on any currently-focused element that might be inside the element
|
|
18
22
|
// we're making inert, since Firefox fails to do this, which can result in the focus styles remaining on
|
|
19
23
|
// an input that is no longer focused
|
|
20
|
-
if (rootElement.contains(document.activeElement)) {
|
|
21
|
-
document.activeElement
|
|
24
|
+
if (rootElement.contains(document.activeElement) && document.activeElement instanceof HTMLElement) {
|
|
25
|
+
document.activeElement.blur();
|
|
22
26
|
}
|
|
23
27
|
rootElement.setAttribute("aria-hidden", "true");
|
|
24
28
|
rootElement.setAttribute("inert", "");
|
|
25
29
|
} else if (rootElement !== topModal) {
|
|
26
|
-
Array.from(rootElement.children).forEach(
|
|
30
|
+
Array.from(rootElement.children).forEach(node => {
|
|
31
|
+
// istanbul ignore else
|
|
32
|
+
if (node instanceof HTMLElement) {
|
|
33
|
+
hideNonTopModalElements(node);
|
|
34
|
+
}
|
|
35
|
+
});
|
|
27
36
|
}
|
|
28
37
|
};
|
|
29
38
|
if (isTopModal) {
|
|
@@ -106,11 +106,16 @@ const DatePicker = ({
|
|
|
106
106
|
onDayClick?.(date, ev);
|
|
107
107
|
}
|
|
108
108
|
};
|
|
109
|
-
const
|
|
110
|
-
|
|
109
|
+
const handleKeyUp = (0, _react.useCallback)(ev => {
|
|
110
|
+
/* istanbul ignore else */
|
|
111
|
+
if (open && _events.default.isEscKey(ev)) {
|
|
111
112
|
inputElement.current?.querySelector("input")?.focus();
|
|
112
113
|
setOpen(false);
|
|
114
|
+
ev.stopPropagation();
|
|
113
115
|
}
|
|
116
|
+
}, [inputElement, open, setOpen]);
|
|
117
|
+
const handleOnKeyDown = ev => {
|
|
118
|
+
/* istanbul ignore else */
|
|
114
119
|
if (ref.current?.querySelector(".DayPicker-NavBar button") === document.activeElement && _events.default.isTabKey(ev) && _events.default.isShiftKey(ev)) {
|
|
115
120
|
ev.preventDefault();
|
|
116
121
|
setOpen(false);
|
|
@@ -153,6 +158,7 @@ const DatePicker = ({
|
|
|
153
158
|
}, /*#__PURE__*/_react.default.createElement(_dayPicker.default, {
|
|
154
159
|
ref: ref,
|
|
155
160
|
onMouseDown: pickerMouseDown,
|
|
161
|
+
onKeyUp: handleKeyUp,
|
|
156
162
|
onKeyDown: handleOnKeyDown
|
|
157
163
|
}, /*#__PURE__*/_react.default.createElement("div", {
|
|
158
164
|
id: pickerTabGuardId
|
|
@@ -189,13 +189,17 @@ const DateInput = exports.DateInput = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
189
189
|
onFocus(ev);
|
|
190
190
|
}
|
|
191
191
|
};
|
|
192
|
+
const handleKeyUp = (0, _react.useCallback)(ev => {
|
|
193
|
+
/* istanbul ignore else */
|
|
194
|
+
if (open && _events.default.isEscKey(ev)) {
|
|
195
|
+
setOpen(false);
|
|
196
|
+
ev.stopPropagation();
|
|
197
|
+
}
|
|
198
|
+
}, [open]);
|
|
192
199
|
const handleKeyDown = ev => {
|
|
193
200
|
if (onKeyDown) {
|
|
194
201
|
onKeyDown(ev);
|
|
195
202
|
}
|
|
196
|
-
if (_events.default.isEscKey(ev)) {
|
|
197
|
-
setOpen(false);
|
|
198
|
-
}
|
|
199
203
|
if (open && _events.default.isTabKey(ev)) {
|
|
200
204
|
if (_events.default.isShiftKey(ev)) {
|
|
201
205
|
setOpen(false);
|
|
@@ -297,6 +301,7 @@ const DateInput = exports.DateInput = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
297
301
|
onChange: handleChange,
|
|
298
302
|
onClick: handleClick,
|
|
299
303
|
onFocus: handleFocus,
|
|
304
|
+
onKeyUp: handleKeyUp,
|
|
300
305
|
onKeyDown: handleKeyDown,
|
|
301
306
|
iconOnClick: handleClick,
|
|
302
307
|
onMouseDown: handleMouseDown,
|
|
@@ -12,6 +12,12 @@ export interface PortalProps {
|
|
|
12
12
|
id?: string;
|
|
13
13
|
/** Callback function triggered when parent element is scrolled or window resized. */
|
|
14
14
|
onReposition?: () => void;
|
|
15
|
+
/** A flag to ensure the portal content will remain interactive with by both mouse
|
|
16
|
+
* users and screenreader users, even if a modal is opened outside of or on top of
|
|
17
|
+
* the portal.
|
|
18
|
+
* To be used with caution.
|
|
19
|
+
*/
|
|
20
|
+
inertOptOut?: boolean;
|
|
15
21
|
}
|
|
16
|
-
declare const Portal: ({ children, className, id, onReposition }: PortalProps) => React.JSX.Element;
|
|
22
|
+
declare const Portal: ({ children, className, id, onReposition, inertOptOut, }: PortalProps) => React.JSX.Element;
|
|
17
23
|
export default Portal;
|
|
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", {
|
|
|
6
6
|
exports.default = exports.PortalContext = void 0;
|
|
7
7
|
var _react = _interopRequireWildcard(require("react"));
|
|
8
8
|
var _reactDom = _interopRequireDefault(require("react-dom"));
|
|
9
|
+
var _styledComponents = _interopRequireWildcard(require("styled-components"));
|
|
9
10
|
var _guid = _interopRequireDefault(require("../../__internal__/utils/helpers/guid"));
|
|
10
11
|
var _carbonScopedTokensProvider = _interopRequireDefault(require("../../style/design-tokens/carbon-scoped-tokens-provider/carbon-scoped-tokens-provider.component"));
|
|
11
12
|
var _portal = _interopRequireDefault(require("./portal.style"));
|
|
@@ -13,11 +14,22 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
|
|
|
13
14
|
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
|
|
14
15
|
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
|
|
15
16
|
const PortalContext = exports.PortalContext = /*#__PURE__*/_react.default.createContext({});
|
|
17
|
+
const Container = _styledComponents.default.div`
|
|
18
|
+
${({
|
|
19
|
+
theme
|
|
20
|
+
}) => (0, _styledComponents.css)`
|
|
21
|
+
{
|
|
22
|
+
position: relative;
|
|
23
|
+
z-index: ${theme.zIndex.aboveAll};
|
|
24
|
+
}
|
|
25
|
+
`}
|
|
26
|
+
`;
|
|
16
27
|
const Portal = ({
|
|
17
28
|
children,
|
|
18
29
|
className,
|
|
19
30
|
id,
|
|
20
|
-
onReposition
|
|
31
|
+
onReposition,
|
|
32
|
+
inertOptOut
|
|
21
33
|
}) => {
|
|
22
34
|
const [portalNode, setPortalNode] = (0, _react.useState)(null);
|
|
23
35
|
const uniqueId = (0, _react.useMemo)(() => (0, _guid.default)(), []);
|
|
@@ -60,6 +72,9 @@ const Portal = ({
|
|
|
60
72
|
if (id !== undefined) {
|
|
61
73
|
node.setAttribute("id", id);
|
|
62
74
|
}
|
|
75
|
+
if (inertOptOut) {
|
|
76
|
+
node.setAttribute("data-not-inert", "true");
|
|
77
|
+
}
|
|
63
78
|
setPortalNode(node);
|
|
64
79
|
let mainNode = document.body;
|
|
65
80
|
const rootDiv = document.getElementById("root");
|
|
@@ -73,8 +88,9 @@ const Portal = ({
|
|
|
73
88
|
}
|
|
74
89
|
return node;
|
|
75
90
|
};
|
|
91
|
+
const portalContent = inertOptOut ? /*#__PURE__*/_react.default.createElement(Container, null, children) : children;
|
|
76
92
|
return /*#__PURE__*/_react.default.createElement(_portal.default, {
|
|
77
93
|
"data-portal-entrance": uniqueId
|
|
78
|
-
}, /*#__PURE__*/_reactDom.default.createPortal( /*#__PURE__*/_react.default.createElement(_carbonScopedTokensProvider.default, null,
|
|
94
|
+
}, /*#__PURE__*/_reactDom.default.createPortal( /*#__PURE__*/_react.default.createElement(_carbonScopedTokensProvider.default, null, portalContent), getPortalContainer()));
|
|
79
95
|
};
|
|
80
96
|
var _default = exports.default = Portal;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="react" />
|
|
2
2
|
import TypeIcon from "../message/type-icon/type-icon.style";
|
|
3
3
|
import { MessageVariant } from "../message/message.component";
|
|
4
|
-
declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
|
|
4
|
+
declare const StyledPortal: import("styled-components").StyledComponent<({ children, className, id, onReposition, inertOptOut, }: import("../portal/portal").PortalProps) => import("react").JSX.Element, any, {
|
|
5
5
|
align?: "left" | "right" | "center" | undefined;
|
|
6
6
|
alignY?: "bottom" | "top" | "center" | undefined;
|
|
7
7
|
isCenter?: boolean | undefined;
|
|
@@ -15,6 +15,10 @@ function useModalAria(containerRef) {
|
|
|
15
15
|
(0, _react.useEffect)(() => {
|
|
16
16
|
const originalValues = [];
|
|
17
17
|
const hideNonTopModalElements = rootElement => {
|
|
18
|
+
if (rootElement.dataset.notInert === "true") {
|
|
19
|
+
// stop recursing, and do nothing, if the container has the "data-not-inert" flag
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
18
22
|
if (!rootElement.contains(topModal)) {
|
|
19
23
|
originalValues.push({
|
|
20
24
|
element: rootElement,
|
|
@@ -24,13 +28,18 @@ function useModalAria(containerRef) {
|
|
|
24
28
|
// need to manually call the blur event on any currently-focused element that might be inside the element
|
|
25
29
|
// we're making inert, since Firefox fails to do this, which can result in the focus styles remaining on
|
|
26
30
|
// an input that is no longer focused
|
|
27
|
-
if (rootElement.contains(document.activeElement)) {
|
|
28
|
-
document.activeElement
|
|
31
|
+
if (rootElement.contains(document.activeElement) && document.activeElement instanceof HTMLElement) {
|
|
32
|
+
document.activeElement.blur();
|
|
29
33
|
}
|
|
30
34
|
rootElement.setAttribute("aria-hidden", "true");
|
|
31
35
|
rootElement.setAttribute("inert", "");
|
|
32
36
|
} else if (rootElement !== topModal) {
|
|
33
|
-
Array.from(rootElement.children).forEach(
|
|
37
|
+
Array.from(rootElement.children).forEach(node => {
|
|
38
|
+
// istanbul ignore else
|
|
39
|
+
if (node instanceof HTMLElement) {
|
|
40
|
+
hideNonTopModalElements(node);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
34
43
|
}
|
|
35
44
|
};
|
|
36
45
|
if (isTopModal) {
|