UNPKG

@react-md/menu

Version:

Create menus that auto-position themselves within the viewport and adhere to the accessibility guidelines

167 lines 9.32 kB
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); }; var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; /* eslint-disable jsx-a11y/no-static-element-interactions */ import React, { forwardRef, useRef, useState } from "react"; import cn from "classnames"; import { ScaleTransition, useFixedPositioning, } from "@react-md/transition"; import { bem, CENTER_CENTER_ANCHOR, TOP_INNER_RIGHT_ANCHOR, } from "@react-md/utils"; import { MenuEvents } from "./MenuEvents"; import { OrientationProvider } from "./Orientation"; import { useMenu } from "./useMenu"; var block = bem("rmd-menu"); /** * The `Menu` component is a fully controlled component that will animate in and * out based on the `visible` prop as well as handle keyboard focus, closing * when needed, etc. */ export var Menu = forwardRef(function Menu(_a, forwardedRef) { var _b = _a.role, role = _b === void 0 ? "menu" : _b, _c = _a.tabIndex, tabIndex = _c === void 0 ? -1 : _c, controlId = _a.controlId, propStyle = _a.style, className = _a.className, visible = _a.visible, onRequestClose = _a.onRequestClose, children = _a.children, portal = _a.portal, portalInto = _a.portalInto, portalIntoId = _a.portalIntoId, _d = _a.mountOnEnter, mountOnEnter = _d === void 0 ? true : _d, _e = _a.unmountOnExit, unmountOnExit = _e === void 0 ? true : _e, propOnEnter = _a.onEnter, propOnEntering = _a.onEntering, propOnEntered = _a.onEntered, onExit = _a.onExit, onExiting = _a.onExiting, propOnExited = _a.onExited, timeout = _a.timeout, classNames = _a.classNames, propAnchor = _a.anchor, propOnClick = _a.onClick, propOnKeyDown = _a.onKeyDown, _f = _a.defaultFocus, defaultFocus = _f === void 0 ? "first" : _f, _g = _a.horizontal, horizontal = _g === void 0 ? false : _g, positionOptions = _a.positionOptions, _h = _a.closeOnScroll, closeOnScroll = _h === void 0 ? false : _h, _j = _a.closeOnResize, closeOnResize = _j === void 0 ? false : _j, _k = _a.disableControlClickOkay, disableControlClickOkay = _k === void 0 ? false : _k, props = __rest(_a, ["role", "tabIndex", "controlId", "style", "className", "visible", "onRequestClose", "children", "portal", "portalInto", "portalIntoId", "mountOnEnter", "unmountOnExit", "onEnter", "onEntering", "onEntered", "onExit", "onExiting", "onExited", "timeout", "classNames", "anchor", "onClick", "onKeyDown", "defaultFocus", "horizontal", "positionOptions", "closeOnScroll", "closeOnResize", "disableControlClickOkay"]); var anchor = propAnchor; if (!anchor) { anchor = horizontal ? CENTER_CENTER_ANCHOR : TOP_INNER_RIGHT_ANCHOR; } // TODO: Refactor all the menu functionality since I made this when I had no // idea what I was doing with hooks var _l = useMenu({ ref: forwardedRef, visible: visible, controlId: controlId, horizontal: horizontal, onClick: propOnClick, onKeyDown: propOnKeyDown, portalled: portal || typeof portalInto !== "undefined" || !!portalIntoId, defaultFocus: defaultFocus, onRequestClose: onRequestClose, disableControlClickOkay: disableControlClickOkay, }), ref = _l.ref, menuRef = _l.menuRef, onClick = _l.onClick, onKeyDown = _l.onKeyDown; var _m = useState(false), cancelled = _m[0], setCancelled = _m[1]; var prevVisible = useRef(visible); if (prevVisible.current !== visible) { prevVisible.current = visible; if (cancelled) { setCancelled(false); } } var _o = useFixedPositioning(__assign(__assign({}, positionOptions), { fixedTo: function () { return document.getElementById(controlId); }, onScroll: function (_event, _a) { var visible = _a.visible; if (!closeOnScroll && visible) { return; } if (!visible) { setCancelled(true); } onRequestClose(); }, onResize: closeOnResize ? onRequestClose : undefined, anchor: anchor, onEnter: propOnEnter, onEntering: propOnEntering, onEntered: propOnEntered, onExited: propOnExited, transformOrigin: true })), style = _o.style, onEnter = _o.onEnter, onEntering = _o.onEntering, onEntered = _o.onEntered, onExited = _o.onExited; var orientation = horizontal ? "horizontal" : "vertical"; return (React.createElement(ScaleTransition, { portal: portal, portalInto: portalInto, portalIntoId: portalIntoId, appear: mountOnEnter, visible: visible, classNames: classNames, timeout: timeout, onEnter: onEnter, onEntering: onEntering, onEntered: onEntered, onExit: onExit, onExiting: onExiting, onExited: onExited, mountOnEnter: mountOnEnter, unmountOnExit: unmountOnExit }, React.createElement(OrientationProvider, { orientation: orientation }, React.createElement("div", __assign({}, props, { "aria-orientation": orientation, ref: ref, role: role, tabIndex: tabIndex, style: __assign(__assign({}, propStyle), style), className: cn(block({ horizontal: horizontal }), className), onClick: onClick, onKeyDown: onKeyDown }), children, React.createElement(MenuEvents, { menuRef: menuRef, cancelled: cancelled, defaultFocus: defaultFocus }))))); }); if (process.env.NODE_ENV !== "production") { try { var PropTypes = require("prop-types"); Menu.propTypes = { id: PropTypes.string.isRequired, role: PropTypes.string, className: PropTypes.string, controlId: PropTypes.string.isRequired, visible: PropTypes.bool.isRequired, onRequestClose: PropTypes.func.isRequired, "aria-label": PropTypes.string, "aria-labelledby": PropTypes.string, tabIndex: PropTypes.number, anchor: PropTypes.shape({ x: PropTypes.oneOf([ "inner-left", "inner-right", "center", "left", "right", ]), y: PropTypes.oneOf(["above", "below", "center", "top", "bottom"]), }), positionOptions: PropTypes.shape({ xMargin: PropTypes.number, yMargin: PropTypes.number, vwMargin: PropTypes.number, vhMargin: PropTypes.number, disableSwapping: PropTypes.bool, }), mountOnEnter: PropTypes.bool, unmountOnExit: PropTypes.bool, defaultFocus: PropTypes.oneOf(["first", "last"]), classNames: PropTypes.oneOfType([ PropTypes.string, PropTypes.shape({ appear: PropTypes.string, appearActive: PropTypes.string, enter: PropTypes.string, enterActive: PropTypes.string, exit: PropTypes.string, exitActive: PropTypes.string, }), ]), timeout: PropTypes.oneOfType([ PropTypes.number, PropTypes.shape({ enter: PropTypes.number, exit: PropTypes.number, }), ]), onClick: PropTypes.func, onKeyDown: PropTypes.func, children: PropTypes.node, horizontal: PropTypes.bool, onEnter: PropTypes.func, onEntering: PropTypes.func, onEntered: PropTypes.func, onExit: PropTypes.func, onExiting: PropTypes.func, onExited: PropTypes.func, portal: PropTypes.bool, portalInto: PropTypes.oneOfType([ PropTypes.string, PropTypes.func, PropTypes.object, ]), portalIntoId: PropTypes.string, closeOnScroll: PropTypes.bool, closeOnResize: PropTypes.bool, disableControlClickOkay: PropTypes.bool, // eslint-disable-next-line @typescript-eslint/ban-ts-comment // @ts-expect-error _a11yValidator: function (props, _propName, component) { var label = props["aria-label"]; var labelledBy = props["aria-labelledby"]; if (label || labelledBy) { return null; } return new Error("Either the `aria-label` or `aria-labelledby` props are required for accessibility in the " + component + " component, but neither were provided."); }, }; } catch (e) { } } //# sourceMappingURL=Menu.js.map