UNPKG

@fluentui/react-northstar

Version:
267 lines (266 loc) 9.88 kB
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