orcs-design-system 3.3.48 → 3.3.54
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/README.md +5 -52
- package/es/components/SideNavV2/__tests__/interaction-scenarios.test.js +82 -0
- package/es/components/SideNavV2/__tests__/sections.test.js +1 -1
- package/es/components/SideNavV2/components/ExpandedPanel.js +27 -3
- package/es/components/SideNavV2/hooks/useSideNavState.js +65 -14
- package/es/components/SideNavV2/sections/SideNavTeamsSection.js +6 -1
- package/es/components/Tag/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -36,15 +36,7 @@ A new browser window will open with a random localhost port. ORCS runs [Storyboo
|
|
|
36
36
|
|
|
37
37
|
All library components and files are located in `/lib`. Static files are located in `/assets`.
|
|
38
38
|
|
|
39
|
-
### Viewing changes in
|
|
40
|
-
|
|
41
|
-
As an alternative to `npm link` you can run `npm run dist` and then copy the `es` folder directly into TD or PM:
|
|
42
|
-
|
|
43
|
-
`cp -R es/ ../../../team-directory/node_modules/orcs-design-system/`
|
|
44
|
-
|
|
45
|
-
**_This has now been been made easier with using Nodemon and a custom script. Read on for how to set this up._**
|
|
46
|
-
|
|
47
|
-
### Working with orcs locally (hot reloading).
|
|
39
|
+
### Viewing local orcs changes in other projects (with hot reloading)
|
|
48
40
|
|
|
49
41
|
1. `cp .env.example .env`
|
|
50
42
|
2. OPTIONAL: Update `WORKING_DIR` in `.env` if orcs resides in a different working directory to your project. Else-wise Orcs will assume the project is one level up from itself.
|
|
@@ -63,39 +55,6 @@ snapshot: {
|
|
|
63
55
|
|
|
64
56
|
Now you can make any changes in orcs and it will build and then copy the es from the build into your project's node_modules. Run `npm install` in your project dir if you want to revert to the npm installation.
|
|
65
57
|
|
|
66
|
-
### Symlinking with `npm link`
|
|
67
|
-
|
|
68
|
-
##### We haven't had much success with this recently
|
|
69
|
-
|
|
70
|
-
If you need to do `npm link` in your local environment you might encounter the following issues:
|
|
71
|
-
|
|
72
|
-
- https://reactjs.org/warnings/invalid-hook-call-warning.html#duplicate-react
|
|
73
|
-
- https://github.com/styled-components/styled-components/issues/2379
|
|
74
|
-
|
|
75
|
-
Both react and styled-components cause duplicate instance issue after npm link, to fix that we need to ensure both app project and lib project are sharing the same instance of them.
|
|
76
|
-
|
|
77
|
-
In `orcs-design-system` folder:
|
|
78
|
-
|
|
79
|
-
```
|
|
80
|
-
npm link {PATH_APP_REPO}/node_modules/react
|
|
81
|
-
npm link {PATH_APP_REPO}/node_modules/styled-components
|
|
82
|
-
npm link
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
In `{PATH_APP_REPO}`:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
npm i orcs-design-system
|
|
89
|
-
npm link orcs-design-system
|
|
90
|
-
npm start
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
### Testing
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
npm run test
|
|
97
|
-
```
|
|
98
|
-
|
|
99
58
|
### Publishing changes
|
|
100
59
|
|
|
101
60
|
In order to publish a new version, you will have to patch and push your changes.
|
|
@@ -105,11 +64,11 @@ After your changes have been merged to master, from your master branch:
|
|
|
105
64
|
npm version patch
|
|
106
65
|
```
|
|
107
66
|
|
|
108
|
-
|
|
67
|
+
This will bump version patch number and make a commit to current branch.
|
|
109
68
|
|
|
110
69
|
### Deploying to GitHub Pages
|
|
111
70
|
|
|
112
|
-
ORCS automatically deploys to GitHub Pages when a new version is published. To manually deploy:
|
|
71
|
+
ORCS automatically deploys to GitHub Pages when a new version is published and merged to master. To manually deploy:
|
|
113
72
|
|
|
114
73
|
```
|
|
115
74
|
npm run deploy-storybook
|
|
@@ -138,17 +97,11 @@ import { Box } from "orcs-design-system"
|
|
|
138
97
|
|
|
139
98
|
The [ORCS Storybook](https://orchestrated-io.github.io/orcs-design-system) contains documentation for each component, including code examples and props tables.
|
|
140
99
|
|
|
141
|
-
For components with subcomponents, each subcomponent must be imported. For example, to use `Tabs`:
|
|
142
|
-
|
|
143
|
-
```
|
|
144
|
-
import { TabsContainer, Tab } from "orcs-design-system"
|
|
145
|
-
```
|
|
146
|
-
|
|
147
100
|
### Using Styled System props
|
|
148
101
|
|
|
149
|
-
The design system components are built with [Styled System](https://styled-system
|
|
102
|
+
The design system components are built with [Styled System](https://github.com/styled-system/styled-system) props. Generally, components can access the `space` and `layout` prop categories, with additional prop categories on a per-component basis. Check the _Properties_ section in a component's documentation to see what props it can use. Custom props will be listed in the props table.
|
|
150
103
|
|
|
151
|
-
As a guide to using these props, see the [Styled System reference table](https://styled-system
|
|
104
|
+
As a guide to using these props, see the [Styled System reference table](https://github.com/styled-system/styled-system/blob/master/docs/table.md).
|
|
152
105
|
|
|
153
106
|
The design system's theme scales are contained in [systemtheme](https://github.com/orchestrated-io/orcs-design-system/blob/master/packages/orcs-design-system/lib/systemtheme.js).
|
|
154
107
|
|
|
@@ -341,4 +341,86 @@ describe("SideNavV2 Interaction Scenarios", () => {
|
|
|
341
341
|
expect(getToggleButton()).toBeInTheDocument();
|
|
342
342
|
});
|
|
343
343
|
});
|
|
344
|
+
describe("Scenario 8: ExpandedPanel hover behavior", () => {
|
|
345
|
+
it("should show/hide ExpandedPanel based on hover state", async () => {
|
|
346
|
+
renderSideNav();
|
|
347
|
+
|
|
348
|
+
// Open expanded panel
|
|
349
|
+
const settingsButton = screen.getByTestId("nav-item-Settings");
|
|
350
|
+
fireEvent.click(settingsButton);
|
|
351
|
+
await waitFor(() => {
|
|
352
|
+
expect(screen.getByTestId("expanded-panel")).toBeInTheDocument();
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
// Hover out of wrapper should hide the panel
|
|
356
|
+
const wrapper = screen.getByTestId("side-nav-items").closest('[data-testid="side-nav-wrapper"]') || document.body;
|
|
357
|
+
fireEvent.mouseLeave(wrapper);
|
|
358
|
+
await waitFor(() => {
|
|
359
|
+
expect(screen.queryByTestId("expanded-panel")).not.toBeInTheDocument();
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
// Hover back in should show the previously opened panel
|
|
363
|
+
fireEvent.mouseEnter(wrapper);
|
|
364
|
+
await waitFor(() => {
|
|
365
|
+
expect(screen.getByTestId("expanded-panel")).toBeInTheDocument();
|
|
366
|
+
});
|
|
367
|
+
});
|
|
368
|
+
it("should not re-show panel if it was manually closed", async () => {
|
|
369
|
+
renderSideNav();
|
|
370
|
+
|
|
371
|
+
// Open expanded panel
|
|
372
|
+
const settingsButton = screen.getByTestId("nav-item-Settings");
|
|
373
|
+
fireEvent.click(settingsButton);
|
|
374
|
+
await waitFor(() => {
|
|
375
|
+
expect(screen.getByTestId("expanded-panel")).toBeInTheDocument();
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
// Manually close the panel
|
|
379
|
+
const hidePanelButton = screen.getByTestId("hide-panel-button");
|
|
380
|
+
fireEvent.click(hidePanelButton);
|
|
381
|
+
await waitFor(() => {
|
|
382
|
+
expect(screen.queryByTestId("expanded-panel")).not.toBeInTheDocument();
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// Hover out and back in should not re-show the panel
|
|
386
|
+
const wrapper = screen.getByTestId("side-nav-items").closest('[data-testid="side-nav-wrapper"]') || document.body;
|
|
387
|
+
fireEvent.mouseLeave(wrapper);
|
|
388
|
+
fireEvent.mouseEnter(wrapper);
|
|
389
|
+
|
|
390
|
+
// Panel should still be hidden
|
|
391
|
+
expect(screen.queryByTestId("expanded-panel")).not.toBeInTheDocument();
|
|
392
|
+
});
|
|
393
|
+
it("should hide panel on hover out even when navigation is locked open", async () => {
|
|
394
|
+
renderSideNav();
|
|
395
|
+
|
|
396
|
+
// Open expanded panel
|
|
397
|
+
const settingsButton = screen.getByTestId("nav-item-Settings");
|
|
398
|
+
fireEvent.click(settingsButton);
|
|
399
|
+
await waitFor(() => {
|
|
400
|
+
expect(screen.getByTestId("expanded-panel")).toBeInTheDocument();
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
// Click "Keep Open" to lock navigation
|
|
404
|
+
const toggleButton = getToggleButton();
|
|
405
|
+
fireEvent.click(toggleButton);
|
|
406
|
+
|
|
407
|
+
// Navigation should be locked open
|
|
408
|
+
await waitFor(() => {
|
|
409
|
+
expect(toggleButton).toHaveAttribute("data-testid", "toggle-handle");
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
// Hover out of wrapper should still hide the panel
|
|
413
|
+
const wrapper = screen.getByTestId("side-nav-items").closest('[data-testid="side-nav-wrapper"]') || document.body;
|
|
414
|
+
fireEvent.mouseLeave(wrapper);
|
|
415
|
+
await waitFor(() => {
|
|
416
|
+
expect(screen.queryByTestId("expanded-panel")).not.toBeInTheDocument();
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
// Hover back in should show the panel again
|
|
420
|
+
fireEvent.mouseEnter(wrapper);
|
|
421
|
+
await waitFor(() => {
|
|
422
|
+
expect(screen.getByTestId("expanded-panel")).toBeInTheDocument();
|
|
423
|
+
});
|
|
424
|
+
});
|
|
425
|
+
});
|
|
344
426
|
});
|
|
@@ -195,7 +195,7 @@ describe("SideNavTeamsSection", () => {
|
|
|
195
195
|
teams: mockTeams,
|
|
196
196
|
isExpanded: false
|
|
197
197
|
}));
|
|
198
|
-
expect(screen.queryByText("
|
|
198
|
+
expect(screen.queryByText("My Teams")).not.toBeInTheDocument();
|
|
199
199
|
});
|
|
200
200
|
it("should render avatars for each team", () => {
|
|
201
201
|
renderWithRouter(/*#__PURE__*/_jsx(SideNavTeamsSection, {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import React from "react";
|
|
1
|
+
import React, { useEffect, useRef } from "react";
|
|
2
2
|
import PropTypes from "prop-types";
|
|
3
3
|
import { SideNavExpanded, ResizeHandle, ToggleIcon } from "../styles/SideNavV2.styles";
|
|
4
4
|
import PanelControlComponent from "./PanelControl";
|
|
@@ -10,6 +10,7 @@ import Icon from "../../Icon";
|
|
|
10
10
|
*
|
|
11
11
|
* Renders an expandable panel that can be resized by the user. Supports both
|
|
12
12
|
* desktop (horizontal resize) and mobile (vertical resize) orientations.
|
|
13
|
+
* Hover behavior is handled at the parent component level.
|
|
13
14
|
*
|
|
14
15
|
* @param {Object} props - Component props
|
|
15
16
|
* @param {Object} props.item - Navigation item data
|
|
@@ -34,6 +35,26 @@ const ExpandedPanel = _ref => {
|
|
|
34
35
|
onResizeStart,
|
|
35
36
|
onItemClick
|
|
36
37
|
} = _ref;
|
|
38
|
+
const panelRef = useRef(null);
|
|
39
|
+
const isHoveringInPanelRef = useRef(false);
|
|
40
|
+
|
|
41
|
+
// Handle hover behavior for the panel
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!panelRef.current) return;
|
|
44
|
+
const panel = panelRef.current;
|
|
45
|
+
const handleMouseEnter = () => {
|
|
46
|
+
isHoveringInPanelRef.current = true;
|
|
47
|
+
};
|
|
48
|
+
const handleMouseLeave = () => {
|
|
49
|
+
isHoveringInPanelRef.current = false;
|
|
50
|
+
};
|
|
51
|
+
panel.addEventListener("mouseenter", handleMouseEnter);
|
|
52
|
+
panel.addEventListener("mouseleave", handleMouseLeave);
|
|
53
|
+
return () => {
|
|
54
|
+
panel.removeEventListener("mouseenter", handleMouseEnter);
|
|
55
|
+
panel.removeEventListener("mouseleave", handleMouseLeave);
|
|
56
|
+
};
|
|
57
|
+
}, []);
|
|
37
58
|
if (item.actionType !== "component" || item.hide) {
|
|
38
59
|
return null;
|
|
39
60
|
}
|
|
@@ -41,7 +62,10 @@ const ExpandedPanel = _ref => {
|
|
|
41
62
|
position: "relative",
|
|
42
63
|
height: "100%",
|
|
43
64
|
children: [/*#__PURE__*/_jsxs(SideNavExpanded, {
|
|
44
|
-
ref:
|
|
65
|
+
ref: el => {
|
|
66
|
+
expandedRef.current = el;
|
|
67
|
+
panelRef.current = el;
|
|
68
|
+
},
|
|
45
69
|
tabIndex: "0",
|
|
46
70
|
active: expandedItem,
|
|
47
71
|
large: item.large,
|
|
@@ -85,7 +109,7 @@ ExpandedPanel.propTypes = {
|
|
|
85
109
|
onItemClick: PropTypes.func.isRequired
|
|
86
110
|
};
|
|
87
111
|
ExpandedPanel.__docgenInfo = {
|
|
88
|
-
"description": "ExpandedPanel - A resizable panel component for expanded navigation items\n\nRenders an expandable panel that can be resized by the user. Supports both\ndesktop (horizontal resize) and mobile (vertical resize) orientations.\n\n@param {Object} props - Component props\n@param {Object} props.item - Navigation item data\n@param {number} [props.expandedItem] - Currently expanded item index\n@param {boolean} props.isExpanded - Whether the navigation is expanded\n@param {number} [props.expandedWidth] - Width of the expanded panel (desktop)\n@param {boolean} props.isSmallScreen - Whether currently on a small screen\n@param {React.RefObject} props.expandedRef - Ref for the expanded panel\n@param {Function} props.onResizeStart - Resize start handler\n@param {Function} props.onItemClick - Item click handler\n@returns {JSX.Element} Rendered expanded panel or null if not applicable",
|
|
112
|
+
"description": "ExpandedPanel - A resizable panel component for expanded navigation items\n\nRenders an expandable panel that can be resized by the user. Supports both\ndesktop (horizontal resize) and mobile (vertical resize) orientations.\nHover behavior is handled at the parent component level.\n\n@param {Object} props - Component props\n@param {Object} props.item - Navigation item data\n@param {number} [props.expandedItem] - Currently expanded item index\n@param {boolean} props.isExpanded - Whether the navigation is expanded\n@param {number} [props.expandedWidth] - Width of the expanded panel (desktop)\n@param {boolean} props.isSmallScreen - Whether currently on a small screen\n@param {React.RefObject} props.expandedRef - Ref for the expanded panel\n@param {Function} props.onResizeStart - Resize start handler\n@param {Function} props.onItemClick - Item click handler\n@returns {JSX.Element} Rendered expanded panel or null if not applicable",
|
|
89
113
|
"methods": [],
|
|
90
114
|
"displayName": "ExpandedPanel",
|
|
91
115
|
"props": {
|
|
@@ -35,6 +35,11 @@ const useSideNavState = items => {
|
|
|
35
35
|
const wasExpandedByHoverRef = useRef(false);
|
|
36
36
|
const wasCollapsedWithExpandedPanelRef = useRef(false);
|
|
37
37
|
const [isToggling, setIsToggling] = useState(false);
|
|
38
|
+
|
|
39
|
+
// New refs for ExpandedPanel hover behavior
|
|
40
|
+
const previouslyOpenedPanelRef = useRef(null);
|
|
41
|
+
const wasPanelManuallyClosedRef = useRef(false);
|
|
42
|
+
const isHoveringInWrapperRef = useRef(false);
|
|
38
43
|
const firstExpandedItemByDefault = findFirstExpandedByDefault(items);
|
|
39
44
|
|
|
40
45
|
// Initialize expanded item by default
|
|
@@ -77,43 +82,61 @@ const useSideNavState = items => {
|
|
|
77
82
|
// Extract common mouse event logic to reduce duplication
|
|
78
83
|
const createMouseEventHandlers = useCallback(() => {
|
|
79
84
|
const baseHandler = shouldExpand => {
|
|
80
|
-
if (
|
|
85
|
+
if (isToggling) {
|
|
81
86
|
return;
|
|
82
87
|
}
|
|
83
88
|
isHoveringRef.current = true;
|
|
89
|
+
isHoveringInWrapperRef.current = true;
|
|
84
90
|
|
|
85
|
-
// Only auto-expand if the user has manually collapsed it before
|
|
91
|
+
// Only auto-expand navigation if the user has manually collapsed it before
|
|
86
92
|
// AND it wasn't collapsed while having an expanded panel
|
|
87
|
-
|
|
93
|
+
// AND the navigation is not locked
|
|
94
|
+
if (shouldExpand && !isLocked && hasBeenManuallyCollapsedRef.current && !wasCollapsedWithExpandedPanelRef.current) {
|
|
88
95
|
setIsExpanded(true);
|
|
89
96
|
wasExpandedByHoverRef.current = true;
|
|
90
97
|
}
|
|
98
|
+
|
|
99
|
+
// Auto-expand previously opened panel if hovering back in
|
|
100
|
+
// This should work regardless of navigation lock state
|
|
101
|
+
if (shouldExpand && previouslyOpenedPanelRef.current !== null && !wasPanelManuallyClosedRef.current && expandedItem === null) {
|
|
102
|
+
setExpandedItem(previouslyOpenedPanelRef.current);
|
|
103
|
+
// Mark that this panel was opened by hover (not manually)
|
|
104
|
+
wasPanelManuallyClosedRef.current = false;
|
|
105
|
+
}
|
|
91
106
|
};
|
|
92
107
|
return {
|
|
93
108
|
handleEnter: () => baseHandler(true),
|
|
94
109
|
handleLeave: () => {
|
|
95
|
-
if (isLocked) return;
|
|
96
110
|
isHoveringRef.current = false;
|
|
111
|
+
isHoveringInWrapperRef.current = false;
|
|
97
112
|
|
|
98
|
-
// Only auto-collapse if the user has manually collapsed it before
|
|
113
|
+
// Only auto-collapse navigation if the user has manually collapsed it before
|
|
99
114
|
// AND it was expanded by hover (not locked)
|
|
100
115
|
// AND it wasn't collapsed while having an expanded panel
|
|
101
|
-
if (hasBeenManuallyCollapsedRef.current && wasExpandedByHoverRef.current && !wasCollapsedWithExpandedPanelRef.current) {
|
|
116
|
+
if (!isLocked && hasBeenManuallyCollapsedRef.current && wasExpandedByHoverRef.current && !wasCollapsedWithExpandedPanelRef.current) {
|
|
102
117
|
setIsExpanded(false);
|
|
103
118
|
wasExpandedByHoverRef.current = false;
|
|
104
119
|
}
|
|
105
120
|
|
|
121
|
+
// Auto-hide ExpandedPanel when hovering out (if it was opened by hover)
|
|
122
|
+
// This should work regardless of navigation lock state
|
|
123
|
+
if (expandedItem !== null && previouslyOpenedPanelRef.current === expandedItem && !wasPanelManuallyClosedRef.current) {
|
|
124
|
+
// Store the panel that was open before hiding it
|
|
125
|
+
previouslyOpenedPanelRef.current = expandedItem;
|
|
126
|
+
setExpandedItem(null);
|
|
127
|
+
}
|
|
128
|
+
|
|
106
129
|
// Reset the wasCollapsedWithExpandedPanelRef flag when hovering out of the entire wrapper
|
|
107
130
|
// This allows hover behavior to work again after hovering out and back in
|
|
108
131
|
wasCollapsedWithExpandedPanelRef.current = false;
|
|
109
132
|
// Don't reset hasBeenManuallyCollapsedRef here - it should persist until user manually expands again
|
|
110
133
|
}
|
|
111
134
|
};
|
|
112
|
-
}, [isLocked, setIsExpanded, isToggling]);
|
|
135
|
+
}, [isLocked, setIsExpanded, isToggling, expandedItem, setExpandedItem]);
|
|
113
136
|
|
|
114
137
|
// Mouse event handlers for hover state
|
|
115
138
|
useEffect(() => {
|
|
116
|
-
if (!wrapperRef.current
|
|
139
|
+
if (!wrapperRef.current) return;
|
|
117
140
|
const wrapper = wrapperRef.current;
|
|
118
141
|
const sideNavItems = wrapper.querySelector('[data-testid="side-nav-items"]');
|
|
119
142
|
const toggleHandle = wrapper.querySelector(".toggle-popover");
|
|
@@ -126,12 +149,12 @@ const useSideNavState = items => {
|
|
|
126
149
|
const handleSideNavItemsMouseEnter = handleEnter;
|
|
127
150
|
const handleToggleMouseEnter = handleEnter;
|
|
128
151
|
const handleSideNavItemsMouseLeave = () => {
|
|
129
|
-
if (
|
|
152
|
+
if (isToggling) return;
|
|
130
153
|
// Don't collapse immediately, let the wrapper handle it
|
|
131
154
|
// This allows hovering over ExpandedPanel to keep it expanded
|
|
132
155
|
};
|
|
133
156
|
const handleToggleMouseLeave = () => {
|
|
134
|
-
if (
|
|
157
|
+
if (isToggling) return;
|
|
135
158
|
// Don't collapse immediately, let the wrapper handle it
|
|
136
159
|
// This allows hovering over the toggle handle to keep it expanded
|
|
137
160
|
};
|
|
@@ -159,7 +182,7 @@ const useSideNavState = items => {
|
|
|
159
182
|
toggleHandle.removeEventListener("mouseleave", handleToggleMouseLeave);
|
|
160
183
|
}
|
|
161
184
|
};
|
|
162
|
-
}, [
|
|
185
|
+
}, [createMouseEventHandlers, isToggling]);
|
|
163
186
|
const handleItemClick = useCallback(item => {
|
|
164
187
|
const {
|
|
165
188
|
index: itemIndex,
|
|
@@ -175,26 +198,51 @@ const useSideNavState = items => {
|
|
|
175
198
|
// If we're already on this panel, toggle it closed
|
|
176
199
|
if (expandedItem === relatedPanelIndex) {
|
|
177
200
|
setExpandedItem(null);
|
|
201
|
+
// Mark that this panel was manually closed
|
|
202
|
+
if (previouslyOpenedPanelRef.current === relatedPanelIndex) {
|
|
203
|
+
wasPanelManuallyClosedRef.current = true;
|
|
204
|
+
}
|
|
178
205
|
} else {
|
|
179
206
|
// Otherwise, open the related panel
|
|
180
207
|
setExpandedItem(relatedPanelIndex);
|
|
208
|
+
// Reset manual close flag when opening a panel
|
|
209
|
+
wasPanelManuallyClosedRef.current = false;
|
|
181
210
|
}
|
|
182
211
|
} else {
|
|
183
212
|
// No related panel, close any open panel
|
|
184
213
|
setExpandedItem(null);
|
|
214
|
+
// Mark that any open panel was manually closed
|
|
215
|
+
if (expandedItem !== null) {
|
|
216
|
+
wasPanelManuallyClosedRef.current = true;
|
|
217
|
+
}
|
|
185
218
|
}
|
|
186
219
|
} else {
|
|
187
220
|
// For button items, just close any open panel
|
|
221
|
+
if (expandedItem !== null) {
|
|
222
|
+
wasPanelManuallyClosedRef.current = true;
|
|
223
|
+
}
|
|
188
224
|
setExpandedItem(null);
|
|
189
225
|
}
|
|
190
226
|
onButtonClick && onButtonClick(item);
|
|
191
227
|
} else {
|
|
192
228
|
const wasExpanded = expandedItem !== null;
|
|
193
|
-
|
|
229
|
+
const wasClosingPanel = itemIndex === expandedItem;
|
|
230
|
+
if (wasClosingPanel) {
|
|
231
|
+
// Closing a panel - mark it as manually closed
|
|
232
|
+
wasPanelManuallyClosedRef.current = true;
|
|
233
|
+
// Store reference to the panel that was closed
|
|
234
|
+
previouslyOpenedPanelRef.current = itemIndex;
|
|
235
|
+
} else {
|
|
236
|
+
// Opening a panel - reset manual close flag and track that it was opened manually
|
|
237
|
+
wasPanelManuallyClosedRef.current = false;
|
|
238
|
+
// Store reference to the panel that was opened
|
|
239
|
+
previouslyOpenedPanelRef.current = itemIndex;
|
|
240
|
+
}
|
|
241
|
+
setExpandedItem(wasClosingPanel ? null : itemIndex);
|
|
194
242
|
onButtonClick && onButtonClick(item);
|
|
195
243
|
|
|
196
244
|
// If we just closed an expanded panel, reset the flags to enable hover behavior
|
|
197
|
-
if (wasExpanded &&
|
|
245
|
+
if (wasExpanded && wasClosingPanel) {
|
|
198
246
|
// Reset the wasCollapsedWithExpandedPanelRef flag to enable hover behavior again
|
|
199
247
|
wasCollapsedWithExpandedPanelRef.current = false;
|
|
200
248
|
// Don't reset hasBeenManuallyCollapsedRef - the user has still manually collapsed the nav
|
|
@@ -278,7 +326,10 @@ const useSideNavState = items => {
|
|
|
278
326
|
handleExpandToggle,
|
|
279
327
|
isLocked,
|
|
280
328
|
wasExpandedByHover: wasExpandedByHoverRef.current,
|
|
281
|
-
hasBeenManuallyCollapsed: hasBeenManuallyCollapsedRef.current
|
|
329
|
+
hasBeenManuallyCollapsed: hasBeenManuallyCollapsedRef.current,
|
|
330
|
+
previouslyOpenedPanel: previouslyOpenedPanelRef.current,
|
|
331
|
+
wasPanelManuallyClosed: wasPanelManuallyClosedRef.current,
|
|
332
|
+
isHoveringInWrapper: isHoveringInWrapperRef.current
|
|
282
333
|
};
|
|
283
334
|
};
|
|
284
335
|
export default useSideNavState;
|
|
@@ -54,7 +54,8 @@ SideNavTeamsSection.propTypes = {
|
|
|
54
54
|
teams: PropTypes.arrayOf(PropTypes.shape({
|
|
55
55
|
avatar: PropTypes.string,
|
|
56
56
|
name: PropTypes.string.isRequired,
|
|
57
|
-
link: PropTypes.string.isRequired
|
|
57
|
+
link: PropTypes.string.isRequired,
|
|
58
|
+
gradient: PropTypes.string
|
|
58
59
|
})),
|
|
59
60
|
isExpanded: PropTypes.bool
|
|
60
61
|
};
|
|
@@ -81,6 +82,10 @@ SideNavTeamsSection.__docgenInfo = {
|
|
|
81
82
|
"link": {
|
|
82
83
|
"name": "string",
|
|
83
84
|
"required": true
|
|
85
|
+
},
|
|
86
|
+
"gradient": {
|
|
87
|
+
"name": "string",
|
|
88
|
+
"required": false
|
|
84
89
|
}
|
|
85
90
|
}
|
|
86
91
|
}
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
const TagWrapper = styled.div.withConfig({
|
|
12
12
|
displayName: "Tag__TagWrapper",
|
|
13
13
|
componentId: "sc-1dh2aa8-0"
|
|
14
|
-
})(["", " ", " display:flex;align-items:stretch;height:
|
|
14
|
+
})(["", " ", " display:flex;align-items:stretch;height:auto;max-height:max-content;min-height:", ";justify-content:center;> button{margin:0;}"], space, layout, props => props.small ? themeGet("tagScale.tagHeightSmall") : themeGet("tagScale.tagHeightDefault"));
|
|
15
15
|
const TagValue = styled.button.attrs(props => ({
|
|
16
16
|
"aria-pressed": props.selected
|
|
17
17
|
})).withConfig({
|