Skip to content

Commit 57a3f88

Browse files
authored
feat: resizeDrawer method for plugin api (#3680)
1 parent cf95eb0 commit 57a3f88

File tree

6 files changed

+152
-0
lines changed

6 files changed

+152
-0
lines changed

pages/app-layout/runtime-drawers.page.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,19 @@ export default function WithDrawers() {
112112
<Button onClick={() => awsuiPlugins.appLayout.closeDrawer('circle4-global')}>
113113
Close a drawer without a trigger
114114
</Button>
115+
116+
<Button
117+
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle-global', 400)}
118+
data-testid="button-circle-global-resize"
119+
>
120+
Resize circle-global drawer to 400px
121+
</Button>
122+
<Button
123+
onClick={() => awsuiPlugins.appLayout.resizeDrawer('circle3-global', 500)}
124+
data-testid="button-circle3-global-resize"
125+
>
126+
Resize circle3-global drawer to 500px
127+
</Button>
115128
</SpaceBetween>
116129
</SpaceBetween>
117130
}

src/app-layout/__integ__/runtime-drawers.test.ts

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,12 @@ describe('Visual refresh toolbar only', () => {
148148
hasHorizontalScroll() {
149149
return this.browser.execute(() => document.body.scrollWidth - document.body.clientWidth > 0);
150150
}
151+
152+
async getDrawerWidth(drawerId: string) {
153+
const { width } = await this.getBoundingBox(findDrawerById(wrapper, drawerId)!.toSelector());
154+
155+
return width;
156+
}
151157
}
152158
function setupTest(testFn: (page: PageObject) => Promise<void>) {
153159
return useBrowser(async browser => {
@@ -362,4 +368,32 @@ describe('Visual refresh toolbar only', () => {
362368
await expect(page.isClickable(wrapper.findOpenNavigationPanel().toSelector())).resolves.toBe(false);
363369
})
364370
);
371+
372+
test(
373+
'should programmatically resize drawers',
374+
setupTest(async page => {
375+
await page.setWindowSize(viewports.desktopWide);
376+
const drawerId1 = 'circle-global';
377+
const drawerId2 = 'circle3-global';
378+
await page.click(wrapper.findDrawerTriggerById(drawerId1).toSelector());
379+
await page.click(wrapper.findDrawerTriggerById(drawerId2).toSelector());
380+
381+
await page.waitForAssertion(async () => {
382+
await expect(page.getDrawerWidth(drawerId1)).resolves.toBe(351);
383+
await expect(page.getDrawerWidth(drawerId2)).resolves.toBe(321);
384+
});
385+
386+
await page.click(wrapper.find('[data-testid="button-circle-global-resize"]').toSelector());
387+
388+
await page.waitForAssertion(async () => {
389+
await expect(page.getDrawerWidth(drawerId1)).resolves.toBe(401);
390+
});
391+
392+
await page.click(wrapper.find('[data-testid="button-circle3-global-resize"]').toSelector());
393+
394+
await page.waitForAssertion(async () => {
395+
await expect(page.getDrawerWidth(drawerId2)).resolves.toBe(501);
396+
});
397+
})
398+
);
365399
});

src/app-layout/__tests__/runtime-drawers.test.tsx

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
findActiveDrawerLandmark,
1919
getActiveDrawerWidth,
2020
getGlobalDrawersTestUtils,
21+
getGlobalDrawerWidth,
2122
manyDrawers,
2223
testDrawer,
2324
} from './utils';
@@ -793,6 +794,30 @@ describeEachAppLayout(({ size }) => {
793794

794795
expect(wrapper.findActiveDrawer()).toBeFalsy();
795796
});
797+
798+
// skip these tests on mobile mode, because it only works for desktop view
799+
(size === 'desktop' ? describe : describe.skip)('resizing', () => {
800+
test('resizes a drawer when resizeDrawer is called', async () => {
801+
awsuiPlugins.appLayout.registerDrawer(drawerDefaults);
802+
803+
const { wrapper } = await renderComponent(<AppLayout drawers={[testDrawer]} />);
804+
805+
awsuiPlugins.appLayout.openDrawer('test');
806+
807+
await delay();
808+
809+
expect(wrapper.findActiveDrawer()!.getElement()).toHaveTextContent('runtime drawer content');
810+
expect(getActiveDrawerWidth(wrapper)).toEqual('290px');
811+
812+
awsuiPlugins.appLayout.resizeDrawer('test', 800);
813+
814+
expect(getActiveDrawerWidth(wrapper)).toEqual('800px');
815+
816+
awsuiPlugins.appLayout.resizeDrawer('test', 300);
817+
818+
expect(getActiveDrawerWidth(wrapper)).toEqual('300px');
819+
});
820+
});
796821
});
797822

