@letsprogram/ng-oat 0.1.3 → 0.1.5

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,7 @@
1
1
  import * as i0 from '@angular/core';
2
- import { makeEnvironmentProviders, provideAppInitializer, inject, PLATFORM_ID, Injectable, ElementRef, DestroyRef, signal, output, afterNextRender, Directive, InjectionToken, Renderer2, ViewContainerRef, input, TemplateRef, effect, computed, Component, model, CUSTOM_ELEMENTS_SCHEMA, viewChild, viewChildren, contentChildren, contentChild } from '@angular/core';
2
+ import { makeEnvironmentProviders, provideAppInitializer, inject, PLATFORM_ID, Injectable, ElementRef, DestroyRef, signal, output, afterNextRender, Directive, InjectionToken, Renderer2, ViewContainerRef, input, TemplateRef, effect, computed, Component, model, forwardRef, CUSTOM_ELEMENTS_SCHEMA, viewChild, viewChildren, contentChildren, contentChild, HostListener } from '@angular/core';
3
3
  import { DOCUMENT, isPlatformBrowser, NgTemplateOutlet, NgSwitch, NgSwitchCase, NgSwitchDefault } from '@angular/common';
4
+ import { NG_VALUE_ACCESSOR } from '@angular/forms';
4
5
 
5
6
  const DEFAULT_OPTIONS = {
6
7
  assets: { css: false },
@@ -1772,6 +1773,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1772
1773
  }]
1773
1774
  }], propDecorators: { size: [{ type: i0.Input, args: [{ isSignal: true, alias: "size", required: false }] }], overlay: [{ type: i0.Input, args: [{ isSignal: true, alias: "overlay", required: false }] }] } });
1774
1775
 
