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

376 lines (370 loc) 11.5 kB
import { withActions } from "@storybook/addon-actions/decorator"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; import { ref } from "lit/directives/ref.js"; import { createShadowHostClass } from "../../providers/shadow-dom/shadow-host-helper"; const meta = { title: 'Components/Menu', component: 'modus-wc-menu', args: { orientation: 'vertical', 'selection-mode': 'single', size: 'md', }, argTypes: { orientation: { control: { type: 'select' }, options: ['horizontal', 'vertical'], }, 'selection-mode': { control: { type: 'select' }, options: ['single', 'multiple'], }, size: { control: { type: 'select' }, options: ['xs', 'sm', 'md', 'lg'], }, }, decorators: [withActions], parameters: { actions: { handles: ['menuFocusout', 'menuSelectionChange', 'itemSelect'], }, }, }; export default meta; export const Default = { render: (args) => { // prettier-ignore return html ` <modus-wc-menu aria-label="Menu" ?bordered=${args.bordered} custom-class=${ifDefined(args['custom-class'])} orientation=${ifDefined(args.orientation)} selection-mode=${ifDefined(args['selection-mode'])} size=${ifDefined(args.size)} > <modus-wc-menu-item label="Small" value="1" size="sm" ></modus-wc-menu-item> <modus-wc-menu-item label="Medium" value="2"></modus-wc-menu-item> <modus-wc-menu-item label="Large" value="3" size="lg" ></modus-wc-menu-item> <modus-wc-menu-item label="Bordered" value="3" bordered="true" ></modus-wc-menu-item> <modus-wc-menu-item label="With Sub-label" value="3" sub-label="Sub-label" ></modus-wc-menu-item> <modus-wc-menu-item label="Selected" value="3" selected="true" ></modus-wc-menu-item> <modus-wc-menu-item label="With Start Icon" value="3" > <modus-wc-icon slot="start-icon" name="info"></modus-wc-icon> </modus-wc-menu-item> <modus-wc-menu-item label="Disabled" value="3" disabled="true" ></modus-wc-menu-item> </modus-wc-menu> `; }, }; export const MultiSelect = { args: { 'selection-mode': 'multiple', }, render: (args) => { let outputEl; const handleSelectionChange = (e) => { if (!outputEl) return; const { selectedItems } = e.detail; outputEl.textContent = selectedItems.length > 0 ? `Selected: ${selectedItems.map((i) => i.getAttribute('value')).join(', ')}` : 'Selected: none'; }; // prettier-ignore return html ` <modus-wc-menu aria-label="Menu" ?bordered=${args.bordered} custom-class=${ifDefined(args['custom-class'])} orientation=${ifDefined(args.orientation)} selection-mode=${ifDefined(args['selection-mode'])} size=${ifDefined(args.size)} @menuSelectionChange=${handleSelectionChange} > <modus-wc-menu-item label="Menu Item 1" value="1" ></modus-wc-menu-item> <modus-wc-menu-item label="Menu Item 2" value="2"></modus-wc-menu-item> <modus-wc-menu-item label="Menu Item 3" value="3" ></modus-wc-menu-item> <modus-wc-menu-item label="Menu Item 4" value="4" bordered="true" ></modus-wc-menu-item> <modus-wc-menu-item label="Menu Item 5" value="5" sub-label="Menu Item 5 Sub-label" ></modus-wc-menu-item> </modus-wc-menu> <p ${ref((el) => { outputEl = el; })} style="font-size: 0.875rem; margin-top: 0.5rem; color: var(--modus-wc-color-gray-6);">Selected: none</p> `; }, }; export const CustomMenu = { render: () => { // prettier-ignore return html ` <style> .custom-menu-width { width: 400px; } .custom-flex-row { display: flex; align-items: center; } .custom-nested-row { padding-inline-start: 3rem; } .custom-justify-end { margin-left: auto; } .green-square { height: 18px; width: 18px; background-color: green; } .red-square { height: 18px; width: 18px; background-color: red; } </style> <modus-wc-menu aria-label="Custom menu" custom-class="custom-menu-width" > <li> <div class="custom-flex-row"> <modus-wc-icon decorative="true" name="expand_more"></modus-wc-icon> <modus-wc-button aria-label="Visible button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Visible icon" name="visibility_on"></modus-wc-icon> </modus-wc-button> <div>Parent</div> <div class="custom-justify-end"> <modus-wc-button aria-label="Actions button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Actions icon" name="more_vertical"></modus-wc-icon> </modus-wc-button> </div> </div> </li> <li> <div class="custom-flex-row custom-nested-row"> <modus-wc-button aria-label="Visible button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Visible icon" name="visibility_on"></modus-wc-icon> </modus-wc-button> <div class="green-square"></div> <div>Child</div> <div class="custom-justify-end"> <modus-wc-button aria-label="Actions button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Actions icon" name="more_vertical"></modus-wc-icon> </modus-wc-button> </div> </div> </li> <li> <div class="custom-flex-row custom-nested-row"> <modus-wc-button aria-label="Visible button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Invisible icon" name="visibility_off"></modus-wc-icon> </modus-wc-button> <div class="red-square"></div> <div>Child</div> <div class="custom-justify-end"> <modus-wc-button aria-label="Actions button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Actions icon" name="more_vertical"></modus-wc-icon> </modus-wc-button> </div> </div> </li> <li> <div class="custom-flex-row"> <modus-wc-icon decorative="true" name="chevron_right"></modus-wc-icon> <modus-wc-button aria-label="Visible button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Visible icon" name="visibility_on"></modus-wc-icon> </modus-wc-button> <div>Parent</div> <div class="custom-justify-end"> <modus-wc-button aria-label="Actions button" size="sm" shape="circle" variant="borderless"> <modus-wc-icon aria-label="Actions icon" name="more_vertical"></modus-wc-icon> </modus-wc-button> </div> </div> </li> </modus-wc-menu> `; }, }; export const CollapsibleMenu = { render: () => { return html ` <style> .menu-width { width: 400px; } </style> <modus-wc-menu custom-class="menu-width"> <modus-wc-menu-item label="Charts" .hasSubmenu=${true} id="charts-menu" 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> <script> // Adding this block to show how to set submenu properties via JS // document.addEventListener('DOMContentLoaded', () => { // const chartsMenu = document.querySelector('#charts-menu'); // const reportsMenu = document.querySelector('#reports-menu'); // const chartsSubMenu = document.querySelector('#charts-submenu'); // const reportsSubMenu = document.querySelector('#reports-submenu'); // // 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> `; }, }; export const ShadowDomParent = { render: (args) => { // Create a unique shadow host for menu component if (!customElements.get('menu-shadow-host')) { const MenuShadowHost = createShadowHostClass({ componentTag: 'modus-wc-menu', propsMapper: (v, el) => { const menuEl = el; menuEl.ariaLabel = 'Shadow DOM Menu'; menuEl.bordered = Boolean(v.bordered); menuEl.customClass = v['custom-class'] || ''; menuEl.orientation = v.orientation || 'vertical'; menuEl.size = v.size || 'md'; // Only set innerHTML once on initial creation if (!el.querySelector('modus-wc-menu-item')) { el.innerHTML = ` <modus-wc-menu-item label="Small" value="1" size="sm" ></modus-wc-menu-item> <modus-wc-menu-item label="Medium" value="2"></modus-wc-menu-item> <modus-wc-menu-item label="Large" value="3" size="lg" ></modus-wc-menu-item> <modus-wc-menu-item label="Bordered" value="3" bordered="true" ></modus-wc-menu-item> <modus-wc-menu-item label="With Sub-label" value="3" sub-label="Sub-label" ></modus-wc-menu-item> <modus-wc-menu-item label="Selected" value="3" selected="true" ></modus-wc-menu-item> <modus-wc-menu-item label="With Start Icon" value="3" > <modus-wc-icon slot="start-icon" name="info"></modus-wc-icon> </modus-wc-menu-item> <modus-wc-menu-item label="Disabled" value="3" disabled="true" ></modus-wc-menu-item> `; } }, }); customElements.define('menu-shadow-host', MenuShadowHost); } return html `<menu-shadow-host .props=${Object.assign({}, args)}></menu-shadow-host>`; }, };