@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
190 lines (187 loc) • 6.13 kB
JavaScript
'use client';
import { useMotionComponent } from "../../MotionProvider/index.mjs";
import { useNativeButton } from "../../hooks/useNativeButton.mjs";
import { useAppElement } from "../../ThemeProvider/AppElementContext.mjs";
import { backdropTransition, modalMotionConfig } from "./constants.mjs";
import { styles } from "./style.mjs";
import { cloneElement, createContext, createElement, isValidElement, use, useCallback, useEffect, useMemo, useState } from "react";
import { jsx } from "react/jsx-runtime";
import { cx } from "antd-style";
import { AnimatePresence } from "motion/react";
import { mergeProps } from "@base-ui/react/merge-props";
import { mergeRefs } from "react-merge-refs";
import { X } from "lucide-react";
import { Dialog } from "@base-ui/react/dialog";
//#region src/base-ui/Modal/atoms.tsx
const mergeStateClassName = (base, className) => {
if (typeof className === "function") return (state) => cx(base, className(state));
return cx(base, className);
};
const ModalOpenContext = createContext(null);
const ModalActionsContext = createContext(null);
const useModalOpen = () => use(ModalOpenContext);
const useModalActions = () => use(ModalActionsContext);
const AnimatedModalRoot = ({ open, children, onExitComplete: onExitCompleteProp, ...rest }) => {
const [isPresent, setIsPresent] = useState(!!open);
useEffect(() => {
if (open) setIsPresent(true);
}, [open]);
const handleExitComplete = useCallback(() => {
setIsPresent(false);
onExitCompleteProp?.();
}, [onExitCompleteProp]);
const actions = useMemo(() => ({ onExitComplete: handleExitComplete }), [handleExitComplete]);
if (!isPresent) return null;
return /* @__PURE__ */ jsx(ModalOpenContext, {
value: open,
children: /* @__PURE__ */ jsx(ModalActionsContext, {
value: actions,
children: /* @__PURE__ */ jsx(Dialog.Root, {
modal: true,
open: true,
...rest,
children
})
})
});
};
const ModalRoot = ({ open, onExitComplete, ...rest }) => {
if (open !== void 0) return /* @__PURE__ */ jsx(AnimatedModalRoot, {
open,
onExitComplete,
...rest
});
return /* @__PURE__ */ jsx(Dialog.Root, {
modal: true,
...rest
});
};
const ModalPortal = ({ container, ...rest }) => {
const appElement = useAppElement();
return /* @__PURE__ */ jsx(Dialog.Portal, {
container: container ?? appElement ?? void 0,
...rest
});
};
const ModalViewport = ({ className, ...rest }) => /* @__PURE__ */ jsx(Dialog.Viewport, {
...rest,
className: mergeStateClassName(styles.viewport, className)
});
const ModalBackdrop = ({ className, style, ...rest }) => {
const open = useModalOpen();
const Motion = useMotionComponent();
if (open !== null) return /* @__PURE__ */ jsx(Dialog.Backdrop, {
...rest,
className: cx(styles.backdrop, className),
style: {
...style,
transition: "none"
},
render: /* @__PURE__ */ jsx(Motion.div, {
animate: { opacity: open ? 1 : 0 },
initial: { opacity: 0 },
transition: backdropTransition
})
});
return /* @__PURE__ */ jsx(Dialog.Backdrop, {
...rest,
className: mergeStateClassName(styles.backdrop, className),
style
});
};
const ModalPopup = ({ className, children, width, style, motionProps, panelClassName, popupStyle, ...rest }) => {
const open = useModalOpen();
const actions = useModalActions();
const Motion = useMotionComponent();
if (open !== null && actions) return /* @__PURE__ */ jsx(Dialog.Popup, {
...rest,
className: cx(styles.popup, className),
style: popupStyle,
children: /* @__PURE__ */ jsx(AnimatePresence, {
onExitComplete: actions.onExitComplete,
children: open ? /* @__PURE__ */ createElement(Motion.div, {
...modalMotionConfig,
...motionProps,
className: cx(styles.popupInner, panelClassName),
key: "modal-popup-panel",
style: {
maxWidth: width ?? void 0,
transition: "none",
...style
}
}, children) : null
})
});
return /* @__PURE__ */ jsx(Dialog.Popup, {
...rest,
className: mergeStateClassName(styles.popup, className),
style: popupStyle,
children: /* @__PURE__ */ jsx("div", {
className: cx(styles.popupInner, panelClassName),
style: {
maxWidth: width ?? void 0,
...style
},
children
})
});
};
const ModalHeader = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.header, className)
});
const ModalTitle = ({ className, ...rest }) => /* @__PURE__ */ jsx(Dialog.Title, {
...rest,
className: mergeStateClassName(styles.title, className)
});
const ModalDescription = Dialog.Description;
const ModalContent = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.content, className)
});
const ModalFooter = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.footer, className)
});
const ModalClose = ({ className, children, ...rest }) => /* @__PURE__ */ jsx(Dialog.Close, {
...rest,
className: mergeStateClassName(styles.close, className),
children: children ?? /* @__PURE__ */ jsx(X, { size: 18 })
});
const ModalTrigger = ({ children, className, nativeButton, ref: refProp, ...rest }) => {
const { isNativeButtonTriggerElement, resolvedNativeButton } = useNativeButton({
children,
nativeButton
});
const renderer = (props) => {
const resolvedProps = (() => {
if (isNativeButtonTriggerElement) return props;
const { type, ...restProps } = props;
return restProps;
})();
return cloneElement(children, {
...mergeProps(children.props, resolvedProps),
ref: mergeRefs([
children.ref,
props.ref,
refProp
])
});
};
if (isValidElement(children)) return /* @__PURE__ */ jsx(Dialog.Trigger, {
...rest,
className,
nativeButton: resolvedNativeButton,
render: renderer
});
return /* @__PURE__ */ jsx(Dialog.Trigger, {
...rest,
className,
nativeButton: resolvedNativeButton,
ref: refProp,
children
});
};
//#endregion
export { ModalBackdrop, ModalClose, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalPopup, ModalPortal, ModalRoot, ModalTitle, ModalTrigger, ModalViewport, useModalActions, useModalOpen };
//# sourceMappingURL=atoms.mjs.map