carbon-react 114.13.1 → 114.13.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/esm/__internal__/input-icon-toggle/input-icon-toggle.component.js +2 -1
- package/esm/components/link/link.component.d.ts +2 -0
- package/esm/components/link/link.component.js +7 -1
- package/esm/components/menu/__internal__/keyboard-navigation/index.d.ts +4 -2
- package/esm/components/menu/__internal__/keyboard-navigation/index.js +16 -15
- package/esm/components/menu/__internal__/locators.d.ts +6 -0
- package/esm/components/menu/__internal__/locators.js +6 -0
- package/esm/components/menu/__internal__/submenu/submenu.component.js +109 -108
- package/esm/components/menu/menu-full-screen/menu-full-screen.component.js +1 -2
- package/esm/components/menu/menu-item/index.js +0 -1
- package/esm/components/menu/menu-item/menu-item.component.js +77 -51
- package/esm/components/menu/menu-item/menu-item.d.ts +7 -3
- package/esm/components/menu/menu.component.js +33 -37
- package/esm/components/menu/menu.context.d.ts +2 -2
- package/esm/components/menu/menu.context.js +2 -2
- package/esm/components/menu/scrollable-block/scrollable-block.component.js +6 -24
- package/lib/__internal__/input-icon-toggle/input-icon-toggle.component.js +2 -1
- package/lib/components/link/link.component.d.ts +2 -0
- package/lib/components/link/link.component.js +7 -1
- package/lib/components/menu/__internal__/keyboard-navigation/index.d.ts +4 -2
- package/lib/components/menu/__internal__/keyboard-navigation/index.js +16 -15
- package/lib/components/menu/__internal__/locators.d.ts +6 -0
- package/lib/components/menu/__internal__/locators.js +18 -0
- package/lib/components/menu/__internal__/submenu/submenu.component.js +111 -113
- package/lib/components/menu/menu-full-screen/menu-full-screen.component.js +1 -2
- package/lib/components/menu/menu-item/menu-item.component.js +76 -52
- package/lib/components/menu/menu-item/menu-item.d.ts +7 -3
- package/lib/components/menu/menu.component.js +33 -37
- package/lib/components/menu/menu.context.d.ts +2 -2
- package/lib/components/menu/menu.context.js +2 -2
- package/lib/components/menu/scrollable-block/scrollable-block.component.js +6 -25
- package/package.json +1 -1
|
@@ -11,7 +11,7 @@ import MenuContext from "../menu.context";
|
|
|
11
11
|
import Submenu from "../__internal__/submenu/submenu.component";
|
|
12
12
|
import SubmenuContext from "../__internal__/submenu/submenu.context";
|
|
13
13
|
import { StyledMenuItem } from "../menu.style";
|
|
14
|
-
import
|
|
14
|
+
import guid from "../../../__internal__/utils/helpers/guid";
|
|
15
15
|
|
|
16
16
|
const MenuItem = ({
|
|
17
17
|
submenu,
|
|
@@ -33,41 +33,70 @@ const MenuItem = ({
|
|
|
33
33
|
onSubmenuClose,
|
|
34
34
|
overrideColor,
|
|
35
35
|
rel,
|
|
36
|
-
isFocused,
|
|
37
36
|
...rest
|
|
38
37
|
}) => {
|
|
39
|
-
|
|
38
|
+
var _ref$current, _ref$current2;
|
|
39
|
+
|
|
40
|
+
const {
|
|
41
|
+
inFullscreenView,
|
|
42
|
+
registerItem,
|
|
43
|
+
unregisterItem,
|
|
44
|
+
focusId,
|
|
45
|
+
menuType,
|
|
46
|
+
openSubmenuId
|
|
47
|
+
} = useContext(MenuContext);
|
|
48
|
+
const menuItemId = useRef(guid());
|
|
40
49
|
const submenuContext = useContext(SubmenuContext);
|
|
41
|
-
const ref = useRef(null);
|
|
42
|
-
const focusFromMenu = isFocused;
|
|
43
|
-
const focusFromSubmenu = submenuContext.isFocused;
|
|
44
|
-
const isChildSearch = useRef(false);
|
|
45
|
-
const childRef = useRef();
|
|
46
50
|
const {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
registerItem: registerSubmenuItem,
|
|
52
|
+
unregisterItem: unregisterSubmenuItem,
|
|
53
|
+
submenuFocusId,
|
|
54
|
+
updateFocusId: updateSubmenuFocusId,
|
|
55
|
+
handleKeyDown: handleSubmenuKeyDown,
|
|
56
|
+
shiftTabPressed
|
|
57
|
+
} = submenuContext;
|
|
58
|
+
const ref = useRef(null);
|
|
59
|
+
const focusFromMenu = focusId === menuItemId.current;
|
|
60
|
+
const focusFromSubmenu = submenuFocusId ? submenuFocusId === menuItemId.current : undefined;
|
|
61
|
+
const inputRef = useRef(null);
|
|
62
|
+
const inputIcon = useRef(null);
|
|
63
|
+
inputIcon.current = (_ref$current = ref.current) === null || _ref$current === void 0 ? void 0 : _ref$current.querySelector("[data-element='input-icon-toggle']");
|
|
64
|
+
inputRef.current = (_ref$current2 = ref.current) === null || _ref$current2 === void 0 ? void 0 : _ref$current2.querySelector("[data-element='input']");
|
|
65
|
+
const focusRef = inputRef.current ? inputRef : ref;
|
|
66
|
+
useEffect(() => {
|
|
67
|
+
const id = menuItemId.current;
|
|
68
|
+
|
|
69
|
+
if (registerSubmenuItem) {
|
|
70
|
+
registerSubmenuItem(id);
|
|
71
|
+
} else if (registerItem) {
|
|
72
|
+
registerItem(id);
|
|
52
73
|
}
|
|
53
74
|
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
return () => {
|
|
76
|
+
if (unregisterSubmenuItem) {
|
|
77
|
+
unregisterSubmenuItem(id);
|
|
78
|
+
} else if (unregisterItem) {
|
|
79
|
+
unregisterItem(id);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
}, [registerSubmenuItem, registerItem, unregisterSubmenuItem, unregisterItem]);
|
|
57
83
|
useEffect(() => {
|
|
58
|
-
|
|
84
|
+
var _inputIcon$current;
|
|
85
|
+
|
|
86
|
+
if (!openSubmenuId && focusFromSubmenu === undefined && focusFromMenu) {
|
|
59
87
|
focusRef.current.focus();
|
|
60
|
-
} else if (focusFromSubmenu) {
|
|
88
|
+
} else if (focusFromSubmenu && !(shiftTabPressed && ((_inputIcon$current = inputIcon.current) === null || _inputIcon$current === void 0 ? void 0 : _inputIcon$current.getAttribute("tabindex")) === "0")) {
|
|
61
89
|
focusRef.current.focus();
|
|
62
90
|
}
|
|
63
|
-
}, [focusFromMenu, focusFromSubmenu, focusRef]);
|
|
91
|
+
}, [openSubmenuId, focusFromMenu, focusFromSubmenu, inputIcon, shiftTabPressed, focusRef]);
|
|
64
92
|
const updateFocusOnClick = useCallback(() => {
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
submenuContext.updateFocusIndex(submenuContext.itemIndex);
|
|
93
|
+
if (updateSubmenuFocusId) {
|
|
94
|
+
updateSubmenuFocusId(menuItemId.current);
|
|
68
95
|
}
|
|
69
|
-
}, [
|
|
96
|
+
}, [updateSubmenuFocusId]);
|
|
70
97
|
const handleKeyDown = useCallback(event => {
|
|
98
|
+
var _inputIcon$current2, _inputRef$current;
|
|
99
|
+
|
|
71
100
|
if (onKeyDown) {
|
|
72
101
|
onKeyDown(event);
|
|
73
102
|
}
|
|
@@ -76,16 +105,16 @@ const MenuItem = ({
|
|
|
76
105
|
ref.current.focus();
|
|
77
106
|
}
|
|
78
107
|
|
|
79
|
-
|
|
80
|
-
var _focusRef$current;
|
|
108
|
+
const shouldFocusIcon = ((_inputIcon$current2 = inputIcon.current) === null || _inputIcon$current2 === void 0 ? void 0 : _inputIcon$current2.getAttribute("tabindex")) === "0" && document.activeElement === inputRef.current && ((_inputRef$current = inputRef.current) === null || _inputRef$current === void 0 ? void 0 : _inputRef$current.value); // let natural tab order move focus if input icon is tabbable
|
|
81
109
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
}
|
|
85
|
-
} else {
|
|
86
|
-
menuContext.handleKeyDown(event);
|
|
110
|
+
if (Events.isTabKey(event) && (!Events.isShiftKey(event) && shouldFocusIcon || Events.isShiftKey(event) && document.activeElement === inputIcon.current)) {
|
|
111
|
+
return;
|
|
87
112
|
}
|
|
88
|
-
|
|
113
|
+
|
|
114
|
+
if (handleSubmenuKeyDown) {
|
|
115
|
+
handleSubmenuKeyDown(event);
|
|
116
|
+
}
|
|
117
|
+
}, [onKeyDown, handleSubmenuKeyDown, inputIcon]);
|
|
89
118
|
const classes = useMemo(() => classNames({
|
|
90
119
|
"carbon-menu-item--has-link": href || onClick
|
|
91
120
|
}), [href, onClick]);
|
|
@@ -94,7 +123,7 @@ const MenuItem = ({
|
|
|
94
123
|
href,
|
|
95
124
|
target,
|
|
96
125
|
rel,
|
|
97
|
-
onClick: onClick || (
|
|
126
|
+
onClick: onClick || (inputRef.current ? updateFocusOnClick : undefined),
|
|
98
127
|
icon,
|
|
99
128
|
selected,
|
|
100
129
|
variant,
|
|
@@ -102,11 +131,8 @@ const MenuItem = ({
|
|
|
102
131
|
overrideColor,
|
|
103
132
|
ref
|
|
104
133
|
};
|
|
105
|
-
const clonedChildren = isChildSearch.current ? childrenItems.map(child => /*#__PURE__*/React.cloneElement(child, {
|
|
106
|
-
ref: childRef
|
|
107
|
-
})) : children;
|
|
108
134
|
|
|
109
|
-
const getTitle = title => maxWidth && typeof title === "string" ? title :
|
|
135
|
+
const getTitle = title => maxWidth && typeof title === "string" ? title : undefined;
|
|
110
136
|
|
|
111
137
|
const itemMaxWidth = !inFullscreenView ? maxWidth : undefined;
|
|
112
138
|
const asPassiveItem = !(onClick || href);
|
|
@@ -114,13 +140,14 @@ const MenuItem = ({
|
|
|
114
140
|
if (submenu) {
|
|
115
141
|
return /*#__PURE__*/React.createElement(StyledMenuItem, _extends({
|
|
116
142
|
"data-component": "menu-item",
|
|
117
|
-
menuType:
|
|
143
|
+
menuType: menuType,
|
|
118
144
|
display: "inline-block",
|
|
119
145
|
title: getTitle(submenu),
|
|
120
146
|
maxWidth: itemMaxWidth,
|
|
121
147
|
onClick: updateFocusOnClick
|
|
122
148
|
}, rest, {
|
|
123
|
-
inFullscreenView: inFullscreenView
|
|
149
|
+
inFullscreenView: inFullscreenView,
|
|
150
|
+
id: menuItemId.current
|
|
124
151
|
}), /*#__PURE__*/React.createElement(Submenu, _extends({}, typeof submenu !== "boolean" && {
|
|
125
152
|
title: submenu
|
|
126
153
|
}, {
|
|
@@ -132,29 +159,31 @@ const MenuItem = ({
|
|
|
132
159
|
ariaLabel: ariaLabel,
|
|
133
160
|
onSubmenuOpen: onSubmenuOpen,
|
|
134
161
|
onSubmenuClose: onSubmenuClose
|
|
135
|
-
}, elementProps, rest),
|
|
162
|
+
}, elementProps, rest), children));
|
|
136
163
|
}
|
|
137
164
|
|
|
138
165
|
return /*#__PURE__*/React.createElement(StyledMenuItem, _extends({
|
|
139
166
|
"data-component": "menu-item",
|
|
140
|
-
menuType:
|
|
141
|
-
inSubmenu:
|
|
167
|
+
menuType: menuType,
|
|
168
|
+
inSubmenu: !!handleSubmenuKeyDown,
|
|
142
169
|
display: "inline-block",
|
|
143
170
|
title: getTitle(children),
|
|
144
171
|
maxWidth: itemMaxWidth
|
|
145
172
|
}, rest, {
|
|
146
173
|
inFullscreenView: inFullscreenView && !Object.keys(submenuContext).length,
|
|
147
|
-
menuOpen: menuOpen
|
|
174
|
+
menuOpen: menuOpen,
|
|
175
|
+
id: menuItemId.current
|
|
148
176
|
}), /*#__PURE__*/React.createElement(StyledMenuItemWrapper, _extends({
|
|
149
|
-
as:
|
|
150
|
-
isSearch:
|
|
151
|
-
menuType:
|
|
177
|
+
as: inputRef.current ? "div" : Link,
|
|
178
|
+
isSearch: inputRef.current,
|
|
179
|
+
menuType: menuType
|
|
152
180
|
}, elementProps, {
|
|
153
181
|
ariaLabel: ariaLabel,
|
|
154
182
|
maxWidth: maxWidth,
|
|
155
183
|
inFullscreenView: inFullscreenView,
|
|
156
|
-
asPassiveItem: asPassiveItem
|
|
157
|
-
|
|
184
|
+
asPassiveItem: asPassiveItem,
|
|
185
|
+
placeholderTabIndex: asPassiveItem
|
|
186
|
+
}), children));
|
|
158
187
|
};
|
|
159
188
|
|
|
160
189
|
MenuItem.propTypes = {
|
|
@@ -243,10 +272,7 @@ MenuItem.propTypes = {
|
|
|
243
272
|
overrideColor: PropTypes.bool,
|
|
244
273
|
|
|
245
274
|
/** @ignore @private */
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
/** @ignore @private */
|
|
249
|
-
indexInMenu: PropTypes.number
|
|
275
|
+
"data-component": PropTypes.string
|
|
250
276
|
};
|
|
251
277
|
MenuItem.displayName = "MenuItem";
|
|
252
278
|
export default MenuItem;
|
|
@@ -31,10 +31,14 @@ export interface MenuItemBaseProps extends LayoutProps, FlexboxProps {
|
|
|
31
31
|
onSubmenuOpen?: () => void;
|
|
32
32
|
/** Callback triggered when submenu closes. Only valid with submenu prop */
|
|
33
33
|
onSubmenuClose?: () => void;
|
|
34
|
-
/**
|
|
35
|
-
|
|
36
|
-
|
|
34
|
+
/**
|
|
35
|
+
@ignore @private
|
|
36
|
+
private prop, used inside ScrollableBlock to ensure the MenuItem's color variant overrides the CSS
|
|
37
|
+
for other MenuItems inside the block
|
|
38
|
+
*/
|
|
37
39
|
overrideColor?: boolean;
|
|
40
|
+
/** @private @ignore */
|
|
41
|
+
"data-component"?: string;
|
|
38
42
|
}
|
|
39
43
|
|
|
40
44
|
export interface MenuWithChildren extends MenuItemBaseProps {
|
|
@@ -1,64 +1,60 @@
|
|
|
1
1
|
function _extends() { _extends = Object.assign || 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
2
|
|
|
3
|
-
import React, {
|
|
3
|
+
import React, { useCallback, useState, useRef } from "react";
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
import propTypes from "@styled-system/prop-types";
|
|
6
6
|
import { StyledMenuWrapper } from "./menu.style";
|
|
7
|
-
import { menuKeyboardNavigation } from "./__internal__/keyboard-navigation";
|
|
8
|
-
import Events from "../../__internal__/utils/helpers/events";
|
|
9
7
|
import MenuContext from "./menu.context";
|
|
8
|
+
import { menuKeyboardNavigation } from "./__internal__/keyboard-navigation";
|
|
9
|
+
import { MENU_ITEM_CHILDREN_LOCATOR } from "./__internal__/locators";
|
|
10
10
|
|
|
11
11
|
const Menu = ({
|
|
12
12
|
menuType = "light",
|
|
13
13
|
children,
|
|
14
14
|
...rest
|
|
15
15
|
}) => {
|
|
16
|
-
const [
|
|
17
|
-
const [openSubmenuIndex, setOpenSubmenuIndex] = useState(null);
|
|
16
|
+
const [openSubmenuId, setOpenSubmenuId] = useState(null);
|
|
18
17
|
const ref = useRef();
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
if (!Events.composedPath(event).includes(ref.current)) {
|
|
26
|
-
setFocusedItemIndex(undefined);
|
|
27
|
-
document.removeEventListener("click", onClickOutside);
|
|
28
|
-
}
|
|
18
|
+
const [focusId, setFocusId] = useState(undefined);
|
|
19
|
+
const [itemIds, setItemIds] = useState([]);
|
|
20
|
+
const registerItem = useCallback(id => {
|
|
21
|
+
setItemIds(prevState => {
|
|
22
|
+
return [...prevState, id];
|
|
23
|
+
});
|
|
29
24
|
}, []);
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
const unregisterItem = useCallback(id => {
|
|
26
|
+
setItemIds(prevState => {
|
|
27
|
+
return prevState.filter(itemId => itemId !== id);
|
|
28
|
+
});
|
|
29
|
+
}, []);
|
|
30
|
+
|
|
31
|
+
const handleKeyDown = event => {
|
|
32
|
+
/* istanbul ignore else */
|
|
33
|
+
if (ref.current) {
|
|
34
|
+
const focusableItems = Array.from(ref.current.querySelectorAll(MENU_ITEM_CHILDREN_LOCATOR));
|
|
35
|
+
const newIndex = menuKeyboardNavigation(event, focusableItems);
|
|
36
|
+
setFocusId(itemIds[newIndex]);
|
|
37
|
+
}
|
|
38
|
+
};
|
|
39
|
+
|
|
36
40
|
return /*#__PURE__*/React.createElement(StyledMenuWrapper, _extends({
|
|
37
41
|
"data-component": "menu",
|
|
38
42
|
menuType: menuType
|
|
39
43
|
}, rest, {
|
|
40
44
|
ref: ref,
|
|
41
|
-
role: "list"
|
|
45
|
+
role: "list",
|
|
46
|
+
onKeyDown: handleKeyDown
|
|
42
47
|
}), /*#__PURE__*/React.createElement(MenuContext.Provider, {
|
|
43
48
|
value: {
|
|
44
49
|
menuType,
|
|
45
|
-
handleKeyDown,
|
|
46
50
|
inMenu: true,
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
openSubmenuId,
|
|
52
|
+
setOpenSubmenuId,
|
|
53
|
+
focusId,
|
|
54
|
+
registerItem,
|
|
55
|
+
unregisterItem
|
|
49
56
|
}
|
|
50
|
-
},
|
|
51
|
-
const isFocused = focusedItemIndex === index;
|
|
52
|
-
|
|
53
|
-
if ( /*#__PURE__*/React.isValidElement(child) && child.type.displayName === "MenuItem" && child.props.submenu) {
|
|
54
|
-
return /*#__PURE__*/React.cloneElement(child, {
|
|
55
|
-
isFocused,
|
|
56
|
-
indexInMenu: index
|
|
57
|
-
});
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return child;
|
|
61
|
-
})));
|
|
57
|
+
}, children));
|
|
62
58
|
};
|
|
63
59
|
|
|
64
60
|
Menu.propTypes = {
|
|
@@ -4,7 +4,6 @@ import React, { useContext } from "react";
|
|
|
4
4
|
import PropTypes from "prop-types";
|
|
5
5
|
import MenuContext from "../menu.context";
|
|
6
6
|
import MenuItem from "../menu-item";
|
|
7
|
-
import SubmenuContext from "../__internal__/submenu/submenu.context";
|
|
8
7
|
import StyledScrollableBlock from "./scrollable-block.style";
|
|
9
8
|
import Box from "../../box";
|
|
10
9
|
|
|
@@ -16,13 +15,9 @@ const ScrollableBlock = ({
|
|
|
16
15
|
parentVariant,
|
|
17
16
|
...rest
|
|
18
17
|
}) => {
|
|
19
|
-
const menuContext = useContext(MenuContext);
|
|
20
|
-
const submenuContext = useContext(SubmenuContext);
|
|
21
18
|
const {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
handleKeyDown
|
|
25
|
-
} = submenuContext;
|
|
19
|
+
menuType
|
|
20
|
+
} = useContext(MenuContext);
|
|
26
21
|
const scrollVariants = {
|
|
27
22
|
light: "light",
|
|
28
23
|
dark: "dark",
|
|
@@ -31,35 +26,22 @@ const ScrollableBlock = ({
|
|
|
31
26
|
};
|
|
32
27
|
return /*#__PURE__*/React.createElement(StyledScrollableBlock, _extends({
|
|
33
28
|
"data-component": "submenu-scrollable-block",
|
|
34
|
-
menuType:
|
|
29
|
+
menuType: menuType,
|
|
35
30
|
variant: variant
|
|
36
31
|
}, rest), parent && /*#__PURE__*/React.createElement(MenuItem, {
|
|
32
|
+
"data-component": "scrollable-block-parent",
|
|
37
33
|
overrideColor: true,
|
|
38
34
|
variant: parentVariant,
|
|
39
35
|
as: "div",
|
|
40
36
|
href: "#"
|
|
41
37
|
}, parent), /*#__PURE__*/React.createElement(Box, {
|
|
42
38
|
overflowY: "scroll",
|
|
43
|
-
scrollVariant: scrollVariants[
|
|
39
|
+
scrollVariant: scrollVariants[menuType],
|
|
44
40
|
height: height,
|
|
45
41
|
p: 0,
|
|
46
42
|
as: "ul",
|
|
47
43
|
role: "list"
|
|
48
|
-
},
|
|
49
|
-
let isFocused = false;
|
|
50
|
-
const blockItemFocused = focusIndex >= blockIndex;
|
|
51
|
-
|
|
52
|
-
if (blockItemFocused) {
|
|
53
|
-
isFocused = focusIndex - blockIndex === index;
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
return /*#__PURE__*/React.createElement(SubmenuContext.Provider, {
|
|
57
|
-
value: {
|
|
58
|
-
isFocused,
|
|
59
|
-
handleKeyDown
|
|
60
|
-
}
|
|
61
|
-
}, child);
|
|
62
|
-
})));
|
|
44
|
+
}, children));
|
|
63
45
|
};
|
|
64
46
|
|
|
65
47
|
ScrollableBlock.propTypes = {
|
|
@@ -72,7 +72,8 @@ const InputIconToggle = ({
|
|
|
72
72
|
onFocus: onFocus,
|
|
73
73
|
onBlur: onBlur,
|
|
74
74
|
onMouseDown: onMouseDown,
|
|
75
|
-
tabIndex: iconTabIndex
|
|
75
|
+
tabIndex: iconTabIndex,
|
|
76
|
+
"data-element": "input-icon-toggle"
|
|
76
77
|
}, /*#__PURE__*/_react.default.createElement(_icon.default, {
|
|
77
78
|
type: type
|
|
78
79
|
}));
|
|
@@ -26,6 +26,8 @@ export interface LinkProps extends StyledLinkProps, React.AriaAttributes {
|
|
|
26
26
|
ariaLabel?: string;
|
|
27
27
|
/** allows to set rel property in <a> tag */
|
|
28
28
|
rel?: string;
|
|
29
|
+
/** @ignore @private internal prop to be set when no href or onClick passed */
|
|
30
|
+
placeholderTabIndex?: boolean;
|
|
29
31
|
}
|
|
30
32
|
export declare const Link: React.ForwardRefExoticComponent<LinkProps & React.RefAttributes<HTMLButtonElement | HTMLLinkElement>>;
|
|
31
33
|
export default Link;
|
|
@@ -45,6 +45,7 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
45
45
|
target,
|
|
46
46
|
variant = "default",
|
|
47
47
|
isDarkBackground,
|
|
48
|
+
placeholderTabIndex,
|
|
48
49
|
...rest
|
|
49
50
|
}, ref) => {
|
|
50
51
|
const l = (0, _useLocale.default)();
|
|
@@ -104,7 +105,11 @@ const Link = /*#__PURE__*/_react.default.forwardRef(({
|
|
|
104
105
|
type = "button";
|
|
105
106
|
}
|
|
106
107
|
|
|
107
|
-
return /*#__PURE__*/_react.default.createElement(type, componentProps,
|
|
108
|
+
return /*#__PURE__*/_react.default.createElement(type, { ...componentProps,
|
|
109
|
+
...(placeholderTabIndex && href === undefined && !onClick && {
|
|
110
|
+
tabIndex: -1
|
|
111
|
+
})
|
|
112
|
+
}, /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, renderLinkIcon(), /*#__PURE__*/_react.default.createElement(_link.StyledContent, null, isSkipLink ? l.link.skipLinkLabel() : children), renderLinkIcon("right")));
|
|
108
113
|
};
|
|
109
114
|
|
|
110
115
|
return /*#__PURE__*/_react.default.createElement(_link.StyledLink, _extends({
|
|
@@ -182,6 +187,7 @@ Link.propTypes = {
|
|
|
182
187
|
"onClick": _propTypes.default.func,
|
|
183
188
|
"onKeyDown": _propTypes.default.func,
|
|
184
189
|
"onMouseDown": _propTypes.default.func,
|
|
190
|
+
"placeholderTabIndex": _propTypes.default.bool,
|
|
185
191
|
"rel": _propTypes.default.string,
|
|
186
192
|
"target": _propTypes.default.string,
|
|
187
193
|
"tooltipMessage": _propTypes.default.string,
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
import React from "react";
|
|
2
|
+
declare function characterNavigation(inputString?: string, focusableItems?: Element[]): Element | undefined;
|
|
3
|
+
declare function menuKeyboardNavigation(event: React.KeyboardEvent, focusableItems: Element[]): number | undefined;
|
|
4
|
+
export { characterNavigation, menuKeyboardNavigation };
|
|
@@ -8,31 +8,32 @@ exports.menuKeyboardNavigation = menuKeyboardNavigation;
|
|
|
8
8
|
|
|
9
9
|
var _events = _interopRequireDefault(require("../../../../__internal__/utils/helpers/events"));
|
|
10
10
|
|
|
11
|
-
var
|
|
11
|
+
var _locators = require("../locators");
|
|
12
12
|
|
|
13
13
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
14
14
|
|
|
15
|
-
function characterNavigation(inputString, focusableItems
|
|
16
|
-
if (!inputString) return
|
|
15
|
+
function characterNavigation(inputString, focusableItems) {
|
|
16
|
+
if (!inputString || !focusableItems) return undefined;
|
|
17
17
|
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
return
|
|
18
|
+
const getInnerText = element => {
|
|
19
|
+
var _element$textContent, _element$textContent$;
|
|
20
|
+
|
|
21
|
+
return element === null || element === void 0 ? void 0 : (_element$textContent = element.textContent) === null || _element$textContent === void 0 ? void 0 : (_element$textContent$ = _element$textContent.split("\n")) === null || _element$textContent$ === void 0 ? void 0 : _element$textContent$.map(text => text.trim()).join(" ");
|
|
22
22
|
};
|
|
23
23
|
|
|
24
24
|
const getMenuText = element => {
|
|
25
|
-
|
|
26
|
-
return element.submenu;
|
|
27
|
-
}
|
|
25
|
+
var _getInnerText;
|
|
28
26
|
|
|
29
|
-
return
|
|
27
|
+
return (_getInnerText = getInnerText(element)) === null || _getInnerText === void 0 ? void 0 : _getInnerText.toLowerCase();
|
|
30
28
|
};
|
|
31
29
|
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
30
|
+
const matchingItem = focusableItems.find(item => {
|
|
31
|
+
var _getMenuText;
|
|
32
|
+
|
|
33
|
+
if (!(item !== null && item !== void 0 && item.getAttribute("data-component"))) return false;
|
|
34
|
+
return [_locators.MENU_ITEM, _locators.SCROLLABLE_BLOCK_PARENT].includes(item.getAttribute("data-component")) && ((_getMenuText = getMenuText(item)) === null || _getMenuText === void 0 ? void 0 : _getMenuText.startsWith(inputString.toLowerCase()));
|
|
35
|
+
});
|
|
36
|
+
return matchingItem;
|
|
36
37
|
}
|
|
37
38
|
|
|
38
39
|
function menuKeyboardNavigation(event, focusableItems) {
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const MENU_ITEM: "menu-item";
|
|
2
|
+
export const SCROLLABLE_BLOCK: "submenu-scrollable-block";
|
|
3
|
+
export const SCROLLABLE_BLOCK_PARENT: "scrollable-block-parent";
|
|
4
|
+
export const ALL_CHILDREN_SELECTOR: string;
|
|
5
|
+
export const BLOCK_INDEX_SELECTOR: string;
|
|
6
|
+
export const MENU_ITEM_CHILDREN_LOCATOR: string;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.MENU_ITEM_CHILDREN_LOCATOR = exports.BLOCK_INDEX_SELECTOR = exports.ALL_CHILDREN_SELECTOR = exports.SCROLLABLE_BLOCK_PARENT = exports.SCROLLABLE_BLOCK = exports.MENU_ITEM = void 0;
|
|
7
|
+
const MENU_ITEM = "menu-item";
|
|
8
|
+
exports.MENU_ITEM = MENU_ITEM;
|
|
9
|
+
const SCROLLABLE_BLOCK = "submenu-scrollable-block";
|
|
10
|
+
exports.SCROLLABLE_BLOCK = SCROLLABLE_BLOCK;
|
|
11
|
+
const SCROLLABLE_BLOCK_PARENT = "scrollable-block-parent";
|
|
12
|
+
exports.SCROLLABLE_BLOCK_PARENT = SCROLLABLE_BLOCK_PARENT;
|
|
13
|
+
const ALL_CHILDREN_SELECTOR = `[data-component='${MENU_ITEM}'], [data-component='${SCROLLABLE_BLOCK_PARENT}']`;
|
|
14
|
+
exports.ALL_CHILDREN_SELECTOR = ALL_CHILDREN_SELECTOR;
|
|
15
|
+
const BLOCK_INDEX_SELECTOR = `[data-component='${MENU_ITEM}'], [data-component='${SCROLLABLE_BLOCK}']`;
|
|
16
|
+
exports.BLOCK_INDEX_SELECTOR = BLOCK_INDEX_SELECTOR;
|
|
17
|
+
const MENU_ITEM_CHILDREN_LOCATOR = `[data-component='${MENU_ITEM}']`;
|
|
18
|
+
exports.MENU_ITEM_CHILDREN_LOCATOR = MENU_ITEM_CHILDREN_LOCATOR;
|