1776
+ /** Injection token provided by each value-type ng-oat form component. */
1777
+ const NG_OAT_VALUE_HOST = new InjectionToken('NG_OAT_VALUE_HOST');
1778
+ /** Injection token provided by each checkbox-type ng-oat form component. */
1779
+ const NG_OAT_CHECKBOX_HOST = new InjectionToken('NG_OAT_CHECKBOX_HOST');
1780
+
1775
1781
  /**
1776
1782
  * Angular wrapper for Oat CSS toggle switch.
1777
1783
  * Implements `FormCheckboxControl` for seamless Signal Forms integration — no CVA needed.
@@ -1789,16 +1795,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1789
1795
  class NgOatSwitch {
1790
1796
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
1791
1797
  checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
1792
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1798
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
1799
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
1793
1800
  value = undefined;
1794
1801
  changed = output();
1795
1802
  onInputChange(event) {
1796
1803
  const val = event.target.checked;
1797
1804
  this.checked.set(val);
1805
+ this.touched.set(true);
1798
1806
  this.changed.emit(val);
1799
1807
  }
1800
1808
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatSwitch, deps: [], target: i0.ɵɵFactoryTarget.Component });
1801
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.0", type: NgOatSwitch, isStandalone: true, selector: "ng-oat-switch", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", changed: "changed" }, ngImport: i0, template: `
1809
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.0", type: NgOatSwitch, isStandalone: true, selector: "ng-oat-switch", inputs: { label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", disabled: "disabledChange", touched: "touchedChange", changed: "changed" }, providers: [{ provide: NG_OAT_CHECKBOX_HOST, useExisting: forwardRef(() => NgOatSwitch) }], ngImport: i0, template: `
1802
1810
  <label>
1803
1811
  <input
1804
1812
  type="checkbox"
@@ -1815,6 +1823,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1815
1823
  type: Component,
1816
1824
  args: [{
1817
1825
  selector: 'ng-oat-switch',
1826
+ providers: [{ provide: NG_OAT_CHECKBOX_HOST, useExisting: forwardRef(() => NgOatSwitch) }],
1818
1827
  template: `
1819
1828
  <label>
1820
1829
  <input
@@ -1828,7 +1837,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1828
1837
  </label>
1829
1838
  `,
1830
1839
  }]
1831
- }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
1840
+ }], propDecorators: { label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], changed: [{ type: i0.Output, args: ["changed"] }] } });
1832
1841
 
1833
1842
  /**
1834
1843
  * Angular wrapper for Oat CSS skeleton loader.
@@ -1979,7 +1988,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
1979
1988
  * <ng-oat-table
1980
1989
  * [columns]="[{key:'name', label:'Name'}, {key:'email', label:'Email'}]"
1981
1990
  * [data]="users"
1982
- * [striped]="true"
1991
+ * [scrollX]="true"
1992
+ * [scrollY]="'320px'"
1983
1993
  * (rowClick)="onRowClick($event)">
1984
1994
  * </ng-oat-table>
1985
1995
  * ```
@@ -1990,13 +2000,17 @@ class NgOatTable {
1990
2000
  striped = input(false, ...(ngDevMode ? [{ debugName: "striped" }] : []));
1991
2001
  clickable = input(false, ...(ngDevMode ? [{ debugName: "clickable" }] : []));
1992
2002
  emptyText = input('No data available.', ...(ngDevMode ? [{ debugName: "emptyText" }] : []));
2003
+ scrollX = input(false, ...(ngDevMode ? [{ debugName: "scrollX" }] : []));
2004
+ scrollY = input('', ...(ngDevMode ? [{ debugName: "scrollY" }] : []));
1993
2005
  rowClick = output();
1994
2006
  onRowClick(row) {
1995
2007
  this.rowClick.emit(row);
1996
2008
  }
1997
2009
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatTable, deps: [], target: i0.ɵɵFactoryTarget.Component });
1998
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatTable, isStandalone: true, selector: "ng-oat-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, clickable: { classPropertyName: "clickable", publicName: "clickable", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick" }, ngImport: i0, template: `
1999
- <div class="table">
2010
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatTable, isStandalone: true, selector: "ng-oat-table", inputs: { columns: { classPropertyName: "columns", publicName: "columns", isSignal: true, isRequired: true, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: true, transformFunction: null }, striped: { classPropertyName: "striped", publicName: "striped", isSignal: true, isRequired: false, transformFunction: null }, clickable: { classPropertyName: "clickable", publicName: "clickable", isSignal: true, isRequired: false, transformFunction: null }, emptyText: { classPropertyName: "emptyText", publicName: "emptyText", isSignal: true, isRequired: false, transformFunction: null }, scrollX: { classPropertyName: "scrollX", publicName: "scrollX", isSignal: true, isRequired: false, transformFunction: null }, scrollY: { classPropertyName: "scrollY", publicName: "scrollY", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { rowClick: "rowClick" }, ngImport: i0, template: `
2011
+ <div class="table" [class.ng-oat-table-scroll-x]="scrollX()"
2012
+ [style.max-height]="scrollY() || null"
2013
+ [style.overflow-y]="scrollY() ? 'auto' : null">
2000
2014
  <table>
2001
2015
  <thead>
2002
2016
  <tr>
@@ -2024,12 +2038,14 @@ class NgOatTable {
2024
2038
  </tbody>
2025
2039
  </table>
2026
2040
  </div>
2027
- `, isInline: true, styles: [".clickable{cursor:pointer}.clickable:hover{background:var(--hover)}\n"] });
2041
+ `, isInline: true, styles: [".clickable{cursor:pointer}.clickable:hover{background:var(--hover)}.ng-oat-table-scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}:host([scrollY]) thead th,.ng-oat-table-scroll-x thead th{position:sticky;top:0;z-index:1;background:var(--card, var(--background))}\n"] });
2028
2042
  }
2029
2043
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatTable, decorators: [{
2030
2044
  type: Component,
2031
2045
  args: [{ selector: 'ng-oat-table', template: `
2032
- <div class="table">
2046
+ <div class="table" [class.ng-oat-table-scroll-x]="scrollX()"
2047
+ [style.max-height]="scrollY() || null"
2048
+ [style.overflow-y]="scrollY() ? 'auto' : null">
2033
2049
  <table>
2034
2050
  <thead>
2035
2051
  <tr>
@@ -2057,8 +2073,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
2057
2073
  </tbody>
2058
2074
  </table>
2059
2075
  </div>
2060
- `, styles: [".clickable{cursor:pointer}.clickable:hover{background:var(--hover)}\n"] }]
2061
- }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], clickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickable", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }] } });
2076
+ `, styles: [".clickable{cursor:pointer}.clickable:hover{background:var(--hover)}.ng-oat-table-scroll-x{overflow-x:auto;-webkit-overflow-scrolling:touch}:host([scrollY]) thead th,.ng-oat-table-scroll-x thead th{position:sticky;top:0;z-index:1;background:var(--card, var(--background))}\n"] }]
2077
+ }], propDecorators: { columns: [{ type: i0.Input, args: [{ isSignal: true, alias: "columns", required: true }] }], data: [{ type: i0.Input, args: [{ isSignal: true, alias: "data", required: true }] }], striped: [{ type: i0.Input, args: [{ isSignal: true, alias: "striped", required: false }] }], clickable: [{ type: i0.Input, args: [{ isSignal: true, alias: "clickable", required: false }] }], emptyText: [{ type: i0.Input, args: [{ isSignal: true, alias: "emptyText", required: false }] }], scrollX: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollX", required: false }] }], scrollY: [{ type: i0.Input, args: [{ isSignal: true, alias: "scrollY", required: false }] }], rowClick: [{ type: i0.Output, args: ["rowClick"] }] } });
2062
2078
 
2063
2079
  /**
2064
2080
  * Angular component wrapper for Oat's dropdown.
@@ -3048,9 +3064,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3048
3064
  class NgOatInputOtp {
3049
3065
  length = input(6, ...(ngDevMode ? [{ debugName: "length" }] : []));
3050
3066
  separator = input(0, ...(ngDevMode ? [{ debugName: "separator" }] : []));
3051
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3067
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3052
3068
  mask = input(false, ...(ngDevMode ? [{ debugName: "mask" }] : []));
3053
3069
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
3070
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
3054
3071
  checked = undefined;
3055
3072
  slotInputRefs = viewChildren('slotInput', ...(ngDevMode ? [{ debugName: "slotInputRefs" }] : []));
3056
3073
  slots = computed(() => {
@@ -3062,6 +3079,7 @@ class NgOatInputOtp {
3062
3079
  const input = event.target;
3063
3080
  const char = input.value.replace(/\D/g, '').slice(-1);
3064
3081
  input.value = char;
3082
+ this.touched.set(true);
3065
3083
  this.updateValueAt(index, char);
3066
3084
  // Auto-advance to next slot
3067
3085
  if (char && index < this.length() - 1) {
@@ -3127,7 +3145,7 @@ class NgOatInputOtp {
3127
3145
  this.focusSlot(0);
3128
3146
  }
3129
3147
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatInputOtp, deps: [], target: i0.ɵɵFactoryTarget.Component });
3130
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatInputOtp, isStandalone: true, selector: "ng-oat-input-otp", inputs: { length: { classPropertyName: "length", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange" }, viewQueries: [{ propertyName: "slotInputRefs", predicate: ["slotInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
3148
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatInputOtp, isStandalone: true, selector: "ng-oat-input-otp", inputs: { length: { classPropertyName: "length", publicName: "length", isSignal: true, isRequired: false, transformFunction: null }, separator: { classPropertyName: "separator", publicName: "separator", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, mask: { classPropertyName: "mask", publicName: "mask", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", value: "valueChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatInputOtp) }], viewQueries: [{ propertyName: "slotInputRefs", predicate: ["slotInput"], descendants: true, isSignal: true }], ngImport: i0, template: `
3131
3149
  <div class="otp-group" role="group" [attr.aria-label]="'OTP input with ' + length() + ' digits'">
3132
3150
  @for (slot of slots(); track $index) {
3133
3151
  @if (separator() > 0 && $index === separator()) {
@@ -3155,7 +3173,7 @@ class NgOatInputOtp {
3155
3173
  }
3156
3174
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatInputOtp, decorators: [{
3157
3175
  type: Component,
3158
- args: [{ selector: 'ng-oat-input-otp', template: `
3176
+ args: [{ selector: 'ng-oat-input-otp', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatInputOtp) }], template: `
3159
3177
  <div class="otp-group" role="group" [attr.aria-label]="'OTP input with ' + length() + ' digits'">
3160
3178
  @for (slot of slots(); track $index) {
3161
3179
  @if (separator() > 0 && $index === separator()) {
@@ -3180,7 +3198,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3180
3198
  }
3181
3199
  </div>
3182
3200
  `, styles: [":host{display:inline-block}\n"] }]
3183
- }], propDecorators: { length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], slotInputRefs: [{ type: i0.ViewChildren, args: ['slotInput', { isSignal: true }] }] } });
3201
+ }], propDecorators: { length: [{ type: i0.Input, args: [{ isSignal: true, alias: "length", required: false }] }], separator: [{ type: i0.Input, args: [{ isSignal: true, alias: "separator", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], mask: [{ type: i0.Input, args: [{ isSignal: true, alias: "mask", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], slotInputRefs: [{ type: i0.ViewChildren, args: ['slotInput', { isSignal: true }] }] } });
3184
3202
 
3185
3203
  /**
3186
3204
  * Search input with icon, clear button, optional keyboard shortcut badge, and built-in debounce.
@@ -3194,7 +3212,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3194
3212
  */
