@oicl/openbridge-webcomponents 2.0.0-next.117 → 2.0.0-next.119
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/openbridge-webcomponents.bundle.js +37 -33
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +30 -24
- 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/automation/vertical-line/vertical-line.d.ts +6 -0
- package/dist/automation/vertical-line/vertical-line.d.ts.map +1 -1
- package/dist/automation/vertical-line/vertical-line.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/pivot-item-group/pivot-item-group.d.ts +1 -0
- package/dist/components/pivot-item-group/pivot-item-group.d.ts.map +1 -1
- package/dist/components/pivot-item-group/pivot-item-group.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 +3 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slide-button.js","sources":["../../../src/components/slide-button/slide-button.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property, query, state} from 'lit/decorators.js';\nimport componentStyle from './slide-button.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport '../../icons/icon-chevron-double-right-google.js';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcSlideButtonSlideEvent = CustomEvent<{completed: boolean}>;\n\n/**\n * `<obc-slide-button>` – A slide-to-confirm button that requires users to drag the button to the end of a track to trigger an action.\n *\n * Appears as a horizontal button with a draggable handle. The user must slide the handle to the right to complete the action, helping prevent accidental activations. Commonly used for critical or irreversible actions where explicit user intent is required (e.g., \"Delete\", \"Confirm\", \"Unlock\").\n *\n * ---\n *\n * ### Features\n * - **Slide-to-activate interaction:** Requires a deliberate sliding gesture to trigger the action, reducing accidental clicks.\n * - **Disabled state:** Can be disabled to prevent interaction (`disabled` property).\n * - **Leading icon (optional):** Supports a leading icon via the `leading-icon` slot, controlled by the `hasLeadingIcon` property.\n * - **Custom label:** Label text is provided via the `label` slot.\n * - **Auto-disable option:** When `autoDisable` is true, the button disables itself after a successful slide, preventing repeated actions.\n * - **Hug content:** The `hugContent` property allows the button to shrink to fit its content, rather than stretching to full width.\n * - **Visual feedback:** Provides animated feedback when sliding and snapping back if not completed.\n * - **Trailing icon:** Always displays a trailing double-chevron icon to indicate sliding direction.\n * - **Keyboard accessible:** The handle is focusable; `Enter` or `Space` triggers the action (with the same `slide` event and `autoDisable` behavior as a completed drag).\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-slide-button` for actions that require extra confirmation or where accidental activation could have significant consequences. Typical scenarios include confirming deletions, submitting irreversible forms, or unlocking sensitive features. Avoid using for routine or low-risk actions where a standard button suffices.\n *\n * - The sliding gesture provides a clear affordance for intentional actions.\n * - If you want the button to automatically disable after use (e.g., to prevent double submissions), set `autoDisable` to true.\n * - For best usability, keep the label concise and action-oriented (e.g., \"Slide to confirm\", \"Slide to delete\").\n * - The leading icon is optional and can be omitted for a simpler appearance.\n * - The button will snap back if the slide is not completed past the threshold.\n * - Only one slide button should be used for a given action to avoid confusion.\n * - Keyboard users activate with `Enter`/`Space` (single press — Tab + activation is considered deliberate). Provide `aria-label` on the host if the slotted label is not descriptive on its own (`aria-labelledby` is not supported — ID references cannot cross the shadow boundary).\n *\n * **TODO(designer):** Confirm if there are recommended minimum/maximum label lengths or if there are accessibility guidelines for color contrast and drag affordance.\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * | -------------- | --------------------- | --------------------------------------------- |\n * | leading-icon | `hasLeadingIcon` true | Icon at the start of the button (optional) |\n * | label | Always | Main label text for the button |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `disabled` (boolean): Disables the button and prevents interaction. When true, the button is visually muted and cannot be slid.\n * - `hasLeadingIcon` (boolean): Controls whether the leading icon slot is shown. Set to false to hide the icon area.\n * - `hugContent` (boolean): If true, the button shrinks to fit its content instead of stretching to full width.\n * - `autoDisable` (boolean): When true, the button automatically disables itself after a successful slide action.\n *\n * ---\n *\n * ### Events\n * - `slide` – Fired when the slide action is completed (i.e., the handle is dragged past the threshold). The event detail contains `{completed: true}`.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-slide-button autoDisable>\n * <obi-placeholder slot=\"leading-icon\"></obi-placeholder>\n * <span slot=\"label\">Slide to confirm</span>\n * </obc-slide-button>\n * ```\n * In this example, the button displays a leading icon and a label. After sliding to the end, it disables itself automatically.\n *\n * @slot leading-icon - The icon to display at the start of the button content (shown when `hasLeadingIcon` is true).\n * @slot label - The label text to display in the button.\n * @fires {ObcSlideButtonSlideEvent} slide - Emitted when the slide action is completed.\n * @experimental\n */\n@customElement('obc-slide-button')\nexport class ObcSlideButton extends LitElement {\n /**\n * Whether the slide button is disabled. When true, the button cannot be interacted with and appears visually muted.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * Whether to show the leading icon slot. Set to true to show the icon area at the start of the button.\n */\n @property({type: Boolean}) hasLeadingIcon = false;\n\n /**\n * Whether the button should hug its content. When true, the button width shrinks to fit its content instead of stretching to fill the container.\n */\n @property({type: Boolean}) hugContent = false;\n\n /**\n * Whether to automatically disable the button after a successful slide. When true, the button disables itself after the slide action completes.\n */\n @property({type: Boolean}) autoDisable = false;\n\n @state() private dragging = false;\n @state() private animatingBack = false;\n\n private dragStartX = 0;\n private dragCurrentX = 0;\n private dragOffset = 0;\n private trackWidth = 0;\n private buttonWidth = 0;\n private slideThreshold = 0.8;\n\n @query('.slide-button')\n private buttonRef?: HTMLElement;\n\n @query('.visual-container')\n private visualContainerRef?: HTMLElement;\n\n private onDragStart = (e: MouseEvent | TouchEvent) => {\n if (this.disabled) return;\n\n this.dragging = true;\n if (e instanceof MouseEvent) {\n this.dragStartX = e.clientX;\n } else {\n this.dragStartX = e.touches[0].clientX;\n }\n this.dragCurrentX = this.dragStartX;\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n\n window.addEventListener('mousemove', this.onDragMove);\n window.addEventListener('touchmove', this.onDragMove, {passive: false});\n window.addEventListener('mouseup', this.onDragEnd);\n window.addEventListener('touchend', this.onDragEnd);\n };\n\n private onDragMove = (e: MouseEvent | TouchEvent) => {\n if (!this.dragging) return;\n\n let clientX;\n if (e instanceof MouseEvent) {\n clientX = e.clientX;\n } else {\n clientX = e.touches[0].clientX;\n e.preventDefault();\n }\n\n this.dragCurrentX = clientX;\n this.dragOffset = this.dragCurrentX - this.dragStartX;\n this.requestUpdate();\n };\n\n private onDragEnd = () => {\n if (!this.dragging) return;\n\n this.dragging = false;\n this.animatingBack = true;\n\n const maxOffset = this.trackWidth - this.buttonWidth;\n const dragProgress = Math.max(0, this.dragOffset) / maxOffset;\n\n if (dragProgress >= this.slideThreshold) {\n this.completeSlide();\n }\n\n this.dragOffset = 0;\n this.requestUpdate();\n\n setTimeout(() => {\n this.animatingBack = false;\n this.requestUpdate();\n }, this.getResetDurationMs());\n\n window.removeEventListener('mousemove', this.onDragMove);\n window.removeEventListener('touchmove', this.onDragMove);\n window.removeEventListener('mouseup', this.onDragEnd);\n window.removeEventListener('touchend', this.onDragEnd);\n };\n\n private getResetDurationMs(): number {\n const resetDuration = getComputedStyle(this).getPropertyValue(\n '--slide-button-reset-duration'\n );\n return parseFloat(resetDuration) * 1000;\n }\n\n private completeSlide() {\n /**\n * Emitted when the slide action is completed (handle dragged past the\n * @fires {ObcSlideButtonSlideEvent} slide - threshold or activated via keyboard).\n */\n this.dispatchEvent(new CustomEvent('slide', {detail: {completed: true}}));\n\n if (this.autoDisable) {\n setTimeout(() => {\n this.disabled = true;\n this.requestUpdate();\n }, this.getResetDurationMs());\n }\n }\n\n private handleKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n e.preventDefault();\n if (this.disabled) return;\n this.completeSlide();\n this.playKeyboardFeedback();\n };\n\n private keyboardFeedbackTimeouts: ReturnType<typeof setTimeout>[] = [];\n\n private playKeyboardFeedback() {\n this.keyboardFeedbackTimeouts.forEach(clearTimeout);\n this.keyboardFeedbackTimeouts = [];\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n this.dragOffset = this.trackWidth - this.buttonWidth;\n this.animatingBack = true;\n this.requestUpdate();\n const durationMs = this.getResetDurationMs();\n this.keyboardFeedbackTimeouts.push(\n setTimeout(() => {\n this.dragOffset = 0;\n this.requestUpdate();\n this.keyboardFeedbackTimeouts.push(\n setTimeout(() => {\n this.animatingBack = false;\n this.requestUpdate();\n }, durationMs)\n );\n }, durationMs)\n );\n }\n\n private getButtonStyle() {\n if (!this.dragging && !this.animatingBack) return '';\n\n const maxOffset = this.trackWidth - this.buttonWidth + 1;\n let left = Math.max(-1, this.dragOffset - 1);\n left = Math.min(left, maxOffset - 1);\n\n return `left: ${left}px;`;\n }\n\n override firstUpdated() {\n const resizeObserver = new ResizeObserver(() => {\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n });\n if (this.visualContainerRef)\n resizeObserver.observe(this.visualContainerRef);\n if (this.buttonRef) resizeObserver.observe(this.buttonRef);\n }\n\n override render() {\n const containerClasses = {\n 'slide-button-container': true,\n dragging: this.dragging,\n 'animating-back': this.animatingBack,\n disabled: this.disabled,\n 'hug-content': this.hugContent,\n };\n\n const visualClasses = {\n 'visual-container': true,\n };\n\n const buttonClasses = {\n 'slide-button': true,\n 'has-leading-icon': this.hasLeadingIcon,\n };\n\n const forwardedAriaLabel = this.getAttribute('aria-label') ?? undefined;\n\n return html`\n <div class=${classMap(containerClasses)}>\n <div class=${classMap(visualClasses)}>\n <div\n class=\"button-touch-target\"\n style=${this.getButtonStyle()}\n role=\"button\"\n tabindex=${this.disabled ? '-1' : '0'}\n aria-disabled=${this.disabled ? 'true' : 'false'}\n aria-label=${ifDefined(forwardedAriaLabel)}\n @mousedown=${this.onDragStart}\n @touchstart=${this.onDragStart}\n @keydown=${this.handleKeydown}\n >\n <div class=${classMap(buttonClasses)}>\n <div class=\"button-content\">\n ${this.hasLeadingIcon\n ? html`\n <div class=\"leading-icon\">\n <slot name=\"leading-icon\"></slot>\n </div>\n `\n : nothing}\n <div class=\"button-label\">\n <slot name=\"label\"></slot>\n </div>\n </div>\n </div>\n </div>\n <div class=\"trailing-icon-area\">\n <obi-chevron-double-right-google\n class=\"trailing-icon\"\n aria-hidden=\"true\"\n ></obi-chevron-double-right-google>\n </div>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slide-button': ObcSlideButton;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slide-button.js","sources":["../../../src/components/slide-button/slide-button.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property, query, state} from 'lit/decorators.js';\nimport componentStyle from './slide-button.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport '../../icons/icon-chevron-double-right-google.js';\nimport {customElement} from '../../decorator.js';\n\nexport type ObcSlideButtonSlideEvent = CustomEvent<{completed: boolean}>;\n\n/**\n * `<obc-slide-button>` – A slide-to-confirm button that requires users to drag the button to the end of a track to trigger an action.\n *\n * Appears as a horizontal button with a draggable handle. The user must slide the handle to the right to complete the action, helping prevent accidental activations. Commonly used for critical or irreversible actions where explicit user intent is required (e.g., \"Delete\", \"Confirm\", \"Unlock\").\n *\n * ---\n *\n * ### Features\n * - **Slide-to-activate interaction:** Requires a deliberate sliding gesture to trigger the action, reducing accidental clicks.\n * - **Disabled state:** Can be disabled to prevent interaction (`disabled` property).\n * - **Leading icon (optional):** Supports a leading icon via the `leading-icon` slot, controlled by the `hasLeadingIcon` property.\n * - **Custom label:** Label text is provided via the `label` slot.\n * - **Auto-disable option:** When `autoDisable` is true, the button disables itself after a successful slide, preventing repeated actions.\n * - **Hug content:** The `hugContent` property allows the button to shrink to fit its content, rather than stretching to full width.\n * - **Visual feedback:** Provides animated feedback when sliding and snapping back if not completed.\n * - **Trailing icon:** Always displays a trailing double-chevron icon to indicate sliding direction.\n * - **Keyboard accessible:** The handle is focusable; `Enter` or `Space` triggers the action (with the same `slide` event and `autoDisable` behavior as a completed drag).\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-slide-button` for actions that require extra confirmation or where accidental activation could have significant consequences. Typical scenarios include confirming deletions, submitting irreversible forms, or unlocking sensitive features. Avoid using for routine or low-risk actions where a standard button suffices.\n *\n * - The sliding gesture provides a clear affordance for intentional actions.\n * - If you want the button to automatically disable after use (e.g., to prevent double submissions), set `autoDisable` to true.\n * - For best usability, keep the label concise and action-oriented (e.g., \"Slide to confirm\", \"Slide to delete\").\n * - The leading icon is optional and can be omitted for a simpler appearance.\n * - The button will snap back if the slide is not completed past the threshold.\n * - Only one slide button should be used for a given action to avoid confusion.\n * - Keyboard users activate with `Enter`/`Space` (single press — Tab + activation is considered deliberate). Provide `aria-label` on the host if the slotted label is not descriptive on its own (`aria-labelledby` is not supported — ID references cannot cross the shadow boundary).\n *\n * **TODO(designer):** Confirm if there are recommended minimum/maximum label lengths or if there are accessibility guidelines for color contrast and drag affordance.\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * | -------------- | --------------------- | --------------------------------------------- |\n * | leading-icon | `hasLeadingIcon` true | Icon at the start of the button (optional) |\n * | label | Always | Main label text for the button |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `disabled` (boolean): Disables the button and prevents interaction. When true, the button is visually muted and cannot be slid.\n * - `hasLeadingIcon` (boolean): Controls whether the leading icon slot is shown. Set to false to hide the icon area.\n * - `hugContent` (boolean): If true, the button shrinks to fit its content instead of stretching to full width.\n * - `autoDisable` (boolean): When true, the button automatically disables itself after a successful slide action.\n *\n * ---\n *\n * ### Events\n * - `slide` – Fired when the slide action is completed (i.e., the handle is dragged past the threshold). The event detail contains `{completed: true}`.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-slide-button autoDisable>\n * <obi-placeholder slot=\"leading-icon\"></obi-placeholder>\n * <span slot=\"label\">Slide to confirm</span>\n * </obc-slide-button>\n * ```\n * In this example, the button displays a leading icon and a label. After sliding to the end, it disables itself automatically.\n *\n * @slot leading-icon - The icon to display at the start of the button content (shown when `hasLeadingIcon` is true).\n * @slot label - The label text to display in the button.\n * @fires {ObcSlideButtonSlideEvent} slide - Emitted when the slide action is completed.\n * @experimental\n */\n@customElement('obc-slide-button')\nexport class ObcSlideButton extends LitElement {\n /**\n * Whether the slide button is disabled. When true, the button cannot be interacted with and appears visually muted.\n */\n @property({type: Boolean}) disabled = false;\n\n /**\n * Whether to show the leading icon slot. Set to true to show the icon area at the start of the button.\n */\n @property({type: Boolean}) hasLeadingIcon = false;\n\n /**\n * Whether the button should hug its content. When true, the button width shrinks to fit its content instead of stretching to fill the container.\n */\n @property({type: Boolean}) hugContent = false;\n\n /**\n * Whether to automatically disable the button after a successful slide. When true, the button disables itself after the slide action completes.\n */\n @property({type: Boolean}) autoDisable = false;\n\n @state() private dragging = false;\n @state() private animatingBack = false;\n\n private dragStartX = 0;\n private dragCurrentX = 0;\n private dragOffset = 0;\n private trackWidth = 0;\n private buttonWidth = 0;\n private slideThreshold = 0.8;\n\n @query('.slide-button')\n private buttonRef?: HTMLElement;\n\n @query('.visual-container')\n private visualContainerRef?: HTMLElement;\n\n private onDragStart = (e: MouseEvent | TouchEvent) => {\n if (this.disabled) return;\n\n this.dragging = true;\n if (e instanceof MouseEvent) {\n this.dragStartX = e.clientX;\n } else {\n this.dragStartX = e.touches[0].clientX;\n }\n this.dragCurrentX = this.dragStartX;\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n\n window.addEventListener('mousemove', this.onDragMove);\n window.addEventListener('touchmove', this.onDragMove, {passive: false});\n window.addEventListener('mouseup', this.onDragEnd);\n window.addEventListener('touchend', this.onDragEnd);\n };\n\n private onDragMove = (e: MouseEvent | TouchEvent) => {\n if (!this.dragging) return;\n\n let clientX;\n if (e instanceof MouseEvent) {\n clientX = e.clientX;\n } else {\n clientX = e.touches[0].clientX;\n e.preventDefault();\n }\n\n this.dragCurrentX = clientX;\n this.dragOffset = this.dragCurrentX - this.dragStartX;\n this.requestUpdate();\n };\n\n private onDragEnd = () => {\n if (!this.dragging) return;\n\n this.dragging = false;\n this.animatingBack = true;\n\n const maxOffset = this.trackWidth - this.buttonWidth;\n const dragProgress = Math.max(0, this.dragOffset) / maxOffset;\n\n if (dragProgress >= this.slideThreshold) {\n this.completeSlide();\n }\n\n this.dragOffset = 0;\n this.requestUpdate();\n\n setTimeout(() => {\n this.animatingBack = false;\n this.requestUpdate();\n }, this.getResetDurationMs());\n\n window.removeEventListener('mousemove', this.onDragMove);\n window.removeEventListener('touchmove', this.onDragMove);\n window.removeEventListener('mouseup', this.onDragEnd);\n window.removeEventListener('touchend', this.onDragEnd);\n };\n\n private getResetDurationMs(): number {\n const resetDuration = getComputedStyle(this).getPropertyValue(\n '--slide-button-reset-duration'\n );\n return parseFloat(resetDuration) * 1000;\n }\n\n private completeSlide() {\n /**\n * Emitted when the slide action is completed (handle dragged past the\n * threshold or activated via keyboard).\n * @fires slide\n */\n this.dispatchEvent(new CustomEvent('slide', {detail: {completed: true}}));\n\n if (this.autoDisable) {\n setTimeout(() => {\n this.disabled = true;\n this.requestUpdate();\n }, this.getResetDurationMs());\n }\n }\n\n private handleKeydown = (e: KeyboardEvent) => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n e.preventDefault();\n if (this.disabled) return;\n this.completeSlide();\n this.playKeyboardFeedback();\n };\n\n private keyboardFeedbackTimeouts: ReturnType<typeof setTimeout>[] = [];\n\n private playKeyboardFeedback() {\n this.keyboardFeedbackTimeouts.forEach(clearTimeout);\n this.keyboardFeedbackTimeouts = [];\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n this.dragOffset = this.trackWidth - this.buttonWidth;\n this.animatingBack = true;\n this.requestUpdate();\n const durationMs = this.getResetDurationMs();\n this.keyboardFeedbackTimeouts.push(\n setTimeout(() => {\n this.dragOffset = 0;\n this.requestUpdate();\n this.keyboardFeedbackTimeouts.push(\n setTimeout(() => {\n this.animatingBack = false;\n this.requestUpdate();\n }, durationMs)\n );\n }, durationMs)\n );\n }\n\n private getButtonStyle() {\n if (!this.dragging && !this.animatingBack) return '';\n\n const maxOffset = this.trackWidth - this.buttonWidth + 1;\n let left = Math.max(-1, this.dragOffset - 1);\n left = Math.min(left, maxOffset - 1);\n\n return `left: ${left}px;`;\n }\n\n override firstUpdated() {\n const resizeObserver = new ResizeObserver(() => {\n this.trackWidth = this.visualContainerRef?.offsetWidth || 0;\n this.buttonWidth = this.buttonRef?.offsetWidth || 0;\n });\n if (this.visualContainerRef)\n resizeObserver.observe(this.visualContainerRef);\n if (this.buttonRef) resizeObserver.observe(this.buttonRef);\n }\n\n override render() {\n const containerClasses = {\n 'slide-button-container': true,\n dragging: this.dragging,\n 'animating-back': this.animatingBack,\n disabled: this.disabled,\n 'hug-content': this.hugContent,\n };\n\n const visualClasses = {\n 'visual-container': true,\n };\n\n const buttonClasses = {\n 'slide-button': true,\n 'has-leading-icon': this.hasLeadingIcon,\n };\n\n const forwardedAriaLabel = this.getAttribute('aria-label') ?? undefined;\n\n return html`\n <div class=${classMap(containerClasses)}>\n <div class=${classMap(visualClasses)}>\n <div\n class=\"button-touch-target\"\n style=${this.getButtonStyle()}\n role=\"button\"\n tabindex=${this.disabled ? '-1' : '0'}\n aria-disabled=${this.disabled ? 'true' : 'false'}\n aria-label=${ifDefined(forwardedAriaLabel)}\n @mousedown=${this.onDragStart}\n @touchstart=${this.onDragStart}\n @keydown=${this.handleKeydown}\n >\n <div class=${classMap(buttonClasses)}>\n <div class=\"button-content\">\n ${this.hasLeadingIcon\n ? html`\n <div class=\"leading-icon\">\n <slot name=\"leading-icon\"></slot>\n </div>\n `\n : nothing}\n <div class=\"button-label\">\n <slot name=\"label\"></slot>\n </div>\n </div>\n </div>\n </div>\n <div class=\"trailing-icon-area\">\n <obi-chevron-double-right-google\n class=\"trailing-icon\"\n aria-hidden=\"true\"\n ></obi-chevron-double-right-google>\n </div>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slide-button': ObcSlideButton;\n }\n}\n"],"names":[],"mappings":"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"}
|
|
@@ -205,13 +205,13 @@ export declare class ObcSlider extends LitElement {
|
|
|
205
205
|
* Fires the `value` event with the new value.
|
|
206
206
|
*
|
|
207
207
|
* @param value - The new value to set.
|
|
208
|
-
* @fires value
|
|
208
|
+
* @fires value
|
|
209
209
|
*/
|
|
210
210
|
onInput(value: number): void;
|
|
211
211
|
/**
|
|
212
212
|
* Fires the `change` event with the current value.
|
|
213
213
|
*
|
|
214
|
-
* @fires change
|
|
214
|
+
* @fires change
|
|
215
215
|
*/
|
|
216
216
|
private fireChangeEvent;
|
|
217
217
|
/**
|
|
@@ -67,7 +67,7 @@ let ObcSlider = class extends LitElement {
|
|
|
67
67
|
* Fires the `value` event with the new value.
|
|
68
68
|
*
|
|
69
69
|
* @param value - The new value to set.
|
|
70
|
-
* @fires value
|
|
70
|
+
* @fires value
|
|
71
71
|
*/
|
|
72
72
|
onInput(value) {
|
|
73
73
|
this.value = value;
|
|
@@ -76,7 +76,7 @@ let ObcSlider = class extends LitElement {
|
|
|
76
76
|
/**
|
|
77
77
|
* Fires the `change` event with the current value.
|
|
78
78
|
*
|
|
79
|
-
* @fires change
|
|
79
|
+
* @fires change
|
|
80
80
|
*/
|
|
81
81
|
fireChangeEvent() {
|
|
82
82
|
this.dispatchEvent(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"slider.js","sources":["../../../src/components/slider/slider.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport {styleMap} from 'lit/directives/style-map.js';\nimport componentStyle from './slider.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 of slider visual and interaction variants.\n *\n * - `normal`: Standard slider appearance and interaction.\n * - `enhanced`: Visually prominent slider with increased track and thumb size for easier manipulation.\n * - `no-input`: Read-only display; disables user input and interaction.\n */\nexport enum ObcSliderVariant {\n Normal = 'normal',\n Enhanced = 'enhanced',\n NoInput = 'no-input',\n}\n\n/**\n * Custom event type for slider value changes.\n * The event detail contains the new numeric value.\n */\nexport type ObcSliderValueEvent = CustomEvent<number>;\n\n/**\n * Custom event type for slider change event (fired after user interaction completes).\n * The event detail contains the new numeric value.\n */\nexport type ObcSliderChangeEvent = CustomEvent<number>;\n\n/**\n * `<obc-slider>` – A horizontal slider component for selecting a numeric value within a defined range.\n *\n * Provides a visual and interactive way for users to adjust values such as volume, brightness, or other continuous settings. The slider supports optional step increments, left/right icon buttons for quick adjustments, and can be configured for read-only display or enhanced visual prominence.\n *\n * Appears as a horizontal track with a draggable thumb, and may include optional icon buttons on either side for increment/decrement actions. The component can be used for both direct manipulation (dragging the thumb) and discrete changes (via buttons).\n *\n * ---\n *\n * ### Features\n * - **Variants:**\n * - **Normal:** Standard slider with a slim track and thumb.\n * - **Enhanced:** Larger track and thumb for improved accessibility and visual emphasis.\n * - **No Input:** Read-only mode; disables all user interaction and presents the current value visually.\n * - **Value Range:** Supports configurable `min`, `max`, and `step` properties for precise control over allowed values.\n * - **Step Buttons:** Optional left and right icon buttons allow users to increment or decrement the value by a defined step (`stepClick`).\n * - **Icons:** Custom icons can be slotted into the left and right button positions for contextual meaning (e.g., `<obi-arrow></obi-arrow>, <obi-placeholder></obi-placeholder>`).\n * - **Seeking:** When `allowSeeking` is enabled, users can click or drag along the track to set the value, with smooth animated transitions based on `seekingSpeed`.\n * - **Hug Container:** The `hugcontainer` attribute removes spacing between the slider and its icon buttons, allowing for a compact layout.\n * - **Accessibility:** Underlying input is a native `<input type=\"range\">` for keyboard and screen reader support.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-slider` when you need users to select or adjust a value within a continuous or stepped range, such as for volume, brightness, or similar controls. The enhanced variant is suitable for scenarios where the slider is a primary control or needs to be more visually prominent. The no-input variant is ideal for displaying a value without allowing user changes.\n *\n * - For discrete, step-based changes, provide `step` and/or `stepClick` values.\n * - Use left/right icons to clarify the meaning of the adjustment (e.g., low/high, decrease/increase).\n * - Enable `allowSeeking` for scenarios where users should be able to jump to a specific value by clicking the track.\n * - Use `hugcontainer` when the slider should visually connect tightly with its icon buttons.\n *\n * **TODO(designer):** Clarify recommended use cases for each variant and when to use `allowSeeking` vs. standard interaction.\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-------------|---------------------------|--------------------------------------------|\n * | icon-left | `hasLeftIcon` is true | Icon/button for decrement action |\n * | icon-right | `hasRightIcon` is true | Icon/button for increment action |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `value` (number): Current slider value. Updates as the user interacts.\n * - `min` (number): Minimum allowed value (default: 0).\n * - `max` (number): Maximum allowed value (default: 100).\n * - `step` (number): Step granularity for value changes (optional).\n * - `stepClick` (number): Amount to increment/decrement when clicking icon buttons (default: 10).\n * - `variant` (ObcSliderVariant): Visual/interaction style (`normal`, `enhanced`, `no-input`). Default: `normal`.\n * - `hasLeftIcon`/`hasRightIcon` (boolean): Show icon button on left/right.\n * - `allowSeeking` (boolean): Enables animated seeking to clicked value on the track.\n * - `seekingSpeed` (number): Animation speed for seeking (default: 1/3; higher is faster).\n * - `hugcontainer` (attribute): Removes spacing between slider and icon buttons for a compact layout.\n *\n * ---\n *\n * ### Events\n * - `value` – Fired continuously when the slider value changes during user interaction or programmatically. The event detail contains the new value as a number.\n * - `change` – Fired only after user interaction completes (mouse/touch release or button click). The event detail contains the new value as a number.\n *\n * ---\n *\n * ### Best Practices & Constraints\n * - Only use `no-input` variant for read-only display; interactive controls should use `normal` or `enhanced`.\n * - For accessibility, ensure the slider has a visible label or context.\n * - Use step values that make sense for the range (e.g., avoid step=0.01 for a 0–10 range unless fine granularity is needed).\n * - When using icon buttons, provide icons that clearly indicate their function.\n * - The slider is horizontal only; for vertical sliders, use a different component.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-slider\n * value=\"40\"\n * min=\"0\"\n * max=\"100\"\n * step=\"10\"\n * haslefticon\n * hasrighticon\n * variant=\"enhanced\"\n * >\n * <obi-arrow slot=\"icon-left\"></obi-arrow>\n * <obi-arrow slot=\"icon-right\"></obi-arrow>\n * </obc-slider>\n * ```\n *\n * In this example, the slider allows selection from 0 to 100 in steps of 10, with left/right arrow icons for quick adjustments.\n *\n * @slot icon-left - Slot for the left icon button (shown when `hasLeftIcon` is true)\n * @slot icon-right - Slot for the right icon button (shown when `hasRightIcon` is true)\n * @attr hugcontainer - If set, the slider will not have any spacing between the slider icons and the container\n * @fires {ObcSliderValueEvent} value - Fired when the value is changed\n * @fires {ObcSliderChangeEvent} change - Fired when user interaction completes; dispatched on release even if the value did not change\n * @stable\n */\n@customElement('obc-slider')\nexport class ObcSlider extends LitElement {\n /**\n * The current value of the slider.\n *\n * Updates as the user drags the thumb, clicks the track (if `allowSeeking`), or uses the increment/decrement buttons.\n */\n @property({type: Number}) value = 50;\n\n /**\n * The minimum allowed value for the slider.\n *\n * Default is 0.\n */\n @property({type: Number}) min = 0;\n\n /**\n * The maximum allowed value for the slider.\n *\n * Default is 100.\n */\n @property({type: Number}) max = 100;\n\n /**\n * The step granularity for slider value changes.\n *\n * If set, the slider will snap to multiples of this value between min and max.\n * Optional; if not set, the slider is continuous.\n */\n @property({type: Number}) step: number | undefined;\n\n /**\n * The amount to increment or decrement the value when clicking the left/right icon buttons.\n *\n * Default is 10.\n * @availableWhen hasLeftIcon==true || hasRightIcon==true\n */\n @property({type: Number}) stepClick = 10;\n\n /**\n * The visual and interaction style of the slider.\n *\n * - `normal`: Standard appearance.\n * - `enhanced`: Larger track and thumb for emphasis.\n * - `no-input`: Read-only; disables all user input.\n *\n * Default is `normal`.\n */\n @property({type: String}) variant: ObcSliderVariant = ObcSliderVariant.Normal;\n\n /**\n * Whether to display a left icon button for decrementing the value.\n *\n * When true, the `icon-left` slot is rendered as a button.\n */\n @property({type: Boolean}) hasLeftIcon = false;\n\n /**\n * Whether to display a right icon button for incrementing the value.\n *\n * When true, the `icon-right` slot is rendered as a button.\n */\n @property({type: Boolean}) hasRightIcon = false;\n\n /**\n * Enables animated seeking: clicking or dragging along the track will set the value to the clicked position, animating smoothly.\n *\n * Default is false.\n * @availableWhen variant!=no-input && disabled==false\n */\n @property({type: Boolean}) allowSeeking = false;\n\n /**\n * The speed of the smooth animation that moves the value to the clicked position (used when `allowSeeking` is false).\n *\n * Expressed as the inverse of seconds to go from min to max (e.g., 1/3 means 3 seconds for full range).\n * Default is 1/3.\n * @availableWhen allowSeeking==false && variant!=no-input && disabled==false\n */\n @property({type: Number}) seekingSpeed = 1 / 3;\n\n @property({type: Boolean}) disabled = false;\n\n private get ratio(): number {\n const range = this.max - this.min;\n if (!Number.isFinite(range) || range <= 0) return 0;\n const ratio = (this.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 isTouchActive = false;\n private targetValue = 0;\n private isDragging = false;\n private animationStartTime: number | null = null;\n private animationStartValue: number = 0;\n\n /**\n * Handles input changes from the slider or buttons.\n * Fires the `value` event with the new value.\n *\n * @param value - The new value to set.\n * @fires value - Fired when the value is changed\n */\n onInput(value: number) {\n this.value = value;\n this.dispatchEvent(new CustomEvent('value', {detail: this.value}));\n }\n\n /**\n * Fires the `change` event with the current value.\n *\n * @fires change - Fired when user interaction completes; dispatched on release even if the value did not change\n */\n private fireChangeEvent() {\n this.dispatchEvent(\n new CustomEvent('change', {detail: this.value}) as ObcSliderChangeEvent\n );\n }\n\n /**\n * Decrements the value by `stepClick` when the left icon button is clicked.\n */\n onReduceClick() {\n if (this.disabled) return;\n this.onInput(Math.max(this.value - this.stepClick, this.min));\n this.fireChangeEvent();\n }\n\n /**\n * Increments the value by `stepClick` when the right icon button is clicked.\n */\n onIncreaseClick() {\n if (this.disabled) return;\n this.onInput(Math.min(this.value + this.stepClick, this.max));\n this.fireChangeEvent();\n }\n\n private get slider(): HTMLInputElement {\n return this.renderRoot.querySelector('input[type=\"range\"]')!;\n }\n\n private isClickingThumb(e: MouseEvent | TouchEvent) {\n const rect = this.slider.getBoundingClientRect();\n const left = rect.left + 24;\n const width = rect.width - 48;\n const thumbWidth = 48;\n const ratioValue = this.ratio;\n const thumbCenter = left + width * ratioValue;\n\n let clientX: number;\n if ('touches' in e) {\n clientX = e.touches[0].clientX;\n } else {\n clientX = e.clientX;\n }\n\n const isNearThumb = Math.abs(clientX - thumbCenter) <= thumbWidth / 2;\n return isNearThumb;\n }\n\n private onMouseDown(e: MouseEvent) {\n if (this.variant === ObcSliderVariant.NoInput || this.disabled) return;\n if (this.isClickingThumb(e)) return;\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 onTouchStart(e: TouchEvent) {\n if (this.variant === ObcSliderVariant.NoInput || this.disabled) return;\n if (this.isClickingThumb(e)) return;\n this.isTouchActive = true;\n this.updateTargetValue(e);\n e.preventDefault();\n window.addEventListener('touchmove', this.onWindowTouchMove, {\n passive: false,\n });\n window.addEventListener('touchend', this.onWindowTouchEnd);\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 onWindowTouchMove = (e: TouchEvent) => {\n this.onTouchMove(e);\n };\n\n private onWindowTouchEnd = () => {\n this.onTouchEnd();\n };\n\n private onMouseMove(e: MouseEvent) {\n if (this.isMouseDown) {\n this.updateTargetValue(e);\n }\n }\n\n private onTouchMove(e: TouchEvent) {\n if (this.isTouchActive) {\n this.updateTargetValue(e);\n }\n }\n\n private onMouseUp() {\n this.isMouseDown = false;\n window.removeEventListener('mousemove', this.onWindowMouseMove);\n window.removeEventListener('mouseup', this.onWindowMouseUp);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private onTouchEnd() {\n this.isTouchActive = false;\n window.removeEventListener('touchmove', this.onWindowTouchMove);\n window.removeEventListener('touchend', this.onWindowTouchEnd);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private updateTargetValue(e: MouseEvent | TouchEvent) {\n const rect = this.slider.getBoundingClientRect();\n const left = rect.left + 24;\n const width = rect.width - 48;\n const x = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;\n const percent = (x - left) / width;\n const min = parseFloat(this.slider.min);\n const max = parseFloat(this.slider.max);\n const unroundedValue = min + (max - min) * percent;\n if (this.step) {\n this.targetValue = Math.round(unroundedValue / this.step) * this.step;\n } else {\n this.targetValue = unroundedValue;\n }\n }\n\n private startAnimation() {\n this.isDragging = this.allowSeeking;\n this.animationStartTime = performance.now();\n this.animationStartValue = parseFloat(this.slider.value);\n const min = parseFloat(this.slider.min);\n const max = parseFloat(this.slider.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 if (parseFloat(this.slider.value) !== nextValue) {\n this.slider.value = String(nextValue);\n this.slider.dispatchEvent(new Event('input'));\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 || this.isTouchActive) {\n // If mouse or touch is still active, wait for new target\n this.animationStartTime = performance.now();\n this.animationStartValue = parseFloat(this.slider.value);\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 override render() {\n return html`\n ${this.hasLeftIcon\n ? html` <obc-icon-button\n ?disabled=${this.disabled}\n @click=${this.onReduceClick}\n variant=\"normal\"\n >\n <slot name=\"icon-left\"></slot>\n </obc-icon-button>`\n : null}\n <div\n class=${classMap({\n wrapper: true,\n [this.variant]: true,\n disabled: this.disabled,\n })}\n style=${styleMap({\n '--_ratio': String(this.ratio),\n })}\n >\n <div class=\"track\"></div>\n <input\n type=\"range\"\n min=${this.min}\n max=${this.max}\n step=${ifDefined(this.step)}\n .value=${this.value.toString()}\n ?disabled=${this.variant === ObcSliderVariant.NoInput ||\n this.disabled}\n class=\"slider\"\n @input=${(event: Event) => {\n this.value = Number((event.target as HTMLInputElement).value);\n this.dispatchEvent(new CustomEvent('value', {detail: this.value}));\n }}\n @change=${() => {\n this.fireChangeEvent();\n }}\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n />\n <div\n class=\"interactive-track-hover\"\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n ></div>\n <div\n class=\"container-hover\"\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n ></div>\n <div class=\"interactive-track\"></div>\n <div class=\"thumb\"></div>\n </div>\n ${this.hasRightIcon\n ? html`<obc-icon-button\n ?disabled=${this.disabled}\n @click=${this.onIncreaseClick}\n variant=\"normal\"\n >\n <slot name=\"icon-right\"></slot>\n </obc-icon-button>`\n : null}\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slider': ObcSlider;\n }\n}\n"],"names":["ObcSliderVariant"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"slider.js","sources":["../../../src/components/slider/slider.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS} from 'lit';\nimport {property} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport {styleMap} from 'lit/directives/style-map.js';\nimport componentStyle from './slider.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 of slider visual and interaction variants.\n *\n * - `normal`: Standard slider appearance and interaction.\n * - `enhanced`: Visually prominent slider with increased track and thumb size for easier manipulation.\n * - `no-input`: Read-only display; disables user input and interaction.\n */\nexport enum ObcSliderVariant {\n Normal = 'normal',\n Enhanced = 'enhanced',\n NoInput = 'no-input',\n}\n\n/**\n * Custom event type for slider value changes.\n * The event detail contains the new numeric value.\n */\nexport type ObcSliderValueEvent = CustomEvent<number>;\n\n/**\n * Custom event type for slider change event (fired after user interaction completes).\n * The event detail contains the new numeric value.\n */\nexport type ObcSliderChangeEvent = CustomEvent<number>;\n\n/**\n * `<obc-slider>` – A horizontal slider component for selecting a numeric value within a defined range.\n *\n * Provides a visual and interactive way for users to adjust values such as volume, brightness, or other continuous settings. The slider supports optional step increments, left/right icon buttons for quick adjustments, and can be configured for read-only display or enhanced visual prominence.\n *\n * Appears as a horizontal track with a draggable thumb, and may include optional icon buttons on either side for increment/decrement actions. The component can be used for both direct manipulation (dragging the thumb) and discrete changes (via buttons).\n *\n * ---\n *\n * ### Features\n * - **Variants:**\n * - **Normal:** Standard slider with a slim track and thumb.\n * - **Enhanced:** Larger track and thumb for improved accessibility and visual emphasis.\n * - **No Input:** Read-only mode; disables all user interaction and presents the current value visually.\n * - **Value Range:** Supports configurable `min`, `max`, and `step` properties for precise control over allowed values.\n * - **Step Buttons:** Optional left and right icon buttons allow users to increment or decrement the value by a defined step (`stepClick`).\n * - **Icons:** Custom icons can be slotted into the left and right button positions for contextual meaning (e.g., `<obi-arrow></obi-arrow>, <obi-placeholder></obi-placeholder>`).\n * - **Seeking:** When `allowSeeking` is enabled, users can click or drag along the track to set the value, with smooth animated transitions based on `seekingSpeed`.\n * - **Hug Container:** The `hugcontainer` attribute removes spacing between the slider and its icon buttons, allowing for a compact layout.\n * - **Accessibility:** Underlying input is a native `<input type=\"range\">` for keyboard and screen reader support.\n *\n * ---\n *\n * ### Usage Guidelines\n * Use `obc-slider` when you need users to select or adjust a value within a continuous or stepped range, such as for volume, brightness, or similar controls. The enhanced variant is suitable for scenarios where the slider is a primary control or needs to be more visually prominent. The no-input variant is ideal for displaying a value without allowing user changes.\n *\n * - For discrete, step-based changes, provide `step` and/or `stepClick` values.\n * - Use left/right icons to clarify the meaning of the adjustment (e.g., low/high, decrease/increase).\n * - Enable `allowSeeking` for scenarios where users should be able to jump to a specific value by clicking the track.\n * - Use `hugcontainer` when the slider should visually connect tightly with its icon buttons.\n *\n * **TODO(designer):** Clarify recommended use cases for each variant and when to use `allowSeeking` vs. standard interaction.\n *\n * ---\n *\n * ### Slots\n *\n * | Slot Name | Renders When... | Purpose |\n * |-------------|---------------------------|--------------------------------------------|\n * | icon-left | `hasLeftIcon` is true | Icon/button for decrement action |\n * | icon-right | `hasRightIcon` is true | Icon/button for increment action |\n *\n * ---\n *\n * ### Properties and Attributes\n * - `value` (number): Current slider value. Updates as the user interacts.\n * - `min` (number): Minimum allowed value (default: 0).\n * - `max` (number): Maximum allowed value (default: 100).\n * - `step` (number): Step granularity for value changes (optional).\n * - `stepClick` (number): Amount to increment/decrement when clicking icon buttons (default: 10).\n * - `variant` (ObcSliderVariant): Visual/interaction style (`normal`, `enhanced`, `no-input`). Default: `normal`.\n * - `hasLeftIcon`/`hasRightIcon` (boolean): Show icon button on left/right.\n * - `allowSeeking` (boolean): Enables animated seeking to clicked value on the track.\n * - `seekingSpeed` (number): Animation speed for seeking (default: 1/3; higher is faster).\n * - `hugcontainer` (attribute): Removes spacing between slider and icon buttons for a compact layout.\n *\n * ---\n *\n * ### Events\n * - `value` – Fired continuously when the slider value changes during user interaction or programmatically. The event detail contains the new value as a number.\n * - `change` – Fired only after user interaction completes (mouse/touch release or button click). The event detail contains the new value as a number.\n *\n * ---\n *\n * ### Best Practices & Constraints\n * - Only use `no-input` variant for read-only display; interactive controls should use `normal` or `enhanced`.\n * - For accessibility, ensure the slider has a visible label or context.\n * - Use step values that make sense for the range (e.g., avoid step=0.01 for a 0–10 range unless fine granularity is needed).\n * - When using icon buttons, provide icons that clearly indicate their function.\n * - The slider is horizontal only; for vertical sliders, use a different component.\n *\n * ---\n *\n * ### Example\n *\n * ```html\n * <obc-slider\n * value=\"40\"\n * min=\"0\"\n * max=\"100\"\n * step=\"10\"\n * haslefticon\n * hasrighticon\n * variant=\"enhanced\"\n * >\n * <obi-arrow slot=\"icon-left\"></obi-arrow>\n * <obi-arrow slot=\"icon-right\"></obi-arrow>\n * </obc-slider>\n * ```\n *\n * In this example, the slider allows selection from 0 to 100 in steps of 10, with left/right arrow icons for quick adjustments.\n *\n * @slot icon-left - Slot for the left icon button (shown when `hasLeftIcon` is true)\n * @slot icon-right - Slot for the right icon button (shown when `hasRightIcon` is true)\n * @attr hugcontainer - If set, the slider will not have any spacing between the slider icons and the container\n * @fires {ObcSliderValueEvent} value - Fired when the value is changed\n * @fires {ObcSliderChangeEvent} change - Fired when user interaction completes; dispatched on release even if the value did not change\n * @stable\n */\n@customElement('obc-slider')\nexport class ObcSlider extends LitElement {\n /**\n * The current value of the slider.\n *\n * Updates as the user drags the thumb, clicks the track (if `allowSeeking`), or uses the increment/decrement buttons.\n */\n @property({type: Number}) value = 50;\n\n /**\n * The minimum allowed value for the slider.\n *\n * Default is 0.\n */\n @property({type: Number}) min = 0;\n\n /**\n * The maximum allowed value for the slider.\n *\n * Default is 100.\n */\n @property({type: Number}) max = 100;\n\n /**\n * The step granularity for slider value changes.\n *\n * If set, the slider will snap to multiples of this value between min and max.\n * Optional; if not set, the slider is continuous.\n */\n @property({type: Number}) step: number | undefined;\n\n /**\n * The amount to increment or decrement the value when clicking the left/right icon buttons.\n *\n * Default is 10.\n * @availableWhen hasLeftIcon==true || hasRightIcon==true\n */\n @property({type: Number}) stepClick = 10;\n\n /**\n * The visual and interaction style of the slider.\n *\n * - `normal`: Standard appearance.\n * - `enhanced`: Larger track and thumb for emphasis.\n * - `no-input`: Read-only; disables all user input.\n *\n * Default is `normal`.\n */\n @property({type: String}) variant: ObcSliderVariant = ObcSliderVariant.Normal;\n\n /**\n * Whether to display a left icon button for decrementing the value.\n *\n * When true, the `icon-left` slot is rendered as a button.\n */\n @property({type: Boolean}) hasLeftIcon = false;\n\n /**\n * Whether to display a right icon button for incrementing the value.\n *\n * When true, the `icon-right` slot is rendered as a button.\n */\n @property({type: Boolean}) hasRightIcon = false;\n\n /**\n * Enables animated seeking: clicking or dragging along the track will set the value to the clicked position, animating smoothly.\n *\n * Default is false.\n * @availableWhen variant!=no-input && disabled==false\n */\n @property({type: Boolean}) allowSeeking = false;\n\n /**\n * The speed of the smooth animation that moves the value to the clicked position (used when `allowSeeking` is false).\n *\n * Expressed as the inverse of seconds to go from min to max (e.g., 1/3 means 3 seconds for full range).\n * Default is 1/3.\n * @availableWhen allowSeeking==false && variant!=no-input && disabled==false\n */\n @property({type: Number}) seekingSpeed = 1 / 3;\n\n @property({type: Boolean}) disabled = false;\n\n private get ratio(): number {\n const range = this.max - this.min;\n if (!Number.isFinite(range) || range <= 0) return 0;\n const ratio = (this.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 isTouchActive = false;\n private targetValue = 0;\n private isDragging = false;\n private animationStartTime: number | null = null;\n private animationStartValue: number = 0;\n\n /**\n * Handles input changes from the slider or buttons.\n * Fires the `value` event with the new value.\n *\n * @param value - The new value to set.\n * @fires value\n */\n onInput(value: number) {\n this.value = value;\n this.dispatchEvent(new CustomEvent('value', {detail: this.value}));\n }\n\n /**\n * Fires the `change` event with the current value.\n *\n * @fires change\n */\n private fireChangeEvent() {\n this.dispatchEvent(\n new CustomEvent('change', {detail: this.value}) as ObcSliderChangeEvent\n );\n }\n\n /**\n * Decrements the value by `stepClick` when the left icon button is clicked.\n */\n onReduceClick() {\n if (this.disabled) return;\n this.onInput(Math.max(this.value - this.stepClick, this.min));\n this.fireChangeEvent();\n }\n\n /**\n * Increments the value by `stepClick` when the right icon button is clicked.\n */\n onIncreaseClick() {\n if (this.disabled) return;\n this.onInput(Math.min(this.value + this.stepClick, this.max));\n this.fireChangeEvent();\n }\n\n private get slider(): HTMLInputElement {\n return this.renderRoot.querySelector('input[type=\"range\"]')!;\n }\n\n private isClickingThumb(e: MouseEvent | TouchEvent) {\n const rect = this.slider.getBoundingClientRect();\n const left = rect.left + 24;\n const width = rect.width - 48;\n const thumbWidth = 48;\n const ratioValue = this.ratio;\n const thumbCenter = left + width * ratioValue;\n\n let clientX: number;\n if ('touches' in e) {\n clientX = e.touches[0].clientX;\n } else {\n clientX = e.clientX;\n }\n\n const isNearThumb = Math.abs(clientX - thumbCenter) <= thumbWidth / 2;\n return isNearThumb;\n }\n\n private onMouseDown(e: MouseEvent) {\n if (this.variant === ObcSliderVariant.NoInput || this.disabled) return;\n if (this.isClickingThumb(e)) return;\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 onTouchStart(e: TouchEvent) {\n if (this.variant === ObcSliderVariant.NoInput || this.disabled) return;\n if (this.isClickingThumb(e)) return;\n this.isTouchActive = true;\n this.updateTargetValue(e);\n e.preventDefault();\n window.addEventListener('touchmove', this.onWindowTouchMove, {\n passive: false,\n });\n window.addEventListener('touchend', this.onWindowTouchEnd);\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 onWindowTouchMove = (e: TouchEvent) => {\n this.onTouchMove(e);\n };\n\n private onWindowTouchEnd = () => {\n this.onTouchEnd();\n };\n\n private onMouseMove(e: MouseEvent) {\n if (this.isMouseDown) {\n this.updateTargetValue(e);\n }\n }\n\n private onTouchMove(e: TouchEvent) {\n if (this.isTouchActive) {\n this.updateTargetValue(e);\n }\n }\n\n private onMouseUp() {\n this.isMouseDown = false;\n window.removeEventListener('mousemove', this.onWindowMouseMove);\n window.removeEventListener('mouseup', this.onWindowMouseUp);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private onTouchEnd() {\n this.isTouchActive = false;\n window.removeEventListener('touchmove', this.onWindowTouchMove);\n window.removeEventListener('touchend', this.onWindowTouchEnd);\n this.stopAnimation();\n this.fireChangeEvent();\n }\n\n private updateTargetValue(e: MouseEvent | TouchEvent) {\n const rect = this.slider.getBoundingClientRect();\n const left = rect.left + 24;\n const width = rect.width - 48;\n const x = e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;\n const percent = (x - left) / width;\n const min = parseFloat(this.slider.min);\n const max = parseFloat(this.slider.max);\n const unroundedValue = min + (max - min) * percent;\n if (this.step) {\n this.targetValue = Math.round(unroundedValue / this.step) * this.step;\n } else {\n this.targetValue = unroundedValue;\n }\n }\n\n private startAnimation() {\n this.isDragging = this.allowSeeking;\n this.animationStartTime = performance.now();\n this.animationStartValue = parseFloat(this.slider.value);\n const min = parseFloat(this.slider.min);\n const max = parseFloat(this.slider.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 if (parseFloat(this.slider.value) !== nextValue) {\n this.slider.value = String(nextValue);\n this.slider.dispatchEvent(new Event('input'));\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 || this.isTouchActive) {\n // If mouse or touch is still active, wait for new target\n this.animationStartTime = performance.now();\n this.animationStartValue = parseFloat(this.slider.value);\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 override render() {\n return html`\n ${this.hasLeftIcon\n ? html` <obc-icon-button\n ?disabled=${this.disabled}\n @click=${this.onReduceClick}\n variant=\"normal\"\n >\n <slot name=\"icon-left\"></slot>\n </obc-icon-button>`\n : null}\n <div\n class=${classMap({\n wrapper: true,\n [this.variant]: true,\n disabled: this.disabled,\n })}\n style=${styleMap({\n '--_ratio': String(this.ratio),\n })}\n >\n <div class=\"track\"></div>\n <input\n type=\"range\"\n min=${this.min}\n max=${this.max}\n step=${ifDefined(this.step)}\n .value=${this.value.toString()}\n ?disabled=${this.variant === ObcSliderVariant.NoInput ||\n this.disabled}\n class=\"slider\"\n @input=${(event: Event) => {\n this.value = Number((event.target as HTMLInputElement).value);\n this.dispatchEvent(new CustomEvent('value', {detail: this.value}));\n }}\n @change=${() => {\n this.fireChangeEvent();\n }}\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n />\n <div\n class=\"interactive-track-hover\"\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n ></div>\n <div\n class=\"container-hover\"\n @mousedown=${this.onMouseDown}\n @touchstart=${this.onTouchStart}\n @mousemove=${this.onMouseMove}\n @touchmove=${this.onTouchMove}\n @mouseup=${this.onMouseUp}\n @touchend=${this.onTouchEnd}\n ></div>\n <div class=\"interactive-track\"></div>\n <div class=\"thumb\"></div>\n </div>\n ${this.hasRightIcon\n ? html`<obc-icon-button\n ?disabled=${this.disabled}\n @click=${this.onIncreaseClick}\n variant=\"normal\"\n >\n <slot name=\"icon-right\"></slot>\n </obc-icon-button>`\n : null}\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-slider': ObcSlider;\n }\n}\n"],"names":["ObcSliderVariant"],"mappings":"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"}
|
|
@@ -222,13 +222,13 @@ export declare class ObcSliderDouble extends LitElement {
|
|
|
222
222
|
* Handles input changes from the slider thumbs.
|
|
223
223
|
* Updates the low and high values and emits the `value` event.
|
|
224
224
|
*
|
|
225
|
-
* @fires
|
|
225
|
+
* @fires value
|
|
226
226
|
*/
|
|
227
227
|
onInput(): void;
|
|
228
228
|
/**
|
|
229
229
|
* Fires the `change` event with the current low and high values.
|
|
230
230
|
*
|
|
231
|
-
* @fires change
|
|
231
|
+
* @fires change
|
|
232
232
|
*/
|
|
233
233
|
private fireChangeEvent;
|
|
234
234
|
private THUMB_WIDTH;
|
|
@@ -73,7 +73,7 @@ let ObcSliderDouble = class extends LitElement {
|
|
|
73
73
|
* Handles input changes from the slider thumbs.
|
|
74
74
|
* Updates the low and high values and emits the `value` event.
|
|
75
75
|
*
|
|
76
|
-
* @fires
|
|
76
|
+
* @fires value
|
|
77
77
|
*/
|
|
78
78
|
onInput() {
|
|
79
79
|
let newLow = parseFloat(this.minInput.value);
|
|
@@ -95,7 +95,7 @@ let ObcSliderDouble = class extends LitElement {
|
|
|
95
95
|
/**
|
|
96
96
|
* Fires the `change` event with the current low and high values.
|
|
97
97
|
*
|
|
98
|
-
* @fires change
|
|
98
|
+
* @fires change
|
|
99
99
|
*/
|
|
100
100
|
fireChangeEvent() {
|
|
101
101
|
this.dispatchEvent(
|
|
@@ -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":";;;;;;;;;;;;;;;;;;AAgBO,IAAK,2CAAAA,4BAAL;AACLA,0BAAA,QAAA,IAAS;AACTA,0BAAA,UAAA,IAAW;AACXA,0BAAA,SAAA,IAAU;AAHA,SAAAA;AAAA,GAAA,0BAAA,CAAA,CAAA;AAqHL,IAAM,kBAAN,cAA8B,WAAW;AAAA,EAAzC,cAAA;AAAA,UAAA,GAAA,SAAA;AAKqB,SAAA,MAAM;AAMN,SAAA,OAAO;AAMP,SAAA,MAAM;AAMN,SAAA,MAAM;AAYN,SAAA,YAAY;AASZ,SAAA,UACxB;AAMyB,SAAA,eAAe;AAEf,SAAA,WAAW;AAOZ,SAAA,eAAe,IAAI;AAKnB,SAAA,YAAY;AAKZ,SAAA,gBAAgB;AAKhB,SAAA,aAAa;AAUM,SAAA,kBAAkB;AAUlB,SAAA,mBAAmB;AAOhE,SAAA,eAAe;AAkBf,SAAQ,iBAAgC;AACxC,SAAQ,cAAc;AACtB,SAAQ,cAAc;AACtB,SAAQ,aAAa;AACrB,SAAQ,iBAAiB;AACzB,SAAQ,qBAAoC;AAC5C,SAAQ,sBAA8B;AA6CtC,SAAQ,cAAc;AACtB,SAAQ,sBAAsB;AAuF9B,SAAQ,oBAAoB,CAAC,MAAkB;AAC7C,WAAK,YAAY,CAAC;AAAA,IACpB;AAEA,SAAQ,kBAAkB,MAAM;AAC9B,WAAK,UAAA;AAAA,IACP;AAAA,EAAA;AAAA,EAjKA,IAAY,WAAmB;AAC7B,WAAO,KAAK,aAAa,KAAK,GAAG;AAAA,EACnC;AAAA,EAEA,IAAY,YAAoB;AAC9B,WAAO,KAAK,aAAa,KAAK,IAAI;AAAA,EACpC;AAAA,EAEQ,aAAa,OAAuB;AAC1C,UAAM,QAAQ,KAAK,MAAM,KAAK;AAC9B,QAAI,CAAC,OAAO,SAAS,KAAK,KAAK,SAAS,EAAG,QAAO;AAClD,UAAM,SAAS,QAAQ,KAAK,OAAO;AACnC,QAAI,CAAC,OAAO,SAAS,KAAK,EAAG,QAAO;AACpC,WAAO,KAAK,IAAI,GAAG,KAAK,IAAI,GAAG,KAAK,CAAC;AAAA,EACvC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsBA,UAAU;AACR,QAAI,SAAS,WAAW,KAAK,SAAS,KAAK;AAC3C,QAAI,UAAU,WAAW,KAAK,SAAS,KAAK;AAC5C,QAAI,SAAS,KAAK,MAAM;AACtB,eAAS,KAAK;AACd,WAAK,SAAS,QAAQ,KAAK,KAAK,SAAA;AAAA,IAClC;AACA,QAAI,UAAU,KAAK,KAAK;AACtB,gBAAU,KAAK;AACf,WAAK,SAAS,QAAQ,KAAK,IAAI,SAAA;AAAA,IACjC;AACA,SAAK,MAAM;AACX,SAAK,OAAO;AACZ,SAAK;AAAA,MACH,IAAI,YAAY,SAAS,EAAC,QAAQ,EAAC,KAAK,KAAK,KAAK,MAAM,KAAK,KAAA,GAAM;AAAA,IAAA;AAAA,EAEvE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOQ,kBAAkB;AACxB,SAAK;AAAA,MACH,IAAI,YAAY,UAAU;AAAA,QACxB,QAAQ,EAAC,KAAK,KAAK,KAAK,MAAM,KAAK,KAAA;AAAA,MAAI,CACxC;AAAA,IAAA;AAAA,EAEL;AAAA,EAKQ,cAAc,GAAe;AACnC,UAAM,OAAO,KAAK,SAAS,sBAAA;AAC3B,UAAM,OAAO,KAAK,OAAO,KAAK,cAAc,KAAK,sBAAsB;AACvE,UAAM,QAAQ,KAAK,QAAQ,KAAK;AAChC,UAAM,WAAW,EAAE,UAAU,QAAQ;AACrC,WAAO,KAAK,OAAO,KAAK,MAAM,KAAK,OAAO;AAAA,EAC5C;AAAA,EAEQ,eAAe,GAAe;AACpC,UAAM,OAAO,KAAK,SAAS,sBAAA;AAC3B,UAAM,OAAO,KAAK,OAAO,KAAK,sBAAsB;AACpD,UAAM,QAAQ,KAAK,QAAQ,KAAK;AAChC,UAAM,WAAW,EAAE,UAAU,QAAQ;AACrC,WAAO,KAAK,OAAO,KAAK,MAAM,KAAK,OAAO;AAAA,EAC5C;AAAA,EAEQ,aAAa;AACnB,UAAM,OAAO,KAAK,SAAS,sBAAA;AAC3B,UAAM,aAAa,KAAK,MAAM,KAAK;AACnC,UAAM,kBAAkB,KAAK,cAAc,KAAK;AAChD,WAAO,aAAa;AAAA,EACtB;AAAA,EAEQ,mBAAmB,GAAe;AACxC,UAAM,QAAQ,KAAK,cAAc,CAAC;AAClC,QAAI,QAAQ,KAAK,KAAK;AACpB,aAAO;AAAA,IACT;AACA,WAAO,SAAS,KAAK,MAAM,KAAK,WAAA;AAAA,EAClC;AAAA,EAEQ,mBAAmB,GAAe;AACxC,UAAM,QAAQ,KAAK,eAAe,CAAC;AACnC,QAAI,QAAQ,KAAK,MAAM;AACrB,aAAO;AAAA,IACT;AACA,WAAO,SAAS,KAAK,OAAO,KAAK,WAAA;AAAA,EACnC;AAAA,EAEQ,mBAAmB,GAAe;AACxC,UAAM,QAAQ,KAAK,cAAc,CAAC;AAClC,WAAO,SAAS,KAAK,MAAM,KAAK,eAAe;AAAA,EACjD;AAAA,EAEQ,oBAAoB,GAAe;AACzC,UAAM,QAAQ,KAAK,eAAe,CAAC;AACnC,WAAO,SAAS,KAAK,OAAO,KAAK,eAAe;AAAA,EAClD;AAAA,EAEQ,oBAAoB,GAAe;AACzC,UAAM,WAAW,KAAK,cAAc,CAAC;AACrC,UAAM,YAAY,KAAK,eAAe,CAAC;AACvC,WAAO,KAAK,IAAI,WAAW,KAAK,GAAG,KAAK,KAAK,IAAI,YAAY,KAAK,IAAI;AAAA,EACxE;AAAA,EAEQ,YAAY,GAAe;AACjC,QAAI,KAAK,YAAY,cAAkC,KAAK;AAC1D;AACF,QAAI,KAAK,mBAAmB,CAAC,GAAG;AAC9B,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,WAAW,KAAK,mBAAmB,CAAC,GAAG;AACrC,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,WAAW,KAAK,mBAAmB,CAAC,GAAG;AACrC,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,WAAW,KAAK,oBAAoB,CAAC,GAAG;AACtC,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,WAAW,KAAK,oBAAoB,CAAC,GAAG;AACtC,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB,OAAO;AACL,WAAK,iBAAiB;AACtB,WAAK,aAAa;AAAA,IACpB;AACA,SAAK,cAAc;AACnB,SAAK,kBAAkB,CAAC;AACxB,MAAE,eAAA;AACF,WAAO,iBAAiB,aAAa,KAAK,iBAAiB;AAC3D,WAAO,iBAAiB,WAAW,KAAK,eAAe;AACvD,SAAK,eAAA;AAAA,EACP;AAAA,EAUQ,YAAY,GAAe;AACjC,QAAI,KAAK,aAAa;AACpB,WAAK,kBAAkB,CAAC;AAAA,IAC1B;AAAA,EACF;AAAA,EAEQ,YAAY;AAClB,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,WAAO,oBAAoB,aAAa,KAAK,iBAAiB;AAC9D,WAAO,oBAAoB,WAAW,KAAK,eAAe;AAC1D,SAAK,cAAA;AACL,SAAK,gBAAA;AAAA,EACP;AAAA,EAEQ,kBAAkB,GAAe;AACvC,UAAM,iBAAiB,KAAK,iBACxB,KAAK,cAAc,CAAC,IACpB,KAAK,eAAe,CAAC;AACzB,QAAI,KAAK,MAAM;AACb,WAAK,cAAc,KAAK,MAAM,iBAAiB,KAAK,IAAI,IAAI,KAAK;AAAA,IACnE,OAAO;AACL,WAAK,cAAc;AAAA,IACrB;AACA,QAAI,KAAK,gBAAgB;AACvB,WAAK,cAAc,KAAK;AAAA,QACtB,KAAK;AAAA,QACL,KAAK,IAAI,KAAK,aAAa,KAAK,IAAI;AAAA,MAAA;AAAA,IAExC,OAAO;AACL,WAAK,cAAc,KAAK;AAAA,QACtB,KAAK;AAAA,QACL,KAAK,IAAI,KAAK,aAAa,KAAK,GAAG;AAAA,MAAA;AAAA,IAEvC;AAAA,EACF;AAAA,EAEQ,iBAAiB;AACvB,SAAK,aAAa,KAAK;AACvB,SAAK,qBAAqB,YAAY,IAAA;AACtC,SAAK,sBAAsB,KAAK,iBAAiB,KAAK,MAAM,KAAK;AACjE,UAAM,MAAM,KAAK;AACjB,UAAM,MAAM,KAAK;AACjB,UAAM,OAAO,KAAK;AAClB,UAAM,WAAY,IAAI,KAAK,eAAgB;AAC3C,UAAM,YAAY,KAAK,cAAc,KAAK,sBAAsB,IAAI;AAEpE,UAAM,UAAU,MAAM;AACpB,UAAI,YAAY,KAAK;AACrB,UAAI,CAAC,KAAK,YAAY;AACpB,cAAM,MAAM,YAAY,IAAA;AACxB,cAAM,UAAU,OAAO,KAAK,sBAAsB;AAClD,cAAM,QAAQ,KAAK,IAAI,MAAM,GAAG;AAEhC,cAAM,mBAAmB,KAAK,IAAI,UAAU,UAAU,CAAC;AACvD,cAAM,gBACJ,KAAK,sBAAsB,YAAY,QAAQ;AAEjD,YAAI,YAAY,GAAG;AACjB,sBACE,SAAS,SACL,gBACA,KAAK,KAAK,gBAAgB,MAAM,IAAI,IAAI,OAAO;AACrD,sBAAY,KAAK,IAAI,KAAK,aAAa,SAAS;AAAA,QAClD,OAAO;AACL,sBACE,SAAS,SACL,gBACA,KAAK,OAAO,gBAAgB,OAAO,IAAI,IAAI,OAAO;AACxD,sBAAY,KAAK,IAAI,KAAK,aAAa,SAAS;AAAA,QAClD;AAAA,MACF;AAEA,YAAM,iBAAiB,KAAK,iBACxB,KAAK,QAAQ,YACb,KAAK,SAAS;AAClB,UAAI,gBAAgB;AAClB,YAAI,KAAK,gBAAgB;AACvB,eAAK,MAAM;AAAA,QACb,OAAO;AACL,eAAK,OAAO;AAAA,QACd;AACA,aAAK;AAAA,UACH,IAAI,YAAY,SAAS,EAAC,QAAQ,EAAC,KAAK,KAAK,KAAK,MAAM,KAAK,KAAA,GAAM;AAAA,QAAA;AAAA,MAEvE;AAEA,UACG,YAAY,KAAK,YAAY,KAAK,eAClC,YAAY,KAAK,YAAY,KAAK,aACnC;AACA,aAAK,iBAAiB,sBAAsB,OAAO;AAAA,MACrD,WAAW,KAAK,aAAa;AAE3B,aAAK,qBAAqB,YAAY,IAAA;AACtC,aAAK,sBAAsB,KAAK,iBAAiB,KAAK,MAAM,KAAK;AACjE,aAAK,iBAAiB,sBAAsB,OAAO;AACnD,aAAK,aAAa;AAAA,MACpB;AAAA,IACF;AAEA,SAAK,iBAAiB,sBAAsB,OAAO;AAAA,EACrD;AAAA,EAEQ,gBAAgB;AACtB,QAAI,KAAK,mBAAmB,MAAM;AAChC,2BAAqB,KAAK,cAAc;AACxC,WAAK,iBAAiB;AAAA,IACxB;AAAA,EACF;AAAA,EAEQ,YAAY,OAAe;AACjC,WAAO,MAAM,QAAQ,KAAK,aAAa,IAAI,KAAK;AAAA,EAClD;AAAA,EAES,SAAS;AAChB,WAAO;AAAA,QACH,KAAK,kBACH;AAAA;AAAA,sBAEY,SAAS;AAAA,MACf,OAAO;AAAA,MACP,KAAK;AAAA,MACL,UAAU,KAAK;AAAA,IAAA,CAChB,CAAC;AAAA,8BACc,KAAK,UAAU;AAAA;AAAA,0CAEH,KAAK,YAAY,KAAK,GAAG,CAAC;AAAA;AAAA,cAG1D,IAAI;AAAA;AAAA,gBAEE,SAAS;AAAA,MACf,SAAS;AAAA,MACT,CAAC,KAAK,OAAO,GAAG;AAAA,MAChB,WAAW,KAAK;AAAA,MAChB,UAAU,KAAK;AAAA,MACf,UAAU,KAAK;AAAA,IAAA,CAChB,CAAC;AAAA,gBACM,SAAS;AAAA,MACf,gBAAgB,OAAO,KAAK,QAAQ;AAAA,MACpC,iBAAiB,OAAO,KAAK,SAAS;AAAA,IAAA,CACvC,CAAC;AAAA,qBACW,KAAK,WAAW;AAAA,mBAClB,KAAK,SAAS;AAAA,qBACZ,KAAK,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKrB,KAAK,GAAG;AAAA,gBACR,KAAK,GAAG;AAAA;AAAA,iBAEP,UAAU,KAAK,IAAI,CAAC;AAAA,mBAClB,KAAK,IAAI,SAAA,CAAU;AAAA,sBAChB,KAAK,YAAY,cAC7B,KAAK,QAAQ;AAAA,mBACJ,KAAK,OAAO;AAAA,oBACX,MAAM,KAAK,gBAAA,CAAiB;AAAA;AAAA;AAAA;AAAA;AAAA,gBAKhC,KAAK,GAAG;AAAA,gBACR,KAAK,GAAG;AAAA,iBACP,UAAU,KAAK,IAAI,CAAC;AAAA,mBAClB,KAAK,KAAK,SAAA,CAAU;AAAA,sBACjB,KAAK,YAAY,cAC7B,KAAK,QAAQ;AAAA,mBACJ,KAAK,OAAO;AAAA,oBACX,MAAM,KAAK,gBAAA,CAAiB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,QAMxC,KAAK,mBACH;AAAA;AAAA,sBAEY,SAAS;AAAA,MACf,OAAO;AAAA,MACP,KAAK;AAAA,MACL,UAAU,KAAK;AAAA,IAAA,CAChB,CAAC;AAAA,8BACc,KAAK,UAAU;AAAA;AAAA,2CAEF,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA;AAAA,cAG5D,IAAI;AAAA;AAAA,EAEZ;AAGF;AA7ca,gBA4cK,SAAS,UAAU,cAAc;AAvcvB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GALb,gBAKe,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAXb,gBAWe,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAjBb,gBAiBe,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAvBb,gBAuBe,WAAA,OAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA7Bb,gBA6Be,WAAA,QAAA,CAAA;AAMA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAnCb,gBAmCe,WAAA,aAAA,CAAA;AASA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Cb,gBA4Ce,WAAA,WAAA,CAAA;AAOC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAnDd,gBAmDgB,WAAA,gBAAA,CAAA;AAEA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GArDd,gBAqDgB,WAAA,YAAA,CAAA;AAOD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Db,gBA4De,WAAA,gBAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAjEb,gBAiEe,WAAA,aAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtEb,gBAsEe,WAAA,iBAAA,CAAA;AAKA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA3Eb,gBA2Ee,WAAA,cAAA,CAAA;AAUmB,gBAAA;AAAA,EAA5C,SAAS,EAAC,MAAM,SAAS,WAAW,OAAM;AAAA,GArFhC,gBAqFkC,WAAA,mBAAA,CAAA;AAUA,gBAAA;AAAA,EAA5C,SAAS,EAAC,MAAM,SAAS,WAAW,OAAM;AAAA,GA/FhC,gBA+FkC,WAAA,oBAAA,CAAA;AAO7C,gBAAA;AAAA,EADC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAM,WAAW,gBAAe;AAAA,GArGxD,gBAsGX,WAAA,gBAAA,CAAA;AA2BQ,gBAAA;AAAA,EADP,MAAM,yBAAyB;AAAA,GAhIrB,gBAiIH,WAAA,YAAA,CAAA;AAGA,gBAAA;AAAA,EADP,MAAM,yBAAyB;AAAA,GAnIrB,gBAoIH,WAAA,YAAA,CAAA;AApIG,kBAAN,gBAAA;AAAA,EADN,cAAc,mBAAmB;AAAA,GACrB,eAAA;"}
|
|
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":"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"}
|
|
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 };
|