robust-react-ui
Version:
A React component library, built with a focus on accessibility, extensibility and reusability.
303 lines (298 loc) • 17.2 kB
JavaScript
;
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var React = require('react');
var React__default = _interopDefault(React);
var index = require('../../utils/getClassNames/index.js');
var _tslib = require('../../_virtual/_tslib.js');
var FOCUS_DELAY = 120;
var NavigationBar = function (_a) {
var data = _a.data, onEnterLinkFunction = _a.onEnterLinkFunction, ariaLabel = _a.ariaLabel, id = _a.id;
var _b = React.useState([]), nodes = _b[0], setNodes = _b[1];
var _c = React.useState(false), closeAll = _c[0], setCloseAll = _c[1];
React.useEffect(function () {
var allNodes = [];
var getNode = function (x, i) {
var o = {};
if (x.children && x.children.length && x.children.length > 0) {
o.menuOpen = false;
o.hasMenu = true;
}
else {
o.hasMenu = false;
}
o.id = x.id;
o.parentId = x.parentId;
o.ref = React.createRef();
o.order = i;
o.name = x.linkName;
return o;
};
data.forEach(function (x, i) {
var _a;
var node0 = _tslib.__assign(_tslib.__assign({}, getNode(x, i)), { lv: 1 });
allNodes.push(node0);
(_a = x.children) === null || _a === void 0 ? void 0 : _a.forEach(function (x2, i2) {
var _a;
var node1 = _tslib.__assign(_tslib.__assign({}, getNode(x2, i2)), { menuId: x.id, lv: 2 });
allNodes.push(node1);
(_a = x2.children) === null || _a === void 0 ? void 0 : _a.forEach(function (x3, i3) {
var node2 = _tslib.__assign(_tslib.__assign({}, getNode(x3, i3)), { menuId: x.id, lv: 3 });
allNodes.push(node2);
});
});
});
setNodes(allNodes);
}, []);
var closeAllMenuButOne = function (menuId) {
setNodes(nodes.map(function (n) {
if (n.id === menuId) {
return _tslib.__assign(_tslib.__assign({}, n), { menuOpen: true });
}
return _tslib.__assign(_tslib.__assign({}, n), { menuOpen: false });
}));
};
var traverseTopLevelMenu = function (menuId, dir) {
var menuNodes = nodes.filter(function (x) { return x.parentId === null; });
var max = menuNodes.length - 1;
var ord = menuNodes.find(function (x) { return x.id === menuId; }).order;
var next = ord === max ? 0 : ord + 1;
var prev = ord === 0 ? max : ord - 1;
if (dir === 'LEFT') {
var m = menuNodes.find(function (x) { return x.order === prev; });
m.ref.current.focus();
if (closeAll)
closeAllMenuButOne(m.id);
}
if (dir === 'RIGHT') {
var m = menuNodes.find(function (x) { return x.order === next; });
m.ref.current.focus();
if (closeAll)
closeAllMenuButOne(m.id);
}
};
var openMenu = function (menuId) {
setNodes(nodes.map(function (n) {
if (n.id === menuId) {
return _tslib.__assign(_tslib.__assign({}, n), { menuOpen: true });
}
return n;
}));
// focus on first child
setTimeout(function () {
var _a, _b;
var exists = nodes.find(function (n) { return n.parentId === menuId; });
(_b = (_a = exists === null || exists === void 0 ? void 0 : exists.ref) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.focus();
}, FOCUS_DELAY);
};
var focusDownNode = function (node) {
// get nodes at the level
var filtered = nodes.filter(function (n) { return n.parentId === node.parentId; });
// find the current pos
var currentNode = filtered.find(function (n) { return n.id === node.id; });
var max = filtered.length - 1;
// set the next pos and focus
if (currentNode.order === max) {
filtered[0].ref.current.focus();
}
else {
filtered[currentNode.order + 1].ref.current.focus();
}
};
var focusUpNode = function (node) {
// get nodes at the level
var filtered = nodes.filter(function (n) { return n.parentId === node.parentId; });
// find the current pos
var currentNode = filtered.find(function (n) { return n.id === node.id; });
var max = filtered.length - 1;
// set the next pos and focus
if (currentNode.order === 0) {
filtered[max].ref.current.focus();
}
else {
filtered[currentNode.order - 1].ref.current.focus();
}
};
var handleLeftPress = function (node) {
// if has children has parent close the current dropdown
// focus on parent node
var foundNode = nodes.find(function (n) { return n.id === node.id; });
if (foundNode.lv > 2) {
setNodes(nodes.map(function (n) {
if (n.id === node.parentId) {
return _tslib.__assign(_tslib.__assign({}, n), { menuOpen: false });
}
return n;
}));
setTimeout(function () {
var _a, _b, _c;
(_c = (_b = (_a = nodes.find(function (n) { return n.id === node.parentId; })) === null || _a === void 0 ? void 0 : _a.ref) === null || _b === void 0 ? void 0 : _b.current) === null || _c === void 0 ? void 0 : _c.focus();
}, FOCUS_DELAY);
}
else {
// else navigate to the previous TOPLEVEL nav item
if (!closeAll)
setCloseAll(true);
traverseTopLevelMenu(foundNode.menuId, 'LEFT');
}
};
var handleRightPress = function (node) {
// if has children open the menu
var foundNode = nodes.find(function (n) { return n.id === node.id; });
if (foundNode.hasMenu) {
// open menu
openMenu(node.id);
// focus on the first
setTimeout(function () {
var _a, _b, _c;
(_c = (_b = (_a = nodes.find(function (n) { return n.parentId === node.id; })) === null || _a === void 0 ? void 0 : _a.ref) === null || _b === void 0 ? void 0 : _b.current) === null || _c === void 0 ? void 0 : _c.focus();
}, FOCUS_DELAY);
}
else {
// else navigate to the next TOPLEVEL nav item
if (!closeAll)
setCloseAll(true);
traverseTopLevelMenu(foundNode.menuId, 'RIGHT');
}
};
var handleLinkDefaultAction = function (href) {
if (onEnterLinkFunction) {
onEnterLinkFunction(href);
return;
}
if (typeof window !== 'undefined') {
window.location.href = href;
}
};
var closeAllAndFocusTopMenu = function (node) {
// node.parentId
setNodes(nodes.map(function (x) { return (_tslib.__assign(_tslib.__assign({}, x), { menuOpen: false })); }));
nodes.find(function (n) { return n.id === node.parentId; }).ref.current.focus();
};
return (React__default.createElement("nav", { className: "rrui-nav", "data-testid": "NavigationBar", "aria-label": ariaLabel },
React__default.createElement("ul", { id: id || null, role: "menubar", "aria-label": ariaLabel }, data.map(function (a, _ai) {
var _a;
var n = nodes.find(function (nodeToFind4) { return nodeToFind4.id === a.id; });
return (React__default.createElement("li", { role: "none", className: index({
'rrui-nav__menu-item': true,
'rrui-nav__menu-item--expanded': n === null || n === void 0 ? void 0 : n.menuOpen,
'rrui-nav__menu-item--has-menu': n === null || n === void 0 ? void 0 : n.hasMenu,
}), key: a.linkName + _ai.toString() },
React__default.createElement("a", { ref: n === null || n === void 0 ? void 0 : n.ref, onKeyDown: function (e) {
// left
if (e.keyCode === 37) {
traverseTopLevelMenu(a.id, 'LEFT');
}
// right
if (e.keyCode === 39) {
traverseTopLevelMenu(a.id, 'RIGHT');
}
// enter
if (e.keyCode === 13) {
if (n.hasMenu) {
openMenu(a.id);
}
else {
handleLinkDefaultAction(a.linkHref);
}
}
}, role: "menuitem", "aria-haspopup": (n === null || n === void 0 ? void 0 : n.hasMenu) ? 'true' : 'false', "aria-expanded": (n === null || n === void 0 ? void 0 : n.menuOpen) ? 'true' : 'false', href: a.linkHref ? a.linkHref : '#', tabIndex: 0 },
a.linkName,
(n === null || n === void 0 ? void 0 : n.hasMenu) && (React__default.createElement("svg", { width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: index({
'rrui-nav__chevron': true,
}) },
React__default.createElement("polyline", { points: "9 18 15 12 9 6" })))),
a.children && (React__default.createElement("ul", { className: index({
'rrui-nav__dropdown': true,
'rrui-nav__dropdown--open': (_a = nodes.find(function (nodeToFind2) { return nodeToFind2.id === a.id; })) === null || _a === void 0 ? void 0 : _a.menuOpen,
}), role: "menu", "aria-label": a.linkName }, a.children.map(function (b, _bi) {
var _a;
var n2 = nodes.find(function (nodeToFind) { return nodeToFind.id === b.id; });
return (React__default.createElement(React__default.Fragment, { key: b.linkName + _bi.toString() },
React__default.createElement("li", { role: "none", className: index({
'rrui-nav__dropdown-item': true,
'rrui-nav__dropdown-item--expanded': n2 === null || n2 === void 0 ? void 0 : n2.menuOpen,
}) },
React__default.createElement("a", { ref: n2 === null || n2 === void 0 ? void 0 : n2.ref, id: b.id.toString(), role: "menuitem", href: b.linkHref ? b.linkHref : '#', "aria-haspopup": (n2 === null || n2 === void 0 ? void 0 : n2.hasMenu) ? 'true' : 'false', "aria-expanded": (n2 === null || n2 === void 0 ? void 0 : n2.menuOpen) ? 'true' : 'false', tabIndex: -1, onKeyDown: function (e) {
e.preventDefault();
// up
if (e.keyCode === 38) {
focusUpNode(b);
}
// down
if (e.keyCode === 40) {
focusDownNode(b);
}
// right
if (e.keyCode === 39) {
handleRightPress(b);
}
// left
if (e.keyCode === 37) {
handleLeftPress(b);
}
// escape
if (e.keyCode === 27) {
closeAllAndFocusTopMenu(b);
}
// enter
if (e.keyCode === 13) {
if (n2.hasMenu) {
handleRightPress(b);
}
else {
handleLinkDefaultAction(b.linkHref);
}
}
} },
b.linkName,
(n2 === null || n2 === void 0 ? void 0 : n2.hasMenu) && (React__default.createElement("svg", { xmlns: "http://www.w3.org/2000/svg", width: "24", height: "24", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: index({
'rrui-nav__chevron': true,
'rrui-nav__chevron--submenu': true,
'rrui-nav__chevron--expanded': n2 === null || n2 === void 0 ? void 0 : n2.menuOpen,
}) },
React__default.createElement("polyline", { points: "9 18 15 12 9 6" })))),
b.children && (React__default.createElement("ul", { className: index({
'rrui-nav__dropdown': true,
'rrui-nav__dropdown--nested': true,
'rrui-nav__dropdown--open': (_a = nodes.find(function (nodeToFind3) { return nodeToFind3.id === b.id; })) === null || _a === void 0 ? void 0 : _a.menuOpen,
}), role: "menu", "aria-label": b.linkName }, b.children.map(function (c, _ci) {
var n3 = nodes.find(function (nodeToFind5) { return nodeToFind5.id === c.id; });
return (React__default.createElement(React__default.Fragment, { key: c.linkName + _ci.toString() },
React__default.createElement("li", { role: "none", className: "rrui-nav__dropdown-item" },
React__default.createElement("a", { onKeyDown: function (e) {
e.preventDefault();
// up
if (e.keyCode === 38) {
focusUpNode(c);
}
// down
if (e.keyCode === 40) {
focusDownNode(c);
}
// right
if (e.keyCode === 39) {
handleRightPress(c);
}
// left or escape
if (e.keyCode === 37 ||
e.keyCode === 27) {
handleLeftPress(c);
}
// enter
if (e.keyCode === 13) {
if (n3.hasMenu) {
handleRightPress(c);
}
else {
handleLinkDefaultAction(c.linkHref);
}
}
}, ref: n3 === null || n3 === void 0 ? void 0 : n3.ref, id: c.id.toString(), role: "menuitem", href: c.linkHref ? c.linkHref : '#', "aria-haspopup": "false", "aria-expanded": null, tabIndex: -1 }, c.linkName)),
c.hasSeparator && (React__default.createElement("li", { role: "separator", className: "rrui-nav__separator" }))));
})))),
b.hasSeparator && (React__default.createElement("li", { role: "separator", className: "rrui-nav__separator" }))));
})))));
}))));
};
module.exports = NavigationBar;
//# sourceMappingURL=NavigationBar.js.map