Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Modal: Støtte for å lukke ved klikk utenfor #2386

Merged
merged 10 commits into from
Oct 27, 2023
5 changes: 5 additions & 0 deletions .changeset/slimy-cameras-reflect.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@navikt/ds-react": minor
---

:sparkles: Modal: Støtte for å lukke ved klikk utenfor
10 changes: 10 additions & 0 deletions @navikt/core/react/src/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
open,
onBeforeClose,
onCancel,
closeOnClickOutside,
KenAJoh marked this conversation as resolved.
Show resolved Hide resolved
width,
portal,
className,
Expand Down Expand Up @@ -129,6 +130,7 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
typeof width === "string" && ["small", "medium"].includes(width);

const component = (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
<dialog
{...rest}
ref={mergedRef}
Expand All @@ -147,6 +149,14 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
event.preventDefault();
} else if (onCancel) onCancel(event);
}}
onClick={
closeOnClickOutside
KenAJoh marked this conversation as resolved.
Show resolved Hide resolved
? (event) =>
event.target === modalRef.current &&
(!onBeforeClose || onBeforeClose() !== false) &&
modalRef.current.close()
: undefined
}
aria-labelledby={
!ariaLabelledby && !rest["aria-label"] && header
? ariaLabelId
Expand Down
5 changes: 4 additions & 1 deletion @navikt/core/react/src/modal/modal.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useRef, useState } from "react";
import { FileIcon } from "@navikt/aksel-icons";
import React, { useRef, useState } from "react";
import { BodyLong, Button, Heading } from "..";
import Modal from "./Modal";

Expand Down Expand Up @@ -27,6 +27,7 @@ export const WithUseRef = () => {
heading: "Title",
size: "small",
}}
closeOnClickOutside
>
<Modal.Body>
<BodyLong spacing>
Expand All @@ -45,6 +46,7 @@ export const WithUseRef = () => {
onBeforeClose={() =>
window.confirm("Are you sure you want to close the modal?")
}
closeOnClickOutside
aria-labelledby="heading123"
>
<Modal.Header>
Expand Down Expand Up @@ -111,6 +113,7 @@ export const WithUseState = () => {
e.stopPropagation(); // onClose wil propagate to parent modal if not stopped
setOpen2(false);
}}
closeOnClickOutside
aria-label="Nested modal"
width={800}
>
Expand Down
9 changes: 8 additions & 1 deletion @navikt/core/react/src/modal/types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export interface ModalProps
extends React.DialogHTMLAttributes<HTMLDialogElement> {
extends Omit<React.DialogHTMLAttributes<HTMLDialogElement>, "onClick"> {
KenAJoh marked this conversation as resolved.
Show resolved Hide resolved
/**
* Content for the header. Alteratively you can use <Modal.Header> instead for more control,
* but then you have to set `aria-label` or `aria-labelledby` on the modal manually.
Expand Down Expand Up @@ -42,6 +42,13 @@ export interface ModalProps
* Called when the user presses the Esc key, unless `onBeforeClose()` returns `false`.
*/
onCancel?: React.ReactEventHandler<HTMLDialogElement>;
/**
* Whether to close when clicking on the backdrop.
*
* **WARNING:** Users may click outside by accident. Don't use if closing causes data loss, or the modal contains important info.
* @default false
*/
closeOnClickOutside?: boolean;
/**
* @default fit-content (up to 700px)
* */
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import { BodyLong, Button, Modal } from "@navikt/ds-react";
import { withDsExample } from "components/website-modules/examples/withDsExample";
import { useRef } from "react";

const Example = () => {
const ref = useRef<HTMLDialogElement>(null);

return (
<div className="py-16">
<Button onClick={() => ref.current?.showModal()}>Åpne modal</Button>

<Modal ref={ref} header={{ heading: "Overskrift" }} closeOnClickOutside>
<Modal.Body>
<BodyLong>
Culpa aliquip ut cupidatat laborum minim quis ex in aliqua. Qui
incididunt dolor do ad ut. Incididunt eiusmod nostrud deserunt duis
laborum. Proident aute culpa qui nostrud velit adipisicing minim.
Consequat aliqua aute dolor do sit Lorem nisi mollit velit. Aliqua
exercitation non minim minim pariatur sunt laborum ipsum.
Exercitation nostrud est laborum magna non non aliqua qui esse.
</BodyLong>
</Modal.Body>
</Modal>
</div>
);
};

export default withDsExample(Example);

/* Storybook story */
export const Demo = {
render: Example,
};

export const args = {
index: 5,
desc: "Husk at det er lett å klikke utenfor ved et uhell. Ikke bruk 'closeOnClickOutside' hvis det kan føre til at brukeren mister data eller går glipp av viktig informasjon.",
};
Loading