@fluentui/react-northstar
Version:
A themable React component library.
267 lines (266 loc) • 9.88 kB
JavaScript
import _invoke from "lodash/invoke";
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { menuButtonBehavior } from '@fluentui/accessibility';
import { Ref } from '@fluentui/react-component-ref';
import * as customPropTypes from '@fluentui/react-proptypes';
import { commonPropTypes, getOrGenerateIdFromShorthand } from '../../utils';
import { createShorthandFactory } from '../../utils/factories';
import { Popup } from '../Popup/Popup';
import { Menu } from '../Menu/Menu';
import { focusMenuItem } from './focusUtils';
import { ALIGNMENTS, POSITIONS, AUTOSIZES } from '../../utils/positioner';
import { useAccessibility, useTelemetry, getElementType, useUnhandledProps, useFluentContext, useAutoControlled, useStyles, useOnIFrameFocus } from '@fluentui/react-bindings';
export var menuButtonClassName = 'ui-menubutton';
export var menuButtonSlotClassNames = {
menu: menuButtonClassName + "__menu"
};
/**
* A MenuButton displays a menu connected to trigger element.
* @accessibility
*/
export var MenuButton = /*#__PURE__*/function () {
var MenuButton = /*#__PURE__*/React.forwardRef(function (props, ref) {
var context = useFluentContext();
var _useTelemetry = useTelemetry(MenuButton.displayName, context.telemetry),
setStart = _useTelemetry.setStart,
setEnd = _useTelemetry.setEnd;
setStart();
var contextMenu = props.contextMenu,
menu = props.menu,
accessibility = props.accessibility,
align = props.align,
className = props.className,
defaultOpen = props.defaultOpen,
flipBoundary = props.flipBoundary,
mountNode = props.mountNode,
mouseLeaveDelay = props.mouseLeaveDelay,
offset = props.offset,
on = props.on,
onOpenChange = props.onOpenChange,
overflowBoundary = props.overflowBoundary,
pointing = props.pointing,
popperRef = props.popperRef,
position = props.position,
positionFixed = props.positionFixed,
tabbableTrigger = props.tabbableTrigger,
target = props.target,
trigger = props.trigger,
unstable_disableTether = props.unstable_disableTether,
unstable_pinned = props.unstable_pinned,
autoSize = props.autoSize,
variables = props.variables;
var _useAutoControlled = useAutoControlled({
defaultValue: props.defaultOpen,
value: props.open,
initialValue: false
}),
open = _useAutoControlled[0],
setOpen = _useAutoControlled[1];
useOnIFrameFocus(open, context.target, function (e) {
setOpen(function (__) {
_invoke(props, 'onOpenChange', e, Object.assign({}, props, {
open: false
}));
return false;
});
});
var menuId = React.useRef();
menuId.current = getOrGenerateIdFromShorthand('menubutton-menu-', menu, menuId.current);
var triggerId = React.useRef();
triggerId.current = getOrGenerateIdFromShorthand('menubutton-trigger-', trigger, triggerId.current);
var triggerRef = React.useRef();
var menuRef = React.useRef();
var ElementType = getElementType(props);
var unhandledProps = useUnhandledProps(MenuButton.handledProps, props);
var getA11yProps = useAccessibility(accessibility, {
debugName: MenuButton.displayName,
actionHandlers: {
closeMenu: function (_closeMenu) {
function closeMenu(_x) {
return _closeMenu.apply(this, arguments);
}
closeMenu.toString = function () {
return _closeMenu.toString();
};
return closeMenu;
}(function (e) {
return closeMenu(e);
}),
openAndFocusFirst: function openAndFocusFirst(e) {
return openAndFocus(e, 'first');
},
openAndFocusLast: function openAndFocusLast(e) {
return openAndFocus(e, 'last');
}
},
mapPropsToBehavior: function mapPropsToBehavior() {
return {
menuId: menuId.current,
triggerId: triggerId.current,
open: open,
trigger: props.trigger,
contextMenu: contextMenu,
on: on,
tabbableTrigger: tabbableTrigger
};
},
rtl: context.rtl
});
var popupProps = {
accessibility: accessibility,
align: align,
defaultOpen: defaultOpen,
mountNode: mountNode,
mouseLeaveDelay: mouseLeaveDelay,
flipBoundary: flipBoundary,
offset: offset,
on: on,
onOpenChange: onOpenChange,
open: open,
overflowBoundary: overflowBoundary,
pointing: pointing,
popperRef: popperRef,
position: position,
positionFixed: positionFixed,
tabbableTrigger: tabbableTrigger,
target: target,
trigger: trigger,
unstable_disableTether: unstable_disableTether,
unstable_pinned: unstable_pinned,
autoSize: autoSize
};
var _useStyles = useStyles(MenuButton.displayName, {
className: menuButtonClassName,
mapPropsToInlineStyles: function mapPropsToInlineStyles() {
return {
className: className,
styles: props.styles,
variables: variables
};
},
rtl: context.rtl
}),
classes = _useStyles.classes,
resolvedStyles = _useStyles.styles;
var closeMenu = function closeMenu(e) {
handleOpenChange(e, false);
};
var openAndFocus = function openAndFocus(e, which) {
e.preventDefault();
handleOpenChange(e, true, function () {
return menuRef.current && focusMenuItem(menuRef.current, which);
});
};
var handleOpenChange = function handleOpenChange(e, open, callback) {
_invoke(props, 'onOpenChange', e, Object.assign({}, props, {
open: open
}));
setOpen(open);
callback && callback();
};
var handleMenuOverrides = function handleMenuOverrides(predefinedProps) {
return {
onItemClick: function onItemClick(e, itemProps) {
_invoke(predefinedProps, 'onItemClick', e, itemProps);
_invoke(props, 'onMenuItemClick', e, itemProps);
if (!itemProps || !itemProps.menu) {
// do not close if clicked on item with submenu
handleOpenChange(e, false);
}
},
onKeyDown: function onKeyDown(e, itemProps) {
_invoke(predefinedProps, 'onKeyDown', e, itemProps);
if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') {
e.stopPropagation();
}
}
};
};
var content = Menu.create(menu, {
defaultProps: function defaultProps() {
return getA11yProps('menu', {
vertical: true,
className: menuButtonSlotClassNames.menu
});
},
overrideProps: handleMenuOverrides
});
var overrideProps = Object.assign({
accessibility: getA11yProps.unstable_behaviorDefinition,
open: open,
onOpenChange: function onOpenChange(e, _ref) {
var open = _ref.open;
handleOpenChange(e, open);
},
content: {
styles: resolvedStyles.popupContent,
content: content && /*#__PURE__*/React.createElement(Ref, {
innerRef: menuRef
}, content)
},
children: undefined
}, contextMenu ? {
on: 'context',
trapFocus: true,
tabbableTrigger: false
} : {
inline: true,
autoFocus: true
});
var popup = Popup.create(popupProps, {
overrideProps: overrideProps
});
if (contextMenu) {
setEnd();
return popup;
}
var element = getA11yProps.unstable_wrapWithFocusZone( /*#__PURE__*/React.createElement(ElementType, getA11yProps('root', Object.assign({
ref: ref,
className: classes.root
}, unhandledProps)), /*#__PURE__*/React.createElement(Ref, {
innerRef: triggerRef
}, popup)));
setEnd();
return element;
});
MenuButton.displayName = 'MenuButton';
MenuButton.propTypes = Object.assign({}, commonPropTypes.createCommon({
content: false
}), {
align: PropTypes.oneOf(ALIGNMENTS),
defaultOpen: PropTypes.bool,
mountNode: customPropTypes.domNode,
mouseLeaveDelay: PropTypes.number,
offset: PropTypes.oneOfType([PropTypes.func, PropTypes.arrayOf(PropTypes.number)]),
on: PropTypes.oneOfType([PropTypes.oneOf(['hover', 'click', 'focus', 'context']), PropTypes.arrayOf(PropTypes.oneOf(['click', 'focus', 'context'])), PropTypes.arrayOf(PropTypes.oneOf(['hover', 'focus', 'context']))]),
flipBoundary: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object), PropTypes.oneOf(['clippingParents', 'window', 'scrollParent'])]),
overflowBoundary: PropTypes.oneOfType([PropTypes.object, PropTypes.arrayOf(PropTypes.object), PropTypes.oneOf(['clippingParents', 'window', 'scrollParent'])]),
open: PropTypes.bool,
onMenuItemClick: PropTypes.func,
onOpenChange: PropTypes.func,
popperRef: customPropTypes.ref,
position: PropTypes.oneOf(POSITIONS),
positionFixed: PropTypes.bool,
target: PropTypes.any,
trigger: customPropTypes.every([customPropTypes.disallow(['children']), PropTypes.any]),
tabbableTrigger: PropTypes.bool,
unstable_disableTether: PropTypes.oneOf([true, false, 'all']),
unstable_pinned: PropTypes.bool,
autoSize: PropTypes.oneOf(AUTOSIZES),
menu: PropTypes.oneOfType([customPropTypes.itemShorthandWithoutJSX, PropTypes.arrayOf(customPropTypes.itemShorthandWithoutJSX)]),
contextMenu: PropTypes.bool
});
MenuButton.defaultProps = {
accessibility: menuButtonBehavior,
align: 'start',
position: 'below'
};
MenuButton.handledProps = Object.keys(MenuButton.propTypes);
MenuButton.create = createShorthandFactory({
Component: MenuButton,
mappedProp: 'menu'
});
return MenuButton;
}();
//# sourceMappingURL=MenuButton.js.map