@oicl/openbridge-webcomponents 2.0.0-next.117 → 2.0.0-next.119

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +37 -33
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +30 -24
  4. package/dist/ar/poi/poi-base.d.ts +6 -0
  5. package/dist/ar/poi/poi-base.d.ts.map +1 -1
  6. package/dist/ar/poi/poi-base.js.map +1 -1
  7. package/dist/ar/poi-button/poi-button.d.ts +2 -2
  8. package/dist/ar/poi-button/poi-button.js.map +1 -1
  9. package/dist/automation/vertical-line/vertical-line.d.ts +6 -0
  10. package/dist/automation/vertical-line/vertical-line.d.ts.map +1 -1
  11. package/dist/automation/vertical-line/vertical-line.js.map +1 -1
  12. package/dist/components/accordion-card/accordion-card.d.ts.map +1 -1
  13. package/dist/components/accordion-card/accordion-card.js.map +1 -1
  14. package/dist/components/advice-message-item/advice-message-item.d.ts +4 -2
  15. package/dist/components/advice-message-item/advice-message-item.d.ts.map +1 -1
  16. package/dist/components/advice-message-item/advice-message-item.js +4 -2
  17. package/dist/components/advice-message-item/advice-message-item.js.map +1 -1
  18. package/dist/components/app-menu/app-menu.d.ts +1 -1
  19. package/dist/components/app-menu/app-menu.js +1 -1
  20. package/dist/components/app-menu/app-menu.js.map +1 -1
  21. package/dist/components/brilliance-menu/brilliance-menu.d.ts +8 -4
  22. package/dist/components/brilliance-menu/brilliance-menu.d.ts.map +1 -1
  23. package/dist/components/brilliance-menu/brilliance-menu.js +8 -4
  24. package/dist/components/brilliance-menu/brilliance-menu.js.map +1 -1
  25. package/dist/components/check-button/check-button.js.map +1 -1
  26. package/dist/components/checkbox/checkbox.d.ts +2 -2
  27. package/dist/components/checkbox/checkbox.js.map +1 -1
  28. package/dist/components/command-menu/command-menu.d.ts +1 -1
  29. package/dist/components/command-menu/command-menu.js +1 -1
  30. package/dist/components/command-menu/command-menu.js.map +1 -1
  31. package/dist/components/dropdown-button/dropdown-button.d.ts +2 -2
  32. package/dist/components/dropdown-button/dropdown-button.js +2 -2
  33. package/dist/components/dropdown-button/dropdown-button.js.map +1 -1
  34. package/dist/components/menu-button/menu-button.d.ts.map +1 -1
  35. package/dist/components/menu-button/menu-button.js.map +1 -1
  36. package/dist/components/navigation-item/navigation-item.d.ts +1 -5
  37. package/dist/components/navigation-item/navigation-item.d.ts.map +1 -1
  38. package/dist/components/navigation-item/navigation-item.js +0 -8
  39. package/dist/components/navigation-item/navigation-item.js.map +1 -1
  40. package/dist/components/navigation-item-group/navigation-item-group.d.ts +2 -1
  41. package/dist/components/navigation-item-group/navigation-item-group.d.ts.map +1 -1
  42. package/dist/components/navigation-item-group/navigation-item-group.js +2 -1
  43. package/dist/components/navigation-item-group/navigation-item-group.js.map +1 -1
  44. package/dist/components/notification-button/notification-button.d.ts +1 -1
  45. package/dist/components/notification-button/notification-button.js +1 -1
  46. package/dist/components/notification-button/notification-button.js.map +1 -1
  47. package/dist/components/notification-message-item/notification-message-item.d.ts +4 -2
  48. package/dist/components/notification-message-item/notification-message-item.d.ts.map +1 -1
  49. package/dist/components/notification-message-item/notification-message-item.js +4 -2
  50. package/dist/components/notification-message-item/notification-message-item.js.map +1 -1
  51. package/dist/components/pivot-item/pivot-item.d.ts +1 -1
  52. package/dist/components/pivot-item/pivot-item.js +1 -1
  53. package/dist/components/pivot-item/pivot-item.js.map +1 -1
  54. package/dist/components/pivot-item-group/pivot-item-group.d.ts +1 -0
  55. package/dist/components/pivot-item-group/pivot-item-group.d.ts.map +1 -1
  56. package/dist/components/pivot-item-group/pivot-item-group.js.map +1 -1
  57. package/dist/components/slide-button/slide-button.d.ts.map +1 -1
  58. package/dist/components/slide-button/slide-button.js.map +1 -1
  59. package/dist/components/slider/slider.d.ts +2 -2
  60. package/dist/components/slider/slider.js +2 -2
  61. package/dist/components/slider/slider.js.map +1 -1
  62. package/dist/components/slider-double/slider-double.d.ts +2 -2
  63. package/dist/components/slider-double/slider-double.js +2 -2
  64. package/dist/components/slider-double/slider-double.js.map +1 -1
  65. package/dist/components/stepper-box/stepper-box.d.ts +4 -2
  66. package/dist/components/stepper-box/stepper-box.d.ts.map +1 -1
  67. package/dist/components/stepper-box/stepper-box.js +4 -2
  68. package/dist/components/stepper-box/stepper-box.js.map +1 -1
  69. package/dist/components/system-button/system-button.d.ts +1 -1
  70. package/dist/components/system-button/system-button.js +1 -1
  71. package/dist/components/system-button/system-button.js.map +1 -1
  72. package/dist/components/tabbed-card/tabbed-card.d.ts.map +1 -1
  73. package/dist/components/tabbed-card/tabbed-card.js.map +1 -1
  74. package/dist/components/toggle-button-option/toggle-button-option.d.ts +2 -1
  75. package/dist/components/toggle-button-option/toggle-button-option.d.ts.map +1 -1
  76. package/dist/components/toggle-button-option/toggle-button-option.js +2 -1
  77. package/dist/components/toggle-button-option/toggle-button-option.js.map +1 -1
  78. package/dist/components/toggle-button-vertical-group/toggle-button-vertical-group.js.map +1 -1
  79. package/dist/components/toggle-switch/toggle-switch.d.ts +1 -1
  80. package/dist/components/toggle-switch/toggle-switch.js +1 -1
  81. package/dist/components/toggle-switch/toggle-switch.js.map +1 -1
  82. package/dist/components/top-bar/top-bar.d.ts.map +1 -1
  83. package/dist/components/top-bar/top-bar.js.map +1 -1
  84. package/dist/components/topbar-message-item/topbar-message-item.js.map +1 -1
  85. package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.d.ts +1 -1
  86. package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.js +1 -1
  87. package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.js.map +1 -1
  88. package/package.json +3 -1
