@carbon-labs/react-ui-shell 0.42.0 → 0.44.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/es/components/SideNav.d.ts +2 -0
- package/es/components/SideNav.js +33 -10
- package/es/components/SideNavItems.js +3 -1
- package/es/components/SideNavMenu.d.ts +19 -0
- package/es/components/SideNavMenu.js +127 -20
- package/es/node_modules/@carbon/icons-react/es/generated/bucket-0.js +2956 -0
- package/lib/components/SideNav.d.ts +2 -0
- package/lib/components/SideNav.js +33 -10
- package/lib/components/SideNavItems.js +3 -1
- package/lib/components/SideNavMenu.d.ts +19 -0
- package/lib/components/SideNavMenu.js +123 -16
- package/lib/node_modules/@carbon/icons-react/es/generated/bucket-0.js +3082 -0
- package/package.json +2 -2
- package/scss/styles/_side-nav.scss +80 -0
|
@@ -43,6 +43,8 @@ interface SideNavContextData {
|
|
|
43
43
|
navType?: SIDE_NAV_TYPE;
|
|
44
44
|
isTreeview?: boolean;
|
|
45
45
|
setIsTreeview?: (value: boolean) => void;
|
|
46
|
+
currentPrimaryMenu?: string;
|
|
47
|
+
setCurrentPrimaryMenu?: (value: string) => void;
|
|
46
48
|
}
|
|
47
49
|
export declare const SideNavContext: React.Context<SideNavContextData>;
|
|
48
50
|
export declare const SideNav: React.ForwardRefExoticComponent<Omit<SideNavProps, "ref"> & React.RefAttributes<HTMLElement>>;
|
package/es/components/SideNav.js
CHANGED
|
@@ -75,6 +75,7 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
75
75
|
const expanded = controlled ? expandedProp : expandedState;
|
|
76
76
|
const sideNavRef = useRef(null);
|
|
77
77
|
const navRef = useMergedRefs([sideNavRef, ref]);
|
|
78
|
+
const [currentPrimaryMenu, setCurrentPrimaryMenu] = useState();
|
|
78
79
|
const sideNavToggleText = expandedState ? t('collapse.sidenav') : t('expand.sidenav');
|
|
79
80
|
const handleToggle = function (event) {
|
|
80
81
|
let value = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : !expanded;
|
|
@@ -149,11 +150,22 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
149
150
|
resetNodeTabIndices();
|
|
150
151
|
}
|
|
151
152
|
}, [prefix, internalIsTreeview]);
|
|
153
|
+
const smMediaQuery = `(min-width: ${breakpoints.sm.width})`;
|
|
154
|
+
const isSm = useMatchMedia(smMediaQuery);
|
|
152
155
|
useEffect(() => {
|
|
153
156
|
if (sideNavRef.current) {
|
|
157
|
+
const backButton = sideNavRef?.current.querySelector(`.${prefix}--side-nav__back-button`);
|
|
154
158
|
const firstElement = sideNavRef?.current?.querySelector('a, button');
|
|
155
|
-
if (
|
|
156
|
-
|
|
159
|
+
if (navType == SIDE_NAV_TYPE.PANEL || expanded) {
|
|
160
|
+
if (isSm && backButton) {
|
|
161
|
+
backButton.tabIndex = 0;
|
|
162
|
+
const firstElementAfterBack = backButton.nextElementSibling?.querySelector('a, button');
|
|
163
|
+
if (firstElementAfterBack) {
|
|
164
|
+
firstElementAfterBack.tabIndex = 0;
|
|
165
|
+
}
|
|
166
|
+
} else if (firstElement) {
|
|
167
|
+
firstElement.tabIndex = 0;
|
|
168
|
+
}
|
|
157
169
|
}
|
|
158
170
|
}
|
|
159
171
|
}, [expanded]);
|
|
@@ -221,15 +233,17 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
221
233
|
let nextFocusNode = null;
|
|
222
234
|
if (match(event, ArrowUp)) {
|
|
223
235
|
const parentNode = parentSideNavMenu(treeWalker.currentNode);
|
|
224
|
-
let previousSideNavMenu =
|
|
225
|
-
|
|
236
|
+
let previousSideNavMenu = treeWalker.currentNode?.previousSibling;
|
|
226
237
|
// skip the divider
|
|
227
238
|
if (previousSideNavMenu?.classList.contains(`${prefix}--side-nav__divider`)) {
|
|
228
239
|
previousSideNavMenu = previousSideNavMenu?.previousElementSibling;
|
|
229
240
|
}
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
if (
|
|
241
|
+
if (previousSideNavMenu?.classList.contains(`${prefix}--side-nav__item--primary`)) {
|
|
242
|
+
nextFocusNode = previousSideNavMenu;
|
|
243
|
+
} else if (treeWalker.currentNode.classList.contains(`${prefix}--side-nav__item--primary`)) {
|
|
244
|
+
nextFocusNode = treeWalker.currentNode.previousSibling;
|
|
245
|
+
} // when previous sibling is open, go to its last item
|
|
246
|
+
else if (previousSideNavMenu?.getAttribute('aria-expanded') == 'true') {
|
|
233
247
|
const allItems = previousSideNavMenu.querySelectorAll(`.${prefix}--side-nav__item`);
|
|
234
248
|
const lastMenu = allItems[allItems.length - 1];
|
|
235
249
|
if (lastMenu && lastMenu.getAttribute('aria-expanded') == 'false') {
|
|
@@ -241,7 +255,7 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
241
255
|
nextFocusNode = treeWalker.previousSibling();
|
|
242
256
|
|
|
243
257
|
// first item in the menu, go back up to SideNavMenu button
|
|
244
|
-
if (nextFocusNode == null) {
|
|
258
|
+
if (nextFocusNode == null && !parentNode.classList.contains(`${prefix}--side-nav__item--primary`)) {
|
|
245
259
|
nextFocusNode = parentNode;
|
|
246
260
|
}
|
|
247
261
|
}
|
|
@@ -253,6 +267,11 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
253
267
|
const parent = parentSideNavMenu(treeWalker.currentNode);
|
|
254
268
|
nextFocusNode = parent?.nextElementSibling;
|
|
255
269
|
}
|
|
270
|
+
} else if (treeWalker.currentNode.classList.contains(`${prefix}--side-nav__item--primary`)) {
|
|
271
|
+
nextFocusNode = treeWalker.currentNode.nextSibling;
|
|
272
|
+
if (nextFocusNode?.classList.contains(`${prefix}--side-nav__divider`)) {
|
|
273
|
+
nextFocusNode = nextFocusNode.nextSibling;
|
|
274
|
+
}
|
|
256
275
|
} else {
|
|
257
276
|
nextFocusNode = treeWalker.nextNode();
|
|
258
277
|
}
|
|
@@ -327,7 +346,9 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
327
346
|
function resetNodeTabIndices() {
|
|
328
347
|
const items = sideNavRef?.current?.querySelectorAll('[tabIndex="0"]') ?? [];
|
|
329
348
|
items.forEach(item => {
|
|
330
|
-
if (item.classList.contains(`${prefix}--side-nav__toggle`))
|
|
349
|
+
if (item.classList.contains(`${prefix}--side-nav__toggle`) || item.classList.contains(`${prefix}--side-nav__back-button`) ||
|
|
350
|
+
// checks if a link is in primary nav
|
|
351
|
+
item.classList.contains(`${prefix}--side-nav__link`) && item.closest(`ul`)?.getAttribute('aria-label') === ariaLabel) {
|
|
331
352
|
return;
|
|
332
353
|
}
|
|
333
354
|
item.tabIndex = -1;
|
|
@@ -358,7 +379,9 @@ function SideNavRenderFunction(_ref, ref) {
|
|
|
358
379
|
isRail,
|
|
359
380
|
navType,
|
|
360
381
|
isTreeview: internalIsTreeview,
|
|
361
|
-
setIsTreeview
|
|
382
|
+
setIsTreeview,
|
|
383
|
+
currentPrimaryMenu,
|
|
384
|
+
setCurrentPrimaryMenu
|
|
362
385
|
}
|
|
363
386
|
}, isFixedNav || hideOverlay ? null :
|
|
364
387
|
/*#__PURE__*/
|
|
@@ -21,7 +21,8 @@ const SideNavItems = _ref => {
|
|
|
21
21
|
accessibilityLabel: accessibilityLabel
|
|
22
22
|
} = _ref;
|
|
23
23
|
const {
|
|
24
|
-
isTreeview
|
|
24
|
+
isTreeview,
|
|
25
|
+
currentPrimaryMenu
|
|
25
26
|
} = useContext(SideNavContext);
|
|
26
27
|
const listRef = useRef(null); // Adjust type if necessary
|
|
27
28
|
const prefix = usePrefix();
|
|
@@ -57,6 +58,7 @@ const SideNavItems = _ref => {
|
|
|
57
58
|
return /*#__PURE__*/React.createElement("ul", _extends({}, isTreeview && accessibilityLabel, {
|
|
58
59
|
ref: listRef,
|
|
59
60
|
className: className,
|
|
61
|
+
tabIndex: currentPrimaryMenu ? -1 : undefined,
|
|
60
62
|
role: isTreeview ? 'tree' : ''
|
|
61
63
|
}), childrenWithExpandedState);
|
|
62
64
|
};
|
|
@@ -6,6 +6,15 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import React from 'react';
|
|
8
8
|
export interface SideNavMenuProps {
|
|
9
|
+
/**
|
|
10
|
+
* Title for back button in sm screen
|
|
11
|
+
*/
|
|
12
|
+
backButtonTitle?: string;
|
|
13
|
+
/**
|
|
14
|
+
* A custom icon to render on the back button in sm screen
|
|
15
|
+
* default is ArrowLeft
|
|
16
|
+
*/
|
|
17
|
+
backButtonRenderIcon?: React.ComponentType;
|
|
9
18
|
/**
|
|
10
19
|
* An optional CSS class to apply to the component.
|
|
11
20
|
*/
|
|
@@ -23,6 +32,10 @@ export interface SideNavMenuProps {
|
|
|
23
32
|
* SideNavMenu depth to determine spacing
|
|
24
33
|
*/
|
|
25
34
|
depth?: number;
|
|
35
|
+
/**
|
|
36
|
+
* Provide a unique id
|
|
37
|
+
*/
|
|
38
|
+
id?: string;
|
|
26
39
|
/**
|
|
27
40
|
* Indicates whether the SideNavMenu is active.
|
|
28
41
|
*/
|
|
@@ -44,6 +57,12 @@ export interface SideNavMenuProps {
|
|
|
44
57
|
* Indicates if the side navigation container is expanded or collapsed.
|
|
45
58
|
*/
|
|
46
59
|
isSideNavExpanded?: boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Specifies if this is the primary SideNav.
|
|
62
|
+
* If true, child components will open to the right,
|
|
63
|
+
* creating the double-wide navigation layout
|
|
64
|
+
*/
|
|
65
|
+
primary?: boolean;
|
|
47
66
|
/**
|
|
48
67
|
* The boolean to show the flyout menu has been selected.
|
|
49
68
|
*/
|
|
@@ -5,33 +5,45 @@
|
|
|
5
5
|
* LICENSE file in the root directory of this source tree.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
+
import { breakpoints } from '../node_modules/@carbon/layout/es/index.js';
|
|
8
9
|
import cx from '../_virtual/index.js';
|
|
9
10
|
import PropTypes from 'prop-types';
|
|
10
11
|
import React, { useContext, useState, useRef, useEffect } from 'react';
|
|
11
12
|
import { CARBON_SIDENAV_ITEMS } from './_utils.js';
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
13
|
+
import { useId } from '../internal/useId.js';
|
|
14
|
+
import { SideNavIcon, Button } from '@carbon/react';
|
|
15
|
+
import { Escape, ArrowLeft as ArrowLeft$1, ArrowRight } from '../internal/keyboard/keys.js';
|
|
14
16
|
import { match } from '../internal/keyboard/match.js';
|
|
15
17
|
import { usePrefix } from '../internal/usePrefix.js';
|
|
16
18
|
import { SideNavContext, SIDE_NAV_TYPE } from './SideNav.js';
|
|
17
19
|
import { useMergedRefs } from '../internal/useMergedRefs.js';
|
|
18
20
|
import { SharkFinIcon } from './SharkFinIcon.js';
|
|
19
21
|
import { SideNavFlyoutMenu } from './SideNavFlyoutMenu.js';
|
|
20
|
-
import {
|
|
22
|
+
import { SideNavItems } from './SideNavItems.js';
|
|
23
|
+
import { useMatchMedia } from '../internal/useMatchMedia.js';
|
|
24
|
+
import { ArrowLeft } from '../node_modules/@carbon/icons-react/es/generated/bucket-0.js';
|
|
25
|
+
import { ChevronRight, ChevronDown } from '../node_modules/@carbon/icons-react/es/generated/bucket-3.js';
|
|
21
26
|
|
|
22
|
-
var _SharkFinIcon, _ChevronDown;
|
|
27
|
+
var _ArrowLeft, _SharkFinIcon, _ChevronRight, _ChevronDown;
|
|
28
|
+
const smMediaQuery = `(max-width: ${breakpoints.md.width})`;
|
|
23
29
|
const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref) {
|
|
24
30
|
let {
|
|
31
|
+
backButtonRenderIcon = () => _ArrowLeft || (_ArrowLeft = /*#__PURE__*/React.createElement(ArrowLeft, {
|
|
32
|
+
size: 16
|
|
33
|
+
})),
|
|
34
|
+
backButtonTitle = 'My products',
|
|
25
35
|
className: customClassName,
|
|
26
36
|
children,
|
|
27
37
|
defaultExpanded = false,
|
|
28
38
|
depth: propDepth,
|
|
39
|
+
id,
|
|
29
40
|
isActive = false,
|
|
30
41
|
large = false,
|
|
31
42
|
renderIcon: IconElement,
|
|
32
43
|
isSideNavExpanded,
|
|
33
44
|
title,
|
|
34
|
-
onMenuToggle
|
|
45
|
+
onMenuToggle,
|
|
46
|
+
primary
|
|
35
47
|
} = _ref;
|
|
36
48
|
const depth = propDepth;
|
|
37
49
|
const {
|
|
@@ -46,10 +58,19 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
46
58
|
const [isExpanded, setIsExpanded] = useState(defaultExpanded);
|
|
47
59
|
const [active, setActive] = useState(isActive);
|
|
48
60
|
const firstLink = useRef(null);
|
|
61
|
+
const backButtonRef = useRef(null);
|
|
62
|
+
const uid = useId('side-nav-menu');
|
|
63
|
+
const uniqueId = id || uid;
|
|
49
64
|
const [prevExpanded, setPrevExpanded] = useState(defaultExpanded);
|
|
65
|
+
const [isSecondaryOpen, setSecondaryOpen] = useState(defaultExpanded);
|
|
66
|
+
const {
|
|
67
|
+
currentPrimaryMenu,
|
|
68
|
+
setCurrentPrimaryMenu
|
|
69
|
+
} = useContext(SideNavContext);
|
|
50
70
|
const className = cx({
|
|
51
71
|
[`${prefix}--side-nav__item`]: true,
|
|
52
|
-
[`${prefix}--side-nav__item--
|
|
72
|
+
[`${prefix}--side-nav__item--primary`]: primary,
|
|
73
|
+
[`${prefix}--side-nav__item--active`]: !primary && (active || hasActiveDescendant(children) && !isExpanded),
|
|
53
74
|
[`${prefix}--side-nav__item--icon`]: IconElement,
|
|
54
75
|
[`${prefix}--side-nav__item--large`]: large,
|
|
55
76
|
[customClassName]: !!customClassName
|
|
@@ -58,6 +79,10 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
58
79
|
[`${prefix}--side-nav__submenu`]: true,
|
|
59
80
|
[`${prefix}--side-nav__submenu--active`]: active || hasActiveDescendant(children) && isExpanded
|
|
60
81
|
});
|
|
82
|
+
const primaryClassNames = cx({
|
|
83
|
+
[`${prefix}--side-nav__menu-secondary-wrapper`]: true,
|
|
84
|
+
[`${prefix}--side-nav__menu-secondary-wrapper-expanded`]: isSideNavExpanded && isSecondaryOpen && currentPrimaryMenu === uniqueId
|
|
85
|
+
});
|
|
61
86
|
const buttonRef = useRef(null);
|
|
62
87
|
const listRef = useRef(null);
|
|
63
88
|
const menuRef = useMergedRefs([buttonRef, ref]);
|
|
@@ -159,7 +184,7 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
159
184
|
const isMenu = node.hasAttribute('aria-expanded');
|
|
160
185
|
const isExpanded = node.getAttribute('aria-expanded');
|
|
161
186
|
const parent = parentSideNavMenu(node);
|
|
162
|
-
if (match(event, ArrowLeft)) {
|
|
187
|
+
if (match(event, ArrowLeft$1)) {
|
|
163
188
|
event.stopPropagation();
|
|
164
189
|
|
|
165
190
|
// collapse menu
|
|
@@ -168,10 +193,11 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
168
193
|
if (onMenuToggle) {
|
|
169
194
|
onMenuToggle();
|
|
170
195
|
}
|
|
171
|
-
|
|
172
|
-
|
|
196
|
+
if (!primary && isExpanded) {
|
|
197
|
+
setIsExpanded(false);
|
|
198
|
+
}
|
|
173
199
|
// go to previous level's side nav menu button
|
|
174
|
-
} else {
|
|
200
|
+
} else if (!isSm) {
|
|
175
201
|
// since we're in a menu, it finds its own <li>, we go up one more
|
|
176
202
|
const previousMenu = parentSideNavMenu(parent);
|
|
177
203
|
const button = previousMenu.querySelector('button');
|
|
@@ -181,33 +207,74 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
181
207
|
|
|
182
208
|
// go to side nav menu button
|
|
183
209
|
} else if (parent) {
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
210
|
+
if (parent.hasAttribute('aria-expanded')) {
|
|
211
|
+
const button = parent.querySelector('button');
|
|
212
|
+
if (button) {
|
|
213
|
+
button.tabIndex = 0;
|
|
214
|
+
button.focus();
|
|
215
|
+
}
|
|
216
|
+
} else if (!isSm) {
|
|
217
|
+
const previousMenu = parentSideNavMenu(parent);
|
|
218
|
+
const button = previousMenu.querySelector('button');
|
|
219
|
+
button.tabIndex = 0;
|
|
220
|
+
button?.focus();
|
|
221
|
+
}
|
|
187
222
|
}
|
|
188
223
|
}
|
|
189
224
|
if (match(event, ArrowRight)) {
|
|
225
|
+
setIsExpanded(true);
|
|
226
|
+
if (primary && node.hasAttribute('aria-expanded')) {
|
|
227
|
+
event.preventDefault();
|
|
228
|
+
}
|
|
190
229
|
event.stopPropagation();
|
|
191
230
|
|
|
192
231
|
// expand menu when sidenav is expanded
|
|
193
232
|
if (isMenu && sideNavExpanded) {
|
|
194
|
-
setIsExpanded(true);
|
|
195
233
|
if (onMenuToggle) {
|
|
196
234
|
onMenuToggle();
|
|
197
235
|
}
|
|
198
236
|
|
|
199
237
|
// if already expanded, focus on first element
|
|
200
|
-
if (isExpanded == 'true') {
|
|
201
|
-
|
|
238
|
+
if (isExpanded == 'true' || isSm) {
|
|
239
|
+
const nextNode = node.nextElementSibling?.querySelector('a, button');
|
|
202
240
|
if (nextNode) {
|
|
203
241
|
nextNode.tabIndex = 0;
|
|
204
242
|
nextNode.focus();
|
|
205
243
|
}
|
|
244
|
+
if (isSm) {
|
|
245
|
+
const nextNodeAfterBackButton = nextNode.nextElementSibling?.querySelector('a, button');
|
|
246
|
+
if (nextNodeAfterBackButton) {
|
|
247
|
+
nextNodeAfterBackButton.tabIndex = 0;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
206
250
|
}
|
|
207
251
|
}
|
|
208
252
|
}
|
|
209
253
|
}
|
|
210
254
|
}
|
|
255
|
+
function handleOnBackButtonClick(event) {
|
|
256
|
+
const node = event.target;
|
|
257
|
+
const parent = parentSideNavMenu(node);
|
|
258
|
+
const button = parent.querySelector('button');
|
|
259
|
+
if (button) {
|
|
260
|
+
button.tabIndex = 0;
|
|
261
|
+
button.focus();
|
|
262
|
+
}
|
|
263
|
+
setIsExpanded(false);
|
|
264
|
+
}
|
|
265
|
+
useEffect(() => {
|
|
266
|
+
if (isExpanded && primary && setCurrentPrimaryMenu) {
|
|
267
|
+
setCurrentPrimaryMenu(uniqueId);
|
|
268
|
+
}
|
|
269
|
+
setSecondaryOpen(isExpanded);
|
|
270
|
+
}, [isExpanded]);
|
|
271
|
+
useEffect(() => {
|
|
272
|
+
if (currentPrimaryMenu !== uniqueId) {
|
|
273
|
+
setIsExpanded(false);
|
|
274
|
+
} else {
|
|
275
|
+
setIsExpanded(true);
|
|
276
|
+
}
|
|
277
|
+
}, [currentPrimaryMenu]);
|
|
211
278
|
|
|
212
279
|
// save expanded state before SideNav collapse
|
|
213
280
|
const [lastExpandedState, setLastExpandedState] = useState(isExpanded);
|
|
@@ -222,6 +289,14 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
222
289
|
}
|
|
223
290
|
}, [sideNavExpanded]);
|
|
224
291
|
const [openPopover, setOpenPopover] = React.useState(false);
|
|
292
|
+
const isSm = useMatchMedia(smMediaQuery);
|
|
293
|
+
|
|
294
|
+
// keeps the secondary open when moving from small to large breakpoints
|
|
295
|
+
useEffect(() => {
|
|
296
|
+
if (!isSm && uniqueId === currentPrimaryMenu) {
|
|
297
|
+
setIsExpanded(true);
|
|
298
|
+
}
|
|
299
|
+
}, [isSm]);
|
|
225
300
|
const content =
|
|
226
301
|
/*#__PURE__*/
|
|
227
302
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
|
|
@@ -230,7 +305,8 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
230
305
|
"aria-expanded": isExpanded,
|
|
231
306
|
className: className,
|
|
232
307
|
ref: listRef,
|
|
233
|
-
onKeyDown: handleKeyDown
|
|
308
|
+
onKeyDown: handleKeyDown,
|
|
309
|
+
id: uniqueId
|
|
234
310
|
}, /*#__PURE__*/React.createElement("button", {
|
|
235
311
|
"aria-expanded": isExpanded,
|
|
236
312
|
className: buttonClassName,
|
|
@@ -243,10 +319,13 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
243
319
|
if (navType == SIDE_NAV_TYPE.PANEL && !isExpanded && firstLink.current && !sideNavExpanded) {
|
|
244
320
|
setOpenPopover(!openPopover);
|
|
245
321
|
// window.location.href = firstLink.current;
|
|
246
|
-
} else {
|
|
322
|
+
} else if (isSm || !primary || currentPrimaryMenu !== uniqueId) {
|
|
247
323
|
setIsExpanded(!isExpanded);
|
|
248
324
|
setLastExpandedState(!isExpanded);
|
|
249
325
|
}
|
|
326
|
+
if (isSm && backButtonRef.current) {
|
|
327
|
+
backButtonRef.current.focus();
|
|
328
|
+
}
|
|
250
329
|
},
|
|
251
330
|
ref: menuRef,
|
|
252
331
|
type: "button",
|
|
@@ -260,9 +339,24 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
260
339
|
}, title), /*#__PURE__*/React.createElement(SideNavIcon, {
|
|
261
340
|
className: `${prefix}--side-nav__submenu-chevron`,
|
|
262
341
|
small: true
|
|
263
|
-
},
|
|
342
|
+
}, primary ? _ChevronRight || (_ChevronRight = /*#__PURE__*/React.createElement(ChevronRight, {
|
|
264
343
|
size: 20
|
|
265
|
-
}))
|
|
344
|
+
})) : _ChevronDown || (_ChevronDown = /*#__PURE__*/React.createElement(ChevronDown, {
|
|
345
|
+
size: 20
|
|
346
|
+
})))), primary ? /*#__PURE__*/React.createElement("div", {
|
|
347
|
+
className: primaryClassNames
|
|
348
|
+
}, /*#__PURE__*/React.createElement(SideNavItems, {
|
|
349
|
+
accessibilityLabel: {
|
|
350
|
+
'aria-label': `${title} submenu`
|
|
351
|
+
}
|
|
352
|
+
}, isSm && /*#__PURE__*/React.createElement(Button, {
|
|
353
|
+
ref: backButtonRef,
|
|
354
|
+
kind: "ghost",
|
|
355
|
+
size: "md",
|
|
356
|
+
onClick: handleOnBackButtonClick,
|
|
357
|
+
className: `${prefix}--side-nav__back-button`,
|
|
358
|
+
renderIcon: backButtonRenderIcon
|
|
359
|
+
}, backButtonTitle), childrenToRender)) : /*#__PURE__*/React.createElement("ul", {
|
|
266
360
|
className: `${prefix}--side-nav__menu`,
|
|
267
361
|
role: "group"
|
|
268
362
|
}, childrenToRender));
|
|
@@ -275,6 +369,15 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
|
|
|
275
369
|
});
|
|
276
370
|
SideNavMenu.displayName = 'SideNavMenu';
|
|
277
371
|
SideNavMenu.propTypes = {
|
|
372
|
+
/**
|
|
373
|
+
* A custom icon to render on the back button in sm screen
|
|
374
|
+
*/
|
|
375
|
+
// @ts-expect-error - PropTypes are unable to cover this case.
|
|
376
|
+
backButtonRenderIcon: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
|
|
377
|
+
/**
|
|
378
|
+
* Title for back button in sm screen
|
|
379
|
+
*/
|
|
380
|
+
backButtonTitle: PropTypes.string,
|
|
278
381
|
/**
|
|
279
382
|
* Provide <SideNavMenuItem>'s inside of the `SideNavMenu`
|
|
280
383
|
*/
|
|
@@ -293,6 +396,10 @@ SideNavMenu.propTypes = {
|
|
|
293
396
|
* SideNavMenu depth to determine spacing
|
|
294
397
|
*/
|
|
295
398
|
depth: PropTypes.number,
|
|
399
|
+
/**
|
|
400
|
+
* Provide a unique id
|
|
401
|
+
*/
|
|
402
|
+
id: PropTypes.string,
|
|
296
403
|
/**
|
|
297
404
|
* Specify whether the `SideNavMenu` is "active". `SideNavMenu` should be
|
|
298
405
|
* considered active if one of its menu items are a link for the current
|