@lobehub/ui
Version:
Lobe UI is an open-source UI component library for building AIGC web apps
262 lines (261 loc) • 8.84 kB
JavaScript
"use client";
import { useMotionComponent } from "../../MotionProvider/index.mjs";
import { useNativeButton } from "../../hooks/useNativeButton.mjs";
import { useAppElement } from "../../ThemeProvider/AppElementContext.mjs";
import { useLayerZIndex } from "../zIndex/useLayerZIndex.mjs";
import { drawerBackdropTransition, getDrawerMotionConfig, pushAxis } from "./constants.mjs";
import { DrawerLayerProvider, useDrawerLayer } from "./DrawerLayerContext.mjs";
import { styles } from "./style.mjs";
import { cloneElement, createContext, createElement, isValidElement, use, useCallback, useEffect, useMemo, useRef, 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, useMergeRefs } from "react-merge-refs";
import { X } from "lucide-react";
import { Dialog } from "@base-ui/react/dialog";
//#region src/base-ui/Drawer/atoms.tsx
const mergeStateClassName = (base, className) => {
if (typeof className === "function") return (state) => cx(base, className(state));
return cx(base, className);
};
const popupPlacementClass = {
bottom: styles.popupBottom,
left: styles.popupLeft,
right: styles.popupRight,
top: styles.popupTop
};
const panelPlacementClass = {
bottom: styles.panelBottom,
left: styles.panelLeft,
right: styles.panelRight,
top: styles.panelTop
};
const panelRoundedClass = {
bottom: styles.panelRoundedBottom,
left: styles.panelRoundedLeft,
right: styles.panelRoundedRight,
top: styles.panelRoundedTop
};
const DrawerOpenContext = createContext(null);
const DrawerActionsContext = createContext(null);
const useDrawerOpen = () => use(DrawerOpenContext);
const useDrawerActions = () => use(DrawerActionsContext);
const AnimatedDrawerRoot = ({ open, children, onExitComplete: onExitCompleteProp, zIndex: explicitZIndex, ...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]);
const { zIndex, ref: popupRef } = useLayerZIndex("modal", explicitZIndex);
const layer = useMemo(() => ({
popupRef,
zIndex
}), [zIndex, popupRef]);
if (!isPresent) return null;
return /* @__PURE__ */ jsx(DrawerOpenContext, {
value: open,
children: /* @__PURE__ */ jsx(DrawerActionsContext, {
value: actions,
children: /* @__PURE__ */ jsx(DrawerLayerProvider, {
value: layer,
children: /* @__PURE__ */ jsx(Dialog.Root, {
modal: true,
open: true,
...rest,
children
})
})
})
});
};
const NonAnimatedDrawerRoot = ({ zIndex: explicitZIndex, children, ...rest }) => {
const { zIndex, ref: popupRef } = useLayerZIndex("modal", explicitZIndex);
const layer = useMemo(() => ({
popupRef,
zIndex
}), [zIndex, popupRef]);
return /* @__PURE__ */ jsx(DrawerLayerProvider, {
value: layer,
children: /* @__PURE__ */ jsx(Dialog.Root, {
modal: true,
...rest,
children
})
});
};
const DrawerRoot = ({ open, onExitComplete, ...rest }) => {
if (open !== void 0) return /* @__PURE__ */ jsx(AnimatedDrawerRoot, {
open,
onExitComplete,
...rest
});
return /* @__PURE__ */ jsx(NonAnimatedDrawerRoot, { ...rest });
};
const DrawerPortal = ({ container, ...rest }) => {
const appElement = useAppElement();
return /* @__PURE__ */ jsx(Dialog.Portal, {
container: container ?? appElement ?? void 0,
...rest
});
};
const DrawerBackdrop = ({ className, style, ...rest }) => {
const open = useDrawerOpen();
const layer = useDrawerLayer();
const Motion = useMotionComponent();
const layerStyle = layer?.zIndex !== void 0 ? { zIndex: layer.zIndex } : void 0;
if (open !== null) return /* @__PURE__ */ jsx(Dialog.Backdrop, {
...rest,
className: cx(styles.backdrop, className),
style: {
...layerStyle,
...style,
transition: "none"
},
render: /* @__PURE__ */ jsx(Motion.div, {
animate: { opacity: open ? 1 : 0 },
initial: { opacity: 0 },
transition: drawerBackdropTransition
})
});
return /* @__PURE__ */ jsx(Dialog.Backdrop, {
...rest,
className: mergeStateClassName(styles.backdrop, className),
style: {
...layerStyle,
...style
}
});
};
const DrawerPopup = ({ className, children, placement: placementProp = "right", width: widthProp, height: heightProp, flush, pushOffset = 0, motionProps, panelClassName, panelStyle, popupStyle, ref: forwardedRef, ...rest }) => {
const open = useDrawerOpen();
const actions = useDrawerActions();
const layer = useDrawerLayer();
const Motion = useMotionComponent();
const composedRef = useMergeRefs([forwardedRef, layer?.popupRef]);
const openGeometryRef = useRef({
height: heightProp,
placement: placementProp,
width: widthProp
});
if (open !== false) openGeometryRef.current = {
height: heightProp,
placement: placementProp,
width: widthProp
};
const { height, placement, width } = openGeometryRef.current;
const sizeStyle = placement === "left" || placement === "right" ? { width } : { height };
const resolvedPopupStyle = {
...layer?.zIndex === void 0 ? void 0 : { zIndex: layer.zIndex + 1 },
...sizeStyle,
...popupStyle
};
const popupBaseClassName = cx(styles.popup, popupPlacementClass[placement]);
const resolvedPanelClassName = cx(styles.panel, panelPlacementClass[placement], flush ? styles.panelFlush : panelRoundedClass[placement], panelClassName);
if (open !== null && actions) {
const motionConfig = getDrawerMotionConfig(placement, pushOffset);
return /* @__PURE__ */ jsx(Dialog.Popup, {
...rest,
className: cx(popupBaseClassName, className),
"data-drawer-anchor": placement,
ref: composedRef,
style: resolvedPopupStyle,
children: /* @__PURE__ */ jsx(AnimatePresence, {
onExitComplete: actions.onExitComplete,
children: open ? /* @__PURE__ */ createElement(Motion.div, {
...motionConfig,
...motionProps,
className: resolvedPanelClassName,
"data-drawer-placement": placement,
key: "drawer-popup-panel",
style: {
transition: "none",
...panelStyle
}
}, children) : null
})
});
}
const { axis, sign } = pushAxis[placement];
const pushVars = { [axis === "x" ? "--drawer-push-x" : "--drawer-push-y"]: `${pushOffset * sign}px` };
return /* @__PURE__ */ jsx(Dialog.Popup, {
...rest,
className: mergeStateClassName(popupBaseClassName, className),
"data-drawer-anchor": placement,
ref: composedRef,
style: resolvedPopupStyle,
children: /* @__PURE__ */ jsx("div", {
className: resolvedPanelClassName,
"data-drawer-placement": placement,
style: {
...pushVars,
...panelStyle
},
children
})
});
};
const DrawerHeader = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.header, className)
});
const DrawerTitle = ({ className, ...rest }) => /* @__PURE__ */ jsx(Dialog.Title, {
...rest,
className: mergeStateClassName(styles.title, className)
});
const DrawerDescription = Dialog.Description;
const DrawerContent = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.content, className)
});
const DrawerFooter = ({ className, ...rest }) => /* @__PURE__ */ jsx("div", {
...rest,
className: cx(styles.footer, className)
});
const DrawerClose = ({ className, children, ...rest }) => /* @__PURE__ */ jsx(Dialog.Close, {
...rest,
className: mergeStateClassName(styles.close, className),
children: children ?? /* @__PURE__ */ jsx(X, { size: 16 })
});
const DrawerTrigger = ({ 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;
})();
const mergedProps = mergeProps(children.props, resolvedProps);
return cloneElement(children, {
...mergedProps,
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 { DrawerBackdrop, DrawerClose, DrawerContent, DrawerDescription, DrawerFooter, DrawerHeader, DrawerPopup, DrawerPortal, DrawerRoot, DrawerTitle, DrawerTrigger, useDrawerActions, useDrawerOpen };
//# sourceMappingURL=atoms.mjs.map