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

155 lines (152 loc) 6.47 kB
import { withActions } from "@storybook/addon-actions/decorator"; import { html } from "lit"; import { ifDefined } from "lit/directives/if-defined.js"; const meta = { title: 'Components/ThemeSwitcher', component: 'modus-wc-theme-switcher', args: { 'custom-class': undefined, 'initial-theme': undefined, }, decorators: [withActions], parameters: { actions: { handles: ['themeChange'], }, }, }; export default meta; // When no data-theme is set on the root element, default to the design system's base theme "modus-modern-light" const getCurrentTheme = () => { const dataTheme = document.documentElement.getAttribute('data-theme') || 'modus-modern-light'; const mode = dataTheme.endsWith('-dark') ? 'dark' : 'light'; const theme = dataTheme.replace(`-${mode}`, ''); return { theme, mode }; }; const Template = { // prettier-ignore render: (args) => { const currentTheme = getCurrentTheme(); return html ` <modus-wc-theme-provider .initialTheme=${currentTheme}> <modus-wc-theme-switcher aria-label="Theme toggle" custom-class=${ifDefined(args['custom-class'])} ></modus-wc-theme-switcher> </modus-wc-theme-provider> `; }, }; export const Default = Object.assign({}, Template); // New story for testing theme configurations const ThemeTestTemplate = { render: () => { const currentTheme = getCurrentTheme(); return html ` <modus-wc-theme-provider .initialTheme=${currentTheme}> <div style="padding: 40px"> <h2 style="text-align: center; color: var(--mwc-color-on-surface);"> Theme Configuration Test </h2> <p style="text-align: center; color: var(--mwc-color-on-surface-secondary); margin-bottom: 30px;" > This story matches the global Storybook theme </p> <div style="display: flex; gap: 10px; flex-wrap: wrap; justify-content: center; margin-bottom: 30px;" > <modus-wc-button color="primary">Primary Button</modus-wc-button> <modus-wc-button color="secondary" >Secondary Button</modus-wc-button > <modus-wc-button color="tertiary">Tertiary Button</modus-wc-button> <modus-wc-button color="danger">Danger Button</modus-wc-button> </div> <div style="display: flex; gap: 15px; flex-wrap: wrap; justify-content: center; align-items: center;" > <modus-wc-badge color="primary">Badge</modus-wc-badge> <modus-wc-badge color="secondary">Badge 2</modus-wc-badge> <modus-wc-chip label="Chip 1"></modus-wc-chip> <modus-wc-chip label="Chip 2" active></modus-wc-chip> <modus-wc-switch label="Switch"></modus-wc-switch> </div> </div> </modus-wc-theme-provider> `; }, }; export const ThemeTest = Object.assign(Object.assign({}, ThemeTestTemplate), { parameters: { docs: { description: { story: 'This example syncs with the active Storybook theme. Toggle between light and dark modes using the theme switcher on the default story to see the components adapt accordingly.', }, }, } }); export const ShadowDomParent = { render: (args) => { if (!customElements.get('theme-switcher-shadow-host')) { class ThemeSwitcherShadowHost extends HTMLElement { constructor() { super(); this.themeObserver = null; this.sr = this.attachShadow({ mode: 'open' }); } connectedCallback() { if (this.sr.childElementCount) return; // Sync data-theme so CSS variables work inside shadow root const wrapper = document.createElement('div'); wrapper.style.display = 'contents'; const syncTheme = () => { const theme = document.documentElement.getAttribute('data-theme'); if (theme) wrapper.setAttribute('data-theme', theme); }; syncTheme(); this.themeObserver = new MutationObserver(syncTheme); this.themeObserver.observe(document.documentElement, { attributes: true, attributeFilter: ['data-theme'], }); // Create provider + switcher together here (not in constructor) so // provider connects first and initializes themeStore before the // switcher reads themeStore.state.mode for its isDarkMode field const provider = document.createElement('modus-wc-theme-provider'); provider.initialTheme = getCurrentTheme(); const switcher = document.createElement('modus-wc-theme-switcher'); switcher.setAttribute('aria-label', 'Theme toggle'); provider.appendChild(switcher); wrapper.appendChild(provider); this.sr.appendChild(wrapper); if (this._props) this.applyProps(); } disconnectedCallback() { var _a; (_a = this.themeObserver) === null || _a === void 0 ? void 0 : _a.disconnect(); this.themeObserver = null; } set props(v) { this._props = v; this.applyProps(); } get props() { return this._props; } applyProps() { const switcher = this.sr.querySelector('modus-wc-theme-switcher'); if (!switcher || !this._props) return; switcher.customClass = this._props['custom-class'] || ''; } } customElements.define('theme-switcher-shadow-host', ThemeSwitcherShadowHost); } return html `<theme-switcher-shadow-host .props=${Object.assign({}, args)} ></theme-switcher-shadow-host>`; }, };