798823
describe('toolbar mode only features', () => {
@@ -1646,6 +1671,33 @@ describe('toolbar mode only features', () => {
16461671
});
16471672
});
16481673
});
1674+
1675+
test('resizes multiple global drawers when resizeDrawer is called', async () => {
1676+
awsuiPlugins.appLayout.registerDrawer({ ...drawerDefaults, type: 'global' });
1677+
awsuiPlugins.appLayout.registerDrawer({ ...drawerDefaults, type: 'global', id: 'test1' });
1678+
1679+
const { globalDrawersWrapper } = await renderComponent(<AppLayout />);
1680+
1681+
awsuiPlugins.appLayout.openDrawer('test');
1682+
awsuiPlugins.appLayout.openDrawer('test1');
1683+
1684+
await delay();
1685+
1686+
expect(globalDrawersWrapper.findDrawerById('test')!.getElement()).toHaveTextContent('runtime drawer content');
1687+
expect(globalDrawersWrapper.findDrawerById('test1')!.getElement()).toHaveTextContent('runtime drawer content');
1688+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test')).toEqual('290px');
1689+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test1')).toEqual('290px');
1690+
1691+
awsuiPlugins.appLayout.resizeDrawer('test', 800);
1692+
1693+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test')).toEqual('800px');
1694+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test1')).toEqual('290px');
1695+
1696+
awsuiPlugins.appLayout.resizeDrawer('test1', 801);
1697+
1698+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test')).toEqual('800px');
1699+
expect(getGlobalDrawerWidth(globalDrawersWrapper, 'test1')).toEqual('801px');
1700+
});
16491701
});
16501702

