@oicl/openbridge-webcomponents 2.0.0-next.66 → 2.0.0-next.68

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/bundle/openbridge-webcomponents.bundle.js +2738 -2408
  2. package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
  3. package/custom-elements.json +347 -30
  4. package/dist/automation/automation-button/automation-button.css.js +9 -9
  5. package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.d.ts +1 -0
  6. package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.d.ts.map +1 -1
  7. package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.js +9 -28
  8. package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.js.map +1 -1
  9. package/dist/components/accordion-card/accordion-card.css.js +1 -1
  10. package/dist/components/dropdown-button/dropdown-button.d.ts +11 -0
  11. package/dist/components/dropdown-button/dropdown-button.d.ts.map +1 -1
  12. package/dist/components/dropdown-button/dropdown-button.js +24 -2
  13. package/dist/components/dropdown-button/dropdown-button.js.map +1 -1
  14. package/dist/components/keyboard-numeric/keyboard-numeric.d.ts +1 -2
  15. package/dist/components/keyboard-numeric/keyboard-numeric.d.ts.map +1 -1
  16. package/dist/components/keyboard-numeric/keyboard-numeric.js +10 -15
  17. package/dist/components/keyboard-numeric/keyboard-numeric.js.map +1 -1
  18. package/dist/components/number-input-field/number-input-field.d.ts +9 -0
  19. package/dist/components/number-input-field/number-input-field.d.ts.map +1 -1
  20. package/dist/components/number-input-field/number-input-field.js +30 -1
  21. package/dist/components/number-input-field/number-input-field.js.map +1 -1
  22. package/dist/components/number-input-field/number-input-format.d.ts +9 -0
  23. package/dist/components/number-input-field/number-input-format.d.ts.map +1 -1
  24. package/dist/components/number-input-field/number-input-format.js +33 -2
  25. package/dist/components/number-input-field/number-input-format.js.map +1 -1
  26. package/dist/components/stepper-box/stepper-box.css.js +0 -6
  27. package/dist/components/stepper-box/stepper-box.css.js.map +1 -1
  28. package/dist/components/stepper-box/stepper-box.d.ts +3 -13
  29. package/dist/components/stepper-box/stepper-box.d.ts.map +1 -1
  30. package/dist/components/stepper-box/stepper-box.js.map +1 -1
  31. package/dist/components/toggle-button-group/toggle-button-group.d.ts +14 -0
  32. package/dist/components/toggle-button-group/toggle-button-group.d.ts.map +1 -1
  33. package/dist/components/toggle-button-group/toggle-button-group.js +25 -5
  34. package/dist/components/toggle-button-group/toggle-button-group.js.map +1 -1
  35. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.css.js +4 -0
  36. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.css.js.map +1 -1
  37. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.d.ts +1 -0
  38. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.d.ts.map +1 -1
  39. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.js +13 -1
  40. package/dist/integration-systems/integration-fleet-button/integration-fleet-button.js.map +1 -1
  41. package/dist/navigation-instruments/graph-mini/graph-mini.css.js +2 -1
  42. package/dist/navigation-instruments/graph-mini/graph-mini.css.js.map +1 -1
  43. package/dist/navigation-instruments/graph-mini/graph-mini.d.ts.map +1 -1
  44. package/dist/navigation-instruments/graph-mini/graph-mini.js +7 -5
  45. package/dist/navigation-instruments/graph-mini/graph-mini.js.map +1 -1
  46. package/dist/navigation-instruments/indicator-graph/indicator-graph.css.js +66 -0
  47. package/dist/navigation-instruments/indicator-graph/indicator-graph.css.js.map +1 -0
  48. package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts +54 -0
  49. package/dist/navigation-instruments/indicator-graph/indicator-graph.d.ts.map +1 -0
  50. package/dist/navigation-instruments/indicator-graph/indicator-graph.js +203 -0
  51. package/dist/navigation-instruments/indicator-graph/indicator-graph.js.map +1 -0
  52. package/package.json +1 -1
