@ng-forge/dynamic-forms-ionic 0.1.3 → 0.3.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,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, input, computed, ChangeDetectionStrategy, Component, signal, InjectionToken, Pipe, linkedSignal, model, isSignal } from '@angular/core';
2
+ import { inject, input, computed, ChangeDetectionStrategy, Component, ElementRef, signal, InjectionToken, linkedSignal, model, isSignal } from '@angular/core';
3
3
  import { IonButton, IonCheckbox, IonNote, IonInput, IonModal, IonDatetime, IonButtons, IonHeader, IonContent, IonToolbar, IonTitle, IonItem, IonRadioGroup, IonRadio, IonSelect, IonSelectOption, IonRange, IonTextarea, IonToggle } from '@ionic/angular/standalone';
4
- import { EventBus, ARRAY_CONTEXT, resolveTokens, DynamicTextPipe, buildBaseInputs, FIELD_SIGNAL_CONTEXT, resolveSubmitButtonDisabled, resolveNextButtonDisabled, NextPageEvent, PreviousPageEvent, DYNAMIC_FORM_LOGGER, AddArrayItemEvent, RemoveArrayItemEvent } from '@ng-forge/dynamic-forms';
4
+ import { EventBus, ARRAY_CONTEXT, resolveTokens, DynamicTextPipe, buildBaseInputs, FIELD_SIGNAL_CONTEXT, resolveSubmitButtonDisabled, resolveNextButtonDisabled, NextPageEvent, PreviousPageEvent, DynamicFormLogger, AddArrayItemEvent, RemoveArrayItemEvent } from '@ng-forge/dynamic-forms';
5
5
  import { AsyncPipe } from '@angular/common';
6
- import { Field } from '@angular/forms/signals';
7
- import { createResolvedErrorsSignal, shouldShowErrors, valueFieldMapper, optionsFieldMapper, checkboxFieldMapper, datepickerFieldMapper } from '@ng-forge/dynamic-forms/integration';
6
+ import { FormField } from '@angular/forms/signals';
7
+ import { createResolvedErrorsSignal, shouldShowErrors, setupMetaTracking, isEqual, ValueInArrayPipe, valueFieldMapper, optionsFieldMapper, checkboxFieldMapper, datepickerFieldMapper } from '@ng-forge/dynamic-forms/integration';
8
8
  import { format } from 'date-fns';
9
9
  import { explicitEffect } from 'ngxtension/explicit-effect';
10
10
 
@@ -64,8 +64,8 @@ class IonicButtonFieldComponent {
64
64
  this.eventBus.dispatch(event);
65
65
  }
66
66
  }
67
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicButtonFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
68
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.5", type: IonicButtonFieldComponent, isStandalone: true, selector: "df-ionic-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()" } }, ngImport: i0, template: `
67
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicButtonFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
68
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: IonicButtonFieldComponent, isStandalone: true, selector: "df-ion-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()" } }, ngImport: i0, template: `
69
69
  <ion-button
70
70
  [type]="buttonType()"
71
71
  [expand]="props()?.expand"
@@ -83,10 +83,10 @@ class IonicButtonFieldComponent {
83
83
  </ion-button>
84
84
  `, isInline: true, dependencies: [{ kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
85
85
  }
86
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicButtonFieldComponent, decorators: [{
86
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicButtonFieldComponent, decorators: [{
87
87
  type: Component,
88
88
  args: [{
89
- selector: 'df-ionic-button',
89
+ selector: 'df-ion-button',
90
90
  imports: [IonButton, DynamicTextPipe, AsyncPipe],
91
91
  host: {
92
92
  '[id]': '`${key()}`',
@@ -121,6 +121,7 @@ var ionicButton_component = /*#__PURE__*/Object.freeze({
121
121
  // Public API - component
122
122
 
123
123
  class IonicCheckboxFieldComponent {
124
+ elementRef = inject((ElementRef));
124
125
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
125
126
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
126
127
  // Properties
@@ -129,11 +130,18 @@ class IonicCheckboxFieldComponent {
129
130
  className = input('', ...(ngDevMode ? [{ debugName: "className" }] : []));
130
131
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
131
132
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
133
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
132
134
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
133
135
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
134
136
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
135
137
  showErrors = shouldShowErrors(this.field);
136
138
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
139
+ constructor() {
140
+ // Shadow DOM - apply meta to ion-checkbox element
141
+ setupMetaTracking(this.elementRef, this.meta, {
142
+ selector: 'ion-checkbox',
143
+ });
144
+ }
137
145
  // ─────────────────────────────────────────────────────────────────────────────
138
146
  // Accessibility
139
147
  // ─────────────────────────────────────────────────────────────────────────────
@@ -148,12 +156,12 @@ class IonicCheckboxFieldComponent {
148
156
  isRequired = computed(() => {
149
157
  return this.field()().required?.() === true;
150
158
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
151
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
152
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicCheckboxFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
159
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
160
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicCheckboxFieldComponent, isStandalone: true, selector: "df-ion-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: `
153
161
  @let f = field();
154
162
 
155
163
  <ion-checkbox
156
- [field]="f"
164
+ [formField]="f"
157
165
  [labelPlacement]="props()?.labelPlacement ?? 'end'"
158
166
  [justify]="props()?.justify"
159
167
  [color]="props()?.color ?? 'primary'"
@@ -168,15 +176,15 @@ class IonicCheckboxFieldComponent {
168
176
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
169
177
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
170
178
  }
171
- `, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
179
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
172
180
  }
173
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicCheckboxFieldComponent, decorators: [{
181
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicCheckboxFieldComponent, decorators: [{
174
182
  type: Component,
175
- args: [{ selector: 'df-ionic-checkbox', imports: [IonCheckbox, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
183
+ args: [{ selector: 'df-ion-checkbox', imports: [IonCheckbox, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
176
184
  @let f = field();
177
185
 
178
186
  <ion-checkbox
179
- [field]="f"
187
+ [formField]="f"
180
188
  [labelPlacement]="props()?.labelPlacement ?? 'end'"
181
189
  [justify]="props()?.justify"
182
190
  [color]="props()?.color ?? 'primary'"
@@ -196,8 +204,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
196
204
  '[id]': '`${key()}`',
197
205
  '[attr.data-testid]': 'key()',
198
206
  '[attr.hidden]': 'field()().hidden() || null',
199
- }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
200
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
207
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"] }]
208
+ }], 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 }] }] } });
201
209
 
202
210
  var ionicCheckbox_component = /*#__PURE__*/Object.freeze({
203
211
  __proto__: null,
@@ -205,6 +213,7 @@ var ionicCheckbox_component = /*#__PURE__*/Object.freeze({
205
213
  });
206
214
 
207
215
  class IonicDatepickerFieldComponent {
216
+ elementRef = inject((ElementRef));
208
217
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
209
218
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
210
219
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
@@ -215,12 +224,19 @@ class IonicDatepickerFieldComponent {
215
224
  maxDate = input(null, ...(ngDevMode ? [{ debugName: "maxDate" }] : []));
216
225
  startAt = input(null, ...(ngDevMode ? [{ debugName: "startAt" }] : []));
217
226
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
227
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
218
228
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
219
229
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
220
230
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
221
231
  showErrors = shouldShowErrors(this.field);
222
232
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
223
233
  isModalOpen = signal(false, ...(ngDevMode ? [{ debugName: "isModalOpen" }] : []));
234
+ constructor() {
235
+ // Shadow DOM - apply meta to ion-input element
236
+ setupMetaTracking(this.elementRef, this.meta, {
237
+ selector: 'ion-input',
238
+ });
239
+ }
224
240
  // ─────────────────────────────────────────────────────────────────────────────
225
241
  // Accessibility
226
242
  // ─────────────────────────────────────────────────────────────────────────────
@@ -279,9 +295,11 @@ class IonicDatepickerFieldComponent {
279
295
  return format(date, 'MMM d, yyyy');
280
296
  }
281
297
  }
282
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicDatepickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
283
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicDatepickerFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
298
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicDatepickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
299
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicDatepickerFieldComponent, isStandalone: true, selector: "df-ion-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()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, ngImport: i0, template: `
284
300
  @let f = field(); @let dateValue = f().value();
301
+ @let ariaInvalid = isAriaInvalid();
302
+ @let ariaRequired = isRequired() || null;
285
303
 
286
304
  <ion-input
287
305
  [label]="(label() | dynamicText | async) ?? undefined"
@@ -292,18 +310,13 @@ class IonicDatepickerFieldComponent {
292
310
  [readonly]="true"
293
311
  [fill]="'outline'"
294
312
  [attr.tabindex]="tabIndex()"
295
- [attr.aria-invalid]="isAriaInvalid()"
296
- [attr.aria-required]="isRequired() || null"
297
- [class.ion-invalid]="f().invalid()"
298
- [class.ion-touched]="f().touched()"
313
+ [attr.aria-invalid]="ariaInvalid"
314
+ [attr.aria-required]="ariaRequired"
299
315
  (click)="!f().disabled() && openModal()"
300
- >
301
- <div slot="error">
302
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
303
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
304
- }
305
- </div>
306
- </ion-input>
316
+ />
317
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
318
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
319
+ }
307
320
 
308
321
  <ion-modal [isOpen]="isModalOpen()" (didDismiss)="closeModal()">
309
322
  <ng-template>
@@ -334,11 +347,11 @@ class IonicDatepickerFieldComponent {
334
347
  </ion-content>
335
348
  </ng-template>
336
349
  </ion-modal>
337
- `, isInline: true, styles: ["ion-input{cursor:pointer}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
350
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", "ion-input{cursor:pointer}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonModal, selector: "ion-modal" }, { kind: "component", type: IonDatetime, selector: "ion-datetime", inputs: ["cancelText", "clearText", "color", "dayValues", "disabled", "doneText", "firstDayOfWeek", "formatOptions", "highlightedDates", "hourCycle", "hourValues", "isDateEnabled", "locale", "max", "min", "minuteValues", "mode", "monthValues", "multiple", "name", "preferWheel", "presentation", "readonly", "showAdjacentDays", "showClearButton", "showDefaultButtons", "showDefaultTimeLabel", "showDefaultTitle", "size", "titleSelectedDatesFormatter", "value", "yearValues"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "component", type: IonButtons, selector: "ion-buttons", inputs: ["collapse"] }, { kind: "component", type: IonHeader, selector: "ion-header", inputs: ["collapse", "mode", "translucent"] }, { kind: "component", type: IonContent, selector: "ion-content", inputs: ["color", "fixedSlotPlacement", "forceOverscroll", "fullscreen", "scrollEvents", "scrollX", "scrollY"] }, { kind: "component", type: IonToolbar, selector: "ion-toolbar", inputs: ["color", "mode"] }, { kind: "component", type: IonTitle, selector: "ion-title", inputs: ["color", "size"] }, { kind: "component", type: IonButton, selector: "ion-button", inputs: ["buttonType", "color", "disabled", "download", "expand", "fill", "form", "href", "mode", "rel", "routerAnimation", "routerDirection", "shape", "size", "strong", "target", "type"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
338
351
  }
339
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicDatepickerFieldComponent, decorators: [{
352
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicDatepickerFieldComponent, decorators: [{
340
353
  type: Component,
341
- args: [{ selector: 'df-ionic-datepicker', imports: [
354
+ args: [{ selector: 'df-ion-datepicker', imports: [
342
355
  IonInput,
343
356
  IonModal,
344
357
  IonDatetime,
@@ -353,6 +366,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
353
366
  AsyncPipe,
354
367
  ], template: `
355
368
  @let f = field(); @let dateValue = f().value();
369
+ @let ariaInvalid = isAriaInvalid();
370
+ @let ariaRequired = isRequired() || null;
356
371
 
357
372
  <ion-input
358
373
  [label]="(label() | dynamicText | async) ?? undefined"
@@ -363,18 +378,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
363
378
  [readonly]="true"
364
379
  [fill]="'outline'"
365
380
  [attr.tabindex]="tabIndex()"
366
- [attr.aria-invalid]="isAriaInvalid()"
367
- [attr.aria-required]="isRequired() || null"
368
- [class.ion-invalid]="f().invalid()"
369
- [class.ion-touched]="f().touched()"
381
+ [attr.aria-invalid]="ariaInvalid"
382
+ [attr.aria-required]="ariaRequired"
370
383
  (click)="!f().disabled() && openModal()"
371
- >
372
- <div slot="error">
373
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
374
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
375
- }
376
- </div>
377
- </ion-input>
384
+ />
385
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
386
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
387
+ }
378
388
 
379
389
  <ion-modal [isOpen]="isModalOpen()" (didDismiss)="closeModal()">
380
390
  <ng-template>
@@ -410,8 +420,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
410
420
  '[attr.data-testid]': 'key()',
411
421
  '[class]': 'className()',
412
422
  '[attr.hidden]': 'field()().hidden() || null',
413
- }, styles: ["ion-input{cursor:pointer}:host([hidden]){display:none!important}\n"] }]
414
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
423
+ }, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", "ion-input{cursor:pointer}:host([hidden]){display:none!important}\n"] }]
424
+ }], 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 }] }] } });
415
425
 
