@atlaskit/dropdown-menu
Version:
A dropdown menu displays a list of actions or options to a user.
71 lines (70 loc) • 2.53 kB
JavaScript
import _slicedToArray from "@babel/runtime/helpers/slicedToArray";
import React, { useCallback, useEffect, useRef, useState } from 'react';
import { bind } from 'bind-event-listener';
import { useLayering } from '@atlaskit/layering/use-layering';
import handleFocus from '../utils/handle-focus';
import { FocusManagerContext } from './focus-manager-context';
/**
* Focus manager logic.
*/
var FocusManager = function FocusManager(_ref) {
var children = _ref.children,
onClose = _ref.onClose;
var menuItemRefs = useRef([]);
// Used to force a re-render only
var _useState = useState(0),
_useState2 = _slicedToArray(_useState, 2),
refresh = _useState2[0],
setRefresh = _useState2[1];
var registerMode = useRef('ordered');
registerMode.current = 'ordered';
var registerRef = useCallback(function (ref) {
if (menuItemRefs.current.includes(ref)) {
return;
}
switch (registerMode.current) {
case 'ordered':
menuItemRefs.current.push(ref);
break;
case 'unordered':
// Reset and force a rerender
registerMode.current = 'regenerate';
menuItemRefs.current = [];
setRefresh(refresh + 1);
break;
case 'regenerate':
// Ignore registrations until the next render cycle
break;
default:
throw new Error("Unexpected case of ".concat(registerMode.current));
}
},
// Updating register ref on force reload will cause `useRegisterItemWithFocusManager` to re-register
[refresh]);
var _useLayering = useLayering(),
isLayerDisabled = _useLayering.isLayerDisabled,
currentLevel = _useLayering.currentLevel;
// Root menu (from a button) is at level 1; first submenu is at level 2. ARIA: Left only closes submenus.
var isNestedMenu = currentLevel > 1;
// Intentionally rebinding on each render
useEffect(function () {
if (registerMode.current === 'ordered') {
// Use effect is called after rendering is complete and useEffects of the children a called first
registerMode.current = 'unordered';
}
});
useEffect(function () {
return bind(window, {
type: 'keydown',
listener: handleFocus(menuItemRefs, isLayerDisabled, onClose, isNestedMenu)
});
}, [isLayerDisabled, onClose, isNestedMenu]);
var contextValue = {
menuItemRefs: menuItemRefs.current,
registerRef: registerRef
};
return /*#__PURE__*/React.createElement(FocusManagerContext.Provider, {
value: contextValue
}, children);
};
export default FocusManager;