Skip to content

Commit 15429e1

Browse files
authored
fix(components): make sure that drawer content re-renders on change; close drawer when section is removed while drawer is open (#7194)
* chore(components): ensure that section anchor gets re-rendered when section changes * fix(components): closer drawer when active section is removed from the toolbar data list * chore(components): clarify comments
1 parent 8c3b0f6 commit 15429e1

File tree

3 files changed

+125
-3
lines changed

3 files changed

+125
-3
lines changed

packages/compass-components/src/components/drawer-portal.spec.tsx

Lines changed: 116 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import React, { useState } from 'react';
2-
import { render, screen, waitFor } from '@mongodb-js/testing-library-compass';
2+
import {
3+
render,
4+
screen,
5+
userEvent,
6+
waitFor,
7+
} from '@mongodb-js/testing-library-compass';
38
import {
49
DrawerContentProvider,
510
DrawerSection,
@@ -47,4 +52,114 @@ describe('DrawerSection', function () {
4752
.be.visible;
4853
});
4954
});
55+
56+
// Doesn't really matter, but leafygreen uses these as keys when rendering and
57+
// this produces a ton of warnings in the logs if they are not unique
58+
const icons = ['ArrowDown', 'CaretDown', 'ChevronDown'] as const;
59+
60+
it('switches drawer content when selecting a different section in the toolbar', async function () {
61+
render(
62+
<DrawerContentProvider>
63+
<DrawerAnchor>
64+
{[1, 2, 3].map((n, idx) => {
65+
return (
66+
<DrawerSection
67+
key={`section-${n}`}
68+
id={`section-${n}`}
69+
label={`Section ${n}`}
70+
title={`Section ${n}`}
71+
glyph={icons[idx]}
72+
>
73+
This is section {n}
74+
</DrawerSection>
75+
);
76+
})}
77+
</DrawerAnchor>
78+
</DrawerContentProvider>
79+
);
80+
81+
userEvent.click(screen.getByRole('button', { name: 'Section 1' }));
82+
await waitFor(() => {
83+
expect(screen.getByText('This is section 1')).to.be.visible;
84+
});
85+
86+
userEvent.click(screen.getByRole('button', { name: 'Section 2' }));
87+
await waitFor(() => {
88+
expect(screen.getByText('This is section 2')).to.be.visible;
89+
});
90+
91+
userEvent.click(screen.getByRole('button', { name: 'Section 3' }));
92+
await waitFor(() => {
93+
expect(screen.getByText('This is section 3')).to.be.visible;
94+
});
95+
96+
userEvent.click(screen.getByRole('button', { name: 'Section 1' }));
97+
await waitFor(() => {
98+
expect(screen.getByText('This is section 1')).to.be.visible;
99+
});
100+
101+
userEvent.click(screen.getByRole('button', { name: 'Close drawer' }));
102+
await waitFor(() => {
103+
expect(screen.queryByText('This is section 1')).not.to.exist;
104+
expect(screen.queryByText('This is section 2')).not.to.exist;
105+
expect(screen.queryByText('This is section 3')).not.to.exist;
106+
});
107+
});
108+
109+
it('closes drawer when opened section is removed from toolbar data', async function () {
110+
// Render two sections, auto-open first one
111+
const { rerender } = render(
112+
<DrawerContentProvider>
113+
<DrawerAnchor>
114+
<DrawerSection
115+
id="test-section-1"
116+
label="Test section 1"
117+
title="Test section 1"
118+
glyph="Trash"
119+
autoOpen
120+
>
121+
This is a test section
122+
</DrawerSection>
123+
<DrawerSection
124+
id="test-section-2"
125+
label="Test section 2"
126+
title="Test section 2"
127+
glyph="Bell"
128+
>
129+
This is another test section
130+
</DrawerSection>
131+
</DrawerAnchor>
132+
</DrawerContentProvider>
133+
);
134+
135+
await waitFor(() => {
136+
expect(screen.getByText('This is a test section')).to.be.visible;
137+
});
138+
139+
// Now render without opened section
140+
rerender(
141+
<DrawerContentProvider>
142+
<DrawerAnchor>
143+
<DrawerSection
144+
id="test-section-2"
145+
label="Test section 2"
146+
title="Test section 2"
147+
glyph="Bell"
148+
>
149+
This is another test section
150+
</DrawerSection>
151+
</DrawerAnchor>
152+
</DrawerContentProvider>
153+
);
154+
155+
await waitFor(() => {
156+
expect(screen.queryByText('This is a test section')).not.to.exist;
157+
});
158+
159+
expect(
160+
// Specifically a selector for the drawer content section, not the whole
161+
// drawer with toolbar
162+
screen.getByTestId('lg-drawer')
163+
).to.have.attribute('aria-hidden', 'true');
164+
});
50165
});

packages/compass-components/src/components/drawer-portal.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ export const DrawerAnchor: React.FunctionComponent<{
221221
...data,
222222
content: (
223223
<div
224+
key={data.id}
224225
data-drawer-section={data.id}
225226
className={drawerSectionPortalStyles}
226227
></div>

packages/compass-components/src/components/drawer/drawer-toolbar-layout/drawer-toolbar-layout-container.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,12 @@ export const DrawerToolbarLayoutContainer = forwardRef<
3737
}: DrawerToolbarLayoutContainerProps,
3838
forwardRef
3939
) => {
40-
const { openDrawer, closeDrawer, getActiveDrawerContent, isDrawerOpen } =
41-
useDrawerToolbarContext();
40+
const {
41+
openDrawer,
42+
closeDrawer,
43+
getActiveDrawerContent,
44+
isDrawerOpen: _isDrawerOpen,
45+
} = useDrawerToolbarContext();
4246
const { id } = getActiveDrawerContent() || {};
4347
const lgIds = getLgIds(dataLgId);
4448
const hasData = toolbarData && toolbarData.length > 0;
@@ -61,6 +65,8 @@ export const DrawerToolbarLayoutContainer = forwardRef<
6165
openDrawer(id);
6266
};
6367

68+
const isDrawerOpen = Boolean(title && content && _isDrawerOpen);
69+
6470
return (
6571
<LayoutComponent
6672
{...rest}

0 commit comments

Comments
 (0)