@react-md/menu
Version:
Create menus that auto-position themselves within the viewport and adhere to the accessibility guidelines
192 lines • 10.5 kB
JavaScript
"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