@yamada-ui/popover
Version:
Yamada UI popover component
464 lines (460 loc) • 15.4 kB
JavaScript
"use client"
;
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/popover-content.tsx
var popover_content_exports = {};
__export(popover_content_exports, {
PopoverContent: () => PopoverContent
});
module.exports = __toCommonJS(popover_content_exports);
var import_core3 = require("@yamada-ui/core");
var import_motion = require("@yamada-ui/motion");
var import_transitions = require("@yamada-ui/transitions");
var import_utils3 = require("@yamada-ui/utils");
// src/popover.tsx
var import_core = require("@yamada-ui/core");
var import_use_animation = require("@yamada-ui/use-animation");
var import_use_disclosure = require("@yamada-ui/use-disclosure");
var import_use_focus = require("@yamada-ui/use-focus");
var import_use_popper = require("@yamada-ui/use-popper");
var import_utils = require("@yamada-ui/utils");
var import_react = require("react");
var import_jsx_runtime = require("react/jsx-runtime");
var popoverProperties = [
...import_use_popper.popperProperties,
"open",
"isOpen",
"defaultOpen",
"defaultIsOpen",
"onOpen",
"onClose",
"initialFocusRef",
"restoreFocus",
"autoFocus",
"closeOnBlur",
"closeOnEsc",
"closeOnButton",
"trigger",
"openDelay",
"closeDelay",
"lazy",
"isLazy",
"lazyBehavior",
"animation",
"duration"
];
var [PopoverProvider, usePopover] = (0, import_utils.createContext)({
name: "PopoverContext",
errorMessage: `usePopoverContext returned is 'undefined'. Seems you forgot to wrap the components in "<Popover />"`
});
var Popover = (props) => {
const [styles, mergedProps] = (0, import_core.useComponentMultiStyle)("Popover", props);
const {
animation = "scale",
autoFocus = true,
children,
closeDelay = 200,
closeOnBlur = true,
closeOnButton = true,
closeOnEsc = true,
duration,
initialFocusRef,
isLazy,
lazy = isLazy,
lazyBehavior = "unmount",
openDelay = 200,
relatedRef,
restoreFocus = true,
trigger = "click",
...rest
} = (0, import_core.omitThemeProps)(mergedProps);
const id = (0, import_react.useId)();
const { open, onClose, onOpen, onToggle } = (0, import_use_disclosure.useDisclosure)(mergedProps);
const anchorRef = (0, import_react.useRef)(null);
const triggerRef = (0, import_react.useRef)(null);
const headerRef = (0, import_react.useRef)(null);
const bodyRef = (0, import_react.useRef)(null);
const popoverRef = (0, import_react.useRef)(null);
const { present, onAnimationComplete } = (0, import_use_animation.useAnimationObserver)({
ref: popoverRef,
open
});
const openTimeout = (0, import_react.useRef)(void 0);
const closeTimeout = (0, import_react.useRef)(void 0);
const hoveringRef = (0, import_react.useRef)(false);
const hasBeenOpened = (0, import_react.useRef)(false);
const { forceUpdate, referenceRef, transformOrigin, getPopperProps } = (0, import_use_popper.usePopper)({
...rest,
enabled: open
});
if (open) hasBeenOpened.current = true;
(0, import_react.useEffect)(() => {
return () => {
if (openTimeout.current) clearTimeout(openTimeout.current);
if (closeTimeout.current) clearTimeout(closeTimeout.current);
};
}, []);
(0, import_use_focus.useFocusOnPointerDown)({
ref: triggerRef,
enabled: open
});
(0, import_use_focus.useFocusOnHide)(popoverRef, {
focusRef: triggerRef,
shouldFocus: restoreFocus && (trigger === "click" || trigger === "contextmenu"),
visible: open
});
(0, import_use_focus.useFocusOnShow)(popoverRef, {
focusRef: initialFocusRef,
shouldFocus: autoFocus && (trigger === "click" || trigger === "contextmenu"),
visible: open
});
const shouldRenderContent = (0, import_use_disclosure.useLazyDisclosure)({
enabled: lazy,
isSelected: present,
mode: lazyBehavior,
wasSelected: hasBeenOpened.current
});
const getPopoverProps = (0, import_react.useCallback)(
(props2 = {}, ref = null) => {
var _a, _b;
const popoverProps = {
id,
"aria-describedby": (_a = bodyRef.current) == null ? void 0 : _a.id,
"aria-hidden": !open,
"aria-labelledby": (_b = headerRef.current) == null ? void 0 : _b.id,
role: "dialog",
...props2,
ref: (0, import_utils.mergeRefs)(popoverRef, ref),
style: {
...props2.style,
transformOrigin
},
tabIndex: -1,
onBlur: (0, import_utils.handlerAll)(props2.onBlur, (ev) => {
const relatedTarget = (0, import_utils.getEventRelatedTarget)(ev);
const targetIsPopover = (0, import_utils.isContains)(popoverRef.current, relatedTarget);
const targetIsTrigger = (0, import_utils.isContains)(triggerRef.current, relatedTarget);
const targetIsRelated = (relatedRef == null ? void 0 : relatedRef.current) ? (0, import_utils.isContains)(relatedRef.current, relatedTarget) : false;
const validBlur = !targetIsPopover && !targetIsTrigger && !targetIsRelated;
if (open && closeOnBlur && validBlur) onClose();
}),
onKeyDown: (0, import_utils.handlerAll)(props2.onKeyDown, (ev) => {
if (closeOnEsc && ev.key === "Escape") onClose();
})
};
if (trigger === "hover") {
popoverProps.onMouseEnter = (0, import_utils.handlerAll)(props2.onMouseEnter, () => {
hoveringRef.current = true;
});
popoverProps.onMouseLeave = (0, import_utils.handlerAll)(props2.onMouseLeave, (ev) => {
if (ev.nativeEvent.relatedTarget === null) return;
hoveringRef.current = false;
if (closeOnBlur) setTimeout(onClose, closeDelay);
});
}
return popoverProps;
},
[
closeDelay,
closeOnBlur,
closeOnEsc,
open,
onClose,
transformOrigin,
trigger,
relatedRef,
id
]
);
const maybeReferenceRef = (0, import_react.useCallback)(
(node) => {
if (anchorRef.current == null) referenceRef(node);
},
[referenceRef]
);
const getTriggerProps = (0, import_react.useCallback)(
(props2 = {}, ref = null) => {
const triggerProps = {
"aria-controls": open ? id : void 0,
"aria-expanded": open,
role: "button",
...props2,
ref: (0, import_utils.mergeRefs)(triggerRef, ref, maybeReferenceRef)
};
if (trigger === "click") {
triggerProps.onClick = (0, import_utils.handlerAll)(props2.onClick, onToggle);
triggerProps.onBlur = (0, import_utils.handlerAll)(props2.onBlur, (ev) => {
const relatedTarget = (0, import_utils.getEventRelatedTarget)(ev);
const validBlur = !(0, import_utils.isContains)(popoverRef.current, relatedTarget);
if (open && closeOnBlur && validBlur) onClose();
});
}
if (trigger === "contextmenu") {
triggerProps.onContextMenu = (0, import_utils.handlerAll)(props2.onContextMenu, (ev) => {
ev.preventDefault();
onOpen();
});
triggerProps.onBlur = (0, import_utils.handlerAll)(props2.onBlur, (ev) => {
const relatedTarget = (0, import_utils.getEventRelatedTarget)(ev);
const validBlur = !(0, import_utils.isContains)(popoverRef.current, relatedTarget);
if (open && closeOnBlur && validBlur) onClose();
});
}
if (trigger === "hover") {
triggerProps.onFocus = (0, import_utils.handlerAll)(props2.onFocus, () => {
if (openTimeout.current === void 0) onOpen();
});
triggerProps.onBlur = (0, import_utils.handlerAll)(props2.onBlur, (ev) => {
const relatedTarget = (0, import_utils.getEventRelatedTarget)(ev);
const validBlur = !(0, import_utils.isContains)(popoverRef.current, relatedTarget);
if (open && closeOnBlur && validBlur) onClose();
});
triggerProps.onKeyDown = (0, import_utils.handlerAll)(props2.onKeyDown, (ev) => {
if (ev.key === "Escape") onClose();
});
triggerProps.onMouseEnter = (0, import_utils.handlerAll)(props2.onMouseEnter, () => {
hoveringRef.current = true;
openTimeout.current = window.setTimeout(onOpen, openDelay);
});
triggerProps.onMouseLeave = (0, import_utils.handlerAll)(props2.onMouseLeave, () => {
hoveringRef.current = false;
if (openTimeout.current) {
clearTimeout(openTimeout.current);
openTimeout.current = void 0;
}
closeTimeout.current = window.setTimeout(() => {
if (!hoveringRef.current) onClose();
}, closeDelay);
});
}
return triggerProps;
},
[
closeDelay,
closeOnBlur,
open,
maybeReferenceRef,
onClose,
onOpen,
onToggle,
openDelay,
trigger,
id
]
);
const getAnchorProps = (0, import_react.useCallback)(
(props2 = {}, ref = null) => {
return {
...props2,
ref: (0, import_utils.mergeRefs)(ref, anchorRef, referenceRef)
};
},
[anchorRef, referenceRef]
);
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
PopoverProvider,
{
value: {
id,
animation,
bodyRef,
closeOnButton,
duration,
forceUpdate,
headerRef,
open,
shouldRenderContent,
styles,
getAnchorProps,
getPopoverProps,
getPopperProps,
getTriggerProps,
onAnimationComplete,
onClose
},
children: (0, import_utils.runIfFunc)(children, {
forceUpdate,
open,
onClose
})
}
);
};
Popover.displayName = "Popover";
Popover.__ui__ = "Popover";
// src/popover-close-button.tsx
var import_close_button = require("@yamada-ui/close-button");
var import_core2 = require("@yamada-ui/core");
var import_utils2 = require("@yamada-ui/utils");
var import_jsx_runtime2 = require("react/jsx-runtime");
var PopoverCloseButton = (0, import_core2.forwardRef)(
({ onClick, ...rest }, ref) => {
const { id, styles, onClose } = usePopover();
const css = {
position: "absolute",
...styles.closeButton
};
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
import_close_button.CloseButton,
{
ref,
className: (0, import_utils2.cx)("ui-popover__close-button"),
size: "sm",
"aria-controls": id,
"aria-label": "Close popover",
onClick: (0, import_utils2.handlerAll)(onClick, (ev) => {
ev.stopPropagation();
onClose == null ? void 0 : onClose();
}),
__css: css,
...rest
}
);
}
);
PopoverCloseButton.displayName = "PopoverCloseButton";
PopoverCloseButton.__ui__ = "PopoverCloseButton";
// src/popover-content.tsx
var import_jsx_runtime3 = require("react/jsx-runtime");
var getPopoverContentProps = (animation = "scale", duration) => {
const custom = {
duration,
enter: { visibility: "visible" },
reverse: true,
transitionEnd: { exit: { visibility: "hidden" } }
};
switch (animation) {
case "scale":
return {
...import_transitions.scaleFadeProps,
custom: { ...custom, scale: 0.95 }
};
case "top":
return {
...import_transitions.slideFadeProps,
custom: { ...custom, offsetX: 0, offsetY: -16 }
};
case "right":
return {
...import_transitions.slideFadeProps,
custom: { ...custom, offsetX: 16, offsetY: 0 }
};
case "left":
return {
...import_transitions.slideFadeProps,
custom: { ...custom, offsetX: -16, offsetY: 0 }
};
case "bottom":
return {
...import_transitions.slideFadeProps,
custom: { ...custom, offsetX: 0, offsetY: 16 }
};
}
};
var PopoverContent = (0, import_motion.motionForwardRef)(
({
className,
children,
maxW,
maxWidth = maxW,
minW,
minWidth = minW,
w,
width = w,
z,
zIndex = z,
containerProps,
__css,
...rest
}, ref) => {
var _a, _b, _c, _d, _e;
const {
animation,
closeOnButton,
duration,
open,
shouldRenderContent,
styles,
getPopoverProps,
getPopperProps,
onAnimationComplete
} = usePopover();
if (!shouldRenderContent) return null;
const validChildren = (0, import_utils3.getValidChildren)(children);
const [customPopoverCloseButton, ...cloneChildren] = (0, import_utils3.findChildren)(
validChildren,
PopoverCloseButton
);
const css = (_a = __css != null ? __css : styles.container) != null ? _a : {};
const computedCSS = {
display: "flex",
flexDirection: "column",
outline: 0,
position: "relative",
w: "100%",
...css
};
width != null ? width : width = (_b = css.width) != null ? _b : css.w;
minWidth != null ? minWidth : minWidth = (_c = css.minWidth) != null ? _c : css.minW;
maxWidth != null ? maxWidth : maxWidth = (_d = css.maxWidth) != null ? _d : css.maxW;
zIndex != null ? zIndex : zIndex = (_e = css.zIndex) != null ? _e : css.z;
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
import_core3.ui.div,
{
...getPopperProps({
style: { visibility: open ? "visible" : "hidden" }
}),
className: "ui-popover",
maxWidth,
minWidth,
outline: "none",
width,
zIndex,
...containerProps,
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
import_motion.motion.section,
{
className: (0, import_utils3.cx)("ui-popover__content", className),
...animation !== "none" ? getPopoverContentProps(animation, duration) : {},
...getPopoverProps(rest, ref),
animate: open ? "enter" : "exit",
exit: "exit",
initial: "exit",
onAnimationComplete: (0, import_utils3.funcAll)(
onAnimationComplete,
rest.onAnimationComplete
),
__css: computedCSS,
children: [
customPopoverCloseButton != null ? customPopoverCloseButton : closeOnButton ? /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(PopoverCloseButton, {}) : null,
cloneChildren
]
}
)
}
);
}
);
PopoverContent.displayName = "PopoverContent";
PopoverContent.__ui__ = "PopoverContent";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
PopoverContent
});
//# sourceMappingURL=popover-content.js.map