UNPKG

@base-ui-components/react

Version:

Base UI is a library of headless ('unstyled') React components and low-level hooks. You gain complete control over your app's CSS and accessibility features.

166 lines (165 loc) 5.89 kB
"use strict"; 'use client'; var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default; Object.defineProperty(exports, "__esModule", { value: true }); exports.useDialogRoot = useDialogRoot; var React = _interopRequireWildcard(require("react")); var _useControlled = require("@base-ui-components/utils/useControlled"); var _useEventCallback = require("@base-ui-components/utils/useEventCallback"); var _floatingUiReact = require("../../floating-ui-react"); var _utils = require("../../floating-ui-react/utils"); var _useScrollLock = require("../../utils/useScrollLock"); var _useTransitionStatus = require("../../utils/useTransitionStatus"); var _useOpenInteractionType = require("../../utils/useOpenInteractionType"); var _useOpenChangeComplete = require("../../utils/useOpenChangeComplete"); var _translateOpenChangeReason = require("../../utils/translateOpenChangeReason"); function useDialogRoot(params) { const { defaultOpen, dismissible, modal, onNestedDialogClose, onNestedDialogOpen, onOpenChange: onOpenChangeParameter, open: openParam, onOpenChangeComplete } = params; const [open, setOpenUnwrapped] = (0, _useControlled.useControlled)({ controlled: openParam, default: defaultOpen, name: 'DialogRoot', state: 'open' }); const popupRef = React.useRef(null); const backdropRef = React.useRef(null); const internalBackdropRef = React.useRef(null); const [titleElementId, setTitleElementId] = React.useState(undefined); const [descriptionElementId, setDescriptionElementId] = React.useState(undefined); const [triggerElement, setTriggerElement] = React.useState(null); const [popupElement, setPopupElement] = React.useState(null); const { mounted, setMounted, transitionStatus } = (0, _useTransitionStatus.useTransitionStatus)(open); const { openMethod, triggerProps, reset: resetOpenInteractionType } = (0, _useOpenInteractionType.useOpenInteractionType)(open); const setOpen = (0, _useEventCallback.useEventCallback)((nextOpen, event, reason) => { onOpenChangeParameter?.(nextOpen, event, reason); setOpenUnwrapped(nextOpen); }); const handleUnmount = (0, _useEventCallback.useEventCallback)(() => { setMounted(false); onOpenChangeComplete?.(false); resetOpenInteractionType(); }); (0, _useOpenChangeComplete.useOpenChangeComplete)({ enabled: !params.actionsRef, open, ref: popupRef, onComplete() { if (!open) { handleUnmount(); } } }); React.useImperativeHandle(params.actionsRef, () => ({ unmount: handleUnmount }), [handleUnmount]); const handleFloatingUIOpenChange = (nextOpen, event, reason) => { setOpen(nextOpen, event, (0, _translateOpenChangeReason.translateOpenChangeReason)(reason)); }; const context = (0, _floatingUiReact.useFloatingRootContext)({ elements: { reference: triggerElement, floating: popupElement }, open, onOpenChange: handleFloatingUIOpenChange }); const [ownNestedOpenDialogs, setOwnNestedOpenDialogs] = React.useState(0); const isTopmost = ownNestedOpenDialogs === 0; const role = (0, _floatingUiReact.useRole)(context); const click = (0, _floatingUiReact.useClick)(context); const dismiss = (0, _floatingUiReact.useDismiss)(context, { outsidePressEvent: 'intentional', outsidePress(event) { if (event.button !== 0) { return false; } const target = (0, _utils.getTarget)(event); if (isTopmost && dismissible) { const backdrop = target; // Only close if the click occurred on the dialog's owning backdrop. // This supports multiple modal dialogs that aren't nested in the React tree: // https://github.com/mui/base-ui/issues/1320 if (modal) { return backdrop ? internalBackdropRef.current === backdrop || backdropRef.current === backdrop : false; } return true; } return false; }, escapeKey: isTopmost }); (0, _useScrollLock.useScrollLock)({ enabled: open && modal === true, mounted, open, referenceElement: popupElement }); const { getReferenceProps, getFloatingProps } = (0, _floatingUiReact.useInteractions)([role, click, dismiss]); React.useEffect(() => { if (onNestedDialogOpen && open) { onNestedDialogOpen(ownNestedOpenDialogs); } if (onNestedDialogClose && !open) { onNestedDialogClose(); } return () => { if (onNestedDialogClose && open) { onNestedDialogClose(); } }; }, [open, onNestedDialogClose, onNestedDialogOpen, ownNestedOpenDialogs]); const handleNestedDialogOpen = React.useCallback(ownChildrenCount => { setOwnNestedOpenDialogs(ownChildrenCount + 1); }, []); const handleNestedDialogClose = React.useCallback(() => { setOwnNestedOpenDialogs(0); }, []); const dialogTriggerProps = React.useMemo(() => getReferenceProps(triggerProps), [getReferenceProps, triggerProps]); return React.useMemo(() => { return { modal, setOpen, open, titleElementId, setTitleElementId, descriptionElementId, setDescriptionElementId, onNestedDialogOpen: handleNestedDialogOpen, onNestedDialogClose: handleNestedDialogClose, nestedOpenDialogCount: ownNestedOpenDialogs, openMethod, mounted, transitionStatus, triggerProps: dialogTriggerProps, getPopupProps: getFloatingProps, setTriggerElement, setPopupElement, popupRef, backdropRef, internalBackdropRef, floatingRootContext: context }; }, [modal, setOpen, open, titleElementId, descriptionElementId, handleNestedDialogOpen, handleNestedDialogClose, ownNestedOpenDialogs, openMethod, mounted, transitionStatus, dialogTriggerProps, getFloatingProps, context]); }