@ng-forge/dynamic-forms-material 0.3.1 → 0.4.0

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,15 +1,15 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, ElementRef, input, computed, ChangeDetectionStrategy, Component, viewChild, afterRenderEffect, linkedSignal, isSignal } from '@angular/core';
2
+ import { InjectionToken, computed, inject, ElementRef, input, afterRenderEffect, ChangeDetectionStrategy, Component, viewChild, linkedSignal, isSignal } from '@angular/core';
3
3
  import { FormField } from '@angular/forms/signals';
4
4
  import { MatCheckbox } from '@angular/material/checkbox';
5
- import { DynamicTextPipe, EventBus, ARRAY_CONTEXT, resolveTokens, buildBaseInputs, FIELD_SIGNAL_CONTEXT, resolveSubmitButtonDisabled, resolveNextButtonDisabled, NextPageEvent, PreviousPageEvent, DynamicFormLogger, AddArrayItemEvent, RemoveArrayItemEvent } from '@ng-forge/dynamic-forms';
6
- import { createResolvedErrorsSignal, shouldShowErrors, setupMetaTracking, isEqual, ValueInArrayPipe, valueFieldMapper, optionsFieldMapper, checkboxFieldMapper, datepickerFieldMapper } from '@ng-forge/dynamic-forms/integration';
5
+ import { DynamicTextPipe, EventBus, ARRAY_CONTEXT, resolveTokens, DEFAULT_PROPS, buildBaseInputs, RootFormRegistryService, FORM_OPTIONS, resolveSubmitButtonDisabled, FIELD_SIGNAL_CONTEXT, resolveNextButtonDisabled, NextPageEvent, PreviousPageEvent, DynamicFormLogger, AddArrayItemEvent, RemoveArrayItemEvent } from '@ng-forge/dynamic-forms';
6
+ import { createResolvedErrorsSignal, shouldShowErrors, setupMetaTracking, isEqual, valueFieldMapper, optionsFieldMapper, checkboxFieldMapper, datepickerFieldMapper } from '@ng-forge/dynamic-forms/integration';
7
7
  import { MatError, MatInput, MatHint } from '@angular/material/input';
8
8
  import { AsyncPipe } from '@angular/common';
9
- import { explicitEffect } from 'ngxtension/explicit-effect';
10
9
  import { MatFormField, MatLabel, MatSuffix, MatError as MatError$1 } from '@angular/material/form-field';
11
10
  import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker';
12
11
  import { provideNativeDateAdapter } from '@angular/material/core';
12
+ import { explicitEffect } from 'ngxtension/explicit-effect';
13
13
  import { MatRadioGroup, MatRadioButton } from '@angular/material/radio';
14
14
  import { MatSelect, MatOption } from '@angular/material/select';
15
15
  import { MatSlider, MatSliderThumb } from '@angular/material/slider';
@@ -39,6 +39,29 @@ import { MatSlideToggle } from '@angular/material/slide-toggle';
39
39
  */
40
40
  const MATERIAL_CONFIG = new InjectionToken('MATERIAL_CONFIG');
41
41
 
