136 lines
4.2 KiB
Plaintext
136 lines
4.2 KiB
Plaintext
"use client";
|
|
|
|
// src/use-modal.ts
|
|
import { useAriaModalOverlay } from "@heroui/use-aria-modal-overlay";
|
|
import { useCallback, useId, useRef, useState, useMemo } from "react";
|
|
import { modal } from "@heroui/theme";
|
|
import { mapPropsVariants, useProviderContext } from "@heroui/system";
|
|
import { useAriaButton } from "@heroui/use-aria-button";
|
|
import { useFocusRing } from "@react-aria/focus";
|
|
import { clsx, dataAttr, objectToDeps } from "@heroui/shared-utils";
|
|
import { useDOMRef } from "@heroui/react-utils";
|
|
import { useOverlayTriggerState } from "@react-stately/overlays";
|
|
import { mergeRefs, mergeProps } from "@react-aria/utils";
|
|
function useModal(originalProps) {
|
|
var _a, _b, _c;
|
|
const globalContext = useProviderContext();
|
|
const [props, variantProps] = mapPropsVariants(originalProps, modal.variantKeys);
|
|
const {
|
|
ref,
|
|
as,
|
|
className,
|
|
classNames,
|
|
isOpen,
|
|
defaultOpen,
|
|
onOpenChange,
|
|
motionProps,
|
|
closeButton,
|
|
isDismissable = true,
|
|
hideCloseButton = false,
|
|
shouldBlockScroll = true,
|
|
portalContainer,
|
|
isKeyboardDismissDisabled = false,
|
|
onClose,
|
|
...otherProps
|
|
} = props;
|
|
const Component = as || "section";
|
|
const domRef = useDOMRef(ref);
|
|
const closeButtonRef = useRef(null);
|
|
const [headerMounted, setHeaderMounted] = useState(false);
|
|
const [bodyMounted, setBodyMounted] = useState(false);
|
|
const disableAnimation = (_b = (_a = originalProps.disableAnimation) != null ? _a : globalContext == null ? void 0 : globalContext.disableAnimation) != null ? _b : false;
|
|
const dialogId = useId();
|
|
const headerId = useId();
|
|
const bodyId = useId();
|
|
const state = useOverlayTriggerState({
|
|
isOpen,
|
|
defaultOpen,
|
|
onOpenChange: (isOpen2) => {
|
|
onOpenChange == null ? void 0 : onOpenChange(isOpen2);
|
|
if (!isOpen2) {
|
|
onClose == null ? void 0 : onClose();
|
|
}
|
|
}
|
|
});
|
|
const { modalProps, underlayProps } = useAriaModalOverlay(
|
|
{
|
|
isDismissable,
|
|
shouldBlockScroll,
|
|
isKeyboardDismissDisabled
|
|
},
|
|
state,
|
|
domRef
|
|
);
|
|
const { buttonProps: closeButtonProps } = useAriaButton({ onPress: state.close }, closeButtonRef);
|
|
const { isFocusVisible: isCloseButtonFocusVisible, focusProps: closeButtonFocusProps } = useFocusRing();
|
|
const baseStyles = clsx(classNames == null ? void 0 : classNames.base, className);
|
|
const slots = useMemo(
|
|
() => modal({
|
|
...variantProps,
|
|
disableAnimation
|
|
}),
|
|
[objectToDeps(variantProps), disableAnimation]
|
|
);
|
|
const getDialogProps = (props2 = {}, ref2 = null) => {
|
|
var _a2;
|
|
return {
|
|
ref: mergeRefs(ref2, domRef),
|
|
...mergeProps(modalProps, otherProps, props2),
|
|
className: slots.base({ class: clsx(baseStyles, props2.className) }),
|
|
id: dialogId,
|
|
"data-open": dataAttr(state.isOpen),
|
|
"data-dismissable": dataAttr(isDismissable),
|
|
"aria-modal": dataAttr(true),
|
|
"data-placement": (_a2 = originalProps == null ? void 0 : originalProps.placement) != null ? _a2 : "right",
|
|
"aria-labelledby": headerMounted ? headerId : void 0,
|
|
"aria-describedby": bodyMounted ? bodyId : void 0
|
|
};
|
|
};
|
|
const getBackdropProps = useCallback(
|
|
(props2 = {}) => ({
|
|
className: slots.backdrop({ class: classNames == null ? void 0 : classNames.backdrop }),
|
|
onClick: () => state.close(),
|
|
...underlayProps,
|
|
...props2
|
|
}),
|
|
[slots, classNames, underlayProps]
|
|
);
|
|
const getCloseButtonProps = () => {
|
|
return {
|
|
role: "button",
|
|
tabIndex: 0,
|
|
"aria-label": "Close",
|
|
"data-focus-visible": dataAttr(isCloseButtonFocusVisible),
|
|
className: slots.closeButton({ class: classNames == null ? void 0 : classNames.closeButton }),
|
|
...mergeProps(closeButtonProps, closeButtonFocusProps)
|
|
};
|
|
};
|
|
return {
|
|
Component,
|
|
slots,
|
|
domRef,
|
|
headerId,
|
|
bodyId,
|
|
motionProps,
|
|
classNames,
|
|
isDismissable,
|
|
closeButton,
|
|
hideCloseButton,
|
|
portalContainer,
|
|
shouldBlockScroll,
|
|
backdrop: (_c = originalProps.backdrop) != null ? _c : "opaque",
|
|
isOpen: state.isOpen,
|
|
onClose: state.close,
|
|
disableAnimation,
|
|
setBodyMounted,
|
|
setHeaderMounted,
|
|
getDialogProps,
|
|
getBackdropProps,
|
|
getCloseButtonProps
|
|
};
|
|
}
|
|
|
|
export {
|
|
useModal
|
|
};
|