diff --git a/packages/react/src/components/Modal/index.mdx b/packages/react/src/components/Modal/index.mdx index 48cd73a..18b534b 100644 --- a/packages/react/src/components/Modal/index.mdx +++ b/packages/react/src/components/Modal/index.mdx @@ -149,6 +149,12 @@ You can change this behavior by passing the `closeOnClickOutside` prop. +## 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. + + + ## 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 diff --git a/packages/react/src/components/Modal/index.spec.tsx b/packages/react/src/components/Modal/index.spec.tsx index 6c752b3..b28a048 100644 --- a/packages/react/src/components/Modal/index.spec.tsx +++ b/packages/react/src/components/Modal/index.spec.tsx @@ -209,6 +209,54 @@ describe("", () => { await user.click(modal); expect(screen.queryByText("Modal Content")).toBeInTheDocument(); }); + it("close on esc by default", async () => { + const Wrapper = () => { + const modal = useModal(); + return ( + + + +
Modal Content
+
+
+ ); + }; + + render(); + 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 ( + + + +
Modal Content
+
+
+ ); + }; + + render(); + 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 diff --git a/packages/react/src/components/Modal/index.stories.tsx b/packages/react/src/components/Modal/index.stories.tsx index 90d72b4..405cb57 100644 --- a/packages/react/src/components/Modal/index.stories.tsx +++ b/packages/react/src/components/Modal/index.stories.tsx @@ -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, diff --git a/packages/react/src/components/Modal/index.tsx b/packages/react/src/components/Modal/index.tsx index 7367ab6..ab4650a 100644 --- a/packages/react/src/components/Modal/index.tsx +++ b/packages/react/src/components/Modal/index.tsx @@ -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 ; }; -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 && (