3195
3213
  class NgOatSearchInput {
3196
3214
  placeholder = input('Search...', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
3197
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3215
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
3198
3216
  shortcut = input('', ...(ngDevMode ? [{ debugName: "shortcut" }] : []));
3199
3217
  debounceMs = input(300, ...(ngDevMode ? [{ debugName: "debounceMs" }] : []));
3200
3218
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
@@ -3267,7 +3285,7 @@ class NgOatSearchInput {
3267
3285
  this.searchInputRef()?.nativeElement.focus(options);
3268
3286
  }
3269
3287
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatSearchInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
3270
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatSearchInput, isStandalone: true, selector: "ng-oat-search-input", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", search: "search", touched: "touchedChange" }, viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
3288
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatSearchInput, isStandalone: true, selector: "ng-oat-search-input", inputs: { placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, shortcut: { classPropertyName: "shortcut", publicName: "shortcut", isSignal: true, isRequired: false, transformFunction: null }, debounceMs: { classPropertyName: "debounceMs", publicName: "debounceMs", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { disabled: "disabledChange", value: "valueChange", search: "search", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatSearchInput) }], viewQueries: [{ propertyName: "searchInputRef", first: true, predicate: ["searchEl"], descendants: true, isSignal: true }], ngImport: i0, template: `
3271
3289
  <div class="search-input" [class.has-value]="hasValue()">
3272
3290
  <span class="search-input-icon" aria-hidden="true">
3273
3291
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -3303,7 +3321,7 @@ class NgOatSearchInput {
3303
3321
  }
3304
3322
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatSearchInput, decorators: [{
3305
3323
  type: Component,
3306
- args: [{ selector: 'ng-oat-search-input', template: `
3324
+ args: [{ selector: 'ng-oat-search-input', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatSearchInput) }], template: `
3307
3325
  <div class="search-input" [class.has-value]="hasValue()">
3308
3326
  <span class="search-input-icon" aria-hidden="true">
3309
3327
  <svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
@@ -3336,7 +3354,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
3336
3354
  }
3337
3355
  </div>
3338
3356
  `, styles: [":host{display:block}\n"] }]
