Skip to content

Commit 233ec89

Browse files
authored
fix(dialog): prevent outside-click from other dialog managers closing active dialogs (#3112)
1 parent 7893492 commit 233ec89

File tree

2 files changed

+54
-0
lines changed

2 files changed

+54
-0
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import React from 'react';
2+
import { act, fireEvent, render, screen, waitFor } from '@testing-library/react';
3+
import { useDialogOnNearestManager } from '../hooks';
4+
import { DialogAnchor } from '../service';
5+
import { DialogManagerProvider } from '../../../context';
6+
7+
const DialogFixture = ({ dialogId, testId }: { dialogId: string; testId: string }) => {
8+
const { dialog } = useDialogOnNearestManager({ id: dialogId });
9+
10+
return (
11+
<>
12+
<button data-testid={`open-${dialogId}`} onClick={() => dialog.open()}>
13+
Open
14+
</button>
15+
<DialogAnchor id={dialogId}>
16+
<button data-testid={testId}>Dialog content</button>
17+
</DialogAnchor>
18+
</>
19+
);
20+
};
21+
22+
describe('DialogPortal', () => {
23+
it('does not close dialogs from another manager when clicking in a different manager overlay', async () => {
24+
render(
25+
<DialogManagerProvider id='manager-a'>
26+
<DialogFixture dialogId='dialog-a' testId='dialog-a-content' />
27+
<DialogManagerProvider id='manager-b'>
28+
<DialogFixture dialogId='dialog-b' testId='dialog-b-content' />
29+
</DialogManagerProvider>
30+
</DialogManagerProvider>,
31+
);
32+
33+
act(() => {
34+
fireEvent.click(screen.getByTestId('open-dialog-a'));
35+
fireEvent.click(screen.getByTestId('open-dialog-b'));
36+
});
37+
38+
expect(screen.getByTestId('dialog-a-content')).toBeInTheDocument();
39+
expect(screen.getByTestId('dialog-b-content')).toBeInTheDocument();
40+
41+
act(() => {
42+
fireEvent.click(screen.getByTestId('dialog-b-content'));
43+
});
44+
45+
await waitFor(() => {
46+
expect(screen.getByTestId('dialog-a-content')).toBeInTheDocument();
47+
expect(screen.getByTestId('dialog-b-content')).toBeInTheDocument();
48+
});
49+
});
50+
});

src/components/Dialog/service/DialogPortal.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,10 @@ export const DialogPortalDestination = () => {
2525

2626
const handleDocumentClick = (event: MouseEvent) => {
2727
const target = event.target as Node;
28+
const clickedOverlay = (target as HTMLElement).closest?.(
29+
'[data-str-chat__portal-id]',
30+
);
31+
if (clickedOverlay && clickedOverlay !== destinationRoot) return;
2832
if (target !== destinationRoot && destinationRoot.contains(target)) return;
2933
// Defer so target onClick handlers (e.g. context-menu toggle buttons) can run first.
3034
setTimeout(() => {

0 commit comments

Comments
 (0)