@@ -1 +1 @@
1
- {"version":3,"file":"system-button.js","sources":["../../../src/components/system-button/system-button.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {customElement} from '../../decorator.js';\nimport compentStyle from './system-button.css?inline';\nimport {property} from 'lit/decorators.js';\nimport '../icon-button/icon-button.js';\nimport {IconButtonVariant} from '../icon-button/icon-button.js';\nimport '../../icons/icon-configure.js';\nimport '../../icons/icon-com-microphone.js';\nimport '../../icons/icon-com-mic-muted-google.js';\nimport '../../icons/icon-wifi2-google.js';\nimport '../../icons/icon-wifi2-off-google.js';\nimport '../../icons/icon-sensor-gps-bad.js';\nimport '../../icons/icon-sensor-gps-low.js';\nimport '../../icons/icon-sensor-gps-medium.js';\nimport '../../icons/icon-sensor-gps-full.js';\nimport '../../icons/icon-sound-muted.js';\nimport '../../icons/icon-sound-no.js';\nimport '../../icons/icon-sound-low.js';\nimport '../../icons/icon-sound.js';\nimport '../button/button.js';\nimport '../battery-icon/battery-icon.js';\n\nexport enum SystemButtonVariant {\n condensed = 'condensed',\n expanded = 'expanded',\n actions = 'actions',\n}\n\nexport enum ActivePanel {\n microphone = 'microphone',\n volume = 'volume',\n systemIcons = 'system-icons',\n}\n\n/**\n * Describes the enabled state and current value for each system indicator displayed by `<obc-system-button>`.\n *\n * - `wifi`: WiFi status (enabled, connected, strength, network name)\n * - `audio`: Audio status (enabled, muted, volume)\n * - `microphone`: Microphone status (enabled, muted, sensitivity)\n * - `battery`: Battery status (enabled, level, charging)\n * - `gps`: GPS status (enabled, connected, quality)\n */\nexport interface SystemState {\n wifi?: {\n connected: boolean;\n networkName?: string;\n strength: 0 | 1 | 2 | 3 | 4; // Maps directly to icon variants\n };\n audio?: {\n muted: boolean;\n volume: number; // 0-100\n };\n microphone?: {\n muted: boolean;\n sensitivity: number; // 0-100\n };\n battery?: {\n level: number; // 0-100\n charging: boolean;\n poweredNotCharging?: boolean;\n notification?: boolean;\n };\n gps?: {\n connected: boolean;\n quality: 'bad' | 'low' | 'medium' | 'full'; // Maps to GPS icon variants\n };\n}\n\n/**\n * `<obc-system-button>` – A multi-state system status and quick-action button for displaying and controlling core system indicators.\n *\n * This component provides a compact, interactive summary of system-level statuses such as WiFi, audio, microphone, battery, and GPS. It can be used as a single icon button, an expanded status display, or a segmented set of quick-action buttons, depending on the chosen variant. Designed for use in application toolbars, system menus, or quick-access panels where users need to view and interact with system controls at a glance.\n *\n * Appears as an icon or set of icons representing real-time system states. Supports toggling panels for detailed control or configuration, and adapts its layout to suit condensed, expanded, or action-oriented contexts.\n *\n * ## Features\n *\n * - **Variants**:\n * - **Condensed**: Single icon button (typically a settings or system icon) for minimal space usage.\n * - **Expanded**: Horizontal button displaying a row of system status icons (WiFi, audio, microphone, battery, GPS) for quick visual overview.\n * - **Actions**: Segmented button group, each segment representing a system function (microphone, volume, system icons), with interactive actions for each.\n * - **Dynamic Iconography**: Icons update in real time to reflect system state (e.g., WiFi strength, battery level, mute status, GPS quality).\n * - **Quick Actions**: In actions variant, clicking a segment opens the corresponding control panel (e.g., microphone settings, volume slider).\n * - **State Awareness**: Each system indicator (WiFi, audio, microphone, battery, GPS) can be enabled/disabled independently, and their visual state reflects connection, mute, charge, or quality status.\n * - **Accessibility**: Button segments are keyboard accessible and support disabled state.\n * - **Customizable**: System state can be controlled via the `systemState` property, allowing for integration with live system data.\n *\n * ## Usage Guidelines\n *\n * Use `<obc-system-button>` to provide users with a compact, always-visible summary of key system statuses and quick access to related controls. Ideal for application toolbars, overlays, or system menus where users need to monitor and adjust system settings without leaving their current context.\n *\n * - Use the **condensed** variant for minimal UI or when only a single system menu entry is needed.\n * - Use the **expanded** variant to show multiple system statuses at a glance, especially when space allows and quick status recognition is important.\n * - Use the **actions** variant to provide direct access to system controls (e.g., mute/unmute, adjust volume, open system settings).\n *\n * Only enable system indicators that are relevant to your application context. For example, if GPS is not available, set `systemState.gps.enabled` to `false` to hide the GPS icon.\n *\n * **TODO(designer):** Provide guidance on when to use each variant and any best practices for grouping or prioritizing system indicators.\n *\n *\n * ## Properties and Attributes\n *\n * - `variant` (`condensed` | `expanded` | `actions`): Controls the visual and interactive mode of the button. Default is `condensed`.\n * - `disabled` (boolean): Disables all interactions and renders the button(s) in a disabled state.\n * - `systemState` (object): Object describing the enabled state and current value for each system indicator (WiFi, audio, microphone, battery, GPS). Each sub-property (e.g., `wifi.enabled`, `audio.volume`) controls the presence and state of its corresponding icon.\n * - `menuOpen` (boolean): Indicates whether a system panel is currently open (used internally for expanded/actions variants).\n * - `activePanel` (string or null): Indicates which panel (if any) is currently active (`microphone`, `volume`, `system-icons`, or `null`).\n *\n * ## Events\n *\n * - `menu-toggle` – Fired when the expanded variant is toggled open or closed.\n * - `system-state-change` – Fired when the system state is updated via `updateSystemState()`.\n * - `microphone-panel-open` – Fired when the microphone action segment is activated.\n * - `volume-panel-open` – Fired when the volume action segment is activated.\n * - `system-icons-panel-open` – Fired when the system icons action segment is activated.\n *\n * ## Best Practices and Constraints\n *\n * - Only enable system indicators that are relevant to your application context.\n * - In the actions variant, avoid overloading the UI with too many segments; keep the number of quick actions manageable.\n * - Each segment in the actions variant should have a clear, distinct purpose.\n * - The component is intended for summary/status and quick access, not for detailed configuration (which should be handled in dedicated panels).\n * - For accessibility, ensure that all interactive segments are reachable via keyboard and provide appropriate labels.\n *\n * ## Example\n *\n * ```html\n * <obc-system-button\n * variant=\"actions\"\n * .systemState=\"${{\n * wifi: {enabled: true, connected: true, strength: 3},\n * audio: {enabled: true, muted: false, volume: 65},\n * microphone: {enabled: true, muted: false, sensitivity: 80},\n * battery: {enabled: true, level: 78, charging: false},\n * gps: {enabled: true, connected: true, quality: 'medium'},\n * }}\"\n * >\n * <span slot=\"icon\"><obi-placeholder></obi-placeholder></span>\n * </obc-system-button>\n * ```\n *\n * @fires {CustomEvent<{open: boolean}>} menu-toggle - When the expanded variant is toggled open or closed\n * @fires {CustomEvent<{state: SystemState}>} system-state-change - When the system state is updated\n * @fires {CustomEvent<void>} microphone-panel-open - When the microphone action segment is activated\n * @fires {CustomEvent<void>} volume-panel-open - When the volume action segment is activated\n * @fires {CustomEvent<void>} system-icons-panel-open - When the system icons action segment is activated\n * @stable\n */\n@customElement('obc-system-button')\nexport class ObcSystemButton extends LitElement {\n /**\n * Controls the visual and interactive mode of the system button.\n *\n * - `condensed`: Single icon button for minimal UI.\n * - `expanded`: Horizontal button showing a row of system status icons.\n * - `actions`: Segmented button group for quick access to system controls.\n *\n * Default: `condensed`\n */\n @property({type: String}) variant: SystemButtonVariant =\n SystemButtonVariant.condensed;\n\n /**\n * Disables all interactions and renders the button(s) in a disabled state.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * Object describing the enabled state and current value for each system indicator (WiFi, audio, microphone, battery, GPS).\n *\n * Each sub-property (e.g., `wifi.enabled`, `audio.volume`) controls the presence and state of its corresponding icon.\n *\n * Default: all indicators disabled except WiFi (connected), audio (volume 65), microphone (sensitivity 80), battery (level 78), GPS (quality medium).\n */\n @property({type: Object}) systemState: SystemState = {\n wifi: {connected: true, strength: 3},\n audio: {muted: false, volume: 65},\n microphone: {muted: false, sensitivity: 80},\n battery: {level: 78, charging: false},\n gps: {connected: false, quality: 'medium'},\n };\n\n /**\n * Indicates whether a system panel is currently open (used internally for expanded/actions variants).\n */\n @property({type: Boolean}) menuOpen = false;\n\n /**\n * Indicates which panel (if any) is currently active.\n * One of: `'microphone'`, `'volume'`, `'system-icons'`, or `null`.\n */\n @property({type: String}) activePanel: ActivePanel | null = null;\n\n private _handleExpandedTypeClick() {\n this.menuOpen = !this.menuOpen;\n /**\n * Fired when the expanded variant is toggled open or closed.\n *\n * @event menu-toggle - When the expanded variant is toggled open or closed\n * @type {CustomEvent<{open: boolean}>}\n */\n this.dispatchEvent(\n new CustomEvent('menu-toggle', {\n detail: {open: this.menuOpen},\n })\n );\n }\n\n /**\n * Updates the system state and dispatches a change event.\n * Called by the System Menu component.\n *\n * @param newState Partial system state to merge with the current state.\n * @fires {CustomEvent<{state: SystemState}>} system-state-change - When the system state is updated\n */\n public updateSystemState(newState: Partial<SystemState>) {\n this.systemState = {...this.systemState, ...newState};\n this.dispatchEvent(\n new CustomEvent('system-state-change', {\n detail: {state: this.systemState},\n })\n );\n }\n\n /**\n * Closes the system menu panel.\n * Called by the System Menu component.\n */\n public closeMenu() {\n this.menuOpen = false;\n this.activePanel = null;\n }\n\n private _handleMicrophoneActionClick = () => {\n this.activePanel = ActivePanel.microphone;\n this.menuOpen = true;\n /**\n * Fired when the microphone action segment is activated.\n *\n * @event microphone-panel-open - When the microphone action segment is activated\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('microphone-panel-open'));\n };\n\n private _handleVolumeActionClick = () => {\n this.activePanel = ActivePanel.volume;\n this.menuOpen = true;\n /**\n * Fired when the volume action segment is activated.\n *\n * @event volume-panel-open - When the volume action segment is activated\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('volume-panel-open'));\n };\n\n private _handleSystemIconsActionClick = () => {\n this.activePanel = ActivePanel.systemIcons;\n this.menuOpen = true;\n /**\n * Fired when the system icons action segment is activated.\n *\n * @event system-icons-panel-open - When the system icons action segment is activated\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('system-icons-panel-open'));\n };\n\n private _renderActionsButtons() {\n const buttons = [];\n let buttonCount = 0;\n\n // Count enabled buttons first to determine segment positions\n if (this.systemState.microphone !== undefined) buttonCount++;\n if (this.systemState.audio !== undefined) buttonCount++;\n // Always show system icons button\n buttonCount++;\n\n let currentIndex = 0;\n\n // Microphone button\n if (this.systemState.microphone !== undefined) {\n const segmentPosition =\n buttonCount === 1\n ? 'single'\n : currentIndex === 0\n ? 'start'\n : currentIndex === buttonCount - 1\n ? 'end'\n : 'middle';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleMicrophoneActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\">${this._renderMicrophoneIcon()}</span>\n ${this.systemState.microphone.muted ? 'Off' : 'On'}\n </obc-button>\n `);\n currentIndex++;\n }\n\n // Volume button\n if (this.systemState.audio !== undefined) {\n const segmentPosition =\n buttonCount === 1\n ? 'single'\n : currentIndex === 0\n ? 'start'\n : currentIndex === buttonCount - 1\n ? 'end'\n : 'middle';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleVolumeActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\">${this._renderVolumeIcon()}</span>\n ${this.systemState.audio.volume}\n </obc-button>\n `);\n currentIndex++;\n }\n\n // System icons button (always shown)\n const segmentPosition =\n buttonCount === 1 ? 'single' : currentIndex === 0 ? 'start' : 'end';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleSystemIconsActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\" class=\"multiple-icons\">\n ${this._renderWifiIcon()} ${this._renderGpsIcon()}\n ${this._renderBatteryIcon()}\n </span>\n </obc-button>\n `);\n\n return buttons;\n }\n\n private _renderMicrophoneIcon() {\n if (this.systemState.microphone === undefined) return nothing;\n\n if (this.systemState.microphone.muted) {\n return html`<obi-com-mic-muted-google></obi-com-mic-muted-google>`;\n } else {\n return html`<obi-com-microphone></obi-com-microphone>`;\n }\n }\n\n private _renderVolumeIcon() {\n if (this.systemState.audio === undefined) return nothing;\n\n const volume = this.systemState.audio.volume;\n const muted = this.systemState.audio.muted;\n\n if (muted) {\n return html`<obi-sound-muted></obi-sound-muted>`;\n }\n\n // Show different sound levels based on volume\n if (volume === 0) {\n return html`<obi-sound-no></obi-sound-no>`;\n } else if (volume <= 50) {\n return html`<obi-sound-low></obi-sound-low>`;\n } else {\n return html`<obi-sound></obi-sound>`;\n }\n }\n\n private _renderWifiIcon() {\n if (this.systemState.wifi === undefined) return nothing;\n\n if (!this.systemState.wifi.connected) {\n return html`<obi-wifi2-off-google></obi-wifi2-off-google>`;\n }\n\n // Show strength-based icon when connected - update rendering icons when we get new icons\n switch (this.systemState.wifi.strength) {\n case 0:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 1:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 2:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 3:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 4:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n default:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n }\n }\n\n private _renderGpsIcon() {\n if (this.systemState.gps === undefined) return nothing;\n\n if (!this.systemState.gps.connected) {\n return html`<obi-sensor-gps-bad></obi-sensor-gps-bad>`;\n }\n\n // Show GPS quality based on signal\n switch (this.systemState.gps.quality) {\n case 'bad':\n return html`<obi-sensor-gps-bad></obi-sensor-gps-bad>`;\n case 'low':\n return html`<obi-sensor-gps-low></obi-sensor-gps-low>`;\n case 'medium':\n return html`<obi-sensor-gps-medium></obi-sensor-gps-medium>`;\n case 'full':\n return html`<obi-sensor-gps-full></obi-sensor-gps-full>`;\n default:\n return html`<obi-sensor-gps-medium></obi-sensor-gps-medium>`;\n }\n }\n\n private _renderBatteryIcon() {\n if (this.systemState.battery === undefined) return nothing;\n\n const level = this.systemState.battery.level;\n const charging = this.systemState.battery.charging;\n const poweredNotCharging =\n this.systemState.battery.poweredNotCharging ?? false;\n const notification = this.systemState.battery.notification ?? false;\n return html`<obc-battery-icon\n class=\"icon\"\n .level=${level}\n .charging=${charging}\n .poweredNotCharging=${poweredNotCharging}\n .notification=${notification}\n horizontal\n ></obc-battery-icon>`;\n }\n\n override render() {\n switch (this.variant) {\n case 'condensed':\n return html`\n <obc-icon-button\n variant=${IconButtonVariant.flat}\n .disabled=${this.disabled}\n >\n <obi-configure></obi-configure>\n </obc-icon-button>\n `;\n\n case 'expanded':\n return html` <button\n class=\"expanded-visually-hidden\"\n @click=${this._handleExpandedTypeClick}\n .disabled=${this.disabled}\n >\n <div class=\"expanded-inner-wrapper\">\n <div class=\"expanded-icon-container\">\n ${this._renderMicrophoneIcon()} ${this._renderVolumeIcon()}\n ${this._renderWifiIcon()} ${this._renderGpsIcon()}\n ${this._renderBatteryIcon()}\n </div>\n </div>\n </button>`;\n\n case 'actions':\n return html`\n <div class=\"system-button--actions\">\n ${this._renderActionsButtons()}\n </div>\n `;\n default:\n return html`\n <obc-icon-button variant=${IconButtonVariant.normal}>\n <obi-configure></obi-configure>\n </obc-icon-button>\n `;\n }\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-system-button': ObcSystemButton;\n }\n}\n"],"names":["SystemButtonVariant","ActivePanel","segmentPosition"],"mappings":"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"}
1
+ {"version":3,"file":"system-button.js","sources":["../../../src/components/system-button/system-button.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {customElement} from '../../decorator.js';\nimport compentStyle from './system-button.css?inline';\nimport {property} from 'lit/decorators.js';\nimport '../icon-button/icon-button.js';\nimport {IconButtonVariant} from '../icon-button/icon-button.js';\nimport '../../icons/icon-configure.js';\nimport '../../icons/icon-com-microphone.js';\nimport '../../icons/icon-com-mic-muted-google.js';\nimport '../../icons/icon-wifi2-google.js';\nimport '../../icons/icon-wifi2-off-google.js';\nimport '../../icons/icon-sensor-gps-bad.js';\nimport '../../icons/icon-sensor-gps-low.js';\nimport '../../icons/icon-sensor-gps-medium.js';\nimport '../../icons/icon-sensor-gps-full.js';\nimport '../../icons/icon-sound-muted.js';\nimport '../../icons/icon-sound-no.js';\nimport '../../icons/icon-sound-low.js';\nimport '../../icons/icon-sound.js';\nimport '../button/button.js';\nimport '../battery-icon/battery-icon.js';\n\nexport enum SystemButtonVariant {\n condensed = 'condensed',\n expanded = 'expanded',\n actions = 'actions',\n}\n\nexport enum ActivePanel {\n microphone = 'microphone',\n volume = 'volume',\n systemIcons = 'system-icons',\n}\n\n/**\n * Describes the enabled state and current value for each system indicator displayed by `<obc-system-button>`.\n *\n * - `wifi`: WiFi status (enabled, connected, strength, network name)\n * - `audio`: Audio status (enabled, muted, volume)\n * - `microphone`: Microphone status (enabled, muted, sensitivity)\n * - `battery`: Battery status (enabled, level, charging)\n * - `gps`: GPS status (enabled, connected, quality)\n */\nexport interface SystemState {\n wifi?: {\n connected: boolean;\n networkName?: string;\n strength: 0 | 1 | 2 | 3 | 4; // Maps directly to icon variants\n };\n audio?: {\n muted: boolean;\n volume: number; // 0-100\n };\n microphone?: {\n muted: boolean;\n sensitivity: number; // 0-100\n };\n battery?: {\n level: number; // 0-100\n charging: boolean;\n poweredNotCharging?: boolean;\n notification?: boolean;\n };\n gps?: {\n connected: boolean;\n quality: 'bad' | 'low' | 'medium' | 'full'; // Maps to GPS icon variants\n };\n}\n\n/**\n * `<obc-system-button>` – A multi-state system status and quick-action button for displaying and controlling core system indicators.\n *\n * This component provides a compact, interactive summary of system-level statuses such as WiFi, audio, microphone, battery, and GPS. It can be used as a single icon button, an expanded status display, or a segmented set of quick-action buttons, depending on the chosen variant. Designed for use in application toolbars, system menus, or quick-access panels where users need to view and interact with system controls at a glance.\n *\n * Appears as an icon or set of icons representing real-time system states. Supports toggling panels for detailed control or configuration, and adapts its layout to suit condensed, expanded, or action-oriented contexts.\n *\n * ## Features\n *\n * - **Variants**:\n * - **Condensed**: Single icon button (typically a settings or system icon) for minimal space usage.\n * - **Expanded**: Horizontal button displaying a row of system status icons (WiFi, audio, microphone, battery, GPS) for quick visual overview.\n * - **Actions**: Segmented button group, each segment representing a system function (microphone, volume, system icons), with interactive actions for each.\n * - **Dynamic Iconography**: Icons update in real time to reflect system state (e.g., WiFi strength, battery level, mute status, GPS quality).\n * - **Quick Actions**: In actions variant, clicking a segment opens the corresponding control panel (e.g., microphone settings, volume slider).\n * - **State Awareness**: Each system indicator (WiFi, audio, microphone, battery, GPS) can be enabled/disabled independently, and their visual state reflects connection, mute, charge, or quality status.\n * - **Accessibility**: Button segments are keyboard accessible and support disabled state.\n * - **Customizable**: System state can be controlled via the `systemState` property, allowing for integration with live system data.\n *\n * ## Usage Guidelines\n *\n * Use `<obc-system-button>` to provide users with a compact, always-visible summary of key system statuses and quick access to related controls. Ideal for application toolbars, overlays, or system menus where users need to monitor and adjust system settings without leaving their current context.\n *\n * - Use the **condensed** variant for minimal UI or when only a single system menu entry is needed.\n * - Use the **expanded** variant to show multiple system statuses at a glance, especially when space allows and quick status recognition is important.\n * - Use the **actions** variant to provide direct access to system controls (e.g., mute/unmute, adjust volume, open system settings).\n *\n * Only enable system indicators that are relevant to your application context. For example, if GPS is not available, set `systemState.gps.enabled` to `false` to hide the GPS icon.\n *\n * **TODO(designer):** Provide guidance on when to use each variant and any best practices for grouping or prioritizing system indicators.\n *\n *\n * ## Properties and Attributes\n *\n * - `variant` (`condensed` | `expanded` | `actions`): Controls the visual and interactive mode of the button. Default is `condensed`.\n * - `disabled` (boolean): Disables all interactions and renders the button(s) in a disabled state.\n * - `systemState` (object): Object describing the enabled state and current value for each system indicator (WiFi, audio, microphone, battery, GPS). Each sub-property (e.g., `wifi.enabled`, `audio.volume`) controls the presence and state of its corresponding icon.\n * - `menuOpen` (boolean): Indicates whether a system panel is currently open (used internally for expanded/actions variants).\n * - `activePanel` (string or null): Indicates which panel (if any) is currently active (`microphone`, `volume`, `system-icons`, or `null`).\n *\n * ## Events\n *\n * - `menu-toggle` – Fired when the expanded variant is toggled open or closed.\n * - `system-state-change` – Fired when the system state is updated via `updateSystemState()`.\n * - `microphone-panel-open` – Fired when the microphone action segment is activated.\n * - `volume-panel-open` – Fired when the volume action segment is activated.\n * - `system-icons-panel-open` – Fired when the system icons action segment is activated.\n *\n * ## Best Practices and Constraints\n *\n * - Only enable system indicators that are relevant to your application context.\n * - In the actions variant, avoid overloading the UI with too many segments; keep the number of quick actions manageable.\n * - Each segment in the actions variant should have a clear, distinct purpose.\n * - The component is intended for summary/status and quick access, not for detailed configuration (which should be handled in dedicated panels).\n * - For accessibility, ensure that all interactive segments are reachable via keyboard and provide appropriate labels.\n *\n * ## Example\n *\n * ```html\n * <obc-system-button\n * variant=\"actions\"\n * .systemState=\"${{\n * wifi: {enabled: true, connected: true, strength: 3},\n * audio: {enabled: true, muted: false, volume: 65},\n * microphone: {enabled: true, muted: false, sensitivity: 80},\n * battery: {enabled: true, level: 78, charging: false},\n * gps: {enabled: true, connected: true, quality: 'medium'},\n * }}\"\n * >\n * <span slot=\"icon\"><obi-placeholder></obi-placeholder></span>\n * </obc-system-button>\n * ```\n *\n * @fires {CustomEvent<{open: boolean}>} menu-toggle - When the expanded variant is toggled open or closed\n * @fires {CustomEvent<{state: SystemState}>} system-state-change - When the system state is updated\n * @fires {CustomEvent<void>} microphone-panel-open - When the microphone action segment is activated\n * @fires {CustomEvent<void>} volume-panel-open - When the volume action segment is activated\n * @fires {CustomEvent<void>} system-icons-panel-open - When the system icons action segment is activated\n * @stable\n */\n@customElement('obc-system-button')\nexport class ObcSystemButton extends LitElement {\n /**\n * Controls the visual and interactive mode of the system button.\n *\n * - `condensed`: Single icon button for minimal UI.\n * - `expanded`: Horizontal button showing a row of system status icons.\n * - `actions`: Segmented button group for quick access to system controls.\n *\n * Default: `condensed`\n */\n @property({type: String}) variant: SystemButtonVariant =\n SystemButtonVariant.condensed;\n\n /**\n * Disables all interactions and renders the button(s) in a disabled state.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * Object describing the enabled state and current value for each system indicator (WiFi, audio, microphone, battery, GPS).\n *\n * Each sub-property (e.g., `wifi.enabled`, `audio.volume`) controls the presence and state of its corresponding icon.\n *\n * Default: all indicators disabled except WiFi (connected), audio (volume 65), microphone (sensitivity 80), battery (level 78), GPS (quality medium).\n */\n @property({type: Object}) systemState: SystemState = {\n wifi: {connected: true, strength: 3},\n audio: {muted: false, volume: 65},\n microphone: {muted: false, sensitivity: 80},\n battery: {level: 78, charging: false},\n gps: {connected: false, quality: 'medium'},\n };\n\n /**\n * Indicates whether a system panel is currently open (used internally for expanded/actions variants).\n */\n @property({type: Boolean}) menuOpen = false;\n\n /**\n * Indicates which panel (if any) is currently active.\n * One of: `'microphone'`, `'volume'`, `'system-icons'`, or `null`.\n */\n @property({type: String}) activePanel: ActivePanel | null = null;\n\n private _handleExpandedTypeClick() {\n this.menuOpen = !this.menuOpen;\n /**\n * Fired when the expanded variant is toggled open or closed.\n *\n * @event menu-toggle\n * @type {CustomEvent<{open: boolean}>}\n */\n this.dispatchEvent(\n new CustomEvent('menu-toggle', {\n detail: {open: this.menuOpen},\n })\n );\n }\n\n /**\n * Updates the system state and dispatches a change event.\n * Called by the System Menu component.\n *\n * @param newState Partial system state to merge with the current state.\n * @fires system-state-change\n */\n public updateSystemState(newState: Partial<SystemState>) {\n this.systemState = {...this.systemState, ...newState};\n this.dispatchEvent(\n new CustomEvent('system-state-change', {\n detail: {state: this.systemState},\n })\n );\n }\n\n /**\n * Closes the system menu panel.\n * Called by the System Menu component.\n */\n public closeMenu() {\n this.menuOpen = false;\n this.activePanel = null;\n }\n\n private _handleMicrophoneActionClick = () => {\n this.activePanel = ActivePanel.microphone;\n this.menuOpen = true;\n /**\n * Fired when the microphone action segment is activated.\n *\n * @event microphone-panel-open\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('microphone-panel-open'));\n };\n\n private _handleVolumeActionClick = () => {\n this.activePanel = ActivePanel.volume;\n this.menuOpen = true;\n /**\n * Fired when the volume action segment is activated.\n *\n * @event volume-panel-open\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('volume-panel-open'));\n };\n\n private _handleSystemIconsActionClick = () => {\n this.activePanel = ActivePanel.systemIcons;\n this.menuOpen = true;\n /**\n * Fired when the system icons action segment is activated.\n *\n * @event system-icons-panel-open\n * @type {CustomEvent<void>}\n */\n this.dispatchEvent(new CustomEvent('system-icons-panel-open'));\n };\n\n private _renderActionsButtons() {\n const buttons = [];\n let buttonCount = 0;\n\n // Count enabled buttons first to determine segment positions\n if (this.systemState.microphone !== undefined) buttonCount++;\n if (this.systemState.audio !== undefined) buttonCount++;\n // Always show system icons button\n buttonCount++;\n\n let currentIndex = 0;\n\n // Microphone button\n if (this.systemState.microphone !== undefined) {\n const segmentPosition =\n buttonCount === 1\n ? 'single'\n : currentIndex === 0\n ? 'start'\n : currentIndex === buttonCount - 1\n ? 'end'\n : 'middle';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleMicrophoneActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\">${this._renderMicrophoneIcon()}</span>\n ${this.systemState.microphone.muted ? 'Off' : 'On'}\n </obc-button>\n `);\n currentIndex++;\n }\n\n // Volume button\n if (this.systemState.audio !== undefined) {\n const segmentPosition =\n buttonCount === 1\n ? 'single'\n : currentIndex === 0\n ? 'start'\n : currentIndex === buttonCount - 1\n ? 'end'\n : 'middle';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleVolumeActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\">${this._renderVolumeIcon()}</span>\n ${this.systemState.audio.volume}\n </obc-button>\n `);\n currentIndex++;\n }\n\n // System icons button (always shown)\n const segmentPosition =\n buttonCount === 1 ? 'single' : currentIndex === 0 ? 'start' : 'end';\n\n buttons.push(html`\n <obc-button\n .variant=${IconButtonVariant.normal}\n .segmentPosition=${segmentPosition}\n .showLeadingIcon=${true}\n @click=${this._handleSystemIconsActionClick}\n .disabled=${this.disabled}\n >\n <span slot=\"leading-icon\" class=\"multiple-icons\">\n ${this._renderWifiIcon()} ${this._renderGpsIcon()}\n ${this._renderBatteryIcon()}\n </span>\n </obc-button>\n `);\n\n return buttons;\n }\n\n private _renderMicrophoneIcon() {\n if (this.systemState.microphone === undefined) return nothing;\n\n if (this.systemState.microphone.muted) {\n return html`<obi-com-mic-muted-google></obi-com-mic-muted-google>`;\n } else {\n return html`<obi-com-microphone></obi-com-microphone>`;\n }\n }\n\n private _renderVolumeIcon() {\n if (this.systemState.audio === undefined) return nothing;\n\n const volume = this.systemState.audio.volume;\n const muted = this.systemState.audio.muted;\n\n if (muted) {\n return html`<obi-sound-muted></obi-sound-muted>`;\n }\n\n // Show different sound levels based on volume\n if (volume === 0) {\n return html`<obi-sound-no></obi-sound-no>`;\n } else if (volume <= 50) {\n return html`<obi-sound-low></obi-sound-low>`;\n } else {\n return html`<obi-sound></obi-sound>`;\n }\n }\n\n private _renderWifiIcon() {\n if (this.systemState.wifi === undefined) return nothing;\n\n if (!this.systemState.wifi.connected) {\n return html`<obi-wifi2-off-google></obi-wifi2-off-google>`;\n }\n\n // Show strength-based icon when connected - update rendering icons when we get new icons\n switch (this.systemState.wifi.strength) {\n case 0:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 1:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 2:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 3:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n case 4:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n default:\n return html`<obi-wifi2-google></obi-wifi2-google>`;\n }\n }\n\n private _renderGpsIcon() {\n if (this.systemState.gps === undefined) return nothing;\n\n if (!this.systemState.gps.connected) {\n return html`<obi-sensor-gps-bad></obi-sensor-gps-bad>`;\n }\n\n // Show GPS quality based on signal\n switch (this.systemState.gps.quality) {\n case 'bad':\n return html`<obi-sensor-gps-bad></obi-sensor-gps-bad>`;\n case 'low':\n return html`<obi-sensor-gps-low></obi-sensor-gps-low>`;\n case 'medium':\n return html`<obi-sensor-gps-medium></obi-sensor-gps-medium>`;\n case 'full':\n return html`<obi-sensor-gps-full></obi-sensor-gps-full>`;\n default:\n return html`<obi-sensor-gps-medium></obi-sensor-gps-medium>`;\n }\n }\n\n private _renderBatteryIcon() {\n if (this.systemState.battery === undefined) return nothing;\n\n const level = this.systemState.battery.level;\n const charging = this.systemState.battery.charging;\n const poweredNotCharging =\n this.systemState.battery.poweredNotCharging ?? false;\n const notification = this.systemState.battery.notification ?? false;\n return html`<obc-battery-icon\n class=\"icon\"\n .level=${level}\n .charging=${charging}\n .poweredNotCharging=${poweredNotCharging}\n .notification=${notification}\n horizontal\n ></obc-battery-icon>`;\n }\n\n override render() {\n switch (this.variant) {\n case 'condensed':\n return html`\n <obc-icon-button\n variant=${IconButtonVariant.flat}\n .disabled=${this.disabled}\n >\n <obi-configure></obi-configure>\n </obc-icon-button>\n `;\n\n case 'expanded':\n return html` <button\n class=\"expanded-visually-hidden\"\n @click=${this._handleExpandedTypeClick}\n .disabled=${this.disabled}\n >\n <div class=\"expanded-inner-wrapper\">\n <div class=\"expanded-icon-container\">\n ${this._renderMicrophoneIcon()} ${this._renderVolumeIcon()}\n ${this._renderWifiIcon()} ${this._renderGpsIcon()}\n ${this._renderBatteryIcon()}\n </div>\n </div>\n </button>`;\n\n case 'actions':\n return html`\n <div class=\"system-button--actions\">\n ${this._renderActionsButtons()}\n </div>\n `;\n default:\n return html`\n <obc-icon-button variant=${IconButtonVariant.normal}>\n <obi-configure></obi-configure>\n </obc-icon-button>\n `;\n }\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-system-button': ObcSystemButton;\n }\n}\n"],"names":["SystemButtonVariant","ActivePanel","segmentPosition"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabbed-card.d.ts","sourceRoot":"","sources":["../../../src/components/tabbed-card/tabbed-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,MAAM,MAAM,wBAAwB,GAAG,WAAW,CAAC;IACjD,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6GG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C;;;OAGG;IACuB,KAAK,EAAE,MAAM,CAAK;IAE5C;;;OAGG;IACuB,WAAW,EAAE,MAAM,CAAK;IAElD;;;;OAIG;IACwB,kBAAkB,EAAE,OAAO,CAAS;IAE/D;;;OAGG;IACwB,WAAW,EAAE,OAAO,CAAS;IAExD,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,kBAAkB;IA2BjB,MAAM;IAWf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
1
+ {"version":3,"file":"tabbed-card.d.ts","sourceRoot":"","sources":["../../../src/components/tabbed-card/tabbed-card.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,MAAM,MAAM,wBAAwB,GAAG,WAAW,CAAC;IACjD,GAAG,EAAE,MAAM,CAAC;CACb,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6GG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C;;;OAGG;IACuB,KAAK,EAAE,MAAM,CAAK;IAE5C;;;OAGG;IACuB,WAAW,EAAE,MAAM,CAAK;IAElD;;;;OAIG;IACwB,kBAAkB,EAAE,OAAO,CAAS;IAE/D;;;OAGG;IACwB,WAAW,EAAE,OAAO,CAAS;IAExD,OAAO,CAAC,cAAc;IA2BtB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,mBAAmB;IAkC3B,OAAO,CAAC,kBAAkB;IA2BjB,MAAM;IAWf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"tabbed-card.js","sources":["../../../src/components/tabbed-card/tabbed-card.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './tabbed-card.css?inline';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcTabbedCardChangeEvent = CustomEvent<{\n tab: number;\n}>;\n\n/**\n * `<obc-tabbed-card>` – A card component that organizes content into multiple tabbed sections, allowing users to switch between views without leaving the current context.\n *\n * Displays a horizontal row of tabs at the top, each associated with a content panel below. Users can navigate between tabs using mouse or keyboard, with the active tab's content shown in the main area. This pattern is ideal for grouping related information or settings within a compact space.\n *\n * ---\n *\n * ### Features\n * - **Configurable Tab Count:** Supports 1–5 tabs, each with a custom title and content area.\n * - **Flexible Content Structure:**\n * - **Default Slot Mode:** When `hasDefaultSlotOnly` is true, all tab content is provided via the default slot, and the consumer is responsible for toggling content based on the selected tab.\n * - **Named Slot Mode:** When `hasDefaultSlotOnly` is false (default), each tab uses its own named slots (`tab-title-x`, `tab-content-x`) for title and content.\n * - **Keyboard Navigation:** Supports Left/Right Arrow to move between tabs, Home/End to jump to first/last tab, following WAI-ARIA Tabs Pattern for accessibility.\n * - **Active Tab Highlighting:** Visually distinguishes the selected tab and its content panel.\n * - **Automatic Tab Activation:** Tabs activate on focus, streamlining keyboard navigation.\n * - **Responsive Layout:** Adapts to container width and height.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-tabbed-card` to present related content or controls in a compact, organized manner, such as settings panels, dashboards, or multi-step forms. Ideal when users need to switch between several views without navigating away from the current page. Avoid using tabs for unrelated content or when only a single view is needed.\n *\n * - For up to five tabs, supply each tab's title and content using the corresponding named slots.\n * - If you need to control tab content visibility yourself (e.g., for advanced state management), set `hasDefaultSlotOnly` and provide all content in the default slot.\n * - Keyboard users can navigate tabs using arrow keys, Home, and End.\n * - For best accessibility, keep tab titles concise and ensure content is meaningfully grouped.\n *\n * **TODO(designer):** Clarify if there are recommended limits for tab title length or content complexity, and if there are visual guidelines for tab overflow (more than five tabs).\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-------------------|-------------------------------|------------------------------------------|\n * | (default) | `hasDefaultSlotOnly` is true | All tab content (consumer toggles views) |\n * | tab-title-0 | Always | Title for the first tab |\n * | tab-content-0 | Always (unless default slot) | Content for the first tab |\n * | tab-icon-0 | hasTabIcons is true | Icon for the first tab |\n * | tab-title-1 | nTabs > 1 | Title for the second tab |\n * | tab-content-1 | nTabs > 1 | Content for the second tab |\n * | tab-icon-1 | hasTabIcons is true | Icon for the second tab |\n * | tab-title-2 | nTabs > 2 | Title for the third tab |\n * | tab-content-2 | nTabs > 2 | Content for the third tab |\n * | tab-icon-2 | hasTabIcons is true | Icon for the third tab |\n * | tab-title-3 | nTabs > 3 | Title for the fourth tab |\n * | tab-content-3 | nTabs > 3 | Content for the fourth tab |\n * | tab-icon-3 | hasTabIcons is true | Icon for the fourth tab |\n * | tab-title-4 | nTabs > 4 | Title for the fifth tab |\n * | tab-content-4 | nTabs > 4 | Content for the fifth tab |\n * | tab-icon-4 | hasTabIcons is true | Icon for the fifth tab |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `nTabs` (number): Number of tabs to display (default: 1). Determines how many tab-title/content slot pairs are rendered.\n * - `selectedTab` (number): Index of the currently selected tab (default: 0). Updates automatically on user interaction.\n * - `hasDefaultSlotOnly` (boolean): If true, only the default slot is rendered for tab content, and the consumer is responsible for toggling content based on the selected tab.\n *\n * ---\n *\n * ### Events\n * - `tab-change` – Fired whenever the selected tab changes, with detail `{tab: number}` indicating the new tab index.\n *\n * ---\n *\n * ### Best Practices & Constraints\n * - Keep tab titles short for optimal display.\n * - Use tabs for closely related content; avoid mixing unrelated features in a single tabbed card.\n * - For accessibility, ensure each tab has a unique, descriptive title.\n * - Do not exceed five tabs for best usability; if more are needed, consider alternative navigation patterns.\n * - When using `hasDefaultSlotOnly`, ensure your content updates in sync with the `selectedTab` property.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-tabbed-card nTabs=\"3\">\n * <span slot=\"tab-title-0\">Overview</span>\n * <span slot=\"tab-title-1\">Details</span>\n * <span slot=\"tab-title-2\">Settings</span>\n *\n * <div slot=\"tab-content-0\">Overview Content</div>\n * <div slot=\"tab-content-1\">Details Content</div>\n * <div slot=\"tab-content-2\">Settings Content</div>\n * </obc-tabbed-card>\n * ```\n *\n * In this example, three tabs are shown, each with its own title and content panel.\n *\n * @slot - Default slot for tab content (used only when `hasDefaultSlotOnly` is true)\n * @slot tab-title-0 - Title for the first tab\n * @slot tab-content-0 - Content for the first tab\n * @slot tab-title-1 - Title for the second tab\n * @slot tab-content-1 - Content for the second tab\n * @slot tab-title-2 - Title for the third tab\n * @slot tab-content-2 - Content for the third tab\n * @slot tab-title-3 - Title for the fourth tab\n * @slot tab-content-3 - Content for the fourth tab\n * @slot tab-title-4 - Title for the fifth tab\n * @slot tab-content-4 - Content for the fifth tab\n * @slot tab-icon-0 - Icon for the first tab\n * @slot tab-icon-1 - Icon for the second tab\n * @slot tab-icon-2 - Icon for the third tab\n * @slot tab-icon-3 - Icon for the fourth tab\n * @slot tab-icon-4 - Icon for the fifth tab\n * @fires {CustomEvent<{tab:number}>} tab-change - Fired when the selected tab changes\n * @stable\n */\n@customElement('obc-tabbed-card')\nexport class ObcTabbedCard extends LitElement {\n /**\n * Number of tabs to display (1–5). Determines how many tab-title/content slot pairs are rendered.\n * @default 1\n */\n @property({type: Number}) nTabs: number = 1;\n\n /**\n * Index of the currently selected tab (zero-based). Updates automatically on user interaction.\n * @default 0\n */\n @property({type: Number}) selectedTab: number = 0;\n\n /**\n * If true, only the default slot is rendered for tab content, and the consumer is responsible for toggling content based on the selected tab.\n * When false (default), each tab uses its own named slots for title and content.\n * @default false\n */\n @property({type: Boolean}) hasDefaultSlotOnly: boolean = false;\n\n /**\n * If true, each tab will have an icon slot.\n * @default false\n */\n @property({type: Boolean}) hasTabIcons: boolean = false;\n\n private _handleKeyDown(e: KeyboardEvent) {\n const targetButton = e.target as HTMLElement;\n if (!targetButton.classList.contains('tab-button')) return;\n\n const currentIndex = this.selectedTab;\n\n switch (e.key) {\n case 'ArrowRight':\n this.setSelectedTab((currentIndex + 1) % this.nTabs);\n break;\n case 'ArrowLeft':\n this.setSelectedTab((currentIndex - 1 + this.nTabs) % this.nTabs);\n break;\n case 'Home':\n this.setSelectedTab(0);\n break;\n case 'End':\n this.setSelectedTab(this.nTabs - 1);\n break;\n default:\n return;\n }\n\n e.preventDefault();\n this._focusTab(this.selectedTab);\n }\n\n private setSelectedTab(index: number) {\n this.selectedTab = index;\n /**\n * @fires {CustomEvent<{tab:number}>} tab-change - Fired when the selected tab changes.\n */\n this.dispatchEvent(new CustomEvent('tab-change', {detail: {tab: index}}));\n }\n\n private _focusTab(index: number) {\n const button = this.shadowRoot?.querySelector(\n `button[data-index=\"${index}\"]`\n ) as HTMLButtonElement;\n button?.focus();\n }\n\n private _generateTabHeaders() {\n return [...Array(this.nTabs)].map((_, index) => {\n const hasDivider =\n index !== this.nTabs - 1 &&\n this.selectedTab !== index &&\n index + 1 !== this.selectedTab;\n const tabIcon = this.hasTabIcons\n ? html`<span class=\"tab-icon\">\n <slot name=\"tab-icon-${index}\"></slot>\n </span>`\n : nothing;\n return html`\n <button\n class=\"tab-button ${hasDivider ? 'has-divider' : ''}\"\n role=\"tab\"\n aria-selected=\"${this.selectedTab === index}\"\n aria-controls=\"panel-${index}\"\n id=\"tab-${index}\"\n data-index=\"${index}\"\n tabindex=\"${this.selectedTab === index ? 0 : -1}\"\n @click=\"${() => this.setSelectedTab(index)}\"\n @focus=\"${() => this.setSelectedTab(index)}\"\n >\n <div class=\"tab-title-container\">\n ${tabIcon}\n <slot class=\"tab-title\" name=\"tab-title-${index}\"\n >Tab ${index + 1}</slot\n >\n </div>\n </button>\n `;\n });\n }\n\n private _generateTabPanels() {\n if (this.hasDefaultSlotOnly) {\n return html`<div\n role=\"tabpanel\"\n class=\"tab-content\"\n id=\"panel-${this.selectedTab}\"\n aria-labelledby=\"tab-${this.selectedTab}\"\n tabindex=\"0\"\n >\n <slot></slot>\n </div>`;\n }\n return [...Array(this.nTabs)].map(\n (_, index) => html`\n <div\n role=\"tabpanel\"\n id=\"panel-${index}\"\n aria-labelledby=\"tab-${index}\"\n tabindex=\"0\"\n ?hidden=\"${this.selectedTab !== index}\"\n >\n <slot name=\"tab-content-${index}\"></slot>\n </div>\n `\n );\n }\n\n override render() {\n return html`\n <div class=\"tab-container\" @keydown=\"${this._handleKeyDown}\">\n <div class=\"tab-header\" role=\"tablist\" aria-label=\"Tab List\">\n ${this._generateTabHeaders()}\n </div>\n <div class=\"tab-panels\">${this._generateTabPanels()}</div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-tabbed-card': ObcTabbedCard;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"tabbed-card.js","sources":["../../../src/components/tabbed-card/tabbed-card.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './tabbed-card.css?inline';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcTabbedCardChangeEvent = CustomEvent<{\n tab: number;\n}>;\n\n/**\n * `<obc-tabbed-card>` – A card component that organizes content into multiple tabbed sections, allowing users to switch between views without leaving the current context.\n *\n * Displays a horizontal row of tabs at the top, each associated with a content panel below. Users can navigate between tabs using mouse or keyboard, with the active tab's content shown in the main area. This pattern is ideal for grouping related information or settings within a compact space.\n *\n * ---\n *\n * ### Features\n * - **Configurable Tab Count:** Supports 1–5 tabs, each with a custom title and content area.\n * - **Flexible Content Structure:**\n * - **Default Slot Mode:** When `hasDefaultSlotOnly` is true, all tab content is provided via the default slot, and the consumer is responsible for toggling content based on the selected tab.\n * - **Named Slot Mode:** When `hasDefaultSlotOnly` is false (default), each tab uses its own named slots (`tab-title-x`, `tab-content-x`) for title and content.\n * - **Keyboard Navigation:** Supports Left/Right Arrow to move between tabs, Home/End to jump to first/last tab, following WAI-ARIA Tabs Pattern for accessibility.\n * - **Active Tab Highlighting:** Visually distinguishes the selected tab and its content panel.\n * - **Automatic Tab Activation:** Tabs activate on focus, streamlining keyboard navigation.\n * - **Responsive Layout:** Adapts to container width and height.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-tabbed-card` to present related content or controls in a compact, organized manner, such as settings panels, dashboards, or multi-step forms. Ideal when users need to switch between several views without navigating away from the current page. Avoid using tabs for unrelated content or when only a single view is needed.\n *\n * - For up to five tabs, supply each tab's title and content using the corresponding named slots.\n * - If you need to control tab content visibility yourself (e.g., for advanced state management), set `hasDefaultSlotOnly` and provide all content in the default slot.\n * - Keyboard users can navigate tabs using arrow keys, Home, and End.\n * - For best accessibility, keep tab titles concise and ensure content is meaningfully grouped.\n *\n * **TODO(designer):** Clarify if there are recommended limits for tab title length or content complexity, and if there are visual guidelines for tab overflow (more than five tabs).\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-------------------|-------------------------------|------------------------------------------|\n * | (default) | `hasDefaultSlotOnly` is true | All tab content (consumer toggles views) |\n * | tab-title-0 | Always | Title for the first tab |\n * | tab-content-0 | Always (unless default slot) | Content for the first tab |\n * | tab-icon-0 | hasTabIcons is true | Icon for the first tab |\n * | tab-title-1 | nTabs > 1 | Title for the second tab |\n * | tab-content-1 | nTabs > 1 | Content for the second tab |\n * | tab-icon-1 | hasTabIcons is true | Icon for the second tab |\n * | tab-title-2 | nTabs > 2 | Title for the third tab |\n * | tab-content-2 | nTabs > 2 | Content for the third tab |\n * | tab-icon-2 | hasTabIcons is true | Icon for the third tab |\n * | tab-title-3 | nTabs > 3 | Title for the fourth tab |\n * | tab-content-3 | nTabs > 3 | Content for the fourth tab |\n * | tab-icon-3 | hasTabIcons is true | Icon for the fourth tab |\n * | tab-title-4 | nTabs > 4 | Title for the fifth tab |\n * | tab-content-4 | nTabs > 4 | Content for the fifth tab |\n * | tab-icon-4 | hasTabIcons is true | Icon for the fifth tab |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `nTabs` (number): Number of tabs to display (default: 1). Determines how many tab-title/content slot pairs are rendered.\n * - `selectedTab` (number): Index of the currently selected tab (default: 0). Updates automatically on user interaction.\n * - `hasDefaultSlotOnly` (boolean): If true, only the default slot is rendered for tab content, and the consumer is responsible for toggling content based on the selected tab.\n *\n * ---\n *\n * ### Events\n * - `tab-change` – Fired whenever the selected tab changes, with detail `{tab: number}` indicating the new tab index.\n *\n * ---\n *\n * ### Best Practices & Constraints\n * - Keep tab titles short for optimal display.\n * - Use tabs for closely related content; avoid mixing unrelated features in a single tabbed card.\n * - For accessibility, ensure each tab has a unique, descriptive title.\n * - Do not exceed five tabs for best usability; if more are needed, consider alternative navigation patterns.\n * - When using `hasDefaultSlotOnly`, ensure your content updates in sync with the `selectedTab` property.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-tabbed-card nTabs=\"3\">\n * <span slot=\"tab-title-0\">Overview</span>\n * <span slot=\"tab-title-1\">Details</span>\n * <span slot=\"tab-title-2\">Settings</span>\n *\n * <div slot=\"tab-content-0\">Overview Content</div>\n * <div slot=\"tab-content-1\">Details Content</div>\n * <div slot=\"tab-content-2\">Settings Content</div>\n * </obc-tabbed-card>\n * ```\n *\n * In this example, three tabs are shown, each with its own title and content panel.\n *\n * @slot - Default slot for tab content (used only when `hasDefaultSlotOnly` is true)\n * @slot tab-title-0 - Title for the first tab\n * @slot tab-content-0 - Content for the first tab\n * @slot tab-title-1 - Title for the second tab\n * @slot tab-content-1 - Content for the second tab\n * @slot tab-title-2 - Title for the third tab\n * @slot tab-content-2 - Content for the third tab\n * @slot tab-title-3 - Title for the fourth tab\n * @slot tab-content-3 - Content for the fourth tab\n * @slot tab-title-4 - Title for the fifth tab\n * @slot tab-content-4 - Content for the fifth tab\n * @slot tab-icon-0 - Icon for the first tab\n * @slot tab-icon-1 - Icon for the second tab\n * @slot tab-icon-2 - Icon for the third tab\n * @slot tab-icon-3 - Icon for the fourth tab\n * @slot tab-icon-4 - Icon for the fifth tab\n * @fires {CustomEvent<{tab:number}>} tab-change - Fired when the selected tab changes\n * @stable\n */\n@customElement('obc-tabbed-card')\nexport class ObcTabbedCard extends LitElement {\n /**\n * Number of tabs to display (1–5). Determines how many tab-title/content slot pairs are rendered.\n * @default 1\n */\n @property({type: Number}) nTabs: number = 1;\n\n /**\n * Index of the currently selected tab (zero-based). Updates automatically on user interaction.\n * @default 0\n */\n @property({type: Number}) selectedTab: number = 0;\n\n /**\n * If true, only the default slot is rendered for tab content, and the consumer is responsible for toggling content based on the selected tab.\n * When false (default), each tab uses its own named slots for title and content.\n * @default false\n */\n @property({type: Boolean}) hasDefaultSlotOnly: boolean = false;\n\n /**\n * If true, each tab will have an icon slot.\n * @default false\n */\n @property({type: Boolean}) hasTabIcons: boolean = false;\n\n private _handleKeyDown(e: KeyboardEvent) {\n const targetButton = e.target as HTMLElement;\n if (!targetButton.classList.contains('tab-button')) return;\n\n const currentIndex = this.selectedTab;\n\n switch (e.key) {\n case 'ArrowRight':\n this.setSelectedTab((currentIndex + 1) % this.nTabs);\n break;\n case 'ArrowLeft':\n this.setSelectedTab((currentIndex - 1 + this.nTabs) % this.nTabs);\n break;\n case 'Home':\n this.setSelectedTab(0);\n break;\n case 'End':\n this.setSelectedTab(this.nTabs - 1);\n break;\n default:\n return;\n }\n\n e.preventDefault();\n this._focusTab(this.selectedTab);\n }\n\n private setSelectedTab(index: number) {\n this.selectedTab = index;\n /**\n * Fired when the selected tab changes.\n * @fires tab-change\n */\n this.dispatchEvent(new CustomEvent('tab-change', {detail: {tab: index}}));\n }\n\n private _focusTab(index: number) {\n const button = this.shadowRoot?.querySelector(\n `button[data-index=\"${index}\"]`\n ) as HTMLButtonElement;\n button?.focus();\n }\n\n private _generateTabHeaders() {\n return [...Array(this.nTabs)].map((_, index) => {\n const hasDivider =\n index !== this.nTabs - 1 &&\n this.selectedTab !== index &&\n index + 1 !== this.selectedTab;\n const tabIcon = this.hasTabIcons\n ? html`<span class=\"tab-icon\">\n <slot name=\"tab-icon-${index}\"></slot>\n </span>`\n : nothing;\n return html`\n <button\n class=\"tab-button ${hasDivider ? 'has-divider' : ''}\"\n role=\"tab\"\n aria-selected=\"${this.selectedTab === index}\"\n aria-controls=\"panel-${index}\"\n id=\"tab-${index}\"\n data-index=\"${index}\"\n tabindex=\"${this.selectedTab === index ? 0 : -1}\"\n @click=\"${() => this.setSelectedTab(index)}\"\n @focus=\"${() => this.setSelectedTab(index)}\"\n >\n <div class=\"tab-title-container\">\n ${tabIcon}\n <slot class=\"tab-title\" name=\"tab-title-${index}\"\n >Tab ${index + 1}</slot\n >\n </div>\n </button>\n `;\n });\n }\n\n private _generateTabPanels() {\n if (this.hasDefaultSlotOnly) {\n return html`<div\n role=\"tabpanel\"\n class=\"tab-content\"\n id=\"panel-${this.selectedTab}\"\n aria-labelledby=\"tab-${this.selectedTab}\"\n tabindex=\"0\"\n >\n <slot></slot>\n </div>`;\n }\n return [...Array(this.nTabs)].map(\n (_, index) => html`\n <div\n role=\"tabpanel\"\n id=\"panel-${index}\"\n aria-labelledby=\"tab-${index}\"\n tabindex=\"0\"\n ?hidden=\"${this.selectedTab !== index}\"\n >\n <slot name=\"tab-content-${index}\"></slot>\n </div>\n `\n );\n }\n\n override render() {\n return html`\n <div class=\"tab-container\" @keydown=\"${this._handleKeyDown}\">\n <div class=\"tab-header\" role=\"tablist\" aria-label=\"Tab List\">\n ${this._generateTabHeaders()}\n </div>\n <div class=\"tab-panels\">${this._generateTabPanels()}</div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-tabbed-card': ObcTabbedCard;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -146,7 +146,8 @@ export declare class ObcToggleButtonOption extends LitElement {
146
146
  */
147
147
  large: boolean;
148
148
  /**
149
- * @fires {CustomEvent<{value: string}>} selected - Fired when the option is clicked and not already selected.
149
+ * Fired when the option is clicked and not already selected.
150
+ * @fires selected
150
151
  */
151
152
  onClick(event: Event): void;
152
153
  render(): import('lit-html').TemplateResult<1>;
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-button-option.d.ts","sourceRoot":"","sources":["../../../src/components/toggle-button-option/toggle-button-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAMhD,oBAAY,yBAAyB;IACnC,IAAI,SAAS;IACb,IAAI,SAAS;IACb,aAAa,oBAAoB;IACjC,QAAQ,cAAc;CACvB;AAED,oBAAY,4BAA4B;IACtC,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,qBACa,qBAAsB,SAAQ,UAAU;IACnD;;OAEG;IACuB,KAAK,SAAW;IAE1C;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;OAEG;IACuC,SAAS,UAAS;IAE5D;;;;OAIG;IACuB,IAAI,4BAAkC;IAEhE;;;OAGG;IACuB,OAAO,+BAAwC;IAEzE;;;;OAIG;IACwB,OAAO,UAAS;IAE3C;;OAEG;IAEuC,WAAW,EAAE,OAAO,CAAQ;IAEtE;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;;;OAIG;IACuC,KAAK,UAAS;IAExD;;OAEG;IACH,OAAO,CAAC,KAAK,EAAE,KAAK;IAcX,MAAM;IA8Cf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,0BAA0B,EAAE,qBAAqB,CAAC;KACnD;CACF"}
1
+ {"version":3,"file":"toggle-button-option.d.ts","sourceRoot":"","sources":["../../../src/components/toggle-button-option/toggle-button-option.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAMhD,oBAAY,yBAAyB;IACnC,IAAI,SAAS;IACb,IAAI,SAAS;IACb,aAAa,oBAAoB;IACjC,QAAQ,cAAc;CACvB;AAED,oBAAY,4BAA4B;IACtC,IAAI,SAAS;IACb,OAAO,YAAY;IACnB,MAAM,WAAW;CAClB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA0FG;AACH,qBACa,qBAAsB,SAAQ,UAAU;IACnD;;OAEG;IACuB,KAAK,SAAW;IAE1C;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;OAEG;IACuC,SAAS,UAAS;IAE5D;;;;OAIG;IACuB,IAAI,4BAAkC;IAEhE;;;OAGG;IACuB,OAAO,+BAAwC;IAEzE;;;;OAIG;IACwB,OAAO,UAAS;IAE3C;;OAEG;IAEuC,WAAW,EAAE,OAAO,CAAQ;IAEtE;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;;;OAIG;IACuC,KAAK,UAAS;IAExD;;;OAGG;IACH,OAAO,CAAC,KAAK,EAAE,KAAK;IAcX,MAAM;IA8Cf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,0BAA0B,EAAE,qBAAqB,CAAC;KACnD;CACF"}
@@ -40,7 +40,8 @@ let ObcToggleButtonOption = class extends LitElement {
40
40
  this.large = false;
41
41
  }
42
42
  /**
43
- * @fires {CustomEvent<{value: string}>} selected - Fired when the option is clicked and not already selected.
43
+ * Fired when the option is clicked and not already selected.
44
+ * @fires selected
44
45
  */
45
46
  onClick(event) {
46
47
  if (this.disabled) {
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-button-option.js","sources":["../../../src/components/toggle-button-option/toggle-button-option.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport componentStyle from './toggle-button-option.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcToggleButtonOptionType {\n icon = 'icon',\n text = 'text',\n iconTextUnder = 'icon-text-under',\n iconText = 'text-icon',\n}\n\nexport enum ObcToggleButtonOptionVariant {\n flat = 'flat',\n regular = 'regular',\n normal = 'normal',\n}\n\n/**\n * `<obc-toggle-button-option>` – A single selectable option within a toggle button group.\n *\n * Represents an individual button option within an `<obc-toggle-button-group>`. This component should not\n * be used standalone; it is designed to function exclusively as a child element of a toggle button group,\n * which manages selection state and interaction logic.\n *\n * The option renders as a button with flexible content layouts (text, icon, or both) and provides visual\n * feedback for selection, activation, and disabled states. All styling properties (type, variant, size)\n * are typically propagated from the parent group to ensure visual consistency across all options.\n *\n * ### Features\n *\n * - **Selection state:** Displays a distinct visual style when selected, controlled by the parent group.\n * Only one option in a group can be selected at a time.\n * - **Activation state:** Shows temporary visual feedback when clicked, useful in external control scenarios\n * where the parent manages state updates asynchronously (e.g., waiting for API confirmation).\n * **TODO(designer)** – Clarify the exact visual difference between `activated` and `selected` states and when developers should use activation.\n * - **Disabled state:** Can be individually disabled while other options in the group remain interactive.\n * When disabled, the option is visually dimmed and does not respond to clicks. The parent group will skip\n * over disabled options when determining fallback selections.\n * - **Flexible content layouts:**\n * - `text`: Text label only (default).\n * - `icon`: Icon only (compact, ideal for limited space).\n * - `iconText`: Icon and text side-by-side.\n * - `iconTextUnder`: Icon stacked above text label.\n * - **Divider handling:** Supports automatic divider rendering between options. The `showDivider` property is\n * managed by the parent group to hide dividers after the selected option for a cohesive appearance.\n * - **Size variants:** Standard and large sizes supported via the `large` property for improved touch targets\n * and accessibility.\n *\n * ### Usage Guidelines\n *\n * **Always use `<obc-toggle-button-option>` as a child of `<obc-toggle-button-group>`.** The parent group\n * handles all selection logic, event coordination, and style propagation. Using this component outside a\n * group will result in non-functional behavior.\n *\n * **Ideal use cases:**\n * - As a building block for view toggles (list/grid/chart)\n * - As filter options within a segmented control\n * - As mode selectors in toolbars or control panels\n *\n * **Best Practices:**\n * - Assign a unique `value` to each option in the group to enable proper selection tracking.\n * - Use the default slot for text labels (short, descriptive text: 1-2 words ideal).\n * - Use the `icon` slot for icon content when the parent group's `type` includes icons.\n * - Avoid manually setting `type`, `variant`, `hugText`, or `large` properties; let the parent group propagate these for consistency.\n * - For icon-only options, ensure icons are universally understandable or provide tooltips for accessibility.\n * - Use the `disabled` property sparingly; if all options are disabled, consider disabling the entire group instead.\n *\n * **When not to use:**\n * - Do not use this component standalone without a parent `<obc-toggle-button-group>`.\n * - Do not use for multi-select scenarios (use checkboxes or chips instead).\n * - Do not use for standalone action buttons (use `<obc-button>` or similar instead).\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-----------|-----------------|---------|\n * | (default) | When `type` is `text`, `iconText`, or `iconTextUnder` | Text label content for the option. Keep concise (1-2 words). |\n * | icon | When `type` is `icon`, `iconText`, or `iconTextUnder` | Icon content for the option. Use OpenBridge icons like `<obi-placeholder>` or `<obi-search>`. |\n *\n * ### Events\n *\n * - `selected` – Fired when the option is clicked and is not already selected. The parent group listens to\n * this event to update selection state. Event detail: `{ value: string }`.\n *\n * ### Example\n *\n * ```html\n * <!-- Used within a toggle button group -->\n * <obc-toggle-button-group value=\"list\" type=\"iconText\">\n * <obc-toggle-button-option value=\"list\">\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * List\n * </obc-toggle-button-option>\n * <obc-toggle-button-option value=\"grid\">\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * Grid\n * </obc-toggle-button-option>\n * <obc-toggle-button-option value=\"chart\" disabled>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * Chart\n * </obc-toggle-button-option>\n * </obc-toggle-button-group>\n * ```\n *\n * @slot - Text label content for the option (when type includes text).\n * @slot icon - Icon content for the option (when type includes icons).\n * @fires {CustomEvent<{value: string}>} selected - Fired when the option is clicked and not already selected.\n */\n@customElement('obc-toggle-button-option')\nexport class ObcToggleButtonOption extends LitElement {\n /**\n * Value associated with this option. Used in selection events.\n */\n @property({type: String}) value = 'value';\n\n /**\n * Whether this option is currently selected (toggles visual state).\n */\n @property({type: Boolean, reflect: true}) selected = false;\n\n /**\n * Whether this option is currently activated (toggles visual state).\n */\n @property({type: Boolean, reflect: true}) activated = false;\n\n /**\n * Layout of icon and label.\n * One of: \"icon\", \"text\", \"icon-text-under\", \"text-icon\".\n * Controls which slots/content are displayed and their arrangement.\n */\n @property({type: String}) type = ObcToggleButtonOptionType.text;\n\n /**\n * The visual variant of the toggle button option.\n * One of: \"flat\", \"regular\", \"normal\".\n */\n @property({type: String}) variant = ObcToggleButtonOptionVariant.regular;\n\n /**\n * If true, button width shrinks to fit label content.\n *\n * @availableWhen type!=icon-text-under\n */\n @property({type: Boolean}) hugText = false;\n\n /**\n * If true, renders the divider between options.\n */\n // eslint-disable-next-line openbridge/prefer-boolean-property-default-false -- reflected attribute used by parent CSS\n @property({type: Boolean, reflect: true}) showDivider: boolean = true;\n\n /**\n * If true, the option is disabled and cannot be interacted with.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * If true, the option uses a larger size.\n *\n * @availableWhen type!=icon-text-under\n */\n @property({type: Boolean, reflect: true}) large = false;\n\n /**\n * @fires {CustomEvent<{value: string}>} selected - Fired when the option is clicked and not already selected.\n */\n onClick(event: Event) {\n if (this.disabled) {\n event.preventDefault();\n return;\n }\n\n // Only fire event if not already selected\n if (!this.selected) {\n this.dispatchEvent(\n new CustomEvent('selected', {detail: {value: this.value}})\n );\n }\n }\n\n override render() {\n const isInlineLabel =\n this.type === ObcToggleButtonOptionType.text ||\n this.type === ObcToggleButtonOptionType.iconText;\n const hasIcon = this.type !== ObcToggleButtonOptionType.text;\n const hasLabel = this.type !== ObcToggleButtonOptionType.icon;\n const isIconTextUnder =\n this.type === ObcToggleButtonOptionType.iconTextUnder;\n\n return html`\n <button\n class=${classMap({\n wrapper: true,\n selected: this.selected,\n 'inline-label': isInlineLabel,\n 'type-flat': this.variant === ObcToggleButtonOptionVariant.flat,\n 'type-regular': this.variant === ObcToggleButtonOptionVariant.regular,\n 'type-normal': this.variant === ObcToggleButtonOptionVariant.normal,\n 'icon-text-under': isIconTextUnder,\n 'hug-text': this.hugText,\n disabled: this.disabled,\n activated: this.activated,\n large: this.large,\n })}\n ?disabled=${this.disabled}\n @click=${this.onClick}\n >\n <div class=\"visible-wrapper\" part=\"visible-wrapper\">\n ${hasIcon\n ? html`<div class=\"icon\" part=\"icon\">\n <slot name=\"icon\"></slot>\n </div>`\n : ''}\n ${hasLabel && !isIconTextUnder\n ? html`<div class=\"label\"><slot></slot></div>`\n : ''}\n </div>\n ${hasLabel && isIconTextUnder\n ? html`<div class=\"label-container\">\n <div class=\"label\"><slot></slot></div>\n </div>`\n : ''}\n </button>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-button-option': ObcToggleButtonOption;\n }\n}\n"],"names":["ObcToggleButtonOptionType","ObcToggleButtonOptionVariant"],"mappings":"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"}
1
+ {"version":3,"file":"toggle-button-option.js","sources":["../../../src/components/toggle-button-option/toggle-button-option.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport componentStyle from './toggle-button-option.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\n\nexport enum ObcToggleButtonOptionType {\n icon = 'icon',\n text = 'text',\n iconTextUnder = 'icon-text-under',\n iconText = 'text-icon',\n}\n\nexport enum ObcToggleButtonOptionVariant {\n flat = 'flat',\n regular = 'regular',\n normal = 'normal',\n}\n\n/**\n * `<obc-toggle-button-option>` – A single selectable option within a toggle button group.\n *\n * Represents an individual button option within an `<obc-toggle-button-group>`. This component should not\n * be used standalone; it is designed to function exclusively as a child element of a toggle button group,\n * which manages selection state and interaction logic.\n *\n * The option renders as a button with flexible content layouts (text, icon, or both) and provides visual\n * feedback for selection, activation, and disabled states. All styling properties (type, variant, size)\n * are typically propagated from the parent group to ensure visual consistency across all options.\n *\n * ### Features\n *\n * - **Selection state:** Displays a distinct visual style when selected, controlled by the parent group.\n * Only one option in a group can be selected at a time.\n * - **Activation state:** Shows temporary visual feedback when clicked, useful in external control scenarios\n * where the parent manages state updates asynchronously (e.g., waiting for API confirmation).\n * **TODO(designer)** – Clarify the exact visual difference between `activated` and `selected` states and when developers should use activation.\n * - **Disabled state:** Can be individually disabled while other options in the group remain interactive.\n * When disabled, the option is visually dimmed and does not respond to clicks. The parent group will skip\n * over disabled options when determining fallback selections.\n * - **Flexible content layouts:**\n * - `text`: Text label only (default).\n * - `icon`: Icon only (compact, ideal for limited space).\n * - `iconText`: Icon and text side-by-side.\n * - `iconTextUnder`: Icon stacked above text label.\n * - **Divider handling:** Supports automatic divider rendering between options. The `showDivider` property is\n * managed by the parent group to hide dividers after the selected option for a cohesive appearance.\n * - **Size variants:** Standard and large sizes supported via the `large` property for improved touch targets\n * and accessibility.\n *\n * ### Usage Guidelines\n *\n * **Always use `<obc-toggle-button-option>` as a child of `<obc-toggle-button-group>`.** The parent group\n * handles all selection logic, event coordination, and style propagation. Using this component outside a\n * group will result in non-functional behavior.\n *\n * **Ideal use cases:**\n * - As a building block for view toggles (list/grid/chart)\n * - As filter options within a segmented control\n * - As mode selectors in toolbars or control panels\n *\n * **Best Practices:**\n * - Assign a unique `value` to each option in the group to enable proper selection tracking.\n * - Use the default slot for text labels (short, descriptive text: 1-2 words ideal).\n * - Use the `icon` slot for icon content when the parent group's `type` includes icons.\n * - Avoid manually setting `type`, `variant`, `hugText`, or `large` properties; let the parent group propagate these for consistency.\n * - For icon-only options, ensure icons are universally understandable or provide tooltips for accessibility.\n * - Use the `disabled` property sparingly; if all options are disabled, consider disabling the entire group instead.\n *\n * **When not to use:**\n * - Do not use this component standalone without a parent `<obc-toggle-button-group>`.\n * - Do not use for multi-select scenarios (use checkboxes or chips instead).\n * - Do not use for standalone action buttons (use `<obc-button>` or similar instead).\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-----------|-----------------|---------|\n * | (default) | When `type` is `text`, `iconText`, or `iconTextUnder` | Text label content for the option. Keep concise (1-2 words). |\n * | icon | When `type` is `icon`, `iconText`, or `iconTextUnder` | Icon content for the option. Use OpenBridge icons like `<obi-placeholder>` or `<obi-search>`. |\n *\n * ### Events\n *\n * - `selected` – Fired when the option is clicked and is not already selected. The parent group listens to\n * this event to update selection state. Event detail: `{ value: string }`.\n *\n * ### Example\n *\n * ```html\n * <!-- Used within a toggle button group -->\n * <obc-toggle-button-group value=\"list\" type=\"iconText\">\n * <obc-toggle-button-option value=\"list\">\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * List\n * </obc-toggle-button-option>\n * <obc-toggle-button-option value=\"grid\">\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * Grid\n * </obc-toggle-button-option>\n * <obc-toggle-button-option value=\"chart\" disabled>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * Chart\n * </obc-toggle-button-option>\n * </obc-toggle-button-group>\n * ```\n *\n * @slot - Text label content for the option (when type includes text).\n * @slot icon - Icon content for the option (when type includes icons).\n * @fires {CustomEvent<{value: string}>} selected - Fired when the option is clicked and not already selected.\n */\n@customElement('obc-toggle-button-option')\nexport class ObcToggleButtonOption extends LitElement {\n /**\n * Value associated with this option. Used in selection events.\n */\n @property({type: String}) value = 'value';\n\n /**\n * Whether this option is currently selected (toggles visual state).\n */\n @property({type: Boolean, reflect: true}) selected = false;\n\n /**\n * Whether this option is currently activated (toggles visual state).\n */\n @property({type: Boolean, reflect: true}) activated = false;\n\n /**\n * Layout of icon and label.\n * One of: \"icon\", \"text\", \"icon-text-under\", \"text-icon\".\n * Controls which slots/content are displayed and their arrangement.\n */\n @property({type: String}) type = ObcToggleButtonOptionType.text;\n\n /**\n * The visual variant of the toggle button option.\n * One of: \"flat\", \"regular\", \"normal\".\n */\n @property({type: String}) variant = ObcToggleButtonOptionVariant.regular;\n\n /**\n * If true, button width shrinks to fit label content.\n *\n * @availableWhen type!=icon-text-under\n */\n @property({type: Boolean}) hugText = false;\n\n /**\n * If true, renders the divider between options.\n */\n // eslint-disable-next-line openbridge/prefer-boolean-property-default-false -- reflected attribute used by parent CSS\n @property({type: Boolean, reflect: true}) showDivider: boolean = true;\n\n /**\n * If true, the option is disabled and cannot be interacted with.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * If true, the option uses a larger size.\n *\n * @availableWhen type!=icon-text-under\n */\n @property({type: Boolean, reflect: true}) large = false;\n\n /**\n * Fired when the option is clicked and not already selected.\n * @fires selected\n */\n onClick(event: Event) {\n if (this.disabled) {\n event.preventDefault();\n return;\n }\n\n // Only fire event if not already selected\n if (!this.selected) {\n this.dispatchEvent(\n new CustomEvent('selected', {detail: {value: this.value}})\n );\n }\n }\n\n override render() {\n const isInlineLabel =\n this.type === ObcToggleButtonOptionType.text ||\n this.type === ObcToggleButtonOptionType.iconText;\n const hasIcon = this.type !== ObcToggleButtonOptionType.text;\n const hasLabel = this.type !== ObcToggleButtonOptionType.icon;\n const isIconTextUnder =\n this.type === ObcToggleButtonOptionType.iconTextUnder;\n\n return html`\n <button\n class=${classMap({\n wrapper: true,\n selected: this.selected,\n 'inline-label': isInlineLabel,\n 'type-flat': this.variant === ObcToggleButtonOptionVariant.flat,\n 'type-regular': this.variant === ObcToggleButtonOptionVariant.regular,\n 'type-normal': this.variant === ObcToggleButtonOptionVariant.normal,\n 'icon-text-under': isIconTextUnder,\n 'hug-text': this.hugText,\n disabled: this.disabled,\n activated: this.activated,\n large: this.large,\n })}\n ?disabled=${this.disabled}\n @click=${this.onClick}\n >\n <div class=\"visible-wrapper\" part=\"visible-wrapper\">\n ${hasIcon\n ? html`<div class=\"icon\" part=\"icon\">\n <slot name=\"icon\"></slot>\n </div>`\n : ''}\n ${hasLabel && !isIconTextUnder\n ? html`<div class=\"label\"><slot></slot></div>`\n : ''}\n </div>\n ${hasLabel && isIconTextUnder\n ? html`<div class=\"label-container\">\n <div class=\"label\"><slot></slot></div>\n </div>`\n : ''}\n </button>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-button-option': ObcToggleButtonOption;\n }\n}\n"],"names":["ObcToggleButtonOptionType","ObcToggleButtonOptionVariant"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-button-vertical-group.js","sources":["../../../src/components/toggle-button-vertical-group/toggle-button-vertical-group.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS, PropertyValues} from 'lit';\nimport {property, queryAssignedElements} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport {classMap} from 'lit/directives/class-map.js';\n\nimport {\n ObcToggleButtonVerticalOption,\n ObcToggleButtonVerticalOptionType,\n} from '../toggle-button-vertical-option/toggle-button-vertical-option.js';\n\nimport style from './toggle-button-vertical-group.css?inline';\n\nexport type ObcToggleButtonVerticalGroupValueChangeEvent = CustomEvent<{\n value: string;\n previousValue: string;\n}>;\n\nexport type ObcToggleButtonVerticalGroupChangeEvent = CustomEvent<{\n value: string;\n}>;\n\n/**\n * `<obc-toggle-button-vertical-group>` – A vertically oriented segmented control for selecting a single option from a set.\n *\n * Provides a vertical stack of connected toggle buttons where only one option can be selected at a time.\n * Each option is represented by an `<obc-toggle-button-vertical-option>` child element. The group manages selection\n * state automatically, deselecting the previous option when a new one is chosen.\n *\n * Appears as a visually unified vertical column of buttons with clear selection indicators. Commonly used for sidebar\n * navigation, vertical filter controls, or mode selection in vertical layouts. Ideal for scenarios where vertical\n * space is available and horizontal space is limited, such as side panels or navigation drawers.\n *\n * ### Features\n *\n * - **Single selection mode:** Only one option can be active at a time; selecting a new option automatically\n * deselects the previous one. Similar to radio button behavior but with a button-like vertical appearance.\n * - **Visual variants:**\n * - `regular` (default): Standard appearance with full background and border styling.\n * - `flat`: Minimal style with reduced visual weight, no prominent background or border.\n * - `normal`: **TODO(designer)** – Clarify the visual difference and intended use case for the `normal` variant compared to `regular` and `flat`.\n * - **Layout behavior:**\n * - By default, the group stretches to fill available container width, with options stacked vertically.\n * - When `hugWidth` is true, the group shrinks to fit its content width instead of expanding.\n * - **Empty selection mode:** When `allowEmptySelection` is true, a `value` that does not match any enabled\n * option leaves the group with no option selected, instead of defaulting to the first enabled option. Use\n * this when a selection may legitimately be absent (e.g. unset, loading, or error states) so the UI does not\n * imply a choice the user has not made.\n * - **Disabled state:** Setting `disabled` on the group disables all contained options at once. Individual\n * options can also be disabled independently while the group remains enabled.\n * - **Divider management:** Automatically shows visual dividers between options and hides the divider after\n * the last option for a clean, unified appearance.\n * - **Property propagation:** The group automatically synchronizes the `type` property to all child\n * `<obc-toggle-button-vertical-option>` elements for consistent styling.\n * - **Automatic fallback selection:** If the current value is set to a disabled or non-existent option, the\n * group automatically selects the first enabled option to ensure a valid state.\n *\n * ### Usage Guidelines\n *\n * Use `<obc-toggle-button-vertical-group>` when you need users to choose exactly one option from a small set of\n * mutually exclusive choices (typically 2-5 options) in a vertical layout. It provides a more compact and visually\n * integrated alternative to radio buttons for vertical navigation or control panels.\n *\n * **Ideal use cases:**\n * - Sidebar navigation toggles (e.g., dashboard/reports/settings views)\n * - Vertical filter controls (e.g., all/active/archived items)\n * - Mode selectors in vertical panels (e.g., edit/preview/code modes)\n * - View toggles in constrained horizontal spaces (e.g., mobile side panels)\n * - Control panels with vertical layout preference\n *\n * **When not to use:**\n * - For binary on/off choices, use a switch or checkbox instead.\n * - For multiple selections from a set, use checkboxes or chips.\n * - For many options (6+), consider a dropdown/select or radio button list for better scannability.\n * - For horizontal layouts with adequate space, use `<obc-toggle-button-group>` instead.\n * - For navigation between pages or sections, use tabs or a navigation menu.\n *\n * **Best Practices:**\n * - Each option must have a unique `value` property to prevent selection conflicts.\n * - Provide clear, concise labels for each option. Keep text short (1-2 words ideal).\n * - For icon-only buttons, ensure icons are universally recognizable or provide tooltips.\n * - Set an initial `value` to indicate the default selection, or the first enabled option will be selected automatically.\n * - Avoid disabling the currently selected option; if an option becomes unavailable, selection will shift to the first enabled option.\n * - Use `type=\"flat\"` in dense UIs or when the toggle is secondary to other content.\n * - Ensure adequate vertical space for the number of options to avoid excessive scrolling or cramped layouts.\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-----------|-----------------|---------|\n * | (default) | Always | Place one or more `<obc-toggle-button-vertical-option>` elements here to define the selectable options in the group. Each option can include an icon via its own `icon` slot. |\n *\n * ### Events\n *\n * - `value` – Fired when the selected value changes, either through user interaction or programmatic change.\n * Event detail: `{ value: string, previousValue: string }`. Listen to this event to react to selection changes.\n *\n * ### Example\n *\n * ```html\n * <obc-toggle-button-vertical-group value=\"list\" type=\"regular\">\n * <obc-toggle-button-vertical-option value=\"list\" label=\"List\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * <obc-toggle-button-vertical-option value=\"grid\" label=\"Grid\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * <obc-toggle-button-vertical-option value=\"table\" label=\"Table\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * </obc-toggle-button-vertical-group>\n * ```\n *\n * @slot - Place one or more `<obc-toggle-button-vertical-option>` elements here to define the selectable options.\n * @fires {CustomEvent<{value: string, previousValue: string}>} value - Fired when the selected value changes.\n * @fires {CustomEvent<{value: string}>} change - Fired when the selected value changes by user interaction.\n * @stable\n */\n@customElement('obc-toggle-button-vertical-group')\nexport class ObcToggleButtonVerticalGroup extends LitElement {\n /**\n * The value of the currently selected option.\n *\n * Setting this property programmatically updates the selection. If the value does not match any enabled option, the group selects the first available enabled option.\n */\n @property({type: String}) value = '';\n\n /**\n * Visual style for all options in the group.\n *\n * One of: \"flat\", \"regular\", \"normal\".\n */\n @property({type: String}) type = ObcToggleButtonVerticalOptionType.regular;\n\n /**\n * If true, the group shrinks to fit its content width instead of stretching to fill its container.\n *\n * Defaults to false.\n */\n @property({type: Boolean}) hugWidth = false;\n\n /**\n * If true, a `value` that does not match any enabled option leaves the group with no option selected\n * instead of defaulting to the first enabled option.\n *\n * This also applies when the currently selected option becomes disabled: the group clears its selection\n * rather than falling back to another option.\n *\n * Defaults to false (the first enabled option is selected when the value does not match).\n */\n @property({type: Boolean}) allowEmptySelection = false;\n\n /**\n * Disables the entire group and all contained options.\n *\n * When set to true, all options become non-interactive, regardless of their individual disabled state.\n *\n * Defaults to false.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n @queryAssignedElements({selector: 'obc-toggle-button-vertical-option'})\n private options!: NodeListOf<ObcToggleButtonVerticalOption>;\n\n private _originalDisabledStates = new Map<\n ObcToggleButtonVerticalOption,\n boolean\n >();\n\n private hasAnyEnabledOption(): boolean {\n if (this.disabled) return false;\n return Array.from(this.options).some((opt) => !opt.disabled);\n }\n\n private canSelectOption(value: string): boolean {\n if (this.disabled) return false;\n const option = this.getOptionByValue(value);\n return option !== null && !option.disabled;\n }\n\n private getOptionByValue(\n value: string\n ): ObcToggleButtonVerticalOption | null {\n return Array.from(this.options).find((opt) => opt.value === value) || null;\n }\n\n private getFirstSelectableOption(): ObcToggleButtonVerticalOption | null {\n if (this.disabled) return null;\n return Array.from(this.options).find((opt) => !opt.disabled) || null;\n }\n\n private updateSelection(\n newValue: string,\n emitValueEvent: boolean = true,\n emitChangeEvent: boolean = false\n ) {\n const oldValue = this.value;\n\n if (!this.hasAnyEnabledOption()) {\n this.options.forEach((option) => {\n option.selected = option.value === this.value;\n });\n this.updateDividers();\n return;\n }\n\n if (!this.canSelectOption(newValue)) {\n if (this.value && this.getOptionByValue(this.value)) {\n this.options.forEach((option) => {\n option.selected = option.value === this.value;\n });\n this.updateDividers();\n return;\n }\n if (this.allowEmptySelection) {\n newValue = '';\n } else {\n const fallback = this.getFirstSelectableOption();\n newValue = fallback?.value || '';\n }\n }\n\n this.value = newValue;\n\n this.options.forEach((option) => {\n option.selected = option.value === newValue;\n });\n\n this.updateDividers();\n\n if (emitValueEvent && oldValue !== newValue) {\n /**\n * Fired when the selected option changes.\n *\n * The event detail contains the new value and the previous value:\n * `{ value: string, previousValue: string }`\n *\n * @event value - Fired when the selected value changes.\n */\n this.dispatchEvent(\n new CustomEvent('value', {\n detail: {value: newValue, previousValue: oldValue},\n })\n );\n }\n\n if (emitChangeEvent && oldValue !== newValue) {\n /**\n * Fired when the selected value changes by user interaction.\n *\n * The event detail contains the new value:\n * `{ value: string }`\n *\n * @event change - Fired when the selected value changes by user interaction.\n */\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: newValue},\n })\n );\n }\n }\n\n protected override firstUpdated(changed: PropertyValues) {\n super.firstUpdated(changed);\n\n const values = Array.from(this.options).map((opt) => opt.value);\n const uniqueValues = new Set(values);\n if (values.length !== uniqueValues.size) {\n console.warn(\n 'Toggle button vertical group has duplicate values. This may cause unexpected behavior.'\n );\n }\n\n this.options.forEach((opt) => {\n this._originalDisabledStates.set(opt, opt.disabled);\n\n opt.addEventListener('selected', (e) => this.onOptionSelected(e));\n\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (\n mutation.attributeName === 'disabled' &&\n !opt.hasAttribute('data-group-disabled')\n ) {\n this._originalDisabledStates.set(opt, opt.disabled);\n this.handleOptionDisabledChange();\n }\n });\n });\n observer.observe(opt, {attributes: true, attributeFilter: ['disabled']});\n\n opt.type = this.type;\n\n if (this.disabled) {\n opt.setAttribute('data-group-disabled', 'true');\n opt.disabled = true;\n }\n });\n\n if (!this.value || !this.getOptionByValue(this.value)) {\n if (this.allowEmptySelection) {\n this.updateSelection('', false);\n } else {\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value, false);\n }\n }\n } else {\n this.updateSelection(this.value, false);\n }\n }\n\n private handleOptionDisabledChange() {\n const currentOption = this.getOptionByValue(this.value);\n if (currentOption?.disabled && this.hasAnyEnabledOption()) {\n if (this.allowEmptySelection) {\n this.updateSelection('');\n return;\n }\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value);\n }\n }\n }\n\n override willUpdate(changed: PropertyValues): void {\n if (changed.has('value')) {\n this.updateSelection(this.value);\n }\n\n if (changed.has('type')) {\n this.options.forEach((opt) => {\n opt.type = this.type;\n });\n }\n\n if (changed.has('disabled')) {\n this.options.forEach((option) => {\n if (this.disabled) {\n option.setAttribute('data-group-disabled', 'true');\n option.disabled = true;\n } else {\n option.removeAttribute('data-group-disabled');\n const originalState =\n this._originalDisabledStates.get(option) || false;\n option.disabled = originalState;\n }\n });\n }\n }\n\n override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n const currentOption = this.getOptionByValue(this.value);\n if (currentOption?.disabled && this.hasAnyEnabledOption()) {\n if (this.allowEmptySelection) {\n this.updateSelection('');\n return;\n }\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value);\n }\n }\n }\n\n private updateDividers(): void {\n const last = this.options.length - 1;\n this.options.forEach((opt, idx) => {\n opt.showDivider = idx !== last;\n });\n }\n\n private onOptionSelected(e: Event): void {\n const {value} = (e as CustomEvent).detail;\n this.updateSelection(value, true, true);\n }\n\n override render() {\n const classes = {\n 'outer-wrapper': true,\n flat: this.type === ObcToggleButtonVerticalOptionType.flat,\n regular: this.type === ObcToggleButtonVerticalOptionType.regular,\n normal: this.type === ObcToggleButtonVerticalOptionType.normal,\n 'hug-width': this.hugWidth,\n disabled: this.disabled,\n };\n\n return html`\n <div class=${classMap(classes)}>\n <div class=\"wrapper\"><slot></slot></div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(style);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-button-vertical-group': ObcToggleButtonVerticalGroup;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toggle-button-vertical-group.js","sources":["../../../src/components/toggle-button-vertical-group/toggle-button-vertical-group.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS, PropertyValues} from 'lit';\nimport {property, queryAssignedElements} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport {classMap} from 'lit/directives/class-map.js';\n\nimport {\n ObcToggleButtonVerticalOption,\n ObcToggleButtonVerticalOptionType,\n} from '../toggle-button-vertical-option/toggle-button-vertical-option.js';\n\nimport style from './toggle-button-vertical-group.css?inline';\n\nexport type ObcToggleButtonVerticalGroupValueChangeEvent = CustomEvent<{\n value: string;\n previousValue: string;\n}>;\n\nexport type ObcToggleButtonVerticalGroupChangeEvent = CustomEvent<{\n value: string;\n}>;\n\n/**\n * `<obc-toggle-button-vertical-group>` – A vertically oriented segmented control for selecting a single option from a set.\n *\n * Provides a vertical stack of connected toggle buttons where only one option can be selected at a time.\n * Each option is represented by an `<obc-toggle-button-vertical-option>` child element. The group manages selection\n * state automatically, deselecting the previous option when a new one is chosen.\n *\n * Appears as a visually unified vertical column of buttons with clear selection indicators. Commonly used for sidebar\n * navigation, vertical filter controls, or mode selection in vertical layouts. Ideal for scenarios where vertical\n * space is available and horizontal space is limited, such as side panels or navigation drawers.\n *\n * ### Features\n *\n * - **Single selection mode:** Only one option can be active at a time; selecting a new option automatically\n * deselects the previous one. Similar to radio button behavior but with a button-like vertical appearance.\n * - **Visual variants:**\n * - `regular` (default): Standard appearance with full background and border styling.\n * - `flat`: Minimal style with reduced visual weight, no prominent background or border.\n * - `normal`: **TODO(designer)** – Clarify the visual difference and intended use case for the `normal` variant compared to `regular` and `flat`.\n * - **Layout behavior:**\n * - By default, the group stretches to fill available container width, with options stacked vertically.\n * - When `hugWidth` is true, the group shrinks to fit its content width instead of expanding.\n * - **Empty selection mode:** When `allowEmptySelection` is true, a `value` that does not match any enabled\n * option leaves the group with no option selected, instead of defaulting to the first enabled option. Use\n * this when a selection may legitimately be absent (e.g. unset, loading, or error states) so the UI does not\n * imply a choice the user has not made.\n * - **Disabled state:** Setting `disabled` on the group disables all contained options at once. Individual\n * options can also be disabled independently while the group remains enabled.\n * - **Divider management:** Automatically shows visual dividers between options and hides the divider after\n * the last option for a clean, unified appearance.\n * - **Property propagation:** The group automatically synchronizes the `type` property to all child\n * `<obc-toggle-button-vertical-option>` elements for consistent styling.\n * - **Automatic fallback selection:** If the current value is set to a disabled or non-existent option, the\n * group automatically selects the first enabled option to ensure a valid state.\n *\n * ### Usage Guidelines\n *\n * Use `<obc-toggle-button-vertical-group>` when you need users to choose exactly one option from a small set of\n * mutually exclusive choices (typically 2-5 options) in a vertical layout. It provides a more compact and visually\n * integrated alternative to radio buttons for vertical navigation or control panels.\n *\n * **Ideal use cases:**\n * - Sidebar navigation toggles (e.g., dashboard/reports/settings views)\n * - Vertical filter controls (e.g., all/active/archived items)\n * - Mode selectors in vertical panels (e.g., edit/preview/code modes)\n * - View toggles in constrained horizontal spaces (e.g., mobile side panels)\n * - Control panels with vertical layout preference\n *\n * **When not to use:**\n * - For binary on/off choices, use a switch or checkbox instead.\n * - For multiple selections from a set, use checkboxes or chips.\n * - For many options (6+), consider a dropdown/select or radio button list for better scannability.\n * - For horizontal layouts with adequate space, use `<obc-toggle-button-group>` instead.\n * - For navigation between pages or sections, use tabs or a navigation menu.\n *\n * **Best Practices:**\n * - Each option must have a unique `value` property to prevent selection conflicts.\n * - Provide clear, concise labels for each option. Keep text short (1-2 words ideal).\n * - For icon-only buttons, ensure icons are universally recognizable or provide tooltips.\n * - Set an initial `value` to indicate the default selection, or the first enabled option will be selected automatically.\n * - Avoid disabling the currently selected option; if an option becomes unavailable, selection will shift to the first enabled option.\n * - Use `type=\"flat\"` in dense UIs or when the toggle is secondary to other content.\n * - Ensure adequate vertical space for the number of options to avoid excessive scrolling or cramped layouts.\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-----------|-----------------|---------|\n * | (default) | Always | Place one or more `<obc-toggle-button-vertical-option>` elements here to define the selectable options in the group. Each option can include an icon via its own `icon` slot. |\n *\n * ### Events\n *\n * - `value` – Fired when the selected value changes, either through user interaction or programmatic change.\n * Event detail: `{ value: string, previousValue: string }`. Listen to this event to react to selection changes.\n *\n * ### Example\n *\n * ```html\n * <obc-toggle-button-vertical-group value=\"list\" type=\"regular\">\n * <obc-toggle-button-vertical-option value=\"list\" label=\"List\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * <obc-toggle-button-vertical-option value=\"grid\" label=\"Grid\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * <obc-toggle-button-vertical-option value=\"table\" label=\"Table\" hasIcon>\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-button-vertical-option>\n * </obc-toggle-button-vertical-group>\n * ```\n *\n * @slot - Place one or more `<obc-toggle-button-vertical-option>` elements here to define the selectable options.\n * @fires {CustomEvent<{value: string, previousValue: string}>} value - Fired when the selected value changes.\n * @fires {CustomEvent<{value: string}>} change - Fired when the selected value changes by user interaction.\n * @stable\n */\n@customElement('obc-toggle-button-vertical-group')\nexport class ObcToggleButtonVerticalGroup extends LitElement {\n /**\n * The value of the currently selected option.\n *\n * Setting this property programmatically updates the selection. If the value does not match any enabled option, the group selects the first available enabled option.\n */\n @property({type: String}) value = '';\n\n /**\n * Visual style for all options in the group.\n *\n * One of: \"flat\", \"regular\", \"normal\".\n */\n @property({type: String}) type = ObcToggleButtonVerticalOptionType.regular;\n\n /**\n * If true, the group shrinks to fit its content width instead of stretching to fill its container.\n *\n * Defaults to false.\n */\n @property({type: Boolean}) hugWidth = false;\n\n /**\n * If true, a `value` that does not match any enabled option leaves the group with no option selected\n * instead of defaulting to the first enabled option.\n *\n * This also applies when the currently selected option becomes disabled: the group clears its selection\n * rather than falling back to another option.\n *\n * Defaults to false (the first enabled option is selected when the value does not match).\n */\n @property({type: Boolean}) allowEmptySelection = false;\n\n /**\n * Disables the entire group and all contained options.\n *\n * When set to true, all options become non-interactive, regardless of their individual disabled state.\n *\n * Defaults to false.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n @queryAssignedElements({selector: 'obc-toggle-button-vertical-option'})\n private options!: NodeListOf<ObcToggleButtonVerticalOption>;\n\n private _originalDisabledStates = new Map<\n ObcToggleButtonVerticalOption,\n boolean\n >();\n\n private hasAnyEnabledOption(): boolean {\n if (this.disabled) return false;\n return Array.from(this.options).some((opt) => !opt.disabled);\n }\n\n private canSelectOption(value: string): boolean {\n if (this.disabled) return false;\n const option = this.getOptionByValue(value);\n return option !== null && !option.disabled;\n }\n\n private getOptionByValue(\n value: string\n ): ObcToggleButtonVerticalOption | null {\n return Array.from(this.options).find((opt) => opt.value === value) || null;\n }\n\n private getFirstSelectableOption(): ObcToggleButtonVerticalOption | null {\n if (this.disabled) return null;\n return Array.from(this.options).find((opt) => !opt.disabled) || null;\n }\n\n private updateSelection(\n newValue: string,\n emitValueEvent: boolean = true,\n emitChangeEvent: boolean = false\n ) {\n const oldValue = this.value;\n\n if (!this.hasAnyEnabledOption()) {\n this.options.forEach((option) => {\n option.selected = option.value === this.value;\n });\n this.updateDividers();\n return;\n }\n\n if (!this.canSelectOption(newValue)) {\n if (this.value && this.getOptionByValue(this.value)) {\n this.options.forEach((option) => {\n option.selected = option.value === this.value;\n });\n this.updateDividers();\n return;\n }\n if (this.allowEmptySelection) {\n newValue = '';\n } else {\n const fallback = this.getFirstSelectableOption();\n newValue = fallback?.value || '';\n }\n }\n\n this.value = newValue;\n\n this.options.forEach((option) => {\n option.selected = option.value === newValue;\n });\n\n this.updateDividers();\n\n if (emitValueEvent && oldValue !== newValue) {\n /**\n * Fired when the selected option changes.\n *\n * The event detail contains the new value and the previous value:\n * `{ value: string, previousValue: string }`\n *\n * @event value\n */\n this.dispatchEvent(\n new CustomEvent('value', {\n detail: {value: newValue, previousValue: oldValue},\n })\n );\n }\n\n if (emitChangeEvent && oldValue !== newValue) {\n /**\n * Fired when the selected value changes by user interaction.\n *\n * The event detail contains the new value:\n * `{ value: string }`\n *\n * @event change\n */\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: newValue},\n })\n );\n }\n }\n\n protected override firstUpdated(changed: PropertyValues) {\n super.firstUpdated(changed);\n\n const values = Array.from(this.options).map((opt) => opt.value);\n const uniqueValues = new Set(values);\n if (values.length !== uniqueValues.size) {\n console.warn(\n 'Toggle button vertical group has duplicate values. This may cause unexpected behavior.'\n );\n }\n\n this.options.forEach((opt) => {\n this._originalDisabledStates.set(opt, opt.disabled);\n\n opt.addEventListener('selected', (e) => this.onOptionSelected(e));\n\n const observer = new MutationObserver((mutations) => {\n mutations.forEach((mutation) => {\n if (\n mutation.attributeName === 'disabled' &&\n !opt.hasAttribute('data-group-disabled')\n ) {\n this._originalDisabledStates.set(opt, opt.disabled);\n this.handleOptionDisabledChange();\n }\n });\n });\n observer.observe(opt, {attributes: true, attributeFilter: ['disabled']});\n\n opt.type = this.type;\n\n if (this.disabled) {\n opt.setAttribute('data-group-disabled', 'true');\n opt.disabled = true;\n }\n });\n\n if (!this.value || !this.getOptionByValue(this.value)) {\n if (this.allowEmptySelection) {\n this.updateSelection('', false);\n } else {\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value, false);\n }\n }\n } else {\n this.updateSelection(this.value, false);\n }\n }\n\n private handleOptionDisabledChange() {\n const currentOption = this.getOptionByValue(this.value);\n if (currentOption?.disabled && this.hasAnyEnabledOption()) {\n if (this.allowEmptySelection) {\n this.updateSelection('');\n return;\n }\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value);\n }\n }\n }\n\n override willUpdate(changed: PropertyValues): void {\n if (changed.has('value')) {\n this.updateSelection(this.value);\n }\n\n if (changed.has('type')) {\n this.options.forEach((opt) => {\n opt.type = this.type;\n });\n }\n\n if (changed.has('disabled')) {\n this.options.forEach((option) => {\n if (this.disabled) {\n option.setAttribute('data-group-disabled', 'true');\n option.disabled = true;\n } else {\n option.removeAttribute('data-group-disabled');\n const originalState =\n this._originalDisabledStates.get(option) || false;\n option.disabled = originalState;\n }\n });\n }\n }\n\n override updated(changedProperties: PropertyValues) {\n super.updated(changedProperties);\n\n const currentOption = this.getOptionByValue(this.value);\n if (currentOption?.disabled && this.hasAnyEnabledOption()) {\n if (this.allowEmptySelection) {\n this.updateSelection('');\n return;\n }\n const firstSelectable = this.getFirstSelectableOption();\n if (firstSelectable) {\n this.updateSelection(firstSelectable.value);\n }\n }\n }\n\n private updateDividers(): void {\n const last = this.options.length - 1;\n this.options.forEach((opt, idx) => {\n opt.showDivider = idx !== last;\n });\n }\n\n private onOptionSelected(e: Event): void {\n const {value} = (e as CustomEvent).detail;\n this.updateSelection(value, true, true);\n }\n\n override render() {\n const classes = {\n 'outer-wrapper': true,\n flat: this.type === ObcToggleButtonVerticalOptionType.flat,\n regular: this.type === ObcToggleButtonVerticalOptionType.regular,\n normal: this.type === ObcToggleButtonVerticalOptionType.normal,\n 'hug-width': this.hugWidth,\n disabled: this.disabled,\n };\n\n return html`\n <div class=${classMap(classes)}>\n <div class=\"wrapper\"><slot></slot></div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(style);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-button-vertical-group': ObcToggleButtonVerticalGroup;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -140,7 +140,7 @@ export declare class ObcToggleSwitch extends LitElement {
140
140
  * Handles input events to change the toggle state.
141
141
  * Prevents changes if the toggle is disabled.
142
142
  * @param e {InputEvent}
143
- * @fires input - Dispatched when the value of the input changes
143
+ * @fires input
144
144
  */
145
145
  private _tryChange;
146
146
  private _fireChangeEvent;
@@ -30,7 +30,7 @@ let ObcToggleSwitch = class extends LitElement {
30
30
  * Handles input events to change the toggle state.
31
31
  * Prevents changes if the toggle is disabled.
32
32
  * @param e {InputEvent}
33
- * @fires input - Dispatched when the value of the input changes
33
+ * @fires input
34
34
  */
35
35
  _tryChange(e) {
36
36
  if (this.disabled) {
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-switch.js","sources":["../../../src/components/toggle-switch/toggle-switch.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport '../icon-button/icon-button.js';\nimport componentStyle from './toggle-switch.css?inline';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcToggleSwitchInputEvent = CustomEvent<{\n checked: boolean;\n}>;\n\nexport type ObcToggleSwitchChangeEvent = CustomEvent<{\n checked: boolean;\n}>;\n\n/**\n * `<obc-toggle-switch>` – A toggle switch component for binary on/off selection (also known as a switch, toggle, or enable/disable control).\n *\n * Provides a visual switch control for toggling between two states (checked/unchecked), commonly used for enabling or disabling a setting or feature. The component supports an optional label, description, icon, and divider for flexible presentation in lists or forms.\n *\n * ---\n *\n * ### Features\n * - **Binary toggle:** Allows users to switch between checked (on) and unchecked (off) states.\n * - **Label and Description:** Displays a primary label and an optional secondary description for context.\n * - **Icon Support:** Can display a leading icon via the `icon` slot for visual emphasis.\n * - **Disabled State:** Can be set to disabled, preventing user interaction and visually indicating inactivity.\n * - **Bottom Divider:** Optional divider for use in lists or grouped settings.\n * - **Responsive Layout:** Adapts label/description layout based on content; long descriptions are truncated with ellipsis.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-toggle-switch` for settings or preferences that require a simple on/off or enable/disable control. Ideal for scenarios where the user needs to quickly toggle a feature, such as activating notifications, enabling dark mode, or switching connectivity options. Avoid using for mutually exclusive choices—use radio buttons for those cases.\n *\n * - Place in forms, settings panels, or lists where binary choices are needed.\n * - Use the description property to clarify the effect of the toggle if the label alone is not sufficient.\n * - If an icon is relevant, provide it via the `icon` slot to reinforce the meaning.\n * - For accessibility, ensure the label clearly describes the toggle's function.\n *\n * ---\n *\n * ### Slots\n * | Slot Name | Renders When... | Purpose |\n * |-----------|---------------------|-------------------------------------------|\n * | icon | `hasIcon` is true | Leading icon to visually represent toggle |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `label` (string): Main label for the toggle (required for clarity).\n * - `checked` (boolean): Whether the toggle is in the \"on\" state. Defaults to `false`.\n * - `disabled` (boolean): Disables interaction and applies a disabled style.\n * - `hasDescription` (boolean): If true, shows the description text below the label.\n * - `description` (string): Supplementary text shown when `hasDescription` is true.\n * - `hasBottomDivider` (boolean): If true, renders a divider below the toggle (useful in lists).\n * - `hasIcon` (boolean): If true, displays the `icon` slot before the label.\n *\n * ---\n *\n * ### Events\n * - `input` – Fired when the toggle state changes (checked/unchecked).\n * - `change` – Fired when the toggle state changes by user interaction.\n *\n * Both events report the state the user selected. When `externalControl` is\n * true the component does not update itself; the consumer decides whether to\n * apply the reported state to `checked` and may reject the interaction by\n * leaving `checked` unchanged.\n *\n * ---\n *\n * ### Best Practices\n * - Use concise labels and keep descriptions brief; long descriptions are truncated.\n * - Only use the divider when presenting multiple toggles in a list for visual separation.\n * - For accessibility, ensure the label is descriptive and unique within the context.\n * - Avoid using toggle switches for actions that require confirmation or have destructive effects.\n * - For mutually exclusive options, use radio buttons instead.\n *\n * ---\n *\n * **Example:**\n * ```html\n * <obc-toggle-switch\n * label=\"Enable notifications\"\n * ?checked=${true}\n * ?hasDescription=${true}\n * description=\"Receive updates and alerts\"\n * ?hasIcon=${true}\n * >\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-switch>\n * ```\n *\n * In this example, the toggle switch displays a label, an icon, and a description, and is in the checked state.\n *\n * @slot icon - Leading icon slot (shown when `hasIcon` is true)\n * @fires {ObcToggleSwitchInputEvent} input - Dispatched when the value of the input changes\n * @fires {ObcToggleSwitchChangeEvent} change - Dispatched when the value of the input changes by user interaction\n * @stable\n */\n@customElement('obc-toggle-switch')\nexport class ObcToggleSwitch extends LitElement {\n /**\n * Main label for the toggle switch. Should clearly describe the setting being toggled.\n */\n @property({type: String}) label = 'Label';\n\n /**\n * Whether the toggle is in the \"on\" (checked) state.\n * Set to true to display as active/on.\n */\n @property({type: Boolean}) checked = false;\n\n /**\n * Disables the toggle, preventing user interaction and applying a disabled style.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * If true, displays the description text below the label.\n */\n @property({type: Boolean}) hasDescription = false;\n\n /**\n * Supplementary description text shown when `hasDescription` is true.\n * Use to clarify the effect or details of the toggle.\n * @availableWhen hasDescription==true\n */\n @property({type: String}) description = '';\n\n /**\n * If true, renders a divider below the toggle switch.\n * Useful for visually separating items in a list.\n */\n @property({type: Boolean}) hasBottomDivider = false;\n\n /**\n * If true, displays a leading icon before the label.\n * Provide icon content via the `icon` slot.\n */\n @property({type: Boolean}) hasIcon = false;\n\n /**\n * If true, the toggle is controlled externally.\n * Use to control the toggle state from outside the component.\n */\n @property({type: Boolean}) externalControl = false;\n\n /**\n * The state the user selected in the most recent interaction. In\n * externalControl mode this can differ from `checked` until the consumer\n * accepts the change, so the change event reports it instead of `checked`.\n */\n private _userSelectedChecked?: boolean;\n\n /**\n * Handles input events to change the toggle state.\n * Prevents changes if the toggle is disabled.\n * @param e {InputEvent}\n * @fires input - Dispatched when the value of the input changes\n */\n private _tryChange(e: InputEvent) {\n if (this.disabled) {\n e.preventDefault();\n return;\n }\n\n const nextChecked = !this.checked;\n this._userSelectedChecked = nextChecked;\n if (!this.externalControl) {\n this.checked = nextChecked;\n }\n e.stopPropagation();\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {checked: nextChecked},\n })\n );\n\n if (this.externalControl) {\n (e.target as HTMLInputElement).checked = this.checked;\n }\n }\n\n private _fireChangeEvent(e: Event) {\n if (this.disabled) {\n e.preventDefault();\n return;\n }\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {checked: this._userSelectedChecked ?? this.checked},\n })\n );\n }\n\n override render() {\n return html`\n <label\n class=${classMap({\n checked: this.checked,\n disabled: this.disabled,\n 'has-description': this.hasDescription,\n })}\n >\n <div class=\"icon-label-container\">\n ${this.hasIcon\n ? html`<div class=\"icon-container\"><slot name=\"icon\"></slot></div>`\n : nothing}\n <div class=\"label-container\">\n <span class=\"label\">${this.label}</span>\n ${this.hasDescription\n ? html`<span class=\"description\">${this.description}</span>`\n : nothing}\n </div>\n </div>\n <div class=\"switch\">\n <div class=\"presenter ${classMap({checked: this.checked})}\">\n <div class=\"knob\"></div>\n <input\n type=\"checkbox\"\n .checked=${this.checked}\n ?disabled=${this.disabled}\n @input=${this._tryChange}\n @change=${this._fireChangeEvent}\n />\n </div>\n </div>\n ${this.hasBottomDivider\n ? html`<div class=\"bottom-divider\"></div>`\n : nothing}\n </label>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-switch': ObcToggleSwitch;\n }\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"toggle-switch.js","sources":["../../../src/components/toggle-switch/toggle-switch.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport '../icon-button/icon-button.js';\nimport componentStyle from './toggle-switch.css?inline';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcToggleSwitchInputEvent = CustomEvent<{\n checked: boolean;\n}>;\n\nexport type ObcToggleSwitchChangeEvent = CustomEvent<{\n checked: boolean;\n}>;\n\n/**\n * `<obc-toggle-switch>` – A toggle switch component for binary on/off selection (also known as a switch, toggle, or enable/disable control).\n *\n * Provides a visual switch control for toggling between two states (checked/unchecked), commonly used for enabling or disabling a setting or feature. The component supports an optional label, description, icon, and divider for flexible presentation in lists or forms.\n *\n * ---\n *\n * ### Features\n * - **Binary toggle:** Allows users to switch between checked (on) and unchecked (off) states.\n * - **Label and Description:** Displays a primary label and an optional secondary description for context.\n * - **Icon Support:** Can display a leading icon via the `icon` slot for visual emphasis.\n * - **Disabled State:** Can be set to disabled, preventing user interaction and visually indicating inactivity.\n * - **Bottom Divider:** Optional divider for use in lists or grouped settings.\n * - **Responsive Layout:** Adapts label/description layout based on content; long descriptions are truncated with ellipsis.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-toggle-switch` for settings or preferences that require a simple on/off or enable/disable control. Ideal for scenarios where the user needs to quickly toggle a feature, such as activating notifications, enabling dark mode, or switching connectivity options. Avoid using for mutually exclusive choices—use radio buttons for those cases.\n *\n * - Place in forms, settings panels, or lists where binary choices are needed.\n * - Use the description property to clarify the effect of the toggle if the label alone is not sufficient.\n * - If an icon is relevant, provide it via the `icon` slot to reinforce the meaning.\n * - For accessibility, ensure the label clearly describes the toggle's function.\n *\n * ---\n *\n * ### Slots\n * | Slot Name | Renders When... | Purpose |\n * |-----------|---------------------|-------------------------------------------|\n * | icon | `hasIcon` is true | Leading icon to visually represent toggle |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `label` (string): Main label for the toggle (required for clarity).\n * - `checked` (boolean): Whether the toggle is in the \"on\" state. Defaults to `false`.\n * - `disabled` (boolean): Disables interaction and applies a disabled style.\n * - `hasDescription` (boolean): If true, shows the description text below the label.\n * - `description` (string): Supplementary text shown when `hasDescription` is true.\n * - `hasBottomDivider` (boolean): If true, renders a divider below the toggle (useful in lists).\n * - `hasIcon` (boolean): If true, displays the `icon` slot before the label.\n *\n * ---\n *\n * ### Events\n * - `input` – Fired when the toggle state changes (checked/unchecked).\n * - `change` – Fired when the toggle state changes by user interaction.\n *\n * Both events report the state the user selected. When `externalControl` is\n * true the component does not update itself; the consumer decides whether to\n * apply the reported state to `checked` and may reject the interaction by\n * leaving `checked` unchanged.\n *\n * ---\n *\n * ### Best Practices\n * - Use concise labels and keep descriptions brief; long descriptions are truncated.\n * - Only use the divider when presenting multiple toggles in a list for visual separation.\n * - For accessibility, ensure the label is descriptive and unique within the context.\n * - Avoid using toggle switches for actions that require confirmation or have destructive effects.\n * - For mutually exclusive options, use radio buttons instead.\n *\n * ---\n *\n * **Example:**\n * ```html\n * <obc-toggle-switch\n * label=\"Enable notifications\"\n * ?checked=${true}\n * ?hasDescription=${true}\n * description=\"Receive updates and alerts\"\n * ?hasIcon=${true}\n * >\n * <obi-placeholder slot=\"icon\"></obi-placeholder>\n * </obc-toggle-switch>\n * ```\n *\n * In this example, the toggle switch displays a label, an icon, and a description, and is in the checked state.\n *\n * @slot icon - Leading icon slot (shown when `hasIcon` is true)\n * @fires {ObcToggleSwitchInputEvent} input - Dispatched when the value of the input changes\n * @fires {ObcToggleSwitchChangeEvent} change - Dispatched when the value of the input changes by user interaction\n * @stable\n */\n@customElement('obc-toggle-switch')\nexport class ObcToggleSwitch extends LitElement {\n /**\n * Main label for the toggle switch. Should clearly describe the setting being toggled.\n */\n @property({type: String}) label = 'Label';\n\n /**\n * Whether the toggle is in the \"on\" (checked) state.\n * Set to true to display as active/on.\n */\n @property({type: Boolean}) checked = false;\n\n /**\n * Disables the toggle, preventing user interaction and applying a disabled style.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * If true, displays the description text below the label.\n */\n @property({type: Boolean}) hasDescription = false;\n\n /**\n * Supplementary description text shown when `hasDescription` is true.\n * Use to clarify the effect or details of the toggle.\n * @availableWhen hasDescription==true\n */\n @property({type: String}) description = '';\n\n /**\n * If true, renders a divider below the toggle switch.\n * Useful for visually separating items in a list.\n */\n @property({type: Boolean}) hasBottomDivider = false;\n\n /**\n * If true, displays a leading icon before the label.\n * Provide icon content via the `icon` slot.\n */\n @property({type: Boolean}) hasIcon = false;\n\n /**\n * If true, the toggle is controlled externally.\n * Use to control the toggle state from outside the component.\n */\n @property({type: Boolean}) externalControl = false;\n\n /**\n * The state the user selected in the most recent interaction. In\n * externalControl mode this can differ from `checked` until the consumer\n * accepts the change, so the change event reports it instead of `checked`.\n */\n private _userSelectedChecked?: boolean;\n\n /**\n * Handles input events to change the toggle state.\n * Prevents changes if the toggle is disabled.\n * @param e {InputEvent}\n * @fires input\n */\n private _tryChange(e: InputEvent) {\n if (this.disabled) {\n e.preventDefault();\n return;\n }\n\n const nextChecked = !this.checked;\n this._userSelectedChecked = nextChecked;\n if (!this.externalControl) {\n this.checked = nextChecked;\n }\n e.stopPropagation();\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {checked: nextChecked},\n })\n );\n\n if (this.externalControl) {\n (e.target as HTMLInputElement).checked = this.checked;\n }\n }\n\n private _fireChangeEvent(e: Event) {\n if (this.disabled) {\n e.preventDefault();\n return;\n }\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {checked: this._userSelectedChecked ?? this.checked},\n })\n );\n }\n\n override render() {\n return html`\n <label\n class=${classMap({\n checked: this.checked,\n disabled: this.disabled,\n 'has-description': this.hasDescription,\n })}\n >\n <div class=\"icon-label-container\">\n ${this.hasIcon\n ? html`<div class=\"icon-container\"><slot name=\"icon\"></slot></div>`\n : nothing}\n <div class=\"label-container\">\n <span class=\"label\">${this.label}</span>\n ${this.hasDescription\n ? html`<span class=\"description\">${this.description}</span>`\n : nothing}\n </div>\n </div>\n <div class=\"switch\">\n <div class=\"presenter ${classMap({checked: this.checked})}\">\n <div class=\"knob\"></div>\n <input\n type=\"checkbox\"\n .checked=${this.checked}\n ?disabled=${this.disabled}\n @input=${this._tryChange}\n @change=${this._fireChangeEvent}\n />\n </div>\n </div>\n ${this.hasBottomDivider\n ? html`<div class=\"bottom-divider\"></div>`\n : nothing}\n </label>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-toggle-switch': ObcToggleSwitch;\n }\n}\n"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../../src/components/top-bar/top-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAIhD,OAAO,+BAA+B,CAAC;AACvC,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,6BAA6B,CAAC;AACrC,OAAO,8BAA8B,CAAC;AACtC,OAAO,0BAA0B,CAAC;AAClC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,uCAAuC,CAAC;AAC/C,OAAO,wCAAwC,CAAC;AAChD,OAAO,2CAA2C,CAAC;AACnD,OAAO,kCAAkC,CAAC;AAC1C,OAAO,0CAA0C,CAAC;AAClD,OAAO,0BAA0B,CAAC;AAClC,OAAO,EAEL,cAAc,EACf,MAAM,6BAA6B,CAAC;AAGrC,oBAAY,uBAAuB;IACjC,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4HG;AACH,qBACa,SAAU,SAAQ,UAAU;IACvC;;;;OAIG;IACuB,QAAQ,SAAS;IAE3C;;;;;OAKG;IACuB,QAAQ,SAAU;IAE5C,wDAAwD;IAC9B,cAAc,0BAAgC;IAExE;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,sBAAsB,UAAS;IAE/B;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,uBAAuB,UAAS;IAEhC;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,kBAAkB,UAAS;IAE3B;;;;OAIG;IACwB,IAAI,UAAS;IAExC;;;;;OAKG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IAEH,iBAAiB,UAAS;IAE1B;;;;OAIG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IACwB,SAAS,UAAS;IAE7C;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;OAIG;IACwB,WAAW,UAAS;IAE/C;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;OAIG;IAEH,qBAAqB,SAAO;IAE5B;;;;OAIG;IAEH,yBAAyB,SAAO;IAEhC;;;;OAIG;IAEH,oBAAoB,SAAO;IAE3B;;;;OAIG;IAEH,sBAAsB,SAAO;IAE7B;;;;OAIG;IAEH,mBAAmB,SAAO;IAE1B;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;;OAKG;IAEH,eAAe,EAAE,cAAc,EAAE,CAAM;IAEvC,OAAO,CAAC,oBAAoB;IAO5B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,qBAAqB;IAO7B,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,eAAe;IAad,MAAM;IAkLf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,SAAS,CAAC;KAC1B;CACF"}
1
+ {"version":3,"file":"top-bar.d.ts","sourceRoot":"","sources":["../../../src/components/top-bar/top-bar.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAkB,MAAM,KAAK,CAAC;AAIhD,OAAO,+BAA+B,CAAC;AACvC,OAAO,mBAAmB,CAAC;AAC3B,OAAO,uBAAuB,CAAC;AAC/B,OAAO,6BAA6B,CAAC;AACrC,OAAO,8BAA8B,CAAC;AACtC,OAAO,0BAA0B,CAAC;AAClC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,uCAAuC,CAAC;AAC/C,OAAO,wCAAwC,CAAC;AAChD,OAAO,2CAA2C,CAAC;AACnD,OAAO,kCAAkC,CAAC;AAC1C,OAAO,0CAA0C,CAAC;AAClD,OAAO,0BAA0B,CAAC;AAClC,OAAO,EAEL,cAAc,EACf,MAAM,6BAA6B,CAAC;AAGrC,oBAAY,uBAAuB;IACjC,IAAI,SAAS;IACb,IAAI,SAAS;CACd;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4HG;AACH,qBACa,SAAU,SAAQ,UAAU;IACvC;;;;OAIG;IACuB,QAAQ,SAAS;IAE3C;;;;;OAKG;IACuB,QAAQ,SAAU;IAE5C,wDAAwD;IAC9B,cAAc,0BAAgC;IAExE;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,sBAAsB,UAAS;IAE/B;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,uBAAuB,UAAS;IAEhC;;;;;OAKG;IAEH,mBAAmB,UAAS;IAE5B;;;;;OAKG;IAEH,kBAAkB,UAAS;IAE3B;;;;OAIG;IACwB,IAAI,UAAS;IAExC;;;;;OAKG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IAEH,iBAAiB,UAAS;IAE1B;;;;OAIG;IACwB,cAAc,UAAS;IAElD;;;;OAIG;IACwB,SAAS,UAAS;IAE7C;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;OAIG;IACwB,WAAW,UAAS;IAE/C;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;OAIG;IAEH,qBAAqB,SAAO;IAE5B;;;;OAIG;IAEH,yBAAyB,SAAO;IAEhC;;;;OAIG;IAEH,oBAAoB,SAAO;IAE3B;;;;OAIG;IAEH,sBAAsB,SAAO;IAE7B;;;;OAIG;IAEH,mBAAmB,SAAO;IAE1B;;;;OAIG;IACwB,QAAQ,UAAS;IAE5C;;;;;OAKG;IAEH,eAAe,EAAE,cAAc,EAAE,CAAM;IAEvC,OAAO,CAAC,oBAAoB;IAQ5B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,qBAAqB;IAQ7B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,eAAe,CAA4B;IACnD,OAAO,CAAC,iBAAiB,CAA+B;IACxD,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,qBAAqB,CAAS;IAEtC,OAAO,CAAC,cAAc;IAUtB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,eAAe;IAad,MAAM;IAkLf,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,aAAa,EAAE,SAAS,CAAC;KAC1B;CACF"}