UNPKG

@react-md/menu

Version:

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

192 lines 10.5 kB
"use strict"; 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 __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; 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; }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.Menu = void 0; /* eslint-disable jsx-a11y/no-static-element-interactions */ var react_1 = __importStar(require("react")); var classnames_1 = __importDefault(require("classnames")); var transition_1 = require("@react-md/transition"); var utils_1 = require("@react-md/utils"); var MenuEvents_1 = require("./MenuEvents"); var Orientation_1 = require("./Orientation"); var useMenu_1 = require("./useMenu"); var block = utils_1.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. */ exports.Menu = react_1.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 ? utils_1.CENTER_CENTER_ANCHOR : utils_1.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_1.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 = react_1.useState(false), cancelled = _m[0], setCancelled = _m[1]; var prevVisible = react_1.useRef(visible); if (prevVisible.current !== visible) { prevVisible.current = visible; if (cancelled) { setCancelled(false); } } var _o = transition_1.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_1.default.createElement(transition_1.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_1.default.createElement(Orientation_1.OrientationProvider, { orientation: orientation }, react_1.default.createElement("div", __assign({}, props, { "aria-orientation": orientation, ref: ref, role: role, tabIndex: tabIndex, style: __assign(__assign({}, propStyle), style), className: classnames_1.default(block({ horizontal: horizontal }), className), onClick: onClick, onKeyDown: onKeyDown }), children, react_1.default.createElement(MenuEvents_1.MenuEvents, { menuRef: menuRef, cancelled: cancelled, defaultFocus: defaultFocus }))))); }); if (process.env.NODE_ENV !== "production") { try { var PropTypes = require("prop-types"); exports.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