UNPKG

@navikt/ds-react

Version:

React components from the Norwegian Labour and Welfare Administration.

96 lines 4.82 kB
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