16511703
describeEachAppLayout({ themes: ['refresh-toolbar'], sizes: ['mobile'] }, () => {

src/app-layout/__tests__/utils.tsx

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,15 @@ export function getActiveDrawerWidth(wrapper: AppLayoutWrapper): string {
107107
return drawerElement.style.width;
108108
}
109109

110+
export function getGlobalDrawerWidth(
111+
wrapper: ReturnType<typeof getGlobalDrawersTestUtils>,
112+
drawerId: string
113+
): string | null {
114+
const drawerElement = wrapper.findDrawerById(drawerId)!.getElement();
115+
const value = drawerElement.style.getPropertyValue(customCssProps.drawerSize);
116+
return value ?? null;
117+
}
118+
110119
export const splitPanelI18nStrings: SplitPanelProps.I18nStrings = {
111120
closeButtonAriaLabel: 'Close panel',
112121
openButtonAriaLabel: 'Open panel',

src/app-layout/utils/use-drawers.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,23 @@ function useDrawerRuntimeOpenClose(
159159
}, [disableRuntimeDrawers, onDrawerClosed]);
160160
}
161161

162+
function useDrawerRuntimeResize(
163+
disableRuntimeDrawers: boolean | undefined,
164+
onActiveDrawerResize: ({ id, size }: { id: string; size: number }) => void
165+
) {
166+
const onRuntimeDrawerResize = useStableCallback((drawerId: string, size: number) => {
167+
onActiveDrawerResize({ id: drawerId, size });
168+
});
169+
170+
useEffect(() => {
171+
if (disableRuntimeDrawers) {
172+
return;
173+
}
174+
175+
return awsuiPluginsInternal.appLayout.onDrawerResize(onRuntimeDrawerResize);
176+
}, [disableRuntimeDrawers, onRuntimeDrawerResize]);
177+
}
178+
162179
function applyToolsDrawer(toolsProps: ToolsProps, runtimeDrawers: DrawersLayout) {
163180
const drawers = [...runtimeDrawers.localBefore, ...runtimeDrawers.localAfter];
164181
if (drawers.length === 0 && toolsProps.disableDrawersMerge) {
@@ -297,6 +314,8 @@ export function useDrawers(
297314
onActiveGlobalDrawersChange
298315
);
299316

317+
useDrawerRuntimeResize(disableRuntimeDrawers, onActiveDrawerResize);
318+
300319
const activeDrawerSize = activeDrawerIdResolved
301320
? (drawerSizes[activeDrawerIdResolved] ?? activeDrawer?.defaultSize ?? toolsProps.toolsWidth)
302321
: toolsProps.toolsWidth;

src/internal/plugins/controllers/drawers.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ type DrawersRegistrationListener = (drawers: Array<DrawerConfig>) => void;
5959
type DrawersUpdateListener = (drawers: Array<DrawerConfig>) => void;
6060

6161
export type DrawersToggledListener = (drawerId: string, params?: OpenCloseDrawerParams) => void;
62+
type DrawersResizeListener = (drawerId: string, size: number) => void;
6263

6364
interface OpenCloseDrawerParams {
6465
initiatedByUserAction: boolean;
@@ -69,13 +70,15 @@ export interface DrawersApiPublic {
6970
updateDrawer(config: UpdateDrawerConfig): void;
7071
openDrawer(drawerId: string, params?: OpenCloseDrawerParams): void;
7172
closeDrawer(drawerId: string, params?: OpenCloseDrawerParams): void;
73+
resizeDrawer(drawerId: string, size: number): void;
7274
}
7375

7476
export interface DrawersApiInternal {
7577
clearRegisteredDrawers(): void;
7678
onDrawersRegistered(listener: DrawersRegistrationListener): () => void;
7779
onDrawerOpened(listener: DrawersToggledListener): () => void;
7880
onDrawerClosed(listener: DrawersToggledListener): () => void;
81+
onDrawerResize(listener: DrawersResizeListener): () => void;
7982
onDrawersUpdated(listener: DrawersUpdateListener): void;
8083
getDrawersState(): Array<DrawerConfig>;
8184
}
@@ -86,6 +89,7 @@ export class DrawersController {
8689
private drawerOpenedListener: DrawersToggledListener | null = null;
8790
private drawerClosedListener: DrawersToggledListener | null = null;
8891
private drawersUpdateListeners: Array<DrawersUpdateListener> = [];
92+
private drawerResizeListener: DrawersResizeListener | null = null;
8993

9094
scheduleUpdate = debounce(() => {
9195
this.drawersRegistrationListener?.(this.drawers);
@@ -185,6 +189,25 @@ export class DrawersController {
185189
};
186190
};
187191

192+
onDrawerResize = (listener: DrawersResizeListener) => {
193+
if (this.drawerResizeListener !== null) {
194+
reportRuntimeApiWarning(
195+
'app-layout-drawers',
196+
'multiple app layout instances detected when calling onDrawerResize'
197+
);
198+
}
199+
200+
this.drawerResizeListener = listener;
201+
202+
return () => {
203+
this.drawerResizeListener = null;
204+
};
205+
};
206+
207+
resizeDrawer = (drawerId: string, size: number) => {
208+
this.drawerResizeListener?.(drawerId, size);
209+
};
210+
188211
getDrawersState = () => {
189212
return this.drawers;
190213
};
@@ -194,6 +217,7 @@ export class DrawersController {
194217
api.updateDrawer ??= this.updateDrawer;
195218
api.openDrawer ??= this.openDrawer;
196219
api.closeDrawer ??= this.closeDrawer;
220+
api.resizeDrawer ??= this.resizeDrawer;
197221
return api as DrawersApiPublic;
198222
}
199223

@@ -202,6 +226,7 @@ export class DrawersController {
202226
internalApi.onDrawersRegistered ??= this.onDrawersRegistered;
203227
internalApi.onDrawerOpened ??= this.onDrawerOpened;
204228
internalApi.onDrawerClosed ??= this.onDrawerClosed;
229+
internalApi.onDrawerResize ??= this.onDrawerResize;
205230
internalApi.onDrawersUpdated ??= this.onDrawersUpdated;
206231
internalApi.getDrawersState ??= this.getDrawersState;
207232
return internalApi as DrawersApiInternal;

0 commit comments

Comments
 (0)