1 | import React, { useRef, useReducer, useEffect, useContext, forwardRef, useMemo, useState, useCallback } from 'react';
|
2 | import PropTypes from 'prop-types';
|
3 | import { useId } from '@reach/auto-id';
|
4 | import Popover from '@reach/popover';
|
5 | import { useDescendantsInit, DescendantProvider, useDescendants, useDescendantKeyDown, createDescendantContext, useDescendant } from '@reach/descendants';
|
6 | import { makeId, checkStyles, isFunction, forwardRefWithAs, useForkedRef, wrapEvent, usePrevious, isString, noop, createNamedContext, getOwnerDocument } from '@reach/utils';
|
7 |
|
8 | function _extends() {
|
9 | _extends = Object.assign || function (target) {
|
10 | for (var i = 1; i < arguments.length; i++) {
|
11 | var source = arguments[i];
|
12 |
|
13 | for (var key in source) {
|
14 | if (Object.prototype.hasOwnProperty.call(source, key)) {
|
15 | target[key] = source[key];
|
16 | }
|
17 | }
|
18 | }
|
19 |
|
20 | return target;
|
21 | };
|
22 |
|
23 | return _extends.apply(this, arguments);
|
24 | }
|
25 |
|
26 | function _objectWithoutPropertiesLoose(source, excluded) {
|
27 | if (source == null) return {};
|
28 | var target = {};
|
29 | var sourceKeys = Object.keys(source);
|
30 | var key, i;
|
31 |
|
32 | for (i = 0; i < sourceKeys.length; i++) {
|
33 | key = sourceKeys[i];
|
34 | if (excluded.indexOf(key) >= 0) continue;
|
35 | target[key] = source[key];
|
36 | }
|
37 |
|
38 | return target;
|
39 | }
|
40 |
|
41 |
|
42 |
|
43 | var CLEAR_SELECTION_INDEX = "CLEAR_SELECTION_INDEX";
|
44 | var CLICK_MENU_ITEM = "CLICK_MENU_ITEM";
|
45 | var CLOSE_MENU = "CLOSE_MENU";
|
46 | var OPEN_MENU_AT_FIRST_ITEM = "OPEN_MENU_AT_FIRST_ITEM";
|
47 | var OPEN_MENU_CLEARED = "OPEN_MENU_CLEARED";
|
48 | var SEARCH_FOR_ITEM = "SEARCH_FOR_ITEM";
|
49 | var SELECT_ITEM_AT_INDEX = "SELECT_ITEM_AT_INDEX";
|
50 | var SET_BUTTON_ID = "SET_BUTTON_ID";
|
51 | var MenuDescendantContext = createDescendantContext("MenuDescendantContext");
|
52 | var MenuContext = createNamedContext("MenuContext", {});
|
53 | var initialState = {
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | buttonId: null,
|
59 |
|
60 | isExpanded: false,
|
61 |
|
62 |
|
63 | typeaheadQuery: "",
|
64 |
|
65 |
|
66 | selectionIndex: -1
|
67 | };
|
68 |
|
69 |
|
70 |
|
71 |
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 | var Menu = function Menu(_ref) {
|
78 | var id = _ref.id,
|
79 | children = _ref.children;
|
80 | var buttonRef = useRef(null);
|
81 | var menuRef = useRef(null);
|
82 | var popoverRef = useRef(null);
|
83 |
|
84 | var _useDescendantsInit = useDescendantsInit(),
|
85 | descendants = _useDescendantsInit[0],
|
86 | setDescendants = _useDescendantsInit[1];
|
87 |
|
88 | var _useReducer = useReducer(reducer, initialState),
|
89 | state = _useReducer[0],
|
90 | dispatch = _useReducer[1];
|
91 |
|
92 | var _id = useId(id);
|
93 |
|
94 | var menuId = id || makeId("menu", _id);
|
95 |
|
96 |
|
97 |
|
98 |
|
99 | var buttonClickedRef = useRef(false);
|
100 |
|
101 |
|
102 |
|
103 | var selectCallbacks = useRef([]);
|
104 |
|
105 |
|
106 |
|
107 |
|
108 |
|
109 |
|
110 | var readyToSelect = useRef(false);
|
111 | var context = {
|
112 | buttonRef: buttonRef,
|
113 | dispatch: dispatch,
|
114 | menuId: menuId,
|
115 | menuRef: menuRef,
|
116 | popoverRef: popoverRef,
|
117 | buttonClickedRef: buttonClickedRef,
|
118 | readyToSelect: readyToSelect,
|
119 | selectCallbacks: selectCallbacks,
|
120 | state: state
|
121 | };
|
122 |
|
123 |
|
124 | useEffect(function () {
|
125 | if (state.isExpanded) {
|
126 |
|
127 | window.__REACH_DISABLE_TOOLTIPS = true;
|
128 | window.requestAnimationFrame(function () {
|
129 | focus(menuRef.current);
|
130 | });
|
131 | } else {
|
132 |
|
133 |
|
134 |
|
135 |
|
136 | window.__REACH_DISABLE_TOOLTIPS = false;
|
137 | }
|
138 | }, [state.isExpanded]);
|
139 | useEffect(function () {
|
140 | return checkStyles("menu-button");
|
141 | }, []);
|
142 | return React.createElement(DescendantProvider, {
|
143 | context: MenuDescendantContext,
|
144 | items: descendants,
|
145 | set: setDescendants
|
146 | }, React.createElement(MenuContext.Provider, {
|
147 | value: context
|
148 | }, isFunction(children) ? children({
|
149 | isExpanded: state.isExpanded,
|
150 |
|
151 | isOpen: state.isExpanded
|
152 | }) : children));
|
153 | };
|
154 |
|
155 | if (process.env.NODE_ENV !== "production") {
|
156 | Menu.displayName = "Menu";
|
157 | Menu.propTypes = {
|
158 | children: PropTypes.oneOfType([PropTypes.func, PropTypes.node])
|
159 | };
|
160 | }
|
161 |
|
162 |
|
163 |
|
164 |
|
165 |
|
166 |
|
167 |
|
168 |
|
169 |
|
170 |
|
171 |
|
172 | var MenuButton = forwardRefWithAs(function MenuButton(_ref2, forwardedRef) {
|
173 | var _ref2$as = _ref2.as,
|
174 | Comp = _ref2$as === void 0 ? "button" : _ref2$as,
|
175 | onKeyDown = _ref2.onKeyDown,
|
176 | onMouseDown = _ref2.onMouseDown,
|
177 | id = _ref2.id,
|
178 | props = _objectWithoutPropertiesLoose(_ref2, ["as", "onKeyDown", "onMouseDown", "id"]);
|
179 |
|
180 | var _useContext = useContext(MenuContext),
|
181 | buttonRef = _useContext.buttonRef,
|
182 | buttonClickedRef = _useContext.buttonClickedRef,
|
183 | menuId = _useContext.menuId,
|
184 | _useContext$state = _useContext.state,
|
185 | buttonId = _useContext$state.buttonId,
|
186 | isExpanded = _useContext$state.isExpanded,
|
187 | dispatch = _useContext.dispatch;
|
188 |
|
189 | var ref = useForkedRef(buttonRef, forwardedRef);
|
190 | useEffect(function () {
|
191 | var newButtonId = id != null ? id : menuId ? makeId("menu-button", menuId) : "menu-button";
|
192 |
|
193 | if (buttonId !== newButtonId) {
|
194 | dispatch({
|
195 | type: SET_BUTTON_ID,
|
196 | payload: newButtonId
|
197 | });
|
198 | }
|
199 | }, [buttonId, dispatch, id, menuId]);
|
200 |
|
201 | function handleKeyDown(event) {
|
202 | switch (event.key) {
|
203 | case "ArrowDown":
|
204 | case "ArrowUp":
|
205 | event.preventDefault();
|
206 |
|
207 | dispatch({
|
208 | type: OPEN_MENU_AT_FIRST_ITEM
|
209 | });
|
210 | break;
|
211 |
|
212 | case "Enter":
|
213 | case " ":
|
214 | dispatch({
|
215 | type: OPEN_MENU_AT_FIRST_ITEM
|
216 | });
|
217 | break;
|
218 | }
|
219 | }
|
220 |
|
221 | function handleMouseDown(event) {
|
222 | if (!isExpanded) {
|
223 | buttonClickedRef.current = true;
|
224 | }
|
225 |
|
226 | if (isRightClick(event.nativeEvent)) {
|
227 | return;
|
228 | } else if (isExpanded) {
|
229 | dispatch({
|
230 | type: CLOSE_MENU,
|
231 | payload: {
|
232 | buttonRef: buttonRef
|
233 | }
|
234 | });
|
235 | } else {
|
236 | dispatch({
|
237 | type: OPEN_MENU_CLEARED
|
238 | });
|
239 | }
|
240 | }
|
241 |
|
242 | return React.createElement(Comp
|
243 |
|
244 |
|
245 |
|
246 | , Object.assign({
|
247 | "aria-expanded": isExpanded ? true : undefined,
|
248 | "aria-haspopup": true,
|
249 | "aria-controls": menuId
|
250 | }, props, {
|
251 | ref: ref,
|
252 | "data-reach-menu-button": "",
|
253 | id: buttonId || undefined,
|
254 | onKeyDown: wrapEvent(onKeyDown, handleKeyDown),
|
255 | onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
|
256 | type: "button"
|
257 | }));
|
258 | });
|
259 |
|
260 | if (process.env.NODE_ENV !== "production") {
|
261 | MenuButton.displayName = "MenuButton";
|
262 | MenuButton.propTypes = {
|
263 | children: PropTypes.node
|
264 | };
|
265 | }
|
266 |
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 | var MenuItemImpl = forwardRefWithAs(function MenuItemImpl(_ref3, forwardedRef) {
|
275 | var Comp = _ref3.as,
|
276 | indexProp = _ref3.index,
|
277 | _ref3$isLink = _ref3.isLink,
|
278 | isLink = _ref3$isLink === void 0 ? false : _ref3$isLink,
|
279 | onClick = _ref3.onClick,
|
280 | onDragStart = _ref3.onDragStart,
|
281 | onMouseDown = _ref3.onMouseDown,
|
282 | onMouseEnter = _ref3.onMouseEnter,
|
283 | onMouseLeave = _ref3.onMouseLeave,
|
284 | onMouseMove = _ref3.onMouseMove,
|
285 | onMouseUp = _ref3.onMouseUp,
|
286 | onSelect = _ref3.onSelect,
|
287 | valueTextProp = _ref3.valueText,
|
288 | props = _objectWithoutPropertiesLoose(_ref3, ["as", "index", "isLink", "onClick", "onDragStart", "onMouseDown", "onMouseEnter", "onMouseLeave", "onMouseMove", "onMouseUp", "onSelect", "valueText"]);
|
289 |
|
290 | var _useContext2 = useContext(MenuContext),
|
291 | buttonRef = _useContext2.buttonRef,
|
292 | dispatch = _useContext2.dispatch,
|
293 | readyToSelect = _useContext2.readyToSelect,
|
294 | selectCallbacks = _useContext2.selectCallbacks,
|
295 | _useContext2$state = _useContext2.state,
|
296 | selectionIndex = _useContext2$state.selectionIndex,
|
297 | isExpanded = _useContext2$state.isExpanded;
|
298 |
|
299 | var ownRef = useRef(null);
|
300 |
|
301 |
|
302 |
|
303 | var _useState = useState(valueTextProp || ""),
|
304 | valueText = _useState[0],
|
305 | setValueText = _useState[1];
|
306 |
|
307 | var setValueTextFromDom = useCallback(function (node) {
|
308 | if (node) {
|
309 | ownRef.current = node;
|
310 |
|
311 | if (!valueTextProp || node.textContent && valueText !== node.textContent) {
|
312 | setValueText(node.textContent);
|
313 | }
|
314 | }
|
315 | }, [valueText, valueTextProp]);
|
316 | var ref = useForkedRef(forwardedRef, setValueTextFromDom);
|
317 | var mouseEventStarted = useRef(false);
|
318 | var index = useDescendant({
|
319 | element: ownRef.current,
|
320 | key: valueText,
|
321 | isLink: isLink
|
322 | }, MenuDescendantContext, indexProp);
|
323 | var isSelected = index === selectionIndex;
|
324 |
|
325 | selectCallbacks.current[index] = onSelect;
|
326 |
|
327 | function select() {
|
328 | focus(buttonRef.current);
|
329 | onSelect && onSelect();
|
330 | dispatch({
|
331 | type: CLICK_MENU_ITEM
|
332 | });
|
333 | }
|
334 |
|
335 | function handleClick(event) {
|
336 | if (isLink && !isRightClick(event.nativeEvent)) {
|
337 | select();
|
338 | }
|
339 | }
|
340 |
|
341 | function handleDragStart(event) {
|
342 |
|
343 |
|
344 |
|
345 | if (isLink) {
|
346 | event.preventDefault();
|
347 | }
|
348 | }
|
349 |
|
350 | function handleMouseDown(event) {
|
351 | if (isRightClick(event.nativeEvent)) return;
|
352 |
|
353 | if (isLink) {
|
354 |
|
355 |
|
356 | mouseEventStarted.current = true;
|
357 | } else {
|
358 | event.preventDefault();
|
359 | }
|
360 | }
|
361 |
|
362 | function handleMouseEnter(event) {
|
363 | if (!isSelected && index != null) {
|
364 | dispatch({
|
365 | type: SELECT_ITEM_AT_INDEX,
|
366 | payload: {
|
367 | index: index
|
368 | }
|
369 | });
|
370 | }
|
371 | }
|
372 |
|
373 | function handleMouseLeave(event) {
|
374 |
|
375 | dispatch({
|
376 | type: CLEAR_SELECTION_INDEX
|
377 | });
|
378 | }
|
379 |
|
380 | function handleMouseMove() {
|
381 | readyToSelect.current = true;
|
382 |
|
383 | if (!isSelected && index != null) {
|
384 | dispatch({
|
385 | type: SELECT_ITEM_AT_INDEX,
|
386 | payload: {
|
387 | index: index
|
388 | }
|
389 | });
|
390 | }
|
391 | }
|
392 |
|
393 | function handleMouseUp(event) {
|
394 | if (!readyToSelect.current) {
|
395 | readyToSelect.current = true;
|
396 | return;
|
397 | }
|
398 |
|
399 | if (isRightClick(event.nativeEvent)) return;
|
400 |
|
401 | if (isLink) {
|
402 |
|
403 |
|
404 |
|
405 | if (mouseEventStarted.current) {
|
406 | mouseEventStarted.current = false;
|
407 | } else if (ownRef.current) {
|
408 | ownRef.current.click();
|
409 | }
|
410 | } else {
|
411 | select();
|
412 | }
|
413 | }
|
414 |
|
415 |
|
416 | useEffect(function () {
|
417 | if (!isExpanded) {
|
418 | readyToSelect.current = false;
|
419 | }
|
420 | }, [isExpanded, readyToSelect]);
|
421 |
|
422 |
|
423 | useEffect(function () {
|
424 | var ownerDocument = getOwnerDocument(ownRef.current) || document;
|
425 |
|
426 | var listener = function listener() {
|
427 | return mouseEventStarted.current = false;
|
428 | };
|
429 |
|
430 | ownerDocument.addEventListener("mouseup", listener);
|
431 | return function () {
|
432 | return ownerDocument.removeEventListener("mouseup", listener);
|
433 | };
|
434 | }, []);
|
435 | return React.createElement(Comp, Object.assign({
|
436 | role: "menuitem",
|
437 | id: useMenuItemId(index),
|
438 | tabIndex: -1
|
439 | }, props, {
|
440 | ref: ref,
|
441 | "data-reach-menu-item": "",
|
442 | "data-selected": isSelected ? "" : undefined,
|
443 | "data-valuetext": valueText,
|
444 | onClick: wrapEvent(onClick, handleClick),
|
445 | onDragStart: wrapEvent(onDragStart, handleDragStart),
|
446 | onMouseDown: wrapEvent(onMouseDown, handleMouseDown),
|
447 | onMouseEnter: wrapEvent(onMouseEnter, handleMouseEnter),
|
448 | onMouseLeave: wrapEvent(onMouseLeave, handleMouseLeave),
|
449 | onMouseMove: wrapEvent(onMouseMove, handleMouseMove),
|
450 | onMouseUp: wrapEvent(onMouseUp, handleMouseUp)
|
451 | }));
|
452 | });
|
453 |
|
454 |
|
455 |
|
456 |
|
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 | var MenuItem = forwardRefWithAs(function MenuItem(_ref4, forwardedRef) {
|
463 | var _ref4$as = _ref4.as,
|
464 | as = _ref4$as === void 0 ? "div" : _ref4$as,
|
465 | props = _objectWithoutPropertiesLoose(_ref4, ["as"]);
|
466 |
|
467 | return React.createElement(MenuItemImpl, Object.assign({}, props, {
|
468 | ref: forwardedRef,
|
469 | as: as
|
470 | }));
|
471 | });
|
472 |
|
473 | if (process.env.NODE_ENV !== "production") {
|
474 | MenuItem.displayName = "MenuItem";
|
475 | MenuItem.propTypes = {
|
476 | as: PropTypes.any,
|
477 | onSelect: PropTypes.func.isRequired
|
478 | };
|
479 | }
|
480 |
|
481 |
|
482 |
|
483 |
|
484 |
|
485 |
|
486 |
|
487 |
|
488 |
|
489 |
|
490 |
|
491 |
|
492 | var MenuItems = forwardRefWithAs(function MenuItems(_ref5, forwardedRef) {
|
493 | var _ref5$as = _ref5.as,
|
494 | Comp = _ref5$as === void 0 ? "div" : _ref5$as,
|
495 | children = _ref5.children,
|
496 | id = _ref5.id,
|
497 | onKeyDown = _ref5.onKeyDown,
|
498 | props = _objectWithoutPropertiesLoose(_ref5, ["as", "children", "id", "onKeyDown"]);
|
499 |
|
500 | var _useContext3 = useContext(MenuContext),
|
501 | menuId = _useContext3.menuId,
|
502 | dispatch = _useContext3.dispatch,
|
503 | buttonRef = _useContext3.buttonRef,
|
504 | menuRef = _useContext3.menuRef,
|
505 | selectCallbacks = _useContext3.selectCallbacks,
|
506 | _useContext3$state = _useContext3.state,
|
507 | isExpanded = _useContext3$state.isExpanded,
|
508 | buttonId = _useContext3$state.buttonId,
|
509 | selectionIndex = _useContext3$state.selectionIndex,
|
510 | typeaheadQuery = _useContext3$state.typeaheadQuery;
|
511 |
|
512 | var menuItems = useDescendants(MenuDescendantContext);
|
513 | var ref = useForkedRef(menuRef, forwardedRef);
|
514 | useEffect(function () {
|
515 |
|
516 | var match = findItemFromTypeahead(menuItems, typeaheadQuery);
|
517 |
|
518 | if (typeaheadQuery && match != null) {
|
519 | dispatch({
|
520 | type: SELECT_ITEM_AT_INDEX,
|
521 | payload: {
|
522 | index: match
|
523 | }
|
524 | });
|
525 | }
|
526 |
|
527 | var timeout = window.setTimeout(function () {
|
528 | return typeaheadQuery && dispatch({
|
529 | type: SEARCH_FOR_ITEM,
|
530 | payload: ""
|
531 | });
|
532 | }, 1000);
|
533 | return function () {
|
534 | return window.clearTimeout(timeout);
|
535 | };
|
536 | }, [dispatch, menuItems, typeaheadQuery]);
|
537 | var prevMenuItemsLength = usePrevious(menuItems.length);
|
538 | var prevSelected = usePrevious(menuItems[selectionIndex]);
|
539 | var prevSelectionIndex = usePrevious(selectionIndex);
|
540 | useEffect(function () {
|
541 | if (selectionIndex > menuItems.length - 1) {
|
542 |
|
543 |
|
544 |
|
545 | dispatch({
|
546 | type: SELECT_ITEM_AT_INDEX,
|
547 | payload: {
|
548 | index: menuItems.length - 1
|
549 | }
|
550 | });
|
551 | } else if (
|
552 |
|
553 |
|
554 |
|
555 |
|
556 |
|
557 | prevMenuItemsLength !== menuItems.length && selectionIndex > -1 && prevSelected && prevSelectionIndex === selectionIndex && menuItems[selectionIndex] !== prevSelected) {
|
558 | dispatch({
|
559 | type: SELECT_ITEM_AT_INDEX,
|
560 | payload: {
|
561 | index: menuItems.findIndex(function (i) {
|
562 | return i.key === prevSelected.key;
|
563 | })
|
564 | }
|
565 | });
|
566 | }
|
567 | }, [dispatch, menuItems, prevMenuItemsLength, prevSelected, prevSelectionIndex, selectionIndex]);
|
568 | var handleKeyDown = wrapEvent(function handleKeyDown(event) {
|
569 | var key = event.key;
|
570 |
|
571 | if (!isExpanded) {
|
572 | return;
|
573 | }
|
574 |
|
575 | switch (key) {
|
576 | case "Enter":
|
577 | case " ":
|
578 | var selected = menuItems.find(function (item) {
|
579 | return item.index === selectionIndex;
|
580 | });
|
581 |
|
582 |
|
583 |
|
584 | if (selected) {
|
585 | if (selected.isLink && selected.element) {
|
586 | selected.element.click();
|
587 | } else {
|
588 | event.preventDefault();
|
589 |
|
590 |
|
591 |
|
592 | focus(buttonRef.current);
|
593 | selectCallbacks.current[selected.index] && selectCallbacks.current[selected.index]();
|
594 | dispatch({
|
595 | type: CLICK_MENU_ITEM
|
596 | });
|
597 | }
|
598 | }
|
599 |
|
600 | break;
|
601 |
|
602 | case "Escape":
|
603 | focus(buttonRef.current);
|
604 | dispatch({
|
605 | type: CLOSE_MENU,
|
606 | payload: {
|
607 | buttonRef: buttonRef
|
608 | }
|
609 | });
|
610 | break;
|
611 |
|
612 | case "Tab":
|
613 |
|
614 | event.preventDefault();
|
615 | break;
|
616 |
|
617 | default:
|
618 |
|
619 |
|
620 | if (isString(key) && key.length === 1) {
|
621 | var query = typeaheadQuery + key.toLowerCase();
|
622 | dispatch({
|
623 | type: SEARCH_FOR_ITEM,
|
624 | payload: query
|
625 | });
|
626 | }
|
627 |
|
628 | break;
|
629 | }
|
630 | }, useDescendantKeyDown(MenuDescendantContext, {
|
631 | currentIndex: selectionIndex,
|
632 | orientation: "vertical",
|
633 | rotate: false,
|
634 | callback: function callback(index) {
|
635 | dispatch({
|
636 | type: SELECT_ITEM_AT_INDEX,
|
637 | payload: {
|
638 | index: index
|
639 | }
|
640 | });
|
641 | },
|
642 | key: "index"
|
643 | }));
|
644 | return (
|
645 |
|
646 |
|
647 | React.createElement(Comp
|
648 |
|
649 |
|
650 | , Object.assign({
|
651 | "aria-activedescendant": useMenuItemId(selectionIndex) || undefined,
|
652 | "aria-labelledby": buttonId || undefined,
|
653 |
|
654 |
|
655 |
|
656 | role: "menu",
|
657 | tabIndex: -1
|
658 | }, props, {
|
659 | ref: ref,
|
660 | "data-reach-menu-items": "",
|
661 | id: menuId,
|
662 | onKeyDown: wrapEvent(onKeyDown, handleKeyDown)
|
663 | }), children)
|
664 | );
|
665 | });
|
666 |
|
667 | if (process.env.NODE_ENV !== "production") {
|
668 | MenuItems.displayName = "MenuItems";
|
669 | MenuItems.propTypes = {
|
670 | children: PropTypes.node
|
671 | };
|
672 | }
|
673 |
|
674 |
|
675 |
|
676 |
|
677 |
|
678 |
|
679 |
|
680 |
|
681 |
|
682 |
|
683 |
|
684 |
|
685 |
|
686 |
|
687 | var MenuLink = forwardRefWithAs(function MenuLink(_ref6, forwardedRef) {
|
688 | var _ref6$as = _ref6.as,
|
689 | as = _ref6$as === void 0 ? "a" : _ref6$as,
|
690 | component = _ref6.component,
|
691 | onSelect = _ref6.onSelect,
|
692 | props = _objectWithoutPropertiesLoose(_ref6, ["as", "component", "onSelect"]);
|
693 |
|
694 | if (component) {
|
695 | console.warn("[@reach/menu-button]: Please use the `as` prop instead of `component`.");
|
696 | }
|
697 |
|
698 | return React.createElement("div", {
|
699 | role: "none",
|
700 | tabIndex: -1
|
701 | }, React.createElement(MenuItemImpl, Object.assign({}, props, {
|
702 | ref: forwardedRef,
|
703 | "data-reach-menu-link": "",
|
704 | as: as,
|
705 | isLink: true,
|
706 | onSelect: onSelect || noop
|
707 | })));
|
708 | });
|
709 |
|
710 | if (process.env.NODE_ENV !== "production") {
|
711 | MenuLink.displayName = "MenuLink";
|
712 | MenuLink.propTypes = {
|
713 | as: PropTypes.any,
|
714 | component: PropTypes.any
|
715 | };
|
716 | }
|
717 |
|
718 |
|
719 |
|
720 |
|
721 |
|
722 |
|
723 |
|
724 |
|
725 |
|
726 |
|
727 |
|
728 | var MenuList = forwardRef(function MenuList(_ref7, forwardedRef) {
|
729 | var _ref7$portal = _ref7.portal,
|
730 | portal = _ref7$portal === void 0 ? true : _ref7$portal,
|
731 | props = _objectWithoutPropertiesLoose(_ref7, ["portal"]);
|
732 |
|
733 | return React.createElement(MenuPopover, {
|
734 | portal: portal
|
735 | }, React.createElement(MenuItems, Object.assign({}, props, {
|
736 | ref: forwardedRef,
|
737 | "data-reach-menu-list": ""
|
738 | })));
|
739 | });
|
740 |
|
741 | if (process.env.NODE_ENV !== "production") {
|
742 | MenuList.displayName = "MenuList";
|
743 | MenuList.propTypes = {
|
744 | children: PropTypes.node.isRequired
|
745 | };
|
746 | }
|
747 |
|
748 |
|
749 |
|
750 |
|
751 |
|
752 |
|
753 |
|
754 |
|
755 |
|
756 |
|
757 |
|
758 |
|
759 |
|
760 | var MenuPopover = forwardRef(function MenuPopover(_ref8, forwardedRef) {
|
761 | var children = _ref8.children,
|
762 | _ref8$portal = _ref8.portal,
|
763 | portal = _ref8$portal === void 0 ? true : _ref8$portal,
|
764 | position = _ref8.position,
|
765 | props = _objectWithoutPropertiesLoose(_ref8, ["children", "portal", "position"]);
|
766 |
|
767 | var _useContext4 = useContext(MenuContext),
|
768 | buttonRef = _useContext4.buttonRef,
|
769 | buttonClickedRef = _useContext4.buttonClickedRef,
|
770 | dispatch = _useContext4.dispatch,
|
771 | menuRef = _useContext4.menuRef,
|
772 | popoverRef = _useContext4.popoverRef,
|
773 | isExpanded = _useContext4.state.isExpanded;
|
774 |
|
775 | var ref = useForkedRef(popoverRef, forwardedRef);
|
776 | useEffect(function () {
|
777 | function listener(event) {
|
778 | if (buttonClickedRef.current) {
|
779 | buttonClickedRef.current = false;
|
780 | } else {
|
781 |
|
782 | if (isExpanded && popoverRef.current) {
|
783 | if (!popoverRef.current.contains(event.target)) {
|
784 | dispatch({
|
785 | type: CLOSE_MENU,
|
786 | payload: {
|
787 | buttonRef: buttonRef
|
788 | }
|
789 | });
|
790 | }
|
791 | }
|
792 | }
|
793 | }
|
794 |
|
795 | window.addEventListener("mousedown", listener);
|
796 | return function () {
|
797 | window.removeEventListener("mousedown", listener);
|
798 | };
|
799 | }, [buttonClickedRef, buttonRef, dispatch, isExpanded, menuRef, popoverRef]);
|
800 |
|
801 | var commonProps = _extends({
|
802 | ref: ref,
|
803 |
|
804 | "data-reach-menu": "",
|
805 | "data-reach-menu-popover": "",
|
806 | hidden: !isExpanded,
|
807 | children: children
|
808 | }, props);
|
809 |
|
810 | return portal ? React.createElement(Popover, Object.assign({}, commonProps, {
|
811 | targetRef: buttonRef,
|
812 | position: position
|
813 | })) : React.createElement("div", Object.assign({}, commonProps));
|
814 | });
|
815 |
|
816 | if (process.env.NODE_ENV !== "production") {
|
817 | MenuPopover.displayName = "MenuPopover";
|
818 | MenuPopover.propTypes = {
|
819 | children: PropTypes.node
|
820 | };
|
821 | }
|
822 |
|
823 |
|
824 |
|
825 |
|
826 |
|
827 |
|
828 |
|
829 |
|
830 | function useMenuButtonContext() {
|
831 | var _useContext5 = useContext(MenuContext),
|
832 | isExpanded = _useContext5.state.isExpanded;
|
833 |
|
834 | return useMemo(function () {
|
835 | return {
|
836 | isExpanded: isExpanded
|
837 | };
|
838 | }, [isExpanded]);
|
839 | }
|
840 |
|
841 |
|
842 |
|
843 |
|
844 |
|
845 |
|
846 |
|
847 | function findItemFromTypeahead(items, string) {
|
848 | if (string === void 0) {
|
849 | string = "";
|
850 | }
|
851 |
|
852 | if (!string) {
|
853 | return null;
|
854 | }
|
855 |
|
856 | var found = items.find(function (_ref9) {
|
857 | var _element$dataset, _element$dataset$valu;
|
858 |
|
859 | var element = _ref9.element;
|
860 | return element === null || element === void 0 ? void 0 : (_element$dataset = element.dataset) === null || _element$dataset === void 0 ? void 0 : (_element$dataset$valu = _element$dataset.valuetext) === null || _element$dataset$valu === void 0 ? void 0 : _element$dataset$valu.toLowerCase().startsWith(string);
|
861 | });
|
862 | return found ? items.indexOf(found) : null;
|
863 | }
|
864 |
|
865 | function useMenuItemId(index) {
|
866 | var _useContext6 = useContext(MenuContext),
|
867 | menuId = _useContext6.menuId;
|
868 |
|
869 | return index != null && index > -1 ? makeId("option-" + index, menuId) : undefined;
|
870 | }
|
871 |
|
872 | function isRightClick(nativeEvent) {
|
873 | return nativeEvent.which === 3 || nativeEvent.button === 2;
|
874 | }
|
875 |
|
876 | function focus(element) {
|
877 | element && element.focus();
|
878 | }
|
879 |
|
880 | function reducer(state, action) {
|
881 | if (action === void 0) {
|
882 | action = {};
|
883 | }
|
884 |
|
885 | switch (action.type) {
|
886 | case CLICK_MENU_ITEM:
|
887 | return _extends({}, state, {
|
888 | isExpanded: false,
|
889 | selectionIndex: -1
|
890 | });
|
891 |
|
892 | case CLOSE_MENU:
|
893 | return _extends({}, state, {
|
894 | isExpanded: false,
|
895 | selectionIndex: -1
|
896 | });
|
897 |
|
898 | case OPEN_MENU_AT_FIRST_ITEM:
|
899 | return _extends({}, state, {
|
900 | isExpanded: true,
|
901 | selectionIndex: 0
|
902 | });
|
903 |
|
904 | case OPEN_MENU_CLEARED:
|
905 | return _extends({}, state, {
|
906 | isExpanded: true,
|
907 | selectionIndex: -1
|
908 | });
|
909 |
|
910 | case SELECT_ITEM_AT_INDEX:
|
911 | if (action.payload.index >= 0) {
|
912 | return _extends({}, state, {
|
913 | selectionIndex: action.payload.max != null ? Math.min(Math.max(action.payload.index, 0), action.payload.max) : Math.max(action.payload.index, 0)
|
914 | });
|
915 | }
|
916 |
|
917 | return state;
|
918 |
|
919 | case CLEAR_SELECTION_INDEX:
|
920 | return _extends({}, state, {
|
921 | selectionIndex: -1
|
922 | });
|
923 |
|
924 | case SET_BUTTON_ID:
|
925 | return _extends({}, state, {
|
926 | buttonId: action.payload
|
927 | });
|
928 |
|
929 | case SEARCH_FOR_ITEM:
|
930 | if (typeof action.payload !== "undefined") {
|
931 | return _extends({}, state, {
|
932 | typeaheadQuery: action.payload
|
933 | });
|
934 | }
|
935 |
|
936 | return state;
|
937 |
|
938 | default:
|
939 | return state;
|
940 | }
|
941 | }
|
942 |
|
943 | export { Menu, MenuButton, MenuItem, MenuItems, MenuLink, MenuList, MenuPopover, useMenuButtonContext };
|
944 |
|