chakra-ui
Version:
Responsive and accessible React UI components built with React and Emotion
153 lines (140 loc) • 5.52 kB
JavaScript
import _extends from "@babel/runtime/helpers/extends";
import _objectWithoutProperties from "@babel/runtime/helpers/objectWithoutProperties";
/** @jsx jsx */
import { jsx } from "@emotion/core";
import Portal from "@reach/portal";
import { oneOf } from "prop-types";
import { cloneElement, useEffect, useRef, Fragment } from "react";
import FocusLock from "react-focus-lock";
import { Manager, Popper, Reference } from "react-popper";
import { PopoverTransition, PopoverContent, PopoverCloseButton } from "./components";
import { assignRef, genId } from "../utils";
import { useUIMode } from "../ThemeProvider";
import Box from "../Box";
import useDisclosure from "../useDisclosure";
var Popover = function Popover(_ref) {
var controlledIsOpen = _ref.isOpen,
defaultOpen = _ref.defaultOpen,
_ref$maxWidth = _ref.maxWidth,
maxWidth = _ref$maxWidth === void 0 ? "xs" : _ref$maxWidth,
trigger = _ref.trigger,
gutter = _ref.gutter,
placement = _ref.placement,
children = _ref.children,
showArrow = _ref.showArrow,
showCloseButton = _ref.showCloseButton,
initialFocusRef = _ref.initialFocusRef,
_ref$usePortal = _ref.usePortal,
usePortal = _ref$usePortal === void 0 ? true : _ref$usePortal,
onOpenChange = _ref.onOpenChange,
_ref$trapFocus = _ref.trapFocus,
trapFocus = _ref$trapFocus === void 0 ? false : _ref$trapFocus,
closeOnBlur = _ref.closeOnBlur,
_ref$closeOnEsc = _ref.closeOnEsc,
closeOnEsc = _ref$closeOnEsc === void 0 ? true : _ref$closeOnEsc,
rest = _objectWithoutProperties(_ref, ["isOpen", "defaultOpen", "maxWidth", "trigger", "gutter", "placement", "children", "showArrow", "showCloseButton", "initialFocusRef", "usePortal", "onOpenChange", "trapFocus", "closeOnBlur", "closeOnEsc"]);
var _useDisclosure = useDisclosure(defaultOpen),
isOpen = _useDisclosure.isOpen,
onClose = _useDisclosure.onClose,
onToggle = _useDisclosure.onToggle;
var triggerRef = useRef();
var popperRef = useRef();
useEffect(function () {
onOpenChange && onOpenChange();
}, [isOpen, onOpenChange]);
var handleClick = function handleClick() {
onToggle();
};
/* Close on outside click and blur for the Menu */
var handleBlur = function handleBlur(event) {
if (!trapFocus && isOpen && popperRef.current && triggerRef.current && !popperRef.current.contains(event.relatedTarget) && !triggerRef.current.contains(event.relatedTarget)) {
closeOnBlur && onClose();
}
};
var _useUIMode = useUIMode(),
mode = _useUIMode.mode;
var _bgColor = mode === "light" ? "white" : "gray.700";
var _color = mode === "light" ? "gray.900" : "whiteAlpha.900";
var bg = rest.bg || rest.background || rest.backgroundColor || _bgColor;
var color = rest.color || _color;
var popoverId = genId("popper");
var Wrapper = usePortal ? Portal : Fragment;
return jsx(Manager, null, jsx(Reference, null, function (_ref2) {
var referenceRef = _ref2.ref;
return cloneElement(trigger, {
"aria-haspopup": "true",
"aria-controls": popoverId,
ref: function ref(node) {
triggerRef.current = node;
assignRef(referenceRef, node);
},
onClick: function onClick(event) {
handleClick();
trigger.props.onClick && trigger.props.onClick(event);
}
});
}), jsx(Wrapper, null, jsx(Popper, {
placement: placement
}, function (_ref3) {
var _ref4 = _ref3.ref,
popperStyle = _ref3.style,
placement = _ref3.placement,
arrowProps = _ref3.arrowProps;
return jsx(PopoverTransition, {
duration: 100,
isOpen: isOpen
}, function (styles) {
return jsx(FocusLock, {
returnFocus: true,
onActivation: function onActivation() {
if (initialFocusRef && initialFocusRef.current) {
initialFocusRef.current.focus();
}
}
}, jsx(PopoverContent, _extends({
ref: function ref(node) {
popperRef.current = node;
assignRef(_ref4, node);
},
bg: bg,
color: color,
maxWidth: maxWidth,
"data-placement": placement,
borderRadius: "lg",
boxShadow: "lg",
id: popoverId,
"aria-hidden": isOpen
}, rest, {
tabIndex: "-1",
onBlur: handleBlur,
css: _extends({}, popperStyle, {
transform: "".concat(popperStyle.transform, " scale(").concat(styles.scale, ")"),
opacity: styles.opacity
}),
onKeyDown: function onKeyDown(event) {
event.stopPropagation();
if (event.key === "Escape" && closeOnEsc) {
onClose && onClose();
}
}
}), showCloseButton && jsx(PopoverCloseButton, {
onClick: onClose
}), typeof children === "function" ? children({
isOpen: isOpen,
onClose: onClose
}) : children, showArrow && jsx(Box, {
borderColor: bg,
"data-arrow": "",
ref: arrowProps.ref,
css: arrowProps.style
})));
});
})));
};
export var placementOptions = ["left", "right", "bottom", "auto", "top", "right-end", "right-start", "left-end", "left-start", "bottom-end", "bottom-start", "top-end", "top-start", "auto-start", "auto-end"];
process.env.NODE_ENV !== "production" ? Popover.propTypes = {
interaction: oneOf(["hover", "click"]),
placement: oneOf(placementOptions)
} : void 0;
export default Popover;
export * from "./components";