@chakra-ui/modal
Version:
An accessible dialog (modal) component for React & Chakra UI
126 lines (124 loc) • 3.5 kB
JavaScript
'use client'
import {
modalManager,
useModalManager
} from "./chunk-CYRBRIA2.mjs";
// src/use-modal.ts
import { callAllHandlers } from "@chakra-ui/shared-utils";
import { mergeRefs } from "@chakra-ui/react-use-merge-refs";
import { hideOthers } from "aria-hidden";
import { useCallback, useEffect, useId, useMemo, useRef, useState } from "react";
function useModal(props) {
const {
isOpen,
onClose,
id,
closeOnOverlayClick = true,
closeOnEsc = true,
useInert = true,
onOverlayClick: onOverlayClickProp,
onEsc
} = props;
const dialogRef = useRef(null);
const overlayRef = useRef(null);
const [dialogId, headerId, bodyId] = useIds(
id,
`chakra-modal`,
`chakra-modal--header`,
`chakra-modal--body`
);
useAriaHidden(dialogRef, isOpen && useInert);
const index = useModalManager(dialogRef, isOpen);
const mouseDownTarget = useRef(null);
const onMouseDown = useCallback((event) => {
mouseDownTarget.current = event.target;
}, []);
const onKeyDown = useCallback(
(event) => {
if (event.key === "Escape") {
event.stopPropagation();
if (closeOnEsc) {
onClose == null ? void 0 : onClose();
}
onEsc == null ? void 0 : onEsc();
}
},
[closeOnEsc, onClose, onEsc]
);
const [headerMounted, setHeaderMounted] = useState(false);
const [bodyMounted, setBodyMounted] = useState(false);
const getDialogProps = useCallback(
(props2 = {}, ref = null) => ({
role: "dialog",
...props2,
ref: mergeRefs(ref, dialogRef),
id: dialogId,
tabIndex: -1,
"aria-modal": true,
"aria-labelledby": headerMounted ? headerId : void 0,
"aria-describedby": bodyMounted ? bodyId : void 0,
onClick: callAllHandlers(
props2.onClick,
(event) => event.stopPropagation()
)
}),
[bodyId, bodyMounted, dialogId, headerId, headerMounted]
);
const onOverlayClick = useCallback(
(event) => {
event.stopPropagation();
if (mouseDownTarget.current !== event.target)
return;
if (!modalManager.isTopModal(dialogRef.current))
return;
if (closeOnOverlayClick) {
onClose == null ? void 0 : onClose();
}
onOverlayClickProp == null ? void 0 : onOverlayClickProp();
},
[onClose, closeOnOverlayClick, onOverlayClickProp]
);
const getDialogContainerProps = useCallback(
(props2 = {}, ref = null) => ({
...props2,
ref: mergeRefs(ref, overlayRef),
onClick: callAllHandlers(props2.onClick, onOverlayClick),
onKeyDown: callAllHandlers(props2.onKeyDown, onKeyDown),
onMouseDown: callAllHandlers(props2.onMouseDown, onMouseDown)
}),
[onKeyDown, onMouseDown, onOverlayClick]
);
return {
isOpen,
onClose,
headerId,
bodyId,
setBodyMounted,
setHeaderMounted,
dialogRef,
overlayRef,
getDialogProps,
getDialogContainerProps,
index
};
}
function useAriaHidden(ref, shouldHide) {
const currentElement = ref.current;
useEffect(() => {
if (!ref.current || !shouldHide)
return void 0;
return hideOthers(ref.current);
}, [shouldHide, ref, currentElement]);
}
function useIds(idProp, ...prefixes) {
const reactId = useId();
const id = idProp || reactId;
return useMemo(() => {
return prefixes.map((prefix) => `${prefix}-${id}`);
}, [id, prefixes]);
}
export {
useModal,
useAriaHidden
};
//# sourceMappingURL=chunk-TJ2Q5ITW.mjs.map