3339
- }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], debounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceMs", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], search: [{ type: i0.Output, args: ["search"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], searchInputRef: [{ type: i0.ViewChild, args: ['searchEl', { isSignal: true }] }] } });
3357
+ }], ctorParameters: () => [], propDecorators: { placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], shortcut: [{ type: i0.Input, args: [{ isSignal: true, alias: "shortcut", required: false }] }], debounceMs: [{ type: i0.Input, args: [{ isSignal: true, alias: "debounceMs", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], search: [{ type: i0.Output, args: ["search"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], searchInputRef: [{ type: i0.ViewChild, args: ['searchEl', { isSignal: true }] }] } });
3340
3358
 
3341
3359
  /**
3342
3360
  * Separator component for visual content division. Renders as `<hr>` for
@@ -4985,7 +5003,7 @@ class NgOatInput {
4985
5003
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
4986
5004
  checked = undefined;
4987
5005
  // --- Signal Forms optional bindings ---
4988
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5006
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
4989
5007
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
4990
5008
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
4991
5009
  invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
@@ -5000,7 +5018,7 @@ class NgOatInput {
5000
5018
  type = input('text', ...(ngDevMode ? [{ debugName: "type" }] : []));
5001
5019
  placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
5002
5020
  showErrors = input(true, ...(ngDevMode ? [{ debugName: "showErrors" }] : []));
5003
- inputId = computed(() => `ng-oat-input-${++NgOatInput.nextId}`, ...(ngDevMode ? [{ debugName: "inputId" }] : []));
5021
+ inputId = `ng-oat-input-${++NgOatInput.nextId}`;
5004
5022
  onInput(event) {
5005
5023
  const val = event.target.value;
5006
5024
  this.value.set(val);
@@ -5009,23 +5027,23 @@ class NgOatInput {
5009
5027
  this.touched.set(true);
5010
5028
  }
5011
5029
  focus(options) {
5012
- const input = document.getElementById(this.inputId());
5030
+ const input = document.getElementById(this.inputId);
5013
5031
  input?.focus(options);
5014
5032
  }
5015
5033
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatInput, deps: [], target: i0.ɵɵFactoryTarget.Component });
5016
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatInput, isStandalone: true, selector: "ng-oat-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
5034
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatInput, isStandalone: true, selector: "ng-oat-input", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, min: { classPropertyName: "min", publicName: "min", isSignal: true, isRequired: false, transformFunction: null }, max: { classPropertyName: "max", publicName: "max", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, type: { classPropertyName: "type", publicName: "type", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatInput) }], ngImport: i0, template: `
5017
5035
  @if (label()) {
5018
- <label [attr.for]="inputId()">{{ label() }}</label>
5036
+ <label [attr.for]="inputId">{{ label() }}</label>
5019
5037
  }
5020
5038
  <input
5021
- [id]="inputId()"
5039
+ [id]="inputId"
5022
5040
  [type]="type()"
5023
5041
  [value]="value()"
5024
5042
  [placeholder]="placeholder()"
5025
5043
  [disabled]="disabled()"
5026
5044
  [readOnly]="readonly()"
5027
5045
  [required]="required()"
5028
- [attr.aria-invalid]="invalid() || null"
5046
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5029
5047
  [attr.min]="min() ?? null"
5030
5048
  [attr.max]="max() ?? null"
5031
5049
  [attr.minlength]="minLength() ?? null"
@@ -5033,28 +5051,28 @@ class NgOatInput {
5033
5051
  (input)="onInput($event)"
5034
5052
  (blur)="onBlur()"
5035
5053
  />
5036
- @if (showErrors()) {
5054
+ <!-- @if (showErrors() && touched()) {
5037
5055
  @for (err of errors(); track $index) {
5038
5056
  <small class="error">{{ err.message }}</small>
5039
5057
  }
5040
- }
5058
+ } -->
5041
5059
  `, isInline: true, styles: [":host{display:block}.error{color:var(--danger);display:block;font-size:var(--text-8);margin-block-start:var(--space-1)}\n"] });
5042
5060
  }
5043
5061
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatInput, decorators: [{
5044
5062
  type: Component,
5045
- args: [{ selector: 'ng-oat-input', template: `
5063
+ args: [{ selector: 'ng-oat-input', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatInput) }], template: `
5046
5064
  @if (label()) {
5047
- <label [attr.for]="inputId()">{{ label() }}</label>
5065
+ <label [attr.for]="inputId">{{ label() }}</label>
5048
5066
  }
5049
5067
  <input
5050
- [id]="inputId()"
5068
+ [id]="inputId"
5051
5069
  [type]="type()"
5052
5070
  [value]="value()"
5053
5071
  [placeholder]="placeholder()"
5054
5072
  [disabled]="disabled()"
5055
5073
  [readOnly]="readonly()"
5056
5074
  [required]="required()"
5057
- [attr.aria-invalid]="invalid() || null"
5075
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5058
5076
  [attr.min]="min() ?? null"
5059
5077
  [attr.max]="max() ?? null"
5060
5078
  [attr.minlength]="minLength() ?? null"
@@ -5062,13 +5080,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5062
5080
  (input)="onInput($event)"
5063
5081
  (blur)="onBlur()"
5064
5082
  />
5065
- @if (showErrors()) {
5083
+ <!-- @if (showErrors() && touched()) {
5066
5084
  @for (err of errors(); track $index) {
5067
5085
  <small class="error">{{ err.message }}</small>
5068
5086
  }
5069
- }
5087
+ } -->
5070
5088
  `, styles: [":host{display:block}.error{color:var(--danger);display:block;font-size:var(--text-8);margin-block-start:var(--space-1)}\n"] }]
5071
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5089
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], min: [{ type: i0.Input, args: [{ isSignal: true, alias: "min", required: false }] }], max: [{ type: i0.Input, args: [{ isSignal: true, alias: "max", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], type: [{ type: i0.Input, args: [{ isSignal: true, alias: "type", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5072
5090
 
5073
5091
  /**
5074
5092
  * Oat-styled textarea implementing `FormValueControl<string>`.
@@ -5088,7 +5106,7 @@ class NgOatTextarea {
5088
5106
  static nextId = 0;
5089
5107
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
5090
5108
  checked = undefined;
5091
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5109
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5092
5110
  readonly = input(false, ...(ngDevMode ? [{ debugName: "readonly" }] : []));
5093
5111
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
5094
5112
  invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
@@ -5101,7 +5119,7 @@ class NgOatTextarea {
5101
5119
  placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
5102
5120
  rows = input(4, ...(ngDevMode ? [{ debugName: "rows" }] : []));
5103
5121
  showErrors = input(true, ...(ngDevMode ? [{ debugName: "showErrors" }] : []));
5104
- textareaId = computed(() => `ng-oat-ta-${++NgOatTextarea.nextId}`, ...(ngDevMode ? [{ debugName: "textareaId" }] : []));
5122
+ textareaId = `ng-oat-ta-${++NgOatTextarea.nextId}`;
5105
5123
  onInput(event) {
5106
5124
  const val = event.target.value;
5107
5125
  this.value.set(val);
@@ -5110,29 +5128,29 @@ class NgOatTextarea {
5110
5128
  this.touched.set(true);
5111
5129
  }
5112
5130
  focus(options) {
5113
- const el = document.getElementById(this.textareaId());
5131
+ const el = document.getElementById(this.textareaId);
5114
5132
  el?.focus(options);
5115
5133
  }
5116
5134
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatTextarea, deps: [], target: i0.ɵɵFactoryTarget.Component });
5117
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatTextarea, isStandalone: true, selector: "ng-oat-textarea", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
5135
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatTextarea, isStandalone: true, selector: "ng-oat-textarea", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, rows: { classPropertyName: "rows", publicName: "rows", isSignal: true, isRequired: false, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatTextarea) }], ngImport: i0, template: `
5118
5136
  @if (label()) {
5119
- <label [attr.for]="textareaId()">{{ label() }}</label>
5137
+ <label [attr.for]="textareaId">{{ label() }}</label>
5120
5138
  }
5121
5139
  <textarea
5122
- [id]="textareaId()"
5140
+ [id]="textareaId"
5123
5141
  [value]="value()"
5124
5142
  [placeholder]="placeholder()"
5125
5143
  [disabled]="disabled()"
5126
5144
  [readOnly]="readonly()"
5127
5145
  [required]="required()"
5128
5146
  [rows]="rows()"
5129
- [attr.aria-invalid]="invalid() || null"
5147
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5130
5148
  [attr.minlength]="minLength() ?? null"
5131
5149
  [attr.maxlength]="maxLength() ?? null"
5132
5150
  (input)="onInput($event)"
5133
5151
  (blur)="onBlur()"
5134
5152
  ></textarea>
5135
- @if (showErrors()) {
5153
+ @if (showErrors() && touched()) {
5136
5154
  @for (err of errors(); track $index) {
5137
5155
  <small class="error">{{ err.message }}</small>
5138
5156
  }
@@ -5141,31 +5159,31 @@ class NgOatTextarea {
5141
5159
  }
5142
5160
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatTextarea, decorators: [{
5143
5161
  type: Component,
5144
- args: [{ selector: 'ng-oat-textarea', template: `
5162
+ args: [{ selector: 'ng-oat-textarea', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatTextarea) }], template: `
5145
5163
  @if (label()) {
5146
- <label [attr.for]="textareaId()">{{ label() }}</label>
5164
+ <label [attr.for]="textareaId">{{ label() }}</label>
5147
5165
  }
5148
5166
  <textarea
5149
- [id]="textareaId()"
5167
+ [id]="textareaId"
5150
5168
  [value]="value()"
5151
5169
  [placeholder]="placeholder()"
5152
5170
  [disabled]="disabled()"
5153
5171
  [readOnly]="readonly()"
5154
5172
  [required]="required()"
5155
5173
  [rows]="rows()"
5156
- [attr.aria-invalid]="invalid() || null"
5174
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5157
5175
  [attr.minlength]="minLength() ?? null"
5158
5176
  [attr.maxlength]="maxLength() ?? null"
5159
5177
  (input)="onInput($event)"
5160
5178
  (blur)="onBlur()"
5161
5179
  ></textarea>
5162
- @if (showErrors()) {
5180
+ @if (showErrors() && touched()) {
5163
5181
  @for (err of errors(); track $index) {
5164
5182
  <small class="error">{{ err.message }}</small>
5165
5183
  }
5166
5184
  }
5167
5185
  `, styles: [":host{display:block}.error{color:var(--danger);display:block;font-size:var(--text-8);margin-block-start:var(--space-1)}\n"] }]
5168
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5186
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], rows: [{ type: i0.Input, args: [{ isSignal: true, alias: "rows", required: false }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5169
5187
 
5170
5188
  /**
5171
5189
  * Oat-styled select implementing `FormValueControl<string>`.
@@ -5186,7 +5204,7 @@ class NgOatSelect {
5186
5204
  checked = undefined;
5187
5205
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
5188
5206
  // --- Signal Forms optional bindings ---
5189
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5207
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5190
5208
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
5191
5209
  invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
5192
5210
  errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
@@ -5196,7 +5214,7 @@ class NgOatSelect {
5196
5214
  placeholder = input('', ...(ngDevMode ? [{ debugName: "placeholder" }] : []));
5197
5215
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
5198
5216
  showErrors = input(true, ...(ngDevMode ? [{ debugName: "showErrors" }] : []));
5199
- selectId = computed(() => `ng-oat-sel-${++NgOatSelect.nextId}`, ...(ngDevMode ? [{ debugName: "selectId" }] : []));
5217
+ selectId = `ng-oat-sel-${++NgOatSelect.nextId}`;
5200
5218
  onChange(event) {
5201
5219
  const val = event.target.value;
5202
5220
  this.value.set(val);
@@ -5205,20 +5223,20 @@ class NgOatSelect {
5205
5223
  this.touched.set(true);
5206
5224
  }
5207
5225
  focus(options) {
5208
- const el = document.getElementById(this.selectId());
5226
+ const el = document.getElementById(this.selectId);
5209
5227
  el?.focus(options);
5210
5228
  }
5211
5229
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatSelect, deps: [], target: i0.ɵɵFactoryTarget.Component });
5212
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatSelect, isStandalone: true, selector: "ng-oat-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
5230
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatSelect, isStandalone: true, selector: "ng-oat-select", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatSelect) }], ngImport: i0, template: `
5213
5231
  @if (label()) {
5214
- <label [attr.for]="selectId()">{{ label() }}</label>
5232
+ <label [attr.for]="selectId">{{ label() }}</label>
5215
5233
  }
5216
5234
  <select
5217
- [id]="selectId()"
5235
+ [id]="selectId"
5218
5236
  [value]="value()"
5219
5237
  [disabled]="disabled()"
5220
5238
  [required]="required()"
5221
- [attr.aria-invalid]="invalid() || null"
5239
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5222
5240
  (change)="onChange($event)"
5223
5241
  (blur)="onBlur()"
5224
5242
  >
@@ -5234,7 +5252,7 @@ class NgOatSelect {
5234
5252
  </option>
5235
5253
  }
5236
5254
  </select>
5237
- @if (showErrors()) {
5255
+ @if (showErrors() && touched()) {
5238
5256
  @for (err of errors(); track $index) {
5239
5257
  <small class="error">{{ err.message }}</small>
5240
5258
  }
@@ -5243,16 +5261,16 @@ class NgOatSelect {
5243
5261
  }
5244
5262
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatSelect, decorators: [{
5245
5263
  type: Component,
5246
- args: [{ selector: 'ng-oat-select', template: `
5264
+ args: [{ selector: 'ng-oat-select', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatSelect) }], template: `
5247
5265
  @if (label()) {
5248
- <label [attr.for]="selectId()">{{ label() }}</label>
5266
+ <label [attr.for]="selectId">{{ label() }}</label>
5249
5267
  }
5250
5268
  <select
5251
- [id]="selectId()"
5269
+ [id]="selectId"
5252
5270
  [value]="value()"
5253
5271
  [disabled]="disabled()"
5254
5272
  [required]="required()"
5255
- [attr.aria-invalid]="invalid() || null"
5273
+ [attr.aria-invalid]="(invalid() && touched()) || null"
5256
5274
  (change)="onChange($event)"
5257
5275
  (blur)="onBlur()"
5258
5276
  >
@@ -5268,13 +5286,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5268
5286
  </option>
5269
5287
  }
5270
5288
  </select>
5271
- @if (showErrors()) {
5289
+ @if (showErrors() && touched()) {
5272
5290
  @for (err of errors(); track $index) {
5273
5291
  <small class="error">{{ err.message }}</small>
5274
5292
  }
5275
5293
  }
5276
5294
  `, styles: [":host{display:block}.error{color:var(--danger);display:block;font-size:var(--text-8);margin-block-start:var(--space-1)}\n"] }]
5277
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5295
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5278
5296
 
5279
5297
  /**
5280
5298
  * Oat-styled checkbox implementing `FormCheckboxControl`.
@@ -5292,7 +5310,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5292
5310
  */
5293
5311
  class NgOatCheckbox {
5294
5312
  checked = model(false, ...(ngDevMode ? [{ debugName: "checked" }] : []));
5295
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5313
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5314
+ touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : []));
5296
5315
  /** FormCheckboxControl requires `value` to be undefined */
5297
5316
  value = undefined;
5298
5317
  // --- Component-specific inputs ---
@@ -5300,9 +5319,10 @@ class NgOatCheckbox {
5300
5319
  onChange(event) {
5301
5320
  const val = event.target.checked;
5302
5321
  this.checked.set(val);
5322
+ this.touched.set(true);
5303
5323
  }
5304
5324
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatCheckbox, deps: [], target: i0.ɵɵFactoryTarget.Component });
5305
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.0", type: NgOatCheckbox, isStandalone: true, selector: "ng-oat-checkbox", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange" }, ngImport: i0, template: `
5325
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.2.0", type: NgOatCheckbox, isStandalone: true, selector: "ng-oat-checkbox", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", disabled: "disabledChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_CHECKBOX_HOST, useExisting: forwardRef(() => NgOatCheckbox) }], ngImport: i0, template: `
5306
5326
  <label>
