import _objectWithoutPropertiesLoose from "@babel/runtime/helpers/esm/objectWithoutPropertiesLoose"; import _extends from "@babel/runtime/helpers/esm/extends"; import PropTypes from 'prop-types'; import React, { useContext, useRef } from 'react'; import useCallbackRef from '@restart/hooks/useCallbackRef'; import DropdownContext from './DropdownContext'; import usePopper from './usePopper'; import useRootClose from './useRootClose'; import mergeOptionsWithPopperConfig from './mergeOptionsWithPopperConfig'; var noop = function noop() {}; /** * @memberOf Dropdown * @param {object} options * @param {boolean} options.flip Automatically adjust the menu `drop` position based on viewport edge detection * @param {[number, number]} options.offset Define an offset distance between the Menu and the Toggle * @param {boolean} options.show Display the menu manually, ignored in the context of a `Dropdown` * @param {boolean} options.usePopper opt in/out of using PopperJS to position menus. When disabled you must position it yourself. * @param {string} options.rootCloseEvent The pointer event to listen for when determining "clicks outside" the menu for triggering a close. * @param {object} options.popperConfig Options passed to the [`usePopper`](/api/usePopper) hook. */ export function useDropdownMenu(options) { if (options === void 0) { options = {}; } var context = useContext(DropdownContext); var _useCallbackRef = useCallbackRef(), arrowElement = _useCallbackRef[0], attachArrowRef = _useCallbackRef[1]; var hasShownRef = useRef(false); var _options = options, flip = _options.flip, offset = _options.offset, rootCloseEvent = _options.rootCloseEvent, _options$fixed = _options.fixed, fixed = _options$fixed === void 0 ? false : _options$fixed, _options$popperConfig = _options.popperConfig, popperConfig = _options$popperConfig === void 0 ? {} : _options$popperConfig, _options$usePopper = _options.usePopper, shouldUsePopper = _options$usePopper === void 0 ? !!context : _options$usePopper; var show = (context == null ? void 0 : context.show) == null ? !!options.show : context.show; var alignEnd = (context == null ? void 0 : context.alignEnd) == null ? options.alignEnd : context.alignEnd; if (show && !hasShownRef.current) { hasShownRef.current = true; } var handleClose = function handleClose(e) { context == null ? void 0 : context.toggle(false, e); }; var _ref = context || {}, drop = _ref.drop, setMenu = _ref.setMenu, menuElement = _ref.menuElement, toggleElement = _ref.toggleElement; var placement = alignEnd ? 'bottom-end' : 'bottom-start'; if (drop === 'up') placement = alignEnd ? 'top-end' : 'top-start';else if (drop === 'right') placement = alignEnd ? 'right-end' : 'right-start';else if (drop === 'left') placement = alignEnd ? 'left-end' : 'left-start'; var popper = usePopper(toggleElement, menuElement, mergeOptionsWithPopperConfig({ placement: placement, enabled: !!(shouldUsePopper && show), enableEvents: show, offset: offset, flip: flip, fixed: fixed, arrowElement: arrowElement, popperConfig: popperConfig })); var menuProps = _extends({ ref: setMenu || noop, 'aria-labelledby': toggleElement == null ? void 0 : toggleElement.id }, popper.attributes.popper, { style: popper.styles.popper }); var metadata = { show: show, alignEnd: alignEnd, hasShown: hasShownRef.current, toggle: context == null ? void 0 : context.toggle, popper: shouldUsePopper ? popper : null, arrowProps: shouldUsePopper ? _extends({ ref: attachArrowRef }, popper.attributes.arrow, { style: popper.styles.arrow }) : {} }; useRootClose(menuElement, handleClose, { clickTrigger: rootCloseEvent, disabled: !show }); return [menuProps, metadata]; } var propTypes = { /** * A render prop that returns a Menu element. The `props` * argument should spread through to **a component that can accept a ref**. * * @type {Function ({ * show: boolean, * alignEnd: boolean, * close: (?SyntheticEvent) => void, * placement: Placement, * update: () => void, * forceUpdate: () => void, * props: { * ref: (?HTMLElement) => void, * style: { [string]: string | number }, * aria-labelledby: ?string * }, * arrowProps: { * ref: (?HTMLElement) => void, * style: { [string]: string | number }, * }, * }) => React.Element} */ children: PropTypes.func.isRequired, /** * Controls the visible state of the menu, generally this is * provided by the parent `Dropdown` component, * but may also be specified as a prop directly. */ show: PropTypes.bool, /** * Aligns the dropdown menu to the 'end' of it's placement position. * Generally this is provided by the parent `Dropdown` component, * but may also be specified as a prop directly. */ alignEnd: PropTypes.bool, /** * Enables the Popper.js `flip` modifier, allowing the Dropdown to * automatically adjust it's placement in case of overlap with the viewport or toggle. * Refer to the [flip docs](https://popper.js.org/popper-documentation.html#modifiers..flip.enabled) for more info */ flip: PropTypes.bool, usePopper: PropTypes.oneOf([true, false]), /** * A set of popper options and props passed directly to react-popper's Popper component. */ popperConfig: PropTypes.object, /** * Override the default event used by RootCloseWrapper. */ rootCloseEvent: PropTypes.string }; var defaultProps = { usePopper: true }; /** * Also exported as `` from `Dropdown`. * * @displayName DropdownMenu * @memberOf Dropdown */ function DropdownMenu(_ref2) { var children = _ref2.children, options = _objectWithoutPropertiesLoose(_ref2, ["children"]); var _useDropdownMenu = useDropdownMenu(options), props = _useDropdownMenu[0], meta = _useDropdownMenu[1]; return /*#__PURE__*/React.createElement(React.Fragment, null, meta.hasShown ? children(props, meta) : null); } DropdownMenu.displayName = 'ReactOverlaysDropdownMenu'; DropdownMenu.propTypes = propTypes; DropdownMenu.defaultProps = defaultProps; /** @component */ export default DropdownMenu;