Skip to content

Commit a464cb8

Browse files
authored
[LG-5571] feat(drawer): add toggle behavior for toolbar buttons (#3159)
* feat(drawer): add toggleDrawer function to manage drawer state and use for toolbar buttons * chore(drawer): changeset * docs(drawer): README update
1 parent 8902552 commit a464cb8

File tree

6 files changed

+73
-16
lines changed

6 files changed

+73
-16
lines changed

.changeset/clever-hairs-taste.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
'@leafygreen-ui/drawer': minor
3+
---
4+
5+
[LG-5571](https://jira.mongodb.org/browse/LG-5571): pressing active toolbar button instance will now close the drawer

packages/drawer/README.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -157,10 +157,11 @@ Individual toolbar items can be controlled using the `visible` prop. When all to
157157

158158
To control the `Drawer` state, use the `useDrawerToolbarContext` hook from within `<DrawerLayout>`. This hook provides the `openDrawer()` and `closeDrawer()` functions to open and close the drawer programmatically. The hook takes no arguments and returns the following functions:
159159

160-
| Name | Signature | Description |
161-
| ----------- | ---------------------- | -------------------------------------------------------------------------------------------------- |
162-
| openDrawer | `(id: string) => void` | Opens the `Drawer` associated with the `Toolbar` item that has the matching `id` in `toolbarData`. |
163-
| closeDrawer | `() => void` | Closes the Drawer. |
160+
| Name | Signature | Description |
161+
| ------------ | ---------------------- | ------------------------------------------------------------------------------------------------------------------------------ |
162+
| openDrawer | `(id: string) => void` | Opens the `Drawer` associated with the `Toolbar` item that has the matching `id` in `toolbarData`. |
163+
| closeDrawer | `() => void` | Closes the `Drawer`. |
164+
| toggleDrawer | `(id: string) => void` | If clicking the currently active `Toolbar` item, it closes the `Drawer`. Otherwise, it open the `Drawer` with the new content. |
164165

165166
### Rendering
166167

packages/drawer/src/DrawerToolbarLayout/DrawerToolbarContext/DrawerToolbarContext.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,22 @@ export const DrawerToolbarProvider = ({
7878
}, TRANSITION_DURATION);
7979
}, [setActiveDrawerId]);
8080

