@carbon-labs/react-ui-shell 0.15.0 → 0.17.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.
@@ -30,16 +30,21 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
30
30
  large = false,
31
31
  renderIcon: IconElement,
32
32
  isSideNavExpanded,
33
- tabIndex,
34
33
  title
35
34
  } = _ref;
36
35
  const depth = propDepth;
37
36
  const {
38
- isRail
37
+ isTreeview,
38
+ expanded,
39
+ navType,
40
+ isRail,
41
+ setIsTreeview
39
42
  } = React.useContext(SideNav.SideNavContext);
43
+ const sideNavExpanded = expanded;
40
44
  const prefix = usePrefix.usePrefix();
41
45
  const [isExpanded, setIsExpanded] = React.useState(defaultExpanded);
42
46
  const [active, setActive] = React.useState(isActive);
47
+ const firstLink = React.useRef(null);
43
48
  const [prevExpanded, setPrevExpanded] = React.useState(defaultExpanded);
44
49
  const className = index.default({
45
50
  [`${prefix}--side-nav__item`]: true,
@@ -82,23 +87,35 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
82
87
  return child;
83
88
  });
84
89
  React.useEffect(() => {
85
- if (depth === 0) return;
86
- const calcButtonOffset = () => {
87
- // menu with icon
88
- if (children && IconElement) {
89
- return depth + 3;
90
+ if (navType == SideNav.SIDE_NAV_TYPE.PANEL) {
91
+ // grab first link to redirect if clicked when not expanded
92
+ if (!firstLink?.current && listRef?.current) {
93
+ const firstLinkElement = listRef.current.querySelector(`.${prefix}--side-nav__menu-item a`);
94
+ firstLink.current = firstLinkElement?.getAttribute('href') ?? '';
90
95
  }
96
+ }
97
+ if (depth === 0) return;
98
+
99
+ // if depth is more than 0, that means its nested, thus we set treeview mode
100
+ setIsTreeview?.(true);
101
+ if (isTreeview) {
102
+ const calcButtonOffset = () => {
103
+ // menu with icon
104
+ if (children && IconElement) {
105
+ return depth + 3;
106
+ }
91
107
 
92
- // menu without icon
93
- if (children) {
94
- return depth * 4;
108
+ // menu without icon
109
+ if (children) {
110
+ return depth * 4;
111
+ }
112
+ return depth;
113
+ };
114
+ if (buttonRef.current) {
115
+ buttonRef.current.style.paddingLeft = `${calcButtonOffset()}rem`;
95
116
  }
96
- return depth;
97
- };
98
- if (buttonRef.current) {
99
- buttonRef.current.style.paddingLeft = `${calcButtonOffset()}rem`;
100
117
  }
101
- }, []);
118
+ }, [isTreeview]);
102
119
 
103
120
  /**
104
121
  * Returns the parent SideNavMenu, if node is actually inside one.
@@ -114,56 +131,71 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
114
131
  if (match.match(event, keys.Escape)) {
115
132
  setIsExpanded(false);
116
133
  }
117
- const node = event.target;
118
- const isMenu = node.hasAttribute('aria-expanded');
119
- const isExpanded = node.getAttribute('aria-expanded');
120
- const parent = parentSideNavMenu(node);
121
- if (match.match(event, keys.ArrowLeft)) {
122
- event.stopPropagation();
123
- if (isMenu) {
124
- // collapse menu
125
- if (isExpanded == 'true') {
126
- setIsExpanded(false);
134
+ if (isTreeview) {
135
+ const node = event.target;
136
+ const isMenu = node.hasAttribute('aria-expanded');
137
+ const isExpanded = node.getAttribute('aria-expanded');
138
+ const parent = parentSideNavMenu(node);
139
+ if (match.match(event, keys.ArrowLeft)) {
140
+ event.stopPropagation();
141
+ if (isMenu) {
142
+ // collapse menu
143
+ if (isExpanded == 'true') {
144
+ setIsExpanded(false);
127
145
 
128
- // go to previous level's side nav menu button
129
- } else {
130
- // since we're in a menu, it finds its own <li>, we go up one more
131
- const previousMenu = parentSideNavMenu(parent);
132
- const button = previousMenu.querySelector('button');
146
+ // go to previous level's side nav menu button
147
+ } else {
148
+ // since we're in a menu, it finds its own <li>, we go up one more
149
+ const previousMenu = parentSideNavMenu(parent);
150
+ const button = previousMenu.querySelector('button');
151
+ button.tabIndex = 0;
152
+ button?.focus();
153
+ }
154
+
155
+ // go to side nav menu button
156
+ } else if (parent) {
157
+ const button = parent.querySelector('button');
133
158
  button.tabIndex = 0;
134
159
  button?.focus();
135
160
  }
136
-
137
- // go to side nav menu button
138
- } else if (parent) {
139
- const button = parent.querySelector('button');
140
- button.tabIndex = 0;
141
- button?.focus();
142
161
  }
143
- }
144
- if (match.match(event, keys.ArrowRight)) {
145
- event.stopPropagation();
162
+ if (match.match(event, keys.ArrowRight)) {
163
+ event.stopPropagation();
146
164
 
147
- // expand menu
148
- if (isMenu) {
149
- setIsExpanded(true);
165
+ // expand menu
166
+ if (isMenu) {
167
+ setIsExpanded(true);
150
168
 
151
- // if already expanded, focus on first element
152
- if (isExpanded == 'true') {
153
- let nextNode = node.nextElementSibling?.querySelector('a, button');
154
- if (nextNode) {
155
- nextNode.tabIndex = 0;
156
- nextNode.focus();
169
+ // if already expanded, focus on first element
170
+ if (isExpanded == 'true') {
171
+ let nextNode = node.nextElementSibling?.querySelector('a, button');
172
+ if (nextNode) {
173
+ nextNode.tabIndex = 0;
174
+ nextNode.focus();
175
+ }
157
176
  }
158
177
  }
159
178
  }
160
179
  }
161
180
  }
181
+
182
+ // save expanded state before SideNav collapse
183
+ const [lastExpandedState, setLastExpandedState] = React.useState(isExpanded);
184
+
185
+ // reset when SideNav is panel
186
+ React.useEffect(() => {
187
+ if (navType == SideNav.SIDE_NAV_TYPE.PANEL && !sideNavExpanded) {
188
+ setLastExpandedState(isExpanded);
189
+ setIsExpanded(false);
190
+ } else {
191
+ setIsExpanded(lastExpandedState);
192
+ }
193
+ }, [sideNavExpanded]);
162
194
  return (
163
195
  /*#__PURE__*/
164
196
  // eslint-disable-next-line jsx-a11y/no-noninteractive-element-interactions
165
197
  React.createElement("li", {
166
- role: "treeitem",
198
+ role: isTreeview ? 'treeitem' : undefined,
167
199
  "aria-expanded": isExpanded,
168
200
  className: className,
169
201
  ref: listRef,
@@ -172,11 +204,17 @@ const SideNavMenu = /*#__PURE__*/React.forwardRef(function SideNavMenu(_ref, ref
172
204
  "aria-expanded": isExpanded,
173
205
  className: buttonClassName,
174
206
  onClick: () => {
175
- setIsExpanded(!isExpanded);
207
+ // only when sidenav is panel view
208
+ if (navType == SideNav.SIDE_NAV_TYPE.PANEL && !isExpanded && firstLink.current && !sideNavExpanded) {
209
+ window.location.href = firstLink.current;
210
+ } else {
211
+ setIsExpanded(!isExpanded);
212
+ setLastExpandedState(!isExpanded);
213
+ }
176
214
  },
177
215
  ref: menuRef,
178
216
  type: "button",
179
- tabIndex: -1
217
+ tabIndex: isTreeview ? -1 : 0
180
218
  }, IconElement && /*#__PURE__*/React.createElement(react.SideNavIcon, null, /*#__PURE__*/React.createElement(IconElement, null)), /*#__PURE__*/React.createElement("span", {
181
219
  className: `${prefix}--side-nav__submenu-title`
182
220
  }, title), /*#__PURE__*/React.createElement(react.SideNavIcon, {
@@ -15,6 +15,7 @@ var react = require('@carbon/react');
15
15
  var Link = require('./Link.js');
16
16
  var usePrefix = require('../internal/usePrefix.js');
17
17
  var useMergedRefs = require('../internal/useMergedRefs.js');
18
+ var SideNav = require('./SideNav.js');
18
19
 
19
20
  const SideNavMenuItem = /*#__PURE__*/React.forwardRef(function SideNavMenuItem(props, ref) {
20
21
  const prefix = usePrefix.usePrefix();
@@ -26,6 +27,9 @@ const SideNavMenuItem = /*#__PURE__*/React.forwardRef(function SideNavMenuItem(p
26
27
  isActive,
27
28
  ...rest
28
29
  } = props;
30
+ const {
31
+ isTreeview
32
+ } = React.useContext(SideNav.SideNavContext);
29
33
  const className = index.default(`${prefix}--side-nav__menu-item`, customClassName);
30
34
  const depth = propDepth;
31
35
  const linkClassName = index.default({
@@ -41,14 +45,14 @@ const SideNavMenuItem = /*#__PURE__*/React.forwardRef(function SideNavMenuItem(p
41
45
  if (linkRef.current) {
42
46
  linkRef.current.style.paddingLeft = `${calcLinkOffset()}rem`;
43
47
  }
44
- }, []);
48
+ }, [isTreeview]);
45
49
  return /*#__PURE__*/React.createElement("li", {
46
- role: "treeitem",
47
- "aria-selected": isActive ? 'true' : 'false',
48
50
  className: className
49
51
  }, /*#__PURE__*/React.createElement(Component, _rollupPluginBabelHelpers.extends({}, rest, {
52
+ "aria-selected": isActive ? 'true' : 'false',
53
+ role: isTreeview ? 'treeitem' : undefined,
50
54
  className: linkClassName,
51
- tabIndex: -1,
55
+ tabIndex: isTreeview ? -1 : 0,
52
56
  ref: itemRef
53
57
  }), /*#__PURE__*/React.createElement(react.SideNavLinkText, null, children)));
54
58
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@carbon-labs/react-ui-shell",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "publishConfig": {
5
5
  "access": "public",
6
6
  "provenance": true
@@ -33,5 +33,5 @@
33
33
  "dependencies": {
34
34
  "@ibm/telemetry-js": "^1.9.1"
35
35
  },
36
- "gitHead": "69556e3e509139b1efc47f7c4561a8fceaae8ac7"
36
+ "gitHead": "b9ed739e909accebbb96349c611213832b779c84"
37
37
  }
@@ -48,12 +48,20 @@ div:has(.#{$prefix}--header)
48
48
  font-weight: 600;
49
49
  }
50
50
 
51
+ .#{$prefix}--side-nav__icon > svg,
52
+ .#{$prefix}--side-nav__submenu-chevron > svg {
53
+ fill: $icon-primary;
54
+ }
55
+ }
56
+
57
+ .#{$prefix}--side-nav__link:hover,
58
+ .#{$prefix}--side-nav__submenu:hover {
59
+ .#{$prefix}--side-nav__icon > svg,
51
60
  .#{$prefix}--side-nav__submenu-chevron > svg {
52
61
  fill: $icon-primary;
53
62
  }
54
63
  }
55
64
 
56
- //----------------------------------------------------------------------------
57
65
  // Side-nav Panel
58
66
  //----------------------------------------------------------------------------
59
67
  .#{$prefix}--side-nav--panel {
@@ -63,6 +71,12 @@ div:has(.#{$prefix}--header)
63
71
  margin-inline-end: $spacing-05;
64
72
  }
65
73
 
74
+ .#{$prefix}--side-nav__item.#{$prefix}--side-nav__link:hover {
75
+ .#{$prefix}--side-nav__icon > svg {
76
+ fill: $icon-primary;
77
+ }
78
+ }
79
+
66
80
  .#{$prefix}--side-nav__item.#{$prefix}--side-nav__item--icon
67
81
  a.#{$prefix}--side-nav__link {
68
82
  padding-inline-start: $spacing-10;