5307
5327
  <input
5308
5328
  type="checkbox"
@@ -5318,6 +5338,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5318
5338
  type: Component,
5319
5339
  args: [{
5320
5340
  selector: 'ng-oat-checkbox',
5341
+ providers: [{ provide: NG_OAT_CHECKBOX_HOST, useExisting: forwardRef(() => NgOatCheckbox) }],
5321
5342
  template: `
5322
5343
  <label>
5323
5344
  <input
@@ -5330,7 +5351,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5330
5351
  </label>
5331
5352
  `,
5332
5353
  }]
5333
- }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
5354
+ }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }] } });
5334
5355
 
5335
5356
  /**
5336
5357
  * Oat-styled radio group implementing `FormValueControl<string>`.
@@ -5357,7 +5378,7 @@ class NgOatRadioGroup {
5357
5378
  value = model('', ...(ngDevMode ? [{ debugName: "value" }] : []));
5358
5379
  checked = undefined;
5359
5380
  // --- Signal Forms optional bindings ---
5360
- disabled = input(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5381
+ disabled = model(false, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
5361
5382
  required = input(false, ...(ngDevMode ? [{ debugName: "required" }] : []));
5362
5383
  invalid = input(false, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
5363
5384
  errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
@@ -5366,13 +5387,13 @@ class NgOatRadioGroup {
5366
5387
  label = input('', ...(ngDevMode ? [{ debugName: "label" }] : []));
5367
5388
  options = input.required(...(ngDevMode ? [{ debugName: "options" }] : []));
5368
5389
  showErrors = input(true, ...(ngDevMode ? [{ debugName: "showErrors" }] : []));
5369
- groupName = computed(() => `ng-oat-radio-${++NgOatRadioGroup.nextId}`, ...(ngDevMode ? [{ debugName: "groupName" }] : []));
5390
+ groupName = `ng-oat-radio-${++NgOatRadioGroup.nextId}`;
5370
5391
  onSelect(val) {
5371
5392
  this.value.set(val);
5372
5393
  this.touched.set(true);
5373
5394
  }
5374
5395
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatRadioGroup, deps: [], target: i0.ɵɵFactoryTarget.Component });
5375
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatRadioGroup, isStandalone: true, selector: "ng-oat-radio-group", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange" }, ngImport: i0, template: `
5396
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatRadioGroup, isStandalone: true, selector: "ng-oat-radio-group", inputs: { value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: true, transformFunction: null }, showErrors: { classPropertyName: "showErrors", publicName: "showErrors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", disabled: "disabledChange", touched: "touchedChange" }, providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatRadioGroup) }], ngImport: i0, template: `
5376
5397
  @if (label()) {
5377
5398
  <fieldset>
5378
5399
  <legend>{{ label() }}</legend>
@@ -5380,7 +5401,7 @@ class NgOatRadioGroup {
5380
5401
  <label>
5381
5402
  <input
5382
5403
  type="radio"
5383
- [name]="groupName()"
5404
+ [name]="groupName"
5384
5405
  [value]="opt.value"
5385
5406
  [checked]="opt.value === value()"
5386
5407
  [disabled]="disabled() || (opt.disabled ?? false)"
@@ -5395,7 +5416,7 @@ class NgOatRadioGroup {
5395
5416
  <label>
5396
5417
  <input
5397
5418
  type="radio"
5398
- [name]="groupName()"
5419
+ [name]="groupName"
5399
5420
  [value]="opt.value"
5400
5421
  [checked]="opt.value === value()"
5401
5422
  [disabled]="disabled() || (opt.disabled ?? false)"
@@ -5405,7 +5426,7 @@ class NgOatRadioGroup {
5405
5426
  </label>
5406
5427
  }
5407
5428
  }
5408
- @if (showErrors()) {
5429
+ @if (showErrors() && touched()) {
5409
5430
  @for (err of errors(); track $index) {
5410
5431
  <small class="error">{{ err.message }}</small>
5411
5432
  }
@@ -5414,7 +5435,7 @@ class NgOatRadioGroup {
5414
5435
  }
5415
5436
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatRadioGroup, decorators: [{
5416
5437
  type: Component,
5417
- args: [{ selector: 'ng-oat-radio-group', template: `
5438
+ args: [{ selector: 'ng-oat-radio-group', providers: [{ provide: NG_OAT_VALUE_HOST, useExisting: forwardRef(() => NgOatRadioGroup) }], template: `
5418
5439
  @if (label()) {
5419
5440
  <fieldset>
5420
5441
  <legend>{{ label() }}</legend>
@@ -5422,7 +5443,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5422
5443
  <label>
5423
5444
  <input
5424
5445
  type="radio"
5425
- [name]="groupName()"
5446
+ [name]="groupName"
5426
5447
  [value]="opt.value"
5427
5448
  [checked]="opt.value === value()"
5428
5449
  [disabled]="disabled() || (opt.disabled ?? false)"
@@ -5437,7 +5458,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5437
5458
  <label>
5438
5459
  <input
5439
5460
  type="radio"
5440
- [name]="groupName()"
5461
+ [name]="groupName"
5441
5462
  [value]="opt.value"
5442
5463
  [checked]="opt.value === value()"
5443
5464
  [disabled]="disabled() || (opt.disabled ?? false)"
@@ -5447,35 +5468,54 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5447
5468
  </label>
5448
5469
  }
5449
5470
  }
5450
- @if (showErrors()) {
5471
+ @if (showErrors() && touched()) {
5451
5472
  @for (err of errors(); track $index) {
5452
5473
  <small class="error">{{ err.message }}</small>
5453
5474
  }
5454
5475
  }
5455
5476
  `, styles: [":host{display:block}fieldset{border:none;padding:0;margin:0}legend{font-size:var(--text-7);font-weight:var(--font-medium);margin-block-end:var(--space-1)}label{display:flex;align-items:center;gap:var(--space-2);margin-block-end:var(--space-1)}.error{color:var(--danger);display:block;font-size:var(--text-8);margin-block-start:var(--space-1)}\n"] }]
5456
- }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5477
+ }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: true }] }], showErrors: [{ type: i0.Input, args: [{ isSignal: true, alias: "showErrors", required: false }] }] } });
5457
5478
 
5458
5479
  /**
5459
- * Displays validation errors for a Signal Forms field.
5460
- * Shows errors only when the field has been touched and is invalid.
5480
+ * Displays validation errors for form fields.
5461
5481
  *
5462
- * Usage:
5482
+ * **Signal Forms** — pass the `FieldState` directly:
5463
5483
  * ```html
5464
- * <ng-oat-input label="Email" [formField]="myForm.email" />
5465
5484
  * <ng-oat-form-error [control]="myForm.email" />
5466
5485
  * ```
5486
+ *
5487
+ * **Reactive / Template-driven** — pass error strings and a visibility flag:
5488
+ * ```html
5489
+ * <ng-oat-form-error [errors]="['Email is required']" [show]="email.touched && email.invalid" />
5490
+ * ```
5467
5491
  */
