@atlaskit/dropdown-menu
Version:
A dropdown menu displays a list of actions or options to a user.
101 lines (99 loc) • 3.52 kB
JavaScript
/* menu-wrapper.tsx generated by @compiled/babel-plugin v0.36.1 */
import "./menu-wrapper.compiled.css";
import * as React from 'react';
import { ax, ix } from "@compiled/react/runtime";
import { useContext, useEffect, useLayoutEffect } from 'react';
import MenuGroup from '@atlaskit/menu/menu-group';
import { Box } from '@atlaskit/primitives/compiled';
import Spinner from '@atlaskit/spinner';
import isCheckboxItem from '../utils/is-checkbox-item';
import isRadioItem from '../utils/is-radio-item';
import { FocusManagerContext } from './focus-manager';
const styles = {
spinnerContainer: "_1e0c1txw _1ul91lit _1bah1h6o _ca0qv47k _u5f3v47k _n3tdv47k _19bvv47k"
};
const LoadingIndicator = ({
statusLabel = 'Loading',
testId
}) => /*#__PURE__*/React.createElement(Box, {
xcss: styles.spinnerContainer,
role: "menuitem"
}, /*#__PURE__*/React.createElement(Spinner, {
size: "small",
label: statusLabel,
testId: testId
}));
/**
*
* MenuWrapper wraps all the menu items.
* It handles the logic to close the menu when a MenuItem is clicked, but leaves it open
* if a CheckboxItem or RadioItem is clicked.
* It also sets focus to the first menu item when opened.
*/
const MenuWrapper = ({
children,
isLoading,
maxHeight,
maxWidth,
onClose,
onUpdate,
statusLabel,
setInitialFocusRef,
shouldRenderToParent,
spacing,
testId,
isTriggeredUsingKeyboard,
autoFocus
}) => {
const {
menuItemRefs
} = useContext(FocusManagerContext);
const closeOnMenuItemClick = e => {
const isTargetMenuItemOrDescendant = menuItemRefs.some(menuItemRef => {
const {
current: menuItem
} = menuItemRef;
if (!menuItem) {
return false;
}
const isCheckboxOrRadio = isCheckboxItem(menuItem) || isRadioItem(menuItem);
return menuItem.contains(e.target) && !isCheckboxOrRadio;
});
// Close menu if the click is triggered from a MenuItem or
// its descendant. Don't close the menu if the click is triggered
// from a MenuItemRadio or MenuItemCheckbox so that the user can
// select multiple items.
if (isTargetMenuItemOrDescendant && onClose) {
onClose(e);
}
};
// Using useEffect here causes a flicker.
// useLayoutEffect ensures that the update and render happen in the same
// rAF tick.
useLayoutEffect(() => {
onUpdate();
}, [isLoading, onUpdate]);
useEffect(() => {
var _menuItemRefs$map$fin;
const firstFocusableRef = (_menuItemRefs$map$fin = menuItemRefs.map(({
current
}) => current).find(el => !!el && !el.hasAttribute('disabled'))) !== null && _menuItemRefs$map$fin !== void 0 ? _menuItemRefs$map$fin : null;
if (shouldRenderToParent && (isTriggeredUsingKeyboard || autoFocus)) {
firstFocusableRef === null || firstFocusableRef === void 0 ? void 0 : firstFocusableRef.focus();
}
setInitialFocusRef === null || setInitialFocusRef === void 0 ? void 0 : setInitialFocusRef(firstFocusableRef);
}, [menuItemRefs, setInitialFocusRef, autoFocus, shouldRenderToParent, isTriggeredUsingKeyboard]);
return /*#__PURE__*/React.createElement(MenuGroup, {
isLoading: isLoading,
maxHeight: maxHeight,
maxWidth: maxWidth,
onClick: closeOnMenuItemClick,
role: "menu",
spacing: spacing,
testId: testId && `${testId}--menu-group`
}, isLoading ? /*#__PURE__*/React.createElement(LoadingIndicator, {
statusLabel: statusLabel,
testId: testId && `${testId}--loading-indicator`
}) : children);
};
export default MenuWrapper;