@oicl/openbridge-webcomponents 2.0.0-next.65 → 2.0.0-next.67
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 +15992 -15907
- package/bundle/openbridge-webcomponents.bundle.js.map +1 -1
- package/custom-elements.json +138 -30
- package/dist/automation/automation-button/automation-button.css.js +9 -9
- package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.d.ts +1 -0
- package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.d.ts.map +1 -1
- package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.js +9 -28
- package/dist/automation/valve-analoge-two-way-icon/valve-analog-two-way-icon.js.map +1 -1
- package/dist/components/accordion-card/accordion-card.css.js +1 -1
- package/dist/components/dropdown-button/dropdown-button.d.ts +11 -0
- package/dist/components/dropdown-button/dropdown-button.d.ts.map +1 -1
- package/dist/components/dropdown-button/dropdown-button.js +24 -2
- package/dist/components/dropdown-button/dropdown-button.js.map +1 -1
- package/dist/components/keyboard-numeric/keyboard-numeric.d.ts +1 -2
- package/dist/components/keyboard-numeric/keyboard-numeric.d.ts.map +1 -1
- package/dist/components/keyboard-numeric/keyboard-numeric.js +10 -15
- package/dist/components/keyboard-numeric/keyboard-numeric.js.map +1 -1
- package/dist/components/number-input-field/number-input-field.d.ts +9 -0
- package/dist/components/number-input-field/number-input-field.d.ts.map +1 -1
- package/dist/components/number-input-field/number-input-field.js +30 -1
- package/dist/components/number-input-field/number-input-field.js.map +1 -1
- package/dist/components/number-input-field/number-input-format.d.ts +9 -0
- package/dist/components/number-input-field/number-input-format.d.ts.map +1 -1
- package/dist/components/number-input-field/number-input-format.js +33 -2
- package/dist/components/number-input-field/number-input-format.js.map +1 -1
- package/dist/components/stepper-box/stepper-box.css.js +0 -6
- package/dist/components/stepper-box/stepper-box.css.js.map +1 -1
- package/dist/components/stepper-box/stepper-box.d.ts +3 -13
- package/dist/components/stepper-box/stepper-box.d.ts.map +1 -1
- package/dist/components/stepper-box/stepper-box.js.map +1 -1
- package/dist/components/toggle-button-group/toggle-button-group.d.ts +14 -0
- package/dist/components/toggle-button-group/toggle-button-group.d.ts.map +1 -1
- package/dist/components/toggle-button-group/toggle-button-group.js +25 -5
- package/dist/components/toggle-button-group/toggle-button-group.js.map +1 -1
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.css.js +4 -0
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.css.js.map +1 -1
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.d.ts +1 -0
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.d.ts.map +1 -1
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.js +13 -1
- package/dist/integration-systems/integration-fleet-button/integration-fleet-button.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dropdown-button.js","sources":["../../../src/components/dropdown-button/dropdown-button.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS, nothing, PropertyValues} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport compentStyle from './dropdown-button.css?inline';\nimport '../../icons/icon-drop-down-google.js';\nimport '../button/button.js';\nimport {customElement} from '../../decorator.js';\nimport {classMap} from 'lit/directives/class-map.js';\n\nexport enum DropdownButtonType {\n label = 'label',\n icon = 'icon',\n labelIcon = 'label-icon',\n}\n\nexport type ObcDropdownButtonChangeEvent = CustomEvent<{\n value: string;\n label: string;\n}>;\n\nexport type DropdownButtonOption = {\n value: string;\n label: string;\n level?: number;\n};\n\n/**\n * `<obc-dropdown-button>` – A dropdown select component for choosing a single option from a list.\n *\n * Presents a styled dropdown menu with a visible label and icon, allowing users to select one value from a set of options. The component displays the currently selected label and provides a native select element for accessibility and keyboard navigation.\n *\n * ### Features\n * - **Single selection:** Allows users to pick one option from a provided list.\n * - **Customizable options:** Accepts an array of `{value, label, level?}` objects for flexible option content and optional indentation (via `level`).\n * - **Visual label and icon:** Shows the selected label and a dropdown arrow icon (`<obi-drop-down-google>`).\n * - **Full width mode:** Can expand to fill the width of its container using the `fullWidth` property.\n * - **Accessible:** Uses a native `<select>` element under the hood for keyboard and screen reader support.\n * - **Focus styling:** Highlights the visible wrapper when the select is focused.\n *\n * ### Variants\n * - **Default:** Renders at intrinsic width, sized to content.\n * - **Full Width:** When `fullWidth` is true, stretches to fill the parent container.\n *\n * ### Usage Guidelines\n * Use `<obc-dropdown-button>` when you need a compact, accessible dropdown for single-choice selection. Ideal for forms, filters, and settings where users must pick one value from a list. Options can be grouped visually by providing a `level` property for indentation.\n *\n * **TODO(designer):** Confirm if there are recommended use cases or constraints for the `level` property (e.g., maximum nesting, visual grouping intent).\n *\n * ### Properties\n * - `options` (Array): List of selectable options, each with a `value` (string), `label` (string), and optional `level` (number) for indentation.\n * - `value` (string): The currently selected option's value. If not set, defaults to the first option.\n * - `fullWidth` (boolean): Expands the component to fill its container when true. Default is false.\n *\n * ### Events\n * - `dropdown-change` – Fired when the user selects a different option. The event detail includes `{ value, label }` of the selected option.\n * - `change` – Fired when the user selects a different option. The event detail includes `{ value, label }` of the selected option.\n *\n * ### Best Practices\n * - Always provide a non-empty `options` array; if empty, the select will show no label or options.\n * - Use unique `value` strings for each option to ensure correct selection and event detail.\n * - For grouped or indented options, set the `level` property (e.g., `level: 2` for sub-options).\n * - Avoid using for multi-select scenarios; use a dedicated multi-select component if multiple selections are needed.\n *\n * ### Example:\n * ```html\n * <obc-dropdown-button\n * .options=${[\n * { value: 'volvo', label: 'Volvo' },\n * { value: 'xc90', label: 'XC 90', level: 2 },\n * { value: 'mercedes', label: 'Mercedes' },\n * { value: 'audi', label: 'Audi' }\n * ]}\n * value=\"volvo\"\n * ></obc-dropdown-button>\n * ```\n *\n * @slot - (No named slots; all content is provided via properties)\n * @slot icon - Icon displayed at the start of the button when `type` is `icon` or `label-icon`.\n * @fires dropdown-change {ObcDropdownButtonChangeEvent} - Fires when the value of the select changes\n * @fires change {ObcDropdownButtonChangeEvent} - Fires when the value of the select changes\n */\n@customElement('obc-dropdown-button')\nexport class ObcDropdownButton extends LitElement {\n /**\n * List of selectable options. Each option is an object with a `value` (string), `label` (string), and optional `level` (number) for indentation/grouping.\n *\n * Example:\n * [\n * { value: 'volvo', label: 'Volvo' },\n * { value: 'xc90', label: 'XC 90', level: 2 }\n * ]\n */\n @property({type: Array}) options: DropdownButtonOption[] = [];\n\n /**\n * The value of the currently selected option. If not set, defaults to the first option in the list.\n */\n @property({type: String}) value: string | undefined;\n @property({type: Boolean}) disabled: boolean = false;\n\n /**\n * If true, the select expands to fill the width of its container. Default is false.\n */\n @property({type: Boolean}) fullWidth = false;\n\n /**\n * Controls the button's display type.\n * - `label`: Text label only (default)\n * - `icon`: Icon only, no label\n * - `label-icon`: Icon before the label\n */\n @property({type: String}) type: DropdownButtonType = DropdownButtonType.label;\n\n /**\n * If true, the dropdown menu opens above the button.\n */\n @property({type: Boolean}) openTop = false;\n\n /**\n * If true, the select is integration style. Default is false, only for integration bar.\n */\n @property({type: Boolean}) integration = false;\n\n @property({type: Boolean}) flat = false;\n\n @state() private selectedValue = '';\n @state() private selectedLabel = '';\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.updateSelectedValues();\n }\n\n override willUpdate(changedProperties: PropertyValues): void {\n if (changedProperties.has('value') || changedProperties.has('options')) {\n this.updateSelectedValues();\n }\n }\n\n private updateSelectedValues(): void {\n if (this.options.length === 0) {\n this.selectedValue = '';\n this.selectedLabel = '';\n return;\n }\n this.selectedValue = this.value || this.options[0].value;\n this.selectedLabel = this.value\n ? this.options.find((item) => item.value === this.value)?.label || ''\n : this.options[0].label;\n }\n\n override render() {\n return html`\n <div\n class=${classMap({\n wrapper: true,\n 'full-width': this.fullWidth,\n 'open-top': this.openTop,\n integration: this.integration,\n flat: this.flat && !this.integration,\n disabled: this.disabled,\n })}\n >\n <div class=\"visible-wrapper\">\n ${this.type !== DropdownButtonType.label\n ? html`<div class=\"icon-container\"><slot name=\"icon\"></slot></div>`\n : nothing}\n ${this.type !== DropdownButtonType.icon\n ? html`<div class=\"label\">${this.selectedLabel}</div>`\n : nothing}\n <div class=\"icon\">\n <obi-drop-down-google></obi-drop-down-google>\n </div>\n </div>\n <select @change=${this.changeHandler} ?disabled=${this.disabled}>\n ${this.options.map((item) => {\n const indent = item.level ? (item.level - 1) * 2 : 0;\n const indentText = [];\n for (let i = 0; i < indent; i++) {\n indentText.push(html` `);\n }\n\n return html`<option\n value=${item.value}\n ?selected=${item.value === this.selectedValue}\n >\n ${indentText}${item.label}\n </option>`;\n })}\n </select>\n </div>\n `;\n }\n\n /**\n * Handles the dropdown-change and change event when a new option is selected. Updates the selected value and label, and dispatches a `dropdown-change` and 'change' event with the new selection.\n *\n * @fires dropdown-change {ObcDropdownButtonChangeEvent} - Fired when the user selects a different option.\n * @fires change {ObcDropdownButtonChangeEvent} - Fired when the user selects a different option.\n */\n private changeHandler(event: Event) {\n const target = event.target as HTMLSelectElement;\n this.selectedValue = target.value;\n this.selectedLabel = this.options\n .find((item) => item.value === this.selectedValue)!\n .label.trim();\n this.dispatchEvent(\n new CustomEvent('dropdown-change', {\n detail: {value: this.selectedValue, label: this.selectedLabel},\n })\n );\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: this.selectedValue, label: this.selectedLabel},\n })\n );\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-dropdown-button': ObcDropdownButton;\n }\n}\n"],"names":["DropdownButtonType"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"dropdown-button.js","sources":["../../../src/components/dropdown-button/dropdown-button.ts"],"sourcesContent":["import {LitElement, html, unsafeCSS, nothing, PropertyValues} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport compentStyle from './dropdown-button.css?inline';\nimport '../../icons/icon-drop-down-google.js';\nimport '../button/button.js';\nimport {customElement} from '../../decorator.js';\nimport {classMap} from 'lit/directives/class-map.js';\n\nexport enum DropdownButtonType {\n label = 'label',\n icon = 'icon',\n labelIcon = 'label-icon',\n}\n\nexport type ObcDropdownButtonChangeEvent = CustomEvent<{\n value: string;\n label: string;\n}>;\n\nexport type DropdownButtonOption = {\n value: string;\n label: string;\n level?: number;\n};\n\n/**\n * `<obc-dropdown-button>` – A dropdown select component for choosing a single option from a list.\n *\n * Presents a styled dropdown menu with a visible label and icon, allowing users to select one value from a set of options. The component displays the currently selected label and provides a native select element for accessibility and keyboard navigation.\n *\n * ### Features\n * - **Single selection:** Allows users to pick one option from a provided list.\n * - **Customizable options:** Accepts an array of `{value, label, level?}` objects for flexible option content and optional indentation (via `level`).\n * - **Visual label and icon:** Shows the selected label and a dropdown arrow icon (`<obi-drop-down-google>`).\n * - **Full width mode:** Can expand to fill the width of its container using the `fullWidth` property.\n * - **Accessible:** Uses a native `<select>` element under the hood for keyboard and screen reader support.\n * - **Focus styling:** Highlights the visible wrapper when the select is focused.\n *\n * ### Variants\n * - **Default:** Renders at intrinsic width, sized to content.\n * - **Full Width:** When `fullWidth` is true, stretches to fill the parent container.\n *\n * ### Usage Guidelines\n * Use `<obc-dropdown-button>` when you need a compact, accessible dropdown for single-choice selection. Ideal for forms, filters, and settings where users must pick one value from a list. Options can be grouped visually by providing a `level` property for indentation.\n *\n * **TODO(designer):** Confirm if there are recommended use cases or constraints for the `level` property (e.g., maximum nesting, visual grouping intent).\n *\n * ### Properties\n * - `options` (Array): List of selectable options, each with a `value` (string), `label` (string), and optional `level` (number) for indentation.\n * - `value` (string): The currently selected option's value. If not set, defaults to the first option.\n * - `fullWidth` (boolean): Expands the component to fill its container when true. Default is false.\n * - `allowEmptySelection` (boolean): When true, a `value` that does not match any option leaves the button with no option selected, showing `placeholder` instead of defaulting to the first option. Default is false.\n * - `placeholder` (string): Text shown when nothing is selected and `allowEmptySelection` is true. Default is an empty string.\n *\n * ### Events\n * - `dropdown-change` – Fired when the user selects a different option. The event detail includes `{ value, label }` of the selected option.\n * - `change` – Fired when the user selects a different option. The event detail includes `{ value, label }` of the selected option.\n *\n * ### Best Practices\n * - Always provide a non-empty `options` array; if empty, the select will show no label or options.\n * - Use unique `value` strings for each option to ensure correct selection and event detail.\n * - For grouped or indented options, set the `level` property (e.g., `level: 2` for sub-options).\n * - Avoid using for multi-select scenarios; use a dedicated multi-select component if multiple selections are needed.\n *\n * ### Example:\n * ```html\n * <obc-dropdown-button\n * .options=${[\n * { value: 'volvo', label: 'Volvo' },\n * { value: 'xc90', label: 'XC 90', level: 2 },\n * { value: 'mercedes', label: 'Mercedes' },\n * { value: 'audi', label: 'Audi' }\n * ]}\n * value=\"volvo\"\n * ></obc-dropdown-button>\n * ```\n *\n * @slot - (No named slots; all content is provided via properties)\n * @slot icon - Icon displayed at the start of the button when `type` is `icon` or `label-icon`.\n * @fires dropdown-change {ObcDropdownButtonChangeEvent} - Fires when the value of the select changes\n * @fires change {ObcDropdownButtonChangeEvent} - Fires when the value of the select changes\n */\n@customElement('obc-dropdown-button')\nexport class ObcDropdownButton extends LitElement {\n /**\n * List of selectable options. Each option is an object with a `value` (string), `label` (string), and optional `level` (number) for indentation/grouping.\n *\n * Example:\n * [\n * { value: 'volvo', label: 'Volvo' },\n * { value: 'xc90', label: 'XC 90', level: 2 }\n * ]\n */\n @property({type: Array}) options: DropdownButtonOption[] = [];\n\n /**\n * The value of the currently selected option. If not set, defaults to the first option in the list.\n */\n @property({type: String}) value: string | undefined;\n @property({type: Boolean}) disabled: boolean = false;\n\n /**\n * If true, the select expands to fill the width of its container. Default is false.\n */\n @property({type: Boolean}) fullWidth = false;\n\n /**\n * If true, a `value` that does not match any option leaves the button with no option selected,\n * showing `placeholder` instead of defaulting to the first option. Default is false.\n */\n @property({type: Boolean}) allowEmptySelection = false;\n\n /**\n * Text shown when nothing is selected and `allowEmptySelection` is true. Default is an empty string.\n */\n @property({type: String}) placeholder = '';\n\n /**\n * Controls the button's display type.\n * - `label`: Text label only (default)\n * - `icon`: Icon only, no label\n * - `label-icon`: Icon before the label\n */\n @property({type: String}) type: DropdownButtonType = DropdownButtonType.label;\n\n /**\n * If true, the dropdown menu opens above the button.\n */\n @property({type: Boolean}) openTop = false;\n\n /**\n * If true, the select is integration style. Default is false, only for integration bar.\n */\n @property({type: Boolean}) integration = false;\n\n @property({type: Boolean}) flat = false;\n\n @state() private selectedValue = '';\n @state() private selectedLabel = '';\n\n override connectedCallback(): void {\n super.connectedCallback();\n this.updateSelectedValues();\n }\n\n override willUpdate(changedProperties: PropertyValues): void {\n if (changedProperties.has('value') || changedProperties.has('options')) {\n this.updateSelectedValues();\n }\n }\n\n private updateSelectedValues(): void {\n if (this.options.length === 0) {\n this.selectedValue = '';\n this.selectedLabel = '';\n return;\n }\n const match = this.value\n ? this.options.find((item) => item.value === this.value)\n : undefined;\n if (match) {\n this.selectedValue = match.value;\n this.selectedLabel = match.label;\n return;\n }\n if (this.allowEmptySelection) {\n this.selectedValue = '';\n this.selectedLabel = this.placeholder;\n return;\n }\n this.selectedValue = this.options[0].value;\n this.selectedLabel = this.options[0].label;\n }\n\n override render() {\n return html`\n <div\n class=${classMap({\n wrapper: true,\n 'full-width': this.fullWidth,\n 'open-top': this.openTop,\n integration: this.integration,\n flat: this.flat && !this.integration,\n disabled: this.disabled,\n })}\n >\n <div class=\"visible-wrapper\">\n ${this.type !== DropdownButtonType.label\n ? html`<div class=\"icon-container\"><slot name=\"icon\"></slot></div>`\n : nothing}\n ${this.type !== DropdownButtonType.icon\n ? html`<div class=\"label\">${this.selectedLabel}</div>`\n : nothing}\n <div class=\"icon\">\n <obi-drop-down-google></obi-drop-down-google>\n </div>\n </div>\n <select @change=${this.changeHandler} ?disabled=${this.disabled}>\n ${this.allowEmptySelection && this.selectedValue === ''\n ? html`<option value=\"\" disabled selected hidden>\n ${this.placeholder}\n </option>`\n : nothing}\n ${this.options.map((item) => {\n const indent = item.level ? (item.level - 1) * 2 : 0;\n const indentText = [];\n for (let i = 0; i < indent; i++) {\n indentText.push(html` `);\n }\n\n return html`<option\n value=${item.value}\n ?selected=${item.value === this.selectedValue}\n >\n ${indentText}${item.label}\n </option>`;\n })}\n </select>\n </div>\n `;\n }\n\n /**\n * Handles the dropdown-change and change event when a new option is selected. Updates the selected value and label, and dispatches a `dropdown-change` and 'change' event with the new selection.\n *\n * @fires dropdown-change {ObcDropdownButtonChangeEvent} - Fired when the user selects a different option.\n * @fires change {ObcDropdownButtonChangeEvent} - Fired when the user selects a different option.\n */\n private changeHandler(event: Event) {\n const target = event.target as HTMLSelectElement;\n this.selectedValue = target.value;\n this.selectedLabel = this.options\n .find((item) => item.value === this.selectedValue)!\n .label.trim();\n this.dispatchEvent(\n new CustomEvent('dropdown-change', {\n detail: {value: this.selectedValue, label: this.selectedLabel},\n })\n );\n this.dispatchEvent(\n new CustomEvent('change', {\n detail: {value: this.selectedValue, label: this.selectedLabel},\n })\n );\n }\n\n static override styles = unsafeCSS(compentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-dropdown-button': ObcDropdownButton;\n }\n}\n"],"names":["DropdownButtonType"],"mappings":"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"}
|
|
@@ -41,10 +41,9 @@ export declare class ObcKeyboardNumeric extends LitElement {
|
|
|
41
41
|
/** Optional regex pattern for validation (applies to both keyboard and direct input) */
|
|
42
42
|
validationPattern: string;
|
|
43
43
|
private content;
|
|
44
|
+
private get effectiveValidationPattern();
|
|
44
45
|
/** Validates if a character can be added to the current value */
|
|
45
46
|
private canAddCharacter;
|
|
46
|
-
/** Validates that all characters in a value are allowed */
|
|
47
|
-
private isValidValue;
|
|
48
47
|
private handleCloseClick;
|
|
49
48
|
private handleKeyPress;
|
|
50
49
|
private handleCalculationKey;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard-numeric.d.ts","sourceRoot":"","sources":["../../../src/components/keyboard-numeric/keyboard-numeric.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,sCAAsC,CAAC;AAC9C,OAAO,qBAAqB,CAAC;AAC7B,OAAO,4BAA4B,CAAC;AACpC,OAAO,8BAA8B,CAAC;AACtC,OAAO,8BAA8B,CAAC;AACtC,OAAO,4BAA4B,CAAC;AACpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,6CAA6C,CAAC;AACrD,OAAO,EAEL,4BAA4B,EAG7B,MAAM,6CAA6C,CAAC;AAGrD,oBAAY,sBAAsB;IAChC,QAAQ,aAAa;IACrB,IAAI,SAAS;CACd;AAED,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;
|
|
1
|
+
{"version":3,"file":"keyboard-numeric.d.ts","sourceRoot":"","sources":["../../../src/components/keyboard-numeric/keyboard-numeric.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,UAAU,EAA2B,MAAM,KAAK,CAAC;AAKzD,OAAO,+BAA+B,CAAC;AACvC,OAAO,kCAAkC,CAAC;AAC1C,OAAO,sCAAsC,CAAC;AAC9C,OAAO,qBAAqB,CAAC;AAC7B,OAAO,4BAA4B,CAAC;AACpC,OAAO,8BAA8B,CAAC;AACtC,OAAO,8BAA8B,CAAC;AACtC,OAAO,4BAA4B,CAAC;AACpC,OAAO,2BAA2B,CAAC;AACnC,OAAO,6CAA6C,CAAC;AACrD,OAAO,EAEL,4BAA4B,EAG7B,MAAM,6CAA6C,CAAC;AAGrD,oBAAY,sBAAsB;IAChC,QAAQ,aAAa;IACrB,IAAI,SAAS;CACd;AAED,oBAAY,yBAAyB;IACnC,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAsDD,qBACa,kBAAmB,SAAQ,UAAU;IACtB,IAAI,EAAE,sBAAsB,CACpB;IAElC,wFAAwF;IAC7D,WAAW,UAAS;IAE/C,qCAAqC;IACX,KAAK,SAAoB;IAEnD,0BAA0B;IACA,KAAK,SAAM;IAErC,2DAA2D;IAChC,cAAc,UAAS;IAElD,8EAA8E;IACnD,WAAW,UAAS;IAE/C,0DAA0D;IAChC,UAAU,SAAM;IAE1C,mDAAmD;IACxB,cAAc,UAAS;IAElD,kCAAkC;IACR,IAAI,SAAM;IAEpC,oCAAoC;IACV,mBAAmB,EAAE,4BAA4B,CACtC;IAErC,wFAAwF;IAC9D,iBAAiB,SAAM;IAExC,OAAO,CAAC,OAAO,CACY;IAEpC,OAAO,KAAK,0BAA0B,GAKrC;IAED,iEAAiE;IACjE,OAAO,CAAC,eAAe;IA+BvB,OAAO,CAAC,gBAAgB;IAMxB,OAAO,CAAC,cAAc;IActB,OAAO,CAAC,oBAAoB;IAS5B,OAAO,CAAC,kBAAkB;IA0B1B,OAAO,CAAC,eAAe;IAOvB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,UAAU;IAWlB,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,kBAAkB;IAU1B,OAAO,CAAC,oBAAoB;IAuC5B,OAAO,CAAC,cAAc;IA6BtB,OAAO,CAAC,gBAAgB;cAqBL,MAAM;IAyEzB,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,sBAAsB,EAAE,kBAAkB,CAAC;KAC5C;CACF"}
|
|
@@ -75,6 +75,9 @@ const ALLOWED_CHARS = [
|
|
|
75
75
|
"/"
|
|
76
76
|
];
|
|
77
77
|
const OPERATORS = ["+", "-", "–", "×", "÷", "*", "/"];
|
|
78
|
+
const ALLOWED_CHARS_PATTERN = `^[${ALLOWED_CHARS.map(
|
|
79
|
+
(c) => c.replace(/[-.*+?^${}()|[\]\\]/g, "\\$&")
|
|
80
|
+
).join("")}]*$`;
|
|
78
81
|
let ObcKeyboardNumeric = class extends LitElement {
|
|
79
82
|
constructor() {
|
|
80
83
|
super(...arguments);
|
|
@@ -91,6 +94,12 @@ let ObcKeyboardNumeric = class extends LitElement {
|
|
|
91
94
|
this.validationPattern = "";
|
|
92
95
|
this.content = "numbers";
|
|
93
96
|
}
|
|
97
|
+
get effectiveValidationPattern() {
|
|
98
|
+
if (!this.validationPattern) {
|
|
99
|
+
return ALLOWED_CHARS_PATTERN;
|
|
100
|
+
}
|
|
101
|
+
return `^(?=${ALLOWED_CHARS_PATTERN})(?=${this.validationPattern}).*$`;
|
|
102
|
+
}
|
|
94
103
|
/** Validates if a character can be added to the current value */
|
|
95
104
|
canAddCharacter(char) {
|
|
96
105
|
const potentialValue = this.value + char;
|
|
@@ -112,10 +121,6 @@ let ObcKeyboardNumeric = class extends LitElement {
|
|
|
112
121
|
}
|
|
113
122
|
return true;
|
|
114
123
|
}
|
|
115
|
-
/** Validates that all characters in a value are allowed */
|
|
116
|
-
isValidValue(value) {
|
|
117
|
-
return [...value].every((char) => ALLOWED_CHARS.includes(char));
|
|
118
|
-
}
|
|
119
124
|
handleCloseClick() {
|
|
120
125
|
this.dispatchEvent(
|
|
121
126
|
new CustomEvent("close-click", { bubbles: true, composed: true })
|
|
@@ -190,17 +195,6 @@ let ObcKeyboardNumeric = class extends LitElement {
|
|
|
190
195
|
handleInput(e) {
|
|
191
196
|
const input = e.target;
|
|
192
197
|
const newValue = input.displayValue;
|
|
193
|
-
if (this.validationPattern && newValue) {
|
|
194
|
-
const regex = new RegExp(this.validationPattern);
|
|
195
|
-
if (!regex.test(newValue)) {
|
|
196
|
-
input.displayOverride = this.value;
|
|
197
|
-
return;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
if (newValue && !this.isValidValue(newValue)) {
|
|
201
|
-
input.displayOverride = this.value;
|
|
202
|
-
return;
|
|
203
|
-
}
|
|
204
198
|
this.value = newValue;
|
|
205
199
|
this.dispatchValueChange();
|
|
206
200
|
}
|
|
@@ -284,6 +278,7 @@ let ObcKeyboardNumeric = class extends LitElement {
|
|
|
284
278
|
.textAlign=${this.inputFieldTextAlign}
|
|
285
279
|
.size=${ObcNumberInputFieldSize.Large}
|
|
286
280
|
.helperText=${this.helperText}
|
|
281
|
+
.validationPattern=${this.effectiveValidationPattern}
|
|
287
282
|
?hasLeadingIcon=${this.hasLeadingIcon}
|
|
288
283
|
placeholder="00.0"
|
|
289
284
|
@input=${this.handleInput}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"keyboard-numeric.js","sources":["../../../src/components/keyboard-numeric/keyboard-numeric.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './keyboard-numeric.css?inline';\n\nimport '../icon-button/icon-button.js';\nimport '../../icons/icon-close-google.js';\nimport '../../icons/icon-backspace-google.js';\nimport '../button/button.js';\nimport '../../icons/icon-up-iec.js';\nimport '../../icons/icon-down-iec.js';\nimport '../../icons/icon-multiply.js';\nimport '../../icons/icon-divide.js';\nimport '../../icons/icon-equal.js';\nimport '../number-input-field/number-input-field.js';\nimport {\n ObcNumberInputField,\n ObcNumberInputFieldTextAlign,\n ObcNumberInputFieldSize,\n ObcNumberInputFieldInputEvent,\n} from '../number-input-field/number-input-field.js';\nimport {parseNumberInput} from '../number-input-field/number-input-format.js';\n\nexport enum ObcKeyboardNumericType {\n Floating = 'floating',\n Flat = 'flat',\n}\n\nexport enum ObcKeyboardNumericContent {\n Numbers = 'numbers',\n Symbols = 'symbols',\n}\n\n// Key layouts\nconst NUMBER_KEYS = [\n ['1', '2', '3'],\n ['4', '5', '6'],\n ['7', '8', '9'],\n ['–', '0', ','],\n];\n\nconst SYMBOL_KEYS = [\n ['!', '@', '#'],\n ['$', '%', '&'],\n ['(', ')', '/'],\n ['–', '0', ','],\n];\n\n// All allowed characters for validation\nconst ALLOWED_CHARS = [\n '0',\n '1',\n '2',\n '3',\n '4',\n '5',\n '6',\n '7',\n '8',\n '9',\n '–',\n '-',\n ',',\n '.',\n '+',\n '×',\n '÷',\n '=',\n '!',\n '@',\n '#',\n '$',\n '%',\n '&',\n '(',\n ')',\n '/',\n];\n\nconst OPERATORS = ['+', '-', '–', '×', '÷', '*', '/'];\n\n@customElement('obc-keyboard-numeric')\nexport class ObcKeyboardNumeric extends LitElement {\n @property({type: String}) type: ObcKeyboardNumericType =\n ObcKeyboardNumericType.Floating;\n\n /** Shows the top bar with label and close button (only applicable for floating type) */\n @property({type: Boolean}) hasTitleBar = false;\n\n /** Label displayed in the top bar */\n @property({type: String}) label = 'Parameter name';\n\n /** Current input value */\n @property({type: String}) value = '';\n\n /** Shows the calculation row with +, -, ×, ÷, = buttons */\n @property({type: Boolean}) hasCalculation = false;\n\n /** Shows the #+= / 123 toggle button to switch between numbers and symbols */\n @property({type: Boolean}) has2Symbols = false;\n\n /** Helper text content displayed below the input field */\n @property({type: String}) helperText = '';\n\n /** Shows a leading icon slot in the input field */\n @property({type: Boolean}) hasLeadingIcon = false;\n\n /** Unit text (%, kg, °C, etc.) */\n @property({type: String}) unit = '';\n\n /** Text alignment in input field */\n @property({type: String}) inputFieldTextAlign: ObcNumberInputFieldTextAlign =\n ObcNumberInputFieldTextAlign.Right;\n\n /** Optional regex pattern for validation (applies to both keyboard and direct input) */\n @property({type: String}) validationPattern = '';\n\n @state() private content: ObcKeyboardNumericContent =\n ObcKeyboardNumericContent.Numbers;\n\n /** Validates if a character can be added to the current value */\n private canAddCharacter(char: string): boolean {\n const potentialValue = this.value + char;\n\n if (this.validationPattern) {\n const regex = new RegExp(this.validationPattern);\n return regex.test(potentialValue);\n }\n\n if (!ALLOWED_CHARS.includes(char)) {\n return false;\n }\n\n const lastChar = this.value.slice(-1);\n\n // Only one decimal separator per number segment\n if (char === ',' || char === '.') {\n const segments = this.value.split(/[+\\-–×÷*/]/);\n const currentSegment = segments[segments.length - 1] || '';\n return !currentSegment.includes(',') && !currentSegment.includes('.');\n }\n\n // Minus/plus allowed at beginning or after an operator\n if (char === '–' || char === '-' || char === '+') {\n return (\n this.value === '' || this.value === '0' || OPERATORS.includes(lastChar)\n );\n }\n\n return true;\n }\n\n /** Validates that all characters in a value are allowed */\n private isValidValue(value: string): boolean {\n return [...value].every((char) => ALLOWED_CHARS.includes(char));\n }\n\n private handleCloseClick() {\n this.dispatchEvent(\n new CustomEvent('close-click', {bubbles: true, composed: true})\n );\n }\n\n private handleKeyPress(key: string) {\n if (this.canAddCharacter(key)) {\n if (\n (key === '–' || key === '-' || key === '+') &&\n (this.value === '' || this.value === '0')\n ) {\n this.value = key;\n } else {\n this.value += key;\n }\n this.dispatchValueChange();\n }\n }\n\n private handleCalculationKey(key: string) {\n if (key === '=') {\n this.evaluateExpression();\n } else {\n this.value += key;\n this.dispatchValueChange();\n }\n }\n\n private evaluateExpression() {\n if (!this.value) return;\n\n try {\n const expression = this.value\n .replace(/×/g, '*')\n .replace(/÷/g, '/')\n .replace(/–/g, '-')\n .replace(/,/g, '.');\n\n if (!/^[\\d+\\-*/().]+$/.test(expression)) {\n return;\n }\n\n const result = new Function(`return (${expression})`)();\n\n if (typeof result === 'number' && isFinite(result)) {\n const rounded = Math.round(result * 1000000) / 1000000;\n this.value = String(rounded).replace('.', ',');\n this.dispatchValueChange();\n }\n } catch {\n // If evaluation fails, keep the current value\n }\n }\n\n private handleBackspace() {\n if (this.value.length > 0) {\n this.value = this.value.slice(0, -1);\n this.dispatchValueChange();\n }\n }\n\n private handleClear() {\n this.value = '';\n this.dispatchValueChange();\n }\n\n private handleToggleContent() {\n this.content =\n this.content === ObcKeyboardNumericContent.Numbers\n ? ObcKeyboardNumericContent.Symbols\n : ObcKeyboardNumericContent.Numbers;\n }\n\n private handleDone() {\n this.evaluateExpression();\n this.dispatchEvent(\n new CustomEvent('done-click', {\n detail: {value: this.value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private dispatchValueChange() {\n this.dispatchEvent(\n new CustomEvent('value-change', {\n detail: {value: this.value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleInput(e: ObcNumberInputFieldInputEvent) {\n const input = e.target as ObcNumberInputField;\n const newValue = input.displayValue;\n\n if (this.validationPattern && newValue) {\n const regex = new RegExp(this.validationPattern);\n if (!regex.test(newValue)) {\n input.displayOverride = this.value;\n return;\n }\n }\n\n if (newValue && !this.isValidValue(newValue)) {\n input.displayOverride = this.value;\n return;\n }\n\n this.value = newValue;\n this.dispatchValueChange();\n }\n\n private handleInputKeydown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n e.preventDefault();\n this.handleDone();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n this.handleCloseClick();\n }\n }\n\n private renderCalculationRow() {\n if (!this.hasCalculation) return nothing;\n\n return html`\n <div class=\"calculation-container\">\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('+')}\n >\n <obi-up-iec></obi-up-iec>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('-')}\n >\n <obi-down-iec></obi-down-iec>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('×')}\n >\n <obi-multiply></obi-multiply>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('÷')}\n >\n <obi-divide></obi-divide>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('=')}\n >\n <obi-equal></obi-equal>\n </obc-icon-button>\n </div>\n `;\n }\n\n private renderKeyboard() {\n const keys =\n this.content === ObcKeyboardNumericContent.Numbers\n ? NUMBER_KEYS\n : SYMBOL_KEYS;\n\n return html`\n <div class=\"keys-container\">\n ${keys.map(\n (row) => html`\n <div class=\"row\">\n ${row.map(\n (key) => html`\n <obc-button\n class=\"key-button\"\n variant=\"normal\"\n @click=${() => this.handleKeyPress(key)}\n >\n ${key}\n </obc-button>\n `\n )}\n </div>\n `\n )}\n </div>\n `;\n }\n\n private renderInputField() {\n return html`\n <obc-number-input-field\n class=\"input-field\"\n .value=${parseNumberInput(this.value)}\n .displayOverride=${this.value}\n .unit=${this.unit}\n .textAlign=${this.inputFieldTextAlign}\n .size=${ObcNumberInputFieldSize.Large}\n .helperText=${this.helperText}\n ?hasLeadingIcon=${this.hasLeadingIcon}\n placeholder=\"00.0\"\n @input=${this.handleInput}\n @keydown=${this.handleInputKeydown}\n >\n <slot name=\"leading-icon\" slot=\"leading-icon\"></slot>\n </obc-number-input-field>\n `;\n }\n\n protected override render() {\n const showTitleBar =\n this.hasTitleBar && this.type === ObcKeyboardNumericType.Floating;\n\n return html`\n <div class=\"wrapper type-${this.type}\">\n ${showTitleBar\n ? html`\n <div class=\"top-bar\">\n <div class=\"parameter-name\">${this.label}</div>\n <obc-icon-button variant=\"flat\" @click=${this.handleCloseClick}>\n <obi-close-google></obi-close-google>\n </obc-icon-button>\n </div>\n `\n : nothing}\n\n <div class=\"container-content\">\n ${this.renderInputField()}\n\n <div class=\"key-container\">\n ${this.renderCalculationRow()}\n\n <div class=\"input-container\">\n ${this.renderKeyboard()}\n\n <div class=\"action-container\">\n <div class=\"function-buttons-container\">\n <obc-button\n class=\"action-button\"\n @click=${this.handleBackspace}\n showLeadingIcon\n >\n <obi-backspace-google\n slot=\"leading-icon\"\n ></obi-backspace-google\n >DEL\n </obc-button>\n <obc-button\n class=\"action-button clear\"\n @click=${this.handleClear}\n >\n CLEAR\n </obc-button>\n ${this.has2Symbols\n ? html`\n <obc-button\n class=\"action-button symbols\"\n variant=\"normal\"\n @click=${this.handleToggleContent}\n >\n ${this.content === ObcKeyboardNumericContent.Numbers\n ? '#+='\n : '123'}\n </obc-button>\n `\n : nothing}\n </div>\n <obc-button\n class=\"action-button done\"\n variant=\"raised\"\n @click=${this.handleDone}\n >\n DONE\n </obc-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-keyboard-numeric': ObcKeyboardNumeric;\n }\n}\n"],"names":["ObcKeyboardNumericType","ObcKeyboardNumericContent"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"keyboard-numeric.js","sources":["../../../src/components/keyboard-numeric/keyboard-numeric.ts"],"sourcesContent":["import {LitElement, html, nothing, unsafeCSS} from 'lit';\nimport {property, state} from 'lit/decorators.js';\nimport {customElement} from '../../decorator.js';\nimport componentStyle from './keyboard-numeric.css?inline';\n\nimport '../icon-button/icon-button.js';\nimport '../../icons/icon-close-google.js';\nimport '../../icons/icon-backspace-google.js';\nimport '../button/button.js';\nimport '../../icons/icon-up-iec.js';\nimport '../../icons/icon-down-iec.js';\nimport '../../icons/icon-multiply.js';\nimport '../../icons/icon-divide.js';\nimport '../../icons/icon-equal.js';\nimport '../number-input-field/number-input-field.js';\nimport {\n ObcNumberInputField,\n ObcNumberInputFieldTextAlign,\n ObcNumberInputFieldSize,\n ObcNumberInputFieldInputEvent,\n} from '../number-input-field/number-input-field.js';\nimport {parseNumberInput} from '../number-input-field/number-input-format.js';\n\nexport enum ObcKeyboardNumericType {\n Floating = 'floating',\n Flat = 'flat',\n}\n\nexport enum ObcKeyboardNumericContent {\n Numbers = 'numbers',\n Symbols = 'symbols',\n}\n\n// Key layouts\nconst NUMBER_KEYS = [\n ['1', '2', '3'],\n ['4', '5', '6'],\n ['7', '8', '9'],\n ['–', '0', ','],\n];\n\nconst SYMBOL_KEYS = [\n ['!', '@', '#'],\n ['$', '%', '&'],\n ['(', ')', '/'],\n ['–', '0', ','],\n];\n\n// All allowed characters for validation\nconst ALLOWED_CHARS = [\n '0',\n '1',\n '2',\n '3',\n '4',\n '5',\n '6',\n '7',\n '8',\n '9',\n '–',\n '-',\n ',',\n '.',\n '+',\n '×',\n '÷',\n '=',\n '!',\n '@',\n '#',\n '$',\n '%',\n '&',\n '(',\n ')',\n '/',\n];\n\nconst OPERATORS = ['+', '-', '–', '×', '÷', '*', '/'];\n\nconst ALLOWED_CHARS_PATTERN = `^[${ALLOWED_CHARS.map((c) =>\n c.replace(/[-.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n).join('')}]*$`;\n\n@customElement('obc-keyboard-numeric')\nexport class ObcKeyboardNumeric extends LitElement {\n @property({type: String}) type: ObcKeyboardNumericType =\n ObcKeyboardNumericType.Floating;\n\n /** Shows the top bar with label and close button (only applicable for floating type) */\n @property({type: Boolean}) hasTitleBar = false;\n\n /** Label displayed in the top bar */\n @property({type: String}) label = 'Parameter name';\n\n /** Current input value */\n @property({type: String}) value = '';\n\n /** Shows the calculation row with +, -, ×, ÷, = buttons */\n @property({type: Boolean}) hasCalculation = false;\n\n /** Shows the #+= / 123 toggle button to switch between numbers and symbols */\n @property({type: Boolean}) has2Symbols = false;\n\n /** Helper text content displayed below the input field */\n @property({type: String}) helperText = '';\n\n /** Shows a leading icon slot in the input field */\n @property({type: Boolean}) hasLeadingIcon = false;\n\n /** Unit text (%, kg, °C, etc.) */\n @property({type: String}) unit = '';\n\n /** Text alignment in input field */\n @property({type: String}) inputFieldTextAlign: ObcNumberInputFieldTextAlign =\n ObcNumberInputFieldTextAlign.Right;\n\n /** Optional regex pattern for validation (applies to both keyboard and direct input) */\n @property({type: String}) validationPattern = '';\n\n @state() private content: ObcKeyboardNumericContent =\n ObcKeyboardNumericContent.Numbers;\n\n private get effectiveValidationPattern(): string {\n if (!this.validationPattern) {\n return ALLOWED_CHARS_PATTERN;\n }\n return `^(?=${ALLOWED_CHARS_PATTERN})(?=${this.validationPattern}).*$`;\n }\n\n /** Validates if a character can be added to the current value */\n private canAddCharacter(char: string): boolean {\n const potentialValue = this.value + char;\n\n if (this.validationPattern) {\n const regex = new RegExp(this.validationPattern);\n return regex.test(potentialValue);\n }\n\n if (!ALLOWED_CHARS.includes(char)) {\n return false;\n }\n\n const lastChar = this.value.slice(-1);\n\n // Only one decimal separator per number segment\n if (char === ',' || char === '.') {\n const segments = this.value.split(/[+\\-–×÷*/]/);\n const currentSegment = segments[segments.length - 1] || '';\n return !currentSegment.includes(',') && !currentSegment.includes('.');\n }\n\n // Minus/plus allowed at beginning or after an operator\n if (char === '–' || char === '-' || char === '+') {\n return (\n this.value === '' || this.value === '0' || OPERATORS.includes(lastChar)\n );\n }\n\n return true;\n }\n\n private handleCloseClick() {\n this.dispatchEvent(\n new CustomEvent('close-click', {bubbles: true, composed: true})\n );\n }\n\n private handleKeyPress(key: string) {\n if (this.canAddCharacter(key)) {\n if (\n (key === '–' || key === '-' || key === '+') &&\n (this.value === '' || this.value === '0')\n ) {\n this.value = key;\n } else {\n this.value += key;\n }\n this.dispatchValueChange();\n }\n }\n\n private handleCalculationKey(key: string) {\n if (key === '=') {\n this.evaluateExpression();\n } else {\n this.value += key;\n this.dispatchValueChange();\n }\n }\n\n private evaluateExpression() {\n if (!this.value) return;\n\n try {\n const expression = this.value\n .replace(/×/g, '*')\n .replace(/÷/g, '/')\n .replace(/–/g, '-')\n .replace(/,/g, '.');\n\n if (!/^[\\d+\\-*/().]+$/.test(expression)) {\n return;\n }\n\n const result = new Function(`return (${expression})`)();\n\n if (typeof result === 'number' && isFinite(result)) {\n const rounded = Math.round(result * 1000000) / 1000000;\n this.value = String(rounded).replace('.', ',');\n this.dispatchValueChange();\n }\n } catch {\n // If evaluation fails, keep the current value\n }\n }\n\n private handleBackspace() {\n if (this.value.length > 0) {\n this.value = this.value.slice(0, -1);\n this.dispatchValueChange();\n }\n }\n\n private handleClear() {\n this.value = '';\n this.dispatchValueChange();\n }\n\n private handleToggleContent() {\n this.content =\n this.content === ObcKeyboardNumericContent.Numbers\n ? ObcKeyboardNumericContent.Symbols\n : ObcKeyboardNumericContent.Numbers;\n }\n\n private handleDone() {\n this.evaluateExpression();\n this.dispatchEvent(\n new CustomEvent('done-click', {\n detail: {value: this.value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private dispatchValueChange() {\n this.dispatchEvent(\n new CustomEvent('value-change', {\n detail: {value: this.value},\n bubbles: true,\n composed: true,\n })\n );\n }\n\n private handleInput(e: ObcNumberInputFieldInputEvent) {\n const input = e.target as ObcNumberInputField;\n const newValue = input.displayValue;\n\n this.value = newValue;\n this.dispatchValueChange();\n }\n\n private handleInputKeydown(e: KeyboardEvent) {\n if (e.key === 'Enter') {\n e.preventDefault();\n this.handleDone();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n this.handleCloseClick();\n }\n }\n\n private renderCalculationRow() {\n if (!this.hasCalculation) return nothing;\n\n return html`\n <div class=\"calculation-container\">\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('+')}\n >\n <obi-up-iec></obi-up-iec>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('-')}\n >\n <obi-down-iec></obi-down-iec>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('×')}\n >\n <obi-multiply></obi-multiply>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('÷')}\n >\n <obi-divide></obi-divide>\n </obc-icon-button>\n <obc-icon-button\n class=\"calculation-button\"\n @click=${() => this.handleCalculationKey('=')}\n >\n <obi-equal></obi-equal>\n </obc-icon-button>\n </div>\n `;\n }\n\n private renderKeyboard() {\n const keys =\n this.content === ObcKeyboardNumericContent.Numbers\n ? NUMBER_KEYS\n : SYMBOL_KEYS;\n\n return html`\n <div class=\"keys-container\">\n ${keys.map(\n (row) => html`\n <div class=\"row\">\n ${row.map(\n (key) => html`\n <obc-button\n class=\"key-button\"\n variant=\"normal\"\n @click=${() => this.handleKeyPress(key)}\n >\n ${key}\n </obc-button>\n `\n )}\n </div>\n `\n )}\n </div>\n `;\n }\n\n private renderInputField() {\n return html`\n <obc-number-input-field\n class=\"input-field\"\n .value=${parseNumberInput(this.value)}\n .displayOverride=${this.value}\n .unit=${this.unit}\n .textAlign=${this.inputFieldTextAlign}\n .size=${ObcNumberInputFieldSize.Large}\n .helperText=${this.helperText}\n .validationPattern=${this.effectiveValidationPattern}\n ?hasLeadingIcon=${this.hasLeadingIcon}\n placeholder=\"00.0\"\n @input=${this.handleInput}\n @keydown=${this.handleInputKeydown}\n >\n <slot name=\"leading-icon\" slot=\"leading-icon\"></slot>\n </obc-number-input-field>\n `;\n }\n\n protected override render() {\n const showTitleBar =\n this.hasTitleBar && this.type === ObcKeyboardNumericType.Floating;\n\n return html`\n <div class=\"wrapper type-${this.type}\">\n ${showTitleBar\n ? html`\n <div class=\"top-bar\">\n <div class=\"parameter-name\">${this.label}</div>\n <obc-icon-button variant=\"flat\" @click=${this.handleCloseClick}>\n <obi-close-google></obi-close-google>\n </obc-icon-button>\n </div>\n `\n : nothing}\n\n <div class=\"container-content\">\n ${this.renderInputField()}\n\n <div class=\"key-container\">\n ${this.renderCalculationRow()}\n\n <div class=\"input-container\">\n ${this.renderKeyboard()}\n\n <div class=\"action-container\">\n <div class=\"function-buttons-container\">\n <obc-button\n class=\"action-button\"\n @click=${this.handleBackspace}\n showLeadingIcon\n >\n <obi-backspace-google\n slot=\"leading-icon\"\n ></obi-backspace-google\n >DEL\n </obc-button>\n <obc-button\n class=\"action-button clear\"\n @click=${this.handleClear}\n >\n CLEAR\n </obc-button>\n ${this.has2Symbols\n ? html`\n <obc-button\n class=\"action-button symbols\"\n variant=\"normal\"\n @click=${this.handleToggleContent}\n >\n ${this.content === ObcKeyboardNumericContent.Numbers\n ? '#+='\n : '123'}\n </obc-button>\n `\n : nothing}\n </div>\n <obc-button\n class=\"action-button done\"\n variant=\"raised\"\n @click=${this.handleDone}\n >\n DONE\n </obc-button>\n </div>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n\n static override styles = unsafeCSS(componentStyle);\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'obc-keyboard-numeric': ObcKeyboardNumeric;\n }\n}\n"],"names":["ObcKeyboardNumericType","ObcKeyboardNumericContent"],"mappings":"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"}
|
|
@@ -71,6 +71,13 @@ export declare class ObcNumberInputField extends LitElement {
|
|
|
71
71
|
groupSeparator?: string;
|
|
72
72
|
minFractionDigits: number;
|
|
73
73
|
maxFractionDigits?: number | undefined;
|
|
74
|
+
/**
|
|
75
|
+
* Optional regex pattern. When set, any keystroke or paste whose resulting
|
|
76
|
+
* value does not match this pattern is blocked at the `beforeinput` stage.
|
|
77
|
+
* When unset, a permissive numeric filter (digits, sign, active separators,
|
|
78
|
+
* whitespace) is applied instead.
|
|
79
|
+
*/
|
|
80
|
+
validationPattern: string;
|
|
74
81
|
private hasFocus;
|
|
75
82
|
private displayText;
|
|
76
83
|
private previousValue;
|
|
@@ -81,6 +88,8 @@ export declare class ObcNumberInputField extends LitElement {
|
|
|
81
88
|
private getFormatOptions;
|
|
82
89
|
private formatValueForDisplay;
|
|
83
90
|
private onInput;
|
|
91
|
+
private isProjectedValueAllowed;
|
|
92
|
+
private onBeforeInput;
|
|
84
93
|
private onFocus;
|
|
85
94
|
private onBlur;
|
|
86
95
|
private commitDisplay;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"number-input-field.d.ts","sourceRoot":"","sources":["../../../src/components/number-input-field/number-input-field.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,cAAc,EACd,cAAc,EACf,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"number-input-field.d.ts","sourceRoot":"","sources":["../../../src/components/number-input-field/number-input-field.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,UAAU,EAIV,cAAc,EACd,cAAc,EACf,MAAM,KAAK,CAAC;AAgBb,MAAM,MAAM,6BAA6B,GAAG,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC;AACzE,MAAM,MAAM,8BAA8B,GAAG,WAAW,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAC,CAAC,CAAC;AAE1E,oBAAY,4BAA4B;IACtC,MAAM,WAAW;IACjB,KAAK,UAAU;IACf,gBAAgB,uBAAuB;CACxC;AAED,oBAAY,uBAAuB;IACjC,OAAO,YAAY;IACnB,KAAK,UAAU;CAChB;AAED,oBAAY,4BAA4B;IACtC,IAAI,SAAS;IACb,MAAM,WAAW;IACjB,KAAK,UAAU;CAChB;AAKD;;;;;;;;GAQG;AACH,qBACa,mBAAoB,SAAQ,UAAU;IACvB,KAAK,SAAO;IACZ,IAAI,SAAM;IACV,WAAW,SAAM;IACjB,SAAS,EAAE,4BAA4B,CAC5B;IAEK,QAAQ,UAAS;IACjB,QAAQ,UAAS;IACjB,KAAK,UAAS;IAC9B,SAAS,SAAM;IACzC,kEAAkE;IACvC,oBAAoB,UAAS;IACxD,+EAA+E;IACpD,aAAa,UAAS;IAEjD;;OAEG;IACwB,sBAAsB,UAAS;IAE1D,0CAA0C;IAChB,IAAI,SAAM;IAEpC,2CAA2C;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IAE7C,4CAA4C;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IAEnB,IAAI,EAAE,uBAAuB,CACrB;IAEP,cAAc,UAAS;IACxB,UAAU,SAAM;IAEhB,KAAK,SAAM;IACV,QAAQ,UAAS;IACjB,YAAY,UAAS;IACtB,cAAc,EAAE,4BAA4B,CAClC;IAET,aAAa,UAAS;IACvB,eAAe,EAAE,4BAA4B,CACnC;IAEpC,oFAAoF;IACzD,OAAO,UAAS;IAE3C;;;OAGG;IACyC,eAAe,SAAM;IAEvC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,SAAK;IACtB,iBAAiB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAEjE;;;;;OAKG;IACuB,iBAAiB,SAAM;IAExC,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,WAAW,CAAM;IACzB,OAAO,CAAC,aAAa,CAAO;IAC5B,OAAO,CAAC,mBAAmB,CAAM;IACjC,OAAO,CAAC,kBAAkB,CAAO;IAEnB,OAAO,CAAC,YAAY,CAAC,CAAmB;IAE/D,IAAI,YAAY,IAAI,MAAM,CAEzB;IAED,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,qBAAqB;IAI7B,OAAO,CAAC,OAAO;IAYf,OAAO,CAAC,uBAAuB;IAiB/B,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,OAAO;IAUf,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,aAAa;IAqBrB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,cAAc;IAQtB,OAAO,KAAK,iBAAiB,GAU5B;IAED,OAAO,CAAC,mBAAmB;IAU3B,OAAO,CAAC,6BAA6B;IA6B5B,YAAY;IAQrB,OAAO,KAAK,OAAO,GAKlB;IAEQ,UAAU,CAAC,iBAAiB,EAAE,cAAc;IA2B5C,OAAO;IAYhB,OAAO,CAAC,gBAAgB;IAmBxB,OAAO,CAAC,aAAa;IAyCZ,MAAM;IA6Ff,OAAgB,MAAM,0BAA6B;CACpD;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,qBAAqB;QAC7B,wBAAwB,EAAE,mBAAmB,CAAC;KAC/C;CACF"}
|
|
@@ -4,7 +4,7 @@ import { ifDefined } from "lit/directives/if-defined.js";
|
|
|
4
4
|
import componentStyle from "./number-input-field.css.js";
|
|
5
5
|
import { classMap } from "lit/directives/class-map.js";
|
|
6
6
|
import { customElement } from "../../decorator.js";
|
|
7
|
-
import { formatNumberForDisplay, parseNumberInput, removeGroupingFromDisplay, valuesEqual } from "./number-input-format.js";
|
|
7
|
+
import { formatNumberForDisplay, parseNumberInput, isAllowedIntermediateInput, removeGroupingFromDisplay, valuesEqual } from "./number-input-format.js";
|
|
8
8
|
import { getCssVariableValue } from "../../charthelpers/colors.js";
|
|
9
9
|
var __defProp = Object.defineProperty;
|
|
10
10
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -63,6 +63,7 @@ let ObcNumberInputField = class extends LitElement {
|
|
|
63
63
|
this.squared = false;
|
|
64
64
|
this.displayOverride = "";
|
|
65
65
|
this.minFractionDigits = 0;
|
|
66
|
+
this.validationPattern = "";
|
|
66
67
|
this.hasFocus = false;
|
|
67
68
|
this.displayText = "";
|
|
68
69
|
this.previousValue = NaN;
|
|
@@ -94,6 +95,30 @@ let ObcNumberInputField = class extends LitElement {
|
|
|
94
95
|
this.updateCenterAlignedInputWidth(raw);
|
|
95
96
|
this.dispatchInput();
|
|
96
97
|
}
|
|
98
|
+
isProjectedValueAllowed(projected) {
|
|
99
|
+
if (this.validationPattern) {
|
|
100
|
+
let regex;
|
|
101
|
+
try {
|
|
102
|
+
regex = new RegExp(`^(?:${this.validationPattern})$`);
|
|
103
|
+
} catch {
|
|
104
|
+
return isAllowedIntermediateInput(projected, this.getFormatOptions());
|
|
105
|
+
}
|
|
106
|
+
return regex.test(projected);
|
|
107
|
+
}
|
|
108
|
+
return isAllowedIntermediateInput(projected, this.getFormatOptions());
|
|
109
|
+
}
|
|
110
|
+
onBeforeInput(e) {
|
|
111
|
+
if (this.disabled || this.readonly) return;
|
|
112
|
+
const input = e.target;
|
|
113
|
+
const incoming = e.data ?? e.dataTransfer?.getData("text/plain") ?? null;
|
|
114
|
+
if (incoming === null) return;
|
|
115
|
+
const start = input.selectionStart ?? input.value.length;
|
|
116
|
+
const end = input.selectionEnd ?? input.value.length;
|
|
117
|
+
const projected = input.value.slice(0, start) + incoming + input.value.slice(end);
|
|
118
|
+
if (!this.isProjectedValueAllowed(projected)) {
|
|
119
|
+
e.preventDefault();
|
|
120
|
+
}
|
|
121
|
+
}
|
|
97
122
|
onFocus() {
|
|
98
123
|
this.hasFocus = true;
|
|
99
124
|
const source = this.displayOverride || this.displayText;
|
|
@@ -322,6 +347,7 @@ let ObcNumberInputField = class extends LitElement {
|
|
|
322
347
|
hasHelperOrError ? "helper-text" : void 0
|
|
323
348
|
)}
|
|
324
349
|
autocomplete="off"
|
|
350
|
+
@beforeinput=${this.onBeforeInput}
|
|
325
351
|
@input=${this.onInput}
|
|
326
352
|
/>
|
|
327
353
|
${unitInside ? html`<span class="unit-text">${this.unit}</span>` : nothing}
|
|
@@ -423,6 +449,9 @@ __decorateClass([
|
|
|
423
449
|
__decorateClass([
|
|
424
450
|
property({ type: Number })
|
|
425
451
|
], ObcNumberInputField.prototype, "maxFractionDigits", 2);
|
|
452
|
+
__decorateClass([
|
|
453
|
+
property({ type: String })
|
|
454
|
+
], ObcNumberInputField.prototype, "validationPattern", 2);
|
|
426
455
|
__decorateClass([
|
|
427
456
|
state()
|
|
428
457
|
], ObcNumberInputField.prototype, "hasFocus", 2);
|
|
@@ -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":";;;;;;;;;;;;;;;;;;AAyBO,IAAK,iDAAAA,kCAAL;AACLA,gCAAA,QAAA,IAAS;AACTA,gCAAA,OAAA,IAAQ;AACRA,gCAAA,kBAAA,IAAmB;AAHT,SAAAA;AAAA,GAAA,gCAAA,CAAA,CAAA;AAML,IAAK,4CAAAC,6BAAL;AACLA,2BAAA,SAAA,IAAU;AACVA,2BAAA,OAAA,IAAQ;AAFE,SAAAA;AAAA,GAAA,2BAAA,CAAA,CAAA;AAKL,IAAK,iDAAAC,kCAAL;AACLA,gCAAA,MAAA,IAAO;AACPA,gCAAA,QAAA,IAAS;AACTA,gCAAA,OAAA,IAAQ;AAHE,SAAAA;AAAA,GAAA,gCAAA,CAAA,CAAA;AAMZ,MAAM,iBAAiB;AACvB,MAAM,cAAc;AACpB,MAAM,eAAe;AAWd,IAAM,sBAAN,cAAkC,WAAW;AAAA,EAA7C,cAAA;AAAA,UAAA,GAAA,SAAA;AACqB,SAAA,QAAQ;AACR,SAAA,OAAO;AACP,SAAA,cAAc;AACd,SAAA,YACxB;AAEwC,SAAA,WAAW;AACX,SAAA,WAAW;AACX,SAAA,QAAQ;AACxB,SAAA,YAAY;AAEX,SAAA,uBAAuB;AAEvB,SAAA,gBAAgB;AAKhB,SAAA,yBAAyB;AAG1B,SAAA,OAAO;AAQP,SAAA,OACxB;AAEyB,SAAA,iBAAiB;AAClB,SAAA,aAAa;AAEb,SAAA,QAAQ;AACP,SAAA,WAAW;AACX,SAAA,eAAe;AAChB,SAAA,iBACxB;AAEyB,SAAA,gBAAgB;AACjB,SAAA,kBACxB;AAGyB,SAAA,UAAU;AAMO,SAAA,kBAAkB;AAIpC,SAAA,oBAAoB;AAGrC,SAAQ,WAAW;AACnB,SAAQ,cAAc;AACtB,SAAQ,gBAAgB;AACxB,SAAQ,sBAAsB;AAC9B,SAAQ,qBAAqB;AAAA,EAAA;AAAA,EAItC,IAAI,eAAuB;AACzB,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,mBAA6C;AACnD,WAAO;AAAA,MACL,kBAAkB,KAAK;AAAA,MACvB,gBAAgB,KAAK;AAAA,MACrB,mBAAmB,KAAK;AAAA,MACxB,mBAAmB,KAAK;AAAA,IAAA;AAAA,EAE5B;AAAA,EAEQ,sBAAsB,OAAuB;AACnD,WAAO,uBAAuB,OAAO,KAAK,iBAAA,CAAkB;AAAA,EAC9D;AAAA,EAEQ,QAAQ,GAAU;AACxB,MAAE,gBAAA;AACF,UAAM,MAAO,EAAE,OAA4B;AAC3C,SAAK,cAAc;AACnB,SAAK,kBAAkB;AACvB,UAAM,SAAS,iBAAiB,GAAG;AACnC,SAAK,QAAQ;AACb,SAAK,sBAAsB;AAC3B,SAAK,8BAA8B,GAAG;AACtC,SAAK,cAAA;AAAA,EACP;AAAA,EAEQ,UAAU;AAChB,SAAK,WAAW;AAChB,UAAM,SAAS,KAAK,mBAAmB,KAAK;AAC5C,SAAK,cAAc;AAAA,MACjB;AAAA,MACA,KAAK,iBAAA;AAAA,IAAiB;AAExB,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,SAAS;AACf,SAAK,WAAW;AAChB,SAAK,cAAA;AACL,QAAI,CAAC,YAAY,KAAK,OAAO,KAAK,kBAAkB,GAAG;AACrD,WAAK,qBAAqB,KAAK;AAC/B,WAAK,eAAA;AAAA,IACP;AAAA,EACF;AAAA,EAEQ,gBAAgB;AACtB,UAAM,UAAU,KAAK,YAAY,KAAA;AACjC,QAAI,YAAY,IAAI;AAClB,WAAK,QAAQ;AACb,WAAK,cAAc;AACnB,WAAK,kBAAkB;AACvB;AAAA,IACF;AAEA,UAAM,YAAY,QAAQ,QAAQ,SAAS,EAAE;AAC7C,UAAM,SAAS,iBAAiB,SAAS;AAEzC,QAAI,OAAO,SAAS,MAAM,GAAG;AAC3B,WAAK,QAAQ;AACb,WAAK,cAAc,KAAK,sBAAsB,MAAM;AAAA,IACtD,OAAO;AACL,WAAK,QAAQ;AAAA,IACf;AACA,SAAK,kBAAkB;AAAA,EACzB;AAAA,EAEQ,gBAAgB;AACtB,SAAK;AAAA,MACH,IAAI,YAAY,SAAS;AAAA,QACvB,QAAQ,EAAC,OAAO,KAAK,MAAA;AAAA,MAAK,CAC3B;AAAA,IAAA;AAAA,EAEL;AAAA,EAEQ,iBAAiB;AACvB,SAAK;AAAA,MACH,IAAI,YAAY,UAAU;AAAA,QACxB,QAAQ,EAAC,OAAO,KAAK,MAAA;AAAA,MAAK,CAC3B;AAAA,IAAA;AAAA,EAEL;AAAA,EAEA,IAAY,oBAA6B;AACvC,QAAI,KAAK,cAAe,QAAO;AAC/B,QAAI,KAAK,wBAAwB,KAAK,SAAU,QAAO;AACvD,QACE,KAAK,0BACL,YAAY,KAAK,OAAO,KAAK,aAAa,GAC1C;AACA,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,sBAA8B;AACpC,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK;AAAA,IACd;AACA,QAAI,CAAC,KAAK,qBAAqB,KAAK,cAAc;AAChD,aAAO,KAAK,aAAa;AAAA,IAC3B;AACA,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,8BAA8B,OAAe;AACnD,QAAI,KAAK,cAAc,UAAqC;AAC1D,WAAK,MAAM,eAAe,iCAAiC;AAC3D;AAAA,IACF;AAEA,UAAM,WAAW,OAAO;AAAA,MACtB;AAAA,QACE;AAAA,QACA;AAAA,MAAA;AAAA,IACF;AAGF,UAAM,aAAa,MAAM,WAAW,SAAS,EAAE;AAC/C,UAAM,UAAU,MAAM,SAAS,WAAW;AAG1C,UAAM,kBACJ,WAAW,SAAS,iBAAiB,UAAU;AAEjD,UAAM,gBAAgB,KAAK;AAAA,MACxB,kBAAkB,WAAY;AAAA,IAAA;AAEjC,SAAK,MAAM;AAAA,MACT;AAAA,MACA,GAAG,aAAa;AAAA,IAAA;AAAA,EAEpB;AAAA,EAES,eAAe;AACtB,QAAI,CAAC,KAAK,eAAe,CAAC,KAAK,iBAAiB;AAC9C,WAAK,cAAc,KAAK,sBAAsB,KAAK,KAAK;AAAA,IAC1D;AACA,SAAK,qBAAqB,KAAK;AAC/B,SAAK,8BAA8B,KAAK,qBAAqB;AAAA,EAC/D;AAAA,EAEA,IAAY,UAAmB;AAC7B,QAAI,KAAK,cAAc;AACrB,aAAO,KAAK,aAAa,MAAM,KAAA,EAAO,WAAW;AAAA,IACnD;AACA,WAAO,MAAM,KAAK,KAAK;AAAA,EACzB;AAAA,EAES,WAAW,mBAAmC;AACrD,UAAM,qBACJ,kBAAkB,IAAI,kBAAkB,KACxC,kBAAkB,IAAI,gBAAgB,KACtC,kBAAkB,IAAI,mBAAmB,KACzC,kBAAkB,IAAI,mBAAmB;AAE3C,QAAI,kBAAkB,IAAI,OAAO,KAAK,KAAK,mBAAmB;AAC5D,UAAI,CAAC,KAAK,UAAU;AAClB,aAAK,cAAc,KAAK,sBAAsB,KAAK,KAAK;AACxD,aAAK,kBAAkB;AACvB,aAAK,qBAAqB,KAAK;AAAA,MACjC;AAAA,IACF,WAAW,sBAAsB,CAAC,KAAK,YAAY,KAAK,mBAAmB;AACzE,WAAK,cAAc,KAAK,sBAAsB,KAAK,KAAK;AACxD,WAAK,kBAAkB;AAAA,IACzB;AAEA,QACE,kBAAkB,IAAI,OAAO,KAC7B,CAAC,KAAK,qBACN,KAAK,cACL;AACA,WAAK,QAAQ,iBAAiB,KAAK,aAAa,KAAK;AAAA,IACvD;AAAA,EACF;AAAA,EAES,UAAU;AACjB,QACE,KAAK,0BACL,CAAC,YAAY,KAAK,OAAO,KAAK,aAAa,MAC1C,KAAK,wBAAwB,KAAK,eAAe,CAAC,KAAK,WACxD;AACA,WAAK,gBAAgB,KAAK;AAAA,IAC5B;AAEA,SAAK,8BAA8B,KAAK,qBAAqB;AAAA,EAC/D;AAAA,EAEQ,iBACN,MACA,SACiC;AACjC,QAAI,CAAC,KAAM,QAAO;AAClB,WAAO;AAAA;AAAA,cAEG,SAAS;AAAA,MACf,CAAC,UAAU,eAAe,aAAa,GAAG;AAAA,MAC1C,CAAC,oBAAoB,KAAK,eAAe,EAAE,GAAG;AAAA,IAAA,CAC/C,CAAC;AAAA;AAAA,QAEA,KAAK,gBACH,wEACA,OAAO;AAAA,QACT,IAAI;AAAA;AAAA,EAEV;AAAA,EAEQ,cAAc,GAAiB;AACrC,QAAI,KAAK,SAAU;AACnB,QAAI,KAAK,SAAU;AACnB,QAAI,KAAK,cAAc;AACrB,QAAE,gBAAA;AACF,QAAE,eAAA;AACF,WAAK,aAAa,MAAA;AAClB,YAAM,WAAW,KAAK,aAAa,sBAAA;AACnC,UAAI;AACJ,UAAI,EAAE,UAAU,SAAS,MAAM;AAE7B,yBAAiB;AAAA,MACnB,WAAW,EAAE,UAAU,SAAS,OAAO;AAErC,yBAAiB,KAAK,aAAa,MAAM;AAAA,MAC3C,OAAO;AAKL,cAAM,SAAS,EAAE;AACjB,YAAI,SAAS,SAAS;AACtB,cAAM,OAAO,KAAK,aAAa;AAC/B,iBAAS,IAAI,KAAK,SAAS,GAAG,KAAK,GAAG,KAAK;AACzC,gBAAM,OAAO,KAAK,CAAC;AACnB,gBAAM,WAAW,KAAK,MAAM,MAAM;AAClC,gBAAM,QAAQ,WAAW,cAAc;AACvC,cAAI,SAAS,SAAS,QAAQ,GAAG;AAC/B,6BAAiB,IAAI;AACrB;AAAA,UACF;AACA,oBAAU;AAAA,QACZ;AACA,YAAI,mBAAmB,QAAW;AAChC,2BAAiB;AAAA,QACnB;AAAA,MACF;AACA,WAAK,aAAa,kBAAkB,gBAAgB,cAAc;AAAA,IACpE;AAAA,EACF;AAAA,EAES,SAAS;AAChB,UAAM,mBACJ,QAAQ,KAAK,UAAU,KAAK,QAAQ,KAAK,SAAS,KAAK,SAAS;AAClE,UAAM,aACJ,KAAK,QACL,KAAK,cAAc;AACrB,UAAM,cACJ,KAAK,QACL,KAAK,cAAc;AAErB,UAAM,UAAU,KAAK,oBAAA;AAErB,WAAO;AAAA;AAAA,gBAEK,SAAS;AAAA,MACf,SAAS;AAAA,MACT,CAAC,SAAS,KAAK,SAAS,EAAE,GAAG;AAAA,MAC7B,CAAC,QAAQ,KAAK,IAAI,EAAE,GAAG;AAAA,MACvB,OAAO,KAAK;AAAA,MACZ,UAAU,KAAK;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,YAAY;AAAA,MACZ,UAAU,QAAQ,KAAK,KAAK;AAAA,MAC5B,SAAS,KAAK;AAAA,IAAA,CACf,CAAC;AAAA,uBACa,KAAK,aAAa;AAAA;AAAA,UAE/B,KAAK,QACH;AAAA,sBACU,SAAS;AAAA,MACf,wBAAwB;AAAA,MACxB,CAAC,mBAAmB,KAAK,cAAc,EAAE,GAAG;AAAA,IAAA,CAC7C,CAAC;AAAA;AAAA,gBAEA,KAAK,eACH;AAAA;AAAA,4BAGA,OAAO;AAAA,yCACgB,KAAK,KAAK;AAAA,gBACnC,KAAK,WACH,+CACA,OAAO;AAAA,sBAEb,OAAO;AAAA;AAAA;AAAA;AAAA,cAIL,KAAK,iBACH;AAAA;AAAA,0BAGA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,yBAME,OAAO;AAAA,yBACP,KAAK,OAAO;AAAA,wBACb,KAAK,MAAM;AAAA,+BACJ,KAAK,WAAW;AAAA,uBACxB,UAAU,KAAK,QAAQ,MAAS,CAAC;AAAA,4BAC5B,KAAK,QAAQ;AAAA,4BACb,KAAK,QAAQ;AAAA,4BACb,KAAK,QAAQ;AAAA,4BACb,UAAU,KAAK,SAAS,CAAC;AAAA,4BACzB,UAAU,KAAK,SAAS,CAAC;AAAA,+BACtB,KAAK,QAAQ,SAAS,OAAO;AAAA,mCACzB;AAAA,MACjB,mBAAmB,gBAAgB;AAAA,IAAA,CACpC;AAAA;AAAA,yBAEQ,KAAK,OAAO;AAAA;AAAA,gBAErB,aACE,+BAA+B,KAAK,IAAI,YACxC,OAAO;AAAA;AAAA;AAAA,YAGb,cACE,wCAAwC,KAAK,IAAI,YACjD,OAAO;AAAA;AAAA;AAAA,UAGX,KAAK,SAAS,KAAK,YACjB,KAAK,iBAAiB,KAAK,WAAW,IAAI,IAC1C,KAAK,iBAAiB,KAAK,YAAY,KAAK,CAAC;AAAA;AAAA;AAAA,EAGvD;AAGF;AA3Za,oBA0ZK,SAAS,UAAU,cAAc;AAzZvB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GADb,oBACe,WAAA,SAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAFb,oBAEe,WAAA,QAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAHb,oBAGe,WAAA,eAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAJb,oBAIe,WAAA,aAAA,CAAA;AAGgB,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAP7B,oBAO+B,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAR7B,oBAQ+B,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAzC,SAAS,EAAC,MAAM,SAAS,SAAS,MAAK;AAAA,GAT7B,oBAS+B,WAAA,SAAA,CAAA;AAChB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAVb,oBAUe,WAAA,aAAA,CAAA;AAEC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAZd,oBAYgB,WAAA,wBAAA,CAAA;AAEA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAdd,oBAcgB,WAAA,iBAAA,CAAA;AAKA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAnBd,oBAmBgB,WAAA,0BAAA,CAAA;AAGD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAtBb,oBAsBe,WAAA,QAAA,CAAA;AAGA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAzBb,oBAyBe,WAAA,aAAA,CAAA;AAGA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA5Bb,oBA4Be,WAAA,aAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA9Bb,oBA8Be,WAAA,QAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAjCd,oBAiCgB,WAAA,kBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAlCb,oBAkCe,WAAA,cAAA,CAAA;AAEA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GApCb,oBAoCe,WAAA,SAAA,CAAA;AACC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GArCd,oBAqCgB,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GAtCd,oBAsCgB,WAAA,gBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAvCb,oBAuCe,WAAA,kBAAA,CAAA;AAGC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA1Cd,oBA0CgB,WAAA,iBAAA,CAAA;AACD,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA3Cb,oBA2Ce,WAAA,mBAAA,CAAA;AAIC,gBAAA;AAAA,EAA1B,SAAS,EAAC,MAAM,QAAA,CAAQ;AAAA,GA/Cd,oBA+CgB,WAAA,WAAA,CAAA;AAMiB,gBAAA;AAAA,EAA3C,SAAS,EAAC,MAAM,QAAQ,WAAW,OAAM;AAAA,GArD/B,oBAqDiC,WAAA,mBAAA,CAAA;AAElB,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAvDb,oBAuDe,WAAA,oBAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAxDb,oBAwDe,WAAA,kBAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GAzDb,oBAyDe,WAAA,qBAAA,CAAA;AACA,gBAAA;AAAA,EAAzB,SAAS,EAAC,MAAM,OAAA,CAAO;AAAA,GA1Db,oBA0De,WAAA,qBAAA,CAAA;AAET,gBAAA;AAAA,EAAhB,MAAA;AAAM,GA5DI,oBA4DM,WAAA,YAAA,CAAA;AACA,gBAAA;AAAA,EAAhB,MAAA;AAAM,GA7DI,oBA6DM,WAAA,eAAA,CAAA;AACA,gBAAA;AAAA,EAAhB,MAAA;AAAM,GA9DI,oBA8DM,WAAA,iBAAA,CAAA;AACA,gBAAA;AAAA,EAAhB,MAAA;AAAM,GA/DI,oBA+DM,WAAA,uBAAA,CAAA;AACA,gBAAA;AAAA,EAAhB,MAAA;AAAM,GAhEI,oBAgEM,WAAA,sBAAA,CAAA;AAEc,gBAAA;AAAA,EAA9B,MAAM,cAAc;AAAA,GAlEV,oBAkEoB,WAAA,gBAAA,CAAA;AAlEpB,sBAAN,gBAAA;AAAA,EADN,cAAc,wBAAwB;AAAA,GAC1B,mBAAA;"}
|
|
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,
|
|
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
|
-
|
|
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
|
|
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
|
|
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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"}
|