5468
5492
  class NgOatFormError {
5469
- control = input.required(...(ngDevMode ? [{ debugName: "control" }] : []));
5493
+ /** Signal Forms FieldState for automatic error display. */
5494
+ control = input(...(ngDevMode ? [undefined, { debugName: "control" }] : []));
5495
+ /** Plain error message strings — for Reactive / Template-driven forms. */
5496
+ errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
5497
+ /** External visibility flag — for Reactive / Template-driven forms. */
5498
+ show = input(false, ...(ngDevMode ? [{ debugName: "show" }] : []));
5499
+ /** Unified list of error message strings. */
5500
+ errorMessages = computed(() => {
5501
+ const ctrl = this.control();
5502
+ if (ctrl) {
5503
+ return ctrl.errors().map(e => e.message);
5504
+ }
5505
+ return this.errors();
5506
+ }, ...(ngDevMode ? [{ debugName: "errorMessages" }] : []));
5470
5507
  shouldShowError = computed(() => {
5471
- const field = this.control();
5472
- return !field.valid() && field.touched();
5508
+ const ctrl = this.control();
5509
+ if (ctrl) {
5510
+ return !ctrl.valid() && ctrl.touched();
5511
+ }
5512
+ return this.show() && this.errors().length > 0;
5473
5513
  }, ...(ngDevMode ? [{ debugName: "shouldShowError" }] : []));
5474
5514
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatFormError, deps: [], target: i0.ɵɵFactoryTarget.Component });
5475
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatFormError, isStandalone: true, selector: "ng-oat-form-error", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
5515
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: NgOatFormError, isStandalone: true, selector: "ng-oat-form-error", inputs: { control: { classPropertyName: "control", publicName: "control", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, show: { classPropertyName: "show", publicName: "show", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
5476
5516
  @if (shouldShowError()) {
5477
- @for (error of control().errors(); track error.kind) {
5478
- <small class="error">{{ error.message }}</small>
5517
+ @for (msg of errorMessages(); track $index) {
5518
+ <small class="error">{{ msg }}</small>
5479
5519
  }
5480
5520
  }
5481
5521
  `, isInline: true, styles: [":host{display:block}.error{display:block;font-size:var(--text-8);font-weight:var(--font-normal);color:var(--danger);margin-block-start:var(--space-1)}\n"] });
@@ -5484,12 +5524,175 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImpor
5484
5524
  type: Component,
5485
5525
  args: [{ selector: 'ng-oat-form-error', template: `
5486
5526
  @if (shouldShowError()) {
5487
- @for (error of control().errors(); track error.kind) {
5488
- <small class="error">{{ error.message }}</small>
5527
+ @for (msg of errorMessages(); track $index) {
5528
+ <small class="error">{{ msg }}</small>
5489
5529
  }
5490
5530
  }
5491
5531
  `, styles: [":host{display:block}.error{display:block;font-size:var(--text-8);font-weight:var(--font-normal);color:var(--danger);margin-block-start:var(--space-1)}\n"] }]
5492
- }], propDecorators: { control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: true }] }] } });
5532
+ }], propDecorators: { control: [{ type: i0.Input, args: [{ isSignal: true, alias: "control", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], show: [{ type: i0.Input, args: [{ isSignal: true, alias: "show", required: false }] }] } });
5533
+
5534
+ /**
5535
+ * ControlValueAccessor adapter for ng-oat **value-type** components.
5536
+ *
5537
+ * Auto-activates when a Reactive Forms or Template-driven directive is present
5538
+ * (`formControlName`, `[formControl]`, or `[(ngModel)]`).
5539
+ *
5540
+ * Add this directive to your component's `imports` alongside the form component:
5541
+ * ```typescript
5542
+ * imports: [ReactiveFormsModule, NgOatInput, NgOatValueCva]
5543
+ * ```
5544
+ *
5545
+ * ```html
5546
+ * <ng-oat-input label="Email" formControlName="email" />
5547
+ * <ng-oat-input label="Name" [(ngModel)]="name" />
5548
+ * ```
5549
+ */
5550
+ class NgOatValueCva {
5551
+ host = inject(NG_OAT_VALUE_HOST);
5552
+ onChange = () => { };
5553
+ onTouched = () => { };
5554
+ /**
5555
+ * Listen for native `input` and `change` events that bubble from the inner
5556
+ * `<input>`, `<textarea>`, or `<select>` element up to the host component.
5557
+ */
5558
+ onHostValueChange() {
5559
+ this.onChange(this.host.value());
5560
+ }
5561
+ /** Mark as touched when focus leaves the host element tree. */
5562
+ onHostBlur() {
5563
+ this.host.touched.set(true);
5564
+ this.onTouched();
5565
+ }
5566
+ // --- ControlValueAccessor ---
5567
+ writeValue(val) {
5568
+ this.host.value.set(val ?? '');
5569
+ }
5570
+ registerOnChange(fn) {
5571
+ this.onChange = fn;
5572
+ }
5573
+ registerOnTouched(fn) {
5574
+ this.onTouched = fn;
5575
+ }
5576
+ setDisabledState(isDisabled) {
5577
+ this.host.disabled.set(isDisabled);
5578
+ }
5579
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatValueCva, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5580
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: NgOatValueCva, isStandalone: true, selector: "ng-oat-input[formControlName],ng-oat-input[formControl],ng-oat-input[ngModel],\nng-oat-textarea[formControlName],ng-oat-textarea[formControl],ng-oat-textarea[ngModel],\nng-oat-select[formControlName],ng-oat-select[formControl],ng-oat-select[ngModel],\nng-oat-radio-group[formControlName],ng-oat-radio-group[formControl],ng-oat-radio-group[ngModel],\nng-oat-search-input[formControlName],ng-oat-search-input[formControl],ng-oat-search-input[ngModel],\nng-oat-input-otp[formControlName],ng-oat-input-otp[formControl],ng-oat-input-otp[ngModel]", host: { listeners: { "input": "onHostValueChange()", "change": "onHostValueChange()", "focusout": "onHostBlur()" } }, providers: [
5581
+ {
5582
+ provide: NG_VALUE_ACCESSOR,
5583
+ useExisting: forwardRef(() => NgOatValueCva),
5584
+ multi: true,
5585
+ },
5586
+ ], ngImport: i0 });
5587
+ }
5588
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatValueCva, decorators: [{
5589
+ type: Directive,
5590
+ args: [{
5591
+ selector: `ng-oat-input[formControlName],ng-oat-input[formControl],ng-oat-input[ngModel],
5592
+ ng-oat-textarea[formControlName],ng-oat-textarea[formControl],ng-oat-textarea[ngModel],
5593
+ ng-oat-select[formControlName],ng-oat-select[formControl],ng-oat-select[ngModel],
5594
+ ng-oat-radio-group[formControlName],ng-oat-radio-group[formControl],ng-oat-radio-group[ngModel],
5595
+ ng-oat-search-input[formControlName],ng-oat-search-input[formControl],ng-oat-search-input[ngModel],
5596
+ ng-oat-input-otp[formControlName],ng-oat-input-otp[formControl],ng-oat-input-otp[ngModel]`,
5597
+ providers: [
5598
+ {
5599
+ provide: NG_VALUE_ACCESSOR,
5600
+ useExisting: forwardRef(() => NgOatValueCva),
5601
+ multi: true,
5602
+ },
5603
+ ],
5604
+ }]
5605
+ }], propDecorators: { onHostValueChange: [{
5606
+ type: HostListener,
5607
+ args: ['input']
5608
+ }, {
5609
+ type: HostListener,
5610
+ args: ['change']
5611
+ }], onHostBlur: [{
5612
+ type: HostListener,
5613
+ args: ['focusout']
5614
+ }] } });
5615
+
5616
+ /**
5617
+ * ControlValueAccessor adapter for ng-oat **checkbox-type** components.
5618
+ *
5619
+ * Auto-activates when a Reactive Forms or Template-driven directive is present
5620
+ * (`formControlName`, `[formControl]`, or `[(ngModel)]`).
5621
+ *
5622
+ * Add this directive to your component's `imports` alongside the form component:
5623
+ * ```typescript
5624
+ * imports: [ReactiveFormsModule, NgOatCheckbox, NgOatCheckboxCva]
5625
+ * ```
5626
+ *
5627
+ * ```html
5628
+ * <ng-oat-checkbox label="Accept terms" formControlName="accepted" />
5629
+ * <ng-oat-switch label="Alerts" [(ngModel)]="alertsOn" />
5630
+ * ```
5631
+ */
5632
+ class NgOatCheckboxCva {
5633
+ host = inject(NG_OAT_CHECKBOX_HOST);
5634
+ onChange = () => { };
5635
+ onTouched = () => { };
5636
+ /**
5637
+ * Listen for native `change` events that bubble from the inner
5638
+ * `<input type="checkbox">` up to the host component.
5639
+ */
5640
+ onHostChange() {
5641
+ this.onChange(this.host.checked());
5642
+ this.host.touched.set(true);
5643
+ this.onTouched();
5644
+ }
5645
+ /** Mark as touched when focus leaves the host element tree. */
5646
+ onHostBlur() {
5647
+ this.host.touched.set(true);
5648
+ this.onTouched();
5649
+ }
5650
+ // --- ControlValueAccessor ---
5651
+ writeValue(val) {
5652
+ this.host.checked.set(!!val);
5653
+ }
5654
+ registerOnChange(fn) {
5655
+ this.onChange = fn;
5656
+ }
5657
+ registerOnTouched(fn) {
5658
+ this.onTouched = fn;
5659
+ }
5660
+ setDisabledState(isDisabled) {
5661
+ this.host.disabled.set(isDisabled);
5662
+ }
5663
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatCheckboxCva, deps: [], target: i0.ɵɵFactoryTarget.Directive });
5664
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: NgOatCheckboxCva, isStandalone: true, selector: "ng-oat-checkbox[formControlName],ng-oat-checkbox[formControl],ng-oat-checkbox[ngModel],\nng-oat-switch[formControlName],ng-oat-switch[formControl],ng-oat-switch[ngModel]", host: { listeners: { "change": "onHostChange()", "focusout": "onHostBlur()" } }, providers: [
5665
+ {
5666
+ provide: NG_VALUE_ACCESSOR,
5667
+ useExisting: forwardRef(() => NgOatCheckboxCva),
5668
+ multi: true,
5669
+ },
5670
+ ], ngImport: i0 });
5671
+ }
5672
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: NgOatCheckboxCva, decorators: [{
5673
+ type: Directive,
5674
+ args: [{
5675
+ selector: `ng-oat-checkbox[formControlName],ng-oat-checkbox[formControl],ng-oat-checkbox[ngModel],
5676
+ ng-oat-switch[formControlName],ng-oat-switch[formControl],ng-oat-switch[ngModel]`,
5677
+ providers: [
5678
+ {
5679
+ provide: NG_VALUE_ACCESSOR,
5680
+ useExisting: forwardRef(() => NgOatCheckboxCva),
5681
+ multi: true,
5682
+ },
5683
+ ],
5684
+ }]
5685
+ }], propDecorators: { onHostChange: [{
5686
+ type: HostListener,
5687
+ args: ['change']
5688
+ }], onHostBlur: [{
5689
+ type: HostListener,
5690
+ args: ['focusout']
5691
+ }] } });
5692
+
5693
+ // Forms barrel export
5694
+ /** Convenience array — import both CVA adapters at once. */
5695
+ const NgOatFormsCva = [NgOatValueCva, NgOatCheckboxCva];
5493
5696
 
5494
5697
  // Components barrel export
5495
5698
 
@@ -5510,5 +5713,5 @@ const OAT_VERSION_TOKEN = new InjectionToken('OAT_VERSION', {
5510
5713
  * Generated bundle index. Do not edit.
5511
5714
  */
5512
5715
 
5513
- export { NG_OAT_CHIP_GROUP, NG_OAT_TOGGLE_GROUP, NgOatAccordion, NgOatAlert, NgOatAvatar, NgOatBadge, NgOatBreadcrumb, NgOatButton, NgOatCard, NgOatCardCarousel, NgOatCardFooter, NgOatCardHeader, NgOatCarousel, NgOatCheckbox, NgOatChip, NgOatChipGroup, NgOatChipInput, NgOatDialog, NgOatDialogComponent, NgOatDropdown, NgOatDropdownComponent, NgOatFileUpload, NgOatFormError, NgOatInput, NgOatInputOtp, NgOatMeter, NgOatPagination, NgOatProgress, NgOatRadioGroup, NgOatSearchInput, NgOatSelect, NgOatSeparator, NgOatSidebar, NgOatSidebarComponent, NgOatSkeleton, NgOatSpinner, NgOatSplitButton, NgOatSwitch, NgOatTable, NgOatTabs, NgOatTabsComponent, NgOatTextarea, NgOatThemeRef, NgOatThemeSelector, NgOatThemeSelectorIcon, NgOatToast, NgOatToggle, NgOatToggleGroup, NgOatToolbar, NgOatToolbarRow, NgOatTooltip, NgOatTooltipComponent, OAT_TOKEN_MAP, OAT_VERSION, OAT_VERSION_TOKEN, TOOLTIP_POSITIONER, provideNgOat, provideNgOatTheme };
5716
+ export { NG_OAT_CHECKBOX_HOST, NG_OAT_CHIP_GROUP, NG_OAT_TOGGLE_GROUP, NG_OAT_VALUE_HOST, NgOatAccordion, NgOatAlert, NgOatAvatar, NgOatBadge, NgOatBreadcrumb, NgOatButton, NgOatCard, NgOatCardCarousel, NgOatCardFooter, NgOatCardHeader, NgOatCarousel, NgOatCheckbox, NgOatCheckboxCva, NgOatChip, NgOatChipGroup, NgOatChipInput, NgOatDialog, NgOatDialogComponent, NgOatDropdown, NgOatDropdownComponent, NgOatFileUpload, NgOatFormError, NgOatFormsCva, NgOatInput, NgOatInputOtp, NgOatMeter, NgOatPagination, NgOatProgress, NgOatRadioGroup, NgOatSearchInput, NgOatSelect, NgOatSeparator, NgOatSidebar, NgOatSidebarComponent, NgOatSkeleton, NgOatSpinner, NgOatSplitButton, NgOatSwitch, NgOatTable, NgOatTabs, NgOatTabsComponent, NgOatTextarea, NgOatThemeRef, NgOatThemeSelector, NgOatThemeSelectorIcon, NgOatToast, NgOatToggle, NgOatToggleGroup, NgOatToolbar, NgOatToolbarRow, NgOatTooltip, NgOatTooltipComponent, NgOatValueCva, OAT_TOKEN_MAP, OAT_VERSION, OAT_VERSION_TOKEN, TOOLTIP_POSITIONER, provideNgOat, provideNgOatTheme };
5514
5717
  //# sourceMappingURL=letsprogram-ng-oat.mjs.map