@yamada-ui/modal
Version:
Yamada UI modal component
631 lines (615 loc) • 21.4 kB
JavaScript
"use client"
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/modal.tsx
var modal_exports = {};
__export(modal_exports, {
Modal: () => Modal
});
module.exports = __toCommonJS(modal_exports);
var import_core6 = require("@yamada-ui/core");
var import_focus_lock = require("@yamada-ui/focus-lock");
var import_motion6 = require("@yamada-ui/motion");
var import_portal = require("@yamada-ui/portal");
var import_use_value2 = require("@yamada-ui/use-value");
var import_utils11 = require("@yamada-ui/utils");
var import_react2 = require("react");
var import_react_remove_scroll = require("react-remove-scroll");
// src/dialog-overlay.tsx
var import_motion2 = require("@yamada-ui/motion");
var import_utils3 = require("@yamada-ui/utils");
// src/modal-context.ts
var import_utils = require("@yamada-ui/utils");
var [ModalProvider, useModal] = (0, import_utils.createContext)({
name: `ModalContext`,
errorMessage: `useModal returned is 'undefined'. Seems you forgot to wrap the components in "<Modal />" `
});
var [DialogProvider, useDialog] = (0, import_utils.createContext)({
name: `DialogContext`,
errorMessage: `useDialog returned is 'undefined'. Seems you forgot to wrap the components in "<Dialog />" `
});
var [DrawerProvider, useDrawer] = (0, import_utils.createContext)({
name: `DrawerContext`,
errorMessage: `useDrawer returned is 'undefined'. Seems you forgot to wrap the components in "<Drawer />" `
});
// src/modal-overlay.tsx
var import_motion = require("@yamada-ui/motion");
var import_transitions = require("@yamada-ui/transitions");
var import_utils2 = require("@yamada-ui/utils");
var import_jsx_runtime = require("react/jsx-runtime");
var ModalOverlay = (0, import_motion.motionForwardRef)(
({ className, onClick, __css, ...rest }, ref) => {
const {
animation,
closeOnOverlay,
duration,
styles,
onClose,
onOverlayClick
} = useModal();
const css = {
h: "100dvh",
left: 0,
position: "fixed",
top: 0,
w: "100vw",
...__css ? __css : styles.overlay
};
const props = animation !== "none" ? import_transitions.fadeProps : {};
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
import_motion.motion.div,
{
ref,
className: (0, import_utils2.cx)("ui-modal__overlay", className),
"aria-hidden": true,
custom: { duration },
onClick: (0, import_utils2.handlerAll)(onClick, onOverlayClick, (ev) => {
ev.stopPropagation();
if (closeOnOverlay) onClose == null ? void 0 : onClose();
}),
__css: css,
...props,
...rest
}
);
}
);
ModalOverlay.displayName = "ModalOverlay";
ModalOverlay.__ui__ = "ModalOverlay";
// src/dialog-overlay.tsx
var import_jsx_runtime2 = require("react/jsx-runtime");
var DialogOverlay = (0, import_motion2.motionForwardRef)(
({ className, ...rest }, ref) => {
const styles = useDialog();
const css = { ...styles.overlay };
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
ModalOverlay,
{
ref,
className: (0, import_utils3.cx)("ui-dialog__overlay", className),
__css: css,
...rest
}
);
}
);
DialogOverlay.displayName = "DialogOverlay";
DialogOverlay.__ui__ = "DialogOverlay";
// src/drawer-content.tsx
var import_core4 = require("@yamada-ui/core");
var import_motion3 = require("@yamada-ui/motion");
var import_transitions2 = require("@yamada-ui/transitions");
var import_use_value = require("@yamada-ui/use-value");
var import_utils7 = require("@yamada-ui/utils");
var import_react = require("react");
// src/drawer-close-button.tsx
var import_core2 = require("@yamada-ui/core");
var import_utils5 = require("@yamada-ui/utils");
// src/modal-close-button.tsx
var import_close_button = require("@yamada-ui/close-button");
var import_core = require("@yamada-ui/core");
var import_utils4 = require("@yamada-ui/utils");
var import_jsx_runtime3 = require("react/jsx-runtime");
var ModalCloseButton = (0, import_core.forwardRef)(
({ onClick, __css, ...rest }, ref) => {
const { styles, onClose } = useModal();
const css = {
position: "absolute",
...__css ? __css : styles.closeButton
};
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_close_button.CloseButton,
{
ref,
className: (0, import_utils4.cx)("ui-modal__close-button"),
"aria-label": "Close modal",
onClick: (0, import_utils4.handlerAll)(onClick, (ev) => {
ev.stopPropagation();
onClose == null ? void 0 : onClose();
}),
__css: css,
...rest
}
);
}
);
ModalCloseButton.displayName = "ModalCloseButton";
ModalCloseButton.__ui__ = "ModalCloseButton";
// src/drawer-close-button.tsx
var import_jsx_runtime4 = require("react/jsx-runtime");
var DrawerCloseButton = (0, import_core2.forwardRef)(
({ className, ...rest }, ref) => {
const styles = useDrawer();
const css = { ...styles.closeButton };
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
ModalCloseButton,
{
ref,
className: (0, import_utils5.cx)("ui-drawer__close-button", className),
__css: css,
...rest
}
);
}
);
DrawerCloseButton.displayName = "DrawerCloseButton";
DrawerCloseButton.__ui__ = "DrawerCloseButton";
// src/drawer-drag-bar.tsx
var import_core3 = require("@yamada-ui/core");
var import_utils6 = require("@yamada-ui/utils");
var import_jsx_runtime5 = require("react/jsx-runtime");
var DrawerDragBar = (0, import_core3.forwardRef)(
({ className, __css, ...rest }, ref) => {
const styles = useDrawer();
const css = { ...styles.dragBar };
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
import_core3.ui.div,
{
ref,
className: (0, import_utils6.cx)("ui-drawer__drag-bar", className),
__css: css,
...rest
}
);
}
);
DrawerDragBar.displayName = "DrawerDragBar";
DrawerDragBar.__ui__ = "DrawerDragBar";
// src/drawer-content.tsx
var import_jsx_runtime6 = require("react/jsx-runtime");
var DrawerContent = (0, import_motion3.motionForwardRef)(
({
className,
children,
closeOnDrag,
dragConstraints,
dragElastic,
dragOffset,
dragVelocity,
placement: _placement,
withCloseButton,
withDragBar,
blankForDragProps,
...rest
}, ref) => {
var _a, _b;
const { bodyRef, duration, headerRef, open, onClose } = useModal();
const styles = useDrawer();
const placement = (0, import_use_value.useValue)(_placement);
const validChildren = (0, import_utils7.getValidChildren)(children);
const [customDrawerCloseButton, ...cloneChildren] = (0, import_utils7.findChildren)(
validChildren,
DrawerCloseButton
);
const blankForDragBg = (0, import_react.useMemo)(() => {
var _a2, _b2, _c, _d, _e, _f, _g, _h, _i, _j;
const propBg = (_c = (_b2 = (_a2 = rest.backgroundColor) != null ? _a2 : rest.bgColor) != null ? _b2 : rest.background) != null ? _c : rest.bg;
const styleBg = (_j = (_h = (_f = (_d = styles.container) == null ? void 0 : _d.backgroundColor) != null ? _f : (_e = styles.container) == null ? void 0 : _e.bgColor) != null ? _h : (_g = styles.container) == null ? void 0 : _g.background) != null ? _j : (_i = styles.container) == null ? void 0 : _i.bg;
const computedBg = propBg != null ? propBg : styleBg;
return (0, import_utils7.isArray)(computedBg) ? computedBg : [computedBg];
}, [rest, styles]);
const blankForDrag = (0, import_react.useMemo)(() => {
let position = {};
switch (placement) {
case "top":
position = { left: 0, right: 0, top: "calc(-100dvh + 1px)" };
break;
case "bottom":
position = { bottom: "calc(-100dvh + 1px)", left: 0, right: 0 };
break;
case "left":
position = { bottom: 0, left: "calc(-100% + 1px)", top: 0 };
break;
case "right":
position = { bottom: 0, right: "calc(-100% + 1px)", top: 0 };
break;
}
const [lightBg, darkBg] = blankForDragBg;
return {
_after: {
bg: lightBg,
content: '""',
display: "block",
h: "100dvh",
position: "absolute",
w: "100%",
...position,
...blankForDragProps
},
_dark: {
_after: {
bg: darkBg
}
}
};
}, [placement, blankForDragBg, blankForDragProps]);
const css = (0, import_react.useMemo)(
() => ({
display: "flex",
flexDirection: placement === "top" || placement === "bottom" ? "column" : "row",
outline: 0,
...closeOnDrag ? blankForDrag : {},
...styles.container
}),
[blankForDrag, closeOnDrag, placement, styles]
);
const getDragDirectionRestriction = (0, import_react.useCallback)(
(value) => {
switch (placement) {
case "top":
return { bottom: value };
case "bottom":
return { top: value };
case "left":
return { right: value };
case "right":
return { left: value };
}
},
[placement]
);
const getDragDirection = (0, import_react.useCallback)(() => {
switch (placement) {
case "top":
case "bottom":
return "y";
case "left":
case "right":
return "x";
}
}, [placement]);
const isCloseByDragInfo = (0, import_react.useCallback)(
(info) => {
switch (placement) {
case "top":
return info.velocity.y <= dragVelocity * -1 || info.offset.y <= dragOffset * -1;
case "bottom":
return info.velocity.y >= dragVelocity || info.offset.y >= dragOffset;
case "left":
return info.velocity.x <= dragVelocity * -1 || info.offset.x <= dragOffset * -1;
case "right":
return info.velocity.x >= dragVelocity || info.offset.x >= dragOffset;
}
},
[placement, dragVelocity, dragOffset]
);
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
import_transitions2.Slide,
{
ref,
className: (0, import_utils7.cx)("ui-drawer", className),
"aria-describedby": (_a = bodyRef.current) == null ? void 0 : _a.id,
"aria-labelledby": (_b = headerRef.current) == null ? void 0 : _b.id,
"aria-modal": "true",
drag: closeOnDrag ? getDragDirection() : false,
dragConstraints: getDragDirectionRestriction(dragConstraints),
dragElastic: getDragDirectionRestriction(dragElastic),
dragMomentum: false,
dragSnapToOrigin: true,
duration,
isOpen: open,
placement,
role: "dialog",
tabIndex: -1,
onDragEnd: (_, info) => {
if (isCloseByDragInfo(info)) onClose == null ? void 0 : onClose();
},
__css: css,
...rest,
children: [
customDrawerCloseButton != null ? customDrawerCloseButton : withCloseButton && onClose ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DrawerCloseButton, {}) : null,
withDragBar && closeOnDrag && (placement === "bottom" || placement === "right") ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DrawerDragBar, {}) : null,
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
import_core4.ui.div,
{
className: "ui-drawer__inner",
__css: {
display: "flex",
flexDirection: "column",
w: "100%",
...styles.inner
},
children: cloneChildren
}
),
withDragBar && closeOnDrag && (placement === "top" || placement === "left") ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(DrawerDragBar, {}) : null
]
}
);
}
);
DrawerContent.displayName = "DrawerContent";
DrawerContent.__ui__ = "DrawerContent";
// src/drawer-overlay.tsx
var import_motion4 = require("@yamada-ui/motion");
var import_utils8 = require("@yamada-ui/utils");
var import_jsx_runtime7 = require("react/jsx-runtime");
var DrawerOverlay = (0, import_motion4.motionForwardRef)(
({ className, ...rest }, ref) => {
const styles = useDrawer();
const css = { ...styles.overlay };
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
ModalOverlay,
{
ref,
className: (0, import_utils8.cx)("ui-drawer__overlay", className),
__css: css,
...rest
}
);
}
);
DrawerOverlay.displayName = "DrawerOverlay";
DrawerOverlay.__ui__ = "DrawerOverlay";
// src/modal-content.tsx
var import_motion5 = require("@yamada-ui/motion");
var import_transitions3 = require("@yamada-ui/transitions");
var import_utils10 = require("@yamada-ui/utils");
// src/dialog-close-button.tsx
var import_core5 = require("@yamada-ui/core");
var import_utils9 = require("@yamada-ui/utils");
var import_jsx_runtime8 = require("react/jsx-runtime");
var DialogCloseButton = (0, import_core5.forwardRef)(
({ className, ...rest }, ref) => {
const styles = useDialog();
const css = { ...styles.closeButton };
return /* @__PURE__ */ (0, import_jsx_runtime8.jsx)(
ModalCloseButton,
{
ref,
className: (0, import_utils9.cx)("ui-dialog__close-button", className),
"aria-label": "Close dialog",
__css: css,
...rest
}
);
}
);
DialogCloseButton.displayName = "DialogCloseButton";
DialogCloseButton.__ui__ = "DialogCloseButton";
// src/modal-content.tsx
var import_jsx_runtime9 = require("react/jsx-runtime");
var getModalContentProps = (animation = "scale", duration) => {
switch (animation) {
case "scale":
return {
...import_transitions3.scaleFadeProps,
custom: { duration, reverse: true, scale: 0.95 }
};
case "top":
return {
...import_transitions3.slideFadeProps,
custom: { duration, offsetY: -16, reverse: true }
};
case "right":
return {
...import_transitions3.slideFadeProps,
custom: { duration, offsetX: 16, reverse: true }
};
case "left":
return {
...import_transitions3.slideFadeProps,
custom: { duration, offsetX: -16, reverse: true }
};
case "bottom":
return {
...import_transitions3.slideFadeProps,
custom: { duration, offsetY: 16, reverse: true }
};
}
};
var ModalContent = (0, import_motion5.motionForwardRef)(
({ className, children, __css, ...rest }, ref) => {
var _a, _b;
const {
animation,
bodyRef,
duration,
headerRef,
scrollBehavior,
styles,
withCloseButton,
onClose
} = useModal();
const validChildren = (0, import_utils10.getValidChildren)(children);
const [customModalCloseButton, ...cloneChildren] = (0, import_utils10.findChildren)(
validChildren,
ModalCloseButton,
DialogCloseButton
);
const props = animation !== "none" ? getModalContentProps(animation, duration) : {};
const css = {
display: "flex",
flexDirection: "column",
maxH: "100%",
outline: 0,
overflow: scrollBehavior === "inside" ? "hidden" : "auto",
position: "relative",
...__css ? __css : styles.container
};
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
import_motion5.motion.section,
{
ref,
className: (0, import_utils10.cx)("ui-modal", className),
"aria-describedby": (_a = bodyRef.current) == null ? void 0 : _a.id,
"aria-labelledby": (_b = headerRef.current) == null ? void 0 : _b.id,
"aria-modal": "true",
role: "dialog",
tabIndex: -1,
__css: css,
...props,
...rest,
children: [
customModalCloseButton != null ? customModalCloseButton : withCloseButton && onClose ? /* @__PURE__ */ (0, import_jsx_runtime9.jsx)(ModalCloseButton, {}) : null,
cloneChildren
]
}
);
}
);
ModalContent.displayName = "ModalContent";
ModalContent.__ui__ = "ModalContent";
// src/modal.tsx
var import_jsx_runtime10 = require("react/jsx-runtime");
var Modal = (0, import_motion6.motionForwardRef)(
({ size, ...props }, ref) => {
const [styles, mergedProps] = (0, import_core6.useComponentMultiStyle)("Modal", {
size,
...props
});
const {
className,
allowPinchZoom = false,
animation = "scale",
autoFocus,
blockScrollOnMount = true,
children,
closeOnEsc = true,
closeOnOverlay = true,
duration,
finalFocusRef,
initialFocusRef,
isOpen,
lockFocusAcrossFrames = true,
open = isOpen,
outside = "fallback(4, 1rem)",
placement: _placement = "center",
restoreFocus,
scrollBehavior = "inside",
withCloseButton = true,
withOverlay = true,
containerProps,
portalProps,
onClose,
onCloseComplete,
onEsc,
onOverlayClick,
...rest
} = (0, import_core6.omitThemeProps)(mergedProps);
const headerRef = (0, import_react2.useRef)(null);
const bodyRef = (0, import_react2.useRef)(null);
const placement = (0, import_use_value2.useValue)(_placement);
const validChildren = (0, import_utils11.getValidChildren)(children);
const [customModalOverlay, ...cloneChildren] = (0, import_utils11.findChildren)(
validChildren,
ModalOverlay,
DialogOverlay,
DrawerOverlay
);
const css = {
alignItems: placement.includes("top") ? "flex-start" : placement.includes("bottom") ? "flex-end" : "center",
display: "flex",
h: "100dvh",
justifyContent: placement.includes("left") ? "flex-start" : placement.includes("right") ? "flex-end" : "center",
left: 0,
p: size !== "full" ? outside : void 0,
position: "fixed",
top: 0,
w: "100vw",
zIndex: "fallback(jeice, 110)"
};
const onKeyDown = (0, import_react2.useCallback)(
(ev) => {
if (ev.key !== "Escape") return;
ev.stopPropagation();
if (closeOnEsc) onClose == null ? void 0 : onClose();
onEsc == null ? void 0 : onEsc();
},
[closeOnEsc, onClose, onEsc]
);
let drawerContent = (0, import_utils11.findChild)(validChildren, DrawerContent);
if (drawerContent)
drawerContent = (0, import_react2.cloneElement)(drawerContent, { onKeyDown });
return /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
ModalProvider,
{
value: {
animation,
bodyRef,
closeOnOverlay,
duration,
headerRef,
open,
scrollBehavior,
styles,
withCloseButton,
onClose,
onOverlayClick
},
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_motion6.AnimatePresence, { onExitComplete: onCloseComplete, children: open ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(import_portal.Portal, { ...portalProps, children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
import_focus_lock.FocusLock,
{
autoFocus,
finalFocusRef,
initialFocusRef,
lockFocusAcrossFrames,
restoreFocus,
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
import_react_remove_scroll.RemoveScroll,
{
allowPinchZoom,
enabled: blockScrollOnMount,
forwardProps: true,
children: /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_core6.ui.div, { __css: css, ...containerProps, children: [
customModalOverlay != null ? customModalOverlay : withOverlay && size !== "full" ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(ModalOverlay, {}) : null,
drawerContent != null ? drawerContent : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)(
ModalContent,
{
ref,
className,
onKeyDown,
...rest,
children: cloneChildren
}
)
] })
}
)
}
) }) : null })
}
);
}
);
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
Modal
});
//# sourceMappingURL=modal.js.map