@navikt/ds-react
Version:
React components from the Norwegian Labour and Welfare Administration.
96 lines • 4.82 kB
JavaScript
import React, { useCallback, useEffect, useRef, useState } from "react";
import { useId } from "../../utils-external/index.js";
import { useControllableState, useEventCallback, useTransitionStatus, } from "../../utils/hooks/index.js";
import { DialogBody } from "../body/DialogBody.js";
import { DialogCloseTrigger, } from "../close-trigger/DialogCloseTrigger.js";
import { DialogDescription, } from "../description/DialogDescription.js";
import { DialogFooter } from "../footer/DialogFooter.js";
import { DialogHeader } from "../header/DialogHeader.js";
import { DialogPopup } from "../popup/DialogPopup.js";
import { DialogTitle } from "../title/DialogTitle.js";
import { DialogTrigger } from "../trigger/DialogTrigger.js";
import { DialogContextProvider, useDialogContext } from "./DialogRoot.context.js";
/**
* Dialog component for displaying modal content on top of an application.
* @see [📝 Documentation](https://aksel.nav.no/komponenter/core/dialog)
* @see 🏷️ {@link DialogProps}
* @example
* ```jsx
* <Dialog>
* <Dialog.Trigger>
* <Button>Open dialog</Button>
* </Dialog.Trigger>
* <Dialog.Popup>
* <Dialog.Header>
* <Dialog.Title>Dialog title</Dialog.Title>
* <Dialog.Description>Dialog description</Dialog.Description>
* </Dialog.Header>
* <Dialog.Body>
* Dialog body content
* </Dialog.Body>
* <Dialog.Footer>
* <Dialog.CloseTrigger>
* <Button>Close dialog</Button>
* </Dialog.CloseTrigger>
* </Dialog.Footer>
* </Dialog.Popup>
* </Dialog>
* ```
*/
export const Dialog = (props) => {
var _a;
const { children, defaultOpen = false, open: openParam, onOpenChange, onOpenChangeComplete, size = "medium", } = props;
const [open, setOpenStateInternal] = useControllableState({
defaultValue: defaultOpen,
value: openParam,
});
const { mounted, setMounted, transitionStatus } = useTransitionStatus(open);
const popupRef = useRef(null);
const [triggerElement, setTriggerElement] = useState(null);
const [popupElement, setPopupElement] = useState(null);
const defaultId = useId();
const [titleId, setTitleId] = useState();
const [ownNestedOpenDialogs, setOwnNestedOpenDialogs] = useState(0);
const nestedDialogOpened = useCallback((nestedCount) => {
setOwnNestedOpenDialogs(nestedCount + 1);
}, []);
const nestedDialogClosed = useCallback(() => {
setOwnNestedOpenDialogs(0);
}, []);
const parentContext = useDialogContext(false);
/**
* Notify parent dialog about nested dialogs opening/closing.
* This allows us to better hide/obscure parent dialogs when nested dialogs are opened.
*
* This pattern is not good for deep nesting since the context updates will cause cascading renders
* but should work fine for 1-2 levels of nesting which is the most common use case here.
*/
useEffect(() => {
if (open && parentContext) {
parentContext.nestedDialogOpened(ownNestedOpenDialogs);
return () => parentContext.nestedDialogClosed();
}
}, [open, parentContext, ownNestedOpenDialogs]);
/**
* Passing the original event to onOpenChange to allow preventing the state change
*/
const setOpen = useEventCallback((nextOpen, originalEvent) => {
onOpenChange === null || onOpenChange === void 0 ? void 0 : onOpenChange(nextOpen, originalEvent);
if (originalEvent === null || originalEvent === void 0 ? void 0 : originalEvent.defaultPrevented) {
return;
}
setOpenStateInternal(nextOpen);
});
return (React.createElement(DialogContextProvider, { open: open, setOpen: setOpen, mounted: mounted, transitionStatus: transitionStatus, popupRef: popupRef, setPopupElement: setPopupElement, popupElement: popupElement, popupId: (_a = popupElement === null || popupElement === void 0 ? void 0 : popupElement.id) !== null && _a !== void 0 ? _a : defaultId, setTriggerElement: setTriggerElement, triggerElement: triggerElement, nested: !!parentContext, nestedDialogOpened: nestedDialogOpened, nestedDialogClosed: nestedDialogClosed, nestedOpenDialogCount: ownNestedOpenDialogs, size: size, titleId: titleId, setTitleId: setTitleId, onOpenChangeComplete: onOpenChangeComplete, setMounted: setMounted }, children));
};
Dialog.Trigger = DialogTrigger;
Dialog.CloseTrigger = DialogCloseTrigger;
Dialog.Header = DialogHeader;
Dialog.Title = DialogTitle;
Dialog.Description = DialogDescription;
Dialog.Body = DialogBody;
Dialog.Footer = DialogFooter;
Dialog.Popup = DialogPopup;
export default Dialog;
export { DialogTrigger, DialogCloseTrigger, DialogHeader, DialogTitle, DialogDescription, DialogBody, DialogFooter, DialogPopup, };
//# sourceMappingURL=DialogRoot.js.map