@react-md/menu
Version:
Create menus that auto-position themselves within the viewport and adhere to the accessibility guidelines
118 lines • 7.43 kB
JavaScript
;
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;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.MenuSheet = void 0;
var jsx_runtime_1 = require("react/jsx-runtime");
var react_1 = require("react");
var list_1 = require("@react-md/list");
var sheet_1 = require("@react-md/sheet");
var utils_1 = require("@react-md/utils");
var MenuKeyboardFocusProvider_1 = require("./MenuKeyboardFocusProvider");
var MenuWidget_1 = require("./MenuWidget");
/**
* Implements a `Menu` using the `Sheet` component that probably shouldn't
* really be used externally.
*
* @remarks \@since 5.0.0
* @internal
*/
function MenuSheet(_a) {
var id = _a.id, children = _a.children, header = _a.header, footer = _a.footer, horizontal = _a.horizontal, menuRef = _a.menuRef, menuProps = _a.menuProps, listStyle = _a.listStyle, listClassName = _a.listClassName, listProps = _a.listProps, _b = _a.position, position = _b === void 0 ? "bottom" : _b, _c = _a.verticalSize, verticalSize = _c === void 0 ? "touch" : _c, onClick = _a.onClick, overlayProps = _a.overlayProps, onRequestClose = _a.onRequestClose, props = __rest(_a, ["id", "children", "header", "footer", "horizontal", "menuRef", "menuProps", "listStyle", "listClassName", "listProps", "position", "verticalSize", "onClick", "overlayProps", "onRequestClose"]);
var ariaLabel = props["aria-label"], ariaLabelledBy = props["aria-labelledby"];
var listRef = (0, react_1.useRef)(null);
// Since there is the possibility of other tab focusable elements within the
// sheet and the menu items are programmatically focused, the menu's tabIndex
// needs to be set to `-1` while one of the child menu items are focused. This
// allows Shift+Tab correctly focuses the previous focusable element within
// the sheet. Since `onFocus` and `onBlur` will be bubbled up to the menu
// widget each time a new MenuItem is focused, only disable the focused state
// if the blur event is fired without another focus event within an animation
// frame.
var _d = __read((0, react_1.useState)(false), 2), focused = _d[0], setFocused = _d[1];
var blurredFrame = (0, react_1.useRef)(0);
(0, utils_1.useOnUnmount)(function () {
window.cancelAnimationFrame(blurredFrame.current);
});
return ((0, jsx_runtime_1.jsxs)(sheet_1.Sheet, __assign({ id: "".concat(id, "-sheet") }, props, { onRequestClose: onRequestClose, overlayProps: __assign(__assign({}, overlayProps), { onClick: function (event) {
var _a;
(_a = overlayProps === null || overlayProps === void 0 ? void 0 : overlayProps.onClick) === null || _a === void 0 ? void 0 : _a.call(overlayProps, event);
// prevent closing parent menus if the overlay element is clicked.
event.stopPropagation();
onRequestClose();
} }), position: position, verticalSize: verticalSize, onClick: function (event) {
var _a;
onClick === null || onClick === void 0 ? void 0 : onClick(event);
// Prevent closing parent sheet/menus if an element in the header or
// footer is clicked
if (!(event.target instanceof HTMLElement) ||
!((_a = listRef.current) === null || _a === void 0 ? void 0 : _a.contains(event.target))) {
event.stopPropagation();
}
} }, { children: [header, (0, jsx_runtime_1.jsx)(MenuKeyboardFocusProvider_1.MenuKeyboardFocusProvider, __assign({ horizontal: horizontal }, { children: (0, jsx_runtime_1.jsx)(MenuWidget_1.MenuWidget, __assign({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, id: id, ref: menuRef, tabIndex: focused ? -1 : 0 }, menuProps, { onFocus: function (event) {
var _a;
(_a = menuProps === null || menuProps === void 0 ? void 0 : menuProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(menuProps, event);
window.cancelAnimationFrame(blurredFrame.current);
setFocused(true);
}, onBlur: function (event) {
var _a;
(_a = menuProps === null || menuProps === void 0 ? void 0 : menuProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(menuProps, event);
blurredFrame.current = window.requestAnimationFrame(function () {
setFocused(false);
});
}, onKeyDown: function (event) {
var _a;
// the tab keypress should use the sheet's behavior instead of
// closing the menus
if (event.key === "Tab") {
return;
}
(_a = menuProps === null || menuProps === void 0 ? void 0 : menuProps.onKeyDown) === null || _a === void 0 ? void 0 : _a.call(menuProps, event);
}, disableElevation: true }, { children: (0, jsx_runtime_1.jsx)(list_1.List, __assign({}, listProps, { style: listStyle !== null && listStyle !== void 0 ? listStyle : listProps === null || listProps === void 0 ? void 0 : listProps.style, className: listClassName !== null && listClassName !== void 0 ? listClassName : listProps === null || listProps === void 0 ? void 0 : listProps.className, ref: listRef, horizontal: horizontal, onClick: function (event) {
var _a;
(_a = listProps === null || listProps === void 0 ? void 0 : listProps.onClick) === null || _a === void 0 ? void 0 : _a.call(listProps, event);
// this makes it so you can click on the menu/list without
// closing the menu
if (event.target === event.currentTarget) {
event.stopPropagation();
}
} }, { children: children })) })) })), footer] })));
}
exports.MenuSheet = MenuSheet;
//# sourceMappingURL=MenuSheet.js.map