@@ -1 +1 @@
1
- {"version":3,"file":"number-input-field.js","sources":["../../../src/components/number-input-field/number-input-field.ts"],"sourcesContent":["import {\n LitElement,\n html,\n nothing,\n unsafeCSS,\n TemplateResult,\n PropertyValues,\n} from 'lit';\nimport {property, state, query} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport componentStyle from './number-input-field.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\nimport {\n formatNumberForDisplay,\n NumberInputFormatOptions,\n parseNumberInput,\n removeGroupingFromDisplay,\n valuesEqual,\n} from './number-input-format.js';\nimport {getCssVariableValue} from '../../charthelpers/colors.js';\n\nexport type ObcNumberInputFieldInputEvent = CustomEvent<{value: number}>;\nexport type ObcNumberInputFieldChangeEvent = CustomEvent<{value: number}>;\n\nexport enum ObcNumberInputFieldTextAlign {\n Center = 'center',\n Right = 'right',\n RightUnitOutside = 'right-unit-outside',\n}\n\nexport enum ObcNumberInputFieldSize {\n Regular = 'regular',\n Large = 'large',\n}\n\nexport enum ObcNumberInputFieldPlacement {\n Left = 'left',\n Center = 'center',\n Right = 'right',\n}\n\nconst characterWidth = 9.15199279785156;\nconst symbolWidth = 4.287994384765653;\nconst baseFontSize = 16;\n/**\n * `<obc-number-input-field>` – A specialized input field for numerical values with optional unit display.\n *\n * @slot leading-icon - Icon displayed before the input value (when `hasLeadingIcon` is true)\n * @slot label-icon - Icon displayed before the label text (when `hasLabelIcon` is true)\n * @slot helper-icon - Icon displayed before helper or error text (when `hasHelperIcon` is true)\n * @fires input {CustomEvent<{value: number}>} When the numeric value changes during editing\n * @fires change {CustomEvent<{value: number}>} When the value is committed on blur\n */\n@customElement('obc-number-input-field')\nexport class ObcNumberInputField extends LitElement {\n @property({type: Number}) value = NaN;\n @property({type: String}) unit = '';\n @property({type: String}) placeholder = '';\n @property({type: String}) textAlign: ObcNumberInputFieldTextAlign =\n ObcNumberInputFieldTextAlign.Right;\n\n @property({type: Boolean, reflect: true}) disabled = false;\n @property({type: Boolean, reflect: true}) readonly = false;\n @property({type: Boolean, reflect: true}) error = false;\n @property({type: String}) errorText = '';\n /** If true, the input field will not update its value on focus */\n @property({type: Boolean}) rejectUpdatesOnFocus = false;\n /** If true, the value will only be initially set, and not updated on change */\n @property({type: Boolean}) rejectUpdates = false;\n\n /** If true, the input field will not update its value if the value is the same as the previous value\n * This is useful to avoid React re-rendering to reset the value.\n */\n @property({type: Boolean}) rejectDuplicateUpdates = false;\n\n /** Name attribute for form integration */\n @property({type: String}) name = '';\n\n /** Maximum number of characters allowed */\n @property({type: Number}) maxlength?: number;\n\n /** Minimum number of characters required */\n @property({type: Number}) minlength?: number;\n\n @property({type: String}) size: ObcNumberInputFieldSize =\n ObcNumberInputFieldSize.Regular;\n\n @property({type: Boolean}) hasLeadingIcon = false;\n @property({type: String}) helperText = '';\n\n @property({type: String}) label = '';\n @property({type: Boolean}) required = false;\n @property({type: Boolean}) hasLabelIcon = false;\n @property({type: String}) labelPlacement: ObcNumberInputFieldPlacement =\n ObcNumberInputFieldPlacement.Left;\n\n @property({type: Boolean}) hasHelperIcon = false;\n @property({type: String}) helperPlacement: ObcNumberInputFieldPlacement =\n ObcNumberInputFieldPlacement.Left;\n\n /** Internal property for squared corners, used when input is used in stepper-box */\n @property({type: Boolean}) squared = false;\n\n /**\n * Optional display text override for controlled consumers (e.g. keyboard-numeric)\n * that manage formatted strings while the committed value may be NaN.\n */\n @property({type: String, attribute: false}) displayOverride = '';\n\n @property({type: String}) decimalSeparator?: string;\n @property({type: String}) groupSeparator?: string;\n @property({type: Number}) minFractionDigits = 0;\n @property({type: Number}) maxFractionDigits?: number | undefined;\n\n @state() private hasFocus = false;\n @state() private displayText = '';\n @state() private previousValue = NaN;\n @state() private previousDisplayText = '';\n @state() private lastCommittedValue = NaN;\n\n @query('.value-input') private inputElement?: HTMLInputElement;\n\n get displayValue(): string {\n return this.displayText;\n }\n\n private getFormatOptions(): NumberInputFormatOptions {\n return {\n decimalSeparator: this.decimalSeparator,\n groupSeparator: this.groupSeparator,\n minFractionDigits: this.minFractionDigits,\n maxFractionDigits: this.maxFractionDigits,\n };\n }\n\n private formatValueForDisplay(value: number): string {\n return formatNumberForDisplay(value, this.getFormatOptions());\n }\n\n private onInput(e: Event) {\n e.stopPropagation();\n const raw = (e.target as HTMLInputElement).value;\n this.displayText = raw;\n this.displayOverride = '';\n const parsed = parseNumberInput(raw);\n this.value = parsed;\n this.previousDisplayText = raw;\n this.updateCenterAlignedInputWidth(raw);\n this.dispatchInput();\n }\n\n private onFocus() {\n this.hasFocus = true;\n const source = this.displayOverride || this.displayText;\n this.displayText = removeGroupingFromDisplay(\n source,\n this.getFormatOptions()\n );\n this.displayOverride = '';\n }\n\n private onBlur() {\n this.hasFocus = false;\n this.commitDisplay();\n if (!valuesEqual(this.value, this.lastCommittedValue)) {\n this.lastCommittedValue = this.value;\n this.dispatchChange();\n }\n }\n\n private commitDisplay() {\n const trimmed = this.displayText.trim();\n if (trimmed === '') {\n this.value = NaN;\n this.displayText = '';\n this.displayOverride = '';\n return;\n }\n\n const forCommit = trimmed.replace(/[.,]$/, '');\n const parsed = parseNumberInput(forCommit);\n\n if (Number.isFinite(parsed)) {\n this.value = parsed;\n this.displayText = this.formatValueForDisplay(parsed);\n } else {\n this.value = NaN;\n }\n this.displayOverride = '';\n }\n\n private dispatchInput() {\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {value: this.value},\n })\n );\n }\n\n private dispatchChange() {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: this.value},\n })\n );\n }\n\n private get shouldUpdateValue(): boolean {\n if (this.rejectUpdates) return false;\n if (this.rejectUpdatesOnFocus && this.hasFocus) return false;\n if (\n this.rejectDuplicateUpdates &&\n valuesEqual(this.value, this.previousValue)\n ) {\n return false;\n }\n return true;\n }\n\n private getEffectiveDisplay(): string {\n if (this.displayOverride) {\n return this.displayOverride;\n }\n if (!this.shouldUpdateValue && this.inputElement) {\n return this.inputElement.value;\n }\n return this.displayText;\n }\n\n private updateCenterAlignedInputWidth(value: string) {\n if (this.textAlign !== ObcNumberInputFieldTextAlign.Center) {\n this.style.removeProperty('--obc-number-input-center-width');\n return;\n }\n\n const fontSize = Number.parseFloat(\n getCssVariableValue(\n this,\n '--global-typography-instrument-value-regular-font-size'\n )\n );\n\n const characters = value.replaceAll(/[.,]/g, '');\n const symbols = value.length - characters.length;\n // These values are based on the font size of 16px\n\n const calculatedWidth =\n characters.length * characterWidth + symbols * symbolWidth;\n\n const measuredWidth = Math.ceil(\n (calculatedWidth * fontSize) / baseFontSize\n );\n this.style.setProperty(\n '--obc-number-input-center-width',\n `${measuredWidth}px`\n );\n }\n\n override firstUpdated() {\n if (!this.displayText && !this.displayOverride) {\n this.displayText = this.formatValueForDisplay(this.value);\n }\n this.lastCommittedValue = this.value;\n this.updateCenterAlignedInputWidth(this.getEffectiveDisplay());\n }\n\n private get isEmpty(): boolean {\n if (this.inputElement) {\n return this.inputElement.value.trim().length === 0;\n }\n return isNaN(this.value);\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n const formatPropsChanged =\n changedProperties.has('decimalSeparator') ||\n changedProperties.has('groupSeparator') ||\n changedProperties.has('minFractionDigits') ||\n changedProperties.has('maxFractionDigits');\n\n if (changedProperties.has('value') && this.shouldUpdateValue) {\n if (!this.hasFocus) {\n this.displayText = this.formatValueForDisplay(this.value);\n this.displayOverride = '';\n this.lastCommittedValue = this.value;\n }\n } else if (formatPropsChanged && !this.hasFocus && this.shouldUpdateValue) {\n this.displayText = this.formatValueForDisplay(this.value);\n this.displayOverride = '';\n }\n\n if (\n changedProperties.has('value') &&\n !this.shouldUpdateValue &&\n this.inputElement\n ) {\n this.value = parseNumberInput(this.inputElement.value);\n }\n }\n\n override updated() {\n if (\n this.rejectDuplicateUpdates &&\n !valuesEqual(this.value, this.previousValue) &&\n (this.previousDisplayText !== this.displayText || !this.hasFocus)\n ) {\n this.previousValue = this.value;\n }\n\n this.updateCenterAlignedInputWidth(this.getEffectiveDisplay());\n }\n\n private renderFooterText(\n text: string,\n isError: boolean\n ): TemplateResult | typeof nothing {\n if (!text) return nothing;\n return html`<div\n id=\"helper-text\"\n class=${classMap({\n [isError ? 'error-text' : 'helper-text']: true,\n [`helper-placement-${this.helperPlacement}`]: true,\n })}\n >\n ${this.hasHelperIcon\n ? html`<div class=\"helper-icon\"><slot name=\"helper-icon\"></slot></div>`\n : nothing}\n ${text}\n </div>`;\n }\n\n private onPointerDown(e: PointerEvent) {\n if (this.disabled) return;\n if (this.readonly) return;\n if (this.inputElement) {\n e.stopPropagation();\n e.preventDefault();\n this.inputElement.focus();\n const inputBox = this.inputElement.getBoundingClientRect();\n let selectionStart: number | undefined;\n if (e.clientX < inputBox.left) {\n // set marker at the left edge of the input\n selectionStart = 0;\n } else if (e.clientX > inputBox.right) {\n // set marker at the right edge of the input\n selectionStart = this.inputElement.value.length;\n } else {\n // set marker at the mouse position\n // Start from the right side of the input and move left until the mouse position is found\n // This is done to set the marker also at label touch.\n // Starts from the right since the label is right aligned.\n const mouseX = e.clientX;\n let inputX = inputBox.right;\n const text = this.inputElement.value;\n for (let i = text.length - 1; i >= 0; i--) {\n const char = text[i];\n const isSymbol = char.match(/[.,]/);\n const width = isSymbol ? symbolWidth : characterWidth;\n if (mouseX > inputX - width / 2) {\n selectionStart = i + 1;\n break;\n }\n inputX -= width;\n }\n if (selectionStart === undefined) {\n selectionStart = 0;\n }\n }\n this.inputElement.setSelectionRange(selectionStart, selectionStart);\n }\n }\n\n override render() {\n const hasHelperOrError =\n Boolean(this.helperText) || Boolean(this.error && this.errorText);\n const unitInside =\n this.unit &&\n this.textAlign !== ObcNumberInputFieldTextAlign.RightUnitOutside;\n const unitOutside =\n this.unit &&\n this.textAlign === ObcNumberInputFieldTextAlign.RightUnitOutside;\n\n const display = this.getEffectiveDisplay();\n\n return html`\n <label\n class=${classMap({\n wrapper: true,\n [`align-${this.textAlign}`]: true,\n [`size-${this.size}`]: true,\n error: this.error,\n disabled: this.disabled,\n empty: this.isEmpty,\n helpertext: hasHelperOrError,\n haslabel: Boolean(this.label),\n squared: this.squared,\n })}\n @pointerdown=${this.onPointerDown}\n >\n ${this.label\n ? html`<div\n class=${classMap({\n 'label-text-container': true,\n [`label-placement-${this.labelPlacement}`]: true,\n })}\n >\n ${this.hasLabelIcon\n ? html`<div class=\"label-icon\">\n <slot name=\"label-icon\"></slot>\n </div>`\n : nothing}\n <span class=\"label-text\">${this.label}</span>\n ${this.required\n ? html`<div class=\"required-indicator\"></div>`\n : nothing}\n </div>`\n : nothing}\n\n <div class=\"horizontal-container\">\n <div class=\"input-field-container\" part=\"input-field-container\">\n ${this.hasLeadingIcon\n ? html`<div class=\"leading-icon\">\n <slot name=\"leading-icon\"></slot>\n </div>`\n : nothing}\n <div class=\"label-container\">\n <input\n type=\"text\"\n inputmode=\"decimal\"\n class=\"value-input\"\n .value=${display}\n @focus=${this.onFocus}\n @blur=${this.onBlur}\n .placeholder=${this.placeholder}\n name=${ifDefined(this.name || undefined)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n maxlength=${ifDefined(this.maxlength)}\n minlength=${ifDefined(this.minlength)}\n aria-invalid=${this.error ? 'true' : 'false'}\n aria-describedby=${ifDefined(\n hasHelperOrError ? 'helper-text' : undefined\n )}\n autocomplete=\"off\"\n @input=${this.onInput}\n />\n ${unitInside\n ? html`<span class=\"unit-text\">${this.unit}</span>`\n : nothing}\n </div>\n </div>\n ${unitOutside\n ? html`<span class=\"unit-text external\">${this.unit}</span>`\n : nothing}\n </div>\n\n ${this.error && this.errorText\n ? this.renderFooterText(this.errorText, true)\n : this.renderFooterText(this.helperText, false)}\n </label>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-number-input-field': ObcNumberInputField;\n }\n}\n"],"names":["ObcNumberInputFieldTextAlign","ObcNumberInputFieldSize","ObcNumberInputFieldPlacement"],"mappings":"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"}
1
+ {"version":3,"file":"number-input-field.js","sources":["../../../src/components/number-input-field/number-input-field.ts"],"sourcesContent":["import {\n LitElement,\n html,\n nothing,\n unsafeCSS,\n TemplateResult,\n PropertyValues,\n} from 'lit';\nimport {property, state, query} from 'lit/decorators.js';\nimport {ifDefined} from 'lit/directives/if-defined.js';\nimport componentStyle from './number-input-field.css?inline';\nimport {classMap} from 'lit/directives/class-map.js';\nimport {customElement} from '../../decorator.js';\nimport {\n formatNumberForDisplay,\n isAllowedIntermediateInput,\n NumberInputFormatOptions,\n parseNumberInput,\n removeGroupingFromDisplay,\n valuesEqual,\n} from './number-input-format.js';\nimport {getCssVariableValue} from '../../charthelpers/colors.js';\n\nexport type ObcNumberInputFieldInputEvent = CustomEvent<{value: number}>;\nexport type ObcNumberInputFieldChangeEvent = CustomEvent<{value: number}>;\n\nexport enum ObcNumberInputFieldTextAlign {\n Center = 'center',\n Right = 'right',\n RightUnitOutside = 'right-unit-outside',\n}\n\nexport enum ObcNumberInputFieldSize {\n Regular = 'regular',\n Large = 'large',\n}\n\nexport enum ObcNumberInputFieldPlacement {\n Left = 'left',\n Center = 'center',\n Right = 'right',\n}\n\nconst characterWidth = 9.15199279785156;\nconst symbolWidth = 4.287994384765653;\nconst baseFontSize = 16;\n/**\n * `<obc-number-input-field>` – A specialized input field for numerical values with optional unit display.\n *\n * @slot leading-icon - Icon displayed before the input value (when `hasLeadingIcon` is true)\n * @slot label-icon - Icon displayed before the label text (when `hasLabelIcon` is true)\n * @slot helper-icon - Icon displayed before helper or error text (when `hasHelperIcon` is true)\n * @fires input {CustomEvent<{value: number}>} When the numeric value changes during editing\n * @fires change {CustomEvent<{value: number}>} When the value is committed on blur\n */\n@customElement('obc-number-input-field')\nexport class ObcNumberInputField extends LitElement {\n @property({type: Number}) value = NaN;\n @property({type: String}) unit = '';\n @property({type: String}) placeholder = '';\n @property({type: String}) textAlign: ObcNumberInputFieldTextAlign =\n ObcNumberInputFieldTextAlign.Right;\n\n @property({type: Boolean, reflect: true}) disabled = false;\n @property({type: Boolean, reflect: true}) readonly = false;\n @property({type: Boolean, reflect: true}) error = false;\n @property({type: String}) errorText = '';\n /** If true, the input field will not update its value on focus */\n @property({type: Boolean}) rejectUpdatesOnFocus = false;\n /** If true, the value will only be initially set, and not updated on change */\n @property({type: Boolean}) rejectUpdates = false;\n\n /** If true, the input field will not update its value if the value is the same as the previous value\n * This is useful to avoid React re-rendering to reset the value.\n */\n @property({type: Boolean}) rejectDuplicateUpdates = false;\n\n /** Name attribute for form integration */\n @property({type: String}) name = '';\n\n /** Maximum number of characters allowed */\n @property({type: Number}) maxlength?: number;\n\n /** Minimum number of characters required */\n @property({type: Number}) minlength?: number;\n\n @property({type: String}) size: ObcNumberInputFieldSize =\n ObcNumberInputFieldSize.Regular;\n\n @property({type: Boolean}) hasLeadingIcon = false;\n @property({type: String}) helperText = '';\n\n @property({type: String}) label = '';\n @property({type: Boolean}) required = false;\n @property({type: Boolean}) hasLabelIcon = false;\n @property({type: String}) labelPlacement: ObcNumberInputFieldPlacement =\n ObcNumberInputFieldPlacement.Left;\n\n @property({type: Boolean}) hasHelperIcon = false;\n @property({type: String}) helperPlacement: ObcNumberInputFieldPlacement =\n ObcNumberInputFieldPlacement.Left;\n\n /** Internal property for squared corners, used when input is used in stepper-box */\n @property({type: Boolean}) squared = false;\n\n /**\n * Optional display text override for controlled consumers (e.g. keyboard-numeric)\n * that manage formatted strings while the committed value may be NaN.\n */\n @property({type: String, attribute: false}) displayOverride = '';\n\n @property({type: String}) decimalSeparator?: string;\n @property({type: String}) groupSeparator?: string;\n @property({type: Number}) minFractionDigits = 0;\n @property({type: Number}) maxFractionDigits?: number | undefined;\n\n /**\n * Optional regex pattern. When set, any keystroke or paste whose resulting\n * value does not match this pattern is blocked at the `beforeinput` stage.\n * When unset, a permissive numeric filter (digits, sign, active separators,\n * whitespace) is applied instead.\n */\n @property({type: String}) validationPattern = '';\n\n @state() private hasFocus = false;\n @state() private displayText = '';\n @state() private previousValue = NaN;\n @state() private previousDisplayText = '';\n @state() private lastCommittedValue = NaN;\n\n @query('.value-input') private inputElement?: HTMLInputElement;\n\n get displayValue(): string {\n return this.displayText;\n }\n\n private getFormatOptions(): NumberInputFormatOptions {\n return {\n decimalSeparator: this.decimalSeparator,\n groupSeparator: this.groupSeparator,\n minFractionDigits: this.minFractionDigits,\n maxFractionDigits: this.maxFractionDigits,\n };\n }\n\n private formatValueForDisplay(value: number): string {\n return formatNumberForDisplay(value, this.getFormatOptions());\n }\n\n private onInput(e: Event) {\n e.stopPropagation();\n const raw = (e.target as HTMLInputElement).value;\n this.displayText = raw;\n this.displayOverride = '';\n const parsed = parseNumberInput(raw);\n this.value = parsed;\n this.previousDisplayText = raw;\n this.updateCenterAlignedInputWidth(raw);\n this.dispatchInput();\n }\n\n private isProjectedValueAllowed(projected: string): boolean {\n if (this.validationPattern) {\n let regex: RegExp;\n try {\n // Anchor the consumer pattern so it must match the whole projected\n // value rather than any substring (e.g. `[0-9]` must not pass `a1`).\n regex = new RegExp(`^(?:${this.validationPattern})$`);\n } catch {\n // Invalid pattern: fall back to the numeric filter instead of\n // allowing arbitrary input.\n return isAllowedIntermediateInput(projected, this.getFormatOptions());\n }\n return regex.test(projected);\n }\n return isAllowedIntermediateInput(projected, this.getFormatOptions());\n }\n\n private onBeforeInput(e: InputEvent) {\n if (this.disabled || this.readonly) return;\n const input = e.target as HTMLInputElement;\n\n const incoming = e.data ?? e.dataTransfer?.getData('text/plain') ?? null;\n // Deletions, history, and formatting (`insertLineBreak`, `historyUndo`,\n // `deleteContentBackward`, etc.) have `data === null` and no transferable\n // text — always allow them.\n if (incoming === null) return;\n\n const start = input.selectionStart ?? input.value.length;\n const end = input.selectionEnd ?? input.value.length;\n const projected =\n input.value.slice(0, start) + incoming + input.value.slice(end);\n\n if (!this.isProjectedValueAllowed(projected)) {\n e.preventDefault();\n }\n }\n\n private onFocus() {\n this.hasFocus = true;\n const source = this.displayOverride || this.displayText;\n this.displayText = removeGroupingFromDisplay(\n source,\n this.getFormatOptions()\n );\n this.displayOverride = '';\n }\n\n private onBlur() {\n this.hasFocus = false;\n this.commitDisplay();\n if (!valuesEqual(this.value, this.lastCommittedValue)) {\n this.lastCommittedValue = this.value;\n this.dispatchChange();\n }\n }\n\n private commitDisplay() {\n const trimmed = this.displayText.trim();\n if (trimmed === '') {\n this.value = NaN;\n this.displayText = '';\n this.displayOverride = '';\n return;\n }\n\n const forCommit = trimmed.replace(/[.,]$/, '');\n const parsed = parseNumberInput(forCommit);\n\n if (Number.isFinite(parsed)) {\n this.value = parsed;\n this.displayText = this.formatValueForDisplay(parsed);\n } else {\n this.value = NaN;\n }\n this.displayOverride = '';\n }\n\n private dispatchInput() {\n this.dispatchEvent(\n new CustomEvent('input', {\n detail: {value: this.value},\n })\n );\n }\n\n private dispatchChange() {\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: this.value},\n })\n );\n }\n\n private get shouldUpdateValue(): boolean {\n if (this.rejectUpdates) return false;\n if (this.rejectUpdatesOnFocus && this.hasFocus) return false;\n if (\n this.rejectDuplicateUpdates &&\n valuesEqual(this.value, this.previousValue)\n ) {\n return false;\n }\n return true;\n }\n\n private getEffectiveDisplay(): string {\n if (this.displayOverride) {\n return this.displayOverride;\n }\n if (!this.shouldUpdateValue && this.inputElement) {\n return this.inputElement.value;\n }\n return this.displayText;\n }\n\n private updateCenterAlignedInputWidth(value: string) {\n if (this.textAlign !== ObcNumberInputFieldTextAlign.Center) {\n this.style.removeProperty('--obc-number-input-center-width');\n return;\n }\n\n const fontSize = Number.parseFloat(\n getCssVariableValue(\n this,\n '--global-typography-instrument-value-regular-font-size'\n )\n );\n\n const characters = value.replaceAll(/[.,]/g, '');\n const symbols = value.length - characters.length;\n // These values are based on the font size of 16px\n\n const calculatedWidth =\n characters.length * characterWidth + symbols * symbolWidth;\n\n const measuredWidth = Math.ceil(\n (calculatedWidth * fontSize) / baseFontSize\n );\n this.style.setProperty(\n '--obc-number-input-center-width',\n `${measuredWidth}px`\n );\n }\n\n override firstUpdated() {\n if (!this.displayText && !this.displayOverride) {\n this.displayText = this.formatValueForDisplay(this.value);\n }\n this.lastCommittedValue = this.value;\n this.updateCenterAlignedInputWidth(this.getEffectiveDisplay());\n }\n\n private get isEmpty(): boolean {\n if (this.inputElement) {\n return this.inputElement.value.trim().length === 0;\n }\n return isNaN(this.value);\n }\n\n override willUpdate(changedProperties: PropertyValues) {\n const formatPropsChanged =\n changedProperties.has('decimalSeparator') ||\n changedProperties.has('groupSeparator') ||\n changedProperties.has('minFractionDigits') ||\n changedProperties.has('maxFractionDigits');\n\n if (changedProperties.has('value') && this.shouldUpdateValue) {\n if (!this.hasFocus) {\n this.displayText = this.formatValueForDisplay(this.value);\n this.displayOverride = '';\n this.lastCommittedValue = this.value;\n }\n } else if (formatPropsChanged && !this.hasFocus && this.shouldUpdateValue) {\n this.displayText = this.formatValueForDisplay(this.value);\n this.displayOverride = '';\n }\n\n if (\n changedProperties.has('value') &&\n !this.shouldUpdateValue &&\n this.inputElement\n ) {\n this.value = parseNumberInput(this.inputElement.value);\n }\n }\n\n override updated() {\n if (\n this.rejectDuplicateUpdates &&\n !valuesEqual(this.value, this.previousValue) &&\n (this.previousDisplayText !== this.displayText || !this.hasFocus)\n ) {\n this.previousValue = this.value;\n }\n\n this.updateCenterAlignedInputWidth(this.getEffectiveDisplay());\n }\n\n private renderFooterText(\n text: string,\n isError: boolean\n ): TemplateResult | typeof nothing {\n if (!text) return nothing;\n return html`<div\n id=\"helper-text\"\n class=${classMap({\n [isError ? 'error-text' : 'helper-text']: true,\n [`helper-placement-${this.helperPlacement}`]: true,\n })}\n >\n ${this.hasHelperIcon\n ? html`<div class=\"helper-icon\"><slot name=\"helper-icon\"></slot></div>`\n : nothing}\n ${text}\n </div>`;\n }\n\n private onPointerDown(e: PointerEvent) {\n if (this.disabled) return;\n if (this.readonly) return;\n if (this.inputElement) {\n e.stopPropagation();\n e.preventDefault();\n this.inputElement.focus();\n const inputBox = this.inputElement.getBoundingClientRect();\n let selectionStart: number | undefined;\n if (e.clientX < inputBox.left) {\n // set marker at the left edge of the input\n selectionStart = 0;\n } else if (e.clientX > inputBox.right) {\n // set marker at the right edge of the input\n selectionStart = this.inputElement.value.length;\n } else {\n // set marker at the mouse position\n // Start from the right side of the input and move left until the mouse position is found\n // This is done to set the marker also at label touch.\n // Starts from the right since the label is right aligned.\n const mouseX = e.clientX;\n let inputX = inputBox.right;\n const text = this.inputElement.value;\n for (let i = text.length - 1; i >= 0; i--) {\n const char = text[i];\n const isSymbol = char.match(/[.,]/);\n const width = isSymbol ? symbolWidth : characterWidth;\n if (mouseX > inputX - width / 2) {\n selectionStart = i + 1;\n break;\n }\n inputX -= width;\n }\n if (selectionStart === undefined) {\n selectionStart = 0;\n }\n }\n this.inputElement.setSelectionRange(selectionStart, selectionStart);\n }\n }\n\n override render() {\n const hasHelperOrError =\n Boolean(this.helperText) || Boolean(this.error && this.errorText);\n const unitInside =\n this.unit &&\n this.textAlign !== ObcNumberInputFieldTextAlign.RightUnitOutside;\n const unitOutside =\n this.unit &&\n this.textAlign === ObcNumberInputFieldTextAlign.RightUnitOutside;\n\n const display = this.getEffectiveDisplay();\n\n return html`\n <label\n class=${classMap({\n wrapper: true,\n [`align-${this.textAlign}`]: true,\n [`size-${this.size}`]: true,\n error: this.error,\n disabled: this.disabled,\n empty: this.isEmpty,\n helpertext: hasHelperOrError,\n haslabel: Boolean(this.label),\n squared: this.squared,\n })}\n @pointerdown=${this.onPointerDown}\n >\n ${this.label\n ? html`<div\n class=${classMap({\n 'label-text-container': true,\n [`label-placement-${this.labelPlacement}`]: true,\n })}\n >\n ${this.hasLabelIcon\n ? html`<div class=\"label-icon\">\n <slot name=\"label-icon\"></slot>\n </div>`\n : nothing}\n <span class=\"label-text\">${this.label}</span>\n ${this.required\n ? html`<div class=\"required-indicator\"></div>`\n : nothing}\n </div>`\n : nothing}\n\n <div class=\"horizontal-container\">\n <div class=\"input-field-container\" part=\"input-field-container\">\n ${this.hasLeadingIcon\n ? html`<div class=\"leading-icon\">\n <slot name=\"leading-icon\"></slot>\n </div>`\n : nothing}\n <div class=\"label-container\">\n <input\n type=\"text\"\n inputmode=\"decimal\"\n class=\"value-input\"\n .value=${display}\n @focus=${this.onFocus}\n @blur=${this.onBlur}\n .placeholder=${this.placeholder}\n name=${ifDefined(this.name || undefined)}\n ?disabled=${this.disabled}\n ?readonly=${this.readonly}\n ?required=${this.required}\n maxlength=${ifDefined(this.maxlength)}\n minlength=${ifDefined(this.minlength)}\n aria-invalid=${this.error ? 'true' : 'false'}\n aria-describedby=${ifDefined(\n hasHelperOrError ? 'helper-text' : undefined\n )}\n autocomplete=\"off\"\n @beforeinput=${this.onBeforeInput}\n @input=${this.onInput}\n />\n ${unitInside\n ? html`<span class=\"unit-text\">${this.unit}</span>`\n : nothing}\n </div>\n </div>\n ${unitOutside\n ? html`<span class=\"unit-text external\">${this.unit}</span>`\n : nothing}\n </div>\n\n ${this.error && this.errorText\n ? this.renderFooterText(this.errorText, true)\n : this.renderFooterText(this.helperText, false)}\n </label>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-number-input-field': ObcNumberInputField;\n }\n}\n"],"names":["ObcNumberInputFieldTextAlign","ObcNumberInputFieldSize","ObcNumberInputFieldPlacement"],"mappings":"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"}
@@ -10,6 +10,15 @@ export type LocaleNumberSeparators = {
10
10
  };
