carbon-react 143.2.3 → 143.2.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/esm/components/action-popover/__internal__/action-popover-utils.d.ts +7 -0
- package/esm/components/action-popover/__internal__/action-popover-utils.js +20 -0
- package/esm/components/action-popover/action-popover-item/action-popover-item.component.js +5 -4
- package/esm/components/action-popover/action-popover-menu/action-popover-menu.component.js +10 -35
- package/esm/components/action-popover/action-popover.component.js +10 -10
- package/lib/components/action-popover/__internal__/action-popover-utils.d.ts +7 -0
- package/lib/components/action-popover/__internal__/action-popover-utils.js +30 -0
- package/lib/components/action-popover/action-popover-item/action-popover-item.component.js +5 -4
- package/lib/components/action-popover/action-popover-menu/action-popover-menu.component.js +9 -34
- package/lib/components/action-popover/action-popover.component.js +10 -10
- package/package.json +1 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
declare type ReactItem = React.ReactChild | React.ReactFragment | React.ReactPortal;
|
|
3
|
+
export declare const getItems: (children: React.ReactNode | React.ReactNode[]) => ReactItem[];
|
|
4
|
+
export declare const isItemDisabled: (item: ReactItem) => boolean;
|
|
5
|
+
export declare const findFirstFocusableItem: (items: ReactItem[]) => number;
|
|
6
|
+
export declare const findLastFocusableItem: (items: ReactItem[]) => number;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { ActionPopoverItem } from "../action-popover-item/action-popover-item.component";
|
|
3
|
+
|
|
4
|
+
// Reusable type alias for item types
|
|
5
|
+
|
|
6
|
+
export const getItems = children => React.Children.toArray(children).filter(child => /*#__PURE__*/React.isValidElement(child) && child.type === ActionPopoverItem);
|
|
7
|
+
export const isItemDisabled = item => /*#__PURE__*/React.isValidElement(item) && !!item.props?.disabled;
|
|
8
|
+
export const findFirstFocusableItem = items => items.findIndex((_, index) => !isItemDisabled(items[index]));
|
|
9
|
+
|
|
10
|
+
// FIX-ME: FE-6248
|
|
11
|
+
// Once we no longer support Node 16, this function can be removed and `findLastIndex()` can be used in its place.
|
|
12
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex
|
|
13
|
+
export const findLastFocusableItem = items => {
|
|
14
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
15
|
+
if (!isItemDisabled(items[i])) {
|
|
16
|
+
return i;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return -1;
|
|
20
|
+
};
|
|
@@ -110,12 +110,13 @@ export const ActionPopoverItem = ({
|
|
|
110
110
|
}
|
|
111
111
|
}, [alignSubmenu, submenu]);
|
|
112
112
|
|
|
113
|
-
//
|
|
113
|
+
// Focuses item on opening of actionPopover submenu, but we want to do this once the Popover has finished opening
|
|
114
|
+
// We always want the focused item to be in the user's view for accessibility purposes, and without the initial unexpected scroll to top of page when used in a table.
|
|
114
115
|
useEffect(() => {
|
|
115
116
|
if (focusItem) {
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
});
|
|
117
|
+
setTimeout(() => {
|
|
118
|
+
ref.current?.focus();
|
|
119
|
+
}, 0);
|
|
119
120
|
}
|
|
120
121
|
}, [focusItem]);
|
|
121
122
|
useEffect(() => {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
function _extends() { return _extends = Object.assign ? Object.assign.bind() : function (n) { for (var e = 1; e < arguments.length; e++) { var t = arguments[e]; for (var r in t) ({}).hasOwnProperty.call(t, r) && (n[r] = t[r]); } return n; }, _extends.apply(null, arguments); }
|
|
2
|
-
import React, { useCallback, useMemo, useContext, useState
|
|
2
|
+
import React, { useCallback, useMemo, useContext, useState } from "react";
|
|
3
3
|
import PropTypes from "prop-types";
|
|
4
4
|
import invariant from "invariant";
|
|
5
5
|
import { Menu } from "../action-popover.style";
|
|
@@ -7,6 +7,7 @@ import Events from "../../../__internal__/utils/helpers/events";
|
|
|
7
7
|
import ActionPopoverItem from "../action-popover-item/action-popover-item.component";
|
|
8
8
|
import ActionPopoverDivider from "../action-popover-divider/action-popover-divider.component";
|
|
9
9
|
import ActionPopoverContext from "../__internal__/action-popover.context";
|
|
10
|
+
import { findFirstFocusableItem, findLastFocusableItem, getItems, isItemDisabled } from "../__internal__/action-popover-utils";
|
|
10
11
|
const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
11
12
|
children,
|
|
12
13
|
parentID,
|
|
@@ -37,36 +38,10 @@ const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
|
37
38
|
return !incorrectChild;
|
|
38
39
|
}, [children]);
|
|
39
40
|
!hasProperChildren ? process.env.NODE_ENV !== "production" ? invariant(false, `ActionPopoverMenu only accepts children of type \`${ActionPopoverItem.displayName}\`` + ` and \`${ActionPopoverDivider.displayName}\`.`) : invariant(false) : void 0;
|
|
40
|
-
const items = useMemo(() =>
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}, [children]);
|
|
45
|
-
const isItemDisabled = useCallback(value => {
|
|
46
|
-
const item = items[value];
|
|
47
|
-
// The invariant will be triggered before this else path can be explored, hence the ignore else.
|
|
48
|
-
// istanbul ignore else
|
|
49
|
-
return /*#__PURE__*/React.isValidElement(item) && item.props.disabled;
|
|
50
|
-
}, [items]);
|
|
51
|
-
const firstFocusableItem = items.findIndex((_, index) => !isItemDisabled(index));
|
|
52
|
-
|
|
53
|
-
// FIX-ME: FE-6248
|
|
54
|
-
// Once we no longer support Node 16, this function can be removed and `findLastIndex()` can be used in it's place.
|
|
55
|
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex
|
|
56
|
-
function findLastFocusableItem() {
|
|
57
|
-
let lastFocusableItem = -1;
|
|
58
|
-
for (let i = items.length - 1; i >= 0; i--) {
|
|
59
|
-
if (!isItemDisabled(i)) {
|
|
60
|
-
lastFocusableItem = i;
|
|
61
|
-
break;
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
return lastFocusableItem;
|
|
65
|
-
}
|
|
66
|
-
const lastFocusableItem = findLastFocusableItem();
|
|
67
|
-
useEffect(() => {
|
|
68
|
-
if (isOpen && firstFocusableItem !== -1) setFocusIndex(firstFocusableItem);
|
|
69
|
-
}, [isOpen, firstFocusableItem, setFocusIndex]);
|
|
41
|
+
const items = useMemo(() => getItems(children), [children]);
|
|
42
|
+
const checkItemDisabled = useCallback(value => isItemDisabled(items[value]), [items]);
|
|
43
|
+
const firstFocusableItem = findFirstFocusableItem(items);
|
|
44
|
+
const lastFocusableItem = findLastFocusableItem(items);
|
|
70
45
|
const onKeyDown = useCallback(e => {
|
|
71
46
|
if (Events.isTabKey(e)) {
|
|
72
47
|
e.preventDefault();
|
|
@@ -78,7 +53,7 @@ const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
|
78
53
|
e.preventDefault();
|
|
79
54
|
e.stopPropagation();
|
|
80
55
|
let indexValue = focusIndex + 1;
|
|
81
|
-
while (indexValue < items.length &&
|
|
56
|
+
while (indexValue < items.length && checkItemDisabled(indexValue)) {
|
|
82
57
|
indexValue += 1;
|
|
83
58
|
}
|
|
84
59
|
if (indexValue >= items.length) {
|
|
@@ -90,7 +65,7 @@ const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
|
90
65
|
e.preventDefault();
|
|
91
66
|
e.stopPropagation();
|
|
92
67
|
let indexValue = focusIndex - 1;
|
|
93
|
-
while (indexValue >= firstFocusableItem &&
|
|
68
|
+
while (indexValue >= firstFocusableItem && checkItemDisabled(indexValue)) {
|
|
94
69
|
indexValue -= 1;
|
|
95
70
|
}
|
|
96
71
|
if (indexValue < firstFocusableItem) {
|
|
@@ -116,7 +91,7 @@ const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
|
116
91
|
let firstMatch;
|
|
117
92
|
let nextMatch;
|
|
118
93
|
items.forEach((item, index) => {
|
|
119
|
-
if (/*#__PURE__*/React.isValidElement(item) && !
|
|
94
|
+
if (/*#__PURE__*/React.isValidElement(item) && !checkItemDisabled(index) && item.props.children.toLowerCase().startsWith(e.key.toLowerCase())) {
|
|
120
95
|
// istanbul ignore else
|
|
121
96
|
if (firstMatch === undefined) {
|
|
122
97
|
firstMatch = index;
|
|
@@ -132,7 +107,7 @@ const ActionPopoverMenu = /*#__PURE__*/React.forwardRef(({
|
|
|
132
107
|
setFocusIndex(firstMatch);
|
|
133
108
|
}
|
|
134
109
|
}
|
|
135
|
-
}, [focusButton, setOpen, focusIndex, items,
|
|
110
|
+
}, [focusButton, setOpen, focusIndex, items, checkItemDisabled, setFocusIndex, firstFocusableItem, lastFocusableItem]);
|
|
136
111
|
const [childHasSubmenu, setChildHasSubmenu] = useState(false);
|
|
137
112
|
const [childHasIcon, setChildHasIcon] = useState(false);
|
|
138
113
|
const [currentSubmenuPosition, setCurrentSubmenuPosition] = useState(submenuPosition);
|
|
@@ -12,6 +12,7 @@ import ActionPopoverItem from "./action-popover-item/action-popover-item.compone
|
|
|
12
12
|
import ActionPopoverDivider from "./action-popover-divider/action-popover-divider.component";
|
|
13
13
|
import ActionPopoverContext from "./__internal__/action-popover.context";
|
|
14
14
|
import useModalManager from "../../hooks/__internal__/useModalManager";
|
|
15
|
+
import { findFirstFocusableItem, findLastFocusableItem, getItems } from "./__internal__/action-popover-utils";
|
|
15
16
|
const onOpenDefault = () => {};
|
|
16
17
|
const onCloseDefault = () => {};
|
|
17
18
|
export const ActionPopover = ({
|
|
@@ -33,11 +34,6 @@ export const ActionPopover = ({
|
|
|
33
34
|
const [guid] = useState(createGuid());
|
|
34
35
|
const buttonRef = useRef(null);
|
|
35
36
|
const menu = useRef(null);
|
|
36
|
-
const itemCount = useMemo(() => {
|
|
37
|
-
return React.Children.toArray(children).filter(child => {
|
|
38
|
-
return /*#__PURE__*/React.isValidElement(child) && child.type === ActionPopoverItem;
|
|
39
|
-
}).length;
|
|
40
|
-
}, [children]);
|
|
41
37
|
const hasProperChildren = useMemo(() => {
|
|
42
38
|
const incorrectChild = React.Children.toArray(children).find(child => {
|
|
43
39
|
if (! /*#__PURE__*/React.isValidElement(child)) {
|
|
@@ -47,6 +43,9 @@ export const ActionPopover = ({
|
|
|
47
43
|
});
|
|
48
44
|
return !incorrectChild;
|
|
49
45
|
}, [children]);
|
|
46
|
+
const items = useMemo(() => getItems(children), [children]);
|
|
47
|
+
const firstFocusableItem = findFirstFocusableItem(items);
|
|
48
|
+
const lastFocusableItem = findLastFocusableItem(items);
|
|
50
49
|
!hasProperChildren ? process.env.NODE_ENV !== "production" ? invariant(false, `ActionPopover only accepts children of type \`${ActionPopoverItem.displayName}\`` + ` and \`${ActionPopoverDivider.displayName}\`.`) : invariant(false) : void 0;
|
|
51
50
|
const mappedPlacement = useMemo(() => {
|
|
52
51
|
if (placement === "top" && !rightAlignMenu) {
|
|
@@ -76,12 +75,13 @@ export const ActionPopover = ({
|
|
|
76
75
|
const onButtonClick = useCallback(e => {
|
|
77
76
|
e.stopPropagation();
|
|
78
77
|
const isOpening = !isOpen;
|
|
78
|
+
setFocusIndex(firstFocusableItem);
|
|
79
79
|
setOpen(isOpening);
|
|
80
80
|
if (!isOpening) {
|
|
81
81
|
// Closing the menu should focus the MenuButton
|
|
82
82
|
focusButton();
|
|
83
83
|
}
|
|
84
|
-
}, [isOpen, setOpen, focusButton]);
|
|
84
|
+
}, [isOpen, firstFocusableItem, setOpen, focusButton]);
|
|
85
85
|
|
|
86
86
|
// Keyboard commands implemented as recommended by WAI-ARIA best practices
|
|
87
87
|
// https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-actions.html
|
|
@@ -90,15 +90,15 @@ export const ActionPopover = ({
|
|
|
90
90
|
if (Events.isSpaceKey(e) || Events.isDownKey(e) || Events.isEnterKey(e)) {
|
|
91
91
|
e.preventDefault();
|
|
92
92
|
e.stopPropagation();
|
|
93
|
-
setFocusIndex(
|
|
93
|
+
setFocusIndex(firstFocusableItem);
|
|
94
94
|
setOpen(true);
|
|
95
95
|
} else if (Events.isUpKey(e)) {
|
|
96
96
|
e.preventDefault();
|
|
97
97
|
e.stopPropagation();
|
|
98
|
-
setFocusIndex(
|
|
98
|
+
setFocusIndex(lastFocusableItem);
|
|
99
99
|
setOpen(true);
|
|
100
100
|
}
|
|
101
|
-
}, [
|
|
101
|
+
}, [firstFocusableItem, lastFocusableItem, setOpen]);
|
|
102
102
|
const handleEscapeKey = useCallback(e => {
|
|
103
103
|
/* istanbul ignore else */
|
|
104
104
|
if (Events.isEscKey(e)) {
|
|
@@ -115,7 +115,7 @@ export const ActionPopover = ({
|
|
|
115
115
|
const handler = ({
|
|
116
116
|
target
|
|
117
117
|
}) => {
|
|
118
|
-
// If the event didn't
|
|
118
|
+
// If the event didn't come from part of this component, close the menu.
|
|
119
119
|
// There will be multiple document click listeners but we cant prevent propagation because it will interfere with
|
|
120
120
|
// other instances on the same page
|
|
121
121
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
declare type ReactItem = React.ReactChild | React.ReactFragment | React.ReactPortal;
|
|
3
|
+
export declare const getItems: (children: React.ReactNode | React.ReactNode[]) => ReactItem[];
|
|
4
|
+
export declare const isItemDisabled: (item: ReactItem) => boolean;
|
|
5
|
+
export declare const findFirstFocusableItem: (items: ReactItem[]) => number;
|
|
6
|
+
export declare const findLastFocusableItem: (items: ReactItem[]) => number;
|
|
7
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.isItemDisabled = exports.getItems = exports.findLastFocusableItem = exports.findFirstFocusableItem = void 0;
|
|
7
|
+
var _react = _interopRequireDefault(require("react"));
|
|
8
|
+
var _actionPopoverItem = require("../action-popover-item/action-popover-item.component");
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
// Reusable type alias for item types
|
|
11
|
+
|
|
12
|
+
const getItems = children => _react.default.Children.toArray(children).filter(child => /*#__PURE__*/_react.default.isValidElement(child) && child.type === _actionPopoverItem.ActionPopoverItem);
|
|
13
|
+
exports.getItems = getItems;
|
|
14
|
+
const isItemDisabled = item => /*#__PURE__*/_react.default.isValidElement(item) && !!item.props?.disabled;
|
|
15
|
+
exports.isItemDisabled = isItemDisabled;
|
|
16
|
+
const findFirstFocusableItem = items => items.findIndex((_, index) => !isItemDisabled(items[index]));
|
|
17
|
+
|
|
18
|
+
// FIX-ME: FE-6248
|
|
19
|
+
// Once we no longer support Node 16, this function can be removed and `findLastIndex()` can be used in its place.
|
|
20
|
+
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex
|
|
21
|
+
exports.findFirstFocusableItem = findFirstFocusableItem;
|
|
22
|
+
const findLastFocusableItem = items => {
|
|
23
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
24
|
+
if (!isItemDisabled(items[i])) {
|
|
25
|
+
return i;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return -1;
|
|
29
|
+
};
|
|
30
|
+
exports.findLastFocusableItem = findLastFocusableItem;
|
|
@@ -119,12 +119,13 @@ const ActionPopoverItem = ({
|
|
|
119
119
|
}
|
|
120
120
|
}, [alignSubmenu, submenu]);
|
|
121
121
|
|
|
122
|
-
//
|
|
122
|
+
// Focuses item on opening of actionPopover submenu, but we want to do this once the Popover has finished opening
|
|
123
|
+
// We always want the focused item to be in the user's view for accessibility purposes, and without the initial unexpected scroll to top of page when used in a table.
|
|
123
124
|
(0, _react.useEffect)(() => {
|
|
124
125
|
if (focusItem) {
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
});
|
|
126
|
+
setTimeout(() => {
|
|
127
|
+
ref.current?.focus();
|
|
128
|
+
}, 0);
|
|
128
129
|
}
|
|
129
130
|
}, [focusItem]);
|
|
130
131
|
(0, _react.useEffect)(() => {
|
|
@@ -12,6 +12,7 @@ var _events = _interopRequireDefault(require("../../../__internal__/utils/helper
|
|
|
12
12
|
var _actionPopoverItem = _interopRequireDefault(require("../action-popover-item/action-popover-item.component"));
|
|
13
13
|
var _actionPopoverDivider = _interopRequireDefault(require("../action-popover-divider/action-popover-divider.component"));
|
|
14
14
|
var _actionPopover2 = _interopRequireDefault(require("../__internal__/action-popover.context"));
|
|
15
|
+
var _actionPopoverUtils = require("../__internal__/action-popover-utils");
|
|
15
16
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
16
17
|
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); }
|
|
17
18
|
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 && {}.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; }
|
|
@@ -46,36 +47,10 @@ const ActionPopoverMenu = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
46
47
|
return !incorrectChild;
|
|
47
48
|
}, [children]);
|
|
48
49
|
!hasProperChildren ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, `ActionPopoverMenu only accepts children of type \`${_actionPopoverItem.default.displayName}\`` + ` and \`${_actionPopoverDivider.default.displayName}\`.`) : (0, _invariant.default)(false) : void 0;
|
|
49
|
-
const items = (0, _react.useMemo)(() =>
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}, [children]);
|
|
54
|
-
const isItemDisabled = (0, _react.useCallback)(value => {
|
|
55
|
-
const item = items[value];
|
|
56
|
-
// The invariant will be triggered before this else path can be explored, hence the ignore else.
|
|
57
|
-
// istanbul ignore else
|
|
58
|
-
return /*#__PURE__*/_react.default.isValidElement(item) && item.props.disabled;
|
|
59
|
-
}, [items]);
|
|
60
|
-
const firstFocusableItem = items.findIndex((_, index) => !isItemDisabled(index));
|
|
61
|
-
|
|
62
|
-
// FIX-ME: FE-6248
|
|
63
|
-
// Once we no longer support Node 16, this function can be removed and `findLastIndex()` can be used in it's place.
|
|
64
|
-
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findLastIndex
|
|
65
|
-
function findLastFocusableItem() {
|
|
66
|
-
let lastFocusableItem = -1;
|
|
67
|
-
for (let i = items.length - 1; i >= 0; i--) {
|
|
68
|
-
if (!isItemDisabled(i)) {
|
|
69
|
-
lastFocusableItem = i;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
return lastFocusableItem;
|
|
74
|
-
}
|
|
75
|
-
const lastFocusableItem = findLastFocusableItem();
|
|
76
|
-
(0, _react.useEffect)(() => {
|
|
77
|
-
if (isOpen && firstFocusableItem !== -1) setFocusIndex(firstFocusableItem);
|
|
78
|
-
}, [isOpen, firstFocusableItem, setFocusIndex]);
|
|
50
|
+
const items = (0, _react.useMemo)(() => (0, _actionPopoverUtils.getItems)(children), [children]);
|
|
51
|
+
const checkItemDisabled = (0, _react.useCallback)(value => (0, _actionPopoverUtils.isItemDisabled)(items[value]), [items]);
|
|
52
|
+
const firstFocusableItem = (0, _actionPopoverUtils.findFirstFocusableItem)(items);
|
|
53
|
+
const lastFocusableItem = (0, _actionPopoverUtils.findLastFocusableItem)(items);
|
|
79
54
|
const onKeyDown = (0, _react.useCallback)(e => {
|
|
80
55
|
if (_events.default.isTabKey(e)) {
|
|
81
56
|
e.preventDefault();
|
|
@@ -87,7 +62,7 @@ const ActionPopoverMenu = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
87
62
|
e.preventDefault();
|
|
88
63
|
e.stopPropagation();
|
|
89
64
|
let indexValue = focusIndex + 1;
|
|
90
|
-
while (indexValue < items.length &&
|
|
65
|
+
while (indexValue < items.length && checkItemDisabled(indexValue)) {
|
|
91
66
|
indexValue += 1;
|
|
92
67
|
}
|
|
93
68
|
if (indexValue >= items.length) {
|
|
@@ -99,7 +74,7 @@ const ActionPopoverMenu = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
99
74
|
e.preventDefault();
|
|
100
75
|
e.stopPropagation();
|
|
101
76
|
let indexValue = focusIndex - 1;
|
|
102
|
-
while (indexValue >= firstFocusableItem &&
|
|
77
|
+
while (indexValue >= firstFocusableItem && checkItemDisabled(indexValue)) {
|
|
103
78
|
indexValue -= 1;
|
|
104
79
|
}
|
|
105
80
|
if (indexValue < firstFocusableItem) {
|
|
@@ -125,7 +100,7 @@ const ActionPopoverMenu = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
125
100
|
let firstMatch;
|
|
126
101
|
let nextMatch;
|
|
127
102
|
items.forEach((item, index) => {
|
|
128
|
-
if (/*#__PURE__*/_react.default.isValidElement(item) && !
|
|
103
|
+
if (/*#__PURE__*/_react.default.isValidElement(item) && !checkItemDisabled(index) && item.props.children.toLowerCase().startsWith(e.key.toLowerCase())) {
|
|
129
104
|
// istanbul ignore else
|
|
130
105
|
if (firstMatch === undefined) {
|
|
131
106
|
firstMatch = index;
|
|
@@ -141,7 +116,7 @@ const ActionPopoverMenu = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
141
116
|
setFocusIndex(firstMatch);
|
|
142
117
|
}
|
|
143
118
|
}
|
|
144
|
-
}, [focusButton, setOpen, focusIndex, items,
|
|
119
|
+
}, [focusButton, setOpen, focusIndex, items, checkItemDisabled, setFocusIndex, firstFocusableItem, lastFocusableItem]);
|
|
145
120
|
const [childHasSubmenu, setChildHasSubmenu] = (0, _react.useState)(false);
|
|
146
121
|
const [childHasIcon, setChildHasIcon] = (0, _react.useState)(false);
|
|
147
122
|
const [currentSubmenuPosition, setCurrentSubmenuPosition] = (0, _react.useState)(submenuPosition);
|
|
@@ -17,6 +17,7 @@ var _actionPopoverItem = _interopRequireDefault(require("./action-popover-item/a
|
|
|
17
17
|
var _actionPopoverDivider = _interopRequireDefault(require("./action-popover-divider/action-popover-divider.component"));
|
|
18
18
|
var _actionPopover2 = _interopRequireDefault(require("./__internal__/action-popover.context"));
|
|
19
19
|
var _useModalManager = _interopRequireDefault(require("../../hooks/__internal__/useModalManager"));
|
|
20
|
+
var _actionPopoverUtils = require("./__internal__/action-popover-utils");
|
|
20
21
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
21
22
|
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); }
|
|
22
23
|
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 && {}.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; }
|
|
@@ -42,11 +43,6 @@ const ActionPopover = ({
|
|
|
42
43
|
const [guid] = (0, _react.useState)((0, _guid.default)());
|
|
43
44
|
const buttonRef = (0, _react.useRef)(null);
|
|
44
45
|
const menu = (0, _react.useRef)(null);
|
|
45
|
-
const itemCount = (0, _react.useMemo)(() => {
|
|
46
|
-
return _react.default.Children.toArray(children).filter(child => {
|
|
47
|
-
return /*#__PURE__*/_react.default.isValidElement(child) && child.type === _actionPopoverItem.default;
|
|
48
|
-
}).length;
|
|
49
|
-
}, [children]);
|
|
50
46
|
const hasProperChildren = (0, _react.useMemo)(() => {
|
|
51
47
|
const incorrectChild = _react.default.Children.toArray(children).find(child => {
|
|
52
48
|
if (! /*#__PURE__*/_react.default.isValidElement(child)) {
|
|
@@ -56,6 +52,9 @@ const ActionPopover = ({
|
|
|
56
52
|
});
|
|
57
53
|
return !incorrectChild;
|
|
58
54
|
}, [children]);
|
|
55
|
+
const items = (0, _react.useMemo)(() => (0, _actionPopoverUtils.getItems)(children), [children]);
|
|
56
|
+
const firstFocusableItem = (0, _actionPopoverUtils.findFirstFocusableItem)(items);
|
|
57
|
+
const lastFocusableItem = (0, _actionPopoverUtils.findLastFocusableItem)(items);
|
|
59
58
|
!hasProperChildren ? process.env.NODE_ENV !== "production" ? (0, _invariant.default)(false, `ActionPopover only accepts children of type \`${_actionPopoverItem.default.displayName}\`` + ` and \`${_actionPopoverDivider.default.displayName}\`.`) : (0, _invariant.default)(false) : void 0;
|
|
60
59
|
const mappedPlacement = (0, _react.useMemo)(() => {
|
|
61
60
|
if (placement === "top" && !rightAlignMenu) {
|
|
@@ -85,12 +84,13 @@ const ActionPopover = ({
|
|
|
85
84
|
const onButtonClick = (0, _react.useCallback)(e => {
|
|
86
85
|
e.stopPropagation();
|
|
87
86
|
const isOpening = !isOpen;
|
|
87
|
+
setFocusIndex(firstFocusableItem);
|
|
88
88
|
setOpen(isOpening);
|
|
89
89
|
if (!isOpening) {
|
|
90
90
|
// Closing the menu should focus the MenuButton
|
|
91
91
|
focusButton();
|
|
92
92
|
}
|
|
93
|
-
}, [isOpen, setOpen, focusButton]);
|
|
93
|
+
}, [isOpen, firstFocusableItem, setOpen, focusButton]);
|
|
94
94
|
|
|
95
95
|
// Keyboard commands implemented as recommended by WAI-ARIA best practices
|
|
96
96
|
// https://www.w3.org/TR/wai-aria-practices/examples/menu-button/menu-button-actions.html
|
|
@@ -99,15 +99,15 @@ const ActionPopover = ({
|
|
|
99
99
|
if (_events.default.isSpaceKey(e) || _events.default.isDownKey(e) || _events.default.isEnterKey(e)) {
|
|
100
100
|
e.preventDefault();
|
|
101
101
|
e.stopPropagation();
|
|
102
|
-
setFocusIndex(
|
|
102
|
+
setFocusIndex(firstFocusableItem);
|
|
103
103
|
setOpen(true);
|
|
104
104
|
} else if (_events.default.isUpKey(e)) {
|
|
105
105
|
e.preventDefault();
|
|
106
106
|
e.stopPropagation();
|
|
107
|
-
setFocusIndex(
|
|
107
|
+
setFocusIndex(lastFocusableItem);
|
|
108
108
|
setOpen(true);
|
|
109
109
|
}
|
|
110
|
-
}, [
|
|
110
|
+
}, [firstFocusableItem, lastFocusableItem, setOpen]);
|
|
111
111
|
const handleEscapeKey = (0, _react.useCallback)(e => {
|
|
112
112
|
/* istanbul ignore else */
|
|
113
113
|
if (_events.default.isEscKey(e)) {
|
|
@@ -124,7 +124,7 @@ const ActionPopover = ({
|
|
|
124
124
|
const handler = ({
|
|
125
125
|
target
|
|
126
126
|
}) => {
|
|
127
|
-
// If the event didn't
|
|
127
|
+
// If the event didn't come from part of this component, close the menu.
|
|
128
128
|
// There will be multiple document click listeners but we cant prevent propagation because it will interfere with
|
|
129
129
|
// other instances on the same page
|
|
130
130
|
|