@teamsnap/teamsnap-ui
Version:
a CSS component library for TeamSnap
202 lines (201 loc) • 11.2 kB
JavaScript
"use strict";
/**
* @name Nav
*
* @description
* A component for rendering a vertical, usually left-aligned, navigation.
* This component offers a collapsable width.
*
* Please see the Storybook example for a more robust way of how we recommend using the Nav component.
*
* <Nav>
* <Nav.Item onClick={() => alert("Home clicked!")}>Home</Nav.Item>
* <Nav.Item link="https://www.teamsnap.com" linkProps={{target: "_blank"}}>External Link</Nav.Item>
* </Nav>
*/
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 __spreadArray = (this && this.__spreadArray) || function (to, from) {
for (var i = 0, il = from.length, j = to.length; i < il; i++, j++)
to[j] = from[i];
return to;
};
Object.defineProperty(exports, "__esModule", { value: true });
var React = __importStar(require("react"));
var PropTypes = __importStar(require("prop-types"));
var Icon_1 = require("../Icon");
var helpers_1 = require("../../utils/helpers");
var Avatar_1 = require("../Avatar");
var Skittles_1 = require("../Skittles");
var treePropTypes = {
title: PropTypes.string.isRequired,
image: PropTypes.string,
// If an image is not provided and useBadge is, we will try to generate a badge based off the title
useBadge: PropTypes.bool,
// a function for wrapping each item. Commonly used with links or react router.
wrapItem: PropTypes.func,
tree: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired,
image: PropTypes.string,
// If an image is not provided and useBadge is, we will try to generate a badge based off the title
useBadge: PropTypes.bool,
// a function for wrapping each item. Commonly used with links or react router.
wrapItem: PropTypes.func,
tree: PropTypes.arrayOf(PropTypes.shape({
title: PropTypes.string.isRequired,
image: PropTypes.string,
// If an image is not provided and useBadge is, we will try to generate a badge based off the title
useBadge: PropTypes.bool,
// a function for wrapping each item. Commonly used with links or react router.
wrapItem: PropTypes.func,
})),
})),
};
var flyoutSectionsPropTypes = {
heading: PropTypes.string,
tree: PropTypes.arrayOf(PropTypes.shape(treePropTypes)),
};
var navPropTypes = {
// React component children
children: PropTypes.node,
// Custom classnames to add
className: PropTypes.string,
// TeamSnap UI modifiers to add to class name
mods: PropTypes.string,
// Custom React Styles to add to the nav
style: PropTypes.object,
testId: PropTypes.string,
// Any extraneous props
otherProps: PropTypes.object,
headerItem: PropTypes.shape({
title: PropTypes.string,
subtitle: PropTypes.string,
image: PropTypes.string,
useBadge: PropTypes.bool,
}),
// a list of items to be displayed in the header component
flyoutSections: PropTypes.arrayOf(PropTypes.shape(flyoutSectionsPropTypes)),
includeOverlay: PropTypes.bool,
openItems: PropTypes.bool,
};
var itemPropTypes = {
// String that matches a teamsnap-ui icon name
icon: PropTypes.string,
// Teamsnap UI modifiers passed to the icon component
iconModifiers: PropTypes.string,
// bool wether this item should be marked as active or not, multiple can be marked.
isActive: PropTypes.bool,
// function to handle an item being clicked.
onClick: PropTypes.func,
// a function for wrapping each item. Commonly used with links or react router.
wrapItem: PropTypes.func,
children: PropTypes.node,
};
var EmptyComponent = function (_a) {
var children = _a.children;
return React.createElement(React.Fragment, null, children);
};
var Item = function (_a) {
var children = _a.children, icon = _a.icon, iconModifiers = _a.iconModifiers, isActive = _a.isActive, onClick = _a.onClick, wrapItem = _a.wrapItem;
var maybeIcon = icon ? React.createElement(Icon_1.Icon, { name: icon, mods: "" + iconModifiers }) : null;
var Wrapper = wrapItem || EmptyComponent;
return (React.createElement("li", { className: (isActive ? 'is-active' : '') + " Nav-item" },
React.createElement("div", { onKeyDown: onClick || (function () { }), onClick: onClick || (function () { }), role: "button", tabIndex: 0 },
React.createElement(Wrapper, null,
maybeIcon,
" ",
React.createElement("span", { className: "Nav-itemTitle" }, children)))));
};
var FlyOutNode = function (_a) {
var item = _a.item, openItems = _a.openItems, reducer = _a.reducer;
var _b = React.useState(openItems), isExpanded = _b[0], setIsExpanded = _b[1];
var Wrapper = item.wrapItem ? item.wrapItem : function (_a) {
var children = _a.children;
return React.createElement(React.Fragment, null, children);
};
return (React.createElement("li", null,
React.createElement("div", { onClick: function () { return setIsExpanded(!isExpanded); }, onKeyDown: function () { return setIsExpanded(!isExpanded); }, tabIndex: 0, role: "button", className: "Nav-node " + (item.wrapItem ? 'Nav-wrapped' : '') + " " + (item.tree ? 'Nav-hasChildren' : '') + " u-fill u-flex" },
React.createElement(Wrapper, null,
item.tree && (React.createElement(Icon_1.Icon, { className: "Icon " + (isExpanded ? 'Node-expanded' : ''), mods: "u-fontSizeLg u-spaceRightXs", name: "caret-down" })),
!item.image && item.useBadge && React.createElement(Skittles_1.Skittles, { text: item.title, mods: "u-spaceRightSm" }),
React.createElement("span", { title: item.title, className: "Nav-nodeTitle" }, item.title))),
item.tree && item.tree.length > 0 ? (React.createElement("ul", { className: "Nav-submenu " + (isExpanded ? 'isActive' : '') }, reducer(item.tree, openItems))) : null));
};
/**
* This function is pulled out and named so that it can be used by both FlyOutNode and generateFlyoutContents
* @param acc an array
* @param cur a flyout item
*/
var reducer = function (tree, openItems) {
return tree.reduce(function (acc, cur, idx) { return __spreadArray(__spreadArray([], acc), [
React.createElement(FlyOutNode, { key: cur.title + idx, item: cur, openItems: openItems, reducer: reducer }),
]); }, []);
};
var generateFlyoutContents = function (flyoutSections, openItems) {
return flyoutSections.map(function (section, idx) { return (React.createElement("section", { key: idx },
section.heading && (React.createElement("div", { className: "Nav-sectionHeading u-colorNeutral7 u-textUppercase u-textBold u-fontSizeXs" }, section.heading)),
React.createElement("div", { className: "Nav-sectionItems" },
React.createElement("ul", { className: "" + (section.tree.length > 1 ? 'Nav-multi' : 'Nav-single') }, reducer(section.tree, openItems))))); });
};
var Nav = function (_a) {
var className = _a.className, mods = _a.mods, children = _a.children, style = _a.style, otherProps = _a.otherProps, headerItem = _a.headerItem, flyoutSections = _a.flyoutSections, includeOverlay = _a.includeOverlay, openItems = _a.openItems, testId = _a.testId;
var _b = React.useState(false), isCollapsed = _b[0], setCollapsed = _b[1];
var _c = React.useState(false), isFlyoutActive = _c[0], setIsFlyoutActive = _c[1];
var cname = helpers_1.getClassName('Nav', isFlyoutActive && 'is-flyout', isCollapsed && 'is-collapsed', className, mods);
var navHeaderIconClass = helpers_1.getClassName('Nav-headerIcon');
return (React.createElement(React.Fragment, null,
isFlyoutActive && includeOverlay && (React.createElement("div", { className: "Nav-overlay", onClick: function () { return setIsFlyoutActive(!isFlyoutActive); }, onKeyDown: function () { return setIsFlyoutActive(!isFlyoutActive); }, tabIndex: 0, role: "button", "aria-label": "Close Overlay" })),
React.createElement("nav", __assign({ className: cname, style: style, "data-testid": testId }, otherProps),
headerItem ? (React.createElement("div", { className: "Nav-header u-textSemiBold", onClick: function () { return !isCollapsed && setIsFlyoutActive(!isFlyoutActive); }, onKeyDown: function () { return setIsFlyoutActive(!isFlyoutActive); }, tabIndex: 0, role: "button" },
React.createElement("div", { className: navHeaderIconClass },
React.createElement(Avatar_1.Avatar, { src: headerItem.image, size: "fill" })),
React.createElement("div", { className: "u-sizeFill Nav-itemTitle u-spaceLeftSm" },
React.createElement("span", { className: "Nav-itemTitle", title: headerItem.title }, headerItem.title),
(headerItem === null || headerItem === void 0 ? void 0 : headerItem.subtitle) && (React.createElement("span", { className: "Nav-itemSubtitle", title: headerItem.subtitle }, headerItem.subtitle))),
flyoutSections && (React.createElement("div", { className: "Nav-caret" },
React.createElement(Icon_1.Icon, { mods: "u-fontSizeMd u-spaceNone", name: "down" }))))) : null,
React.createElement("div", { className: "Nav-body" }, isFlyoutActive ? generateFlyoutContents(flyoutSections, openItems) : React.createElement("ul", null, children)),
!isFlyoutActive && (React.createElement("div", { className: "Nav-footer", onKeyDown: function () { return setCollapsed(!isCollapsed); }, onClick: function () { return setCollapsed(!isCollapsed); }, role: "button", tabIndex: 0 },
React.createElement(Icon_1.Icon, { name: "left" }),
" ",
React.createElement("span", { className: "Nav-itemTitle" }, "Collapse Menu"))))));
};
Item.propTypes = itemPropTypes;
Nav.Item = Item;
Nav.propTypes = navPropTypes;
Nav.defaultProps = {
children: null,
mods: null,
style: {},
testId: null,
otherProps: {},
};
exports.default = Nav;