@colijnit/corecomponents_v12 300.1.0 → 300.1.1

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.
@@ -1,6 +1,6 @@
1
1
  import { __decorate } from 'tslib';
2
2
  import * as i0 from '@angular/core';
3
- import { Input, Injectable, HostBinding, ViewEncapsulation, Component, Directive, ElementRef, Pipe, EventEmitter, Output, ViewChildren, ViewContainerRef, HostListener, ViewChild, Optional, NgModule, SkipSelf, InjectionToken, Inject, forwardRef, ChangeDetectionStrategy, ContentChildren, NO_ERRORS_SCHEMA, Injector, QueryList } from '@angular/core';
3
+ import { Input, Injectable, HostBinding, ViewEncapsulation, Component, Directive, ElementRef, Pipe, EventEmitter, Output, ViewChildren, ViewContainerRef, HostListener, ViewChild, Optional, NgModule, SkipSelf, InjectionToken, Inject, forwardRef, ChangeDetectionStrategy, ContentChildren, LOCALE_ID, NO_ERRORS_SCHEMA, Injector, QueryList } from '@angular/core';
4
4
  import * as i5 from '@angular/forms';
5
5
  import { NgModel, UntypedFormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';
6
6
  import * as i1 from '@angular/platform-browser';
@@ -532,6 +532,28 @@ class NumberUtils {
532
532
  return { isOk: false, nearestOkNr: nearestOkNr };
533
533
  }
534
534
  }
