UNPKG

@teamsnap/teamsnap-ui

Version:

a CSS component library for TeamSnap

202 lines (201 loc) 11.2 kB
"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;