@yamada-ui/popover
Version:
Yamada UI popover component
336 lines (333 loc) • 11.5 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-close-button.tsx
var popover_close_button_exports = {};
__export(popover_close_button_exports, {
PopoverCloseButton: () => PopoverCloseButton
});
module.exports = __toCommonJS(popover_close_button_exports);
var import_close_button = require("@yamada-ui/close-button");
var import_core2 = require("@yamada-ui/core");
var import_utils2 = 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_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";
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
PopoverCloseButton
});
//# sourceMappingURL=popover-close-button.js.map