11
11
  export declare function getLocaleNumberSeparators(locale?: string | string[]): LocaleNumberSeparators;
12
12
  export declare function parseNumberInput(display: string): number;
13
+ /**
14
+ * Permissive per-keystroke validator used to reject non-numeric characters
15
+ * before they reach the input. Allows half-typed states like `10.`, `-`, `,5`,
16
+ * `1,234.`; final correctness is enforced by `parseNumberInput` at commit.
17
+ *
18
+ * Accepts: optional leading sign, digits, the active decimal separator,
19
+ * the active group separator, and whitespace.
20
+ */
21
+ export declare function isAllowedIntermediateInput(value: string, options?: NumberInputFormatOptions): boolean;
13
22
  export declare function formatNumberForDisplay(value: number, options?: NumberInputFormatOptions): string;
14
23
  export declare function removeGroupingFromDisplay(display: string, options?: NumberInputFormatOptions): string;
15
24
  export declare function valuesEqual(a: number, b: number): boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"number-input-format.d.ts","sourceRoot":"","sources":["../../../src/components/number-input-field/number-input-format.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GACzB,sBAAsB,CAMxB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAUxD;AAcD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAiDR;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAWR;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD"}
1
+ {"version":3,"file":"number-input-format.d.ts","sourceRoot":"","sources":["../../../src/components/number-input-field/number-input-format.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,wBAAwB,GAAG;IACrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACnC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,CAAC;CACxB,CAAC;AAEF,wBAAgB,yBAAyB,CACvC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,EAAE,GACzB,sBAAsB,CAMxB;AAED,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAkCxD;AAMD;;;;;;;GAOG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACrC,OAAO,CAgBT;AAcD,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAiDR;AAED,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,wBAA6B,GACrC,MAAM,CAWR;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,OAAO,CAEzD"}
@@ -10,10 +10,40 @@ function parseNumberInput(display) {
10
10
  if (trimmed === "" || trimmed === "-" || trimmed === "+") {
11
11
  return NaN;
12
12
  }
13
- const normalized = trimmed.replace(",", ".");
13
+ let normalized = trimmed.replace(/[\s']/g, "");
14
+ const commaCount = (normalized.match(/,/g) ?? []).length;
15
+ const dotCount = (normalized.match(/\./g) ?? []).length;
16
+ if (commaCount > 0 && dotCount > 0) {
17
+ const decimalSeparator = normalized.lastIndexOf(",") > normalized.lastIndexOf(".") ? "," : ".";
18
+ const groupSeparator = decimalSeparator === "," ? "." : ",";
19
+ normalized = normalized.split(groupSeparator).join("");
20
+ normalized = normalized.replace(decimalSeparator, ".");
21
+ } else if (commaCount > 1) {
22
+ normalized = normalized.split(",").join("");
23
+ } else if (commaCount === 1) {
24
+ normalized = normalized.replace(",", ".");
25
+ } else if (dotCount > 1) {
26
+ normalized = normalized.split(".").join("");
27
+ }
14
28
  const n = Number(normalized);
15
29
  return Number.isFinite(n) ? n : NaN;
16
30
  }
31
+ function escapeRegex(value) {
32
+ return value.replace(/[-.*+?^${}()|[\]\\]/g, "\\$&");
33
+ }
34
+ function isAllowedIntermediateInput(value, options = {}) {
35
+ if (value === "") return true;
36
+ const localeSeparators = getLocaleNumberSeparators();
37
+ const decimalSeparator = options.decimalSeparator ?? localeSeparators.decimalSeparator;
38
+ const groupSeparator = options.groupSeparator ?? localeSeparators.groupSeparator;
39
+ const allowedChars = /* @__PURE__ */ new Set([decimalSeparator]);
40
+ if (groupSeparator) {
41
+ allowedChars.add(groupSeparator);
42
+ }
43
+ const allowedClass = [...allowedChars].map(escapeRegex).join("") + "0-9 \\t";
44
+ const pattern = new RegExp(`^[+\\-]?[${allowedClass}]*$`);
45
+ return pattern.test(value);
46
+ }
17
47
  function clampFractionDigits(minFractionDigits, maxFractionDigits) {
18
48
  const min = Math.max(0, minFractionDigits ?? 0);
19
49
  const max = maxFractionDigits == void 0 ? void 0 : Math.max(min, maxFractionDigits);
@@ -64,7 +94,7 @@ function removeGroupingFromDisplay(display, options = {}) {
64
94
  if (!groupSeparator) {
65
95
  return display;
66
96
  }
67
- const escaped = groupSeparator.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
97
+ const escaped = escapeRegex(groupSeparator);
68
98
  return display.replace(new RegExp(escaped, "g"), "");
69
99
  }
70
100
  function valuesEqual(a, b) {
@@ -73,6 +103,7 @@ function valuesEqual(a, b) {
73
103
  export {
74
104
  formatNumberForDisplay,
75
105
  getLocaleNumberSeparators,
106
+ isAllowedIntermediateInput,
76
107
  parseNumberInput,
77
108
  removeGroupingFromDisplay,
78
109
  valuesEqual
@@ -1 +1 @@
1
- {"version":3,"file":"number-input-format.js","sources":["../../../src/components/number-input-field/number-input-format.ts"],"sourcesContent":["export type NumberInputFormatOptions = {\n decimalSeparator?: string;\n groupSeparator?: string;\n minFractionDigits?: number;\n maxFractionDigits?: number;\n};\n\nexport type LocaleNumberSeparators = {\n decimalSeparator: string;\n groupSeparator: string;\n};\n\nexport function getLocaleNumberSeparators(\n locale?: string | string[]\n): LocaleNumberSeparators {\n const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);\n return {\n decimalSeparator: parts.find((p) => p.type === 'decimal')?.value ?? '.',\n groupSeparator: parts.find((p) => p.type === 'group')?.value ?? '',\n };\n}\n\nexport function parseNumberInput(display: string): number {\n const trimmed = display.trim();\n if (trimmed === '' || trimmed === '-' || trimmed === '+') {\n return NaN;\n }\n\n const normalized = trimmed.replace(',', '.');\n\n const n = Number(normalized);\n return Number.isFinite(n) ? n : NaN;\n}\n\nfunction clampFractionDigits(\n minFractionDigits: number | undefined,\n maxFractionDigits: number | undefined\n): {min: number; max: number | undefined} {\n const min = Math.max(0, minFractionDigits ?? 0);\n const max =\n maxFractionDigits == undefined\n ? undefined\n : Math.max(min, maxFractionDigits);\n return {min, max};\n}\n\nexport function formatNumberForDisplay(\n value: number,\n options: NumberInputFormatOptions = {}\n): string {\n if (Number.isNaN(value)) {\n return '';\n }\n\n const localeSeparators = getLocaleNumberSeparators();\n const decimalSeparator =\n options.decimalSeparator ?? localeSeparators.decimalSeparator;\n const groupSeparator =\n options.groupSeparator ?? localeSeparators.groupSeparator;\n const {min: minFractionDigits, max: maxFractionDigits} = clampFractionDigits(\n options.minFractionDigits ?? 0,\n options.maxFractionDigits\n );\n const effectiveMaxFractionDigits = maxFractionDigits ?? 20;\n\n const usesLocaleSeparators =\n options.decimalSeparator === undefined &&\n options.groupSeparator === undefined;\n\n if (usesLocaleSeparators) {\n return new Intl.NumberFormat(undefined, {\n minimumFractionDigits: minFractionDigits,\n maximumFractionDigits: effectiveMaxFractionDigits,\n useGrouping: Boolean(groupSeparator),\n }).format(value);\n }\n\n const formatted = new Intl.NumberFormat('en-US', {\n minimumFractionDigits: minFractionDigits,\n maximumFractionDigits: effectiveMaxFractionDigits,\n useGrouping: Boolean(groupSeparator),\n }).format(value);\n\n if (decimalSeparator === '.' && groupSeparator === ',') {\n return formatted;\n }\n\n let result = formatted;\n if (groupSeparator) {\n result = result.replace(/,/g, groupSeparator);\n } else {\n result = result.replace(/,/g, '');\n }\n if (decimalSeparator !== '.') {\n result = result.replace('.', decimalSeparator);\n }\n\n return result;\n}\n\nexport function removeGroupingFromDisplay(\n display: string,\n options: NumberInputFormatOptions = {}\n): string {\n const localeSeparators = getLocaleNumberSeparators();\n const groupSeparator =\n options.groupSeparator ?? localeSeparators.groupSeparator;\n\n if (!groupSeparator) {\n return display;\n }\n\n const escaped = groupSeparator.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n return display.replace(new RegExp(escaped, 'g'), '');\n}\n\nexport function valuesEqual(a: number, b: number): boolean {\n return Object.is(a, b);\n}\n"],"names":[],"mappings":"AAYO,SAAS,0BACd,QACwB;AACxB,QAAM,QAAQ,IAAI,KAAK,aAAa,MAAM,EAAE,cAAc,OAAO;AACjE,SAAO;AAAA,IACL,kBAAkB,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,SAAS,GAAG,SAAS;AAAA,IACpE,gBAAgB,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,OAAO,GAAG,SAAS;AAAA,EAAA;AAEpE;AAEO,SAAS,iBAAiB,SAAyB;AACxD,QAAM,UAAU,QAAQ,KAAA;AACxB,MAAI,YAAY,MAAM,YAAY,OAAO,YAAY,KAAK;AACxD,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,QAAQ,QAAQ,KAAK,GAAG;AAE3C,QAAM,IAAI,OAAO,UAAU;AAC3B,SAAO,OAAO,SAAS,CAAC,IAAI,IAAI;AAClC;AAEA,SAAS,oBACP,mBACA,mBACwC;AACxC,QAAM,MAAM,KAAK,IAAI,GAAG,qBAAqB,CAAC;AAC9C,QAAM,MACJ,qBAAqB,SACjB,SACA,KAAK,IAAI,KAAK,iBAAiB;AACrC,SAAO,EAAC,KAAK,IAAA;AACf;AAEO,SAAS,uBACd,OACA,UAAoC,IAC5B;AACR,MAAI,OAAO,MAAM,KAAK,GAAG;AACvB,WAAO;AAAA,EACT;AAEA,QAAM,mBAAmB,0BAAA;AACzB,QAAM,mBACJ,QAAQ,oBAAoB,iBAAiB;AAC/C,QAAM,iBACJ,QAAQ,kBAAkB,iBAAiB;AAC7C,QAAM,EAAC,KAAK,mBAAmB,KAAK,sBAAqB;AAAA,IACvD,QAAQ,qBAAqB;AAAA,IAC7B,QAAQ;AAAA,EAAA;AAEV,QAAM,6BAA6B,qBAAqB;AAExD,QAAM,uBACJ,QAAQ,qBAAqB,UAC7B,QAAQ,mBAAmB;AAE7B,MAAI,sBAAsB;AACxB,WAAO,IAAI,KAAK,aAAa,QAAW;AAAA,MACtC,uBAAuB;AAAA,MACvB,uBAAuB;AAAA,MACvB,aAAa,QAAQ,cAAc;AAAA,IAAA,CACpC,EAAE,OAAO,KAAK;AAAA,EACjB;AAEA,QAAM,YAAY,IAAI,KAAK,aAAa,SAAS;AAAA,IAC/C,uBAAuB;AAAA,IACvB,uBAAuB;AAAA,IACvB,aAAa,QAAQ,cAAc;AAAA,EAAA,CACpC,EAAE,OAAO,KAAK;AAEf,MAAI,qBAAqB,OAAO,mBAAmB,KAAK;AACtD,WAAO;AAAA,EACT;AAEA,MAAI,SAAS;AACb,MAAI,gBAAgB;AAClB,aAAS,OAAO,QAAQ,MAAM,cAAc;AAAA,EAC9C,OAAO;AACL,aAAS,OAAO,QAAQ,MAAM,EAAE;AAAA,EAClC;AACA,MAAI,qBAAqB,KAAK;AAC5B,aAAS,OAAO,QAAQ,KAAK,gBAAgB;AAAA,EAC/C;AAEA,SAAO;AACT;AAEO,SAAS,0BACd,SACA,UAAoC,IAC5B;AACR,QAAM,mBAAmB,0BAAA;AACzB,QAAM,iBACJ,QAAQ,kBAAkB,iBAAiB;AAE7C,MAAI,CAAC,gBAAgB;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,UAAU,eAAe,QAAQ,uBAAuB,MAAM;AACpE,SAAO,QAAQ,QAAQ,IAAI,OAAO,SAAS,GAAG,GAAG,EAAE;AACrD;AAEO,SAAS,YAAY,GAAW,GAAoB;AACzD,SAAO,OAAO,GAAG,GAAG,CAAC;AACvB;"}
1
+ {"version":3,"file":"number-input-format.js","sources":["../../../src/components/number-input-field/number-input-format.ts"],"sourcesContent":["export type NumberInputFormatOptions = {\n decimalSeparator?: string;\n groupSeparator?: string;\n minFractionDigits?: number;\n maxFractionDigits?: number;\n};\n\nexport type LocaleNumberSeparators = {\n decimalSeparator: string;\n groupSeparator: string;\n};\n\nexport function getLocaleNumberSeparators(\n locale?: string | string[]\n): LocaleNumberSeparators {\n const parts = new Intl.NumberFormat(locale).formatToParts(12345.6);\n return {\n decimalSeparator: parts.find((p) => p.type === 'decimal')?.value ?? '.',\n groupSeparator: parts.find((p) => p.type === 'group')?.value ?? '',\n };\n}\n\nexport function parseNumberInput(display: string): number {\n const trimmed = display.trim();\n if (trimmed === '' || trimmed === '-' || trimmed === '+') {\n return NaN;\n }\n\n // Drop whitespace and apostrophe grouping that may appear in pasted or\n // locale-formatted numbers (e.g. `1 234`, `1'234`).\n let normalized = trimmed.replace(/[\\s']/g, '');\n\n const commaCount = (normalized.match(/,/g) ?? []).length;\n const dotCount = (normalized.match(/\\./g) ?? []).length;\n\n if (commaCount > 0 && dotCount > 0) {\n // Both separators present: the right-most one is the decimal separator,\n // the other is a grouping separator.\n const decimalSeparator =\n normalized.lastIndexOf(',') > normalized.lastIndexOf('.') ? ',' : '.';\n const groupSeparator = decimalSeparator === ',' ? '.' : ',';\n normalized = normalized.split(groupSeparator).join('');\n normalized = normalized.replace(decimalSeparator, '.');\n } else if (commaCount > 1) {\n // Multiple commas without a dot can only be grouping separators.\n normalized = normalized.split(',').join('');\n } else if (commaCount === 1) {\n // A single comma is treated as the decimal separator.\n normalized = normalized.replace(',', '.');\n } else if (dotCount > 1) {\n // Multiple dots without a comma can only be grouping separators.\n normalized = normalized.split('.').join('');\n }\n\n const n = Number(normalized);\n return Number.isFinite(n) ? n : NaN;\n}\n\nfunction escapeRegex(value: string): string {\n return value.replace(/[-.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Permissive per-keystroke validator used to reject non-numeric characters\n * before they reach the input. Allows half-typed states like `10.`, `-`, `,5`,\n * `1,234.`; final correctness is enforced by `parseNumberInput` at commit.\n *\n * Accepts: optional leading sign, digits, the active decimal separator,\n * the active group separator, and whitespace.\n */\nexport function isAllowedIntermediateInput(\n value: string,\n options: NumberInputFormatOptions = {}\n): boolean {\n if (value === '') return true;\n\n const localeSeparators = getLocaleNumberSeparators();\n const decimalSeparator =\n options.decimalSeparator ?? localeSeparators.decimalSeparator;\n const groupSeparator =\n options.groupSeparator ?? localeSeparators.groupSeparator;\n\n const allowedChars = new Set<string>([decimalSeparator]);\n if (groupSeparator) {\n allowedChars.add(groupSeparator);\n }\n const allowedClass = [...allowedChars].map(escapeRegex).join('') + '0-9 \\\\t';\n const pattern = new RegExp(`^[+\\\\-]?[${allowedClass}]*$`);\n return pattern.test(value);\n}\n\nfunction clampFractionDigits(\n minFractionDigits: number | undefined,\n maxFractionDigits: number | undefined\n): {min: number; max: number | undefined} {\n const min = Math.max(0, minFractionDigits ?? 0);\n const max =\n maxFractionDigits == undefined\n ? undefined\n : Math.max(min, maxFractionDigits);\n return {min, max};\n}\n\nexport function formatNumberForDisplay(\n value: number,\n options: NumberInputFormatOptions = {}\n): string {\n if (Number.isNaN(value)) {\n return '';\n }\n\n const localeSeparators = getLocaleNumberSeparators();\n const decimalSeparator =\n options.decimalSeparator ?? localeSeparators.decimalSeparator;\n const groupSeparator =\n options.groupSeparator ?? localeSeparators.groupSeparator;\n const {min: minFractionDigits, max: maxFractionDigits} = clampFractionDigits(\n options.minFractionDigits ?? 0,\n options.maxFractionDigits\n );\n const effectiveMaxFractionDigits = maxFractionDigits ?? 20;\n\n const usesLocaleSeparators =\n options.decimalSeparator === undefined &&\n options.groupSeparator === undefined;\n\n if (usesLocaleSeparators) {\n return new Intl.NumberFormat(undefined, {\n minimumFractionDigits: minFractionDigits,\n maximumFractionDigits: effectiveMaxFractionDigits,\n useGrouping: Boolean(groupSeparator),\n }).format(value);\n }\n\n const formatted = new Intl.NumberFormat('en-US', {\n minimumFractionDigits: minFractionDigits,\n maximumFractionDigits: effectiveMaxFractionDigits,\n useGrouping: Boolean(groupSeparator),\n }).format(value);\n\n if (decimalSeparator === '.' && groupSeparator === ',') {\n return formatted;\n }\n\n let result = formatted;\n if (groupSeparator) {\n result = result.replace(/,/g, groupSeparator);\n } else {\n result = result.replace(/,/g, '');\n }\n if (decimalSeparator !== '.') {\n result = result.replace('.', decimalSeparator);\n }\n\n return result;\n}\n\nexport function removeGroupingFromDisplay(\n display: string,\n options: NumberInputFormatOptions = {}\n): string {\n const localeSeparators = getLocaleNumberSeparators();\n const groupSeparator =\n options.groupSeparator ?? localeSeparators.groupSeparator;\n\n if (!groupSeparator) {\n return display;\n }\n\n const escaped = escapeRegex(groupSeparator);\n return display.replace(new RegExp(escaped, 'g'), '');\n}\n\nexport function valuesEqual(a: number, b: number): boolean {\n return Object.is(a, b);\n}\n"],"names":[],"mappings":"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"}
@@ -54,12 +54,6 @@ const compentStyle = css`
54
54
  :host([disabled]) .helper-text {
55
55
  color: var(--element-disabled-color);
56
56
  }
57
-
58
- :host([disabled]) .field-wrapper.has-unit-slot .unit-slot {
59
- color: var(--on-normal-disabled-color);
60
- border-color: var(--normal-disabled-border-color);
61
- background: var(--normal-disabled-background-color);
62
- }
63
57
  `;
64
58
  export {
65
59
  compentStyle as default
@@ -1 +1 @@
1
- {"version":3,"file":"stepper-box.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"stepper-box.css.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -30,22 +30,15 @@ export declare enum ObcStepperBoxType {
30
30
  * - `up-down`: Uses up and down chevron icons for vertical adjustment.
31
31
  * - `left-right`: Uses left and right chevron icons for horizontal adjustment.
32
32
  * - **Value Display:**
33
- * - Optional unit label via the `unit` slot.
33
+ * - Optional unit label via the `unit` property.
34
34
  * - **Helper Text:**
35
35
  * - When `helperText` is set, displays additional helper or status text below the control.
36
36
  * - **Icon Buttons:**
37
37
  * - Both increment and decrement actions are triggered by icon buttons, with icons adapting to the selected type.
38
- * - **Customizable Layout:**
39
- * - Supports flexible content via the `unit` slot.
40
38
  *
41
39
  * ### Usage Guidelines
42
40
  * 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.
43
41
  *
44
- * ### Slots
45
- * | Slot Name | Renders When... | Purpose |
46
- * |--------------- |--------------------------|-----------------------------------------|
47
- * | unit | If provided | Unit label (e.g., "km", "%"). |
48
- *
49
42
  * ### Events
50
43
  * - `down` – Fired when the decrement (left or down) button is clicked.
51
44
  * - `up` – Fired when the increment (right or up) button is clicked.
@@ -57,12 +50,9 @@ export declare enum ObcStepperBoxType {
57
50
  *
58
51
  * **Example:**
59
52
  * ```
60
- * <obc-stepper-box type="up-down" .value=${5} helperText="Set weight">
61
- * <div slot="unit">kg</div>
62
- * </obc-stepper-box>
53
+ * <obc-stepper-box type="up-down" value="5" unit="kg" helperText="Set weight"></obc-stepper-box>
63
54
  * ```
64
55
  *
65
- * @slot unit - Unit label (e.g., "km", "%")
66
56
  * @fires down {CustomEvent<{value: number}>} Fired when the decrement (left or down) button is clicked
67
57
  * @fires up {CustomEvent<{value: number}>} Fired when the increment (right or up) button is clicked
68
58
  * @fires input {CustomEvent<{value: string}>} Fired when the user types in the number input field
@@ -104,7 +94,7 @@ export declare class ObcStepperBox extends LitElement {
104
94
  */
105
95
  stepDown: number;
106
96
  /**
107
- * Unit text displayed inside the field. Overridden by the `unit` slot if assigned.
97
+ * Unit text displayed inside the field.
108
98
  */
109
99
  unit: string;
110
100
  /**
@@ -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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgDG;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"}
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;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"}
@@ -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` slot.\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 * - **Customizable Layout:**\n * - Supports flexible content via the `unit` slot.\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 * ### Slots\n * | Slot Name | Renders When... | Purpose |\n * |--------------- |--------------------------|-----------------------------------------|\n * | unit | If provided | Unit label (e.g., \"km\", \"%\"). |\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} helperText=\"Set weight\">\n * <div slot=\"unit\">kg</div>\n * </obc-stepper-box>\n * ```\n *\n * @slot unit - Unit label (e.g., \"km\", \"%\")\n * @fires down {CustomEvent<{value: number}>} Fired when the decrement (left or down) button is clicked\n * @fires up {CustomEvent<{value: number}>} Fired when the increment (right or up) button is clicked\n * @fires input {CustomEvent<{value: string}>} Fired when the user types in the number input field\n * @fires change {CustomEvent<{value: number | null}>} Fired when the numeric value changes from any source\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. Overridden by the `unit` slot if assigned.\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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"}
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 down {CustomEvent<{value: number}>} Fired when the decrement (left or down) button is clicked\n * @fires up {CustomEvent<{value: number}>} Fired when the increment (right or up) button is clicked\n * @fires input {CustomEvent<{value: string}>} Fired when the user types in the number input field\n * @fires change {CustomEvent<{value: number | null}>} Fired when the numeric value changes from any source\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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"}
@@ -37,6 +37,10 @@ export type ObcToggleButtonGroupValueChangeEvent = CustomEvent<{
37
37
  * - **External control mode:** When `externalControl` is true, the group emits selection events but does not
38
38
  * update its own `value` property, allowing parent components to manage state (useful for form libraries or
39
39
  * custom state management).
40
+ * - **Empty selection mode:** When `allowEmptySelection` is true, a `value` that does not match any enabled
41
+ * option leaves the group with no option selected, instead of defaulting to the first enabled option. Use
42
+ * this when a selection may legitimately be absent (e.g. unset, loading, or error states) so the UI does not
43
+ * imply a choice the user has not made.
40
44
  * - **Disabled state:** Setting `disabled` on the group disables all contained options at once. Individual
41
45
  * options can also be disabled independently while the group remains enabled.
42
46
  * - **Divider management:** Automatically shows visual dividers between options and hides the divider after
@@ -160,6 +164,16 @@ export declare class ObcToggleButtonGroup extends LitElement {
160
164
  * Defaults to false.
161
165
  */
162
166
  externalControl: boolean;
167
+ /**
168
+ * If true, a `value` that does not match any enabled option leaves the group with no option selected
169
+ * instead of defaulting to the first enabled option.
170
+ *
171
+ * This also applies when the currently selected option becomes disabled: the group clears its selection
172
+ * rather than falling back to another option.
173
+ *
174
+ * Defaults to false (the first enabled option is selected when the value does not match).
175
+ */
176
+ allowEmptySelection: boolean;
163
177
  /**
164
178
  * Disables the entire toggle button group and all contained options when true.
165
179
  *
@@ -1 +1 @@
1
- {"version":3,"file":"toggle-button-group.d.ts","sourceRoot":"","sources":["../../../src/components/toggle-button-group/toggle-button-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAEhE,OAAO,EACL,qBAAqB,EACrB,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,iDAAiD,CAAC;AAKzD,MAAM,MAAM,oCAAoC,GAAG,WAAW,CAAC;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwGG;AACH,qBACa,oBAAqB,SAAQ,UAAU;IAClD;;;;;;OAMG;IACuB,KAAK,SAAM;IAErC;;;;;OAKG;IACuB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAExD;;;;;;;;;OASG;IACuB,IAAI,4BAAkC;IAEhE;;;;;;;;OAQG;IACuB,OAAO,+BAAwC;IAEzE;;;;OAIG;IACwB,OAAO,UAAS;IAE3C;;;;;;OAMG;IACwB,eAAe,UAAS;IAEnD;;;;OAIG;IACuC,QAAQ,UAAS;IAE3D;;;;OAIG;IACuC,KAAK,UAAS;IAGxD,OAAO,EAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAE5C,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,eAAe;IAwCvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,uBAAuB,CAA6C;cAEzD,YAAY,CAC7B,kBAAkB,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,GACtE,IAAI;IA4DP,OAAO,CAAC,0BAA0B;IAUlC,iBAAiB,CAAC,KAAK,EAAE,KAAK;IAarB,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAsC5C,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAYzC,MAAM;IAoBf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,yBAAyB,EAAE,oBAAoB,CAAC;KACjD;CACF"}
1
+ {"version":3,"file":"toggle-button-group.d.ts","sourceRoot":"","sources":["../../../src/components/toggle-button-group/toggle-button-group.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAAE,cAAc,EAAkB,MAAM,KAAK,CAAC;AAEhE,OAAO,EACL,qBAAqB,EACrB,4BAA4B,EAC5B,yBAAyB,EAC1B,MAAM,iDAAiD,CAAC;AAKzD,MAAM,MAAM,oCAAoC,GAAG,WAAW,CAAC;IAC7D,KAAK,EAAE,MAAM,CAAC;IACd,aAAa,EAAE,MAAM,CAAC;CACvB,CAAC,CAAC;AAEH;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4GG;AACH,qBACa,oBAAqB,SAAQ,UAAU;IAClD;;;;;;OAMG;IACuB,KAAK,SAAM;IAErC;;;;;OAKG;IACuB,SAAS,EAAE,MAAM,GAAG,SAAS,CAAC;IAExD;;;;;;;;;OASG;IACuB,IAAI,4BAAkC;IAEhE;;;;;;;;OAQG;IACuB,OAAO,+BAAwC;IAEzE;;;;OAIG;IACwB,OAAO,UAAS;IAE3C;;;;;;OAMG;IACwB,eAAe,UAAS;IAEnD;;;;;;;;OAQG;IACwB,mBAAmB,UAAS;IAEvD;;;;OAIG;IACuC,QAAQ,UAAS;IAE3D;;;;OAIG;IACuC,KAAK,UAAS;IAGxD,OAAO,EAAG,UAAU,CAAC,qBAAqB,CAAC,CAAC;IAE5C,OAAO,CAAC,mBAAmB;IAK3B,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,gBAAgB;IAIxB,OAAO,CAAC,wBAAwB;IAKhC,OAAO,CAAC,eAAe;IA4CvB,OAAO,CAAC,eAAe;IAYvB,OAAO,CAAC,YAAY;IAgBpB,OAAO,CAAC,uBAAuB,CAA6C;cAEzD,YAAY,CAC7B,kBAAkB,EAAE,cAAc,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,WAAW,EAAE,OAAO,CAAC,GACtE,IAAI;IAgEP,OAAO,CAAC,0BAA0B;IAclC,iBAAiB,CAAC,KAAK,EAAE,KAAK;IAarB,UAAU,CAAC,iBAAiB,EAAE,cAAc;IAsC5C,OAAO,CAAC,iBAAiB,EAAE,cAAc;IAgBzC,MAAM;IAoBf,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,yBAAyB,EAAE,oBAAoB,CAAC;KACjD;CACF"}
@@ -22,6 +22,7 @@ let ObcToggleButtonGroup = class extends LitElement {
22
22
  this.variant = ObcToggleButtonOptionVariant.regular;
23
23
  this.hugText = false;
24
24
  this.externalControl = false;
25
+ this.allowEmptySelection = false;
25
26
  this.disabled = false;
26
27
  this.large = false;
27
28
  this._originalDisabledStates = /* @__PURE__ */ new Map();
@@ -59,8 +60,12 @@ let ObcToggleButtonGroup = class extends LitElement {
59
60
  this.setNoDivider();
60
61
  return;
61
62
  }
62
- const fallback = this.getFirstSelectableOption();
63
- newValue = fallback?.value || "";
63
+ if (this.allowEmptySelection) {
64
+ newValue = "";
65
+ } else {
66
+ const fallback = this.getFirstSelectableOption();
67
+ newValue = fallback?.value || "";
68
+ }
64
69
  }
65
70
  this.value = newValue;
66
71
  this.options.forEach((option) => {
@@ -138,9 +143,13 @@ let ObcToggleButtonGroup = class extends LitElement {
138
143
  }
139
144
  });
140
145
  if (!this.value || !this.getOptionByValue(this.value)) {
141
- const firstSelectable = this.getFirstSelectableOption();
142
- if (firstSelectable) {
143
- this.updateSelection(firstSelectable.value, false);
146
+ if (this.allowEmptySelection) {
147
+ this.updateSelection("", false);
148
+ } else {
149
+ const firstSelectable = this.getFirstSelectableOption();
150
+ if (firstSelectable) {
151
+ this.updateSelection(firstSelectable.value, false);
152
+ }
144
153
  }
145
154
  } else {
146
155
  this.updateSelection(this.value, false);
@@ -152,6 +161,10 @@ let ObcToggleButtonGroup = class extends LitElement {
152
161
  handleOptionDisabledChange() {
153
162
  const currentOption = this.getOptionByValue(this.value);
154
163
  if (currentOption?.disabled && this.hasAnyEnabledOption()) {
164
+ if (this.allowEmptySelection) {
165
+ this.updateSelection("");
166
+ return;
167
+ }
155
168
  const firstSelectable = this.getFirstSelectableOption();
156
169
  if (firstSelectable) {
157
170
  this.updateSelection(firstSelectable.value);
@@ -202,6 +215,10 @@ let ObcToggleButtonGroup = class extends LitElement {
202
215
  super.updated(changedProperties);
203
216
  const currentOption = this.getOptionByValue(this.value);
204
217
  if (currentOption?.disabled && this.hasAnyEnabledOption()) {
218
+ if (this.allowEmptySelection) {
219
+ this.updateSelection("");
220
+ return;
221
+ }
205
222
  const firstSelectable = this.getFirstSelectableOption();
206
223
  if (firstSelectable) {
207
224
  this.updateSelection(firstSelectable.value);
@@ -246,6 +263,9 @@ __decorateClass([
246
263
  __decorateClass([
247
264
  property({ type: Boolean })
248
265
  ], ObcToggleButtonGroup.prototype, "externalControl", 2);
266
+ __decorateClass([
267
+ property({ type: Boolean })
268
+ ], ObcToggleButtonGroup.prototype, "allowEmptySelection", 2);
249
269
  __decorateClass([
250
270
  property({ type: Boolean, reflect: true })
251
271
  ], ObcToggleButtonGroup.prototype, "disabled", 2);