@momentum-ui/react-collaboration
Version:
Cisco Momentum UI Framework for React Collaboration Applications
105 lines • 5.44 kB
JavaScript
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
import React, { forwardRef, useContext, useRef, useCallback } from 'react';
import classnames from 'classnames';
import { STYLE, DEFAULTS } from './Menu.constants';
import './Menu.style.scss';
import { useMenu } from '@react-aria/menu';
import { useTreeState } from '@react-stately/tree';
import MenuItem from '../MenuItem';
import { mergeProps } from '@react-aria/utils';
import MenuSection from '../MenuSection';
import MenuSelectionGroup from '../MenuSelectionGroup';
import ContentSeparator from '../ContentSeparator';
import { defaults } from 'lodash';
import { ListContext } from '../List/List.utils';
import { useCheckAriaLabel } from '../../utils/a11y';
export var MenuContext = React.createContext({});
export function useMenuContext(props) {
if (props === void 0) { props = {}; }
var context = useContext(MenuContext);
return defaults({}, props, context);
}
export var MenuAppearanceContext = React.createContext({});
export function useMenuAppearanceContext(props) {
if (props === void 0) { props = {}; }
var menuAppearance = useContext(MenuAppearanceContext);
return defaults({}, props, menuAppearance);
}
var Menu = function (props, providedRef) {
var className = props.className, classNameSelectedItem = props.classNameSelectedItem, id = props.id, style = props.style, _a = props.tickPosition, tickPosition = _a === void 0 ? DEFAULTS.TICK_POSITION : _a, _b = props.itemShape, itemShape = _b === void 0 ? DEFAULTS.ITEM_SHAPE : _b, _c = props.itemSize, itemSize = _c === void 0 ? DEFAULTS.ITEM_SIZE : _c, shouldItemFocusBeInset = props.shouldItemFocusBeInset;
var contextProps = useMenuContext();
// if an explicit aria-label is provided, discard the auto aria-labelledby provided by MenuTrigger
if (contextProps['aria-labelledby'] && props['aria-label']) {
delete contextProps['aria-labelledby'];
}
var _props = __assign({}, mergeProps(contextProps, props));
var state = useTreeState(__assign({}, _props));
var internalRef = useRef();
var ref = providedRef || internalRef;
var itemArray = Array.from(state.collection.getKeys());
// Ensure all separators are in the disabledKeys set so they are not interactable
// This may need copying instead of modifying due to how React works
itemArray.forEach(function (key) {
var _a;
var item = state.collection.getItem(key);
if ((_a = item.props) === null || _a === void 0 ? void 0 : _a._isSeparator) {
state.disabledKeys.add(key);
}
});
var menuProps = useMenu(_props, state, ref).menuProps;
var renderItem = useCallback(function (item, state) {
var _a, _b;
if (item.type === 'section') {
if ((_a = item.props) === null || _a === void 0 ? void 0 : _a.selectionGroup) {
return (React.createElement(MenuSelectionGroup, __assign({ item: item, state: state, onAction: _props.onAction, key: item.key }, item.props)));
}
return React.createElement(MenuSection, { key: item.key, item: item, state: state, onAction: _props.onAction });
}
else {
// collection.getKeys() return all keys (including sub-keys of child elements)
// and we don't want to render items twice
if (item.parentKey !== null) {
return;
}
if ((_b = item.props) === null || _b === void 0 ? void 0 : _b._isSeparator) {
var props_1 = __assign({}, item.props);
delete props_1._isSeparator;
return React.createElement(ContentSeparator, __assign({}, props_1));
}
var menuItem = (React.createElement(MenuItem, { key: item.key, item: item, state: state, onAction: _props.onAction }));
if (item.wrapper) {
menuItem = item.wrapper(menuItem);
}
return menuItem;
}
},
// eslint-disable-next-line react-hooks/exhaustive-deps
[state]);
// the label can be specified as part of the props, or part of the menu context (e.g. provided by MenuTrigger)
useCheckAriaLabel('Menu', menuProps);
// ListContext is necessary to prevent changes in parent ListContext
// for example when Menu is inside a list row
return (React.createElement(MenuAppearanceContext.Provider, { value: { itemShape: itemShape, itemSize: itemSize, tickPosition: tickPosition, classNameSelectedItem: classNameSelectedItem } },
React.createElement(ListContext.Provider, { value: { shouldItemFocusBeInset: shouldItemFocusBeInset } },
React.createElement("div", __assign({ className: classnames(className, STYLE.wrapper), id: id, style: style, ref: ref }, menuProps), itemArray.map(function (key) {
var item = state.collection.getItem(key);
return renderItem(item, state);
})))));
};
/**
* Menu Element which displays a list of options/actions.
*/
var _Menu = forwardRef(Menu);
_Menu.displayName = '_Menu';
export default _Menu;
//# sourceMappingURL=Menu.js.map