Skip to content

Commit

Permalink
Merge 88e95e5 into 792eeab
Browse files Browse the repository at this point in the history
  • Loading branch information
HalvorHaugan authored Oct 27, 2023
2 parents 792eeab + 88e95e5 commit 2631016
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 20 deletions.
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
64 changes: 44 additions & 20 deletions @navikt/core/react/src/modal/Modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -82,11 +82,13 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
open,
onBeforeClose,
onCancel,
closeOnBackdropClick,
width,
portal,
className,
"aria-labelledby": ariaLabelledby,
style,
onClick,
...rest
}: ModalProps,
ref
Expand Down Expand Up @@ -133,30 +135,52 @@ export const Modal = forwardRef<HTMLDialogElement, ModalProps>(
const isWidthPreset =
typeof width === "string" && ["small", "medium"].includes(width);

const mergedClassName = cl("navds-modal", className, {
"navds-modal--polyfilled": needPolyfill,
"navds-modal--autowidth": !width,
[`navds-modal--${width}`]: isWidthPreset,
});

const mergedStyle = {
...style,
...(!isWidthPreset ? { width } : {}),
};

const mergedOnCancel: React.DialogHTMLAttributes<HTMLDialogElement>["onCancel"] =
(event) => {
if (onBeforeClose && onBeforeClose() === false) {
event.preventDefault();
} else if (onCancel) onCancel(event);
};

const mergedOnClick =
closeOnBackdropClick && !needPolyfill // closeOnBackdropClick has issues on polyfill when nesting modals (DatePicker)
? (event: React.MouseEvent<HTMLDialogElement>) => {
onClick && onClick(event);
if (
event.target === modalRef.current &&
(!onBeforeClose || onBeforeClose() !== false)
) {
modalRef.current.close();
}
}
: onClick;

const mergedAriaLabelledBy =
!ariaLabelledby && !rest["aria-label"] && header
? ariaLabelId
: ariaLabelledby;

const component = (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
<dialog
{...rest}
ref={mergedRef}
className={cl("navds-modal", className, {
"navds-modal--polyfilled": needPolyfill,
"navds-modal--autowidth": !width,
[`navds-modal--${width}`]: isWidthPreset,
})}
style={{
...style,
...(!isWidthPreset ? { width } : {}),
}}
onCancel={(event) => {
// FYI: onCancel fires when you press Esc
if (onBeforeClose && onBeforeClose() === false) {
event.preventDefault();
} else if (onCancel) onCancel(event);
}}
aria-labelledby={
!ariaLabelledby && !rest["aria-label"] && header
? ariaLabelId
: ariaLabelledby
}
className={mergedClassName}
style={mergedStyle}
onCancel={mergedOnCancel} // FYI: onCancel fires when you press Esc
onClick={mergedOnClick}
aria-labelledby={mergedAriaLabelledBy}
>
<ModalContext.Provider
value={{
Expand Down
3 changes: 3 additions & 0 deletions @navikt/core/react/src/modal/modal.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export const WithUseRef = () => {
heading: "Title",
size: "small",
}}
closeOnBackdropClick
>
<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?")
}
closeOnBackdropClick
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);
}}
closeOnBackdropClick
aria-label="Nested modal"
width={800}
>
Expand Down
7 changes: 7 additions & 0 deletions @navikt/core/react/src/modal/types.ts
Original file line number Diff line number Diff line change
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 can cause data loss, or the modal contains important info.
* @default false
*/
closeOnBackdropClick?: 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" }} closeOnBackdropClick>
<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 'closeOnBackdropClick' hvis det kan føre til at brukeren mister data eller går glipp av viktig informasjon.",
};

0 comments on commit 2631016

Please sign in to comment.