UNPKG

@trimble-oss/moduswebcomponents

Version:

Modus Web Components is a modern, accessible UI library built with Stencil JS that provides reusable web components following Trimble's Modus design system. This updated version focuses on improved flexibility, enhanced theming options, comprehensive cust

490 lines (467 loc) 17.3 kB
import { withActions } from "@storybook/addon-actions/decorator"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; const meta = { title: 'Components/Side Navigation', component: 'modus-wc-side-navigation', args: { 'collapse-on-click-outside': true, expanded: false, 'max-width': '256px', mode: 'push', 'target-content': '.panel-content', }, argTypes: { 'max-width': { control: { type: 'text' }, description: 'Maximum width of the side navigation panel in an expanded state.', }, mode: { control: { type: 'select' }, options: ['overlay', 'push'], description: 'Display mode of the side navigation (overlay or push).', }, }, decorators: [withActions], parameters: { layout: 'padded', actions: { handles: ['expandedChange', 'itemSelect'], }, }, }; export default meta; export const Default = { render: (args) => { const handleMenuOpenChange = (e) => { const eventSource = e.target; const storyContainer = eventSource === null || eventSource === void 0 ? void 0 : eventSource.closest('.layout-with-navbar'); let sideNav; if (storyContainer) { sideNav = storyContainer.querySelector('modus-wc-side-navigation'); } else { sideNav = document.querySelector('modus-wc-side-navigation'); } if (sideNav) { sideNav.expanded = e.detail; } }; return html ` <style> .layout-with-navbar { display: flex; flex-direction: column; height: 100%; } .main-content-row { display: flex; flex: 1; overflow: hidden; } .modus-wc-menu-item-labels { padding: 0 16px; } .navbar { box-shadow: none; } .panel-content { margin-left: 4rem; padding: 10px; } .side-navigation { height: 500px; align-self: flex-start; position: relative; } </style> <div class="layout-with-navbar"> <modus-wc-navbar app-title="Modus App" class="navbar" logo="/assets/logo.svg" @mainMenuOpenChange=${handleMenuOpenChange} .userCard=${{ avatarAlt: 'User Avatar', avatarSrc: 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg', email: 'user@trimble.com', name: 'Sonic the Hedgehog', }} .visibility=${{ ai: true, apps: true, help: true, mainMenu: true, notifications: true, search: true, searchInput: false, user: true, }} style="z-index: 2;" ></modus-wc-navbar> <div class="main-content-row"> <modus-wc-side-navigation class="side-navigation" collapse-on-click-outside=${args['collapse-on-click-outside']} custom-class=${ifDefined(args['custom-class'])} expanded=${args.expanded} max-width=${args['max-width']} mode=${ifDefined(args.mode)} target-content=${ifDefined(args['target-content'])} > <modus-wc-menu size="lg"> <modus-wc-menu-item label="home" selected> <modus-wc-icon slot="start-icon" name="home"></modus-wc-icon> </modus-wc-menu-item> <modus-wc-menu-item label="profile"> <modus-wc-icon slot="start-icon" name="person"></modus-wc-icon> </modus-wc-menu-item> <modus-wc-menu-item label="settings"> <modus-wc-icon slot="start-icon" name="gears"></modus-wc-icon> </modus-wc-menu-item> </modus-wc-menu> </modus-wc-side-navigation> <div class="panel-content"> <div id="overview"> <p> The side navigation of an application provides context through accessible menu options and positions a consistent component to connect to various pages in the application. </p> <p> The side navigation is a collapsible side content of the site’s pages. It is located alongside the page’s primary content. The component is designed to add side content to a fullscreen application. It is activated through the “hamburger” menu in the Navbar. </p> </div> </div> </div> </div> <script> // Added this block to demonstrate how to handle menu selection, side navigation toggle, and navbar visibility settings using JavaScript. // const menuItems = document.querySelectorAll('modus-wc-menu-item'); // menuItems.forEach((item) => { // item.addEventListener('itemSelect', () => { // menuItems.forEach((i) => i.removeAttribute('selected')); // item.setAttribute('selected', ''); // }); // }); // const handleMenuOpenChange = (e) => { // const eventSource = e.target; // const storyContainer = eventSource?.closest('.layout-with-navbar'); // let sideNav; // if (storyContainer) { // sideNav = storyContainer.querySelector('modus-wc-side-navigation'); // } else { // sideNav = document.querySelector('modus-wc-side-navigation'); // } // if (sideNav) { // sideNav.expanded = e.detail; // } // }; // const visibility = { // ai: true, // apps: true, // help: true, // mainMenu: true, // notifications: true, // search: true, // searchInput: false, // user: true, // }; // const userCard = { // avatarAlt: 'User Avatar', // avatarSrc: // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg', // email: 'user@trimble.com', // name: 'Sonic the Hedgehog', // }; // const navbar = document.querySelector('modus-wc-navbar'); // const sideNav = document.querySelector('modus-wc-side-navigation'); // navbar.visibility = visibility; // navbar.userCard = userCard; // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange); </script> `; }, }; export const WithSubmenu = { render: (args) => { const handleMenuOpenChange = (e) => { const eventSource = e.target; const storyContainer = eventSource === null || eventSource === void 0 ? void 0 : eventSource.closest('.layout-with-navbar'); let sideNav; if (storyContainer) { sideNav = storyContainer.querySelector('modus-wc-side-navigation'); if (sideNav) { // Toggle the side nav state (navbar and side nav can be out of sync) const sideNavEl = sideNav; sideNavEl.expanded = e.detail; } } }; const handleExpandedChange = (e) => { // Collapse all menu items when side nav closes if (!e.detail) { const eventSource = e.target; const menuItems = eventSource.querySelectorAll('modus-wc-menu-item'); menuItems.forEach((menuItem) => { const item = menuItem; if (item.hasSubmenu && typeof item.collapseSubmenu === 'function') { void item.collapseSubmenu(); } }); } }; return html ` <style> .layout-with-navbar { box-shadow: rgba(36, 35, 45, 0.3) 1px 0 4px; display: flex; flex-direction: column; height: 100%; } .main-content-row { display: flex; flex: 1; overflow: hidden; } .panel-content { margin-left: 4rem; padding: 10px; } .side-navigation { align-self: flex-start; height: 500px; position: relative; } .flex-right { float: right; display: flex; margin-left: 50px; } .flex-right:hover { background-color: unset; } .flex-right:active { background-color: unset !important; } </style> <div class="layout-with-navbar"> <modus-wc-navbar app-title="Modus App" class="navbar" id="main-navbar" logo="/assets/logo.svg" @mainMenuOpenChange=${handleMenuOpenChange} .userCard=${{ avatarAlt: 'User Avatar', avatarSrc: 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg', email: 'user@trimble.com', name: 'Sonic the Hedgehog', }} .visibility=${{ ai: true, apps: true, help: true, mainMenu: true, notifications: true, search: true, searchInput: false, user: true, }} style="z-index: 2;" ></modus-wc-navbar> <div class="main-content-row"> <modus-wc-side-navigation class="side-navigation" collapse-on-click-outside=${args['collapse-on-click-outside']} custom-class=${ifDefined(args['custom-class'])} expanded=${args.expanded} id="main-side-nav" max-width=${args['max-width']} mode=${ifDefined(args.mode)} target-content=${ifDefined(args['target-content'])} @expandedChange=${handleExpandedChange} > <modus-wc-menu> <li> <div class="flex-right"> <modus-wc-button custom-class="menu-icon" color="tertiary"> <modus-wc-icon name="filter" size="xs" variant="solid" ></modus-wc-icon> </modus-wc-button> <modus-wc-button custom-class="menu-icon" color="tertiary"> <modus-wc-icon name="settings" size="xs" variant="solid" ></modus-wc-icon> </modus-wc-button> <modus-wc-button custom-class="menu-icon" color="tertiary"> <modus-wc-icon name="more_vertical" size="xs" variant="solid" ></modus-wc-icon> </modus-wc-button> </div> </li> <modus-wc-menu-item label="Charts" id="charts-menu" .hasSubmenu=${true} value="charts" > <modus-wc-icon slot="start-icon" decorative="true" name="bar_graph" ></modus-wc-icon> <modus-wc-menu .isSubMenu=${true} id="charts-submenu"> <modus-wc-menu-item label="Bar Chart" value="bar-chart"> </modus-wc-menu-item> <modus-wc-menu-item label="Line Chart" value="line-chart"> </modus-wc-menu-item> </modus-wc-menu> </modus-wc-menu-item> <modus-wc-menu-item label="Calendar" value="calendar"> <modus-wc-icon slot="start-icon" decorative="true" name="calendar" ></modus-wc-icon> </modus-wc-menu-item> <modus-wc-menu-item label="Reports" .hasSubmenu=${true} id="reports-menu" value="reports" > <modus-wc-icon slot="start-icon" decorative="true" name="master_data" ></modus-wc-icon> <modus-wc-menu .isSubMenu=${true} id="reports-submenu"> <modus-wc-menu-item label="Monthly Report" value="monthly-report" > </modus-wc-menu-item> <modus-wc-menu-item label="Annual Report" value="annual-report" > </modus-wc-menu-item> </modus-wc-menu> </modus-wc-menu-item> </modus-wc-menu> </modus-wc-side-navigation> <div class="panel-content"> <div id="overview"> <h3>Side Navigation with Submenu</h3> <p> This example demonstrates the side navigation component with submenus, allowing for a more organized and hierarchical navigation structure. </p> <p> When the side navigation closes, the expandedChange event is used to call the collapseSubmenu() method on each menu item. This keeps the side navigation component generic while allowing the story to coordinate behavior between components. </p> <p> Menu items inside a collapsed side nav cannot expand their submenus, ensuring a consistent user experience. </p> </div> </div> </div> </div> <script> // const handleMenuOpenChange = (e) => { // const eventSource = e.target; // const storyContainer = eventSource?.closest('.layout-with-navbar'); // let sideNav; // if (storyContainer) { // sideNav = storyContainer.querySelector('modus-wc-side-navigation'); // } else { // sideNav = document.querySelector('modus-wc-side-navigation'); // } // if (sideNav) { // sideNav.expanded = e.detail; // } // }; // const handleExpandedChange = (e) => { // // Collapse all menu items when side nav closes // if (!e.detail) { // const eventSource = e.target; // const menuItems = // eventSource.querySelectorAll('modus-wc-menu-item'); // menuItems.forEach((menuItem) => { // if ( // menuItem.hasSubmenu && // typeof menuItem.collapseSubmenu === 'function' // ) { // menuItem.collapseSubmenu(); // } // }); // } // }; // // Adding event listeners and setting properties here as the storybook initially does not load them // document.addEventListener('DOMContentLoaded', () => { // const navbar = document.querySelector('#main-navbar'); // const sideNav = document.querySelector('#main-side-nav'); // const chartsMenu = document.querySelector('#charts-menu'); // const reportsMenu = document.querySelector('#reports-menu'); // const chartsSubMenu = document.querySelector('#charts-submenu'); // const reportsSubMenu = document.querySelector('#reports-submenu'); // if (navbar) { // // Set navbar properties // navbar.userCard = { // avatarAlt: 'User Avatar', // avatarSrc: // 'https://i1.sndcdn.com/artworks-000405996468-wmh3uv-t500x500.jpg', // email: 'user@trimble.com', // name: 'Sonic the Hedgehog', // }; // navbar.visibility = { // ai: true, // apps: true, // help: true, // mainMenu: true, // notifications: true, // search: true, // searchInput: false, // user: true, // }; // navbar.addEventListener('mainMenuOpenChange', handleMenuOpenChange); // } // if (sideNav) { // sideNav.addEventListener('expandedChange', handleExpandedChange); // } // // Set hasSubmenu property for menu items with submenus // [chartsMenu, reportsMenu].forEach((menuItem) => { // if (menuItem) { // menuItem.hasSubmenu = true; // } // }); // // Set isSubMenu for all submenu elements // [chartsSubMenu, reportsSubMenu].forEach((submenu) => { // if (submenu) { // submenu.isSubMenu = true; // } // }); // }); // </script> `; }, };