(react) add closeOnEsc props to Modal

We want to be able to disable closing modals by pressing escape in
some cases.
This commit is contained in:
Nathan Vasse
2024-04-23 12:01:47 +02:00
committed by NathanVss
parent 2916dd2af9
commit 285cf99681
4 changed files with 63 additions and 1 deletions

View File

@@ -149,6 +149,12 @@ You can change this behavior by passing the `closeOnClickOutside` prop.
<Canvas of={Stories.CloseOnClickOutside} story={{inline: false}}/>
## Close on escape
By default, the modal will be closed when you press the `esc` key. You can change this behavior by passing the `closeOnEsc` prop.
<Canvas of={Stories.DontCloseOnEsc} story={{inline: false}}/>
## Pre Built Modals
As we know that developers love to have handy shortcuts for common use cases, we provide some pre built modals that we

View File

@@ -209,6 +209,54 @@ describe("<Modal/>", () => {
await user.click(modal);
expect(screen.queryByText("Modal Content")).toBeInTheDocument();
});
it("close on esc by default", async () => {
const Wrapper = () => {
const modal = useModal();
return (
<CunninghamProvider>
<button onClick={modal.open}>Open Modal</button>
<Modal size={ModalSize.SMALL} {...modal}>
<div>Modal Content</div>
</Modal>
</CunninghamProvider>
);
};
render(<Wrapper />);
const user = userEvent.setup();
const button = screen.getByText("Open Modal");
expect(screen.queryByText("Modal Content")).not.toBeInTheDocument();
await user.click(button);
expect(screen.getByText("Modal Content")).toBeInTheDocument();
await user.keyboard("{Escape}");
expect(screen.queryByText("Modal Content")).not.toBeInTheDocument();
});
it("does not close on esc when using closeOnEsc=false", async () => {
const Wrapper = () => {
const modal = useModal();
return (
<CunninghamProvider>
<button onClick={modal.open}>Open Modal</button>
<Modal size={ModalSize.SMALL} closeOnEsc={false} {...modal}>
<div>Modal Content</div>
</Modal>
</CunninghamProvider>
);
};
render(<Wrapper />);
const user = userEvent.setup();
const button = screen.getByText("Open Modal");
expect(screen.queryByText("Modal Content")).not.toBeInTheDocument();
await user.click(button);
expect(screen.getByText("Modal Content")).toBeInTheDocument();
await user.keyboard("{Escape}");
expect(screen.queryByText("Modal Content")).toBeInTheDocument();
});
/**
* It should also prevent the modal from closing when pressing the escape key, but it appears

View File

@@ -80,6 +80,12 @@ export const CloseOnClickOutside: Story = {
closeOnClickOutside: true,
},
};
export const DontCloseOnEsc: Story = {
args: {
size: ModalSize.MEDIUM,
closeOnEsc: false,
},
};
export const PreventClose: Story = {
args: {
size: ModalSize.MEDIUM,

View File

@@ -51,6 +51,7 @@ export type ModalProps = PropsWithChildren & {
titleIcon?: React.ReactNode;
hideCloseButton?: boolean;
closeOnClickOutside?: boolean;
closeOnEsc?: boolean;
preventClose?: boolean;
};
@@ -71,7 +72,7 @@ export const Modal = (props: ModalProps) => {
return <ModalInner {...props} />;
};
export const ModalInner = (props: ModalProps) => {
export const ModalInner = ({ closeOnEsc = true, ...props }: ModalProps) => {
const { modalParentSelector } = useModals();
if (!props.isOpen) {
@@ -90,6 +91,7 @@ export const ModalInner = (props: ModalProps) => {
overlayClassName="c__modal__backdrop"
className={classNames(MODAL_CLASS, `${MODAL_CLASS}--${props.size}`)}
shouldCloseOnOverlayClick={!!props.closeOnClickOutside}
shouldCloseOnEsc={closeOnEsc}
bodyOpenClassName={classNames("c__modals--opened", NOSCROLL_CLASS)}
>
{!props.hideCloseButton && !props.preventClose && (