UNPKG

7.26 kBJavaScriptView Raw
1"use strict";
2
3var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");
4
5var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
6
7exports.__esModule = true;
8exports.useDropdownMenu = useDropdownMenu;
9exports["default"] = void 0;
10
11var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));
12
13var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
14
15var _propTypes = _interopRequireDefault(require("prop-types"));
16
17var _react = _interopRequireWildcard(require("react"));
18
19var _useCallbackRef2 = _interopRequireDefault(require("@restart/hooks/useCallbackRef"));
20
21var _DropdownContext = _interopRequireDefault(require("./DropdownContext"));
22
23var _usePopper = _interopRequireWildcard(require("./usePopper"));
24
25var _useRootClose = _interopRequireDefault(require("./useRootClose"));
26
27var noop = function noop() {};
28/**
29 * @memberOf Dropdown
30 * @param {object} options
31 * @param {boolean} options.flip Automatically adjust the menu `drop` position based on viewport edge detection
32 * @param {boolean} options.show Display the menu manually, ignored in the context of a `Dropdown`
33 * @param {boolean} options.usePopper opt in/out of using PopperJS to position menus. When disabled you must position it yourself.
34 * @param {string} options.rootCloseEvent The pointer event to listen for when determining "clicks outside" the menu for triggering a close.
35 * @param {object} options.popperConfig Options passed to the [`usePopper`](/api/usePopper) hook.
36 */
37
38
39function useDropdownMenu(options) {
40 var _modifiers$arrow;
41
42 if (options === void 0) {
43 options = {};
44 }
45
46 var context = (0, _react.useContext)(_DropdownContext["default"]);
47
48 var _useCallbackRef = (0, _useCallbackRef2["default"])(),
49 arrowElement = _useCallbackRef[0],
50 attachArrowRef = _useCallbackRef[1];
51
52 var hasShownRef = (0, _react.useRef)(false);
53 var _options = options,
54 flip = _options.flip,
55 rootCloseEvent = _options.rootCloseEvent,
56 _options$popperConfig = _options.popperConfig,
57 popperConfig = _options$popperConfig === void 0 ? {} : _options$popperConfig,
58 _options$usePopper = _options.usePopper,
59 shouldUsePopper = _options$usePopper === void 0 ? !!context : _options$usePopper;
60 var show = (context == null ? void 0 : context.show) == null ? options.show : context.show;
61 var alignEnd = (context == null ? void 0 : context.alignEnd) == null ? options.alignEnd : context.alignEnd;
62
63 if (show && !hasShownRef.current) {
64 hasShownRef.current = true;
65 }
66
67 var handleClose = function handleClose(e) {
68 context == null ? void 0 : context.toggle(false, e);
69 };
70
71 var _ref = context || {},
72 drop = _ref.drop,
73 setMenu = _ref.setMenu,
74 menuElement = _ref.menuElement,
75 toggleElement = _ref.toggleElement;
76
77 var placement = alignEnd ? 'bottom-end' : 'bottom-start';
78 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';
79 var modifiers = (0, _usePopper.toModifierMap)(popperConfig.modifiers);
80 var popper = (0, _usePopper["default"])(toggleElement, menuElement, (0, _extends2["default"])({}, popperConfig, {
81 placement: placement,
82 enabled: !!(shouldUsePopper && show),
83 modifiers: (0, _extends2["default"])({}, modifiers, {
84 eventListeners: {
85 enabled: !!show
86 },
87 arrow: (0, _extends2["default"])({}, modifiers.arrow, {
88 enabled: !!arrowElement,
89 options: (0, _extends2["default"])({}, (_modifiers$arrow = modifiers.arrow) == null ? void 0 : _modifiers$arrow.options, {
90 element: arrowElement
91 })
92 }),
93 flip: (0, _extends2["default"])({
94 enabled: !!flip
95 }, modifiers.flip)
96 })
97 }));
98 var menu;
99 var menuProps = {
100 ref: setMenu || noop,
101 'aria-labelledby': toggleElement == null ? void 0 : toggleElement.id
102 };
103 var childArgs = {
104 show: show,
105 alignEnd: alignEnd,
106 hasShown: hasShownRef.current,
107 close: handleClose
108 };
109
110 if (!shouldUsePopper) {
111 menu = (0, _extends2["default"])({}, childArgs, {
112 props: menuProps
113 });
114 } else {
115 menu = (0, _extends2["default"])({}, popper, {}, childArgs, {
116 props: (0, _extends2["default"])({}, menuProps, {
117 style: popper.styles
118 }),
119 arrowProps: {
120 ref: attachArrowRef,
121 style: popper.arrowStyles
122 }
123 });
124 }
125
126 (0, _useRootClose["default"])(menuElement, handleClose, {
127 clickTrigger: rootCloseEvent,
128 disabled: !(menu && show)
129 });
130 return menu;
131}
132
133var propTypes = {
134 /**
135 * A render prop that returns a Menu element. The `props`
136 * argument should spread through to **a component that can accept a ref**.
137 *
138 * @type {Function ({
139 * show: boolean,
140 * alignEnd: boolean,
141 * close: (?SyntheticEvent) => void,
142 * placement: Placement,
143 * outOfBoundaries: ?boolean,
144 * scheduleUpdate: () => void,
145 * props: {
146 * ref: (?HTMLElement) => void,
147 * style: { [string]: string | number },
148 * aria-labelledby: ?string
149 * },
150 * arrowProps: {
151 * ref: (?HTMLElement) => void,
152 * style: { [string]: string | number },
153 * },
154 * }) => React.Element}
155 */
156 children: _propTypes["default"].func.isRequired,
157
158 /**
159 * Controls the visible state of the menu, generally this is
160 * provided by the parent `Dropdown` component,
161 * but may also be specified as a prop directly.
162 */
163 show: _propTypes["default"].bool,
164
165 /**
166 * Aligns the dropdown menu to the 'end' of it's placement position.
167 * Generally this is provided by the parent `Dropdown` component,
168 * but may also be specified as a prop directly.
169 */
170 alignEnd: _propTypes["default"].bool,
171
172 /**
173 * Enables the Popper.js `flip` modifier, allowing the Dropdown to
174 * automatically adjust it's placement in case of overlap with the viewport or toggle.
175 * Refer to the [flip docs](https://popper.js.org/popper-documentation.html#modifiers..flip.enabled) for more info
176 */
177 flip: _propTypes["default"].bool,
178 usePopper: _propTypes["default"].oneOf([true, false]),
179
180 /**
181 * A set of popper options and props passed directly to react-popper's Popper component.
182 */
183 popperConfig: _propTypes["default"].object,
184
185 /**
186 * Override the default event used by RootCloseWrapper.
187 */
188 rootCloseEvent: _propTypes["default"].string
189};
190var defaultProps = {
191 usePopper: true
192};
193
194/**
195 * Also exported as `<Dropdown.Menu>` from `Dropdown`.
196 *
197 * @displayName DropdownMenu
198 * @memberOf Dropdown
199 */
200function DropdownMenu(_ref2) {
201 var children = _ref2.children,
202 options = (0, _objectWithoutPropertiesLoose2["default"])(_ref2, ["children"]);
203 var args = useDropdownMenu(options);
204 return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, args.hasShown ? children(args) : null);
205}
206
207DropdownMenu.displayName = 'ReactOverlaysDropdownMenu';
208DropdownMenu.propTypes = propTypes;
209DropdownMenu.defaultProps = defaultProps;
210/** @component */
211
212var _default = DropdownMenu;
213exports["default"] = _default;
\No newline at end of file