42
+ /**
43
+ * Creates a signal that computes the aria-describedby value based on errors and hint state.
44
+ * Errors take precedence over hints - when errors are displayed, the hint is hidden.
45
+ *
46
+ * @param errorsToDisplay Signal containing the array of errors currently being displayed
47
+ * @param errorId Signal containing the base ID for error elements
48
+ * @param hintId Signal containing the ID for the hint element
49
+ * @param hasHint Function that returns true if a hint is configured
50
+ * @returns Signal containing the aria-describedby value (space-separated IDs) or null
51
+ */
52
+ function createAriaDescribedBySignal(errorsToDisplay, errorId, hintId, hasHint) {
53
+ return computed(() => {
54
+ const errors = errorsToDisplay();
55
+ if (errors.length > 0) {
56
+ return errors.map((_, i) => `${errorId()}-${i}`).join(' ');
57
+ }
58
+ if (hasHint()) {
59
+ return hintId();
60
+ }
61
+ return null;
62
+ });
63
+ }
64
+
42
65
  class MatCheckboxFieldComponent {
43
66
  materialConfig = inject(MATERIAL_CONFIG, { optional: true });
44
67
  elementRef = inject((ElementRef));
@@ -80,17 +103,7 @@ class MatCheckboxFieldComponent {
80
103
  return this.field()().required?.() === true ? true : null;
81
104
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
82
105
  /** aria-describedby: links to hint and error messages for screen readers */
83
- ariaDescribedBy = computed(() => {
84
- const ids = [];
85
- if (this.props()?.hint) {
86
- ids.push(this.hintId());
87
- }
88
- const errors = this.errorsToDisplay();
89
- errors.forEach((_, i) => {
90
- ids.push(`${this.errorId()}-${i}`);
91
- });
92
- return ids.join(' ');
93
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
106
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
94
107
  /**
95
108
  * Workaround: Angular Material's MatCheckbox does NOT set aria-required on its internal
96
109
  * input element when [required] is passed, even though it sets the native required attribute.
@@ -98,8 +111,11 @@ class MatCheckboxFieldComponent {
98
111
  *
99
112
  * Bug: MatCheckbox sets `required` attribute but not `aria-required` for screen readers.
100
113
  * @see https://github.com/angular/components/issues/XXXXX (TODO: file issue)
114
+ *
115
+ * Uses afterRenderEffect to ensure DOM is ready before manipulating attributes.
101
116
  */
102
- syncAriaRequiredToDom = explicitEffect([this.ariaRequired], ([isRequired]) => {
117
+ syncAriaRequiredToDom = afterRenderEffect(() => {
118
+ const isRequired = this.ariaRequired();
103
119
  const inputEl = this.elementRef.nativeElement.querySelector('input[type="checkbox"]');
104
120
  if (inputEl) {
105
121
  if (isRequired) {
@@ -110,11 +126,28 @@ class MatCheckboxFieldComponent {
110
126
  }
111
127
  }
112
128
  });
113
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
114
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatCheckboxFieldComponent, isStandalone: true, selector: "df-mat-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
129
+ /**
130
+ * Workaround: Angular Material's MatCheckbox does NOT propagate aria-describedby to its internal
131
+ * input element. This effect imperatively sets/removes aria-describedby on the internal input.
132
+ *
133
+ * Uses afterRenderEffect to ensure DOM is ready before querying internal elements.
134
+ */
135
+ syncAriaDescribedByToDom = afterRenderEffect(() => {
136
+ const describedBy = this.ariaDescribedBy();
137
+ const inputEl = this.elementRef.nativeElement.querySelector('input[type="checkbox"]');
138
+ if (inputEl) {
139
+ if (describedBy) {
140
+ inputEl.setAttribute('aria-describedby', describedBy);
141
+ }
142
+ else {
143
+ inputEl.removeAttribute('aria-describedby');
144
+ }
145
+ }
146
+ });
147
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
148
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatCheckboxFieldComponent, isStandalone: true, selector: "df-mat-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
115
149
  @let f = field();
116
150
  @let checkboxId = key() + '-checkbox';
117
- @let ariaDescribedBy = this.ariaDescribedBy();
118
151
 
119
152
  <mat-checkbox
120
153
  [id]="checkboxId"
@@ -124,27 +157,27 @@ class MatCheckboxFieldComponent {
124
157
  [color]="props()?.color || 'primary'"
125
158
  [disableRipple]="effectiveDisableRipple()"
126
159
  [required]="!!f().required()"
127
- [aria-describedby]="ariaDescribedBy"
160
+ [attr.aria-describedby]="ariaDescribedBy()"
128
161
  [attr.tabindex]="tabIndex()"
129
162
  [attr.hidden]="f().hidden() || null"
130
163
  >
131
164
  {{ label() | dynamicText | async }}
132
165
  </mat-checkbox>
133
166
 
134
- @if (props()?.hint; as hint) {
135
- <div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
136
- }
137
167
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
138
168
  <mat-error [id]="errorId() + '-' + i" [attr.hidden]="f().hidden() || null">{{ error.message }}</mat-error>
169
+ } @empty {
170
+ @if (props()?.hint; as hint) {
171
+ <div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
172
+ }
139
173
  }
140
174
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"], dependencies: [{ kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
141
175
  }
142
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatCheckboxFieldComponent, decorators: [{
176
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatCheckboxFieldComponent, decorators: [{
143
177
  type: Component,
144
178
  args: [{ selector: 'df-mat-checkbox', imports: [MatCheckbox, FormField, MatError, DynamicTextPipe, AsyncPipe], template: `
145
179
  @let f = field();
146
180
  @let checkboxId = key() + '-checkbox';
147
- @let ariaDescribedBy = this.ariaDescribedBy();
148
181
 
149
182
  <mat-checkbox
150
183
  [id]="checkboxId"
@@ -154,18 +187,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
154
187
  [color]="props()?.color || 'primary'"
155
188
  [disableRipple]="effectiveDisableRipple()"
156
189
  [required]="!!f().required()"
157
- [aria-describedby]="ariaDescribedBy"
190
+ [attr.aria-describedby]="ariaDescribedBy()"
158
191
  [attr.tabindex]="tabIndex()"
159
192
  [attr.hidden]="f().hidden() || null"
160
193
  >
161
194
  {{ label() | dynamicText | async }}
162
195
  </mat-checkbox>
163
196
 
164
- @if (props()?.hint; as hint) {
165
- <div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
166
- }
167
197
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
168
198
  <mat-error [id]="errorId() + '-' + i" [attr.hidden]="f().hidden() || null">{{ error.message }}</mat-error>
199
+ } @empty {
200
+ @if (props()?.hint; as hint) {
201
+ <div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
202
+ }
169
203
  }
170
204
  `, host: {
171
205
  '[class]': 'className()',
@@ -176,8 +210,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
176
210
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
177
211
 
178
212
  var matCheckbox_component = /*#__PURE__*/Object.freeze({
179
- __proto__: null,
180
- default: MatCheckboxFieldComponent
213
+ __proto__: null,
214
+ default: MatCheckboxFieldComponent
181
215
  });
182
216
 
183
217
  class MatDatepickerFieldComponent {
@@ -221,23 +255,11 @@ class MatDatepickerFieldComponent {
221
255
  return this.field()().required?.() === true ? true : null;
222
256
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
223
257
  /** aria-describedby: links to hint and error messages for screen readers */
224
- ariaDescribedBy = computed(() => {
225
- const ids = [];
226
- if (this.props()?.hint) {
227
- ids.push(this.hintId());
228
- }
229
- const errors = this.errorsToDisplay();
230
- errors.forEach((_, i) => {
231
- ids.push(`${this.errorId()}-${i}`);
232
- });
233
- return ids.length > 0 ? ids.join(' ') : null;
234
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
235
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatDatepickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
236
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatDatepickerFieldComponent, isStandalone: true, selector: "df-mat-datepicker", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "class": "className()", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, providers: [provideNativeDateAdapter()], ngImport: i0, template: `
258
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
259
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatDatepickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
260
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatDatepickerFieldComponent, isStandalone: true, selector: "df-mat-datepicker", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "class": "className()", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, providers: [provideNativeDateAdapter()], ngImport: i0, template: `
237
261
  @let f = field();
238
262
  @let inputId = key() + '-input';
239
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
240
- @let ariaDescribedBy = this.ariaDescribedBy();
241
263
 
242
264
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
243
265
  @if (label(); as label) {
@@ -253,24 +275,25 @@ class MatDatepickerFieldComponent {
253
275
  [attr.tabindex]="tabIndex()"
254
276
  [min]="minDate()"
255
277
  [max]="maxDate()"
256
- [attr.aria-invalid]="ariaInvalid"
257
- [attr.aria-required]="ariaRequired"
258
- [attr.aria-describedby]="ariaDescribedBy"
278
+ [attr.aria-invalid]="ariaInvalid()"
279
+ [attr.aria-required]="ariaRequired()"
280
+ [attr.aria-describedby]="ariaDescribedBy()"
259
281
  />
260
282
 
261
- <mat-datepicker-toggle matIconSuffix [for]="$any(picker)" />
283
+ <mat-datepicker-toggle matIconSuffix [for]="picker" />
262
284
  <mat-datepicker #picker [startAt]="startAt()" [startView]="props()?.startView || 'month'" [touchUi]="props()?.touchUi ?? false" />
263
285
 
264
- @if (props()?.hint; as hint) {
265
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
266
- }
267
286
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
268
287
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
288
+ } @empty {
289
+ @if (props()?.hint; as hint) {
290
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
291
+ }
269
292
  }
270
293
  </mat-form-field>
271
294
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
272
295
  }
273
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatDatepickerFieldComponent, decorators: [{
296
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatDatepickerFieldComponent, decorators: [{
274
297
  type: Component,
275
298
  args: [{ selector: 'df-mat-datepicker', imports: [
276
299
  MatFormField,
@@ -293,8 +316,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
293
316
  }, template: `
294
317
  @let f = field();
295
318
  @let inputId = key() + '-input';
296
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
297
- @let ariaDescribedBy = this.ariaDescribedBy();
298
319
 
299
320
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
300
321
  @if (label(); as label) {
@@ -310,27 +331,28 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
310
331
  [attr.tabindex]="tabIndex()"
311
332
  [min]="minDate()"
312
333
  [max]="maxDate()"
313
- [attr.aria-invalid]="ariaInvalid"
314
- [attr.aria-required]="ariaRequired"
315
- [attr.aria-describedby]="ariaDescribedBy"
334
+ [attr.aria-invalid]="ariaInvalid()"
335
+ [attr.aria-required]="ariaRequired()"
336
+ [attr.aria-describedby]="ariaDescribedBy()"
316
337
  />
317
338
 
318
- <mat-datepicker-toggle matIconSuffix [for]="$any(picker)" />
339
+ <mat-datepicker-toggle matIconSuffix [for]="picker" />
319
340
  <mat-datepicker #picker [startAt]="startAt()" [startView]="props()?.startView || 'month'" [touchUi]="props()?.touchUi ?? false" />
320
341
 
321
- @if (props()?.hint; as hint) {
322
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
323
- }
324
342
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
325
343
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
344
+ } @empty {
345
+ @if (props()?.hint; as hint) {
346
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
347
+ }
326
348
  }
327
349
  </mat-form-field>
328
350
  `, providers: [provideNativeDateAdapter()], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "mat-form-field{width:100%}\n"] }]
329
351
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], minDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "minDate", required: false }] }], maxDate: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxDate", required: false }] }], startAt: [{ type: i0.Input, args: [{ isSignal: true, alias: "startAt", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
330
352
 
331
353
  var matDatepicker_component = /*#__PURE__*/Object.freeze({
332
- __proto__: null,
333
- default: MatDatepickerFieldComponent
354
+ __proto__: null,
355
+ default: MatDatepickerFieldComponent
334
356
  });
335
357
 
336
358
  class MatInputFieldComponent {
@@ -409,23 +431,11 @@ class MatInputFieldComponent {
409
431
  return this.field()().required?.() === true ? true : null;
410
432
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
411
433
  /** aria-describedby: links to hint and error messages for screen readers */
412
- ariaDescribedBy = computed(() => {
413
- const ids = [];
414
- if (this.props()?.hint) {
415
- ids.push(this.hintId());
416
- }
417
- const errors = this.errorsToDisplay();
418
- errors.forEach((_, i) => {
419
- ids.push(`${this.errorId()}-${i}`);
420
- });
421
- return ids.length > 0 ? ids.join(' ') : null;
422
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
423
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
424
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatInputFieldComponent, isStandalone: true, selector: "df-mat-input", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
434
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
435
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
436
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatInputFieldComponent, isStandalone: true, selector: "df-mat-input", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
425
437
  @let f = field();
426
438
  @let inputId = key() + '-input';
427
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
428
- @let ariaDescribedBy = this.ariaDescribedBy();
429
439
 
430
440
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
431
441
  @if (label()) {
@@ -439,26 +449,25 @@ class MatInputFieldComponent {
439
449
  [type]="props()?.type ?? 'text'"
440
450
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
441
451
  [attr.tabindex]="tabIndex()"
442
- [attr.aria-invalid]="ariaInvalid"
443
- [attr.aria-required]="ariaRequired"
444
- [attr.aria-describedby]="ariaDescribedBy"
452
+ [attr.aria-invalid]="ariaInvalid()"
453
+ [attr.aria-required]="ariaRequired()"
454
+ [attr.aria-describedby]="ariaDescribedBy()"
445
455
  />
446
- @if (props()?.hint; as hint) {
447
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
448
- }
449
456
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
450
457
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
458
+ } @empty {
459
+ @if (props()?.hint; as hint) {
460
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
461
+ }
451
462
  }
452
463
  </mat-form-field>
453
464
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
454
465
  }
455
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatInputFieldComponent, decorators: [{
466
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatInputFieldComponent, decorators: [{
456
467
  type: Component,
457
468
  args: [{ selector: 'df-mat-input', imports: [MatFormField, MatLabel, MatInput, MatHint, FormField, MatError$1, DynamicTextPipe, AsyncPipe], template: `
458
469
  @let f = field();
459
470
  @let inputId = key() + '-input';
460
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
461
- @let ariaDescribedBy = this.ariaDescribedBy();
462
471
 
463
472
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
464
473
  @if (label()) {
@@ -472,15 +481,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
472
481
  [type]="props()?.type ?? 'text'"
473
482
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
474
483
  [attr.tabindex]="tabIndex()"
475
- [attr.aria-invalid]="ariaInvalid"
476
- [attr.aria-required]="ariaRequired"
477
- [attr.aria-describedby]="ariaDescribedBy"
484
+ [attr.aria-invalid]="ariaInvalid()"
485
+ [attr.aria-required]="ariaRequired()"
486
+ [attr.aria-describedby]="ariaDescribedBy()"
478
487
  />
479
- @if (props()?.hint; as hint) {
480
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
481
- }
482
488
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
483
489
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
490
+ } @empty {
491
+ @if (props()?.hint; as hint) {
492
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
493
+ }
484
494
  }
485
495
  </mat-form-field>
486
496
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
@@ -492,8 +502,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
492
502
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }], inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: true }] }] } });
493
503
 
494
504
  var matInput_component = /*#__PURE__*/Object.freeze({
495
- __proto__: null,
496
- default: MatInputFieldComponent
505
+ __proto__: null,
506
+ default: MatInputFieldComponent
497
507
  });
498
508
 
499
509
  class MatMultiCheckboxFieldComponent {
@@ -511,6 +521,14 @@ class MatMultiCheckboxFieldComponent {
511
521
  const currentValues = this.field()().value();
512
522
  return this.options().filter((option) => currentValues.includes(option.value));
513
523
  }, { ...(ngDevMode ? { debugName: "valueViewModel" } : {}), equal: isEqual });
524
+ /** Computed map of checked option values for O(1) lookup in template */
525
+ checkedValuesMap = computed(() => {
526
+ const map = {};
527
+ for (const opt of this.valueViewModel()) {
528
+ map[String(opt.value)] = true;
529
+ }
530
+ return map;
531
+ }, ...(ngDevMode ? [{ debugName: "checkedValuesMap" }] : []));
514
532
  constructor() {
515
533
  // Apply meta attributes to all checkbox inputs, re-apply when options change
516
534
  setupMetaTracking(this.elementRef, this.meta, {
@@ -564,23 +582,12 @@ class MatMultiCheckboxFieldComponent {
564
582
  return this.field()().required?.() === true ? true : null;
565
583
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
566
584
  /** aria-describedby: links to hint and error messages for screen readers */
567
- ariaDescribedBy = computed(() => {
568
- const ids = [];
569
- if (this.props()?.hint) {
570
- ids.push(this.hintId());
571
- }
572
- const errors = this.errorsToDisplay();
573
- errors.forEach((_, i) => {
574
- ids.push(`${this.errorId()}-${i}`);
575
- });
576
- return ids.length > 0 ? ids.join(' ') : null;
577
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
578
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatMultiCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
579
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatMultiCheckboxFieldComponent, isStandalone: true, selector: "df-mat-multi-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className() || \"\"", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, providers: [ValueInArrayPipe], ngImport: i0, template: `
585
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
586
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatMultiCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
587
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatMultiCheckboxFieldComponent, isStandalone: true, selector: "df-mat-multi-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className() || \"\"", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
580
588
  @let f = field();
581
589
  @let checkboxGroupId = key() + '-checkbox-group';
582
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
583
- @let ariaDescribedBy = this.ariaDescribedBy();
590
+ @let checked = checkedValuesMap();
584
591
 
585
592
  @if (label(); as label) {
586
593
  <div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
@@ -590,13 +597,13 @@ class MatMultiCheckboxFieldComponent {
590
597
  [id]="checkboxGroupId"
591
598
  class="checkbox-group"
592
599
  role="group"
593
- [attr.aria-invalid]="ariaInvalid"
594
- [attr.aria-required]="ariaRequired"
595
- [attr.aria-describedby]="ariaDescribedBy"
600
+ [attr.aria-invalid]="ariaInvalid()"
601
+ [attr.aria-required]="ariaRequired()"
602
+ [attr.aria-describedby]="ariaDescribedBy()"
596
603
  >
597
604
  @for (option of options(); track option.value) {
598
605
  <mat-checkbox
599
- [checked]="option | inArray: valueViewModel()"
606
+ [checked]="checked['' + option.value]"
600
607
  [disabled]="f().disabled() || option.disabled"
601
608
  [color]="props()?.color || 'primary'"
602
609
  [labelPosition]="props()?.labelPosition || 'after'"
@@ -607,21 +614,21 @@ class MatMultiCheckboxFieldComponent {
607
614
  }
608
615
  </div>
609
616
 
610
- @if (props()?.hint; as hint) {
611
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
612
- }
613
617
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
614
618
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
619
+ } @empty {
620
+ @if (props()?.hint; as hint) {
621
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
622
+ }
615
623
  }
616
- `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"], dependencies: [{ kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: ValueInArrayPipe, name: "inArray" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
624
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"], dependencies: [{ kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
617
625
  }
618
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatMultiCheckboxFieldComponent, decorators: [{
626
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatMultiCheckboxFieldComponent, decorators: [{
619
627
  type: Component,
620
- args: [{ selector: 'df-mat-multi-checkbox', imports: [MatCheckbox, ValueInArrayPipe, MatError, DynamicTextPipe, AsyncPipe], template: `
628
+ args: [{ selector: 'df-mat-multi-checkbox', imports: [MatCheckbox, MatError, DynamicTextPipe, AsyncPipe], template: `
621
629
  @let f = field();
622
630
  @let checkboxGroupId = key() + '-checkbox-group';
623
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
624
- @let ariaDescribedBy = this.ariaDescribedBy();
631
+ @let checked = checkedValuesMap();
625
632
 
626
633
  @if (label(); as label) {
627
634
  <div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
@@ -631,13 +638,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
631
638
  [id]="checkboxGroupId"
632
639
  class="checkbox-group"
633
640
  role="group"
634
- [attr.aria-invalid]="ariaInvalid"
635
- [attr.aria-required]="ariaRequired"
636
- [attr.aria-describedby]="ariaDescribedBy"
641
+ [attr.aria-invalid]="ariaInvalid()"
642
+ [attr.aria-required]="ariaRequired()"
643
+ [attr.aria-describedby]="ariaDescribedBy()"
637
644
  >
638
645
  @for (option of options(); track option.value) {
639
646
  <mat-checkbox
640
- [checked]="option | inArray: valueViewModel()"
647
+ [checked]="checked['' + option.value]"
641
648
  [disabled]="f().disabled() || option.disabled"
642
649
  [color]="props()?.color || 'primary'"
643
650
  [labelPosition]="props()?.labelPosition || 'after'"
@@ -648,23 +655,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
648
655
  }
649
656
  </div>
650
657
 
651
- @if (props()?.hint; as hint) {
652
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
653
- }
654
658
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
655
659
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
660
+ } @empty {
661
+ @if (props()?.hint; as hint) {
662
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
663
+ }
656
664
  }
657
665
  `, host: {
658
666
  '[class]': 'className() || ""',
659
667
  '[id]': '`${key()}`',
660
668
  '[attr.data-testid]': 'key()',
661
669
  '[attr.hidden]': 'field()().hidden() || null',
662
- }, providers: [ValueInArrayPipe], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"] }]
670
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"] }]
663
671
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
664
672
 
665
673
  var matMultiCheckbox_component = /*#__PURE__*/Object.freeze({
666
- __proto__: null,
667
- default: MatMultiCheckboxFieldComponent
674
+ __proto__: null,
675
+ default: MatMultiCheckboxFieldComponent
668
676
  });
669
677
 
670
678
  class MatRadioFieldComponent {
@@ -707,23 +715,11 @@ class MatRadioFieldComponent {
707
715
  return this.field()().required?.() === true ? true : null;
708
716
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
709
717
  /** aria-describedby: links to hint and error messages for screen readers */
710
- ariaDescribedBy = computed(() => {
711
- const ids = [];
712
- if (this.props()?.hint) {
713
- ids.push(this.hintId());
714
- }
715
- const errors = this.errorsToDisplay();
716
- errors.forEach((_, i) => {
717
- ids.push(`${this.errorId()}-${i}`);
718
- });
719
- return ids.length > 0 ? ids.join(' ') : null;
720
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
721
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatRadioFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
722
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatRadioFieldComponent, isStandalone: true, selector: "df-mat-radio", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className() || \"\"", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
718
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
719
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatRadioFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
720
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatRadioFieldComponent, isStandalone: true, selector: "df-mat-radio", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className() || \"\"", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
723
721
  @let f = field();
724
722
  @let radioGroupId = key() + '-radio-group';
725
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
726
- @let ariaDescribedBy = this.ariaDescribedBy();
727
723
 
728
724
  @if (label()) {
729
725
  <div class="radio-label">{{ label() | dynamicText | async }}</div>
@@ -732,9 +728,9 @@ class MatRadioFieldComponent {
732
728
  <mat-radio-group
733
729
  [id]="radioGroupId"
734
730
  [formField]="f"
735
- [attr.aria-invalid]="ariaInvalid"
736
- [attr.aria-required]="ariaRequired"
737
- [attr.aria-describedby]="ariaDescribedBy"
731
+ [attr.aria-invalid]="ariaInvalid()"
732
+ [attr.aria-required]="ariaRequired()"
733
+ [attr.aria-describedby]="ariaDescribedBy()"
738
734
  >
739
735
  @for (option of options(); track option.value) {
740
736
  <mat-radio-button
@@ -748,21 +744,20 @@ class MatRadioFieldComponent {
748
744
  }
749
745
  </mat-radio-group>
750
746
 
751
- @if (props()?.hint; as hint) {
752
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
753
- }
754
747
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
755
748
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
749
+ } @empty {
750
+ @if (props()?.hint; as hint) {
751
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
752
+ }
756
753
  }
757
754
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"], dependencies: [{ kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
758
755
  }
759
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatRadioFieldComponent, decorators: [{
756
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatRadioFieldComponent, decorators: [{
760
757
  type: Component,
761
758
  args: [{ selector: 'df-mat-radio', imports: [MatRadioGroup, MatRadioButton, FormField, MatError, DynamicTextPipe, AsyncPipe], template: `
762
759
  @let f = field();
763
760
  @let radioGroupId = key() + '-radio-group';
764
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
765
- @let ariaDescribedBy = this.ariaDescribedBy();
766
761
 
767
762
  @if (label()) {
768
763
  <div class="radio-label">{{ label() | dynamicText | async }}</div>
@@ -771,9 +766,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
771
766
  <mat-radio-group
772
767
  [id]="radioGroupId"
773
768
  [formField]="f"
774
- [attr.aria-invalid]="ariaInvalid"
775
- [attr.aria-required]="ariaRequired"
776
- [attr.aria-describedby]="ariaDescribedBy"
769
+ [attr.aria-invalid]="ariaInvalid()"
770
+ [attr.aria-required]="ariaRequired()"
771
+ [attr.aria-describedby]="ariaDescribedBy()"
777
772
  >
778
773
  @for (option of options(); track option.value) {
779
774
  <mat-radio-button
@@ -787,11 +782,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
787
782
  }
788
783
  </mat-radio-group>
789
784
 
790
- @if (props()?.hint; as hint) {
791
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
792
- }
793
785
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
794
786
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
787
+ } @empty {
788
+ @if (props()?.hint; as hint) {
789
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
790
+ }
795
791
  }
796
792
  `, host: {
797
793
  '[class]': 'className() || ""',
@@ -802,8 +798,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
802
798
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
803
799
 
804
800
  var matRadio_component = /*#__PURE__*/Object.freeze({
805
- __proto__: null,
806
- default: MatRadioFieldComponent
801
+ __proto__: null,
802
+ default: MatRadioFieldComponent
807
803
  });
808
804
 
809
805
  class MatSelectFieldComponent {
@@ -849,23 +845,11 @@ class MatSelectFieldComponent {
849
845
  return this.field()().required?.() === true ? true : null;
850
846
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
851
847
  /** aria-describedby: links to hint and error messages for screen readers */
852
- ariaDescribedBy = computed(() => {
853
- const ids = [];
854
- if (this.props()?.hint) {
855
- ids.push(this.hintId());
856
- }
857
- const errors = this.errorsToDisplay();
858
- errors.forEach((_, i) => {
859
- ids.push(`${this.errorId()}-${i}`);
860
- });
861
- return ids.length > 0 ? ids.join(' ') : null;
862
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
863
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
864
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatSelectFieldComponent, isStandalone: true, selector: "df-mat-select", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
848
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
849
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
850
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatSelectFieldComponent, isStandalone: true, selector: "df-mat-select", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
865
851
  @let f = field();
866
852
  @let selectId = key() + '-select';
867
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
868
- @let ariaDescribedBy = this.ariaDescribedBy();
869
853
 
870
854
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
871
855
  @if (label(); as label) {
@@ -878,9 +862,9 @@ class MatSelectFieldComponent {
878
862
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
879
863
  [multiple]="props()?.multiple || false"
880
864
  [compareWith]="props()?.compareWith || defaultCompare"
881
- [attr.aria-invalid]="ariaInvalid"
882
- [attr.aria-required]="ariaRequired"
883
- [attr.aria-describedby]="ariaDescribedBy"
865
+ [attr.aria-invalid]="ariaInvalid()"
866
+ [attr.aria-required]="ariaRequired()"
867
+ [attr.aria-describedby]="ariaDescribedBy()"
884
868
  >
885
869
  @for (option of options(); track option.value) {
886
870
  <mat-option [value]="option.value" [disabled]="option.disabled || false">
@@ -889,22 +873,21 @@ class MatSelectFieldComponent {
889
873
  }
890
874
  </mat-select>
891
875
 
892
- @if (props()?.hint; as hint) {
893
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
894
- }
895
876
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
896
877
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
878
+ } @empty {
879
+ @if (props()?.hint; as hint) {
880
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
881
+ }
897
882
  }
898
883
  </mat-form-field>
899
884
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
900
885
  }
901
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatSelectFieldComponent, decorators: [{
886
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatSelectFieldComponent, decorators: [{
902
887
  type: Component,
903
888
  args: [{ selector: 'df-mat-select', imports: [MatFormField, MatLabel, MatSelect, MatOption, MatHint, FormField, MatError$1, DynamicTextPipe, AsyncPipe], template: `
904
889
  @let f = field();
905
890
  @let selectId = key() + '-select';
906
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
907
- @let ariaDescribedBy = this.ariaDescribedBy();
908
891
 
909
892
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
910
893
  @if (label(); as label) {
@@ -917,9 +900,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
917
900
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
918
901
  [multiple]="props()?.multiple || false"
919
902
  [compareWith]="props()?.compareWith || defaultCompare"
920
- [attr.aria-invalid]="ariaInvalid"
921
- [attr.aria-required]="ariaRequired"
922
- [attr.aria-describedby]="ariaDescribedBy"
903
+ [attr.aria-invalid]="ariaInvalid()"
904
+ [attr.aria-required]="ariaRequired()"
905
+ [attr.aria-describedby]="ariaDescribedBy()"
923
906
  >
924
907
  @for (option of options(); track option.value) {
925
908
  <mat-option [value]="option.value" [disabled]="option.disabled || false">
@@ -928,11 +911,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
928
911
  }
929
912
  </mat-select>
930
913
 
931
- @if (props()?.hint; as hint) {
932
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
933
- }
934
914
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
935
915
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
916
+ } @empty {
917
+ @if (props()?.hint; as hint) {
918
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
919
+ }
936
920
  }
937
921
  </mat-form-field>
938
922
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
@@ -944,8 +928,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
944
928
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], options: [{ type: i0.Input, args: [{ isSignal: true, alias: "options", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
945
929
 
946
930
  var matSelect_component = /*#__PURE__*/Object.freeze({
947
- __proto__: null,
948
- default: MatSelectFieldComponent
931
+ __proto__: null,
932
+ default: MatSelectFieldComponent
949
933
  });
950
934
 
951
935
  class MatSliderFieldComponent {
@@ -979,23 +963,11 @@ class MatSliderFieldComponent {
979
963
  return fieldState.invalid() && fieldState.touched();
980
964
  }, ...(ngDevMode ? [{ debugName: "ariaInvalid" }] : []));
981
965
  /** aria-describedby: links to hint and error messages for screen readers */
982
- ariaDescribedBy = computed(() => {
983
- const ids = [];
984
- if (this.props()?.hint) {
985
- ids.push(this.hintId());
986
- }
987
- const errors = this.errorsToDisplay();
988
- errors.forEach((_, i) => {
989
- ids.push(`${this.errorId()}-${i}`);
990
- });
991
- return ids.length > 0 ? ids.join(' ') : null;
992
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
993
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatSliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
994
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatSliderFieldComponent, isStandalone: true, selector: "df-mat-slider", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
966
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
967
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatSliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
968
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatSliderFieldComponent, isStandalone: true, selector: "df-mat-slider", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
995
969
  @let f = field();
996
970
  @let inputId = key() + '-input';
997
- @let ariaInvalid = this.ariaInvalid();
998
- @let ariaDescribedBy = this.ariaDescribedBy();
999
971
 
1000
972
  @if (label(); as label) {
1001
973
  <div class="slider-label">{{ label | dynamicText | async }}</div>
@@ -1015,26 +987,25 @@ class MatSliderFieldComponent {
1015
987
  [id]="inputId"
1016
988
  [formField]="f"
1017
989
  [attr.tabindex]="tabIndex()"
1018
- [attr.aria-invalid]="ariaInvalid"
1019
- [attr.aria-describedby]="ariaDescribedBy"
990
+ [attr.aria-invalid]="ariaInvalid()"
991
+ [attr.aria-describedby]="ariaDescribedBy()"
1020
992
  />
1021
993
  </mat-slider>
1022
994
 
1023
- @if (props()?.hint; as hint) {
1024
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1025
- }
1026
995
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1027
996
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
997
+ } @empty {
998
+ @if (props()?.hint; as hint) {
999
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1000
+ }
1028
1001
  }
1029
1002
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", ".slider-container{width:100%}\n"], dependencies: [{ kind: "component", type: MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1030
1003
  }
1031
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatSliderFieldComponent, decorators: [{
1004
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatSliderFieldComponent, decorators: [{
1032
1005
  type: Component,
1033
1006
  args: [{ selector: 'df-mat-slider', imports: [MatSlider, MatSliderThumb, MatError, DynamicTextPipe, AsyncPipe, FormField], template: `
1034
1007
  @let f = field();
1035
1008
  @let inputId = key() + '-input';
1036
- @let ariaInvalid = this.ariaInvalid();
1037
- @let ariaDescribedBy = this.ariaDescribedBy();
1038
1009
 
1039
1010
  @if (label(); as label) {
1040
1011
  <div class="slider-label">{{ label | dynamicText | async }}</div>
@@ -1054,16 +1025,17 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1054
1025
  [id]="inputId"
1055
1026
  [formField]="f"
1056
1027
  [attr.tabindex]="tabIndex()"
1057
- [attr.aria-invalid]="ariaInvalid"
1058
- [attr.aria-describedby]="ariaDescribedBy"
1028
+ [attr.aria-invalid]="ariaInvalid()"
1029
+ [attr.aria-describedby]="ariaDescribedBy()"
1059
1030
  />
1060
1031
  </mat-slider>
1061
1032
 
1062
- @if (props()?.hint; as hint) {
1063
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1064
- }
1065
1033
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1066
1034
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
1035
+ } @empty {
1036
+ @if (props()?.hint; as hint) {
1037
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1038
+ }
1067
1039
  }
1068
1040
  `, host: {
1069
1041
  '[class]': 'className()',
@@ -1074,8 +1046,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1074
1046
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
1075
1047
 
1076
1048
  var matSlider_component = /*#__PURE__*/Object.freeze({
1077
- __proto__: null,
1078
- default: MatSliderFieldComponent
1049
+ __proto__: null,
1050
+ default: MatSliderFieldComponent
1079
1051
  });
1080
1052
 
1081
1053
  class MatButtonFieldComponent {
@@ -1134,8 +1106,8 @@ class MatButtonFieldComponent {
1134
1106
  this.eventBus.dispatch(event);
1135
1107
  }
1136
1108
  }
1137
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatButtonFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1138
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: MatButtonFieldComponent, isStandalone: true, selector: "df-mat-button", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, eventArgs: { classPropertyName: "eventArgs", publicName: "eventArgs", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, eventContext: { classPropertyName: "eventContext", publicName: "eventContext", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()" } }, ngImport: i0, template: `
1109
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatButtonFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1110
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.1.0", type: MatButtonFieldComponent, isStandalone: true, selector: "df-mat-button", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, eventArgs: { classPropertyName: "eventArgs", publicName: "eventArgs", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, eventContext: { classPropertyName: "eventContext", publicName: "eventContext", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "hidden() || null" } }, ngImport: i0, template: `
1139
1111
  @let buttonId = key() + '-button';
1140
1112
  <button
1141
1113
  mat-raised-button
@@ -1150,12 +1122,13 @@ class MatButtonFieldComponent {
1150
1122
  </button>
1151
1123
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "button{min-width:fit-content}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1152
1124
  }
1153
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatButtonFieldComponent, decorators: [{
1125
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatButtonFieldComponent, decorators: [{
1154
1126
  type: Component,
1155
1127
  args: [{ selector: 'df-mat-button', imports: [MatButton, DynamicTextPipe, AsyncPipe], host: {
1156
1128
  '[id]': '`${key()}`',
1157
1129
  '[attr.data-testid]': 'key()',
1158
1130
  '[class]': 'className()',
1131
+ '[attr.hidden]': 'hidden() || null',
1159
1132
  }, template: `
1160
1133
  @let buttonId = key() + '-button';
1161
1134
  <button
@@ -1173,8 +1146,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1173
1146
  }], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], event: [{ type: i0.Input, args: [{ isSignal: true, alias: "event", required: false }] }], eventArgs: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventArgs", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], eventContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventContext", required: false }] }] } });
1174
1147
 
1175
1148
  var matButton_component = /*#__PURE__*/Object.freeze({
1176
- __proto__: null,
1177
- default: MatButtonFieldComponent
1149
+ __proto__: null,
1150
+ default: MatButtonFieldComponent
1178
1151
  });
1179
1152
 
1180
1153
  // Public API - component
@@ -1215,17 +1188,23 @@ class MatTextareaFieldComponent {
1215
1188
  * Note: We cannot use [readonly] or [attr.readonly] bindings because Angular throws
1216
1189
  * NG8022: "Binding to '[readonly]' is not allowed on nodes using the '[field]' directive"
1217
1190
  *
1191
+ * Uses afterRenderEffect to ensure DOM is ready before manipulating attributes.
1192
+ *
1218
1193
  * @see https://github.com/angular/angular/issues/65897
1219
1194
  */
1220
- syncReadonlyToDom = explicitEffect([this.textareaRef, this.isReadonly], ([textareaRef, isReadonly]) => {
1221
- if (textareaRef?.nativeElement) {
1222
- if (isReadonly) {
1223
- textareaRef.nativeElement.setAttribute('readonly', '');
1224
- }
1225
- else {
1226
- textareaRef.nativeElement.removeAttribute('readonly');
1195
+ syncReadonlyToDom = afterRenderEffect({
1196
+ write: () => {
1197
+ const textareaRef = this.textareaRef();
1198
+ const isReadonly = this.isReadonly();
1199
+ if (textareaRef?.nativeElement) {
1200
+ if (isReadonly) {
1201
+ textareaRef.nativeElement.setAttribute('readonly', '');
1202
+ }
1203
+ else {
1204
+ textareaRef.nativeElement.removeAttribute('readonly');
1205
+ }
1227
1206
  }
1228
- }
1207
+ },
1229
1208
  });
1230
1209
  effectiveAppearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline', ...(ngDevMode ? [{ debugName: "effectiveAppearance" }] : []));
1231
1210
  effectiveSubscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic', ...(ngDevMode ? [{ debugName: "effectiveSubscriptSizing" }] : []));
@@ -1249,23 +1228,11 @@ class MatTextareaFieldComponent {
1249
1228
  return this.field()().required?.() === true ? true : null;
1250
1229
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
1251
1230
  /** aria-describedby: links to hint and error messages for screen readers */
1252
- ariaDescribedBy = computed(() => {
1253
- const ids = [];
1254
- if (this.props()?.hint) {
1255
- ids.push(this.hintId());
1256
- }
1257
- const errors = this.errorsToDisplay();
1258
- errors.forEach((_, i) => {
1259
- ids.push(`${this.errorId()}-${i}`);
1260
- });
1261
- return ids.length > 0 ? ids.join(' ') : null;
1262
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
1263
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatTextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1264
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatTextareaFieldComponent, isStandalone: true, selector: "df-mat-textarea", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "textareaRef", first: true, predicate: ["textareaRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
1231
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
1232
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatTextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1233
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatTextareaFieldComponent, isStandalone: true, selector: "df-mat-textarea", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "textareaRef", first: true, predicate: ["textareaRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
1265
1234
  @let f = field();
1266
1235
  @let textareaId = key() + '-textarea';
1267
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
1268
- @let ariaDescribedBy = this.ariaDescribedBy();
1269
1236
 
1270
1237
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
1271
1238
  @if (label()) {
@@ -1279,28 +1246,27 @@ class MatTextareaFieldComponent {
1279
1246
  [formField]="f"
1280
1247
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
1281
1248
  [attr.tabindex]="tabIndex()"
1282
- [attr.aria-invalid]="ariaInvalid"
1283
- [attr.aria-required]="ariaRequired"
1284
- [attr.aria-describedby]="ariaDescribedBy"
1249
+ [attr.aria-invalid]="ariaInvalid()"
1250
+ [attr.aria-required]="ariaRequired()"
1251
+ [attr.aria-describedby]="ariaDescribedBy()"
1285
1252
  [style.resize]="props()?.resize || 'vertical'"
1286
1253
  ></textarea>
1287
1254
 
1288
- @if (props()?.hint; as hint) {
1289
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
1290
- }
1291
1255
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1292
1256
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
1257
+ } @empty {
1258
+ @if (props()?.hint; as hint) {
1259
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
1260
+ }
1293
1261
  }
1294
1262
  </mat-form-field>
1295
1263
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n", "mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1296
1264
  }
1297
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatTextareaFieldComponent, decorators: [{
1265
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatTextareaFieldComponent, decorators: [{
1298
1266
  type: Component,
1299
1267
  args: [{ selector: 'df-mat-textarea', imports: [MatFormField, MatLabel, MatInput, MatHint, FormField, MatError$1, DynamicTextPipe, AsyncPipe], template: `
1300
1268
  @let f = field();
1301
1269
  @let textareaId = key() + '-textarea';
1302
- @let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
1303
- @let ariaDescribedBy = this.ariaDescribedBy();
1304
1270
 
1305
1271
  <mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
1306
1272
  @if (label()) {
@@ -1314,17 +1280,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1314
1280
  [formField]="f"
1315
1281
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
1316
1282
  [attr.tabindex]="tabIndex()"
1317
- [attr.aria-invalid]="ariaInvalid"
1318
- [attr.aria-required]="ariaRequired"
1319
- [attr.aria-describedby]="ariaDescribedBy"
1283
+ [attr.aria-invalid]="ariaInvalid()"
1284
+ [attr.aria-required]="ariaRequired()"
1285
+ [attr.aria-describedby]="ariaDescribedBy()"
1320
1286
  [style.resize]="props()?.resize || 'vertical'"
1321
1287
  ></textarea>
1322
1288
 
1323
- @if (props()?.hint; as hint) {
1324
- <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
1325
- }
1326
1289
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1327
1290
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
1291
+ } @empty {
1292
+ @if (props()?.hint; as hint) {
1293
+ <mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
1294
+ }
1328
1295
  }
1329
1296
  </mat-form-field>
1330
1297
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
@@ -1336,8 +1303,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1336
1303
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }], textareaRef: [{ type: i0.ViewChild, args: ['textareaRef', { isSignal: true }] }] } });
1337
1304
 
1338
1305
  var matTextarea_component = /*#__PURE__*/Object.freeze({
1339
- __proto__: null,
1340
- default: MatTextareaFieldComponent
1306
+ __proto__: null,
1307
+ default: MatTextareaFieldComponent
1341
1308
  });
1342
1309
 
1343
1310
  class MatToggleFieldComponent {
@@ -1381,22 +1348,47 @@ class MatToggleFieldComponent {
1381
1348
  return this.field()().required?.() === true ? true : null;
1382
1349
  }, ...(ngDevMode ? [{ debugName: "ariaRequired" }] : []));
1383
1350
  /** aria-describedby: links to hint and error messages for screen readers */
1384
- ariaDescribedBy = computed(() => {
1385
- const ids = [];
1386
- if (this.props()?.hint) {
1387
- ids.push(this.hintId());
1351
+ ariaDescribedBy = createAriaDescribedBySignal(this.errorsToDisplay, this.errorId, this.hintId, () => !!this.props()?.hint);
1352
+ /**
1353
+ * Workaround: Angular Material's MatSlideToggle does NOT propagate aria-required to its internal
1354
+ * button element. This effect imperatively sets/removes aria-required on the internal button.
1355
+ *
1356
+ * Uses afterRenderEffect to ensure DOM is ready before querying internal elements.
1357
+ */
1358
+ syncAriaRequiredToDom = afterRenderEffect(() => {
1359
+ const isRequired = this.ariaRequired();
1360
+ const buttonEl = this.elementRef.nativeElement.querySelector('button[role="switch"]');
1361
+ if (buttonEl) {
1362
+ if (isRequired) {
1363
+ buttonEl.setAttribute('aria-required', 'true');
1364
+ }
1365
+ else {
1366
+ buttonEl.removeAttribute('aria-required');
1367
+ }
1388
1368
  }
1389
- const errors = this.errorsToDisplay();
1390
- errors.forEach((_, i) => {
1391
- ids.push(`${this.errorId()}-${i}`);
1392
- });
1393
- return ids.join(' ');
1394
- }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
1395
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatToggleFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1396
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: MatToggleFieldComponent, isStandalone: true, selector: "df-mat-toggle", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
1369
+ });
1370
+ /**
1371
+ * Workaround: Angular Material's MatSlideToggle does NOT propagate aria-describedby to its internal
1372
+ * button element. This effect imperatively sets/removes aria-describedby on the internal button.
1373
+ *
1374
+ * Uses afterRenderEffect to ensure DOM is ready before querying internal elements.
1375
+ */
1376
+ syncAriaDescribedByToDom = afterRenderEffect(() => {
1377
+ const describedBy = this.ariaDescribedBy();
1378
+ const buttonEl = this.elementRef.nativeElement.querySelector('button[role="switch"]');
1379
+ if (buttonEl) {
1380
+ if (describedBy) {
1381
+ buttonEl.setAttribute('aria-describedby', describedBy);
1382
+ }
1383
+ else {
1384
+ buttonEl.removeAttribute('aria-describedby');
1385
+ }
1386
+ }
1387
+ });
1388
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatToggleFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1389
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.0", type: MatToggleFieldComponent, isStandalone: true, selector: "df-mat-toggle", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "className()", "id": "`${key()}`", "attr.data-testid": "key()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
1397
1390
  @let f = field();
1398
1391
  @let toggleId = key() + '-toggle';
1399
- @let ariaDescribedBy = this.ariaDescribedBy();
1400
1392
 
1401
1393
  <mat-slide-toggle
1402
1394
  [id]="toggleId"
@@ -1406,27 +1398,27 @@ class MatToggleFieldComponent {
1406
1398
  [hideIcon]="props()?.hideIcon || false"
1407
1399
  [disableRipple]="effectiveDisableRipple()"
1408
1400
  [required]="!!f().required()"
1409
- [aria-describedby]="ariaDescribedBy"
1401
+ [attr.aria-describedby]="ariaDescribedBy()"
1410
1402
  [attr.tabindex]="tabIndex()"
1411
1403
  class="toggle-container"
1412
1404
  >
1413
1405
  {{ label() | dynamicText | async }}
1414
1406
  </mat-slide-toggle>
1415
1407
 
1416
- @if (props()?.hint; as hint) {
1417
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1418
- }
1419
1408
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1420
1409
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
1410
+ } @empty {
1411
+ @if (props()?.hint; as hint) {
1412
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1413
+ }
1421
1414
  }
1422
1415
  `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: rgba(0, 0, 0, .6);--df-hint-font-size: .875rem;--df-error-color: #f44336;--df-error-font-size: .875rem;display:block;width:100%}:host([hidden]){display:none!important}.df-mat-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-mat-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-mat-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-mat-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}\n"], dependencies: [{ kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1423
1416
  }
1424
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: MatToggleFieldComponent, decorators: [{
1417
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.0", ngImport: i0, type: MatToggleFieldComponent, decorators: [{
1425
1418
  type: Component,
1426
1419
  args: [{ selector: 'df-mat-toggle', imports: [MatSlideToggle, FormField, MatError, DynamicTextPipe, AsyncPipe], template: `
1427
1420
  @let f = field();
1428
1421
  @let toggleId = key() + '-toggle';
1429
- @let ariaDescribedBy = this.ariaDescribedBy();
1430
1422
 
1431
1423
  <mat-slide-toggle
1432
1424
  [id]="toggleId"
@@ -1436,18 +1428,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1436
1428
  [hideIcon]="props()?.hideIcon || false"
1437
1429
  [disableRipple]="effectiveDisableRipple()"
1438
1430
  [required]="!!f().required()"
1439
- [aria-describedby]="ariaDescribedBy"
1431
+ [attr.aria-describedby]="ariaDescribedBy()"
1440
1432
  [attr.tabindex]="tabIndex()"
1441
1433
  class="toggle-container"
1442
1434
  >
1443
1435
  {{ label() | dynamicText | async }}
1444
1436
  </mat-slide-toggle>
1445
1437
 
1446
- @if (props()?.hint; as hint) {
1447
- <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1448
- }
1449
1438
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1450
1439
  <mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
1440
+ } @empty {
1441
+ @if (props()?.hint; as hint) {
1442
+ <div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
1443
+ }
1451
1444
  }
1452
1445
  `, host: {
1453
1446
  '[class]': 'className()',
@@ -1458,8 +1451,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImpor
1458
1451
  }], ctorParameters: () => [], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], placeholder: [{ type: i0.Input, args: [{ isSignal: true, alias: "placeholder", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
1459
1452
 
1460
1453
  var matToggle_component = /*#__PURE__*/Object.freeze({
1461
- __proto__: null,
1462
- default: MatToggleFieldComponent
1454
+ __proto__: null,
1455
+ default: MatToggleFieldComponent
1463
1456
  });
1464
1457
 
1465
1458
  // Public exports for material field components and types
@@ -1495,9 +1488,9 @@ const MatField = {
1495
1488
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1496
1489
  */
1497
1490
  function buttonFieldMapper(fieldDef) {
1498
- // Build base inputs (static, from field definition)
1499
- const baseInputs = buildBaseInputs(fieldDef);
1491
+ const defaultProps = inject(DEFAULT_PROPS);
1500
1492
  return computed(() => {
1493
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1501
1494
  const inputs = {
1502
1495
  ...baseInputs,
1503
1496
  };
@@ -1535,20 +1528,21 @@ function buttonFieldMapper(fieldDef) {
1535
1528
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1536
1529
  */
1537
1530
  function submitButtonFieldMapper(fieldDef) {
1538
- // Inject field signal context to access form state and options
1539
- const fieldSignalContext = inject(FIELD_SIGNAL_CONTEXT);
1540
- // Build base inputs (static, from field definition)
1541
- const baseInputs = buildBaseInputs(fieldDef);
1542
- // Use button-logic-resolver to compute disabled state
1531
+ const rootFormRegistry = inject(RootFormRegistryService);
1532
+ const defaultProps = inject(DEFAULT_PROPS);
1533
+ const formOptions = inject(FORM_OPTIONS);
1543
1534
  const fieldWithLogic = fieldDef;
1544
- const disabledSignal = resolveSubmitButtonDisabled({
1545
- form: fieldSignalContext.form,
1546
- formOptions: fieldSignalContext.formOptions,
1547
- fieldLogic: fieldWithLogic.logic,
1548
- explicitlyDisabled: fieldDef.disabled,
1549
- });
1550
- // Return computed signal - evaluates disabledSignal inside for reactivity
1551
1535
  return computed(() => {
1536
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1537
+ // Use rootFormRegistry instead of fieldSignalContext.form because when the submit button
1538
+ // is inside a group/array, fieldSignalContext.form points to the nested form tree,
1539
+ // not the root form. We need root form validity for submit button disabled state (#157).
1540
+ const disabledSignal = resolveSubmitButtonDisabled({
1541
+ form: rootFormRegistry.getRootForm(),
1542
+ formOptions: formOptions(),
1543
+ fieldLogic: fieldWithLogic.logic,
1544
+ explicitlyDisabled: fieldDef.disabled,
1545
+ });
1552
1546
  const inputs = {
1553
1547
  ...baseInputs,
1554
1548
  // No event - native form submit handles it via form's onNativeSubmit
@@ -1575,21 +1569,19 @@ function submitButtonFieldMapper(fieldDef) {
1575
1569
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1576
1570
  */
1577
1571
  function nextButtonFieldMapper(fieldDef) {
1578
- // Inject field signal context to access form state and options
1579
1572
  const fieldSignalContext = inject(FIELD_SIGNAL_CONTEXT);
1580
- // Build base inputs (static, from field definition)
1581
- const baseInputs = buildBaseInputs(fieldDef);
1582
- // Use button-logic-resolver to compute disabled state
1573
+ const defaultProps = inject(DEFAULT_PROPS);
1574
+ const formOptions = inject(FORM_OPTIONS);
1583
1575
  const fieldWithLogic = fieldDef;
1584
- const disabledSignal = resolveNextButtonDisabled({
1585
- form: fieldSignalContext.form,
1586
- formOptions: fieldSignalContext.formOptions,
1587
- fieldLogic: fieldWithLogic.logic,
1588
- explicitlyDisabled: fieldDef.disabled,
1589
- currentPageValid: fieldSignalContext.currentPageValid,
1590
- });
1591
- // Return computed signal - evaluates disabledSignal inside for reactivity
1592
1576
  return computed(() => {
1577
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1578
+ const disabledSignal = resolveNextButtonDisabled({
1579
+ form: fieldSignalContext.form,
1580
+ formOptions: formOptions(),
1581
+ fieldLogic: fieldWithLogic.logic,
1582
+ explicitlyDisabled: fieldDef.disabled,
1583
+ currentPageValid: fieldSignalContext.currentPageValid,
1584
+ });
1593
1585
  const inputs = {
1594
1586
  ...baseInputs,
1595
1587
  event: NextPageEvent,
@@ -1610,9 +1602,9 @@ function nextButtonFieldMapper(fieldDef) {
1610
1602
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1611
1603
  */
1612
1604
  function previousButtonFieldMapper(fieldDef) {
1613
- // Build base inputs (static, from field definition)
1614
- const baseInputs = buildBaseInputs(fieldDef);
1605
+ const defaultProps = inject(DEFAULT_PROPS);
1615
1606
  return computed(() => {
1607
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1616
1608
  const inputs = {
1617
1609
  ...baseInputs,
1618
1610
  event: PreviousPageEvent,
@@ -1638,10 +1630,9 @@ function previousButtonFieldMapper(fieldDef) {
1638
1630
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1639
1631
  */
1640
1632
  function addArrayItemButtonFieldMapper(fieldDef) {
1641
- // Try to get array context (available when inside an array)
1642
- // Use optional injection so it doesn't fail when outside an array
1643
1633
  const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
1644
1634
  const logger = inject(DynamicFormLogger);
1635
+ const defaultProps = inject(DEFAULT_PROPS);
1645
1636
  // Determine the target array key
1646
1637
  // Priority: explicit arrayKey from fieldDef > arrayKey from context
1647
1638
  const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
@@ -1649,13 +1640,12 @@ function addArrayItemButtonFieldMapper(fieldDef) {
1649
1640
  logger.warn(`addArrayItem button "${fieldDef.key}" has no array context. ` +
1650
1641
  'Either place it inside an array field, or provide an explicit arrayKey property.');
1651
1642
  }
1652
- // Build base inputs (static, from field definition)
1653
- const baseInputs = buildBaseInputs(fieldDef);
1654
1643
  // Set default eventArgs for AddArrayItemEvent (arrayKey)
1655
1644
  // User can override by providing eventArgs in field definition
1656
1645
  const defaultEventArgs = ['$arrayKey'];
1657
1646
  const eventArgs = 'eventArgs' in fieldDef && fieldDef.eventArgs !== undefined ? fieldDef.eventArgs : defaultEventArgs;
1658
1647
  return computed(() => {
1648
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1659
1649
  // Read signal value if index is a signal (supports differential updates)
1660
1650
  const getIndex = () => {
1661
1651
  if (!arrayContext)
@@ -1694,10 +1684,9 @@ function addArrayItemButtonFieldMapper(fieldDef) {
1694
1684
  * @returns Signal containing Record of input names to values for ngComponentOutlet
1695
1685
  */
1696
1686
  function removeArrayItemButtonFieldMapper(fieldDef) {
1697
- // Try to get array context (available when inside an array)
1698
- // Use optional injection so it doesn't fail when outside an array
1699
1687
  const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
1700
1688
  const logger = inject(DynamicFormLogger);
1689
+ const defaultProps = inject(DEFAULT_PROPS);
1701
1690
  // Determine the target array key
1702
1691
  // Priority: explicit arrayKey from fieldDef > arrayKey from context
1703
1692
  const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
@@ -1705,14 +1694,13 @@ function removeArrayItemButtonFieldMapper(fieldDef) {
1705
1694
  logger.warn(`removeArrayItem button "${fieldDef.key}" has no array context. ` +
1706
1695
  'Either place it inside an array field, or provide an explicit arrayKey property.');
1707
1696
  }
1708
- // Build base inputs (static, from field definition)
1709
- const baseInputs = buildBaseInputs(fieldDef);
1710
1697
  // Set default eventArgs for RemoveArrayItemEvent (arrayKey, index if inside array)
1711
1698
  // When outside array, only pass arrayKey (removes last by default)
1712
1699
  // User can override by providing eventArgs in field definition
1713
1700
  const defaultEventArgs = arrayContext ? ['$arrayKey', '$index'] : ['$arrayKey'];
1714
1701
  const eventArgs = 'eventArgs' in fieldDef && fieldDef.eventArgs !== undefined ? fieldDef.eventArgs : defaultEventArgs;
1715
1702
  return computed(() => {
1703
+ const baseInputs = buildBaseInputs(fieldDef, defaultProps());
1716
1704
  // Read signal value if index is a signal (supports differential updates)
1717
1705
  const getIndex = () => {
1718
1706
  if (!arrayContext)