@oicl/openbridge-webcomponents-full-bundle 2.0.0-next.117 → 2.0.0-next.118
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.
- package/bundle/openbridge-webcomponents.bundle.js +37 -33
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +28 -23
- package/dist/ar/poi/poi-base.d.ts +6 -0
- package/dist/ar/poi/poi-base.d.ts.map +1 -1
- package/dist/ar/poi/poi-base.js.map +1 -1
- package/dist/ar/poi-button/poi-button.d.ts +2 -2
- package/dist/ar/poi-button/poi-button.js.map +1 -1
- package/dist/components/accordion-card/accordion-card.d.ts.map +1 -1
- package/dist/components/accordion-card/accordion-card.js.map +1 -1
- package/dist/components/advice-message-item/advice-message-item.d.ts +4 -2
- package/dist/components/advice-message-item/advice-message-item.d.ts.map +1 -1
- package/dist/components/advice-message-item/advice-message-item.js +4 -2
- package/dist/components/advice-message-item/advice-message-item.js.map +1 -1
- package/dist/components/app-menu/app-menu.d.ts +1 -1
- package/dist/components/app-menu/app-menu.js +1 -1
- package/dist/components/app-menu/app-menu.js.map +1 -1
- package/dist/components/brilliance-menu/brilliance-menu.d.ts +8 -4
- package/dist/components/brilliance-menu/brilliance-menu.d.ts.map +1 -1
- package/dist/components/brilliance-menu/brilliance-menu.js +8 -4
- package/dist/components/brilliance-menu/brilliance-menu.js.map +1 -1
- package/dist/components/check-button/check-button.js.map +1 -1
- package/dist/components/checkbox/checkbox.d.ts +2 -2
- package/dist/components/checkbox/checkbox.js.map +1 -1
- package/dist/components/command-menu/command-menu.d.ts +1 -1
- package/dist/components/command-menu/command-menu.js +1 -1
- package/dist/components/command-menu/command-menu.js.map +1 -1
- package/dist/components/dropdown-button/dropdown-button.d.ts +2 -2
- package/dist/components/dropdown-button/dropdown-button.js +2 -2
- package/dist/components/dropdown-button/dropdown-button.js.map +1 -1
- package/dist/components/menu-button/menu-button.d.ts.map +1 -1
- package/dist/components/menu-button/menu-button.js.map +1 -1
- package/dist/components/navigation-item/navigation-item.d.ts +1 -5
- package/dist/components/navigation-item/navigation-item.d.ts.map +1 -1
- package/dist/components/navigation-item/navigation-item.js +0 -8
- package/dist/components/navigation-item/navigation-item.js.map +1 -1
- package/dist/components/navigation-item-group/navigation-item-group.d.ts +2 -1
- package/dist/components/navigation-item-group/navigation-item-group.d.ts.map +1 -1
- package/dist/components/navigation-item-group/navigation-item-group.js +2 -1
- package/dist/components/navigation-item-group/navigation-item-group.js.map +1 -1
- package/dist/components/notification-button/notification-button.d.ts +1 -1
- package/dist/components/notification-button/notification-button.js +1 -1
- package/dist/components/notification-button/notification-button.js.map +1 -1
- package/dist/components/notification-message-item/notification-message-item.d.ts +4 -2
- package/dist/components/notification-message-item/notification-message-item.d.ts.map +1 -1
- package/dist/components/notification-message-item/notification-message-item.js +4 -2
- package/dist/components/notification-message-item/notification-message-item.js.map +1 -1
- package/dist/components/pivot-item/pivot-item.d.ts +1 -1
- package/dist/components/pivot-item/pivot-item.js +1 -1
- package/dist/components/pivot-item/pivot-item.js.map +1 -1
- package/dist/components/slide-button/slide-button.d.ts.map +1 -1
- package/dist/components/slide-button/slide-button.js.map +1 -1
- package/dist/components/slider/slider.d.ts +2 -2
- package/dist/components/slider/slider.js +2 -2
- package/dist/components/slider/slider.js.map +1 -1
- package/dist/components/slider-double/slider-double.d.ts +2 -2
- package/dist/components/slider-double/slider-double.js +2 -2
- package/dist/components/slider-double/slider-double.js.map +1 -1
- package/dist/components/stepper-box/stepper-box.d.ts +4 -2
- package/dist/components/stepper-box/stepper-box.d.ts.map +1 -1
- package/dist/components/stepper-box/stepper-box.js +4 -2
- package/dist/components/stepper-box/stepper-box.js.map +1 -1
- package/dist/components/system-button/system-button.d.ts +1 -1
- package/dist/components/system-button/system-button.js +1 -1
- package/dist/components/system-button/system-button.js.map +1 -1
- package/dist/components/tabbed-card/tabbed-card.d.ts.map +1 -1
- package/dist/components/tabbed-card/tabbed-card.js.map +1 -1
- package/dist/components/toggle-button-option/toggle-button-option.d.ts +2 -1
- package/dist/components/toggle-button-option/toggle-button-option.d.ts.map +1 -1
- package/dist/components/toggle-button-option/toggle-button-option.js +2 -1
- package/dist/components/toggle-button-option/toggle-button-option.js.map +1 -1
- package/dist/components/toggle-button-vertical-group/toggle-button-vertical-group.js.map +1 -1
- package/dist/components/toggle-switch/toggle-switch.d.ts +1 -1
- package/dist/components/toggle-switch/toggle-switch.js +1 -1
- package/dist/components/toggle-switch/toggle-switch.js.map +1 -1
- package/dist/components/top-bar/top-bar.d.ts.map +1 -1
- package/dist/components/top-bar/top-bar.js.map +1 -1
- package/dist/components/topbar-message-item/topbar-message-item.js.map +1 -1
- package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.d.ts +1 -1
- package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.js +1 -1
- package/dist/integration-systems/integration-dropdown-button/integration-dropdown-button.js.map +1 -1
- package/package.json +1 -1
- package/script/check-slot-event-docs.ts +36 -3
- package/src/ar/poi/poi-base.ts +6 -0
- package/src/ar/poi-button/poi-button.ts +2 -2
- package/src/components/accordion-card/accordion-card.ts +2 -1
- package/src/components/advice-message-item/advice-message-item.ts +4 -2
- package/src/components/app-menu/app-menu.ts +1 -1
- package/src/components/brilliance-menu/brilliance-menu.ts +8 -4
- package/src/components/check-button/check-button.ts +1 -1
- package/src/components/checkbox/checkbox.ts +2 -2
- package/src/components/command-menu/command-menu.ts +1 -1
- package/src/components/dropdown-button/dropdown-button.ts +2 -2
- package/src/components/menu-button/menu-button.ts +8 -4
- package/src/components/navigation-item/navigation-item.ts +1 -10
- package/src/components/navigation-item-group/navigation-item-group.ts +2 -1
- package/src/components/notification-button/notification-button.ts +1 -1
- package/src/components/notification-message-item/notification-message-item.ts +4 -2
- package/src/components/pivot-item/pivot-item.ts +1 -1
- package/src/components/slide-button/slide-button.ts +2 -1
- package/src/components/slider/slider.ts +2 -2
- package/src/components/slider-double/slider-double.ts +2 -2
- package/src/components/stepper-box/stepper-box.ts +4 -2
- package/src/components/system-button/system-button.ts +5 -5
- package/src/components/tabbed-card/tabbed-card.ts +2 -1
- package/src/components/toggle-button-option/toggle-button-option.ts +2 -1
- package/src/components/toggle-button-vertical-group/toggle-button-vertical-group.ts +2 -2
- package/src/components/toggle-switch/toggle-switch.ts +1 -1
- package/src/components/top-bar/top-bar.ts +8 -4
- package/src/components/topbar-message-item/topbar-message-item.ts +2 -2
- package/src/integration-systems/integration-dropdown-button/integration-dropdown-button.ts +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider-double.js","sources":["../../../src/components/slider-double/slider-double.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property, query} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport {styleMap} from 'lit/directives/style-map.js';\nimport componentStyle from './slider-double.css?inline';\nimport '../icon-button/icon-button.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\n\n/**\n * Enum for slider double variants.\n *\n * - `normal`: Standard slider with default styling and interaction.\n * - `enhanced`: Visually enhanced slider with larger track and thumb, suitable for more prominent or touch-friendly UIs.\n * - `no-input`: Non-interactive display mode; disables all user input and presents the slider as read-only.\n */\nexport enum ObcSliderDoubleVariant {\n Normal = 'normal',\n Enhanced = 'enhanced',\n NoInput = 'no-input',\n}\n\n/**\n * Event type for value changes in obc-slider-double.\n * Contains the current low and high values of the slider.\n */\nexport type ObcSliderDoubleValueEvent = CustomEvent<{\n low: number;\n high: number;\n}>;\n\n/**\n * Event type for change event in obc-slider-double (fired after user interaction completes).\n * Contains the current low and high values of the slider.\n */\nexport type ObcSliderDoubleChangeEvent = CustomEvent<{\n low: number;\n high: number;\n}>;\n\n/**\n * `<obc-slider-double>` – A dual-thumb range slider for selecting a value interval within a defined range.\n *\n * This component allows users to select a minimum and maximum value by dragging two thumbs along a horizontal track. It is commonly used for filtering or specifying ranges (such as price, speed, or time intervals) in forms and dashboards. The slider supports both interactive and read-only display modes, as well as visual variants for different UI needs.\n *\n * Appears with two draggable handles (thumbs) and labels showing the current low and high values. The low and high readout labels can be customized via slots.\n *\n * ## Features\n * - **Dual-thumb range selection:** Users can adjust both the lower and upper bounds of a numeric interval.\n * - **Variants:**\n * - **Normal:** Standard slider with compact styling.\n * - **Enhanced:** Larger track and thumb for increased prominence or touch accessibility.\n * - **NoInput:** Read-only mode; disables all user interaction and presents the current range as static.\n * - **Configurable range:** Set minimum (`min`), maximum (`max`), and step size (`step`) for precise control.\n * - **Step click adjustment:** Use `stepClick` to define increment/decrement amount for keyboard or button-based changes.\n * - **Seeking mode:** Enable `allowSeeking` to let users jump to a value by clicking on the track, with smooth animated transitions controlled by `seekingSpeed`.\n * - **Custom labels:** Display formatted value labels with unit (`labelUnit`), decimal precision (`labelDecimals`), and adjustable label width (`labelWidth`).\n * - **Hug container option:** Remove spacing between slider and container edges with the `hugcontainer` attribute for seamless layout integration.\n * - **Custom readouts:** Replace the low/high value labels with custom content using the `left-readout` and `right-readout` slots.\n *\n * ## Usage Guidelines\n * Use `obc-slider-double` when you need users to specify a numeric range, such as filtering results by minimum and maximum values. Ideal for scenarios like:\n * - Filtering items by price, speed, or other continuous values.\n * - Selecting a time interval or threshold range.\n * - Any UI where a bounded numeric interval is required.\n *\n * For single-value selection, use a standard slider component instead. In read-only or summary views, use the `no-input` variant to display the selected range without allowing changes.\n *\n * **TODO(designer):** Confirm if there are recommended minimum thumb separation or constraints for usability, and if there are best practices for using the enhanced variant.\n *\n * ## Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |---------------|-------------------------------|------------------------------------------------------------------------------------------------------------------|\n * | left-readout | `showLeftReadout` is true | Custom content for the left (low) readout label. Falls back to the formatted `low` value. |\n * | right-readout | `showRightReadout` is true | Custom content for the right (high) readout label. Falls back to the formatted `high` value. |\n *\n * ## Properties and Attributes\n * - `low` (number): The current lower bound of the selected range.\n * - `high` (number): The current upper bound of the selected range.\n * - `min` (number): The minimum allowed value (default: 0).\n * - `max` (number): The maximum allowed value (default: 100).\n * - `step` (number): The increment for value changes (default: 1).\n * - `stepClick` (number): Step size for keyboard or button-based changes (default: 10).\n * - `variant` (`normal` | `enhanced` | `no-input`): Visual and interaction style (default: `normal`).\n * - `allowSeeking` (boolean): If true, clicking the track animates the thumb to the clicked position.\n * - `seekingSpeed` (number): Animation speed for seeking (default: 1/3, i.e., full range in 3 seconds).\n * - `labelUnit` (string): Unit label appended to value labels (e.g., `\"%\"`, `\"kn\"`).\n * - `labelDecimals` (number): Number of decimal places for value labels.\n * - `labelWidth` (string): CSS width for value labels (e.g., `\"5ch\"`, `\"60px\"`).\n * - `showLeftReadout` (boolean, property only): Show the left (low) readout label. Default `true`.\n * - `showRightReadout` (boolean, property only): Show the right (high) readout label. Default `true`.\n * - `hugcontainer` (attribute): If present, removes spacing between slider and container edges.\n *\n * ## Events\n * - `value` – Fired continuously whenever the low or high value changes during user interaction. Event detail contains `{low, high}`.\n * - `change` – Fired only after user interaction completes (mouse release). Event detail contains `{low, high}`.\n *\n * ## Best Practices and Constraints\n * - Ensure `low` is always less than or equal to `high`; the component enforces this automatically.\n * - For accessibility, provide clear labels and units so users understand the meaning of the range.\n * - Use the `no-input` variant for summary or review screens where editing is not allowed.\n * - When using `allowSeeking`, set an appropriate `seekingSpeed` for smooth but responsive thumb movement.\n * - Avoid setting `step` too small for large ranges, as this may make precise selection difficult.\n *\n * ## Example\n *\n * ```html\n * <obc-slider-double\n * min=\"0\"\n * max=\"100\"\n * low=\"20\"\n * high=\"80\"\n * step=\"5\"\n * label-unit=\"%\"\n * label-decimals=\"0\"\n * variant=\"enhanced\"\n * allowSeeking\n * >\n * <span slot=\"left-readout\">Min</span>\n * <span slot=\"right-readout\">Max</span>\n * </obc-slider-double>\n * ```\n *\n * In this example, the slider allows selection of a percentage range from 0 to 100, with 5% increments, enhanced styling, and seeking enabled.\n *\n * @slot left-readout - Custom content for the left (low) readout label (rendered when `showLeftReadout` is true)\n * @slot right-readout - Custom content for the right (high) readout label (rendered when `showRightReadout` is true)\n * @fires {ObcSliderDoubleValueEvent} value - Fires when the value is changed\n * @fires {ObcSliderDoubleChangeEvent} change - Fires when user interaction completes\n * @stable\n */\n@customElement('obc-slider-double')\nexport class ObcSliderDouble extends LitElement {\n /**\n * The current lower bound of the selected range.\n * Must be greater than or equal to `min` and less than or equal to `high`.\n */\n @property({type: Number}) low = 0;\n\n /**\n * The current upper bound of the selected range.\n * Must be less than or equal to `max` and greater than or equal to `low`.\n */\n @property({type: Number}) high = 100;\n\n /**\n * The minimum allowed value for the slider.\n * Default is 0.\n */\n @property({type: Number}) min = 0;\n\n /**\n * The maximum allowed value for the slider.\n * Default is 100.\n */\n @property({type: Number}) max = 100;\n\n /**\n * The increment for value changes.\n * If not set, defaults to 1.\n */\n @property({type: Number}) step: number | undefined;\n\n /**\n * Step size for keyboard or button-based changes.\n * Default is 10.\n */\n @property({type: Number}) stepClick = 10;\n\n /**\n * Visual and interaction style of the slider.\n * - `normal`: Standard appearance.\n * - `enhanced`: Larger track and thumb.\n * - `no-input`: Read-only, disables user interaction.\n * Default is `normal`.\n */\n @property({type: String}) variant: ObcSliderDoubleVariant =\n ObcSliderDoubleVariant.Normal;\n\n /**\n * If true, clicking the slider track animates the thumb to the clicked position.\n * Enables seeking mode for rapid value changes.\n */\n @property({type: Boolean}) allowSeeking = false;\n\n @property({type: Boolean}) disabled = false;\n\n /**\n * Animation speed for seeking, in inverse seconds.\n * The value will go from min to max in 1 / seekingSpeed seconds.\n * Default is 1/3 (i.e., 3 seconds for full range).\n */\n @property({type: Number}) seekingSpeed = 1 / 3;\n\n /**\n * Unit label appended to value labels (e.g., \"%\", \"kn\").\n */\n @property({type: String}) labelUnit = '';\n\n /**\n * Number of decimal places to display in value labels.\n */\n @property({type: Number}) labelDecimals = 0;\n\n /**\n * CSS width for value labels (e.g., \"5ch\", \"60px\").\n */\n @property({type: String}) labelWidth = '60px';\n\n /**\n * Whether to show the left (low) readout label.\n *\n * When false, the left readout is hidden entirely. When true, the readout\n * renders the formatted `low` value or the content slotted into `left-readout`.\n *\n * Default is true. Set via JavaScript property (no HTML attribute).\n */\n @property({type: Boolean, attribute: false}) showLeftReadout = true;\n\n /**\n * Whether to show the right (high) readout label.\n *\n * When false, the right readout is hidden entirely. When true, the readout\n * renders the formatted `high` value or the content slotted into `right-readout`.\n *\n * Default is true. Set via JavaScript property (no HTML attribute).\n */\n @property({type: Boolean, attribute: false}) showRightReadout = true;\n\n /**\n * Removes spacing between the slider and its container edges for seamless\n * layout integration. Reflected to the `hugcontainer` HTML attribute.\n */\n @property({type: Boolean, reflect: true, attribute: 'hugcontainer'})\n hugContainer = false;\n\n private get lowRatio(): number {\n return this.computeRatio(this.low);\n }\n\n private get highRatio(): number {\n return this.computeRatio(this.high);\n }\n\n private computeRatio(value: number): number {\n const range = this.max - this.min;\n if (!Number.isFinite(range) || range <= 0) return 0;\n const ratio = (value - this.min) / range;\n if (!Number.isFinite(ratio)) return 0;\n return Math.max(0, Math.min(1, ratio));\n }\n\n private animationFrame: number | null = null;\n private isMouseDown = false;\n private targetValue = 0;\n private isDragging = false;\n private isTargetingLow = false;\n private animationStartTime: number | null = null;\n private animationStartValue: number = 0;\n\n @query('input[type=\"range\"].min')\n private minInput!: HTMLInputElement;\n\n @query('input[type=\"range\"].max')\n private maxInput!: HTMLInputElement;\n\n /**\n * Handles input changes from the slider thumbs.\n * Updates the low and high values and emits the `value` event.\n *\n * @fires {ObcSliderDoubleValueEvent} value - Fires when the value is changed\n */\n onInput() {\n let newLow = parseFloat(this.minInput.value);\n let newHigh = parseFloat(this.maxInput.value);\n if (newLow > this.high) {\n newLow = this.high;\n this.minInput.value = this.high.toString();\n }\n if (newHigh < this.low) {\n newHigh = this.low;\n this.maxInput.value = this.low.toString();\n }\n this.low = newLow;\n this.high = newHigh;\n this.dispatchEvent(\n new CustomEvent('value', {detail: {low: this.low, high: this.high}})\n );\n }\n\n /**\n * Fires the `change` event with the current low and high values.\n *\n * @fires change - Fires when user interaction completes\n */\n private fireChangeEvent() {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {low: this.low, high: this.high},\n }) as ObcSliderDoubleChangeEvent\n );\n }\n\n private THUMB_WIDTH = 48;\n private THUMB_VISIBLE_WIDTH = 12;\n\n private lowClickValue(e: MouseEvent) {\n const rect = this.minInput.getBoundingClientRect();\n const left = rect.left + this.THUMB_WIDTH - this.THUMB_VISIBLE_WIDTH / 2;\n const width = rect.width - this.THUMB_WIDTH;\n const percent = (e.clientX - left) / width;\n return this.min + (this.max - this.min) * percent;\n }\n\n private highClickValue(e: MouseEvent) {\n const rect = this.maxInput.getBoundingClientRect();\n const left = rect.left + this.THUMB_VISIBLE_WIDTH / 2;\n const width = rect.width - this.THUMB_WIDTH;\n const percent = (e.clientX - left) / width;\n return this.min + (this.max - this.min) * percent;\n }\n\n private thumbRange() {\n const rect = this.minInput.getBoundingClientRect();\n const valueRange = this.max - this.min;\n const percentageRange = this.THUMB_WIDTH / rect.width;\n return valueRange * percentageRange;\n }\n\n private isClickingMinThumb(e: MouseEvent) {\n const value = this.lowClickValue(e);\n if (value > this.low) {\n return false;\n }\n return value >= this.low - this.thumbRange();\n }\n\n private isClickingMaxThumb(e: MouseEvent) {\n const value = this.highClickValue(e);\n if (value < this.high) {\n return false;\n }\n return value <= this.high + this.thumbRange();\n }\n\n private isClickingLowTrack(e: MouseEvent) {\n const value = this.lowClickValue(e);\n return value <= this.low - this.thumbRange() / 2;\n }\n\n private isClickingHighTrack(e: MouseEvent) {\n const value = this.highClickValue(e);\n return value >= this.high + this.thumbRange() / 2;\n }\n\n private isClosestToLowThumb(e: MouseEvent) {\n const lowValue = this.lowClickValue(e);\n const highValue = this.highClickValue(e);\n return Math.abs(lowValue - this.low) <= Math.abs(highValue - this.high);\n }\n\n private onMouseDown(e: MouseEvent) {\n if (this.variant === ObcSliderDoubleVariant.NoInput || this.disabled)\n return;\n if (this.isClickingMinThumb(e)) {\n this.isTargetingLow = true;\n this.isDragging = true;\n } else if (this.isClickingMaxThumb(e)) {\n this.isTargetingLow = false;\n this.isDragging = true;\n } else if (this.isClickingLowTrack(e)) {\n this.isTargetingLow = true;\n this.isDragging = false;\n } else if (this.isClickingHighTrack(e)) {\n this.isTargetingLow = false;\n this.isDragging = false;\n } else if (this.isClosestToLowThumb(e)) {\n this.isTargetingLow = true;\n this.isDragging = false;\n } else {\n this.isTargetingLow = false;\n this.isDragging = false;\n }\n this.isMouseDown = true;\n this.updateTargetValue(e);\n e.preventDefault();\n window.addEventListener('mousemove', this.onWindowMouseMove);\n window.addEventListener('mouseup', this.onWindowMouseUp);\n this.startAnimation();\n }\n\n private onWindowMouseMove = (e: MouseEvent) => {\n this.onMouseMove(e);\n };\n\n private onWindowMouseUp = () => {\n this.onMouseUp();\n };\n\n private onMouseMove(e: MouseEvent) {\n if (this.isMouseDown) {\n this.updateTargetValue(e);\n }\n }\n\n private onMouseUp() {\n this.isMouseDown = false;\n this.isDragging = false;\n window.removeEventListener('mousemove', this.onWindowMouseMove);\n window.removeEventListener('mouseup', this.onWindowMouseUp);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private updateTargetValue(e: MouseEvent) {\n const unroundedValue = this.isTargetingLow\n ? this.lowClickValue(e)\n : this.highClickValue(e);\n if (this.step) {\n this.targetValue = Math.round(unroundedValue / this.step) * this.step;\n } else {\n this.targetValue = unroundedValue;\n }\n if (this.isTargetingLow) {\n this.targetValue = Math.max(\n this.min,\n Math.min(this.targetValue, this.high)\n );\n } else {\n this.targetValue = Math.min(\n this.max,\n Math.max(this.targetValue, this.low)\n );\n }\n }\n\n private startAnimation() {\n this.isDragging = this.allowSeeking;\n this.animationStartTime = performance.now();\n this.animationStartValue = this.isTargetingLow ? this.low : this.high;\n const min = this.min;\n const max = this.max;\n const step = this.step;\n const duration = (1 / this.seekingSpeed) * 1000; // ms\n const direction = this.targetValue > this.animationStartValue ? 1 : -1;\n\n const animate = () => {\n let nextValue = this.targetValue;\n if (!this.isDragging) {\n const now = performance.now();\n const elapsed = now - (this.animationStartTime ?? now);\n const range = Math.abs(max - min);\n // How much of the range should be covered by now\n const expectedProgress = Math.min(elapsed / duration, 1);\n const expectedValue =\n this.animationStartValue + direction * range * expectedProgress;\n // Snap to step\n if (direction > 0) {\n nextValue =\n step === undefined\n ? expectedValue\n : Math.ceil(expectedValue - min / step) * step + min;\n nextValue = Math.min(this.targetValue, nextValue);\n } else {\n nextValue =\n step === undefined\n ? expectedValue\n : Math.floor((expectedValue - min) / step) * step + min;\n nextValue = Math.max(this.targetValue, nextValue);\n }\n }\n // Only update if value actually changes\n const isValueChanged = this.isTargetingLow\n ? this.low !== nextValue\n : this.high !== nextValue;\n if (isValueChanged) {\n if (this.isTargetingLow) {\n this.low = nextValue;\n } else {\n this.high = nextValue;\n }\n this.dispatchEvent(\n new CustomEvent('value', {detail: {low: this.low, high: this.high}})\n );\n }\n // Continue animating if not at target\n if (\n (direction > 0 && nextValue < this.targetValue) ||\n (direction < 0 && nextValue > this.targetValue)\n ) {\n this.animationFrame = requestAnimationFrame(animate);\n } else if (this.isMouseDown) {\n // If mouse is still down, wait for new target\n this.animationStartTime = performance.now();\n this.animationStartValue = this.isTargetingLow ? this.low : this.high;\n this.animationFrame = requestAnimationFrame(animate);\n this.isDragging = true;\n }\n };\n\n this.animationFrame = requestAnimationFrame(animate);\n }\n\n private stopAnimation() {\n if (this.animationFrame !== null) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n }\n\n private formatLabel(value: number) {\n return value.toFixed(this.labelDecimals) + this.labelUnit;\n }\n\n override render() {\n return html`\n ${this.showLeftReadout\n ? html`\n <div\n class=${classMap({\n label: true,\n min: true,\n disabled: this.disabled,\n })}\n style=\"width: ${this.labelWidth};\"\n >\n <slot name=\"left-readout\">${this.formatLabel(this.low)}</slot>\n </div>\n `\n : null}\n <div\n class=${classMap({\n wrapper: true,\n [this.variant]: true,\n mouseDown: this.isMouseDown,\n dragging: this.isDragging,\n disabled: this.disabled,\n })}\n style=${styleMap({\n '--_low-ratio': String(this.lowRatio),\n '--_high-ratio': String(this.highRatio),\n })}\n @mousedown=${this.onMouseDown}\n @mouseup=${this.onMouseUp}\n @mousemove=${this.onMouseMove}\n >\n <div class=\"track\"></div>\n <input\n type=\"range\"\n min=${this.min}\n max=${this.max}\n class=\"slider min\"\n step=${ifDefined(this.step)}\n .value=${this.low.toString()}\n ?disabled=${this.variant === ObcSliderDoubleVariant.NoInput ||\n this.disabled}\n @input=${this.onInput}\n @change=${() => this.fireChangeEvent()}\n />\n <input\n type=\"range\"\n class=\"slider max\"\n min=${this.min}\n max=${this.max}\n step=${ifDefined(this.step)}\n .value=${this.high.toString()}\n ?disabled=${this.variant === ObcSliderDoubleVariant.NoInput ||\n this.disabled}\n @input=${this.onInput}\n @change=${() => this.fireChangeEvent()}\n />\n <div class=\"interactive-track\"></div>\n <div class=\"thumb min\"></div>\n <div class=\"thumb max\"></div>\n </div>\n ${this.showRightReadout\n ? html`\n <div\n class=${classMap({\n label: true,\n max: true,\n disabled: this.disabled,\n })}\n style=\"width: ${this.labelWidth};\"\n >\n <slot name=\"right-readout\">${this.formatLabel(this.high)}</slot>\n </div>\n `\n : null}\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slider-double': ObcSliderDouble;\n }\n}\n"],"names":["ObcSliderDoubleVariant"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slider-double.js","sources":["../../../src/components/slider-double/slider-double.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property, query} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport {styleMap} from 'lit/directives/style-map.js';\nimport componentStyle from './slider-double.css?inline';\nimport '../icon-button/icon-button.js';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\n\n/**\n * Enum for slider double variants.\n *\n * - `normal`: Standard slider with default styling and interaction.\n * - `enhanced`: Visually enhanced slider with larger track and thumb, suitable for more prominent or touch-friendly UIs.\n * - `no-input`: Non-interactive display mode; disables all user input and presents the slider as read-only.\n */\nexport enum ObcSliderDoubleVariant {\n Normal = 'normal',\n Enhanced = 'enhanced',\n NoInput = 'no-input',\n}\n\n/**\n * Event type for value changes in obc-slider-double.\n * Contains the current low and high values of the slider.\n */\nexport type ObcSliderDoubleValueEvent = CustomEvent<{\n low: number;\n high: number;\n}>;\n\n/**\n * Event type for change event in obc-slider-double (fired after user interaction completes).\n * Contains the current low and high values of the slider.\n */\nexport type ObcSliderDoubleChangeEvent = CustomEvent<{\n low: number;\n high: number;\n}>;\n\n/**\n * `<obc-slider-double>` – A dual-thumb range slider for selecting a value interval within a defined range.\n *\n * This component allows users to select a minimum and maximum value by dragging two thumbs along a horizontal track. It is commonly used for filtering or specifying ranges (such as price, speed, or time intervals) in forms and dashboards. The slider supports both interactive and read-only display modes, as well as visual variants for different UI needs.\n *\n * Appears with two draggable handles (thumbs) and labels showing the current low and high values. The low and high readout labels can be customized via slots.\n *\n * ## Features\n * - **Dual-thumb range selection:** Users can adjust both the lower and upper bounds of a numeric interval.\n * - **Variants:**\n * - **Normal:** Standard slider with compact styling.\n * - **Enhanced:** Larger track and thumb for increased prominence or touch accessibility.\n * - **NoInput:** Read-only mode; disables all user interaction and presents the current range as static.\n * - **Configurable range:** Set minimum (`min`), maximum (`max`), and step size (`step`) for precise control.\n * - **Step click adjustment:** Use `stepClick` to define increment/decrement amount for keyboard or button-based changes.\n * - **Seeking mode:** Enable `allowSeeking` to let users jump to a value by clicking on the track, with smooth animated transitions controlled by `seekingSpeed`.\n * - **Custom labels:** Display formatted value labels with unit (`labelUnit`), decimal precision (`labelDecimals`), and adjustable label width (`labelWidth`).\n * - **Hug container option:** Remove spacing between slider and container edges with the `hugcontainer` attribute for seamless layout integration.\n * - **Custom readouts:** Replace the low/high value labels with custom content using the `left-readout` and `right-readout` slots.\n *\n * ## Usage Guidelines\n * Use `obc-slider-double` when you need users to specify a numeric range, such as filtering results by minimum and maximum values. Ideal for scenarios like:\n * - Filtering items by price, speed, or other continuous values.\n * - Selecting a time interval or threshold range.\n * - Any UI where a bounded numeric interval is required.\n *\n * For single-value selection, use a standard slider component instead. In read-only or summary views, use the `no-input` variant to display the selected range without allowing changes.\n *\n * **TODO(designer):** Confirm if there are recommended minimum thumb separation or constraints for usability, and if there are best practices for using the enhanced variant.\n *\n * ## Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |---------------|-------------------------------|------------------------------------------------------------------------------------------------------------------|\n * | left-readout | `showLeftReadout` is true | Custom content for the left (low) readout label. Falls back to the formatted `low` value. |\n * | right-readout | `showRightReadout` is true | Custom content for the right (high) readout label. Falls back to the formatted `high` value. |\n *\n * ## Properties and Attributes\n * - `low` (number): The current lower bound of the selected range.\n * - `high` (number): The current upper bound of the selected range.\n * - `min` (number): The minimum allowed value (default: 0).\n * - `max` (number): The maximum allowed value (default: 100).\n * - `step` (number): The increment for value changes (default: 1).\n * - `stepClick` (number): Step size for keyboard or button-based changes (default: 10).\n * - `variant` (`normal` | `enhanced` | `no-input`): Visual and interaction style (default: `normal`).\n * - `allowSeeking` (boolean): If true, clicking the track animates the thumb to the clicked position.\n * - `seekingSpeed` (number): Animation speed for seeking (default: 1/3, i.e., full range in 3 seconds).\n * - `labelUnit` (string): Unit label appended to value labels (e.g., `\"%\"`, `\"kn\"`).\n * - `labelDecimals` (number): Number of decimal places for value labels.\n * - `labelWidth` (string): CSS width for value labels (e.g., `\"5ch\"`, `\"60px\"`).\n * - `showLeftReadout` (boolean, property only): Show the left (low) readout label. Default `true`.\n * - `showRightReadout` (boolean, property only): Show the right (high) readout label. Default `true`.\n * - `hugcontainer` (attribute): If present, removes spacing between slider and container edges.\n *\n * ## Events\n * - `value` – Fired continuously whenever the low or high value changes during user interaction. Event detail contains `{low, high}`.\n * - `change` – Fired only after user interaction completes (mouse release). Event detail contains `{low, high}`.\n *\n * ## Best Practices and Constraints\n * - Ensure `low` is always less than or equal to `high`; the component enforces this automatically.\n * - For accessibility, provide clear labels and units so users understand the meaning of the range.\n * - Use the `no-input` variant for summary or review screens where editing is not allowed.\n * - When using `allowSeeking`, set an appropriate `seekingSpeed` for smooth but responsive thumb movement.\n * - Avoid setting `step` too small for large ranges, as this may make precise selection difficult.\n *\n * ## Example\n *\n * ```html\n * <obc-slider-double\n * min=\"0\"\n * max=\"100\"\n * low=\"20\"\n * high=\"80\"\n * step=\"5\"\n * label-unit=\"%\"\n * label-decimals=\"0\"\n * variant=\"enhanced\"\n * allowSeeking\n * >\n * <span slot=\"left-readout\">Min</span>\n * <span slot=\"right-readout\">Max</span>\n * </obc-slider-double>\n * ```\n *\n * In this example, the slider allows selection of a percentage range from 0 to 100, with 5% increments, enhanced styling, and seeking enabled.\n *\n * @slot left-readout - Custom content for the left (low) readout label (rendered when `showLeftReadout` is true)\n * @slot right-readout - Custom content for the right (high) readout label (rendered when `showRightReadout` is true)\n * @fires {ObcSliderDoubleValueEvent} value - Fires when the value is changed\n * @fires {ObcSliderDoubleChangeEvent} change - Fires when user interaction completes\n * @stable\n */\n@customElement('obc-slider-double')\nexport class ObcSliderDouble extends LitElement {\n /**\n * The current lower bound of the selected range.\n * Must be greater than or equal to `min` and less than or equal to `high`.\n */\n @property({type: Number}) low = 0;\n\n /**\n * The current upper bound of the selected range.\n * Must be less than or equal to `max` and greater than or equal to `low`.\n */\n @property({type: Number}) high = 100;\n\n /**\n * The minimum allowed value for the slider.\n * Default is 0.\n */\n @property({type: Number}) min = 0;\n\n /**\n * The maximum allowed value for the slider.\n * Default is 100.\n */\n @property({type: Number}) max = 100;\n\n /**\n * The increment for value changes.\n * If not set, defaults to 1.\n */\n @property({type: Number}) step: number | undefined;\n\n /**\n * Step size for keyboard or button-based changes.\n * Default is 10.\n */\n @property({type: Number}) stepClick = 10;\n\n /**\n * Visual and interaction style of the slider.\n * - `normal`: Standard appearance.\n * - `enhanced`: Larger track and thumb.\n * - `no-input`: Read-only, disables user interaction.\n * Default is `normal`.\n */\n @property({type: String}) variant: ObcSliderDoubleVariant =\n ObcSliderDoubleVariant.Normal;\n\n /**\n * If true, clicking the slider track animates the thumb to the clicked position.\n * Enables seeking mode for rapid value changes.\n */\n @property({type: Boolean}) allowSeeking = false;\n\n @property({type: Boolean}) disabled = false;\n\n /**\n * Animation speed for seeking, in inverse seconds.\n * The value will go from min to max in 1 / seekingSpeed seconds.\n * Default is 1/3 (i.e., 3 seconds for full range).\n */\n @property({type: Number}) seekingSpeed = 1 / 3;\n\n /**\n * Unit label appended to value labels (e.g., \"%\", \"kn\").\n */\n @property({type: String}) labelUnit = '';\n\n /**\n * Number of decimal places to display in value labels.\n */\n @property({type: Number}) labelDecimals = 0;\n\n /**\n * CSS width for value labels (e.g., \"5ch\", \"60px\").\n */\n @property({type: String}) labelWidth = '60px';\n\n /**\n * Whether to show the left (low) readout label.\n *\n * When false, the left readout is hidden entirely. When true, the readout\n * renders the formatted `low` value or the content slotted into `left-readout`.\n *\n * Default is true. Set via JavaScript property (no HTML attribute).\n */\n @property({type: Boolean, attribute: false}) showLeftReadout = true;\n\n /**\n * Whether to show the right (high) readout label.\n *\n * When false, the right readout is hidden entirely. When true, the readout\n * renders the formatted `high` value or the content slotted into `right-readout`.\n *\n * Default is true. Set via JavaScript property (no HTML attribute).\n */\n @property({type: Boolean, attribute: false}) showRightReadout = true;\n\n /**\n * Removes spacing between the slider and its container edges for seamless\n * layout integration. Reflected to the `hugcontainer` HTML attribute.\n */\n @property({type: Boolean, reflect: true, attribute: 'hugcontainer'})\n hugContainer = false;\n\n private get lowRatio(): number {\n return this.computeRatio(this.low);\n }\n\n private get highRatio(): number {\n return this.computeRatio(this.high);\n }\n\n private computeRatio(value: number): number {\n const range = this.max - this.min;\n if (!Number.isFinite(range) || range <= 0) return 0;\n const ratio = (value - this.min) / range;\n if (!Number.isFinite(ratio)) return 0;\n return Math.max(0, Math.min(1, ratio));\n }\n\n private animationFrame: number | null = null;\n private isMouseDown = false;\n private targetValue = 0;\n private isDragging = false;\n private isTargetingLow = false;\n private animationStartTime: number | null = null;\n private animationStartValue: number = 0;\n\n @query('input[type=\"range\"].min')\n private minInput!: HTMLInputElement;\n\n @query('input[type=\"range\"].max')\n private maxInput!: HTMLInputElement;\n\n /**\n * Handles input changes from the slider thumbs.\n * Updates the low and high values and emits the `value` event.\n *\n * @fires value\n */\n onInput() {\n let newLow = parseFloat(this.minInput.value);\n let newHigh = parseFloat(this.maxInput.value);\n if (newLow > this.high) {\n newLow = this.high;\n this.minInput.value = this.high.toString();\n }\n if (newHigh < this.low) {\n newHigh = this.low;\n this.maxInput.value = this.low.toString();\n }\n this.low = newLow;\n this.high = newHigh;\n this.dispatchEvent(\n new CustomEvent('value', {detail: {low: this.low, high: this.high}})\n );\n }\n\n /**\n * Fires the `change` event with the current low and high values.\n *\n * @fires change\n */\n private fireChangeEvent() {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {low: this.low, high: this.high},\n }) as ObcSliderDoubleChangeEvent\n );\n }\n\n private THUMB_WIDTH = 48;\n private THUMB_VISIBLE_WIDTH = 12;\n\n private lowClickValue(e: MouseEvent) {\n const rect = this.minInput.getBoundingClientRect();\n const left = rect.left + this.THUMB_WIDTH - this.THUMB_VISIBLE_WIDTH / 2;\n const width = rect.width - this.THUMB_WIDTH;\n const percent = (e.clientX - left) / width;\n return this.min + (this.max - this.min) * percent;\n }\n\n private highClickValue(e: MouseEvent) {\n const rect = this.maxInput.getBoundingClientRect();\n const left = rect.left + this.THUMB_VISIBLE_WIDTH / 2;\n const width = rect.width - this.THUMB_WIDTH;\n const percent = (e.clientX - left) / width;\n return this.min + (this.max - this.min) * percent;\n }\n\n private thumbRange() {\n const rect = this.minInput.getBoundingClientRect();\n const valueRange = this.max - this.min;\n const percentageRange = this.THUMB_WIDTH / rect.width;\n return valueRange * percentageRange;\n }\n\n private isClickingMinThumb(e: MouseEvent) {\n const value = this.lowClickValue(e);\n if (value > this.low) {\n return false;\n }\n return value >= this.low - this.thumbRange();\n }\n\n private isClickingMaxThumb(e: MouseEvent) {\n const value = this.highClickValue(e);\n if (value < this.high) {\n return false;\n }\n return value <= this.high + this.thumbRange();\n }\n\n private isClickingLowTrack(e: MouseEvent) {\n const value = this.lowClickValue(e);\n return value <= this.low - this.thumbRange() / 2;\n }\n\n private isClickingHighTrack(e: MouseEvent) {\n const value = this.highClickValue(e);\n return value >= this.high + this.thumbRange() / 2;\n }\n\n private isClosestToLowThumb(e: MouseEvent) {\n const lowValue = this.lowClickValue(e);\n const highValue = this.highClickValue(e);\n return Math.abs(lowValue - this.low) <= Math.abs(highValue - this.high);\n }\n\n private onMouseDown(e: MouseEvent) {\n if (this.variant === ObcSliderDoubleVariant.NoInput || this.disabled)\n return;\n if (this.isClickingMinThumb(e)) {\n this.isTargetingLow = true;\n this.isDragging = true;\n } else if (this.isClickingMaxThumb(e)) {\n this.isTargetingLow = false;\n this.isDragging = true;\n } else if (this.isClickingLowTrack(e)) {\n this.isTargetingLow = true;\n this.isDragging = false;\n } else if (this.isClickingHighTrack(e)) {\n this.isTargetingLow = false;\n this.isDragging = false;\n } else if (this.isClosestToLowThumb(e)) {\n this.isTargetingLow = true;\n this.isDragging = false;\n } else {\n this.isTargetingLow = false;\n this.isDragging = false;\n }\n this.isMouseDown = true;\n this.updateTargetValue(e);\n e.preventDefault();\n window.addEventListener('mousemove', this.onWindowMouseMove);\n window.addEventListener('mouseup', this.onWindowMouseUp);\n this.startAnimation();\n }\n\n private onWindowMouseMove = (e: MouseEvent) => {\n this.onMouseMove(e);\n };\n\n private onWindowMouseUp = () => {\n this.onMouseUp();\n };\n\n private onMouseMove(e: MouseEvent) {\n if (this.isMouseDown) {\n this.updateTargetValue(e);\n }\n }\n\n private onMouseUp() {\n this.isMouseDown = false;\n this.isDragging = false;\n window.removeEventListener('mousemove', this.onWindowMouseMove);\n window.removeEventListener('mouseup', this.onWindowMouseUp);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private updateTargetValue(e: MouseEvent) {\n const unroundedValue = this.isTargetingLow\n ? this.lowClickValue(e)\n : this.highClickValue(e);\n if (this.step) {\n this.targetValue = Math.round(unroundedValue / this.step) * this.step;\n } else {\n this.targetValue = unroundedValue;\n }\n if (this.isTargetingLow) {\n this.targetValue = Math.max(\n this.min,\n Math.min(this.targetValue, this.high)\n );\n } else {\n this.targetValue = Math.min(\n this.max,\n Math.max(this.targetValue, this.low)\n );\n }\n }\n\n private startAnimation() {\n this.isDragging = this.allowSeeking;\n this.animationStartTime = performance.now();\n this.animationStartValue = this.isTargetingLow ? this.low : this.high;\n const min = this.min;\n const max = this.max;\n const step = this.step;\n const duration = (1 / this.seekingSpeed) * 1000; // ms\n const direction = this.targetValue > this.animationStartValue ? 1 : -1;\n\n const animate = () => {\n let nextValue = this.targetValue;\n if (!this.isDragging) {\n const now = performance.now();\n const elapsed = now - (this.animationStartTime ?? now);\n const range = Math.abs(max - min);\n // How much of the range should be covered by now\n const expectedProgress = Math.min(elapsed / duration, 1);\n const expectedValue =\n this.animationStartValue + direction * range * expectedProgress;\n // Snap to step\n if (direction > 0) {\n nextValue =\n step === undefined\n ? expectedValue\n : Math.ceil(expectedValue - min / step) * step + min;\n nextValue = Math.min(this.targetValue, nextValue);\n } else {\n nextValue =\n step === undefined\n ? expectedValue\n : Math.floor((expectedValue - min) / step) * step + min;\n nextValue = Math.max(this.targetValue, nextValue);\n }\n }\n // Only update if value actually changes\n const isValueChanged = this.isTargetingLow\n ? this.low !== nextValue\n : this.high !== nextValue;\n if (isValueChanged) {\n if (this.isTargetingLow) {\n this.low = nextValue;\n } else {\n this.high = nextValue;\n }\n this.dispatchEvent(\n new CustomEvent('value', {detail: {low: this.low, high: this.high}})\n );\n }\n // Continue animating if not at target\n if (\n (direction > 0 && nextValue < this.targetValue) ||\n (direction < 0 && nextValue > this.targetValue)\n ) {\n this.animationFrame = requestAnimationFrame(animate);\n } else if (this.isMouseDown) {\n // If mouse is still down, wait for new target\n this.animationStartTime = performance.now();\n this.animationStartValue = this.isTargetingLow ? this.low : this.high;\n this.animationFrame = requestAnimationFrame(animate);\n this.isDragging = true;\n }\n };\n\n this.animationFrame = requestAnimationFrame(animate);\n }\n\n private stopAnimation() {\n if (this.animationFrame !== null) {\n cancelAnimationFrame(this.animationFrame);\n this.animationFrame = null;\n }\n }\n\n private formatLabel(value: number) {\n return value.toFixed(this.labelDecimals) + this.labelUnit;\n }\n\n override render() {\n return html`\n ${this.showLeftReadout\n ? html`\n <div\n class=${classMap({\n label: true,\n min: true,\n disabled: this.disabled,\n })}\n style=\"width: ${this.labelWidth};\"\n >\n <slot name=\"left-readout\">${this.formatLabel(this.low)}</slot>\n </div>\n `\n : null}\n <div\n class=${classMap({\n wrapper: true,\n [this.variant]: true,\n mouseDown: this.isMouseDown,\n dragging: this.isDragging,\n disabled: this.disabled,\n })}\n style=${styleMap({\n '--_low-ratio': String(this.lowRatio),\n '--_high-ratio': String(this.highRatio),\n })}\n @mousedown=${this.onMouseDown}\n @mouseup=${this.onMouseUp}\n @mousemove=${this.onMouseMove}\n >\n <div class=\"track\"></div>\n <input\n type=\"range\"\n min=${this.min}\n max=${this.max}\n class=\"slider min\"\n step=${ifDefined(this.step)}\n .value=${this.low.toString()}\n ?disabled=${this.variant === ObcSliderDoubleVariant.NoInput ||\n this.disabled}\n @input=${this.onInput}\n @change=${() => this.fireChangeEvent()}\n />\n <input\n type=\"range\"\n class=\"slider max\"\n min=${this.min}\n max=${this.max}\n step=${ifDefined(this.step)}\n .value=${this.high.toString()}\n ?disabled=${this.variant === ObcSliderDoubleVariant.NoInput ||\n this.disabled}\n @input=${this.onInput}\n @change=${() => this.fireChangeEvent()}\n />\n <div class=\"interactive-track\"></div>\n <div class=\"thumb min\"></div>\n <div class=\"thumb max\"></div>\n </div>\n ${this.showRightReadout\n ? html`\n <div\n class=${classMap({\n label: true,\n max: true,\n disabled: this.disabled,\n })}\n style=\"width: ${this.labelWidth};\"\n >\n <slot name=\"right-readout\">${this.formatLabel(this.high)}</slot>\n </div>\n `\n : null}\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slider-double': ObcSliderDouble;\n }\n}\n"],"names":["ObcSliderDoubleVariant"],"mappings":"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"}
|
|
@@ -123,11 +123,13 @@ export declare class ObcStepperBox extends LitElement {
|
|
|
123
123
|
private onNumberFieldInput;
|
|
124
124
|
private dispatchChange;
|
|
125
125
|
/**
|
|
126
|
-
*
|
|
126
|
+
* Dispatches the `down` event when the decrement button is clicked.
|
|
127
|
+
* @fires down
|
|
127
128
|
*/
|
|
128
129
|
down(): void;
|
|
129
130
|
/**
|
|
130
|
-
*
|
|
131
|
+
* Dispatches the `up` event when the increment button is clicked.
|
|
132
|
+
* @fires up
|
|
131
133
|
*/
|
|
132
134
|
up(): void;
|
|
133
135
|
static styles: import('lit').CSSResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepper-box.d.ts","sourceRoot":"","sources":["../../../src/components/stepper-box/stepper-box.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA4B,cAAc,EAAC,MAAM,KAAK,CAAC;AAGzE,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,4BAA4B,CAAC;AACpC,OAAO,uCAAuC,CAAC;AAC/C,OAAO,yCAAyC,CAAC;AACjD,OAAO,0CAA0C,CAAC;AAClD,OAAO,yCAAyC,CAAC;AAEjD,OAAO,6CAA6C,CAAC;AAGrD;;;;;;GAMG;AACH,oBAAY,iBAAiB;IAC3B,MAAM,YAAY;IAClB,SAAS,eAAe;IACxB,SAAS,eAAe;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C;;;;;;;OAOG;IACuB,IAAI,EAAE,iBAAiB,CACnB;IAE9B;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;;OAGG;IACuB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAK;IAEnD;;OAEG;IACuB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACuB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACuB,MAAM,SAAK;IAErC;;OAEG;IACuB,QAAQ,SAAK;IAEvC;;OAEG;IACuB,IAAI,SAAM;IAEpC;;OAEG;IACuB,UAAU,SAAM;IAE1C;;OAEG;IACuB,WAAW,SAAM;IAE3C;;OAEG;IACwB,QAAQ,UAAS;IAE5C,OAAO,KAAK,YAAY,GAOvB;IAED,OAAO,KAAK,UAAU,GAOrB;IAEQ,iBAAiB;IAKjB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAMlD,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,cAAc;IAOtB,OAAO,KAAK,QAAQ,GAQnB;IAED,OAAO,KAAK,SAAS,GAQpB;IAEQ,MAAM;IA0Cf,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,cAAc;IAUtB
|
|
1
|
+
{"version":3,"file":"stepper-box.d.ts","sourceRoot":"","sources":["../../../src/components/stepper-box/stepper-box.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA4B,cAAc,EAAC,MAAM,KAAK,CAAC;AAGzE,OAAO,8BAA8B,CAAC;AACtC,OAAO,+BAA+B,CAAC;AACvC,OAAO,4BAA4B,CAAC;AACpC,OAAO,uCAAuC,CAAC;AAC/C,OAAO,yCAAyC,CAAC;AACjD,OAAO,0CAA0C,CAAC;AAClD,OAAO,yCAAyC,CAAC;AAEjD,OAAO,6CAA6C,CAAC;AAGrD;;;;;;GAMG;AACH,oBAAY,iBAAiB;IAC3B,MAAM,YAAY;IAClB,SAAS,eAAe;IACxB,SAAS,eAAe;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,qBACa,aAAc,SAAQ,UAAU;IAC3C;;;;;;;OAOG;IACuB,IAAI,EAAE,iBAAiB,CACnB;IAE9B;;OAEG;IACuC,QAAQ,UAAS;IAE3D;;;OAGG;IACuB,KAAK,EAAE,MAAM,GAAG,IAAI,CAAK;IAEnD;;OAEG;IACuB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACuB,GAAG,CAAC,EAAE,MAAM,CAAC;IAEvC;;OAEG;IACuB,MAAM,SAAK;IAErC;;OAEG;IACuB,QAAQ,SAAK;IAEvC;;OAEG;IACuB,IAAI,SAAM;IAEpC;;OAEG;IACuB,UAAU,SAAM;IAE1C;;OAEG;IACuB,WAAW,SAAM;IAE3C;;OAEG;IACwB,QAAQ,UAAS;IAE5C,OAAO,KAAK,YAAY,GAOvB;IAED,OAAO,KAAK,UAAU,GAOrB;IAEQ,iBAAiB;IAKjB,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAMlD,OAAO,CAAC,yBAAyB;IAQjC,OAAO,CAAC,KAAK;IAOb,OAAO,CAAC,cAAc;IAOtB,OAAO,KAAK,QAAQ,GAQnB;IAED,OAAO,KAAK,SAAS,GAQpB;IAEQ,MAAM;IA0Cf,OAAO,CAAC,kBAAkB;IA2B1B,OAAO,CAAC,cAAc;IAUtB;;;OAGG;IACH,IAAI;IAiBJ;;;OAGG;IACH,EAAE;IAiBF,OAAgB,MAAM,0BAA2B;CAClD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,iBAAiB,EAAE,aAAa,CAAC;KAClC;CACF"}
|
|
@@ -162,7 +162,8 @@ let ObcStepperBox = class extends LitElement {
|
|
|
162
162
|
);
|
|
163
163
|
}
|
|
164
164
|
/**
|
|
165
|
-
*
|
|
165
|
+
* Dispatches the `down` event when the decrement button is clicked.
|
|
166
|
+
* @fires down
|
|
166
167
|
*/
|
|
167
168
|
down() {
|
|
168
169
|
if (this.downDisabled) {
|
|
@@ -181,7 +182,8 @@ let ObcStepperBox = class extends LitElement {
|
|
|
181
182
|
this.dispatchChange(newValue);
|
|
182
183
|
}
|
|
183
184
|
/**
|
|
184
|
-
*
|
|
185
|
+
* Dispatches the `up` event when the increment button is clicked.
|
|
186
|
+
* @fires up
|
|
185
187
|
*/
|
|
186
188
|
up() {
|
|
187
189
|
if (this.upDisabled) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stepper-box.js","sources":["../../../src/components/stepper-box/stepper-box.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS, PropertyValues} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './stepper-box.css?inline';\nimport '../../icons/icon-down-iec.js';\nimport '../icon-button/icon-button.js';\nimport '../../icons/icon-up-iec.js';\nimport '../../icons/icon-chevron-up-google.js';\nimport '../../icons/icon-chevron-down-google.js';\nimport '../../icons/icon-chevron-right-google.js';\nimport '../../icons/icon-chevron-left-google.js';\nimport {customElement} from '../../decorator.js';\nimport '../number-input-field/number-input-field.js';\nimport {ObcNumberInputFieldTextAlign} from '../number-input-field/number-input-field.js';\n\n/**\n * The visual and behavioral variant of the stepper box.\n *\n * Uses up and down chevron icons for vertical adjustment.\n * Uses left and right chevron icons for horizontal adjustment.\n * Uses plus and minus icons for increment/decrement (default).\n */\nexport enum ObcStepperBoxType {\n upDown = 'up-down',\n leftRight = 'left-right',\n plusMinus = 'plus-minus',\n}\n\n/**\n * `<obc-stepper-box>` – A compact input control for incrementing or decrementing a value using step buttons.\n *\n * This component displays a value with optional unit and helper text, flanked by two icon buttons for adjusting the value up/down, left/right, or plus/minus depending on the selected type. It is typically used for numeric or enumerated value selection where direct text input is not required or desired.\n *\n * ### Features\n * - **Stepper Types:**\n * - `plus-minus` (default): Shows plus and minus icons for increment/decrement.\n * - `up-down`: Uses up and down chevron icons for vertical adjustment.\n * - `left-right`: Uses left and right chevron icons for horizontal adjustment.\n * - **Value Display:**\n * - Optional unit label via the `unit` property.\n * - **Helper Text:**\n * - When `helperText` is set, displays additional helper or status text below the control.\n * - **Icon Buttons:**\n * - Both increment and decrement actions are triggered by icon buttons, with icons adapting to the selected type.\n *\n * ### Usage Guidelines\n * Use `obc-stepper-box` for scenarios where users need to adjust a value in discrete steps, such as quantity pickers, setting numeric parameters, or cycling through options. It is ideal when you want to prevent invalid input and provide a clear, touch-friendly interface for value changes.\n *\n * ### Events\n * - `down` – Fired when the decrement (left or down) button is clicked.\n * - `up` – Fired when the increment (right or up) button is clicked.\n *\n * ### Best Practices\n * - Use the type that best matches the adjustment direction (e.g., `up-down` for vertical, `left-right` for horizontal, `plus-minus` for generic increment/decrement).\n * - Place concise values and units to maintain compact layout.\n * - Avoid using for free-form input; this is for step-based changes only.\n *\n * **Example:**\n * ```\n * <obc-stepper-box type=\"up-down\" value=\"5\" unit=\"kg\" helperText=\"Set weight\"></obc-stepper-box>\n * ```\n *\n * @fires {CustomEvent<{value: number}>} down - Fired when the decrement (left or down) button is clicked\n * @fires {CustomEvent<{value: number}>} up - Fired when the increment (right or up) button is clicked\n * @fires {CustomEvent<{value: string}>} input - Fired when the user types in the number input field\n * @fires {CustomEvent<{value: number | null}>} change - Fired when the value changes through the input field or the increment/decrement buttons; programmatic assignment to `value` does not dispatch it\n * @stable\n */\n@customElement('obc-stepper-box')\nexport class ObcStepperBox extends LitElement {\n /**\n * The visual and behavioral variant of the stepper box.\n * - `plus-minus` (default): Uses plus and minus icons.\n * - `up-down`: Uses up and down chevrons.\n * - `left-right`: Uses left and right chevrons.\n *\n * Changing this property updates the icons and directionality of the stepper buttons.\n */\n @property({type: String}) type: ObcStepperBoxType =\n ObcStepperBoxType.plusMinus;\n\n /**\n * If true, the stepper box is disabled and the buttons are not clickable.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * The current numeric value displayed in the field.\n * Pass `null` to clear the value and show the `placeholder` instead.\n */\n @property({type: Number}) value: number | null = 1;\n\n /**\n * Optional lower bound; decrement button disables at this value.\n */\n @property({type: Number}) min?: number;\n\n /**\n * Optional upper bound; increment button disables at this value.\n */\n @property({type: Number}) max?: number;\n\n /**\n * Increment step size (default 1).\n */\n @property({type: Number}) stepUp = 1;\n\n /**\n * Decrement step size (default 1).\n */\n @property({type: Number}) stepDown = 1;\n\n /**\n * Unit text displayed inside the field.\n */\n @property({type: String}) unit = '';\n\n /**\n * Helper text displayed below the stepper. When set, the helper text is shown.\n */\n @property({type: String}) helperText = '';\n\n /**\n * Placeholder text shown when the input is empty.\n */\n @property({type: String}) placeholder = '';\n\n /**\n * If true, the input is non-editable; programmatic value changes still apply.\n */\n @property({type: Boolean}) readonly = false;\n\n private get downDisabled(): boolean {\n return (\n this.disabled ||\n this.readonly ||\n this.value == null ||\n this.value <= (this.min ?? -Infinity)\n );\n }\n\n private get upDisabled(): boolean {\n return (\n this.disabled ||\n this.readonly ||\n this.value == null ||\n this.value >= (this.max ?? Infinity)\n );\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.syncDisabledAccessibility();\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('disabled')) {\n this.syncDisabledAccessibility();\n }\n }\n\n private syncDisabledAccessibility() {\n if (this.disabled) {\n this.setAttribute('aria-disabled', 'true');\n } else {\n this.removeAttribute('aria-disabled');\n }\n }\n\n private clamp(value: number): number {\n return Math.min(\n Math.max(value, this.min ?? -Infinity),\n this.max ?? Infinity\n );\n }\n\n private normalizedStep(step: number): number {\n if (!Number.isFinite(step) || step <= 0) {\n return 1;\n }\n return step;\n }\n\n private get leftIcon() {\n if (this.type === ObcStepperBoxType.upDown) {\n return html`<obi-chevron-down-google></obi-chevron-down-google>`;\n } else if (this.type === ObcStepperBoxType.leftRight) {\n return html`<obi-chevron-left-google></obi-chevron-left-google>`;\n } else {\n return html`<obi-down-iec></obi-down-iec>`;\n }\n }\n\n private get rightIcon() {\n if (this.type === ObcStepperBoxType.upDown) {\n return html`<obi-chevron-up-google></obi-chevron-up-google>`;\n } else if (this.type === ObcStepperBoxType.leftRight) {\n return html`<obi-chevron-right-google></obi-chevron-right-google>`;\n } else {\n return html`<obi-up-iec></obi-up-iec>`;\n }\n }\n\n override render() {\n const showHelper = Boolean(this.helperText);\n\n return html`\n <div class=\"wrapper\">\n <div class=\"display\">\n <obc-icon-button\n cornerleft\n .showDivider=${false}\n ?disabled=${this.downDisabled}\n @click=${() => this.down()}\n >\n ${this.leftIcon}\n </obc-icon-button>\n <div class=\"field-wrapper\">\n <obc-number-input-field\n squared\n .value=${this.value == null ? NaN : Number(this.value)}\n .unit=${this.unit}\n .placeholder=${this.placeholder}\n .textAlign=${ObcNumberInputFieldTextAlign.Center}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n @input=${this.onNumberFieldInput}\n ></obc-number-input-field>\n </div>\n <obc-icon-button\n cornerright\n .showDivider=${false}\n ?disabled=${this.upDisabled}\n @click=${() => this.up()}\n >\n ${this.rightIcon}\n </obc-icon-button>\n </div>\n ${showHelper\n ? html`<div class=\"helper-text\">${this.helperText}</div>`\n : nothing}\n </div>\n `;\n }\n\n private onNumberFieldInput(e: Event) {\n const input = e.target as HTMLInputElement;\n const raw = input.value;\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {value: raw},\n bubbles: true,\n composed: true,\n })\n );\n\n if (raw.trim() === '') {\n return;\n }\n\n const parsed = Number(raw);\n if (!Number.isFinite(parsed)) {\n return;\n }\n\n const previous = this.value;\n this.value = parsed;\n if (previous !== this.value) {\n this.dispatchChange(this.value);\n }\n }\n\n private dispatchChange(value: number | null) {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n /**\n * @fires down - Dispatches the `down` event when the decrement button is clicked.\n */\n down() {\n if (this.downDisabled) {\n return;\n }\n const current = this.value as number;\n const newValue = this.clamp(current - this.normalizedStep(this.stepDown));\n this.value = newValue;\n this.dispatchEvent(\n new CustomEvent('down', {\n detail: {value: newValue},\n bubbles: true,\n composed: true,\n })\n );\n this.dispatchChange(newValue);\n }\n\n /**\n * @fires up - Dispatches the `up` event when the increment button is clicked.\n */\n up() {\n if (this.upDisabled) {\n return;\n }\n const current = this.value as number;\n const newValue = this.clamp(current + this.normalizedStep(this.stepUp));\n this.value = newValue;\n this.dispatchEvent(\n new CustomEvent('up', {\n detail: {value: newValue},\n bubbles: true,\n composed: true,\n })\n );\n this.dispatchChange(newValue);\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-stepper-box': ObcStepperBox;\n }\n}\n"],"names":["ObcStepperBoxType"],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAqBO,IAAK,sCAAAA,uBAAL;AACLA,qBAAA,QAAA,IAAS;AACTA,qBAAA,WAAA,IAAY;AACZA,qBAAA,WAAA,IAAY;AAHF,SAAAA;AAAA,GAAA,qBAAA,CAAA,CAAA;AA+CL,IAAM,gBAAN,cAA4B,WAAW;AAAA,EAAvC,cAAA;AAAA,UAAA,GAAA,SAAA;AASqB,SAAA,OACxB;AAKwC,SAAA,WAAW;AAM3B,SAAA,QAAuB;AAevB,SAAA,SAAS;AAKT,SAAA,WAAW;AAKX,SAAA,OAAO;AAKP,SAAA,aAAa;AAKb,SAAA,cAAc;AAKb,SAAA,WAAW;AAAA,EAAA;AAAA,EAEtC,IAAY,eAAwB;AAClC,WACE,KAAK,YACL,KAAK,YACL,KAAK,SAAS,QACd,KAAK,UAAU,KAAK,OAAO;AAAA,EAE/B;AAAA,EAEA,IAAY,aAAsB;AAChC,WACE,KAAK,YACL,KAAK,YACL,KAAK,SAAS,QACd,KAAK,UAAU,KAAK,OAAO;AAAA,EAE/B;AAAA,EAES,oBAAoB;AAC3B,UAAM,kBAAA;AACN,SAAK,0BAAA;AAAA,EACP;AAAA,EAES,QAAQ,mBAAmC;AAClD,QAAI,kBAAkB,IAAI,UAAU,GAAG;AACrC,WAAK,0BAAA;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,4BAA4B;AAClC,QAAI,KAAK,UAAU;AACjB,WAAK,aAAa,iBAAiB,MAAM;AAAA,IAC3C,OAAO;AACL,WAAK,gBAAgB,eAAe;AAAA,IACtC;AAAA,EACF;AAAA,EAEQ,MAAM,OAAuB;AACnC,WAAO,KAAK;AAAA,MACV,KAAK,IAAI,OAAO,KAAK,OAAO,SAAS;AAAA,MACrC,KAAK,OAAO;AAAA,IAAA;AAAA,EAEhB;AAAA,EAEQ,eAAe,MAAsB;AAC3C,QAAI,CAAC,OAAO,SAAS,IAAI,KAAK,QAAQ,GAAG;AACvC,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEA,IAAY,WAAW;AACrB,QAAI,KAAK,SAAS,WAA0B;AAC1C,aAAO;AAAA,IACT,WAAW,KAAK,SAAS,cAA6B;AACpD,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAEA,IAAY,YAAY;AACtB,QAAI,KAAK,SAAS,WAA0B;AAC1C,aAAO;AAAA,IACT,WAAW,KAAK,SAAS,cAA6B;AACpD,aAAO;AAAA,IACT,OAAO;AACL,aAAO;AAAA,IACT;AAAA,EACF;AAAA,EAES,SAAS;AAChB,UAAM,aAAa,QAAQ,KAAK,UAAU;AAE1C,WAAO;AAAA;AAAA;AAAA;AAAA;AAAA,2BAKgB,KAAK;AAAA,wBACR,KAAK,YAAY;AAAA,qBACpB,MAAM,KAAK,KAAA,CAAM;AAAA;AAAA,cAExB,KAAK,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,uBAKJ,KAAK,SAAS,OAAO,MAAM,OAAO,KAAK,KAAK,CAAC;AAAA,sBAC9C,KAAK,IAAI;AAAA,6BACF,KAAK,WAAW;AAAA,2BAClB,6BAA6B,MAAM;AAAA,0BACpC,KAAK,QAAQ;AAAA,0BACb,KAAK,QAAQ;AAAA,uBAChB,KAAK,kBAAkB;AAAA;AAAA;AAAA;AAAA;AAAA,2BAKnB,KAAK;AAAA,wBACR,KAAK,UAAU;AAAA,qBAClB,MAAM,KAAK,GAAA,CAAI;AAAA;AAAA,cAEtB,KAAK,SAAS;AAAA;AAAA;AAAA,UAGlB,aACE,gCAAgC,KAAK,UAAU,WAC/C,OAAO;AAAA;AAAA;AAAA,EAGjB;AAAA,EAEQ,mBAAmB,GAAU;AACnC,UAAM,QAAQ,EAAE;AAChB,UAAM,MAAM,MAAM;AAClB,SAAK;AAAA,MACH,IAAI,YAAY,SAAS;AAAA,QACvB,QAAQ,EAAC,OAAO,IAAA;AAAA,QAChB,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAGH,QAAI,IAAI,KAAA,MAAW,IAAI;AACrB;AAAA,IACF;AAEA,UAAM,SAAS,OAAO,GAAG;AACzB,QAAI,CAAC,OAAO,SAAS,MAAM,GAAG;AAC5B;AAAA,IACF;AAEA,UAAM,WAAW,KAAK;AACtB,SAAK,QAAQ;AACb,QAAI,aAAa,KAAK,OAAO;AAC3B,WAAK,eAAe,KAAK,KAAK;AAAA,IAChC;AAAA,EACF;AAAA,EAEQ,eAAe,OAAsB;AAC3C,SAAK;AAAA,MACH,IAAI,YAAY,UAAU;AAAA,QACxB,QAAQ,EAAC,MAAA;AAAA,QACT,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAAA,EAEL;AAAA;AAAA;AAAA;AAAA,EAKA,OAAO;AACL,QAAI,KAAK,cAAc;AACrB;AAAA,IACF;AACA,UAAM,UAAU,KAAK;AACrB,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,eAAe,KAAK,QAAQ,CAAC;AACxE,SAAK,QAAQ;AACb,SAAK;AAAA,MACH,IAAI,YAAY,QAAQ;AAAA,QACtB,QAAQ,EAAC,OAAO,SAAA;AAAA,QAChB,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAEH,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAAA;AAAA;AAAA;AAAA,EAKA,KAAK;AACH,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AACA,UAAM,UAAU,KAAK;AACrB,UAAM,WAAW,KAAK,MAAM,UAAU,KAAK,eAAe,KAAK,MAAM,CAAC;AACtE,SAAK,QAAQ;AACb,SAAK;AAAA,MACH,IAAI,YAAY,MAAM;AAAA,QACpB,QAAQ,EAAC,OAAO,SAAA;AAAA,QAChB,SAAS;AAAA,QACT,UAAU;AAAA,MAAA,CACX;AAAA,IAAA;AAEH,SAAK,eAAe,QAAQ;AAAA,EAC9B;AAGF;AA9Pa,cA6PK,SAAS,UAAU,YAAY;AApPrB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GATb,cASe,WAAA,QAAA,CAAA;AAMgB,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAf7B,cAe+B,WAAA,YAAA,CAAA;AAMhB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GArBb,cAqBe,WAAA,SAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA1Bb,cA0Be,WAAA,OAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA/Bb,cA+Be,WAAA,OAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GApCb,cAoCe,WAAA,UAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAzCb,cAyCe,WAAA,YAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA9Cb,cA8Ce,WAAA,QAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAnDb,cAmDe,WAAA,cAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAxDb,cAwDe,WAAA,eAAA,CAAA;AAKC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA7Dd,cA6DgB,WAAA,YAAA,CAAA;AA7DhB,gBAAN,gBAAA;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB,aAAA;"}
|
|
1
|
+
{"version":3,"file":"stepper-box.js","sources":["../../../src/components/stepper-box/stepper-box.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS, PropertyValues} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport compentStyle from './stepper-box.css?inline';\nimport '../../icons/icon-down-iec.js';\nimport '../icon-button/icon-button.js';\nimport '../../icons/icon-up-iec.js';\nimport '../../icons/icon-chevron-up-google.js';\nimport '../../icons/icon-chevron-down-google.js';\nimport '../../icons/icon-chevron-right-google.js';\nimport '../../icons/icon-chevron-left-google.js';\nimport {customElement} from '../../decorator.js';\nimport '../number-input-field/number-input-field.js';\nimport {ObcNumberInputFieldTextAlign} from '../number-input-field/number-input-field.js';\n\n/**\n * The visual and behavioral variant of the stepper box.\n *\n * Uses up and down chevron icons for vertical adjustment.\n * Uses left and right chevron icons for horizontal adjustment.\n * Uses plus and minus icons for increment/decrement (default).\n */\nexport enum ObcStepperBoxType {\n upDown = 'up-down',\n leftRight = 'left-right',\n plusMinus = 'plus-minus',\n}\n\n/**\n * `<obc-stepper-box>` – A compact input control for incrementing or decrementing a value using step buttons.\n *\n * This component displays a value with optional unit and helper text, flanked by two icon buttons for adjusting the value up/down, left/right, or plus/minus depending on the selected type. It is typically used for numeric or enumerated value selection where direct text input is not required or desired.\n *\n * ### Features\n * - **Stepper Types:**\n * - `plus-minus` (default): Shows plus and minus icons for increment/decrement.\n * - `up-down`: Uses up and down chevron icons for vertical adjustment.\n * - `left-right`: Uses left and right chevron icons for horizontal adjustment.\n * - **Value Display:**\n * - Optional unit label via the `unit` property.\n * - **Helper Text:**\n * - When `helperText` is set, displays additional helper or status text below the control.\n * - **Icon Buttons:**\n * - Both increment and decrement actions are triggered by icon buttons, with icons adapting to the selected type.\n *\n * ### Usage Guidelines\n * Use `obc-stepper-box` for scenarios where users need to adjust a value in discrete steps, such as quantity pickers, setting numeric parameters, or cycling through options. It is ideal when you want to prevent invalid input and provide a clear, touch-friendly interface for value changes.\n *\n * ### Events\n * - `down` – Fired when the decrement (left or down) button is clicked.\n * - `up` – Fired when the increment (right or up) button is clicked.\n *\n * ### Best Practices\n * - Use the type that best matches the adjustment direction (e.g., `up-down` for vertical, `left-right` for horizontal, `plus-minus` for generic increment/decrement).\n * - Place concise values and units to maintain compact layout.\n * - Avoid using for free-form input; this is for step-based changes only.\n *\n * **Example:**\n * ```\n * <obc-stepper-box type=\"up-down\" value=\"5\" unit=\"kg\" helperText=\"Set weight\"></obc-stepper-box>\n * ```\n *\n * @fires {CustomEvent<{value: number}>} down - Fired when the decrement (left or down) button is clicked\n * @fires {CustomEvent<{value: number}>} up - Fired when the increment (right or up) button is clicked\n * @fires {CustomEvent<{value: string}>} input - Fired when the user types in the number input field\n * @fires {CustomEvent<{value: number | null}>} change - Fired when the value changes through the input field or the increment/decrement buttons; programmatic assignment to `value` does not dispatch it\n * @stable\n */\n@customElement('obc-stepper-box')\nexport class ObcStepperBox extends LitElement {\n /**\n * The visual and behavioral variant of the stepper box.\n * - `plus-minus` (default): Uses plus and minus icons.\n * - `up-down`: Uses up and down chevrons.\n * - `left-right`: Uses left and right chevrons.\n *\n * Changing this property updates the icons and directionality of the stepper buttons.\n */\n @property({type: String}) type: ObcStepperBoxType =\n ObcStepperBoxType.plusMinus;\n\n /**\n * If true, the stepper box is disabled and the buttons are not clickable.\n */\n @property({type: Boolean, reflect: true}) disabled = false;\n\n /**\n * The current numeric value displayed in the field.\n * Pass `null` to clear the value and show the `placeholder` instead.\n */\n @property({type: Number}) value: number | null = 1;\n\n /**\n * Optional lower bound; decrement button disables at this value.\n */\n @property({type: Number}) min?: number;\n\n /**\n * Optional upper bound; increment button disables at this value.\n */\n @property({type: Number}) max?: number;\n\n /**\n * Increment step size (default 1).\n */\n @property({type: Number}) stepUp = 1;\n\n /**\n * Decrement step size (default 1).\n */\n @property({type: Number}) stepDown = 1;\n\n /**\n * Unit text displayed inside the field.\n */\n @property({type: String}) unit = '';\n\n /**\n * Helper text displayed below the stepper. When set, the helper text is shown.\n */\n @property({type: String}) helperText = '';\n\n /**\n * Placeholder text shown when the input is empty.\n */\n @property({type: String}) placeholder = '';\n\n /**\n * If true, the input is non-editable; programmatic value changes still apply.\n */\n @property({type: Boolean}) readonly = false;\n\n private get downDisabled(): boolean {\n return (\n this.disabled ||\n this.readonly ||\n this.value == null ||\n this.value <= (this.min ?? -Infinity)\n );\n }\n\n private get upDisabled(): boolean {\n return (\n this.disabled ||\n this.readonly ||\n this.value == null ||\n this.value >= (this.max ?? Infinity)\n );\n }\n\n override connectedCallback() {\n super.connectedCallback();\n this.syncDisabledAccessibility();\n }\n\n override updated(changedProperties: PropertyValues) {\n if (changedProperties.has('disabled')) {\n this.syncDisabledAccessibility();\n }\n }\n\n private syncDisabledAccessibility() {\n if (this.disabled) {\n this.setAttribute('aria-disabled', 'true');\n } else {\n this.removeAttribute('aria-disabled');\n }\n }\n\n private clamp(value: number): number {\n return Math.min(\n Math.max(value, this.min ?? -Infinity),\n this.max ?? Infinity\n );\n }\n\n private normalizedStep(step: number): number {\n if (!Number.isFinite(step) || step <= 0) {\n return 1;\n }\n return step;\n }\n\n private get leftIcon() {\n if (this.type === ObcStepperBoxType.upDown) {\n return html`<obi-chevron-down-google></obi-chevron-down-google>`;\n } else if (this.type === ObcStepperBoxType.leftRight) {\n return html`<obi-chevron-left-google></obi-chevron-left-google>`;\n } else {\n return html`<obi-down-iec></obi-down-iec>`;\n }\n }\n\n private get rightIcon() {\n if (this.type === ObcStepperBoxType.upDown) {\n return html`<obi-chevron-up-google></obi-chevron-up-google>`;\n } else if (this.type === ObcStepperBoxType.leftRight) {\n return html`<obi-chevron-right-google></obi-chevron-right-google>`;\n } else {\n return html`<obi-up-iec></obi-up-iec>`;\n }\n }\n\n override render() {\n const showHelper = Boolean(this.helperText);\n\n return html`\n <div class=\"wrapper\">\n <div class=\"display\">\n <obc-icon-button\n cornerleft\n .showDivider=${false}\n ?disabled=${this.downDisabled}\n @click=${() => this.down()}\n >\n ${this.leftIcon}\n </obc-icon-button>\n <div class=\"field-wrapper\">\n <obc-number-input-field\n squared\n .value=${this.value == null ? NaN : Number(this.value)}\n .unit=${this.unit}\n .placeholder=${this.placeholder}\n .textAlign=${ObcNumberInputFieldTextAlign.Center}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n @input=${this.onNumberFieldInput}\n ></obc-number-input-field>\n </div>\n <obc-icon-button\n cornerright\n .showDivider=${false}\n ?disabled=${this.upDisabled}\n @click=${() => this.up()}\n >\n ${this.rightIcon}\n </obc-icon-button>\n </div>\n ${showHelper\n ? html`<div class=\"helper-text\">${this.helperText}</div>`\n : nothing}\n </div>\n `;\n }\n\n private onNumberFieldInput(e: Event) {\n const input = e.target as HTMLInputElement;\n const raw = input.value;\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {value: raw},\n bubbles: true,\n composed: true,\n })\n );\n\n if (raw.trim() === '') {\n return;\n }\n\n const parsed = Number(raw);\n if (!Number.isFinite(parsed)) {\n return;\n }\n\n const previous = this.value;\n this.value = parsed;\n if (previous !== this.value) {\n this.dispatchChange(this.value);\n }\n }\n\n private dispatchChange(value: number | null) {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n /**\n * Dispatches the `down` event when the decrement button is clicked.\n * @fires down\n */\n down() {\n if (this.downDisabled) {\n return;\n }\n const current = this.value as number;\n const newValue = this.clamp(current - this.normalizedStep(this.stepDown));\n this.value = newValue;\n this.dispatchEvent(\n new CustomEvent('down', {\n detail: {value: newValue},\n bubbles: true,\n composed: true,\n })\n );\n this.dispatchChange(newValue);\n }\n\n /**\n * Dispatches the `up` event when the increment button is clicked.\n * @fires up\n */\n up() {\n if (this.upDisabled) {\n return;\n }\n const current = this.value as number;\n const newValue = this.clamp(current + this.normalizedStep(this.stepUp));\n this.value = newValue;\n this.dispatchEvent(\n new CustomEvent('up', {\n detail: {value: newValue},\n bubbles: true,\n composed: true,\n })\n );\n this.dispatchChange(newValue);\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-stepper-box': ObcStepperBox;\n }\n}\n"],"names":["ObcStepperBoxType"],"mappings":"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"}
|
|
@@ -177,7 +177,7 @@ export declare class ObcSystemButton extends LitElement {
|
|
|
177
177
|
* Called by the System Menu component.
|
|
178
178
|
*
|
|
179
179
|
* @param newState Partial system state to merge with the current state.
|
|
180
|
-
* @fires
|
|
180
|
+
* @fires system-state-change
|
|
181
181
|
*/
|
|
182
182
|
updateSystemState(newState: Partial<SystemState>): void;
|
|
183
183
|
/**
|
|
@@ -83,7 +83,7 @@ let ObcSystemButton = class extends LitElement {
|
|
|
83
83
|
* Called by the System Menu component.
|
|
84
84
|
*
|
|
85
85
|
* @param newState Partial system state to merge with the current state.
|
|
86
|
-
* @fires
|
|
86
|
+
* @fires system-state-change
|
|
87
87
|
*/
|
|
88
88
|
updateSystemState(newState) {
|
|
89
89
|
this.systemState = { ...this.systemState, ...newState };
|
|
@@ -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;
|
|
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":";;;;;;;;;;;;;;AAwHO,IAAM,gBAAN,cAA4B,WAAW;AAAA,EAAvC,cAAA;AAAA,UAAA,GAAA,SAAA;AAKqB,SAAA,QAAgB;AAMhB,SAAA,cAAsB;AAOrB,SAAA,qBAA8B;AAM9B,SAAA,cAAuB;AAAA,EAAA;AAAA,EAE1C,eAAe,GAAkB;AACvC,UAAM,eAAe,EAAE;AACvB,QAAI,CAAC,aAAa,UAAU,SAAS,YAAY,EAAG;AAEpD,UAAM,eAAe,KAAK;AAE1B,YAAQ,EAAE,KAAA;AAAA,MACR,KAAK;AACH,aAAK,gBAAgB,eAAe,KAAK,KAAK,KAAK;AACnD;AAAA,MACF,KAAK;AACH,aAAK,gBAAgB,eAAe,IAAI,KAAK,SAAS,KAAK,KAAK;AAChE;AAAA,MACF,KAAK;AACH,aAAK,eAAe,CAAC;AACrB;AAAA,MACF,KAAK;AACH,aAAK,eAAe,KAAK,QAAQ,CAAC;AAClC;AAAA,MACF;AACE;AAAA,IAAA;AAGJ,MAAE,eAAA;AACF,SAAK,UAAU,KAAK,WAAW;AAAA,EACjC;AAAA,EAEQ,eAAe,OAAe;AACpC,SAAK,cAAc;AAKnB,SAAK,cAAc,IAAI,YAAY,cAAc,EAAC,QAAQ,EAAC,KAAK,MAAA,EAAK,CAAE,CAAC;AAAA,EAC1E;AAAA,EAEQ,UAAU,OAAe;AAC/B,UAAM,SAAS,KAAK,YAAY;AAAA,MAC9B,sBAAsB,KAAK;AAAA,IAAA;AAE7B,YAAQ,MAAA;AAAA,EACV;AAAA,EAEQ,sBAAsB;AAC5B,WAAO,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC,EAAE,IAAI,CAAC,GAAG,UAAU;AAC9C,YAAM,aACJ,UAAU,KAAK,QAAQ,KACvB,KAAK,gBAAgB,SACrB,QAAQ,MAAM,KAAK;AACrB,YAAM,UAAU,KAAK,cACjB;AAAA,mCACyB,KAAK;AAAA,qBAE9B;AACJ,aAAO;AAAA;AAAA,8BAEiB,aAAa,gBAAgB,EAAE;AAAA;AAAA,2BAElC,KAAK,gBAAgB,KAAK;AAAA,iCACpB,KAAK;AAAA,oBAClB,KAAK;AAAA,wBACD,KAAK;AAAA,sBACP,KAAK,gBAAgB,QAAQ,IAAI,EAAE;AAAA,oBACrC,MAAM,KAAK,eAAe,KAAK,CAAC;AAAA,oBAChC,MAAM,KAAK,eAAe,KAAK,CAAC;AAAA;AAAA;AAAA,cAGtC,OAAO;AAAA,sDACiC,KAAK;AAAA,qBACtC,QAAQ,CAAC;AAAA;AAAA;AAAA;AAAA;AAAA,IAK1B,CAAC;AAAA,EACH;AAAA,EAEQ,qBAAqB;AAC3B,QAAI,KAAK,oBAAoB;AAC3B,aAAO;AAAA;AAAA;AAAA,oBAGO,KAAK,WAAW;AAAA,+BACL,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,IAK3C;AACA,WAAO,CAAC,GAAG,MAAM,KAAK,KAAK,CAAC,EAAE;AAAA,MAC5B,CAAC,GAAG,UAAU;AAAA;AAAA;AAAA,sBAGE,KAAK;AAAA,iCACM,KAAK;AAAA;AAAA,qBAEjB,KAAK,gBAAgB,KAAK;AAAA;AAAA,oCAEX,KAAK;AAAA;AAAA;AAAA,IAAA;AAAA,EAIvC;AAAA,EAES,SAAS;AAChB,WAAO;AAAA,6CACkC,KAAK,cAAc;AAAA;AAAA,YAEpD,KAAK,qBAAqB;AAAA;AAAA,kCAEJ,KAAK,oBAAoB;AAAA;AAAA;AAAA,EAGzD;AAGF;AA9Ia,cA6IK,SAAS,UAAU,YAAY;AAxIrB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GALb,cAKe,WAAA,SAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAXb,cAWe,WAAA,eAAA,CAAA;AAOC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAlBd,cAkBgB,WAAA,sBAAA,CAAA;AAMA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAxBd,cAwBgB,WAAA,eAAA,CAAA;AAxBhB,gBAAN,gBAAA;AAAA,EADN,cAAc,iBAAiB;AAAA,GACnB,aAAA;"}
|
|
@@ -146,7 +146,8 @@ export declare class ObcToggleButtonOption extends LitElement {
|
|
|
146
146
|
*/
|
|
147
147
|
large: boolean;
|
|
148
148
|
/**
|
|
149
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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":";;;;;;;;;;;;;;;AAMO,IAAK,8CAAAA,+BAAL;AACLA,6BAAA,MAAA,IAAO;AACPA,6BAAA,MAAA,IAAO;AACPA,6BAAA,eAAA,IAAgB;AAChBA,6BAAA,UAAA,IAAW;AAJD,SAAAA;AAAA,GAAA,6BAAA,CAAA,CAAA;AAOL,IAAK,iDAAAC,kCAAL;AACLA,gCAAA,MAAA,IAAO;AACPA,gCAAA,SAAA,IAAU;AACVA,gCAAA,QAAA,IAAS;AAHC,SAAAA;AAAA,GAAA,gCAAA,CAAA,CAAA;AAkGL,IAAM,wBAAN,cAAoC,WAAW;AAAA,EAA/C,cAAA;AAAA,UAAA,GAAA,SAAA;AAIqB,SAAA,QAAQ;AAKQ,SAAA,WAAW;AAKX,SAAA,YAAY;AAO5B,SAAA,OAAO;AAMP,SAAA,UAAU;AAOT,SAAA,UAAU;AAMK,SAAA,cAAuB;AAKvB,SAAA,WAAW;AAOX,SAAA,QAAQ;AAAA,EAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlD,QAAQ,OAAc;AACpB,QAAI,KAAK,UAAU;AACjB,YAAM,eAAA;AACN;AAAA,IACF;AAGA,QAAI,CAAC,KAAK,UAAU;AAClB,WAAK;AAAA,QACH,IAAI,YAAY,YAAY,EAAC,QAAQ,EAAC,OAAO,KAAK,QAAK,CAAE;AAAA,MAAA;AAAA,IAE7D;AAAA,EACF;AAAA,EAES,SAAS;AAChB,UAAM,gBACJ,KAAK,SAAS,UACd,KAAK,SAAS;AAChB,UAAM,UAAU,KAAK,SAAS;AAC9B,UAAM,WAAW,KAAK,SAAS;AAC/B,UAAM,kBACJ,KAAK,SAAS;AAEhB,WAAO;AAAA;AAAA,gBAEK,SAAS;AAAA,MACf,SAAS;AAAA,MACT,UAAU,KAAK;AAAA,MACf,gBAAgB;AAAA,MAChB,aAAa,KAAK,YAAY;AAAA,MAC9B,gBAAgB,KAAK,YAAY;AAAA,MACjC,eAAe,KAAK,YAAY;AAAA,MAChC,mBAAmB;AAAA,MACnB,YAAY,KAAK;AAAA,MACjB,UAAU,KAAK;AAAA,MACf,WAAW,KAAK;AAAA,MAChB,OAAO,KAAK;AAAA,IAAA,CACb,CAAC;AAAA,oBACU,KAAK,QAAQ;AAAA,iBAChB,KAAK,OAAO;AAAA;AAAA;AAAA,YAGjB,UACE;AAAA;AAAA,wBAGA,EAAE;AAAA,YACJ,YAAY,CAAC,kBACX,+CACA,EAAE;AAAA;AAAA,UAEN,YAAY,kBACV;AAAA;AAAA,sBAGA,EAAE;AAAA;AAAA;AAAA,EAGZ;AAGF;AAvHa,sBAsHK,SAAS,UAAU,cAAc;AAlHvB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAJb,sBAIe,WAAA,SAAA,CAAA;AAKgB,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAT7B,sBAS+B,WAAA,YAAA,CAAA;AAKA,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAd7B,sBAc+B,WAAA,aAAA,CAAA;AAOhB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GArBb,sBAqBe,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA3Bb,sBA2Be,WAAA,WAAA,CAAA;AAOC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAlCd,sBAkCgB,WAAA,WAAA,CAAA;AAMe,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAxC7B,sBAwC+B,WAAA,eAAA,CAAA;AAKA,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GA7C7B,sBA6C+B,WAAA,YAAA,CAAA;AAOA,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GApD7B,sBAoD+B,WAAA,SAAA,CAAA;AApD/B,wBAAN,gBAAA;AAAA,EADN,cAAc,0BAA0B;AAAA,GAC5B,qBAAA;"}
|