416
426
  var ionicDatepicker_component = /*#__PURE__*/Object.freeze({
417
427
  __proto__: null,
@@ -442,6 +452,7 @@ var ionicDatepicker_component = /*#__PURE__*/Object.freeze({
442
452
  const IONIC_CONFIG = new InjectionToken('IONIC_CONFIG');
443
453
 
444
454
  class IonicInputFieldComponent {
455
+ elementRef = inject((ElementRef));
445
456
  ionicConfig = inject(IONIC_CONFIG, { optional: true });
446
457
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
447
458
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
@@ -450,6 +461,7 @@ class IonicInputFieldComponent {
450
461
  className = input('', ...(ngDevMode ? [{ debugName: "className" }] : []));
451
462
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
452
463
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
464
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
453
465
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
454
466
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
455
467
  effectiveFill = computed(() => this.props()?.fill ?? this.ionicConfig?.fill ?? 'solid', ...(ngDevMode ? [{ debugName: "effectiveFill" }] : []));
@@ -459,6 +471,12 @@ class IonicInputFieldComponent {
459
471
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
460
472
  showErrors = shouldShowErrors(this.field);
461
473
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
474
+ constructor() {
475
+ // Shadow DOM - apply meta to ion-input element
476
+ setupMetaTracking(this.elementRef, this.meta, {
477
+ selector: 'ion-input',
478
+ });
479
+ }
462
480
  // ─────────────────────────────────────────────────────────────────────────────
463
481
  // Accessibility
464
482
  // ─────────────────────────────────────────────────────────────────────────────
@@ -473,418 +491,76 @@ class IonicInputFieldComponent {
473
491
  isRequired = computed(() => {
474
492
  return this.field()().required?.() === true;
475
493
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
476
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
477
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicInputFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
494
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
495
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicInputFieldComponent, isStandalone: true, selector: "df-ion-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" } }, ngImport: i0, template: `
478
496
  @let f = field();
479
497
  @let ariaInvalid = isAriaInvalid();
480
498
  @let ariaRequired = isRequired() || null;
481
499
 
482
- @switch (props()?.type ?? 'text') {
483
- @case ('email') {
484
- <ion-input
485
- type="email"
486
- [field]="f"
487
- [label]="(label() | dynamicText | async) ?? undefined"
488
- [labelPlacement]="effectiveLabelPlacement()"
489
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
490
- [clearInput]="props()?.clearInput ?? false"
491
- [counter]="props()?.counter ?? false"
492
- [color]="effectiveColor()"
493
- [fill]="effectiveFill()"
494
- [shape]="effectiveShape()"
495
- [readonly]="f().readonly()"
496
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
497
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
498
- [attr.tabindex]="tabIndex()"
499
- [attr.aria-invalid]="ariaInvalid"
500
- [attr.aria-required]="ariaRequired"
501
- [class.ion-invalid]="f().invalid()"
502
- [class.ion-touched]="f().touched()"
503
- >
504
- <div slot="error">
505
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
506
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
507
- }
508
- </div>
509
- </ion-input>
510
- }
511
- @case ('password') {
512
- <ion-input
513
- type="password"
514
- [field]="f"
515
- [label]="(label() | dynamicText | async) ?? undefined"
516
- [labelPlacement]="effectiveLabelPlacement()"
517
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
518
- [clearInput]="props()?.clearInput ?? false"
519
- [counter]="props()?.counter ?? false"
520
- [color]="effectiveColor()"
521
- [fill]="effectiveFill()"
522
- [shape]="effectiveShape()"
523
- [readonly]="f().readonly()"
524
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
525
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
526
- [attr.tabindex]="tabIndex()"
527
- [attr.aria-invalid]="ariaInvalid"
528
- [attr.aria-required]="ariaRequired"
529
- [class.ion-invalid]="f().invalid()"
530
- [class.ion-touched]="f().touched()"
531
- >
532
- <div slot="error">
533
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
534
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
535
- }
536
- </div>
537
- </ion-input>
538
- }
539
- @case ('number') {
540
- <ion-input
541
- type="number"
542
- [field]="f"
543
- [label]="(label() | dynamicText | async) ?? undefined"
544
- [labelPlacement]="effectiveLabelPlacement()"
545
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
546
- [clearInput]="props()?.clearInput ?? false"
547
- [counter]="props()?.counter ?? false"
548
- [color]="effectiveColor()"
549
- [fill]="effectiveFill()"
550
- [shape]="effectiveShape()"
551
- [readonly]="f().readonly()"
552
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
553
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
554
- [attr.tabindex]="tabIndex()"
555
- [attr.aria-invalid]="ariaInvalid"
556
- [attr.aria-required]="ariaRequired"
557
- [class.ion-invalid]="f().invalid()"
558
- [class.ion-touched]="f().touched()"
559
- >
560
- <div slot="error">
561
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
562
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
563
- }
564
- </div>
565
- </ion-input>
566
- }
567
- @case ('tel') {
568
- <ion-input
569
- type="tel"
570
- [field]="f"
571
- [label]="(label() | dynamicText | async) ?? undefined"
572
- [labelPlacement]="effectiveLabelPlacement()"
573
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
574
- [clearInput]="props()?.clearInput ?? false"
575
- [counter]="props()?.counter ?? false"
576
- [color]="effectiveColor()"
577
- [fill]="effectiveFill()"
578
- [shape]="effectiveShape()"
579
- [readonly]="f().readonly()"
580
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
581
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
582
- [attr.tabindex]="tabIndex()"
583
- [attr.aria-invalid]="ariaInvalid"
584
- [attr.aria-required]="ariaRequired"
585
- [class.ion-invalid]="f().invalid()"
586
- [class.ion-touched]="f().touched()"
587
- >
588
- <div slot="error">
589
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
590
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
591
- }
592
- </div>
593
- </ion-input>
594
- }
595
- @case ('url') {
596
- <ion-input
597
- type="url"
598
- [field]="f"
599
- [label]="(label() | dynamicText | async) ?? undefined"
600
- [labelPlacement]="effectiveLabelPlacement()"
601
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
602
- [clearInput]="props()?.clearInput ?? false"
603
- [counter]="props()?.counter ?? false"
604
- [color]="effectiveColor()"
605
- [fill]="effectiveFill()"
606
- [shape]="effectiveShape()"
607
- [readonly]="f().readonly()"
608
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
609
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
610
- [attr.tabindex]="tabIndex()"
611
- [attr.aria-invalid]="ariaInvalid"
612
- [attr.aria-required]="ariaRequired"
613
- [class.ion-invalid]="f().invalid()"
614
- [class.ion-touched]="f().touched()"
615
- >
616
- <div slot="error">
617
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
618
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
619
- }
620
- </div>
621
- </ion-input>
622
- }
623
- @default {
624
- <ion-input
625
- type="text"
626
- [field]="f"
627
- [label]="(label() | dynamicText | async) ?? undefined"
628
- [labelPlacement]="effectiveLabelPlacement()"
629
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
630
- [clearInput]="props()?.clearInput ?? false"
631
- [counter]="props()?.counter ?? false"
632
- [color]="effectiveColor()"
633
- [fill]="effectiveFill()"
634
- [shape]="effectiveShape()"
635
- [readonly]="f().readonly()"
636
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
637
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
638
- [attr.tabindex]="tabIndex()"
639
- [attr.aria-invalid]="ariaInvalid"
640
- [attr.aria-required]="ariaRequired"
641
- [class.ion-invalid]="f().invalid()"
642
- [class.ion-touched]="f().touched()"
643
- >
644
- <div slot="error">
645
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
646
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
647
- }
648
- </div>
649
- </ion-input>
650
- }
500
+ <ion-input
501
+ [type]="props()?.type ?? 'text'"
502
+ [formField]="f"
503
+ [label]="(label() | dynamicText | async) ?? undefined"
504
+ [labelPlacement]="effectiveLabelPlacement()"
505
+ [placeholder]="(placeholder() | dynamicText | async) ?? ''"
506
+ [clearInput]="props()?.clearInput ?? false"
507
+ [counter]="props()?.counter ?? false"
508
+ [color]="effectiveColor()"
509
+ [fill]="effectiveFill()"
510
+ [shape]="effectiveShape()"
511
+ [readonly]="f().readonly()"
512
+ [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
513
+ [attr.tabindex]="tabIndex()"
514
+ [attr.aria-invalid]="ariaInvalid"
515
+ [attr.aria-required]="ariaRequired"
516
+ />
517
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
518
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
651
519
  }
652
- `, isInline: true, styles: [":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
520
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonInput, selector: "ion-input", inputs: ["accept", "autocapitalize", "autocomplete", "autocorrect", "autofocus", "clearInput", "clearOnEdit", "color", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "max", "maxlength", "min", "minlength", "mode", "multiple", "name", "pattern", "placeholder", "readonly", "required", "shape", "size", "spellcheck", "step", "type", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
653
521
  }
654
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicInputFieldComponent, decorators: [{
522
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicInputFieldComponent, decorators: [{
655
523
  type: Component,
656
- args: [{ selector: 'df-ionic-input', imports: [IonInput, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
524
+ args: [{ selector: 'df-ion-input', imports: [IonInput, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
657
525
  @let f = field();
658
526
  @let ariaInvalid = isAriaInvalid();
659
527
  @let ariaRequired = isRequired() || null;
660
528
 
661
- @switch (props()?.type ?? 'text') {
662
- @case ('email') {
663
- <ion-input
664
- type="email"
665
- [field]="f"
666
- [label]="(label() | dynamicText | async) ?? undefined"
667
- [labelPlacement]="effectiveLabelPlacement()"
668
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
669
- [clearInput]="props()?.clearInput ?? false"
670
- [counter]="props()?.counter ?? false"
671
- [color]="effectiveColor()"
672
- [fill]="effectiveFill()"
673
- [shape]="effectiveShape()"
674
- [readonly]="f().readonly()"
675
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
676
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
677
- [attr.tabindex]="tabIndex()"
678
- [attr.aria-invalid]="ariaInvalid"
679
- [attr.aria-required]="ariaRequired"
680
- [class.ion-invalid]="f().invalid()"
681
- [class.ion-touched]="f().touched()"
682
- >
683
- <div slot="error">
684
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
685
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
686
- }
687
- </div>
688
- </ion-input>
689
- }
690
- @case ('password') {
691
- <ion-input
692
- type="password"
693
- [field]="f"
694
- [label]="(label() | dynamicText | async) ?? undefined"
695
- [labelPlacement]="effectiveLabelPlacement()"
696
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
697
- [clearInput]="props()?.clearInput ?? false"
698
- [counter]="props()?.counter ?? false"
699
- [color]="effectiveColor()"
700
- [fill]="effectiveFill()"
701
- [shape]="effectiveShape()"
702
- [readonly]="f().readonly()"
703
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
704
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
705
- [attr.tabindex]="tabIndex()"
706
- [attr.aria-invalid]="ariaInvalid"
707
- [attr.aria-required]="ariaRequired"
708
- [class.ion-invalid]="f().invalid()"
709
- [class.ion-touched]="f().touched()"
710
- >
711
- <div slot="error">
712
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
713
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
714
- }
715
- </div>
716
- </ion-input>
717
- }
718
- @case ('number') {
719
- <ion-input
720
- type="number"
721
- [field]="f"
722
- [label]="(label() | dynamicText | async) ?? undefined"
723
- [labelPlacement]="effectiveLabelPlacement()"
724
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
725
- [clearInput]="props()?.clearInput ?? false"
726
- [counter]="props()?.counter ?? false"
727
- [color]="effectiveColor()"
728
- [fill]="effectiveFill()"
729
- [shape]="effectiveShape()"
730
- [readonly]="f().readonly()"
731
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
732
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
733
- [attr.tabindex]="tabIndex()"
734
- [attr.aria-invalid]="ariaInvalid"
735
- [attr.aria-required]="ariaRequired"
736
- [class.ion-invalid]="f().invalid()"
737
- [class.ion-touched]="f().touched()"
738
- >
739
- <div slot="error">
740
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
741
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
742
- }
743
- </div>
744
- </ion-input>
745
- }
746
- @case ('tel') {
747
- <ion-input
748
- type="tel"
749
- [field]="f"
750
- [label]="(label() | dynamicText | async) ?? undefined"
751
- [labelPlacement]="effectiveLabelPlacement()"
752
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
753
- [clearInput]="props()?.clearInput ?? false"
754
- [counter]="props()?.counter ?? false"
755
- [color]="effectiveColor()"
756
- [fill]="effectiveFill()"
757
- [shape]="effectiveShape()"
758
- [readonly]="f().readonly()"
759
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
760
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
761
- [attr.tabindex]="tabIndex()"
762
- [attr.aria-invalid]="ariaInvalid"
763
- [attr.aria-required]="ariaRequired"
764
- [class.ion-invalid]="f().invalid()"
765
- [class.ion-touched]="f().touched()"
766
- >
767
- <div slot="error">
768
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
769
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
770
- }
771
- </div>
772
- </ion-input>
773
- }
774
- @case ('url') {
775
- <ion-input
776
- type="url"
777
- [field]="f"
778
- [label]="(label() | dynamicText | async) ?? undefined"
779
- [labelPlacement]="effectiveLabelPlacement()"
780
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
781
- [clearInput]="props()?.clearInput ?? false"
782
- [counter]="props()?.counter ?? false"
783
- [color]="effectiveColor()"
784
- [fill]="effectiveFill()"
785
- [shape]="effectiveShape()"
786
- [readonly]="f().readonly()"
787
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
788
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
789
- [attr.tabindex]="tabIndex()"
790
- [attr.aria-invalid]="ariaInvalid"
791
- [attr.aria-required]="ariaRequired"
792
- [class.ion-invalid]="f().invalid()"
793
- [class.ion-touched]="f().touched()"
794
- >
795
- <div slot="error">
796
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
797
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
798
- }
799
- </div>
800
- </ion-input>
801
- }
802
- @default {
803
- <ion-input
804
- type="text"
805
- [field]="f"
806
- [label]="(label() | dynamicText | async) ?? undefined"
807
- [labelPlacement]="effectiveLabelPlacement()"
808
- [placeholder]="(placeholder() | dynamicText | async) ?? ''"
809
- [clearInput]="props()?.clearInput ?? false"
810
- [counter]="props()?.counter ?? false"
811
- [color]="effectiveColor()"
812
- [fill]="effectiveFill()"
813
- [shape]="effectiveShape()"
814
- [readonly]="f().readonly()"
815
- [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
816
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
817
- [attr.tabindex]="tabIndex()"
818
- [attr.aria-invalid]="ariaInvalid"
819
- [attr.aria-required]="ariaRequired"
820
- [class.ion-invalid]="f().invalid()"
821
- [class.ion-touched]="f().touched()"
822
- >
823
- <div slot="error">
824
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
825
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
826
- }
827
- </div>
828
- </ion-input>
829
- }
529
+ <ion-input
530
+ [type]="props()?.type ?? 'text'"
531
+ [formField]="f"
532
+ [label]="(label() | dynamicText | async) ?? undefined"
533
+ [labelPlacement]="effectiveLabelPlacement()"
534
+ [placeholder]="(placeholder() | dynamicText | async) ?? ''"
535
+ [clearInput]="props()?.clearInput ?? false"
536
+ [counter]="props()?.counter ?? false"
537
+ [color]="effectiveColor()"
538
+ [fill]="effectiveFill()"
539
+ [shape]="effectiveShape()"
540
+ [readonly]="f().readonly()"
541
+ [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
542
+ [attr.tabindex]="tabIndex()"
543
+ [attr.aria-invalid]="ariaInvalid"
544
+ [attr.aria-required]="ariaRequired"
545
+ />
546
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
547
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
830
548
  }
831
549
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
832
550
  '[id]': '`${key()}`',
833
551
  '[attr.data-testid]': 'key()',
834
552
  '[class]': 'className()',
835
553
  '[attr.hidden]': 'field()().hidden() || null',
836
- }, styles: [":host([hidden]){display:none!important}\n"] }]
837
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
554
+ }, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"] }]
555
+ }], 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 }] }] } });
838
556
 
839
557
  var ionicInput_component = /*#__PURE__*/Object.freeze({
840
558
  __proto__: null,
841
559
  default: IonicInputFieldComponent
842
560
  });
843
561
 
844
- class ValueInArrayPipe {
845
- transform(element, array) {
846
- return array?.includes(element) ?? false;
847
- }
848
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: ValueInArrayPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
849
- static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.5", ngImport: i0, type: ValueInArrayPipe, isStandalone: true, name: "inArray" });
850
- }
851
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: ValueInArrayPipe, decorators: [{
852
- type: Pipe,
853
- args: [{
854
- pure: true,
855
- name: 'inArray',
856
- }]
857
- }] });
858
-
859
- /**
860
- * Performs a deep equality comparison between two values
861
- */
862
- function isEqual(a, b) {
863
- if (a === b)
864
- return true;
865
- if (a == null || b == null)
866
- return false;
867
- if (typeof a !== typeof b)
868
- return false;
869
- if (a instanceof Date && b instanceof Date) {
870
- return a.getTime() === b.getTime();
871
- }
872
- if (Array.isArray(a) && Array.isArray(b)) {
873
- if (a.length !== b.length)
874
- return false;
875
- return a.every((item, index) => isEqual(item, b[index]));
876
- }
877
- if (typeof a === 'object' && typeof b === 'object') {
878
- const keysA = Object.keys(a);
879
- const keysB = Object.keys(b);
880
- if (keysA.length !== keysB.length)
881
- return false;
882
- return keysA.every((key) => keysB.includes(key) && isEqual(a[key], b[key]));
883
- }
884
- return Object.is(a, b);
885
- }
886
-
887
562
  class IonicMultiCheckboxFieldComponent {
563
+ elementRef = inject((ElementRef));
888
564
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
889
565
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
890
566
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
@@ -893,6 +569,7 @@ class IonicMultiCheckboxFieldComponent {
893
569
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
894
570
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
895
571
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
572
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
896
573
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
897
574
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
898
575
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
@@ -917,6 +594,11 @@ class IonicMultiCheckboxFieldComponent {
917
594
  return this.options().filter((option) => currentValues.includes(option.value));
918
595
  }, { ...(ngDevMode ? { debugName: "valueViewModel" } : {}), equal: isEqual });
919
596
  constructor() {
597
+ // Shadow DOM - apply meta to ion-checkbox elements, re-apply when options change
598
+ setupMetaTracking(this.elementRef, this.meta, {
599
+ selector: 'ion-checkbox',
600
+ dependents: [this.options],
601
+ });
920
602
  explicitEffect([this.valueViewModel], ([selectedOptions]) => {
921
603
  const selectedValues = selectedOptions.map((option) => option.value);
922
604
  if (!isEqual(selectedValues, this.field()().value())) {
@@ -942,14 +624,21 @@ class IonicMultiCheckboxFieldComponent {
942
624
  }
943
625
  });
944
626
  }
945
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicMultiCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
946
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicMultiCheckboxFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
627
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicMultiCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
628
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicMultiCheckboxFieldComponent, isStandalone: true, selector: "df-ion-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: `
947
629
  @let f = field();
948
630
  @if (label(); as label) {
949
631
  <div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
950
632
  }
951
633
 
952
- <div class="checkbox-group" role="group" [attr.aria-invalid]="isAriaInvalid()" [attr.aria-required]="isRequired() || null">
634
+ <div
635
+ class="checkbox-group"
636
+ role="group"
637
+ [attr.aria-invalid]="isAriaInvalid()"
638
+ [attr.aria-required]="isRequired() || null"
639
+ [class.ion-invalid]="showErrors()"
640
+ [class.ion-touched]="field()().touched()"
641
+ >
953
642
  @for (option of options(); track option.value) {
954
643
  <ion-item lines="none">
955
644
  <ion-checkbox
@@ -969,17 +658,24 @@ class IonicMultiCheckboxFieldComponent {
969
658
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
970
659
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
971
660
  }
972
- `, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}.checkbox-group-label{margin-bottom:8px;font-weight:500}.checkbox-group{display:flex;flex-direction:column;gap:4px}ion-item{--padding-start: 0;--inner-padding-end: 0}\n"], dependencies: [{ kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "pipe", type: ValueInArrayPipe, name: "inArray" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
661
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}.checkbox-group-label{margin-bottom:8px;font-weight:500}.checkbox-group{display:flex;flex-direction:column;gap:4px}ion-item{--padding-start: 0;--inner-padding-end: 0}\n"], dependencies: [{ kind: "component", type: IonCheckbox, selector: "ion-checkbox", inputs: ["checked", "color", "disabled", "errorText", "helperText", "indeterminate", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "pipe", type: ValueInArrayPipe, name: "inArray" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
973
662
  }
974
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicMultiCheckboxFieldComponent, decorators: [{
663
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicMultiCheckboxFieldComponent, decorators: [{
975
664
  type: Component,
976
- args: [{ selector: 'df-ionic-multi-checkbox', imports: [IonCheckbox, IonItem, IonNote, ValueInArrayPipe, DynamicTextPipe, AsyncPipe], template: `
665
+ args: [{ selector: 'df-ion-multi-checkbox', imports: [IonCheckbox, IonItem, IonNote, ValueInArrayPipe, DynamicTextPipe, AsyncPipe], template: `
977
666
  @let f = field();
978
667
  @if (label(); as label) {
979
668
  <div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
980
669
  }
981
670
 
982
- <div class="checkbox-group" role="group" [attr.aria-invalid]="isAriaInvalid()" [attr.aria-required]="isRequired() || null">
671
+ <div
672
+ class="checkbox-group"
673
+ role="group"
674
+ [attr.aria-invalid]="isAriaInvalid()"
675
+ [attr.aria-required]="isRequired() || null"
676
+ [class.ion-invalid]="showErrors()"
677
+ [class.ion-touched]="field()().touched()"
678
+ >
983
679
  @for (option of options(); track option.value) {
984
680
  <ion-item lines="none">
985
681
  <ion-checkbox
@@ -1004,8 +700,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1004
700
  '[id]': '`${key()}`',
1005
701
  '[attr.data-testid]': 'key()',
1006
702
  '[attr.hidden]': 'field()().hidden() || null',
1007
- }, providers: [ValueInArrayPipe], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}.checkbox-group-label{margin-bottom:8px;font-weight:500}.checkbox-group{display:flex;flex-direction:column;gap:4px}ion-item{--padding-start: 0;--inner-padding-end: 0}\n"] }]
1008
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
703
+ }, providers: [ValueInArrayPipe], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}.checkbox-group-label{margin-bottom:8px;font-weight:500}.checkbox-group{display:flex;flex-direction:column;gap:4px}ion-item{--padding-start: 0;--inner-padding-end: 0}\n"] }]
704
+ }], 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 }] }] } });
1009
705
 
1010
706
  var ionicMultiCheckbox_component = /*#__PURE__*/Object.freeze({
1011
707
  __proto__: null,
@@ -1013,6 +709,7 @@ var ionicMultiCheckbox_component = /*#__PURE__*/Object.freeze({
1013
709
  });
1014
710
 
1015
711
  class IonicRadioFieldComponent {
712
+ elementRef = inject((ElementRef));
1016
713
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
1017
714
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
1018
715
  // Properties
@@ -1022,12 +719,20 @@ class IonicRadioFieldComponent {
1022
719
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
1023
720
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
1024
721
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
722
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1025
723
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
1026
724
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
1027
725
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
1028
726
  showErrors = shouldShowErrors(this.field);
1029
727
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
1030
728
  defaultCompare = Object.is;
729
+ constructor() {
730
+ // Shadow DOM - apply meta to ion-radio elements, re-apply when options change
731
+ setupMetaTracking(this.elementRef, this.meta, {
732
+ selector: 'ion-radio',
733
+ dependents: [this.options],
734
+ });
735
+ }
1031
736
  // ─────────────────────────────────────────────────────────────────────────────
1032
737
  // Accessibility
1033
738
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1042,15 +747,15 @@ class IonicRadioFieldComponent {
1042
747
  isRequired = computed(() => {
1043
748
  return this.field()().required?.() === true;
1044
749
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
1045
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicRadioFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1046
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicRadioFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
750
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicRadioFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
751
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicRadioFieldComponent, isStandalone: true, selector: "df-ion-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: `
1047
752
  @let f = field();
1048
753
  @if (label(); as label) {
1049
754
  <div class="radio-label">{{ label | dynamicText | async }}</div>
1050
755
  }
1051
756
 
1052
757
  <ion-radio-group
1053
- [field]="f"
758
+ [formField]="f"
1054
759
  [compareWith]="props()?.compareWith || defaultCompare"
1055
760
  [attr.aria-invalid]="isAriaInvalid()"
1056
761
  [attr.aria-required]="isRequired() || null"
@@ -1073,18 +778,18 @@ class IonicRadioFieldComponent {
1073
778
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1074
779
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1075
780
  }
1076
- `, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}.radio-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:var(--ion-text-color)}\n"], dependencies: [{ kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
781
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}.radio-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:var(--ion-text-color)}\n"], dependencies: [{ kind: "component", type: IonRadioGroup, selector: "ion-radio-group", inputs: ["allowEmptySelection", "compareWith", "errorText", "helperText", "name", "value"] }, { kind: "component", type: IonRadio, selector: "ion-radio", inputs: ["alignment", "color", "disabled", "justify", "labelPlacement", "mode", "name", "value"] }, { kind: "component", type: IonItem, selector: "ion-item", inputs: ["button", "color", "detail", "detailIcon", "disabled", "download", "href", "lines", "mode", "rel", "routerAnimation", "routerDirection", "target", "type"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1077
782
  }
1078
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicRadioFieldComponent, decorators: [{
783
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicRadioFieldComponent, decorators: [{
1079
784
  type: Component,
1080
- args: [{ selector: 'df-ionic-radio', imports: [IonRadioGroup, IonRadio, IonItem, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
785
+ args: [{ selector: 'df-ion-radio', imports: [IonRadioGroup, IonRadio, IonItem, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
1081
786
  @let f = field();
1082
787
  @if (label(); as label) {
1083
788
  <div class="radio-label">{{ label | dynamicText | async }}</div>
1084
789
  }
1085
790
 
1086
791
  <ion-radio-group
1087
- [field]="f"
792
+ [formField]="f"
1088
793
  [compareWith]="props()?.compareWith || defaultCompare"
1089
794
  [attr.aria-invalid]="isAriaInvalid()"
1090
795
  [attr.aria-required]="isRequired() || null"
@@ -1112,8 +817,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1112
817
  '[id]': '`${key()}`',
1113
818
  '[attr.data-testid]': 'key()',
1114
819
  '[attr.hidden]': 'field()().hidden() || null',
1115
- }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}.radio-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:var(--ion-text-color)}\n"] }]
1116
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
820
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}.radio-label{font-size:.875rem;font-weight:500;margin-bottom:.5rem;color:var(--ion-text-color)}\n"] }]
821
+ }], 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 }] }] } });
1117
822
 
1118
823
  var ionicRadio_component = /*#__PURE__*/Object.freeze({
1119
824
  __proto__: null,
@@ -1121,6 +826,7 @@ var ionicRadio_component = /*#__PURE__*/Object.freeze({
1121
826
  });
1122
827
 
1123
828
  class IonicSelectFieldComponent {
829
+ elementRef = inject((ElementRef));
1124
830
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
1125
831
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
1126
832
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
@@ -1129,8 +835,12 @@ class IonicSelectFieldComponent {
1129
835
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
1130
836
  options = input([], ...(ngDevMode ? [{ debugName: "options" }] : []));
1131
837
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
838
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1132
839
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
1133
840
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
841
+ constructor() {
842
+ setupMetaTracking(this.elementRef, this.meta);
843
+ }
1134
844
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
1135
845
  showErrors = shouldShowErrors(this.field);
1136
846
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
@@ -1149,12 +859,14 @@ class IonicSelectFieldComponent {
1149
859
  isRequired = computed(() => {
1150
860
  return this.field()().required?.() === true;
1151
861
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
1152
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1153
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicSelectFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
862
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
863
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicSelectFieldComponent, isStandalone: true, selector: "df-ion-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: `
1154
864
  @let f = field();
865
+ @let ariaInvalid = isAriaInvalid();
866
+ @let ariaRequired = isRequired() || null;
1155
867
 
1156
868
  <ion-select
1157
- [field]="f"
869
+ [formField]="f"
1158
870
  [label]="(label() | dynamicText | async) ?? undefined"
1159
871
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1160
872
  [placeholder]="(placeholder() ?? props()?.placeholder | dynamicText | async) ?? ''"
@@ -1168,31 +880,29 @@ class IonicSelectFieldComponent {
1168
880
  [fill]="props()?.fill ?? 'outline'"
1169
881
  [shape]="props()?.shape"
1170
882
  [attr.tabindex]="tabIndex()"
1171
- [attr.aria-invalid]="isAriaInvalid()"
1172
- [attr.aria-required]="isRequired() || null"
1173
- [class.ion-invalid]="f().invalid()"
1174
- [class.ion-touched]="f().touched()"
883
+ [attr.aria-invalid]="ariaInvalid"
884
+ [attr.aria-required]="ariaRequired"
1175
885
  >
1176
886
  @for (option of options(); track option.value) {
1177
887
  <ion-select-option [value]="option.value" [disabled]="option.disabled || false">
1178
888
  {{ option.label | dynamicText | async }}
1179
889
  </ion-select-option>
1180
890
  }
1181
- <div slot="error">
1182
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1183
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1184
- }
1185
- </div>
1186
891
  </ion-select>
1187
- `, isInline: true, styles: [":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
892
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
893
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
894
+ }
895
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonSelect, selector: "ion-select", inputs: ["cancelText", "color", "compareWith", "disabled", "errorText", "expandedIcon", "fill", "helperText", "interface", "interfaceOptions", "justify", "label", "labelPlacement", "mode", "multiple", "name", "okText", "placeholder", "selectedText", "shape", "toggleIcon", "value"] }, { kind: "component", type: IonSelectOption, selector: "ion-select-option", inputs: ["disabled", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1188
896
  }
1189
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicSelectFieldComponent, decorators: [{
897
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicSelectFieldComponent, decorators: [{
1190
898
  type: Component,
1191
- args: [{ selector: 'df-ionic-select', imports: [IonSelect, IonSelectOption, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
899
+ args: [{ selector: 'df-ion-select', imports: [IonSelect, IonSelectOption, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
1192
900
  @let f = field();
901
+ @let ariaInvalid = isAriaInvalid();
902
+ @let ariaRequired = isRequired() || null;
1193
903
 
1194
904
  <ion-select
1195
- [field]="f"
905
+ [formField]="f"
1196
906
  [label]="(label() | dynamicText | async) ?? undefined"
1197
907
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1198
908
  [placeholder]="(placeholder() ?? props()?.placeholder | dynamicText | async) ?? ''"
@@ -1206,29 +916,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1206
916
  [fill]="props()?.fill ?? 'outline'"
1207
917
  [shape]="props()?.shape"
1208
918
  [attr.tabindex]="tabIndex()"
1209
- [attr.aria-invalid]="isAriaInvalid()"
1210
- [attr.aria-required]="isRequired() || null"
1211
- [class.ion-invalid]="f().invalid()"
1212
- [class.ion-touched]="f().touched()"
919
+ [attr.aria-invalid]="ariaInvalid"
920
+ [attr.aria-required]="ariaRequired"
1213
921
  >
1214
922
  @for (option of options(); track option.value) {
1215
923
  <ion-select-option [value]="option.value" [disabled]="option.disabled || false">
1216
924
  {{ option.label | dynamicText | async }}
1217
925
  </ion-select-option>
1218
926
  }
1219
- <div slot="error">
1220
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1221
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1222
- }
1223
- </div>
1224
927
  </ion-select>
928
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
929
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
930
+ }
1225
931
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1226
932
  '[id]': '`${key()}`',
1227
933
  '[attr.data-testid]': 'key()',
1228
934
  '[class]': 'className()',
1229
935
  '[attr.hidden]': 'field()().hidden() || null',
1230
- }, styles: [":host([hidden]){display:none!important}\n"] }]
1231
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
936
+ }, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"] }]
937
+ }], 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 }] }] } });
1232
938
 
1233
939
  var ionicSelect_component = /*#__PURE__*/Object.freeze({
1234
940
  __proto__: null,
@@ -1236,6 +942,7 @@ var ionicSelect_component = /*#__PURE__*/Object.freeze({
1236
942
  });
1237
943
 
1238
944
  class IonicSliderFieldComponent {
945
+ elementRef = inject((ElementRef));
1239
946
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
1240
947
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
1241
948
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
@@ -1243,8 +950,12 @@ class IonicSliderFieldComponent {
1243
950
  className = input('', ...(ngDevMode ? [{ debugName: "className" }] : []));
1244
951
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
1245
952
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
953
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1246
954
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
1247
955
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
956
+ constructor() {
957
+ setupMetaTracking(this.elementRef, this.meta);
958
+ }
1248
959
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
1249
960
  showErrors = shouldShowErrors(this.field);
1250
961
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
@@ -1263,12 +974,12 @@ class IonicSliderFieldComponent {
1263
974
  isRequired = computed(() => {
1264
975
  return this.field()().required?.() === true;
1265
976
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
1266
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicSliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1267
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicSliderFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
977
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicSliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
978
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicSliderFieldComponent, isStandalone: true, selector: "df-ion-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: `
1268
979
  @let f = field();
1269
980
 
1270
981
  <ion-range
1271
- [field]="f"
982
+ [formField]="f"
1272
983
  [label]="(label() | dynamicText | async) ?? undefined"
1273
984
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1274
985
  [step]="props()?.step ?? 1"
@@ -1286,15 +997,15 @@ class IonicSliderFieldComponent {
1286
997
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1287
998
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1288
999
  }
1289
- `, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonRange, selector: "ion-range", inputs: ["activeBarStart", "color", "debounce", "disabled", "dualKnobs", "label", "labelPlacement", "max", "min", "mode", "name", "pin", "pinFormatter", "snaps", "step", "ticks", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1000
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonRange, selector: "ion-range", inputs: ["activeBarStart", "color", "debounce", "disabled", "dualKnobs", "label", "labelPlacement", "max", "min", "mode", "name", "pin", "pinFormatter", "snaps", "step", "ticks", "value"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1290
1001
  }
1291
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicSliderFieldComponent, decorators: [{
1002
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicSliderFieldComponent, decorators: [{
1292
1003
  type: Component,
1293
- args: [{ selector: 'df-ionic-slider', imports: [IonRange, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
1004
+ args: [{ selector: 'df-ion-slider', imports: [IonRange, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
1294
1005
  @let f = field();
1295
1006
 
1296
1007
  <ion-range
1297
- [field]="f"
1008
+ [formField]="f"
1298
1009
  [label]="(label() | dynamicText | async) ?? undefined"
1299
1010
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1300
1011
  [step]="props()?.step ?? 1"
@@ -1317,8 +1028,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1317
1028
  '[id]': '`${key()}`',
1318
1029
  '[attr.data-testid]': 'key()',
1319
1030
  '[attr.hidden]': 'field()().hidden() || null',
1320
- }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
1321
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
1031
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"] }]
1032
+ }], 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 }] }] } });
1322
1033
 
1323
1034
  var ionicSlider_component = /*#__PURE__*/Object.freeze({
1324
1035
  __proto__: null,
@@ -1326,6 +1037,7 @@ var ionicSlider_component = /*#__PURE__*/Object.freeze({
1326
1037
  });
1327
1038
 
1328
1039
  class IonicTextareaFieldComponent {
1040
+ elementRef = inject((ElementRef));
1329
1041
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
1330
1042
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
1331
1043
  label = input(...(ngDevMode ? [undefined, { debugName: "label" }] : []));
@@ -1333,11 +1045,18 @@ class IonicTextareaFieldComponent {
1333
1045
  className = input('', ...(ngDevMode ? [{ debugName: "className" }] : []));
1334
1046
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
1335
1047
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
1048
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1336
1049
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
1337
1050
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
1338
1051
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
1339
1052
  showErrors = shouldShowErrors(this.field);
1340
1053
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
1054
+ constructor() {
1055
+ // Shadow DOM - apply meta to ion-textarea element
1056
+ setupMetaTracking(this.elementRef, this.meta, {
1057
+ selector: 'ion-textarea',
1058
+ });
1059
+ }
1341
1060
  // ─────────────────────────────────────────────────────────────────────────────
1342
1061
  // Accessibility
1343
1062
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1352,12 +1071,14 @@ class IonicTextareaFieldComponent {
1352
1071
  isRequired = computed(() => {
1353
1072
  return this.field()().required?.() === true;
1354
1073
  }, ...(ngDevMode ? [{ debugName: "isRequired" }] : []));
1355
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicTextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1356
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicTextareaFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
1074
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicTextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1075
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicTextareaFieldComponent, isStandalone: true, selector: "df-ion-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" } }, ngImport: i0, template: `
1357
1076
  @let f = field();
1077
+ @let ariaInvalid = isAriaInvalid();
1078
+ @let ariaRequired = isRequired() || null;
1358
1079
 
1359
1080
  <ion-textarea
1360
- [field]="f"
1081
+ [formField]="f"
1361
1082
  [label]="(label() | dynamicText | async) ?? undefined"
1362
1083
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1363
1084
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
@@ -1369,28 +1090,24 @@ class IonicTextareaFieldComponent {
1369
1090
  [shape]="props()?.shape"
1370
1091
  [readonly]="f().readonly()"
1371
1092
  [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
1372
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
1373
1093
  [attr.tabindex]="tabIndex()"
1374
- [attr.aria-invalid]="isAriaInvalid()"
1375
- [attr.aria-required]="isRequired() || null"
1376
- [class.ion-invalid]="f().invalid()"
1377
- [class.ion-touched]="f().touched()"
1378
- >
1379
- <div slot="error">
1380
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1381
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1382
- }
1383
- </div>
1384
- </ion-textarea>
1385
- `, isInline: true, styles: [":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1094
+ [attr.aria-invalid]="ariaInvalid"
1095
+ [attr.aria-required]="ariaRequired"
1096
+ />
1097
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1098
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1099
+ }
1100
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonTextarea, selector: "ion-textarea", inputs: ["autoGrow", "autocapitalize", "autofocus", "clearOnEdit", "color", "cols", "counter", "counterFormatter", "debounce", "disabled", "enterkeyhint", "errorText", "fill", "helperText", "inputmode", "label", "labelPlacement", "maxlength", "minlength", "mode", "name", "placeholder", "readonly", "required", "rows", "shape", "spellcheck", "value", "wrap"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1386
1101
  }
1387
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicTextareaFieldComponent, decorators: [{
1102
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicTextareaFieldComponent, decorators: [{
1388
1103
  type: Component,
1389
- args: [{ selector: 'df-ionic-textarea', imports: [IonTextarea, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
1104
+ args: [{ selector: 'df-ion-textarea', imports: [IonTextarea, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
1390
1105
  @let f = field();
1106
+ @let ariaInvalid = isAriaInvalid();
1107
+ @let ariaRequired = isRequired() || null;
1391
1108
 
1392
1109
  <ion-textarea
1393
- [field]="f"
1110
+ [formField]="f"
1394
1111
  [label]="(label() | dynamicText | async) ?? undefined"
1395
1112
  [labelPlacement]="props()?.labelPlacement ?? 'stacked'"
1396
1113
  [placeholder]="(placeholder() | dynamicText | async) ?? ''"
@@ -1402,26 +1119,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1402
1119
  [shape]="props()?.shape"
1403
1120
  [readonly]="f().readonly()"
1404
1121
  [helperText]="(props()?.helperText | dynamicText | async) ?? undefined"
1405
- [errorText]="f().invalid() && f().touched() ? ((props()?.errorText | dynamicText | async) ?? undefined) : undefined"
1406
1122
  [attr.tabindex]="tabIndex()"
1407
- [attr.aria-invalid]="isAriaInvalid()"
1408
- [attr.aria-required]="isRequired() || null"
1409
- [class.ion-invalid]="f().invalid()"
1410
- [class.ion-touched]="f().touched()"
1411
- >
1412
- <div slot="error">
1413
- @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1414
- <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1415
- }
1416
- </div>
1417
- </ion-textarea>
1123
+ [attr.aria-invalid]="ariaInvalid"
1124
+ [attr.aria-required]="ariaRequired"
1125
+ />
1126
+ @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1127
+ <ion-note color="danger" class="df-ion-error" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1128
+ }
1418
1129
  `, changeDetection: ChangeDetectionStrategy.OnPush, host: {
1419
1130
  '[id]': '`${key()}`',
1420
1131
  '[attr.data-testid]': 'key()',
1421
1132
  '[class]': 'className()',
1422
1133
  '[attr.hidden]': 'field()().hidden() || null',
1423
- }, styles: [":host([hidden]){display:none!important}\n"] }]
1424
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
1134
+ }, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host([hidden]){display:none!important}\n"] }]
1135
+ }], 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 }] }] } });
1425
1136
 