535
+ /**
536
+ * Decides whether typing one more digit onto the given numeric text would exceed the configured
537
+ * digit limits. When `decimals` (scale) is set, `maxLength` is treated as the total precision: the
538
+ * integer part is capped at (maxLength - decimals) digits and the fractional part at `decimals`
539
+ * digits. When `decimals` is not set, `maxLength` caps the total number of digits.
540
+ *
541
+ * Note: assumes the digit is appended at the end of the value, because native number inputs expose
542
+ * no caret/selection information to constrain mid-string edits.
543
+ */
544
+ static WouldExceedDigitLimits(currentValue, maxLength, decimals) {
545
+ const digits = ('' + (currentValue ?? '')).replace('-', '');
546
+ if (decimals > 0) {
547
+ const separatorIndex = digits.search(/[.,]/);
548
+ if (separatorIndex === -1) {
549
+ const maxIntegerDigits = maxLength > 0 ? maxLength - decimals : Number.POSITIVE_INFINITY;
550
+ return digits.length >= maxIntegerDigits;
551
+ }
552
+ const decimalDigits = digits.length - separatorIndex - 1;
553
+ return decimalDigits >= decimals;
554
+ }
555
+ return maxLength > 0 && digits.length >= maxLength;
556
+ }
535
557
  static _GetLargestDecimalPrecisionOf(...args) {
536
558
  return ArrayUtils.GetMaxCalculatedValue(args, (arg) => {
537
559
  return NumberUtils.GetDecimalPlaces(arg);
@@ -934,8 +956,12 @@ function requiredValidator(control) {
934
956
  function precisionScaleValidator(precision, scale) {
935
957
  return function (control) {
936
958
  let isValid = true;
937
- if (control) {
938
- isValid = NumberUtils.CheckPrecisionAndScale(control.value, precision, scale).isOk;
959
+ if (control && control.value !== null && control.value !== undefined && control.value !== '') {
960
+ // The value may be a locale display string (e.g. "1234567,89"); normalize it to a number so the
961
+ // decimal separator is not counted as an integer digit by CheckPrecisionAndScale.
962
+ const raw = control.value;
963
+ const numeric = typeof raw === 'string' ? Number(raw.replace(',', '.')) : raw;
964
+ isValid = isNaN(numeric) || NumberUtils.CheckPrecisionAndScale(numeric, precision, scale).isOk;
939
965
  }
940
966
  return isValid ? null : { 'precision-scale': "MESSAGE_FIELD_PRECISION_OVERRIDDEN||" + precision };
941
967
  };
@@ -2031,27 +2057,28 @@ class CommitButtonsComponent {
2031
2057
  event.currentTarget.removeEventListener('animationiteration', this._handleAnimationIteration);
2032
2058
  };
2033
2059
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: CommitButtonsComponent, deps: [{ token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Component });
2034
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CommitButtonsComponent, isStandalone: false, selector: "co-commit-buttons", inputs: { committing: "committing", commitFinished: "commitFinished", parentForOverlay: "parentForOverlay" }, outputs: { cancelClick: "cancelClick", commitClick: "commitClick" }, host: { properties: { "class.co-commit-buttons": "this.showClass" } }, viewQueries: [{ propertyName: "content", predicate: ["animatediv"], descendants: true, read: ElementRef }], ngImport: i0, template: `
2035
- <div class="commit-buttons-wrapper" [overlay]="parentForOverlay" [rightAlign]="true" @showHideSaveCancel>
2036
- <div class="commit-buttons-button save" [class.finished]="commitFinished"
2037
- (click)="commitClick.emit($event)">
2038
- @if (committing) {
2039
- <div class="save-button-spinner">
2040
- <div #animatediv></div>
2041
- <div #animatediv></div>
2042
- <div #animatediv></div>
2043
- <div #animatediv></div>
2044
- </div>
2045
- }
2046
- @if (firstShow || commitFinished) {
2047
- <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
2048
- <path class="checkmark-check" [class.first-show]="firstShow" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg>
2049
- }
2050
- </div>
2051
- <div class="commit-buttons-button cancel" (mousedown)="$event.preventDefault()" (click)="cancelClick.emit($event)">
2052
- <div class="cancel-button"></div>
2053
- </div>
2054
- </div>
2060
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: CommitButtonsComponent, isStandalone: false, selector: "co-commit-buttons", inputs: { committing: "committing", commitFinished: "commitFinished", parentForOverlay: "parentForOverlay" }, outputs: { cancelClick: "cancelClick", commitClick: "commitClick" }, host: { properties: { "class.co-commit-buttons": "this.showClass" } }, viewQueries: [{ propertyName: "content", predicate: ["animatediv"], descendants: true, read: ElementRef }], ngImport: i0, template: `
2061
+ <div class="commit-buttons-wrapper" [overlay]="parentForOverlay" [rightAlign]="true" @showHideSaveCancel>
2062
+ <div class="commit-buttons-button save" [class.finished]="commitFinished"
2063
+ (mousedown)="$event.preventDefault()"
2064
+ (click)="commitClick.emit($event)">
2065
+ @if (committing) {
2066
+ <div class="save-button-spinner">
2067
+ <div #animatediv></div>
2068
+ <div #animatediv></div>
2069
+ <div #animatediv></div>
2070
+ <div #animatediv></div>
2071
+ </div>
2072
+ }
2073
+ @if (firstShow || commitFinished) {
2074
+ <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
2075
+ <path class="checkmark-check" [class.first-show]="firstShow" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg>
2076
+ }
2077
+ </div>
2078
+ <div class="commit-buttons-button cancel" (mousedown)="$event.preventDefault()" (click)="cancelClick.emit($event)">
2079
+ <div class="cancel-button"></div>
2080
+ </div>
2081
+ </div>
2055
2082
  `, isInline: true, dependencies: [{ kind: "directive", type: OverlayDirective, selector: "[overlay]", inputs: ["overlay", "view", "inline", "keepInView", "inheritWidth", "rightAlign", "fullSize"] }], animations: [
2056
2083
  trigger('showHideSaveCancel', [
2057
2084
  state('*', style({ transform: 'scaleY(1)', opacity: 1 })),
@@ -2064,27 +2091,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
2064
2091
  type: Component,
2065
2092
  args: [{
2066
2093
  selector: 'co-commit-buttons',
2067
- template: `
2068
- <div class="commit-buttons-wrapper" [overlay]="parentForOverlay" [rightAlign]="true" @showHideSaveCancel>
2069
- <div class="commit-buttons-button save" [class.finished]="commitFinished"
2070
- (click)="commitClick.emit($event)">
2071
- @if (committing) {
2072
- <div class="save-button-spinner">
2073
- <div #animatediv></div>
2074
- <div #animatediv></div>
2075
- <div #animatediv></div>
2076
- <div #animatediv></div>
2077
- </div>
2078
- }
2079
- @if (firstShow || commitFinished) {
2080
- <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
2081
- <path class="checkmark-check" [class.first-show]="firstShow" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg>
2082
- }
2083
- </div>
2084
- <div class="commit-buttons-button cancel" (mousedown)="$event.preventDefault()" (click)="cancelClick.emit($event)">
2085
- <div class="cancel-button"></div>
2086
- </div>
2087
- </div>
2094
+ template: `
2095
+ <div class="commit-buttons-wrapper" [overlay]="parentForOverlay" [rightAlign]="true" @showHideSaveCancel>
2096
+ <div class="commit-buttons-button save" [class.finished]="commitFinished"
2097
+ (mousedown)="$event.preventDefault()"
2098
+ (click)="commitClick.emit($event)">
2099
+ @if (committing) {
2100
+ <div class="save-button-spinner">
2101
+ <div #animatediv></div>
2102
+ <div #animatediv></div>
2103
+ <div #animatediv></div>
2104
+ <div #animatediv></div>
2105
+ </div>
2106
+ }
2107
+ @if (firstShow || commitFinished) {
2108
+ <svg class="checkmark" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 52 52">
2109
+ <path class="checkmark-check" [class.first-show]="firstShow" fill="none" d="M14.1 27.2l7.1 7.2 16.7-16.8"/></svg>
2110
+ }
2111
+ </div>
2112
+ <div class="commit-buttons-button cancel" (mousedown)="$event.preventDefault()" (click)="cancelClick.emit($event)">
2113
+ <div class="cancel-button"></div>
2114
+ </div>
2115
+ </div>
2088
2116
  `,
2089
2117
  animations: [
2090
2118
  trigger('showHideSaveCancel', [
@@ -2267,7 +2295,7 @@ class BaseInputComponent {
2267
2295
  get model() {
2268
2296
  return this._model;
2269
2297
  }
2270
- label;
2298
+ label = '';
2271
2299
  noValidation = false;
2272
2300
  initFocus;
2273
2301
  noClickFocus;
@@ -2517,7 +2545,6 @@ class BaseInputComponent {
2517
2545
  // @implements ConfigurationAdapterComponent
2518
2546
  objectConfigName;
2519
2547
  validationError = '';
2520
- shouldCommit = true;
2521
2548
  _markedAsUserTouched = false;
2522
2549
  _destroyed = false;
2523
2550
  _hasOnPushCdStrategy = false;
@@ -2543,6 +2570,7 @@ class BaseInputComponent {
2543
2570
  _formReadonlyChangeSub;
2544
2571
  _clearMarkedAsUserTouchedSub;
2545
2572
  _canSaveOrCancel = false;
2573
+ _committing = false;
2546
2574
  _commitButtonsComponentRef;
2547
2575
  _validationComponentRef;
2548
2576
  constructor(changeDetector, overlayService, formUserChangeListener, ngZoneWrapper, elementRef) {
@@ -2614,7 +2642,6 @@ class BaseInputComponent {
2614
2642
  return Promise.resolve(true);
2615
2643
  };
2616
2644
  cancelClick(event) {
2617
- this.shouldCommit = false;
2618
2645
  this.keepFocus = true;
2619
2646
  if (this._initialModelSet) {
2620
2647
  this.model = this._initialModel;
@@ -2669,7 +2696,7 @@ class BaseInputComponent {
2669
2696
  this.focus.next();
2670
2697
  }
2671
2698
  async doBlur(event, handleCommit = true) {
2672
- if (this.showSaveCancel && handleCommit && this._modelDirtyForCommit && this.shouldCommit) {
2699
+ if (this.showSaveCancel && handleCommit && this._modelDirtyForCommit) {
2673
2700
  await this._handleCommit(event, false);
2674
2701
  }
2675
2702
  setTimeout(() => {
@@ -2799,23 +2826,37 @@ class BaseInputComponent {
2799
2826
  }
2800
2827
  }
2801
2828
  async _handleCommit(event, doBlur = true) {
2802
- if (!this.showSaveCancel || (!this._modelDirtyForCommit)) {
2829
+ if (!this.showSaveCancel || !this._modelDirtyForCommit || this._committing) {
2803
2830
  return true;
2804
2831
  }
2832
+ this._committing = true;
2805
2833
  this.keepFocus = true;
2806
- this.shouldCommit = true;
2807
2834
  if (this._commitButtonsComponentRef) {
2808
2835
  this._commitButtonsComponentRef.instance.commitFinished = false;
2809
2836
  this._commitButtonsComponentRef.instance.committing = true;
2810
2837
  }
2811
2838
  this._modelDirtyForCommit = false;
2812
- const success = await this.commit(this.model);
2813
- this.keepFocus = false;
2814
- await this._commitFinished();
2815
- if (success && doBlur) {
2816
- this.doBlur(event, false);
2839
+ try {
2840
+ const success = await this.commit(this.model);
2841
+ if (success) {
2842
+ // keep the committed value as the new baseline, otherwise a later model re-emission
2843
+ // would compare against a stale _initialModel and re-open the commit guard.
2844
+ this._initialModel = this._model;
2845
+ this._modelDirtyForCommit = false;
2846
+ }
2847
+ else {
2848
+ this._modelDirtyForCommit = true;
2849
+ }
2850
+ this.keepFocus = false;
2851
+ await this._commitFinished();
2852
+ if (success && doBlur) {
2853
+ this.doBlur(event, false);
2854
+ }
2855
+ return success;
2856
+ }
2857
+ finally {
2858
+ this._committing = false;
2817
2859
  }
2818
- return success;
2819
2860
  }
2820
2861
  _commitFinished() {
2821
2862
  return new Promise((resolve) => {
@@ -2848,6 +2889,8 @@ class BaseInputComponent {
2848
2889
  this.input.disabled = disabled;
2849
2890
  }
2850
2891
  }
2892
+ // protected so numeric components can suppress the native maxlength (which, on a text input, would
2893
+ // wrongly count the decimal separator/sign as characters); they enforce precision/scale in keydown.
2851
2894
  _setNativeMaxLength(maxlength) {
2852
2895
  if (this.input && !isNaN(maxlength)) {
2853
2896
  this.input.maxLength = maxlength;
@@ -5802,48 +5845,40 @@ class GridToolbarComponent {
5802
5845
  }
5803
5846
  }
5804
5847
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: GridToolbarComponent, deps: [{ token: IconCacheService }], target: i0.ɵɵFactoryTarget.Component });
5805
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: GridToolbarComponent, isStandalone: false, selector: "co-grid-toolbar", inputs: { showEdit: "showEdit", showAdd: "showAdd", showDelete: "showDelete", deleteEnabled: "deleteEnabled" }, outputs: { editClick: "editClick", cancelClick: "cancelClick", saveClick: "saveClick", addClick: "addClick", deleteClick: "deleteClick" }, host: { properties: { "class.co-grid-toolbar": "this.showClass" } }, ngImport: i0, template: `
5806
- <div class="grid-toolbar-wrapper">
5807
- @if (showEdit) {
5808
- <co-icon [iconData]="iconsService.getIcon(icons.PenToSquareSolid)" [title]="'edit'" (click)="editClick.emit($event)"></co-icon>
5809
- }
5810
- @if (showEdit) {
5811
- <co-icon [iconData]="iconsService.getIcon(icons.RotateLeftSolid)" [title]="'cancel'" (click)="cancelClick.emit()"></co-icon>
5812
- }
5813
- @if (showEdit) {
5814
- <co-icon [iconData]="iconsService.getIcon(icons.FloppyDiskSolid)" [title]="'save'" (click)="saveClick.emit()"></co-icon>
5815
- }
5816
- @if (showAdd || showEdit) {
5817
- <co-icon [iconData]="iconsService.getIcon(icons.PlusSolid)" [title]="'add'" (click)="addClick.emit()"></co-icon>
5818
- }
5819
- @if (showDelete) {
5820
- <co-icon [iconData]="iconsService.getIcon(icons.TrashCanSolid)" [title]="'delete'" [class.disabled]="!deleteEnabled" (click)="handleDeleteClick()"></co-icon>
5821
- }
5822
- </div>
5848
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: GridToolbarComponent, isStandalone: false, selector: "co-grid-toolbar", inputs: { showEdit: "showEdit", showAdd: "showAdd", showDelete: "showDelete", deleteEnabled: "deleteEnabled" }, outputs: { editClick: "editClick", cancelClick: "cancelClick", saveClick: "saveClick", addClick: "addClick", deleteClick: "deleteClick" }, host: { properties: { "class.co-grid-toolbar": "this.showClass" } }, ngImport: i0, template: `
5849
+ <div class="grid-toolbar-wrapper">
5850
+ @if (showEdit) {
5851
+ <co-icon [iconData]="iconsService.getIcon(icons.PenToSquareSolid)" [title]="'edit'" (click)="editClick.emit($event)"></co-icon>
5852
+ <co-icon [iconData]="iconsService.getIcon(icons.RotateLeftSolid)" [title]="'cancel'" (click)="cancelClick.emit()"></co-icon>
5853
+ <co-icon [iconData]="iconsService.getIcon(icons.FloppyDiskSolid)" [title]="'save'" (click)="saveClick.emit()"></co-icon>
5854
+ }
5855
+ @if (showAdd || showEdit) {
5856
+ <co-icon [iconData]="iconsService.getIcon(icons.PlusSolid)" [title]="'add'" (click)="addClick.emit()"></co-icon>
5857
+ }
5858
+ @if (showDelete) {
5859
+ <co-icon [iconData]="iconsService.getIcon(icons.TrashCanSolid)" [title]="'delete'" [class.disabled]="!deleteEnabled" (click)="handleDeleteClick()"></co-icon>
5860
+ }
5861
+ </div>
5823
5862
  `, isInline: true, dependencies: [{ kind: "component", type: IconComponent, selector: "co-icon", inputs: ["icon", "iconData"] }], encapsulation: i0.ViewEncapsulation.None });
5824
5863
  }
5825
5864
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: GridToolbarComponent, decorators: [{
5826
5865
  type: Component,
5827
5866
  args: [{
5828
5867
  selector: "co-grid-toolbar",
5829
- template: `
5830
- <div class="grid-toolbar-wrapper">
5831
- @if (showEdit) {
5832
- <co-icon [iconData]="iconsService.getIcon(icons.PenToSquareSolid)" [title]="'edit'" (click)="editClick.emit($event)"></co-icon>
5833
- }
5834
- @if (showEdit) {
5835
- <co-icon [iconData]="iconsService.getIcon(icons.RotateLeftSolid)" [title]="'cancel'" (click)="cancelClick.emit()"></co-icon>
5836
- }
5837
- @if (showEdit) {
5838
- <co-icon [iconData]="iconsService.getIcon(icons.FloppyDiskSolid)" [title]="'save'" (click)="saveClick.emit()"></co-icon>
5839
- }
5840
- @if (showAdd || showEdit) {
5841
- <co-icon [iconData]="iconsService.getIcon(icons.PlusSolid)" [title]="'add'" (click)="addClick.emit()"></co-icon>
5842
- }
5843
- @if (showDelete) {
5844
- <co-icon [iconData]="iconsService.getIcon(icons.TrashCanSolid)" [title]="'delete'" [class.disabled]="!deleteEnabled" (click)="handleDeleteClick()"></co-icon>
5845
- }
5846
- </div>
5868
+ template: `
5869
+ <div class="grid-toolbar-wrapper">
5870
+ @if (showEdit) {
5871
+ <co-icon [iconData]="iconsService.getIcon(icons.PenToSquareSolid)" [title]="'edit'" (click)="editClick.emit($event)"></co-icon>
5872
+ <co-icon [iconData]="iconsService.getIcon(icons.RotateLeftSolid)" [title]="'cancel'" (click)="cancelClick.emit()"></co-icon>
5873
+ <co-icon [iconData]="iconsService.getIcon(icons.FloppyDiskSolid)" [title]="'save'" (click)="saveClick.emit()"></co-icon>
5874
+ }
5875
+ @if (showAdd || showEdit) {
5876
+ <co-icon [iconData]="iconsService.getIcon(icons.PlusSolid)" [title]="'add'" (click)="addClick.emit()"></co-icon>
5877
+ }
5878
+ @if (showDelete) {
5879
+ <co-icon [iconData]="iconsService.getIcon(icons.TrashCanSolid)" [title]="'delete'" [class.disabled]="!deleteEnabled" (click)="handleDeleteClick()"></co-icon>
5880
+ }
5881
+ </div>
5847
5882
  `,
5848
5883
  encapsulation: ViewEncapsulation.None,
5849
5884
  standalone: false
@@ -7164,10 +7199,71 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7164
7199
  args: ["class.co-calendar"]
7165
7200
  }] } });
7166
7201
 
7202
+ /**
7203
+ * Resolves the locale-specific decimal separator (e.g. ',' for nl-NL) from the app-wide LOCALE_ID and
7204
+ * converts between a numeric model value and its user-facing display string. Injected app-wide, so no
7205
+ * component has to be given a locale explicitly.
7206
+ *
7207
+ * The model always stays a real number (dot-based / JSON-safe); the separator only affects the display
7208
+ * string shown in the input, never the stored value.
7209
+ */
7210
+ class NumberLocaleService {
7211
+ _decimalSeparator;
7212
+ constructor(localeId) {
7213
+ // Intl uses the locale string directly, so this works without registerLocaleData().
7214
+ const parts = new Intl.NumberFormat(localeId).formatToParts(1.1);
7215
+ const decimalPart = parts.find((part) => part.type === 'decimal');
7216
+ this._decimalSeparator = decimalPart ? decimalPart.value : '.';
7217
+ }
7218
+ get decimalSeparator() {
7219
+ return this._decimalSeparator;
7220
+ }
7221
+ // Parses a user-typed display string to a number. Accepts both ',' and '.' as decimal separator so the
7222
+ // field is forgiving. Returns NaN when the text is not a parsable number.
7223
+ parse(text) {
7224
+ if (text === null || text === undefined) {
7225
+ return NaN;
7226
+ }
7227
+ const normalized = ('' + text).trim().replace(',', '.');
7228
+ if (normalized === '') {
7229
+ return NaN;
7230
+ }
7231
+ return Number(normalized);
7232
+ }
7233
+ // Formats a numeric model value to a display string using the locale decimal separator. Returns '' for
7234
+ // null/undefined/NaN. No grouping (thousands) separators are added, as this targets an editable field.
7235
+ format(value) {
7236
+ if (value === null || value === undefined || isNaN(value)) {
7237
+ return '';
7238
+ }
7239
+ return ('' + value).replace('.', this._decimalSeparator);
7240
+ }
7241
+ // Inserts the locale decimal separator at the input's caret and notifies Angular via an 'input' event.
7242
+ // Used to normalize a typed '.' to the locale separator (e.g. numpad '.' -> ',' for nl-NL).
7243
+ insertDecimalSeparator(input) {
7244
+ const start = input.selectionStart ?? input.value.length;
7245
+ const end = input.selectionEnd ?? input.value.length;
7246
+ input.value = input.value.slice(0, start) + this._decimalSeparator + input.value.slice(end);
7247
+ const caret = start + this._decimalSeparator.length;
7248
+ input.setSelectionRange(caret, caret);
7249
+ input.dispatchEvent(new Event('input', { bubbles: true }));
7250
+ }
7251
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NumberLocaleService, deps: [{ token: LOCALE_ID }], target: i0.ɵɵFactoryTarget.Injectable });
7252
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NumberLocaleService, providedIn: 'root' });
7253
+ }
7254
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: NumberLocaleService, decorators: [{
7255
+ type: Injectable,
7256
+ args: [{ providedIn: 'root' }]
7257
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
7258
+ type: Inject,
7259
+ args: [LOCALE_ID]
7260
+ }] }] });
7261
+
7167
7262
  class InputTextComponent extends BaseInputComponent {
7168
7263
  formComponent;
7169
7264
  changeDetector;
7170
7265
  overlayService;
7266
+ _numberLocale;
7171
7267
  formUserChangeListener;
7172
7268
  ngZoneWrapper;
7173
7269
  elementRef;
@@ -7243,6 +7339,26 @@ class InputTextComponent extends BaseInputComponent {
7243
7339
  get model() {
7244
7340
  return super.model;
7245
7341
  }
7342
+ // keep the display string in sync when the model changes from outside typing (init / programmatic)
7343
+ modelSet() {
7344
+ if (this.digitsOnly && !this._userTyping) {
7345
+ this._displayValue = this._numberLocale.format(this.model);
7346
+ }
7347
+ }
7348
+ // For digitsOnly the input is a text field showing a locale-formatted string; parse it back to a number
7349
+ // before emitting so the model (and thus what is stored) stays numeric. Other types emit the raw value.
7350
+ handleInputModelChange(value) {
7351
+ if (this.digitsOnly) {
7352
+ this._userTyping = true;
7353
+ this._displayValue = value === null || value === undefined ? '' : '' + value;
7354
+ const parsed = this._numberLocale.parse(value);
7355
+ this.modelChange.emit(isNaN(parsed) ? null : parsed);
7356
+ this._userTyping = false;
7357
+ }
7358
+ else {
7359
+ this.modelChange.emit(value);
7360
+ }
7361
+ }
7246
7362
  get pipedModel() {
7247
7363
  if (this.formatPipe) {
7248
7364
  try {
@@ -7254,16 +7370,23 @@ class InputTextComponent extends BaseInputComponent {
7254
7370
  }
7255
7371
  return this.model;
7256
7372
  }
7373
+ // Locale-formatted string bound to the input when digitsOnly (comma for nl-NL); the model stays numeric.
7374
+ get displayValue() {
7375
+ return this._displayValue;
7376
+ }
7257
7377
  isFocusedOnDate = false;
7258
7378
  weekInputBuffer = '';
7259
7379
  isWeekInputMode = false;
7260
7380
  _isLeftIconMouseDown = false;
7261
7381
  _isRightIconMouseDown = false;
7262
- constructor(formComponent, changeDetector, overlayService, formUserChangeListener, ngZoneWrapper, elementRef) {
7382
+ _userTyping = false;
7383
+ _displayValue = '';
7384
+ constructor(formComponent, changeDetector, overlayService, _numberLocale, formUserChangeListener, ngZoneWrapper, elementRef) {
7263
7385
  super(changeDetector, overlayService, formUserChangeListener, ngZoneWrapper, elementRef);
7264
7386
  this.formComponent = formComponent;
7265
7387
  this.changeDetector = changeDetector;
7266
7388
  this.overlayService = overlayService;
7389
+ this._numberLocale = _numberLocale;
7267
7390
  this.formUserChangeListener = formUserChangeListener;
7268
7391
  this.ngZoneWrapper = ngZoneWrapper;
7269
7392
  this.elementRef = elementRef;
@@ -7343,6 +7466,10 @@ class InputTextComponent extends BaseInputComponent {
7343
7466
  if (this.type === 'date') {
7344
7467
  this.isFocusedOnDate = false;
7345
7468
  }
7469
+ if (this.digitsOnly) {
7470
+ // normalize the display once editing stops (e.g. "12," -> "12")
7471
+ this._displayValue = this._numberLocale.format(this.model);
7472
+ }
7346
7473
  this.isFocused.emit(false);
7347
7474
  }
7348
7475
  handleDoFocus(event) {
@@ -7350,10 +7477,17 @@ class InputTextComponent extends BaseInputComponent {
7350
7477
  this.doFocus(event);
7351
7478
  }
7352
7479
  }
7480
+ // For digitsOnly the field is a text input and precision/scale is enforced in keydown; the native
7481
+ // maxlength would wrongly count the decimal separator as a character. Plain text keeps native maxlength.
7482
+ _setNativeMaxLength(maxlength) {
7483
+ if (this.digitsOnly) {
7484
+ return;
7485
+ }
7486
+ super._setNativeMaxLength(maxlength);
7487
+ }
7353
7488
  clearInput(event) {
7354
7489
  this.setModel(null);
7355
7490
  this.keepFocus = true;
7356
- this.shouldCommit = false;
7357
7491
  this.clearIconClick.emit(event);
7358
7492
  }
7359
7493
  handleKeyDownInput(event) {
@@ -7389,16 +7523,39 @@ class InputTextComponent extends BaseInputComponent {
7389
7523
  }
7390
7524
  }
7391
7525
  if (this.digitsOnly && !this.isWeekInputMode) {
7392
- const excludedKeys = this.excludePlusMinus ? ['e', '-', '+'] : ['e'];
7393
- if (excludedKeys.includes(event.key)) {
7394
- event.preventDefault();
7526
+ // the field is a text input (so a locale comma is allowed), so actively permit only numeric characters
7527
+ if (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {
7528
+ const isDigit = /\d/.test(event.key);
7529
+ const isSeparator = event.key === '.' || event.key === ',';
7530
+ const isSign = !this.excludePlusMinus && (event.key === '-' || event.key === '+');
7531
+ if (!isDigit && !isSeparator && !isSign) {
7532
+ event.preventDefault();
7533
+ return;
7534
+ }
7535
+ if (isSeparator) {
7536
+ // only one decimal separator, and only the locale one: normalize a foreign '.'/',' to it
7537
+ if (/[.,]/.test(this.input?.value ?? '')) {
7538
+ event.preventDefault();
7539
+ return;
7540
+ }
7541
+ if (event.key !== this._numberLocale.decimalSeparator) {
7542
+ event.preventDefault();
7543
+ if (this.input) {
7544
+ this._numberLocale.insertDecimalSeparator(this.input);
7545
+ }
7546
+ return;
7547
+ }
7548
+ }
7395
7549
  }
7396
7550
  }
7397
- const value = String(this.model ?? "");
7398
- if (this.type === "number" &&
7399
- this.maxLength > 0 &&
7400
- value.length >= this.maxLength &&
7401
- /^\d$/.test(key)) {
7551
+ // Native <input> ignores maxlength on numeric inputs, so enforce maxLength (as precision) and
7552
+ // decimals (as scale) ourselves for digit keys. Non-numeric text inputs keep the native maxlength.
7553
+ // Read the live element value (not this.model): a numeric input reports "" for an in-progress value
7554
+ // like "1234567.", so this.model would still hold "1234567" and wrongly block the first decimal digit.
7555
+ const currentText = this.input ? this.input.value : String(this.model ?? "");
7556
+ if ((this.digitsOnly || this.type === "number") &&
7557
+ /^\d$/.test(key) &&
7558
+ NumberUtils.WouldExceedDigitLimits(currentText, this.maxLength, this.decimals)) {
7402
7559
  event.preventDefault();
7403
7560
  }
7404
7561
  }
@@ -7448,7 +7605,7 @@ class InputTextComponent extends BaseInputComponent {
7448
7605
  const day = String(date.getDate()).padStart(2, '0');
7449
7606
  return `${year}-${month}-${day}`;
7450
7607
  }
7451
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InputTextComponent, deps: [{ token: FormComponent, optional: true }, { token: i0.ChangeDetectorRef }, { token: OverlayService }, { token: FormInputUserModelChangeListenerService }, { token: NgZoneWrapperService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
7608
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InputTextComponent, deps: [{ token: FormComponent, optional: true }, { token: i0.ChangeDetectorRef }, { token: OverlayService }, { token: NumberLocaleService }, { token: FormInputUserModelChangeListenerService }, { token: NgZoneWrapperService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
7452
7609
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: InputTextComponent, isStandalone: false, selector: "co-input-text", inputs: { useContent: "useContent", placeholder: "placeholder", align: "align", type: "type", formatPipe: "formatPipe", min: "min", max: "max", pattern: "pattern", digitsOnly: "digitsOnly", excludePlusMinus: "excludePlusMinus", showClearButton: "showClearButton", keyDownWhiteList: "keyDownWhiteList", showPlaceholderOnFocus: "showPlaceholderOnFocus", leftIcon: "leftIcon", rightIcon: "rightIcon", leftIconData: "leftIconData", rightIconData: "rightIconData", selectOnFocus: "selectOnFocus", emptyPlace: "emptyPlace", firstDayOfWeek: "firstDayOfWeek", noStyle: "noStyle", hideArrowButtons: "hideArrowButtons", model: "model" }, outputs: { leftIconClick: "leftIconClick", leftIconMouseDown: "leftIconMouseDown", leftIconMouseUp: "leftIconMouseUp", rightIconClick: "rightIconClick", rightIconMouseDown: "rightIconMouseDown", rightIconMouseUp: "rightIconMouseUp", clearIconClick: "clearIconClick", isFocused: "isFocused" }, host: { listeners: { "document:pointerup": "handleDocumentPointerUp($event)", "document:pointercancel": "handleDocumentPointerUp($event)" }, properties: { "class.no-style": "this.noStyle", "class.hide-arrows": "this.hideArrowButtons", "class.isDate": "this.isDate", "class.co-input-text": "this.showClass", "class.has-left-icon": "this.hasLeftIcon", "class.has-right-icon": "this.hasRightIcon", "class.has-own-label": "this.hasOwnLabel" } }, providers: [
7453
7610
  OverlayService, {
7454
7611
  provide: SCREEN_CONFIG_ADAPTER_COMPONENT_INTERFACE_NAME,
@@ -7483,15 +7640,16 @@ class InputTextComponent extends BaseInputComponent {
7483
7640
  <input [class.show]="focused || !formatPipe" #input
7484
7641
  [class.input-input-hidden]="useContent"
7485
7642
  [ngClass]="align"
7486
- [type]="isWeekInputMode ? 'text' : (isFocusedOnDate || (hasValue && emptyPlace)) ? 'date' : (digitsOnly ? 'number' : (type === 'date' ? 'text' : type))"
7643
+ [type]="isWeekInputMode ? 'text' : (isFocusedOnDate || (hasValue && emptyPlace)) ? 'date' : (digitsOnly ? 'text' : (type === 'date' ? 'text' : type))"
7644
+ [attr.inputmode]="digitsOnly ? 'decimal' : null"
7487
7645
  [placeholder]="type === 'date' && !isFocusedOnDate ? '' : placeholder"
7488
7646
  [pattern]="type === 'date' ? pattern : undefined"
7489
- [ngModel]="model"
7647
+ [ngModel]="digitsOnly ? displayValue : model"
7490
7648
  [min]="(type === 'number' || type === 'date') && this.min ? this.min : undefined"
7491
7649
  [max]="(type === 'number' || type === 'date') && this.max ? this.max : undefined"
7492
7650
  [readonly]="readonly"
7493
7651
  [required]="required"
7494
- (ngModelChange)="modelChange.emit($event)"
7652
+ (ngModelChange)="handleInputModelChange($event)"
7495
7653
  (keydown)="handleKeyDownInput($event)"
7496
7654
  (keyup)="keyUp.emit($event)"
7497
7655
  (focusin)="handleInputFocus($event)"
@@ -7559,15 +7717,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7559
7717
  <input [class.show]="focused || !formatPipe" #input
7560
7718
  [class.input-input-hidden]="useContent"
7561
7719
  [ngClass]="align"
7562
- [type]="isWeekInputMode ? 'text' : (isFocusedOnDate || (hasValue && emptyPlace)) ? 'date' : (digitsOnly ? 'number' : (type === 'date' ? 'text' : type))"
7720
+ [type]="isWeekInputMode ? 'text' : (isFocusedOnDate || (hasValue && emptyPlace)) ? 'date' : (digitsOnly ? 'text' : (type === 'date' ? 'text' : type))"
7721
+ [attr.inputmode]="digitsOnly ? 'decimal' : null"
7563
7722
  [placeholder]="type === 'date' && !isFocusedOnDate ? '' : placeholder"
7564
7723
  [pattern]="type === 'date' ? pattern : undefined"
7565
- [ngModel]="model"
7724
+ [ngModel]="digitsOnly ? displayValue : model"
7566
7725
  [min]="(type === 'number' || type === 'date') && this.min ? this.min : undefined"
7567
7726
  [max]="(type === 'number' || type === 'date') && this.max ? this.max : undefined"
7568
7727
  [readonly]="readonly"
7569
7728
  [required]="required"
7570
- (ngModelChange)="modelChange.emit($event)"
7729
+ (ngModelChange)="handleInputModelChange($event)"
7571
7730
  (keydown)="handleKeyDownInput($event)"
7572
7731
  (keyup)="keyUp.emit($event)"
7573
7732
  (focusin)="handleInputFocus($event)"
@@ -7618,7 +7777,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
7618
7777
  }]
7619
7778
  }], ctorParameters: () => [{ type: FormComponent, decorators: [{
7620
7779
  type: Optional
7621
- }] }, { type: i0.ChangeDetectorRef }, { type: OverlayService }, { type: FormInputUserModelChangeListenerService }, { type: NgZoneWrapperService }, { type: i0.ElementRef }], propDecorators: { useContent: [{
7780
+ }] }, { type: i0.ChangeDetectorRef }, { type: OverlayService }, { type: NumberLocaleService }, { type: FormInputUserModelChangeListenerService }, { type: NgZoneWrapperService }, { type: i0.ElementRef }], propDecorators: { useContent: [{
7622
7781
  type: Input
7623
7782
  }], placeholder: [{
7624
7783
  type: Input
@@ -9054,16 +9213,25 @@ class InputNumberPickerComponent extends BaseInputComponent {
9054
9213
  iconCacheService;
9055
9214
  overlayService;
9056
9215
  _ngZone;
9216
+ _numberLocale;
9057
9217
  ngZoneWrapper;
9058
9218
  elementRef;
9059
9219
  // @override
9060
9220
  set model(model) {
9061
9221
  this.setValue(model, true);
9062
9222
  super.model = model;
9223
+ // keep the display string in sync, unless the user is mid-typing (then their raw text is preserved)
9224
+ if (!this._userTyping) {
9225
+ this._displayValue = this._numberLocale.format(model);
9226
+ }
9063
9227
  }
9064
9228
  get model() {
9065
9229
  return super.model;
9066
9230
  }
9231
+ // Locale-formatted string bound to the native text input (comma for nl-NL); the model stays numeric.
9232
+ get displayValue() {
9233
+ return this._displayValue;
9234
+ }
9067
9235
  modelChangeOnEnter = true;
9068
9236
  showPermanentLabel = false;
9069
9237
  leftIconData;
@@ -9084,8 +9252,14 @@ class InputNumberPickerComponent extends BaseInputComponent {
9084
9252
  // @override Default true for us.
9085
9253
  noValidation = true;
9086
9254
  set decimals(decimals) {
9255
+ // Also store on the base so its precision/scale validator picks it up; a setter-only override
9256
+ // would otherwise shadow the inherited getter and make this.decimals read as undefined.
9257
+ super.decimals = decimals;
9087
9258
  this.numberLogic.decimals = decimals;
9088
9259
  }
9260
+ get decimals() {
9261
+ return super.decimals;
9262
+ }
9089
9263
  // @override
9090
9264
  modelChange = new EventEmitter();
9091
9265
  iconClick = new EventEmitter();
@@ -9105,6 +9279,8 @@ class InputNumberPickerComponent extends BaseInputComponent {
9105
9279
  plusSelected = false;
9106
9280
  _numberInputHasFocus = false;
9107
9281
  _changeFromButton = false;
9282
+ _userTyping = false;
9283
+ _displayValue = '';
9108
9284
  _numberLogicValueChangeSub;
9109
9285
  _delayBeforeStartAutoCountMs = 666;
9110
9286
  // the 'speed gears' for auto counting
@@ -9119,12 +9295,13 @@ class InputNumberPickerComponent extends BaseInputComponent {
9119
9295
  _autoCountTimeout;
9120
9296
  _stepIncrementTimeout;
9121
9297
  _startAutocountTimeout;
9122
- constructor(formComponent, iconCacheService, overlayService, _ngZone, changeDetector, formUserChangeListener, ngZoneWrapper, elementRef) {
9298
+ constructor(formComponent, iconCacheService, overlayService, _ngZone, changeDetector, formUserChangeListener, _numberLocale, ngZoneWrapper, elementRef) {
9123
9299
  super(changeDetector, overlayService, formUserChangeListener, ngZoneWrapper, elementRef);
9124
9300
  this.formComponent = formComponent;
9125
9301
  this.iconCacheService = iconCacheService;
9126
9302
  this.overlayService = overlayService;
9127
9303
  this._ngZone = _ngZone;
9304
+ this._numberLocale = _numberLocale;
9128
9305
  this.ngZoneWrapper = ngZoneWrapper;
9129
9306
  this.elementRef = elementRef;
9130
9307
  this._numberLogicValueChangeSub = this.numberLogic.valueChange.subscribe((value) => {
@@ -9174,13 +9351,40 @@ class InputNumberPickerComponent extends BaseInputComponent {
9174
9351
  if (this.myKeyDownWhiteList.find((k) => k === event.keyCode) === undefined) {
9175
9352
  return false;
9176
9353
  }
9354
+ const currentText = this.input ? this.input.value : String(this.model ?? '');
9355
+ if (event.key === '.' || event.key === ',') {
9356
+ // only one decimal separator, and only the locale one: normalize a foreign '.'/',' to it
9357
+ if (/[.,]/.test(currentText)) {
9358
+ return false;
9359
+ }
9360
+ if (event.key !== this._numberLocale.decimalSeparator) {
9361
+ if (this.input) {
9362
+ this._numberLocale.insertDecimalSeparator(this.input);
9363
+ }
9364
+ return false;
9365
+ }
9366
+ }
9367
+ // native text/number inputs ignore maxlength, so enforce maxLength (precision) and decimals (scale) here
9368
+ if (/^\d$/.test(event.key) && NumberUtils.WouldExceedDigitLimits(currentText, this.maxLength, this.decimals)) {
9369
+ return false;
9370
+ }
9371
+ }
9372
+ // precision/scale is enforced in keydown; the native maxlength on this text input would wrongly count
9373
+ // the decimal separator as a character (e.g. blocking "1234567,89" at maxLength 9), so don't set it.
9374
+ _setNativeMaxLength() {
9177
9375
  }
9178
9376
  handleBlur() {
9377
+ // normalize the display once editing stops (e.g. "12," -> "12", trailing zeros dropped)
9378
+ this._displayValue = this._numberLocale.format(this.model);
9179
9379
  this.modelChange.next(this.model);
9180
9380
  }
9181
- handleChangeModel(value) {
9381
+ handleChangeModel(text) {
9182
9382
  this._changeFromButton = false;
9183
- this.numberLogic.setValue(value);
9383
+ // preserve exactly what the user typed while they are typing (avoids caret jumps / eating the separator)
9384
+ this._userTyping = true;
9385
+ this._displayValue = text === null || text === undefined ? '' : '' + text;
9386
+ this.numberLogic.setValue(this._numberLocale.parse(text));
9387
+ this._userTyping = false;
9184
9388
  }
9185
9389
  // Note: recursive through setTimeout().
9186
9390
  doDecrementAuto() {
@@ -9282,7 +9486,7 @@ class InputNumberPickerComponent extends BaseInputComponent {
9282
9486
  break;
9283
9487
  }
9284
9488
  }
9285
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InputNumberPickerComponent, deps: [{ token: FormComponent, optional: true }, { token: IconCacheService }, { token: OverlayService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: FormInputUserModelChangeListenerService }, { token: NgZoneWrapperService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
9489
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: InputNumberPickerComponent, deps: [{ token: FormComponent, optional: true }, { token: IconCacheService }, { token: OverlayService }, { token: i0.NgZone }, { token: i0.ChangeDetectorRef }, { token: FormInputUserModelChangeListenerService }, { token: NumberLocaleService }, { token: NgZoneWrapperService }, { token: i0.ElementRef }], target: i0.ɵɵFactoryTarget.Component });
9286
9490
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.16", type: InputNumberPickerComponent, isStandalone: false, selector: "co-input-number-picker", inputs: { model: "model", modelChangeOnEnter: "modelChangeOnEnter", showPermanentLabel: "showPermanentLabel", leftIconData: "leftIconData", min: "min", step: "step", max: "max", ngModelOptions: "ngModelOptions", minusIcon: "minusIcon", plusIcon: "plusIcon", buttonShowMode: "buttonShowMode", noValidation: "noValidation", decimals: "decimals" }, outputs: { modelChange: "modelChange", iconClick: "iconClick" }, host: { properties: { "class.has-icon": "this.leftIconData", "class.show-buttons-on-focus-only": "this.showButtonsOnFocusOnly", "class.has-label": "this.hasLabel", "class.co-input-number-picker": "this.showClass" } }, providers: [
9287
9491
  OverlayService, {
9288
9492
  provide: SCREEN_CONFIG_ADAPTER_COMPONENT_INTERFACE_NAME, useExisting: forwardRef(() => InputNumberPickerComponent)
@@ -9308,15 +9512,15 @@ class InputNumberPickerComponent extends BaseInputComponent {
9308
9512
  </div>
9309
9513
  <div class="input-wrapper">
9310
9514
  @if (showPermanentLabel) {
9311
- <span class='permanent-label' [textContent]="label"></span>
9515
+ <span class='permanent-label' [textContent]="label ?? ''"></span>
9312
9516
  }
9313
- <input type="number"
9517
+ <input type="text" inputmode="decimal"
9314
9518
  [tabIndex]="readonly ? -1 : 0"
9315
- [ngModel]="model"
9519
+ [ngModel]="displayValue"
9316
9520
  [readonly]="readonly"
9317
9521
  [disabled]="disabled"
9318
9522
  [required]="required"
9319
- [placeholder]="label"
9523
+ [placeholder]="label ?? ''"
9320
9524
  (ngModelChange)="handleChangeModel($event)"
9321
9525
  (keydown)="handleInputKeyDown($event)"
9322
9526
  (blur)="handleBlur()"/>
@@ -9330,7 +9534,7 @@ class InputNumberPickerComponent extends BaseInputComponent {
9330
9534
  (mouseup)="stopAutoCounting()" (mouseleave)="stopAutoCounting()"></co-button>
9331
9535
  }
9332
9536
  </div>
9333
- `, isInline: true, dependencies: [{ kind: "directive", type: i5.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i5.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "co-button", inputs: ["label", "iconData", "iconDataRight", "isToggleButton", "isToggled", "hidden", "disabled"], outputs: ["onClick", "clickedWhileDisabled", "isToggledChange"] }, { kind: "component", type: IconComponent, selector: "co-icon", inputs: ["icon", "iconData"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
9537
+ `, isInline: true, dependencies: [{ kind: "directive", type: i5.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i5.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i5.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i5.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "component", type: ButtonComponent, selector: "co-button", inputs: ["label", "iconData", "iconDataRight", "isToggleButton", "isToggled", "hidden", "disabled"], outputs: ["onClick", "clickedWhileDisabled", "isToggledChange"] }, { kind: "component", type: IconComponent, selector: "co-icon", inputs: ["icon", "iconData"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
9334
9538
  }
9335
9539
  __decorate([
9336
9540
  InputBoolean()
@@ -9357,15 +9561,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
9357
9561
  </div>
9358
9562
  <div class="input-wrapper">
9359
9563
  @if (showPermanentLabel) {
9360
- <span class='permanent-label' [textContent]="label"></span>
9564
+ <span class='permanent-label' [textContent]="label ?? ''"></span>
9361
9565
  }
9362
- <input type="number"
9566
+ <input type="text" inputmode="decimal"
9363
9567
  [tabIndex]="readonly ? -1 : 0"
9364
- [ngModel]="model"
9568
+ [ngModel]="displayValue"
9365
9569
  [readonly]="readonly"
9366
9570
  [disabled]="disabled"
9367
9571
  [required]="required"
9368
- [placeholder]="label"
9572
+ [placeholder]="label ?? ''"
9369
9573
  (ngModelChange)="handleChangeModel($event)"
9370
9574
  (keydown)="handleInputKeyDown($event)"
9371
9575
  (blur)="handleBlur()"/>
@@ -9397,7 +9601,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImpo
9397
9601
  }] }, { type: IconCacheService, decorators: [{
9398
9602
  type: Inject,
9399
9603
  args: [IconCacheService]
9400
- }] }, { type: OverlayService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: FormInputUserModelChangeListenerService }, { type: NgZoneWrapperService }, { type: i0.ElementRef }], propDecorators: { model: [{
9604
+ }] }, { type: OverlayService }, { type: i0.NgZone }, { type: i0.ChangeDetectorRef }, { type: FormInputUserModelChangeListenerService }, { type: NumberLocaleService }, { type: NgZoneWrapperService }, { type: i0.ElementRef }], propDecorators: { model: [{
9401
9605
  type: Input
9402
9606
  }], modelChangeOnEnter: [{
9403
9607
  type: Input
@@ -14110,7 +14314,7 @@ class ListOfValuesComponent extends BaseInputComponent {
14110
14314
  collectionLoadFn;
14111
14315
  collectionLoadFnProp;
14112
14316
  leftIconData;
14113
- searchPlaceholder;
14317
+ searchPlaceholder = '';
14114
14318
  searchDisabled = false;
14115
14319
  showChips = true;
14116
14320
  showClass() {