Skip to content

Commit

Permalink
feat: Add clickOutside prop to Modal (#2214)
Browse files Browse the repository at this point in the history
For the Ruff settings editor, I wanted to close the modal when pressing
escape, but not clicking outside. Turns out this wasn't possible with
our previous modal component.
  • Loading branch information
mattrunyon committed Sep 9, 2024
1 parent 7331976 commit d78ad6d
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 0 deletions.
29 changes: 29 additions & 0 deletions packages/components/src/modal/Modal.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ function makeModal({
className,
children,
keyboard,
clickOutside,
isOpen,
centered,
onOpened,
Expand All @@ -17,6 +18,7 @@ function makeModal({
className?: string;
children?;
keyboard?: boolean;
clickOutside?: boolean;
isOpen?: boolean;
centered?: boolean;
onOpened?: () => void;
Expand All @@ -27,6 +29,7 @@ function makeModal({
<Modal
className={className}
keyboard={keyboard}
clickOutside={clickOutside}
isOpen={isOpen}
centered={centered}
onOpened={onOpened}
Expand Down Expand Up @@ -103,6 +106,32 @@ it('closes only when clicking outside the modal', async () => {
expect(toggle).toBeCalledTimes(0);
});

it('does not close on mouseUp outside the modal when initiated from inside the modal', async () => {
const user = userEvent.setup();
const toggle = jest.fn();
render(makeModal({ isOpen: true, toggle }));

const modalContent = document.querySelector('.modal-content')!;
await user.pointer({ target: modalContent, keys: '[MouseLeft>]' });
expect(toggle).toBeCalledTimes(0);

await user.pointer({
target: screen.getByRole('dialog'),
keys: '[/MouseLeft]',
});
expect(toggle).toBeCalledTimes(0);
});

it('does not close when clicking outside when clickOutside is false', async () => {
const user = userEvent.setup();
const toggle = jest.fn();
render(makeModal({ isOpen: true, toggle, clickOutside: false }));

// note that outer div covers the entire screen
await user.click(screen.getByRole('dialog'));
expect(toggle).toBeCalledTimes(0);
});

it('calls onOpen when opens', () => {
const onOpened = jest.fn();
const toggle = jest.fn();
Expand Down
3 changes: 3 additions & 0 deletions packages/components/src/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ interface ModalProps {
children?: ReactNode;
role?: string;
keyboard?: boolean;
clickOutside?: boolean;
isOpen?: boolean;
centered?: boolean;
size?: 'sm' | 'lg' | 'xl' | undefined;
Expand All @@ -30,6 +31,7 @@ function Modal({
children,
role = 'role',
keyboard = true,
clickOutside = true,
isOpen = false,
centered = false,
size,
Expand Down Expand Up @@ -146,6 +148,7 @@ function Modal({
onMouseUp={e => {
if (
backgroundClicked &&
clickOutside &&
e.target === background.current &&
toggle !== undefined
) {
Expand Down

0 comments on commit d78ad6d

Please sign in to comment.