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

303 lines (286 loc) 11.3 kB
import { withActions } from "@storybook/addon-actions/decorator"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; import { createShadowHostClass } from "../../providers/shadow-dom/shadow-host-helper"; const meta = { title: 'Components/Button Group', component: 'modus-wc-button-group', args: { variant: 'outlined', color: 'primary', disabled: false, orientation: 'horizontal', 'selection-type': 'default', }, argTypes: { variant: { control: { type: 'select' }, options: ['borderless', 'filled', 'outlined'], }, color: { control: { type: 'select' }, options: [ 'primary', 'secondary', 'tertiary', 'warning', 'danger', 'neutral', ], }, disabled: { control: 'boolean' }, orientation: { control: { type: 'select' }, options: ['horizontal', 'vertical'], }, 'selection-type': { control: { type: 'select' }, options: ['default', 'single', 'multiple'], }, }, decorators: [withActions], parameters: { actions: { handles: ['buttonSelectionChange', 'buttonGroupClick'], }, }, }; export default meta; const Template = { render: (args) => { // prettier-ignore return html ` <modus-wc-button-group variant=${ifDefined(args.variant)} color=${ifDefined(args.color)} ?disabled=${(args.disabled)} orientation=${ifDefined(args.orientation)} selection-type=${ifDefined(args['selection-type'])} > <modus-wc-button>Button 1</modus-wc-button> <modus-wc-button>Button 2</modus-wc-button> <modus-wc-button>Button 3</modus-wc-button> </modus-wc-button-group> `; }, }; export const Default = Object.assign({}, Template); export const Vertical = Object.assign(Object.assign({}, Template), { args: { variant: 'outlined', orientation: 'vertical', } }); export const SplitButton = { render: () => { // prettier-ignore return html ` <script> const handleItemSelect = (event) => { // Update the "Selected Value" label const selectedValue = event.detail.value; const displayElement = document.querySelector('#selected-value'); if (displayElement) { displayElement.textContent = selectedValue; } // Close the dropdown menu when an item is selected const dropdownMenu = event.target; const dropdownMenuElement = dropdownMenu.closest( 'modus-wc-dropdown-menu' ); if (dropdownMenuElement) { dropdownMenuElement.menuVisible = false; } }; window.addEventListener('DOMContentLoaded', () => { const menuItems = document.querySelectorAll('#split-button-menu modus-wc-menu-item'); menuItems.forEach(item => item.addEventListener('itemSelect', handleItemSelect) ); }); </script> <div style="display: flex; flex-direction: column; gap: 16px; min-height: 300px;"> <modus-wc-button-group variant="outlined"> <modus-wc-button>Save Document</modus-wc-button> <modus-wc-dropdown-menu menu-placement="bottom-end" menu-size="lg" > <div slot="button"> <modus-wc-icon name="expand_more" size="16"></modus-wc-icon> </div> <div slot="menu" id="split-button-menu"> <modus-wc-menu-item label="Save as Draft" value="Save as Draft"></modus-wc-menu-item> <modus-wc-menu-item label="Save as Template" value="Save as Template"></modus-wc-menu-item> <modus-wc-menu-item label="Save and Share" value="Save and Share"></modus-wc-menu-item> </div> </modus-wc-dropdown-menu> </modus-wc-button-group> <div style="display: flex; gap: 8px;"> <modus-wc-typography hierarchy="h4">Selected Option:</modus-wc-typography> <modus-wc-typography id="selected-value"></modus-wc-typography> </div> </div> `; }, }; export const SingleSelection = { render: () => { // prettier-ignore return html ` <div style="display: flex; flex-direction: column; gap: 16px;"> <div> <h4 style="margin-bottom: 8px;">Single Selection (Only one button can be active at a time)</h4> <modus-wc-button-group selection-type="single" variant="outlined"> <modus-wc-button>Option 1</modus-wc-button> <modus-wc-button pressed>Option 2</modus-wc-button> <modus-wc-button>Option 3</modus-wc-button> <modus-wc-button>Option 4</modus-wc-button> </modus-wc-button-group> </div> <div> <h4 style="margin-bottom: 8px;">Vertical Single Selection</h4> <modus-wc-button-group selection-type="single" orientation="vertical" variant="outlined"> <modus-wc-button pressed>Option 1</modus-wc-button> <modus-wc-button>Option 2</modus-wc-button> <modus-wc-button>Option 3</modus-wc-button> <modus-wc-button>Option 4</modus-wc-button> </modus-wc-button-group> </div> </div> `; }, }; export const MultipleSelection = { render: () => { // prettier-ignore return html ` <div style="display: flex; flex-direction: column; gap: 16px;"> <div> <h4 style="margin-bottom: 8px;">Multiple Selection (Multiple buttons can be active)</h4> <modus-wc-button-group selection-type="multiple" variant="outlined"> <modus-wc-button pressed>Bold</modus-wc-button> <modus-wc-button>Italic</modus-wc-button> <modus-wc-button pressed>Underline</modus-wc-button> <modus-wc-button>Strikethrough</modus-wc-button> </modus-wc-button-group> </div> <div> <h4 style="margin-bottom: 8px;">Multiple Selection with Icons</h4> <modus-wc-button-group selection-type="multiple" variant="outlined" color="primary"> <modus-wc-button pressed icon-only aria-label="Align left"> <modus-wc-icon name="align_left" size="16"></modus-wc-icon> </modus-wc-button> <modus-wc-button pressed icon-only aria-label="Align center"> <modus-wc-icon name="align_top" size="16"></modus-wc-icon> </modus-wc-button> <modus-wc-button icon-only aria-label="Align right"> <modus-wc-icon name="align_right" size="16"></modus-wc-icon> </modus-wc-button> <modus-wc-button icon-only aria-label="Align justify"> <modus-wc-icon name="align_bottom" size="16"></modus-wc-icon> </modus-wc-button> </modus-wc-button-group> </div> </div> `; }, }; export const SelectionEvent = { render: () => { // prettier-ignore return html ` <script> window.addEventListener('DOMContentLoaded', () => { const buttonGroup = document.querySelector('#event-demo-group'); if (buttonGroup) { buttonGroup.addEventListener('buttonSelectionChange', (event) => { const selectedButtons = event.detail.selectedButtons; const buttonTexts = selectedButtons.map(btn => btn.textContent.trim()); // Update the display const displayElement = document.querySelector('#selected-buttons-display'); if (displayElement) { displayElement.textContent = buttonTexts.length > 0 ? buttonTexts.join(', ') : 'None'; } }); } }); </script> <div style="display: flex; flex-direction: column; gap: 16px;"> <div> <modus-wc-button-group id="event-demo-group" selection-type="single" variant="outlined" color="primary" > <modus-wc-button>Apple</modus-wc-button> <modus-wc-button>Banana</modus-wc-button> <modus-wc-button>Cherry</modus-wc-button> <modus-wc-button>Date</modus-wc-button> </modus-wc-button-group> </div> <div style="display: flex; gap: 8px;"> <modus-wc-typography hierarchy="h4">Selected Button(s):</modus-wc-typography> <modus-wc-typography id="selected-buttons-display"></modus-wc-typography> </div> `; }, }; export const ShadowDomParent = { render: (args) => { if (!customElements.get('button-group-shadow-host')) { const ButtonGroupShadowHost = createShadowHostClass({ componentTag: 'modus-wc-button-group', propsMapper: (v, el) => { const bgEl = el; bgEl.variant = v.variant; bgEl.color = v.color; bgEl.disabled = Boolean(v.disabled); bgEl.orientation = v.orientation; bgEl.selectionType = v['selection-type']; if (!el.hasChildNodes()) { el.innerHTML = `<modus-wc-button>Button 1</modus-wc-button><modus-wc-button>Button 2</modus-wc-button><modus-wc-button>Button 3</modus-wc-button>`; } }, }); customElements.define('button-group-shadow-host', ButtonGroupShadowHost); } return html `<button-group-shadow-host .props=${Object.assign({}, args)} ></button-group-shadow-host>`; }, }; export const Migration = { parameters: { docs: { description: { story: ` #### Breaking Changes - The \`size\` prop has been removed. Button sizes are now controlled individually on each button within the group. - Selection state is now managed internally - the \`selected\` attribute on individual buttons is no longer used. - Shadow DOM has been removed (\`shadow: false\`) for better composability. #### Prop Mapping | 1.0 Prop | 2.0 Prop | Notes | |-----------------|-----------------|--------------------------------------------------------------------------| | aria-label | aria-label | Unchanged | | aria-disabled | - | Removed. Use \`disabled\` prop instead | | button-style | variant | Values changed: \`fill\` → \`filled\`, \`outline\` → \`outlined\` | | color | color | \`special\` color removed. Other values unchanged | | disabled | disabled | Unchanged | | - | orientation | New in 2.0. Controls horizontal/vertical layout | | selection-type | selection-type | Values changed: \`none\` → \`default\`, \`single\` and \`multiple\` unchanged | | size | - | Removed. Control size on individual buttons | #### Event Mapping | 1.0 Event | 2.0 Event | Notes | |------------------------|------------------------|------------------------------------------------------------| | buttonGroupClick | buttonGroupClick | Event detail changed: now includes \`{ button, isSelected }\` | | buttonSelectionChange | buttonSelectionChange | Returns array of selected buttons | `, }, }, controls: { disable: true }, canvas: { disable: true }, }, render: () => html `<div></div>`, };