81+
/**
82+
* Handles toolbar button clicks with toggle behavior.
83+
* If the drawer is already open with the same content, it closes the drawer.
84+
* Otherwise, it opens the drawer with the new content.
85+
*/
86+
const toggleDrawer = useCallback(
87+
(id: DataId) => {
88+
if (isDrawerOpen && activeDrawerId === id) {
89+
closeDrawer();
90+
} else {
91+
openDrawer(id);
92+
}
93+
},
94+
[isDrawerOpen, activeDrawerId, closeDrawer, openDrawer],
95+
);
96+
8197
// Checks if the active drawer id is removed from the data or if the active drawer item is not visible. If so, close the drawer.
8298
useEffect(() => {
8399
if (shouldRenderToolbar && activeDrawerId) {
@@ -111,6 +127,7 @@ export const DrawerToolbarProvider = ({
111127
() => ({
112128
openDrawer,
113129
closeDrawer,
130+
toggleDrawer,
114131
getActiveDrawerContent,
115132
isDrawerOpen,
116133
shouldRenderToolbar,
@@ -120,6 +137,7 @@ export const DrawerToolbarProvider = ({
120137
[
121138
openDrawer,
122139
closeDrawer,
140+
toggleDrawer,
123141
getActiveDrawerContent,
124142
isDrawerOpen,
125143
shouldRenderToolbar,

packages/drawer/src/DrawerToolbarLayout/DrawerToolbarContext/DrawerToolbarContext.types.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,15 @@ export interface DrawerToolbarContextType {
1818
*/
1919
closeDrawer: () => void;
2020

21+
/**
22+
* This function is used to handle toolbar button clicks with toggle behavior.
23+
* If the drawer is already open with the same content, it closes the drawer.
24+
* Otherwise, it opens the drawer with the new content.
25+
* @param id - The id of the drawer to toggle
26+
* @returns void
27+
*/
28+
toggleDrawer: (id: DataId) => void;
29+
2130
/**
2231
* Indicates whether the drawer should be closed. Used to manage transition states.
2332
* For example, during close animations, content should remain until the transition completes.

packages/drawer/src/DrawerToolbarLayout/DrawerToolbarLayout/DrawerToolbarLayout.spec.tsx

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -199,11 +199,7 @@ describe('packages/DrawerToolbarLayout', () => {
199199
test('closes the drawer when the active item is hidden', () => {
200200
const { rerender } = render(<Component />);
201201

202-
const { getToolbarTestUtils, isOpen } = getTestUtils();
203-
204-
const { getToolbarIconButtonByLabel } = getToolbarTestUtils();
205-
const codeButton = getToolbarIconButtonByLabel('Code')?.getElement();
206-
userEvent.click(codeButton!);
202+
const { isOpen } = getTestUtils();
207203

208204
expect(isOpen()).toBe(true);
209205

@@ -235,11 +231,7 @@ describe('packages/DrawerToolbarLayout', () => {
235231
test('closes the drawer when the active item is removed from the toolbar data', () => {
236232
const { rerender } = render(<Component />);
237233

238-
const { getToolbarTestUtils, isOpen } = getTestUtils();
239-
240-
const { getToolbarIconButtonByLabel } = getToolbarTestUtils();
241-
const codeButton = getToolbarIconButtonByLabel('Code')?.getElement();
242-
userEvent.click(codeButton!);
234+
const { isOpen } = getTestUtils();
243235

244236
expect(isOpen()).toBe(true);
245237

@@ -293,4 +285,36 @@ describe('packages/DrawerToolbarLayout', () => {
293285
expect(codeButtonRef.current).toHaveAttribute('aria-label', 'Code');
294286
expect(code2ButtonRef.current).toHaveAttribute('aria-label', 'Code2');
295287
});
288+
289+
test('closes the drawer when clicking the same toolbar button while drawer is open', () => {
290+
render(<Component />);
291+
292+
const { getToolbarTestUtils, isOpen } = getTestUtils();
293+
294+
expect(isOpen()).toBe(true);
295+
296+
const { getToolbarIconButtonByLabel } = getToolbarTestUtils();
297+
const codeButton = getToolbarIconButtonByLabel('Code')?.getElement();
298+
299+
userEvent.click(codeButton!);
300+
301+
expect(isOpen()).toBe(false);
302+
});
303+
304+
test('opens the drawer when clicking a different toolbar button while drawer is open', () => {
305+
render(<Component />);
306+
307+
const { getToolbarTestUtils, isOpen, getDrawer } = getTestUtils();
308+
309+
expect(isOpen()).toBe(true);
310+
expect(getDrawer()).toHaveTextContent('Drawer Title');
311+
312+
const { getToolbarIconButtonByLabel } = getToolbarTestUtils();
313+
const code2Button = getToolbarIconButtonByLabel('Code2')?.getElement();
314+
315+
userEvent.click(code2Button!);
316+
317+
expect(isOpen()).toBe(true);
318+
expect(getDrawer()).toHaveTextContent('Drawer Title2');
319+
});
296320
});

packages/drawer/src/DrawerToolbarLayout/DrawerToolbarLayout/DrawerToolbarLayoutContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,8 +35,8 @@ export const DrawerToolbarLayoutContent = forwardRef<
3535
forwardRef,
3636
) => {
3737
const {
38-
openDrawer,
3938
closeDrawer,
39+
toggleDrawer,
4040
getActiveDrawerContent,
4141
isDrawerOpen,
4242
visibleToolbarItems,
@@ -74,7 +74,7 @@ export const DrawerToolbarLayoutContent = forwardRef<
7474
onClick?: (event: React.MouseEvent<HTMLButtonElement>) => void,
7575
) => {
7676
onClick?.(event);
77-
openDrawer(id);
77+
toggleDrawer(id);
7878
};
7979

8080
const renderDrawer = () => {

0 commit comments

Comments
 (0)