carbon-components-angular 5.72.0 → 5.72.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/combobox/combobox.component.d.ts +3 -0
  2. package/docs/documentation/components/ComboBox.html +214 -67
  3. package/docs/documentation/components/Dropdown.html +322 -134
  4. package/docs/documentation/components/DropdownList.html +6 -2
  5. package/docs/documentation/components/RadioGroup.html +166 -77
  6. package/docs/documentation/components/TextInputLabelComponent.html +171 -65
  7. package/docs/documentation/components/TextareaLabelComponent.html +142 -74
  8. package/docs/documentation/coverage.html +22 -22
  9. package/docs/documentation/directives/TextArea.html +106 -11
  10. package/docs/documentation/directives/TextInput.html +118 -24
  11. package/docs/documentation/js/search/search_index.js +2 -2
  12. package/docs/documentation/modules/CheckboxModule/dependencies.svg +42 -42
  13. package/docs/documentation/modules/CheckboxModule.html +42 -42
  14. package/docs/documentation/modules/CodeSnippetModule/dependencies.svg +4 -4
  15. package/docs/documentation/modules/CodeSnippetModule.html +4 -4
  16. package/docs/documentation/modules/ComboBoxModule/dependencies.svg +6 -6
  17. package/docs/documentation/modules/ComboBoxModule.html +6 -6
  18. package/docs/documentation/modules/ContentSwitcherModule/dependencies.svg +4 -4
  19. package/docs/documentation/modules/ContentSwitcherModule.html +4 -4
  20. package/docs/documentation/modules/ContextMenuModule/dependencies.svg +67 -67
  21. package/docs/documentation/modules/ContextMenuModule.html +67 -67
  22. package/docs/documentation/modules/DatePickerInputModule/dependencies.svg +4 -4
  23. package/docs/documentation/modules/DatePickerInputModule.html +4 -4
  24. package/docs/documentation/modules/DatePickerModule/dependencies.svg +6 -6
  25. package/docs/documentation/modules/DatePickerModule.html +6 -6
  26. package/docs/documentation/modules/DialogModule/dependencies.svg +33 -33
  27. package/docs/documentation/modules/DialogModule.html +33 -33
  28. package/docs/documentation/modules/DocumentationModule/dependencies.svg +4 -4
  29. package/docs/documentation/modules/DocumentationModule.html +4 -4
  30. package/docs/documentation/modules/DropdownModule/dependencies.svg +53 -53
  31. package/docs/documentation/modules/DropdownModule.html +53 -53
  32. package/docs/documentation/modules/FileUploaderModule/dependencies.svg +35 -35
  33. package/docs/documentation/modules/FileUploaderModule.html +35 -35
  34. package/docs/documentation/modules/GridModule/dependencies.svg +61 -61
  35. package/docs/documentation/modules/GridModule.html +61 -61
  36. package/docs/documentation/modules/HeaderModule/dependencies.svg +4 -4
  37. package/docs/documentation/modules/HeaderModule.html +4 -4
  38. package/docs/documentation/modules/I18nModule/dependencies.svg +13 -13
  39. package/docs/documentation/modules/I18nModule.html +13 -13
  40. package/docs/documentation/modules/InlineLoadingModule/dependencies.svg +15 -15
  41. package/docs/documentation/modules/InlineLoadingModule.html +15 -15
  42. package/docs/documentation/modules/InputModule/dependencies.svg +4 -4
  43. package/docs/documentation/modules/InputModule.html +4 -4
  44. package/docs/documentation/modules/LayerModule/dependencies.svg +4 -4
  45. package/docs/documentation/modules/LayerModule.html +4 -4
  46. package/docs/documentation/modules/MenuButtonModule/dependencies.svg +4 -4
  47. package/docs/documentation/modules/MenuButtonModule.html +4 -4
  48. package/docs/documentation/modules/ModalModule/dependencies.svg +114 -114
  49. package/docs/documentation/modules/ModalModule.html +114 -114
  50. package/docs/documentation/modules/NFormsModule/dependencies.svg +4 -4
  51. package/docs/documentation/modules/NFormsModule.html +4 -4
  52. package/docs/documentation/modules/NotificationModule/dependencies.svg +4 -4
  53. package/docs/documentation/modules/NotificationModule.html +4 -4
  54. package/docs/documentation/modules/NumberModule/dependencies.svg +25 -25
  55. package/docs/documentation/modules/NumberModule.html +25 -25
  56. package/docs/documentation/modules/PaginationModule/dependencies.svg +4 -4
  57. package/docs/documentation/modules/PaginationModule.html +4 -4
  58. package/docs/documentation/modules/PanelModule/dependencies.svg +4 -4
  59. package/docs/documentation/modules/PanelModule.html +4 -4
  60. package/docs/documentation/modules/PlaceholderModule/dependencies.svg +4 -4
  61. package/docs/documentation/modules/PlaceholderModule.html +4 -4
  62. package/docs/documentation/modules/RadioModule/dependencies.svg +4 -4
  63. package/docs/documentation/modules/RadioModule.html +4 -4
  64. package/docs/documentation/modules/SearchModule/dependencies.svg +48 -44
  65. package/docs/documentation/modules/SearchModule.html +48 -44
  66. package/docs/documentation/modules/SelectModule/dependencies.svg +4 -4
  67. package/docs/documentation/modules/SelectModule.html +4 -4
  68. package/docs/documentation/modules/SideNavModule/dependencies.svg +4 -4
  69. package/docs/documentation/modules/SideNavModule.html +4 -4
  70. package/docs/documentation/modules/SkeletonModule/dependencies.svg +4 -4
  71. package/docs/documentation/modules/SkeletonModule.html +4 -4
  72. package/docs/documentation/modules/SliderModule/dependencies.svg +26 -26
  73. package/docs/documentation/modules/SliderModule.html +26 -26
  74. package/docs/documentation/modules/StructuredListModule/dependencies.svg +43 -43
  75. package/docs/documentation/modules/StructuredListModule.html +43 -43
  76. package/docs/documentation/modules/TableModule/dependencies.svg +225 -225
  77. package/docs/documentation/modules/TableModule.html +225 -225
  78. package/docs/documentation/modules/TabsModule/dependencies.svg +136 -136
  79. package/docs/documentation/modules/TabsModule.html +136 -136
  80. package/docs/documentation/modules/TagModule/dependencies.svg +38 -38
  81. package/docs/documentation/modules/TagModule.html +38 -38
  82. package/docs/documentation/modules/ThemeModule/dependencies.svg +4 -4
  83. package/docs/documentation/modules/ThemeModule.html +4 -4
  84. package/docs/documentation/modules/TilesModule/dependencies.svg +108 -108
  85. package/docs/documentation/modules/TilesModule.html +108 -108
  86. package/docs/documentation/modules/TimePickerModule/dependencies.svg +41 -45
  87. package/docs/documentation/modules/TimePickerModule.html +41 -45
  88. package/docs/documentation/modules/TimePickerSelectModule/dependencies.svg +46 -42
  89. package/docs/documentation/modules/TimePickerSelectModule.html +46 -42
  90. package/docs/documentation/modules/ToggleModule/dependencies.svg +7 -7
  91. package/docs/documentation/modules/ToggleModule.html +7 -7
  92. package/docs/documentation/modules/TooltipModule/dependencies.svg +28 -28
  93. package/docs/documentation/modules/TooltipModule.html +28 -28
  94. package/docs/documentation/modules/TreeviewModule/dependencies.svg +28 -28
  95. package/docs/documentation/modules/TreeviewModule.html +28 -28
  96. package/docs/documentation.json +510 -362
  97. package/docs/storybook/1345.da6e3dec.iframe.bundle.js +1 -0
  98. package/docs/storybook/3224.14e2c79a.iframe.bundle.js +1 -0
  99. package/docs/storybook/557.d4341469.iframe.bundle.js +1 -0
  100. package/docs/storybook/7019.75ad5817.iframe.bundle.js +2 -0
  101. package/docs/storybook/955.7522f55b.iframe.bundle.js +1 -0
  102. package/docs/storybook/combobox-combobox-stories.e3d08f7d.iframe.bundle.js +1 -0
  103. package/docs/storybook/dropdown-dropdown-stories.cf59b2ab.iframe.bundle.js +1 -0
  104. package/docs/storybook/iframe.html +2 -2
  105. package/docs/storybook/{input-input-stories.85a9e65e.iframe.bundle.js → input-input-stories.8bf34960.iframe.bundle.js} +1 -1
  106. package/docs/storybook/{input-textarea-stories.77240fb3.iframe.bundle.js → input-textarea-stories.ad775432.iframe.bundle.js} +1 -1
  107. package/docs/storybook/main.a1247bb8.iframe.bundle.js +1 -0
  108. package/docs/storybook/modal-modal-stories.cc2d04cb.iframe.bundle.js +1 -0
  109. package/docs/storybook/{pagination-pagination-nav-stories.547eede3.iframe.bundle.js → pagination-pagination-nav-stories.01637d11.iframe.bundle.js} +1 -1
  110. package/docs/storybook/{pagination-pagination-stories.fa7c9094.iframe.bundle.js → pagination-pagination-stories.40d17ebd.iframe.bundle.js} +1 -1
  111. package/docs/storybook/{patterns-filtering-single-selection-stories.ec91f833.iframe.bundle.js → patterns-filtering-multi-selection-stories.a46a1d6e.iframe.bundle.js} +1 -1
  112. package/docs/storybook/{patterns-filtering-multiple-categories-stories.531f27d7.iframe.bundle.js → patterns-filtering-multiple-categories-stories.740c719e.iframe.bundle.js} +1 -1
  113. package/docs/storybook/{patterns-filtering-multi-selection-stories.9086f77f.iframe.bundle.js → patterns-filtering-single-selection-stories.cc647b4a.iframe.bundle.js} +1 -1
  114. package/docs/storybook/{patterns-forms-multi-step-form-stories.8696062a.iframe.bundle.js → patterns-forms-multi-step-form-stories.2ea46e56.iframe.bundle.js} +1 -1
  115. package/docs/storybook/{patterns-loading-large-loading-stories.734fb9bc.iframe.bundle.js → patterns-loading-large-loading-stories.e6ae3e31.iframe.bundle.js} +1 -1
  116. package/docs/storybook/{patterns-loading-progressive-loading-stories.10bcf9f2.iframe.bundle.js → patterns-loading-progressive-loading-stories.63165c09.iframe.bundle.js} +1 -1
  117. package/docs/storybook/project.json +1 -1
  118. package/docs/storybook/radio-radio-stories.8ff73370.iframe.bundle.js +1 -0
  119. package/docs/storybook/runtime~main.b11c471e.iframe.bundle.js +1 -0
  120. package/dropdown/dropdown.component.d.ts +8 -1
  121. package/dropdown/list/dropdown-list.component.d.ts +1 -1
  122. package/esm2020/combobox/combobox.component.mjs +19 -9
  123. package/esm2020/dropdown/dropdown.component.mjs +31 -15
  124. package/esm2020/dropdown/list/dropdown-list.component.mjs +1 -1
  125. package/esm2020/input/input.directive.mjs +11 -5
  126. package/esm2020/input/text-area.directive.mjs +11 -5
  127. package/esm2020/input/text-input-label.component.mjs +38 -15
  128. package/esm2020/input/textarea-label.component.mjs +46 -21
  129. package/esm2020/radio/radio-group.component.mjs +19 -7
  130. package/fesm2015/carbon-components-angular-combobox.mjs +18 -8
  131. package/fesm2015/carbon-components-angular-combobox.mjs.map +1 -1
  132. package/fesm2015/carbon-components-angular-dropdown.mjs +31 -14
  133. package/fesm2015/carbon-components-angular-dropdown.mjs.map +1 -1
  134. package/fesm2015/carbon-components-angular-input.mjs +112 -46
  135. package/fesm2015/carbon-components-angular-input.mjs.map +1 -1
  136. package/fesm2015/carbon-components-angular-radio.mjs +18 -6
  137. package/fesm2015/carbon-components-angular-radio.mjs.map +1 -1
  138. package/fesm2020/carbon-components-angular-combobox.mjs +18 -8
  139. package/fesm2020/carbon-components-angular-combobox.mjs.map +1 -1
  140. package/fesm2020/carbon-components-angular-dropdown.mjs +30 -14
  141. package/fesm2020/carbon-components-angular-dropdown.mjs.map +1 -1
  142. package/fesm2020/carbon-components-angular-input.mjs +102 -45
  143. package/fesm2020/carbon-components-angular-input.mjs.map +1 -1
  144. package/fesm2020/carbon-components-angular-radio.mjs +18 -6
  145. package/fesm2020/carbon-components-angular-radio.mjs.map +1 -1
  146. package/input/input.directive.d.ts +4 -1
  147. package/input/text-area.directive.d.ts +4 -1
  148. package/input/text-input-label.component.d.ts +9 -5
  149. package/input/textarea-label.component.d.ts +5 -3
  150. package/package.json +1 -1
  151. package/radio/radio-group.component.d.ts +4 -2
  152. package/docs/storybook/1250.47c381c1.iframe.bundle.js +0 -1
  153. package/docs/storybook/1345.9ccf4f3f.iframe.bundle.js +0 -1
  154. package/docs/storybook/3224.3e279e46.iframe.bundle.js +0 -1
  155. package/docs/storybook/7019.b8944046.iframe.bundle.js +0 -2
  156. package/docs/storybook/955.99b6ac85.iframe.bundle.js +0 -1
  157. package/docs/storybook/combobox-combobox-stories.e7427226.iframe.bundle.js +0 -1
  158. package/docs/storybook/dropdown-dropdown-stories.a76101be.iframe.bundle.js +0 -1
  159. package/docs/storybook/main.cdbf1814.iframe.bundle.js +0 -1
  160. package/docs/storybook/modal-modal-stories.0a864a6a.iframe.bundle.js +0 -1
  161. package/docs/storybook/radio-radio-stories.444fc044.iframe.bundle.js +0 -1
  162. package/docs/storybook/runtime~main.e32f2dfb.iframe.bundle.js +0 -1
  163. /package/docs/storybook/{7019.b8944046.iframe.bundle.js.LICENSE.txt → 7019.75ad5817.iframe.bundle.js.LICENSE.txt} +0 -0
