@carbon-labs/react-ui-shell 0.76.0 → 0.78.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.
@@ -10,7 +10,7 @@ import { SideNavIcon, Layer, Button } from '@carbon/react';
10
10
  import { breakpoints } from '../node_modules/@carbon/layout/es/index.js';
11
11
  import cx from 'classnames';
12
12
  import PropTypes from 'prop-types';
13
- import React__default, { useContext, useState, useRef, useEffect } from 'react';
13
+ import React__default, { useContext, useState, useRef, useCallback, useMemo, useEffect } from 'react';
14
14
  import { CARBON_SIDENAV_ITEMS } from './_utils.js';
15
15
  import { useId } from '../internal/useId.js';
16
16
  import { Escape, Tab, ArrowLeft as ArrowLeft$1, ArrowRight } from '../internal/keyboard/keys.js';
@@ -43,7 +43,8 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
43
43
  onMenuToggle,
44
44
  primary
45
45
  }, ref) {
46
- const depth = propDepth;
46
+ const depth = propDepth || 0;
47
+ const isSideNavCollapsed = isSideNavExpanded === false;
47
48
  const {
48
49
  isTreeview,
49
50
  expanded,
@@ -66,62 +67,16 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
66
67
  currentPrimaryMenu,
67
68
  setCurrentPrimaryMenu
68
69
  } = useContext(SideNavContext);
69
- const className = cx({
70
- [`${prefix}--side-nav__item`]: true,
71
- [`${prefix}--side-nav__item--primary`]: primary,
72
- [`${prefix}--side-nav__item--active`]: !primary && (active || hasActiveDescendant(children) && !isExpanded),
73
- [`${prefix}--side-nav__item--has-active-descendant`]: active || hasActiveDescendant(children) && !isExpanded,
74
- [`${prefix}--side-nav__item--icon`]: IconElement,
75
- [`${prefix}--side-nav__item--large`]: large,
76
- [customClassName]: !!customClassName
77
- });
78
- const buttonClassName = cx({
79
- [`${prefix}--side-nav__submenu`]: true,
80
- [`${prefix}--side-nav__submenu--active`]: active || hasActiveDescendant(children) && isExpanded
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
- });
86
- const buttonRef = useRef(null);
87
- const listRef = useRef(null);
88
- const menuRef = useMergedRefs([buttonRef, ref]);
89
- if (!isSideNavExpanded && isExpanded && isRail) {
90
- setIsExpanded(false);
91
- setPrevExpanded(true);
92
- } else if (isSideNavExpanded && prevExpanded && isRail) {
93
- setIsExpanded(true);
94
- setPrevExpanded(false);
95
- }
96
- let childrenToRender = children;
97
-
98
- // modify nested SideNavMenus
99
- childrenToRender = React__default.Children.map(children, child => {
100
- if (/*#__PURE__*/React__default.isValidElement(child)) {
101
- const childJsxElement = child;
102
- const childDisplayName = childJsxElement.type?.displayName ?? childJsxElement.type?.name;
103
- const isCarbonSideNavItem = CARBON_SIDENAV_ITEMS.includes(childDisplayName);
104
- return /*#__PURE__*/React__default.cloneElement(child, {
105
- ...(isCarbonSideNavItem && {
106
- isSideNavExpanded: isSideNavExpanded
107
- }),
108
- ...{
109
- depth: depth + 1
110
- }
111
- });
112
- }
113
- return child;
114
- });
115
70
 
116
71
  /**
117
72
  Defining the children parameter with the type ReactNode | ReactNode[]. This allows for various possibilities:
118
73
  a single element, an array of elements, or null or undefined.
119
74
  **/
120
- function hasActiveDescendant(children) {
75
+ const hasActiveDescendantInner = useCallback(children => {
121
76
  if (Array.isArray(children)) {
122
77
  return children.some(child => {
123
78
  if (! /*#__PURE__*/React__default.isValidElement(child)) {
124
- setActive(false);
79
+ // setActive(false);
125
80
  return false;
126
81
  }
127
82
 
@@ -129,8 +84,8 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
129
84
  safety when accessing their props.
130
85
  **/
131
86
  const props = child.props;
132
- if (props.isActive === true || props['aria-current'] || props.children instanceof Array && hasActiveDescendant(props.children)) {
133
- setActive(true);
87
+ if (props.isActive === true || props['aria-current'] || props.children instanceof Array && hasActiveDescendantInner(props.children)) {
88
+ // setActive(true);
134
89
  return true;
135
90
  }
136
91
  return false;
@@ -142,12 +97,19 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
142
97
  if (/*#__PURE__*/React__default.isValidElement(children)) {
143
98
  const props = children.props;
144
99
  if (props.isActive === true || props['aria-current']) {
145
- setActive(true);
100
+ // setActive(true);
101
+
146
102
  return true;
147
103
  }
148
104
  }
149
105
  return false;
150
- }
106
+ }, []);
107
+ const hasActiveDescendant = useMemo(() => {
108
+ return hasActiveDescendantInner(children);
109
+ }, [children, hasActiveDescendantInner]);
110
+ useEffect(() => {
111
+ setActive(hasActiveDescendant);
112
+ }, [hasActiveDescendant]);
151
113
  useEffect(() => {
152
114
  if (navType == SIDE_NAV_TYPE.RAIL_PANEL) {
153
115
  // grab first link to redirect if clicked when not expanded
@@ -163,6 +125,52 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
163
125
  // if depth is more than 0, that means its nested, thus we set treeview mode
164
126
  setIsTreeview?.(true);
165
127
  }, [isTreeview]);
128
+ const className = cx({
129
+ [`${prefix}--side-nav__item`]: true,
130
+ [`${prefix}--side-nav__item--primary`]: primary,
131
+ [`${prefix}--side-nav__item--active`]: !primary && (active || hasActiveDescendant && !isExpanded),
132
+ [`${prefix}--side-nav__item--has-active-descendant`]: active || hasActiveDescendant && !isExpanded,
133
+ [`${prefix}--side-nav__item--icon`]: IconElement,
134
+ [`${prefix}--side-nav__item--large`]: large,
135
+ [customClassName]: !!customClassName
136
+ });
137
+ const buttonClassName = cx({
138
+ [`${prefix}--side-nav__submenu`]: true,
139
+ [`${prefix}--side-nav__submenu--active`]: active || hasActiveDescendant && isExpanded
140
+ });
141
+ const primaryClassNames = cx({
142
+ [`${prefix}--side-nav__menu-secondary-wrapper`]: true,
143
+ [`${prefix}--side-nav__menu-secondary-wrapper-expanded`]: isSideNavExpanded && isSecondaryOpen && currentPrimaryMenu === uniqueId
144
+ });
145
+ const buttonRef = useRef(null);
146
+ const listRef = useRef(null);
147
+ const menuRef = useMergedRefs([buttonRef, ref]);
148
+ if (isSideNavCollapsed && isExpanded && isRail) {
149
+ setIsExpanded(false);
150
+ setPrevExpanded(true);
151
+ } else if (!isSideNavCollapsed && prevExpanded && isRail) {
152
+ setIsExpanded(true);
153
+ setPrevExpanded(false);
154
+ }
155
+ let childrenToRender = children;
156
+
157
+ // modify nested SideNavMenus
158
+ childrenToRender = React__default.Children.map(children, child => {
159
+ if (/*#__PURE__*/React__default.isValidElement(child)) {
160
+ const childJsxElement = child;
161
+ const childDisplayName = childJsxElement.type?.displayName ?? childJsxElement.type?.name;
162
+ const isCarbonSideNavItem = CARBON_SIDENAV_ITEMS.includes(childDisplayName);
163
+ return /*#__PURE__*/React__default.cloneElement(child, {
164
+ ...(isCarbonSideNavItem && {
165
+ isSideNavExpanded: !isSideNavCollapsed
166
+ }),
167
+ ...{
168
+ depth: depth + 1
169
+ }
170
+ });
171
+ }
172
+ return child;
173
+ });
166
174
 
167
175
  /**
168
176
  * Returns the parent SideNavMenu, if node is actually inside one.
@@ -288,7 +296,7 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
288
296
  }
289
297
 
290
298
  // will always open to the menu with an active element
291
- if (primary && (active || hasActiveDescendant(children))) {
299
+ if (primary && (active || hasActiveDescendant)) {
292
300
  setIsExpanded(true);
293
301
  }
294
302
  }, [sideNavExpanded]);
@@ -45,7 +45,8 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
45
45
  onMenuToggle,
46
46
  primary
47
47
  }, ref) {
48
- const depth = propDepth;
48
+ const depth = propDepth || 0;
49
+ const isSideNavCollapsed = isSideNavExpanded === false;
49
50
  const {
50
51
  isTreeview,
51
52
  expanded,
@@ -68,62 +69,16 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
68
69
  currentPrimaryMenu,
69
70
  setCurrentPrimaryMenu
70
71
  } = React__default.useContext(SideNav.SideNavContext);
71
- const className = cx({
72
- [`${prefix}--side-nav__item`]: true,
73
- [`${prefix}--side-nav__item--primary`]: primary,
74
- [`${prefix}--side-nav__item--active`]: !primary && (active || hasActiveDescendant(children) && !isExpanded),
75
- [`${prefix}--side-nav__item--has-active-descendant`]: active || hasActiveDescendant(children) && !isExpanded,
76
- [`${prefix}--side-nav__item--icon`]: IconElement,
77
- [`${prefix}--side-nav__item--large`]: large,
78
- [customClassName]: !!customClassName
79
- });
80
- const buttonClassName = cx({
81
- [`${prefix}--side-nav__submenu`]: true,
82
- [`${prefix}--side-nav__submenu--active`]: active || hasActiveDescendant(children) && isExpanded
83
- });
84
- const primaryClassNames = cx({
85
- [`${prefix}--side-nav__menu-secondary-wrapper`]: true,
86
- [`${prefix}--side-nav__menu-secondary-wrapper-expanded`]: isSideNavExpanded && isSecondaryOpen && currentPrimaryMenu === uniqueId
87
- });
88
- const buttonRef = React__default.useRef(null);
89
- const listRef = React__default.useRef(null);
90
- const menuRef = useMergedRefs.useMergedRefs([buttonRef, ref]);
91
- if (!isSideNavExpanded && isExpanded && isRail) {
92
- setIsExpanded(false);
93
- setPrevExpanded(true);
94
- } else if (isSideNavExpanded && prevExpanded && isRail) {
95
- setIsExpanded(true);
96
- setPrevExpanded(false);
97
- }
98
- let childrenToRender = children;
99
-
100
- // modify nested SideNavMenus
101
- childrenToRender = React__default.Children.map(children, child => {
102
- if (/*#__PURE__*/React__default.isValidElement(child)) {
103
- const childJsxElement = child;
104
- const childDisplayName = childJsxElement.type?.displayName ?? childJsxElement.type?.name;
105
- const isCarbonSideNavItem = _utils.CARBON_SIDENAV_ITEMS.includes(childDisplayName);
106
- return /*#__PURE__*/React__default.cloneElement(child, {
107
- ...(isCarbonSideNavItem && {
108
- isSideNavExpanded: isSideNavExpanded
109
- }),
110
- ...{
111
- depth: depth + 1
112
- }
113
- });
114
- }
115
- return child;
116
- });
117
72
 
118
73
  /**
119
74
  Defining the children parameter with the type ReactNode | ReactNode[]. This allows for various possibilities:
120
75
  a single element, an array of elements, or null or undefined.
121
76
  **/
122
- function hasActiveDescendant(children) {
77
+ const hasActiveDescendantInner = React__default.useCallback(children => {
123
78
  if (Array.isArray(children)) {
124
79
  return children.some(child => {
125
80
  if (! /*#__PURE__*/React__default.isValidElement(child)) {
126
- setActive(false);
81
+ // setActive(false);
127
82
  return false;
128
83
  }
129
84
 
@@ -131,8 +86,8 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
131
86
  safety when accessing their props.
132
87
  **/
133
88
  const props = child.props;
134
- if (props.isActive === true || props['aria-current'] || props.children instanceof Array && hasActiveDescendant(props.children)) {
135
- setActive(true);
89
+ if (props.isActive === true || props['aria-current'] || props.children instanceof Array && hasActiveDescendantInner(props.children)) {
90
+ // setActive(true);
136
91
  return true;
137
92
  }
138
93
  return false;
@@ -144,12 +99,19 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
144
99
  if (/*#__PURE__*/React__default.isValidElement(children)) {
145
100
  const props = children.props;
146
101
  if (props.isActive === true || props['aria-current']) {
147
- setActive(true);
102
+ // setActive(true);
103
+
148
104
  return true;
149
105
  }
150
106
  }
151
107
  return false;
152
- }
108
+ }, []);
109
+ const hasActiveDescendant = React__default.useMemo(() => {
110
+ return hasActiveDescendantInner(children);
111
+ }, [children, hasActiveDescendantInner]);
112
+ React__default.useEffect(() => {
113
+ setActive(hasActiveDescendant);
114
+ }, [hasActiveDescendant]);
153
115
  React__default.useEffect(() => {
154
116
  if (navType == SideNav.SIDE_NAV_TYPE.RAIL_PANEL) {
155
117
  // grab first link to redirect if clicked when not expanded
@@ -165,6 +127,52 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
165
127
  // if depth is more than 0, that means its nested, thus we set treeview mode
166
128
  setIsTreeview?.(true);
167
129
  }, [isTreeview]);
130
+ const className = cx({
131
+ [`${prefix}--side-nav__item`]: true,
132
+ [`${prefix}--side-nav__item--primary`]: primary,
133
+ [`${prefix}--side-nav__item--active`]: !primary && (active || hasActiveDescendant && !isExpanded),
134
+ [`${prefix}--side-nav__item--has-active-descendant`]: active || hasActiveDescendant && !isExpanded,
135
+ [`${prefix}--side-nav__item--icon`]: IconElement,
136
+ [`${prefix}--side-nav__item--large`]: large,
137
+ [customClassName]: !!customClassName
138
+ });
139
+ const buttonClassName = cx({
140
+ [`${prefix}--side-nav__submenu`]: true,
141
+ [`${prefix}--side-nav__submenu--active`]: active || hasActiveDescendant && isExpanded
142
+ });
143
+ const primaryClassNames = cx({
144
+ [`${prefix}--side-nav__menu-secondary-wrapper`]: true,
145
+ [`${prefix}--side-nav__menu-secondary-wrapper-expanded`]: isSideNavExpanded && isSecondaryOpen && currentPrimaryMenu === uniqueId
146
+ });
147
+ const buttonRef = React__default.useRef(null);
148
+ const listRef = React__default.useRef(null);
149
+ const menuRef = useMergedRefs.useMergedRefs([buttonRef, ref]);
150
+ if (isSideNavCollapsed && isExpanded && isRail) {
151
+ setIsExpanded(false);
152
+ setPrevExpanded(true);
153
+ } else if (!isSideNavCollapsed && prevExpanded && isRail) {
154
+ setIsExpanded(true);
155
+ setPrevExpanded(false);
156
+ }
157
+ let childrenToRender = children;
158
+
159
+ // modify nested SideNavMenus
160
+ childrenToRender = React__default.Children.map(children, child => {
161
+ if (/*#__PURE__*/React__default.isValidElement(child)) {
162
+ const childJsxElement = child;
163
+ const childDisplayName = childJsxElement.type?.displayName ?? childJsxElement.type?.name;
164
+ const isCarbonSideNavItem = _utils.CARBON_SIDENAV_ITEMS.includes(childDisplayName);
165
+ return /*#__PURE__*/React__default.cloneElement(child, {
166
+ ...(isCarbonSideNavItem && {
167
+ isSideNavExpanded: !isSideNavCollapsed
168
+ }),
169
+ ...{
170
+ depth: depth + 1
171
+ }
172
+ });
173
+ }
174
+ return child;
175
+ });
168
176
 
169
177
  /**
170
178
  * Returns the parent SideNavMenu, if node is actually inside one.
@@ -290,7 +298,7 @@ const SideNavMenu = /*#__PURE__*/React__default.forwardRef(function SideNavMenu(
290
298
  }
291
299
 
292
300
  // will always open to the menu with an active element
293
- if (primary && (active || hasActiveDescendant(children))) {
301
+ if (primary && (active || hasActiveDescendant)) {
294
302
  setIsExpanded(true);
295
303
  }
296
304
  }, [sideNavExpanded]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carbon-labs/react-ui-shell",
3
- "version": "0.76.0",
3
+ "version": "0.78.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
@@ -42,5 +42,5 @@
42
42
  "dependencies": {
43
43
  "@ibm/telemetry-js": "^1.9.1"
44
44
  },
45
- "gitHead": "d39533097983aea53a3add7478e0a5e7cf180305"
45
+ "gitHead": "e481d1b96f41b9cf2d498f7021bf2d507d672fe1"
46
46
  }
@@ -118,24 +118,29 @@ div:has(.#{$prefix}--header)
118
118
  }
119
119
  }
120
120
 
121
+ // Mobile styles for side nav - exclude rail and panel variants
121
122
  @include breakpoint-down(md) {
122
- .#{$prefix}--side-nav__submenu {
123
- padding: 0 $spacing-05 0 convert.to-rem(14px);
124
- }
123
+ .#{$prefix}--side-nav:not(.#{$prefix}--side-nav--rail):not(
124
+ .#{$prefix}--side-nav--panel
125
+ ) {
126
+ .#{$prefix}--side-nav__submenu {
127
+ padding: 0 $spacing-05 0 convert.to-rem(14px);
128
+ }
125
129
 
126
- .#{$prefix}--side-nav__submenu,
127
- .#{$prefix}--side-nav__link,
128
- .#{$prefix}--side-nav__menu a.#{$prefix}--side-nav__link {
129
- block-size: $spacing-08;
130
- }
130
+ .#{$prefix}--side-nav__submenu,
131
+ .#{$prefix}--side-nav__link,
132
+ .#{$prefix}--side-nav__menu a.#{$prefix}--side-nav__link {
133
+ block-size: $spacing-08;
134
+ }
131
135
 
132
- .#{$prefix}--side-nav__icon {
133
- margin-inline-end: convert.to-rem(14px);
134
- }
136
+ .#{$prefix}--side-nav__icon {
137
+ margin-inline-end: convert.to-rem(14px);
138
+ }
135
139
 
136
- .#{$prefix}--side-nav__icon > svg {
137
- block-size: convert.to-rem(20px);
138
- inline-size: convert.to-rem(20px);
140
+ .#{$prefix}--side-nav__icon > svg {
141
+ block-size: convert.to-rem(20px);
142
+ inline-size: convert.to-rem(20px);
143
+ }
139
144
  }
140
145
  }
141
146
 
@@ -605,7 +610,8 @@ div:has(.#{$prefix}--header)
605
610
  }
606
611
 
607
612
  @each $breakpoint in ('sm', 'md', 'lg', 'xlg', 'max') {
608
- .#{$prefix}--side-nav--rail.#{$prefix}--side-nav--hide-rail-breakpoint-down-#{$breakpoint} {
613
+ .#{$prefix}--side-nav--rail.#{$prefix}--side-nav--hide-rail-breakpoint-down-#{$breakpoint},
614
+ .#{$prefix}--side-nav--panel.#{$prefix}--side-nav--hide-rail-breakpoint-down-#{$breakpoint} {
609
615
  @include breakpoint-down($breakpoint) {
610
616
  display: none;
611
617
  }