1426
1137
  var ionicTextarea_component = /*#__PURE__*/Object.freeze({
1427
1138
  __proto__: null,
@@ -1436,6 +1147,7 @@ var ionicTextarea_component = /*#__PURE__*/Object.freeze({
1436
1147
  * The Field directive binds to the `checked` model for checkbox controls.
1437
1148
  */
1438
1149
  class IonicToggleControlComponent {
1150
+ elementRef = inject((ElementRef));
1439
1151
  // ─────────────────────────────────────────────────────────────────────────────
1440
1152
  // FormCheckboxControl implementation
1441
1153
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1459,6 +1171,13 @@ class IonicToggleControlComponent {
1459
1171
  color = input('primary', ...(ngDevMode ? [{ debugName: "color" }] : []));
1460
1172
  enableOnOffLabels = input(false, ...(ngDevMode ? [{ debugName: "enableOnOffLabels" }] : []));
1461
1173
  tabIndex = input(undefined, ...(ngDevMode ? [{ debugName: "tabIndex" }] : []));
1174
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1175
+ constructor() {
1176
+ // Shadow DOM - apply meta to ion-toggle element
1177
+ setupMetaTracking(this.elementRef, this.meta, {
1178
+ selector: 'ion-toggle',
1179
+ });
1180
+ }
1462
1181
  // ─────────────────────────────────────────────────────────────────────────────
1463
1182
  // Computed ARIA attributes
1464
1183
  // ─────────────────────────────────────────────────────────────────────────────
@@ -1496,8 +1215,8 @@ class IonicToggleControlComponent {
1496
1215
  onBlur() {
1497
1216
  this.touched.set(true);
1498
1217
  }
1499
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicToggleControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1500
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.5", type: IonicToggleControlComponent, isStandalone: true, selector: "df-ionic-toggle-control", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, labelPlacement: { classPropertyName: "labelPlacement", publicName: "labelPlacement", isSignal: true, isRequired: false, transformFunction: null }, justify: { classPropertyName: "justify", publicName: "justify", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, enableOnOffLabels: { classPropertyName: "enableOnOffLabels", publicName: "enableOnOffLabels", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touched: "touchedChange" }, ngImport: i0, template: `
1218
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicToggleControlComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1219
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.8", type: IonicToggleControlComponent, isStandalone: true, selector: "df-ion-toggle-control", inputs: { checked: { classPropertyName: "checked", publicName: "checked", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, labelPlacement: { classPropertyName: "labelPlacement", publicName: "labelPlacement", isSignal: true, isRequired: false, transformFunction: null }, justify: { classPropertyName: "justify", publicName: "justify", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null }, enableOnOffLabels: { classPropertyName: "enableOnOffLabels", publicName: "enableOnOffLabels", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, meta: { classPropertyName: "meta", publicName: "meta", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { checked: "checkedChange", touched: "touchedChange" }, ngImport: i0, template: `
1501
1220
  <ion-toggle
1502
1221
  [checked]="isChecked()"
1503
1222
  (ionChange)="onToggleChange($event)"
@@ -1514,14 +1233,11 @@ class IonicToggleControlComponent {
1514
1233
  >
1515
1234
  <ng-content />
1516
1235
  </ion-toggle>
1517
- `, isInline: true, dependencies: [{ kind: "component", type: IonToggle, selector: "ion-toggle", inputs: ["checked", "color", "disabled", "enableOnOffLabels", "errorText", "helperText", "justify", "labelPlacement", "mode", "name", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1236
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n"], dependencies: [{ kind: "component", type: IonToggle, selector: "ion-toggle", inputs: ["checked", "color", "disabled", "enableOnOffLabels", "errorText", "helperText", "justify", "labelPlacement", "mode", "name", "value"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1518
1237
  }
1519
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicToggleControlComponent, decorators: [{
1238
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicToggleControlComponent, decorators: [{
1520
1239
  type: Component,
1521
- args: [{
1522
- selector: 'df-ionic-toggle-control',
1523
- imports: [IonToggle],
1524
- template: `
1240
+ args: [{ selector: 'df-ion-toggle-control', imports: [IonToggle], template: `
1525
1241
  <ion-toggle
1526
1242
  [checked]="isChecked()"
1527
1243
  (ionChange)="onToggleChange($event)"
@@ -1538,12 +1254,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1538
1254
  >
1539
1255
  <ng-content />
1540
1256
  </ion-toggle>
1541
- `,
1542
- changeDetection: ChangeDetectionStrategy.OnPush,
1543
- }]
1544
- }], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], labelPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPlacement", required: false }] }], justify: [{ type: i0.Input, args: [{ isSignal: true, alias: "justify", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], enableOnOffLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableOnOffLabels", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }] } });
1257
+ `, host: {}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n"] }]
1258
+ }], ctorParameters: () => [], propDecorators: { checked: [{ type: i0.Input, args: [{ isSignal: true, alias: "checked", required: false }] }, { type: i0.Output, args: ["checkedChange"] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], labelPlacement: [{ type: i0.Input, args: [{ isSignal: true, alias: "labelPlacement", required: false }] }], justify: [{ type: i0.Input, args: [{ isSignal: true, alias: "justify", required: false }] }], color: [{ type: i0.Input, args: [{ isSignal: true, alias: "color", required: false }] }], enableOnOffLabels: [{ type: i0.Input, args: [{ isSignal: true, alias: "enableOnOffLabels", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], meta: [{ type: i0.Input, args: [{ isSignal: true, alias: "meta", required: false }] }] } });
1545
1259
 
1546
1260
  class IonicToggleFieldComponent {
1261
+ elementRef = inject((ElementRef));
1547
1262
  field = input.required(...(ngDevMode ? [{ debugName: "field" }] : []));
1548
1263
  key = input.required(...(ngDevMode ? [{ debugName: "key" }] : []));
1549
1264
  // Properties
@@ -1552,8 +1267,12 @@ class IonicToggleFieldComponent {
1552
1267
  className = input('', ...(ngDevMode ? [{ debugName: "className" }] : []));
1553
1268
  tabIndex = input(...(ngDevMode ? [undefined, { debugName: "tabIndex" }] : []));
1554
1269
  props = input(...(ngDevMode ? [undefined, { debugName: "props" }] : []));
1270
+ meta = input(...(ngDevMode ? [undefined, { debugName: "meta" }] : []));
1555
1271
  validationMessages = input(...(ngDevMode ? [undefined, { debugName: "validationMessages" }] : []));
1556
1272
  defaultValidationMessages = input(...(ngDevMode ? [undefined, { debugName: "defaultValidationMessages" }] : []));
1273
+ constructor() {
1274
+ setupMetaTracking(this.elementRef, this.meta);
1275
+ }
1557
1276
  resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
1558
1277
  showErrors = shouldShowErrors(this.field);
1559
1278
  errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), ...(ngDevMode ? [{ debugName: "errorsToDisplay" }] : []));
@@ -1562,12 +1281,13 @@ class IonicToggleFieldComponent {
1562
1281
  // ─────────────────────────────────────────────────────────────────────────────
1563
1282
  /** Base ID for error elements */
1564
1283
  errorId = computed(() => `${this.key()}-error`, ...(ngDevMode ? [{ debugName: "errorId" }] : []));
1565
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicToggleFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1566
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.5", type: IonicToggleFieldComponent, isStandalone: true, selector: "df-ionic-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 }, 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: `
1284
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicToggleFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1285
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.8", type: IonicToggleFieldComponent, isStandalone: true, selector: "df-ion-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: `
1567
1286
  @let f = field();
1568
1287
 
1569
- <df-ionic-toggle-control
1570
- [field]="f"
1288
+ <df-ion-toggle-control
1289
+ [formField]="f"
1290
+ [meta]="meta()"
1571
1291
  [labelPlacement]="props()?.labelPlacement ?? 'end'"
1572
1292
  [justify]="props()?.justify"
1573
1293
  [color]="props()?.color ?? 'primary'"
@@ -1575,20 +1295,21 @@ class IonicToggleFieldComponent {
1575
1295
  [tabIndex]="tabIndex()"
1576
1296
  >
1577
1297
  {{ label() | dynamicText | async }}
1578
- </df-ionic-toggle-control>
1298
+ </df-ion-toggle-control>
1579
1299
 
1580
1300
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1581
1301
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
1582
1302
  }
1583
- `, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonicToggleControlComponent, selector: "df-ionic-toggle-control", inputs: ["checked", "touched", "disabled", "readonly", "invalid", "required", "labelPlacement", "justify", "color", "enableOnOffLabels", "tabIndex"], outputs: ["checkedChange", "touchedChange"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1303
+ `, isInline: true, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: IonicToggleControlComponent, selector: "df-ion-toggle-control", inputs: ["checked", "touched", "disabled", "readonly", "invalid", "required", "labelPlacement", "justify", "color", "enableOnOffLabels", "tabIndex", "meta"], outputs: ["checkedChange", "touchedChange"] }, { kind: "component", type: IonNote, selector: "ion-note", inputs: ["color", "mode"] }, { kind: "directive", type: FormField, selector: "[formField]", inputs: ["formField"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
1584
1304
  }
1585
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImport: i0, type: IonicToggleFieldComponent, decorators: [{
1305
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.8", ngImport: i0, type: IonicToggleFieldComponent, decorators: [{
1586
1306
  type: Component,
1587
- args: [{ selector: 'df-ionic-toggle', imports: [IonicToggleControlComponent, IonNote, Field, DynamicTextPipe, AsyncPipe], template: `
1307
+ args: [{ selector: 'df-ion-toggle', imports: [IonicToggleControlComponent, IonNote, FormField, DynamicTextPipe, AsyncPipe], template: `
1588
1308
  @let f = field();
1589
1309
 
1590
- <df-ionic-toggle-control
1591
- [field]="f"
1310
+ <df-ion-toggle-control
1311
+ [formField]="f"
1312
+ [meta]="meta()"
1592
1313
  [labelPlacement]="props()?.labelPlacement ?? 'end'"
1593
1314
  [justify]="props()?.justify"
1594
1315
  [color]="props()?.color ?? 'primary'"
@@ -1596,7 +1317,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1596
1317
  [tabIndex]="tabIndex()"
1597
1318
  >
1598
1319
  {{ label() | dynamicText | async }}
1599
- </df-ionic-toggle-control>
1320
+ </df-ion-toggle-control>
1600
1321
 
1601
1322
  @for (error of errorsToDisplay(); track error.kind; let i = $index) {
1602
1323
  <ion-note color="danger" [id]="errorId() + '-' + i" role="alert">{{ error.message }}</ion-note>
@@ -1606,8 +1327,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.5", ngImpor
1606
1327
  '[id]': '`${key()}`',
1607
1328
  '[attr.data-testid]': 'key()',
1608
1329
  '[attr.hidden]': 'field()().hidden() || null',
1609
- }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
1610
- }], 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 }] }], validationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "validationMessages", required: false }] }], defaultValidationMessages: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValidationMessages", required: false }] }] } });
1330
+ }, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--df-field-gap: .5rem;--df-label-font-weight: 500;--df-label-color: inherit;--df-hint-color: var(--ion-color-medium, #92949c);--df-hint-font-size: .875rem;--df-error-color: var(--ion-color-danger, #eb445a);--df-error-font-size: .875rem}.df-ion-field{display:flex;flex-direction:column;gap:var(--df-field-gap);width:100%}.df-ion-label{font-weight:var(--df-label-font-weight);color:var(--df-label-color)}.df-ion-hint{color:var(--df-hint-color);font-size:var(--df-hint-font-size)}.df-ion-error{color:var(--df-error-color);font-size:var(--df-error-font-size)}:host([hidden]){display:none!important}ion-input.ng-invalid.ng-touched,ion-textarea.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-select.ng-invalid.ng-touched{--highlight-color: var(--ion-color-danger);--border-color: var(--ion-color-danger)}ion-checkbox.ng-invalid.ng-touched{--checkbox-background-checked: var(--ion-color-danger);--border-color: var(--ion-color-danger);--border-color-checked: var(--ion-color-danger)}ion-radio.ng-invalid.ng-touched{--color: var(--ion-color-danger);--color-checked: var(--ion-color-danger)}ion-range.ng-invalid.ng-touched{--bar-background: var(--ion-color-danger);--knob-background: var(--ion-color-danger)}ion-toggle.ng-invalid.ng-touched{--track-background: var(--ion-color-danger-tint);--track-background-checked: var(--ion-color-danger);--handle-background-checked: var(--ion-color-danger-contrast)}\n", ":host{display:block}:host([hidden]){display:none!important}\n"] }]
1331
+ }], 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 }] }] } });
1611
1332
 
1612
1333
  var ionicToggle_component = /*#__PURE__*/Object.freeze({
1613
1334
  __proto__: null,
@@ -1794,7 +1515,7 @@ function addArrayItemButtonFieldMapper(fieldDef) {
1794
1515
  // Try to get array context (available when inside an array)
1795
1516
  // Use optional injection so it doesn't fail when outside an array
1796
1517
  const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
1797
- const logger = inject(DYNAMIC_FORM_LOGGER);
1518
+ const logger = inject(DynamicFormLogger);
1798
1519
  // Determine the target array key
1799
1520
  // Priority: explicit arrayKey from fieldDef > arrayKey from context
1800
1521
  const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
@@ -1850,7 +1571,7 @@ function removeArrayItemButtonFieldMapper(fieldDef) {
1850
1571
  // Try to get array context (available when inside an array)
1851
1572
  // Use optional injection so it doesn't fail when outside an array
1852
1573
  const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
1853
- const logger = inject(DYNAMIC_FORM_LOGGER);
1574
+ const logger = inject(DynamicFormLogger);
1854
1575
  // Determine the target array key
1855
1576
  // Priority: explicit arrayKey from fieldDef > arrayKey from context
1856
1577
  const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
@@ -1903,6 +1624,7 @@ const IONIC_FIELD_TYPES = [
1903
1624
  name: IonicField.Input,
1904
1625
  loadComponent: () => Promise.resolve().then(function () { return ionicInput_component; }),
1905
1626
  mapper: valueFieldMapper,
1627
+ propsToMeta: ['type'],
1906
1628
  },
1907
1629
  {
1908
1630
  name: IonicField.Select,
@@ -1954,6 +1676,7 @@ const IONIC_FIELD_TYPES = [
1954
1676
  name: IonicField.Textarea,
1955
1677
  loadComponent: () => Promise.resolve().then(function () { return ionicTextarea_component; }),
1956
1678
  mapper: valueFieldMapper,
1679
+ propsToMeta: ['rows'],
1957
1680
  },
1958
1681
  {
1959
1682
  name: IonicField.Radio,