@@ -1,10 +1,12 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Directive, Input, HostBinding, TemplateRef, Component, ViewChild, ContentChild, EventEmitter, Output, NgModule } from '@angular/core';
2
+ import { Directive, Self, Optional, Input, HostBinding, TemplateRef, Component, ViewChild, ContentChild, EventEmitter, Output, NgModule } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
3
4
  import { FormsModule } from '@angular/forms';
4
- import * as i1 from '@angular/common';
5
+ import * as i1$1 from '@angular/common';
5
6
  import { CommonModule } from '@angular/common';
6
7
  import * as i2 from 'carbon-components-angular/icon';
7
8
  import { IconModule } from 'carbon-components-angular/icon';
9
+ import { startWith } from 'rxjs/operators';
8
10
  import { BaseIconButton, ButtonModule } from 'carbon-components-angular/button';
9
11
  import * as i3 from 'carbon-components-angular/tooltip';
10
12
  import { TooltipModule } from 'carbon-components-angular/tooltip';
@@ -21,7 +23,8 @@ import { TooltipModule } from 'carbon-components-angular/tooltip';
21
23
  * See the [vanilla carbon docs](http://www.carbondesignsystem.com/components/text-input/code) for more detail.
22
24
  */
23
25
  class TextInput {
24
- constructor() {
26
+ constructor(ngControl) {
27
+ this.ngControl = ngControl;
25
28
  /**
26
29
  * @deprecated since v5 - Use `cdsLayer` directive instead
27
30
  * `light` or `dark` input theme
@@ -65,14 +68,18 @@ class TextInput {
65
68
  return this.invalid ? true : undefined;
66
69
  }
67
70
  }
68
- TextInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInput, deps: [], target: i0.ɵɵFactoryTarget.Directive });
71
+ TextInput.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInput, deps: [{ token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
69
72
  TextInput.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: TextInput, selector: "[cdsText], [ibmText]", inputs: { theme: "theme", size: "size", invalid: "invalid", warn: "warn", skeleton: "skeleton" }, host: { properties: { "class.cds--text-input": "this.inputClass", "class.cds--text-input--sm": "this.isSizeSm", "class.cds--text-input--md": "this.isSizeMd", "class.cds--text-input--lg": "this.isSizelg", "class.cds--layout--size-sm": "this.sizeSm", "class.cds--layout--size-md": "this.sizeMd", "class.cds--layout--size-lg": "this.sizelg", "class.cds--text-input--invalid": "this.invalid", "class.cds--text-input--warning": "this.warn", "class.cds--skeleton": "this.skeleton", "class.cds--text-input--light": "this.isLightTheme", "attr.data-invalid": "this.getInvalidAttribute" } }, ngImport: i0 });
70
73
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInput, decorators: [{
71
74
  type: Directive,
72
75
  args: [{
73
76
  selector: "[cdsText], [ibmText]"
74
77
  }]
75
- }], propDecorators: { theme: [{
78
+ }], ctorParameters: function () { return [{ type: i1.NgControl, decorators: [{
79
+ type: Self
80
+ }, {
81
+ type: Optional
82
+ }] }]; }, propDecorators: { theme: [{
76
83
  type: Input
77
84
  }], size: [{
78
85
  type: Input
@@ -132,7 +139,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
132
139
  * See the [vanilla carbon docs](http://www.carbondesignsystem.com/components/text-input/code) for more detail.
133
140
  */
134
141
  class TextArea {
135
- constructor() {
142
+ constructor(ngControl) {
143
+ this.ngControl = ngControl;
136
144
  /**
137
145
  * @deprecated since v5 - Use `cdsLayer` directive instead
138
146
  * `light` or `dark` input theme
@@ -153,14 +161,18 @@ class TextArea {
153
161
  return this.invalid ? true : undefined;
154
162
  }
155
163
  }
156
- TextArea.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextArea, deps: [], target: i0.ɵɵFactoryTarget.Directive });
164
+ TextArea.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextArea, deps: [{ token: i1.NgControl, optional: true, self: true }], target: i0.ɵɵFactoryTarget.Directive });
157
165
  TextArea.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "14.3.0", type: TextArea, selector: "[cdsTextArea], [ibmTextArea]", inputs: { theme: "theme", invalid: "invalid", warn: "warn", skeleton: "skeleton" }, host: { properties: { "class.cds--text-area": "this.baseClass", "class.cds--text-area--invalid": "this.invalid", "class.cds--text-area--warn": "this.warn", "class.cds--skeleton": "this.skeleton", "class.cds--text-area--light": "this.isLightTheme", "attr.data-invalid": "this.getInvalidAttr" } }, ngImport: i0 });
158
166
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextArea, decorators: [{
159
167
  type: Directive,
160
168
  args: [{
161
169
  selector: "[cdsTextArea], [ibmTextArea]"
162
170
  }]
163
- }], propDecorators: { theme: [{
171
+ }], ctorParameters: function () { return [{ type: i1.NgControl, decorators: [{
172
+ type: Self
173
+ }, {
174
+ type: Optional
175
+ }] }]; }, propDecorators: { theme: [{
164
176
  type: Input
165
177
  }], baseClass: [{
166
178
  type: HostBinding,
@@ -371,12 +383,14 @@ class TextareaLabelComponent {
371
383
  * on each change. Excess words are trimmed from the end of the value.
372
384
  */
373
385
  this.counterMode = "character";
374
- // Tracks current character / word count for the counter display.
386
+ // Tracks current character / word count for the counter display.
375
387
  this.textCount = 0;
376
388
  this.labelClass = true;
377
389
  // Cached reference to the textarea element, set once in ngAfterViewInit.
378
390
  this._textareaElement = null;
379
- // Cached listener so it can be removed precisely (avoids anonymous-function leak)
391
+ // RxJS subscription used when NgControl is available (template-driven & reactive forms).
392
+ this._subscription = null;
393
+ // Fallback DOM listener used only when no NgControl is present (plain textarea).
380
394
  this._inputListener = null;
381
395
  }
382
396
  get isReadonly() {
@@ -423,7 +437,6 @@ class TextareaLabelComponent {
423
437
  }
424
438
  /**
425
439
  * Attach/remove listener and seed `textCount` from the textarea's current value.
426
- * @param changes
427
440
  */
428
441
  ngOnChanges(changes) {
429
442
  if (changes.enableCounter && !changes.enableCounter.firstChange) {
@@ -467,27 +480,47 @@ class TextareaLabelComponent {
467
480
  }
468
481
  }
469
482
  /**
470
- * Attaches the input event listener, ensuring it is never added twice.
483
+ * Attaches the counter listener, listen for either ngControl or native DOM input
484
+ * event listener
471
485
  */
472
486
  _attachCounterListener() {
473
487
  this._detachCounterListener();
474
- if (!this._textareaElement) {
475
- return;
476
- }
477
- this._inputListener = (e) => {
478
- const el = e.target;
479
- // Word-mode enforcement: clamp value to maxCount words on each input so
480
- // the textarea never holds more words than allowed. Character mode relies
481
- // on the native `maxlength` attribute set by the developer.
482
- if (this.counterMode === "word" && this.maxCount != null) {
483
- const clamped = this._truncateToWordLimit(el.value || "", this.maxCount);
484
- if (clamped !== el.value) {
485
- el.value = clamped;
488
+ const control = this.textArea?.ngControl;
489
+ if (control?.valueChanges) {
490
+ // NgControl listener
491
+ this._subscription = control.valueChanges
492
+ .pipe(startWith(control.value))
493
+ .subscribe((value) => {
494
+ const raw = value || "";
495
+ if (this.counterMode === "word" && this.maxCount != null) {
496
+ const clamped = this._truncateToWordLimit(raw, this.maxCount);
497
+ if (clamped !== raw) {
498
+ // Write back through the control so the form model stays in sync.
499
+ // emitEvent false to avoid infinite loop
500
+ control?.control?.setValue(clamped, { emitEvent: false });
501
+ }
486
502
  }
503
+ this.textCount = this._countValue(raw);
504
+ this.changeDetectorRef.markForCheck();
505
+ });
506
+ }
507
+ else {
508
+ // Fallback DOM path
509
+ if (!this._textareaElement) {
510
+ return;
487
511
  }
488
- this.textCount = this._countValue(el.value || "");
489
- };
490
- this._textareaElement.addEventListener("input", this._inputListener);
512
+ this._inputListener = (e) => {
513
+ const el = e.target;
514
+ if (this.counterMode === "word" && this.maxCount != null) {
515
+ const clamped = this._truncateToWordLimit(el.value || "", this.maxCount);
516
+ if (clamped !== el.value) {
517
+ el.value = clamped;
518
+ }
519
+ }
520
+ this.textCount = this._countValue(el.value || "");
521
+ };
522
+ this._textareaElement.addEventListener("input", this._inputListener);
523
+ }
491
524
  }
492
525
  /**
493
526
  * Truncates `value` so it contains at most `limit` Unicode words.
@@ -511,9 +544,12 @@ class TextareaLabelComponent {
511
544
  return wordsSeen < limit ? value : value.slice(0, cutIndex);
512
545
  }
513
546
  /**
514
- * Removes the input event listener and clears the cached reference.
547
+ * Removes the subscription (NgControl path) and removes the DOM listener
548
+ * (fallback path). Safe to call when neither is active.
515
549
  */
516
550
  _detachCounterListener() {
551
+ this._subscription?.unsubscribe();
552
+ this._subscription = null;
517
553
  if (this._inputListener && this._textareaElement) {
518
554
  this._textareaElement.removeEventListener("input", this._inputListener);
519
555
  this._inputListener = null;
@@ -629,7 +665,7 @@ TextareaLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0",
629
665
  </div>
630
666
  </ng-container>
631
667
  </ng-container>
632
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
668
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
633
669
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextareaLabelComponent, decorators: [{
634
670
  type: Component,
635
671
  args: [{
@@ -860,7 +896,9 @@ class TextInputLabelComponent {
860
896
  this.textInputWrapper = true;
861
897
  // Cached reference to the input element, set once in ngAfterViewInit.
862
898
  this._inputElement = null;
863
- // Cached listener so it can be removed precisely (avoids anonymous-function leak).
899
+ // RxJS subscription used when NgControl is available (template-driven & reactive forms).
900
+ this._subscription = null;
901
+ // Fallback cached DOM listener so it can be removed precisely (avoids anonymous-function leak).
864
902
  this._inputListener = null;
865
903
  }
866
904
  get isInlineWrapper() {
@@ -908,8 +946,7 @@ class TextInputLabelComponent {
908
946
  }
909
947
  }
910
948
  /**
911
- * Attach/remove listener and seed `textCount` from the textarea's current value.
912
- * @param changes
949
+ * Attach/remove listener and seed `textCount` from the input's current value.
913
950
  */
914
951
  ngOnChanges(changes) {
915
952
  if (changes.enableCounter && !changes.enableCounter.firstChange) {
@@ -935,23 +972,40 @@ class TextInputLabelComponent {
935
972
  return value instanceof TemplateRef;
936
973
  }
937
974
  /**
938
- * Attaches the input event listener, ensuring it is never added twice.
975
+ * Attaches the counter listener, listen for either ngControl or native DOM input
976
+ * event listener
939
977
  */
940
978
  _attachCounterListener() {
941
979
  this._detachCounterListener();
942
- if (!this._inputElement) {
943
- return;
980
+ const control = this.textInput?.ngControl;
981
+ if (control?.valueChanges) {
982
+ // NgControl listener
983
+ this._subscription = control.valueChanges
984
+ .pipe(startWith(control.value))
985
+ .subscribe((value) => {
986
+ this.textCount = value?.length || 0;
987
+ this.changeDetectorRef.markForCheck();
988
+ });
989
+ }
990
+ else {
991
+ // Fallback DOM path
992
+ if (!this._inputElement) {
993
+ return;
994
+ }
995
+ this._inputListener = (e) => {
996
+ this.textCount = e.target.value?.length || 0;
997
+ this.changeDetectorRef.detectChanges();
998
+ };
999
+ this._inputElement.addEventListener("input", this._inputListener);
944
1000
  }
945
- this._inputListener = (e) => {
946
- this.textCount = e.target.value?.length || 0;
947
- this.changeDetectorRef.detectChanges();
948
- };
949
- this._inputElement.addEventListener("input", this._inputListener);
950
1001
  }
951
1002
  /**
952
- * Removes the input event listener and clears the cached reference.
1003
+ * Removes the subscription (NgControl path) or removes the DOM listener.
1004
+ * Safe to call when neither is active.
953
1005
  */
954
1006
  _detachCounterListener() {
1007
+ this._subscription?.unsubscribe();
1008
+ this._subscription = null;
955
1009
  if (this._inputListener && this._inputElement) {
956
1010
  this._inputElement.removeEventListener("input", this._inputListener);
957
1011
  this._inputListener = null;
@@ -963,7 +1017,7 @@ class TextInputLabelComponent {
963
1017
  */
964
1018
  TextInputLabelComponent.labelCounter = 0;
965
1019
  TextInputLabelComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInputLabelComponent, deps: [{ token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
966
- TextInputLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TextInputLabelComponent, selector: "cds-text-label, ibm-text-label", inputs: { labelInputID: "labelInputID", disabled: "disabled", skeleton: "skeleton", labelTemplate: "labelTemplate", textInputTemplate: "textInputTemplate", helperText: "helperText", invalidText: "invalidText", invalid: "invalid", warn: "warn", warnText: "warnText", ariaLabel: "ariaLabel", fluid: "fluid", decorator: "decorator", hideLabel: "hideLabel", inline: "inline", size: "size", enableCounter: "enableCounter", maxCount: "maxCount" }, host: { properties: { "class.cds--text-input-wrapper--inline": "this.isInlineWrapper", "class.cds--text-input-wrapper--readonly": "this.isReadonly", "class.cds--text-input--fluid": "this.fluidClass", "class.cds--text-input--fluid__skeleton": "this.fluidSkeletonClass", "class.cds--form-item": "this.labelClass", "class.cds--text-input-wrapper": "this.textInputWrapper" } }, viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
1020
+ TextInputLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: TextInputLabelComponent, selector: "cds-text-label, ibm-text-label", inputs: { labelInputID: "labelInputID", disabled: "disabled", skeleton: "skeleton", labelTemplate: "labelTemplate", textInputTemplate: "textInputTemplate", helperText: "helperText", invalidText: "invalidText", invalid: "invalid", warn: "warn", warnText: "warnText", ariaLabel: "ariaLabel", fluid: "fluid", decorator: "decorator", hideLabel: "hideLabel", inline: "inline", size: "size", enableCounter: "enableCounter", maxCount: "maxCount" }, host: { properties: { "class.cds--text-input-wrapper--inline": "this.isInlineWrapper", "class.cds--text-input-wrapper--readonly": "this.isReadonly", "class.cds--text-input--fluid": "this.fluidClass", "class.cds--text-input--fluid__skeleton": "this.fluidSkeletonClass", "class.cds--form-item": "this.labelClass", "class.cds--text-input-wrapper": "this.textInputWrapper" } }, queries: [{ propertyName: "textInput", first: true, predicate: TextInput, descendants: true }], viewQueries: [{ propertyName: "wrapper", first: true, predicate: ["wrapper"], descendants: true }], usesOnChanges: true, ngImport: i0, template: `
967
1021
  <ng-container *ngIf="skeleton">
968
1022
  <span class="cds--label cds--skeleton"></span>
969
1023
  <div class="cds--text-input cds--skeleton"></div>
@@ -1087,7 +1141,7 @@ TextInputLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0"
1087
1141
  <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
1088
1142
  </div>
1089
1143
  </ng-template>
1090
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
1144
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }] });
1091
1145
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: TextInputLabelComponent, decorators: [{
1092
1146
  type: Component,
1093
1147
  args: [{
@@ -1269,6 +1323,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImpor
1269
1323
  }], wrapper: [{
1270
1324
  type: ViewChild,
1271
1325
  args: ["wrapper", { static: false }]
1326
+ }], textInput: [{
1327
+ type: ContentChild,
1328
+ args: [TextInput, { static: false }]
1272
1329
  }], labelClass: [{
1273
1330
  type: HostBinding,
1274
1331
  args: ["class.cds--form-item"]
@@ -1516,7 +1573,7 @@ PasswordInputLabelComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.
1516
1573
  </div>
1517
1574
  </ng-container>
1518
1575
  </div>
1519
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: i3.Tooltip, selector: "cds-tooltip, ibm-tooltip", inputs: ["id", "enterDelayMs", "leaveDelayMs", "disabled", "description", "templateContext"] }] });
1576
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: i3.Tooltip, selector: "cds-tooltip, ibm-tooltip", inputs: ["id", "enterDelayMs", "leaveDelayMs", "disabled", "description", "templateContext"] }] });
1520
1577
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: PasswordInputLabelComponent, decorators: [{
1521
1578
  type: Component,
1522
1579
  args: [{
@@ -1929,7 +1986,7 @@ Label.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0
1929
1986
  <ng-template *ngIf="isTemplate(warnText)" [ngTemplateOutlet]="warnText"></ng-template>
1930
1987
  </div>
1931
1988
  </ng-template>
1932
- `, isInline: true, dependencies: [{ kind: "directive", type: i1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: TextareaLabelComponent, selector: "cds-textarea-label, ibm-textarea-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "textAreaTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "fluid", "hideLabel", "enableCounter", "maxCount", "counterMode", "decorator"] }, { kind: "component", type: TextInputLabelComponent, selector: "cds-text-label, ibm-text-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "textInputTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "fluid", "decorator", "hideLabel", "inline", "size", "enableCounter", "maxCount"] }, { kind: "component", type: PasswordInputLabelComponent, selector: "cds-password-label, ibm-password-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "passwordInputTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "hidePasswordLabel", "showPasswordLabel", "fluid", "hideLabel", "inline"], outputs: ["togglePasswordVisibility"] }] });
1989
+ `, isInline: true, dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1$1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i1$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i1$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i1$1.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "directive", type: i2.IconDirective, selector: "[cdsIcon], [ibmIcon]", inputs: ["ibmIcon", "cdsIcon", "size", "title", "ariaLabel", "ariaLabelledBy", "ariaHidden", "isFocusable"] }, { kind: "component", type: TextareaLabelComponent, selector: "cds-textarea-label, ibm-textarea-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "textAreaTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "fluid", "hideLabel", "enableCounter", "maxCount", "counterMode", "decorator"] }, { kind: "component", type: TextInputLabelComponent, selector: "cds-text-label, ibm-text-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "textInputTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "fluid", "decorator", "hideLabel", "inline", "size", "enableCounter", "maxCount"] }, { kind: "component", type: PasswordInputLabelComponent, selector: "cds-password-label, ibm-password-label", inputs: ["labelInputID", "disabled", "skeleton", "labelTemplate", "passwordInputTemplate", "helperText", "invalidText", "invalid", "warn", "warnText", "ariaLabel", "hidePasswordLabel", "showPasswordLabel", "fluid", "hideLabel", "inline"], outputs: ["togglePasswordVisibility"] }] });
1933
1990
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: Label, decorators: [{
1934
1991
  type: Component,
1935
1992
  args: [{