@ng-forge/dynamic-forms-material 0.1.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.
|
@@ -0,0 +1,1978 @@
|
|
|
1
|
+
import * as i0 from '@angular/core';
|
|
2
|
+
import { InjectionToken, inject, input, ElementRef, computed, ChangeDetectionStrategy, Component, viewChild, Pipe, linkedSignal, isSignal } from '@angular/core';
|
|
3
|
+
import { Field } from '@angular/forms/signals';
|
|
4
|
+
import { MatCheckbox } from '@angular/material/checkbox';
|
|
5
|
+
import { createResolvedErrorsSignal, shouldShowErrors, DynamicTextPipe, EventBus, ARRAY_CONTEXT, resolveTokens, buildBaseInputs, FIELD_SIGNAL_CONTEXT, resolveSubmitButtonDisabled, resolveNextButtonDisabled, NextPageEvent, PreviousPageEvent, AddArrayItemEvent, RemoveArrayItemEvent, valueFieldMapper, optionsFieldMapper, checkboxFieldMapper, datepickerFieldMapper } from '@ng-forge/dynamic-forms';
|
|
6
|
+
import { MatError, MatInput, MatHint } from '@angular/material/input';
|
|
7
|
+
import { AsyncPipe } from '@angular/common';
|
|
8
|
+
import { explicitEffect } from 'ngxtension/explicit-effect';
|
|
9
|
+
import { MatFormField, MatLabel, MatSuffix, MatError as MatError$1 } from '@angular/material/form-field';
|
|
10
|
+
import { MatDatepicker, MatDatepickerInput, MatDatepickerToggle } from '@angular/material/datepicker';
|
|
11
|
+
import { provideNativeDateAdapter } from '@angular/material/core';
|
|
12
|
+
import { MatRadioGroup, MatRadioButton } from '@angular/material/radio';
|
|
13
|
+
import { MatSelect, MatOption } from '@angular/material/select';
|
|
14
|
+
import { MatSlider, MatSliderThumb } from '@angular/material/slider';
|
|
15
|
+
import { MatButton } from '@angular/material/button';
|
|
16
|
+
import { MatSlideToggle } from '@angular/material/slide-toggle';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Injection token for Material Design form configuration.
|
|
20
|
+
* Use this to provide global configuration for Material form fields.
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* import { provideDynamicForm } from '@ng-forge/dynamic-forms';
|
|
25
|
+
* import { withMaterialFields } from '@ng-forge/dynamic-forms-material';
|
|
26
|
+
*
|
|
27
|
+
* export const appConfig: ApplicationConfig = {
|
|
28
|
+
* providers: [
|
|
29
|
+
* provideDynamicForm(
|
|
30
|
+
* ...withMaterialFields({
|
|
31
|
+
* appearance: 'fill',
|
|
32
|
+
* subscriptSizing: 'fixed'
|
|
33
|
+
* })
|
|
34
|
+
* )
|
|
35
|
+
* ]
|
|
36
|
+
* };
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
const MATERIAL_CONFIG = new InjectionToken('MATERIAL_CONFIG');
|
|
40
|
+
|
|
41
|
+
class MatCheckboxFieldComponent {
|
|
42
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
43
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
44
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
45
|
+
/**
|
|
46
|
+
* Host element reference for DOM queries.
|
|
47
|
+
* Used to find the internal checkbox input for accessibility workarounds.
|
|
48
|
+
*/
|
|
49
|
+
hostEl = inject((ElementRef));
|
|
50
|
+
// Properties
|
|
51
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
52
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
53
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
54
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
55
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
56
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
57
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
58
|
+
effectiveDisableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false, { ...(ngDevMode ? { debugName: "effectiveDisableRipple" } : {}) });
|
|
59
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
60
|
+
showErrors = shouldShowErrors(this.field);
|
|
61
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
62
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
63
|
+
// Accessibility
|
|
64
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
65
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
66
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
67
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
68
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
69
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
70
|
+
ariaInvalid = computed(() => {
|
|
71
|
+
const fieldState = this.field()();
|
|
72
|
+
return fieldState.invalid() && fieldState.touched();
|
|
73
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
74
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
75
|
+
ariaRequired = computed(() => {
|
|
76
|
+
return this.field()().required?.() === true ? true : null;
|
|
77
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
78
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
79
|
+
ariaDescribedBy = computed(() => {
|
|
80
|
+
const ids = [];
|
|
81
|
+
if (this.props()?.hint) {
|
|
82
|
+
ids.push(this.hintId());
|
|
83
|
+
}
|
|
84
|
+
const errors = this.errorsToDisplay();
|
|
85
|
+
errors.forEach((_, i) => {
|
|
86
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
87
|
+
});
|
|
88
|
+
return ids.join(' ');
|
|
89
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
90
|
+
/**
|
|
91
|
+
* Workaround: Angular Material's MatCheckbox does NOT set aria-required on its internal
|
|
92
|
+
* input element when [required] is passed, even though it sets the native required attribute.
|
|
93
|
+
* This effect imperatively sets/removes aria-required on the internal input.
|
|
94
|
+
*
|
|
95
|
+
* Bug: MatCheckbox sets `required` attribute but not `aria-required` for screen readers.
|
|
96
|
+
* @see https://github.com/angular/components/issues/XXXXX (TODO: file issue)
|
|
97
|
+
*/
|
|
98
|
+
syncAriaRequiredToDom = explicitEffect([this.ariaRequired], ([isRequired]) => {
|
|
99
|
+
const inputEl = this.hostEl.nativeElement.querySelector('input[type="checkbox"]');
|
|
100
|
+
if (inputEl) {
|
|
101
|
+
if (isRequired) {
|
|
102
|
+
inputEl.setAttribute('aria-required', 'true');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
inputEl.removeAttribute('aria-required');
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
});
|
|
109
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
110
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatCheckboxFieldComponent, isStandalone: true, selector: "df-mat-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
111
|
+
@let f = field();
|
|
112
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
113
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
114
|
+
|
|
115
|
+
<mat-checkbox
|
|
116
|
+
[field]="f"
|
|
117
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
118
|
+
[indeterminate]="props()?.indeterminate || false"
|
|
119
|
+
[color]="props()?.color || 'primary'"
|
|
120
|
+
[disableRipple]="effectiveDisableRipple()"
|
|
121
|
+
[required]="!!f().required?.()"
|
|
122
|
+
[aria-describedby]="ariaDescribedBy"
|
|
123
|
+
[attr.tabindex]="tabIndex()"
|
|
124
|
+
[attr.hidden]="f().hidden() || null"
|
|
125
|
+
>
|
|
126
|
+
{{ label() | dynamicText | async }}
|
|
127
|
+
</mat-checkbox>
|
|
128
|
+
|
|
129
|
+
@if (props()?.hint; as hint) {
|
|
130
|
+
<div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
|
|
131
|
+
}
|
|
132
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
133
|
+
<mat-error [id]="errorId() + '-' + i" [attr.hidden]="f().hidden() || null">{{ error.message }}</mat-error>
|
|
134
|
+
}
|
|
135
|
+
`, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
136
|
+
}
|
|
137
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatCheckboxFieldComponent, decorators: [{
|
|
138
|
+
type: Component,
|
|
139
|
+
args: [{ selector: 'df-mat-checkbox', imports: [MatCheckbox, Field, MatError, DynamicTextPipe, AsyncPipe], template: `
|
|
140
|
+
@let f = field();
|
|
141
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
142
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
143
|
+
|
|
144
|
+
<mat-checkbox
|
|
145
|
+
[field]="f"
|
|
146
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
147
|
+
[indeterminate]="props()?.indeterminate || false"
|
|
148
|
+
[color]="props()?.color || 'primary'"
|
|
149
|
+
[disableRipple]="effectiveDisableRipple()"
|
|
150
|
+
[required]="!!f().required?.()"
|
|
151
|
+
[aria-describedby]="ariaDescribedBy"
|
|
152
|
+
[attr.tabindex]="tabIndex()"
|
|
153
|
+
[attr.hidden]="f().hidden() || null"
|
|
154
|
+
>
|
|
155
|
+
{{ label() | dynamicText | async }}
|
|
156
|
+
</mat-checkbox>
|
|
157
|
+
|
|
158
|
+
@if (props()?.hint; as hint) {
|
|
159
|
+
<div class="mat-hint" [id]="hintId()" [attr.hidden]="f().hidden() || null">{{ hint | dynamicText | async }}</div>
|
|
160
|
+
}
|
|
161
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
162
|
+
<mat-error [id]="errorId() + '-' + i" [attr.hidden]="f().hidden() || null">{{ error.message }}</mat-error>
|
|
163
|
+
}
|
|
164
|
+
`, host: {
|
|
165
|
+
'[class]': 'className()',
|
|
166
|
+
'[id]': '`${key()}`',
|
|
167
|
+
'[attr.data-testid]': 'key()',
|
|
168
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
169
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
|
|
170
|
+
}], 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 }] }] } });
|
|
171
|
+
|
|
172
|
+
var matCheckbox_component = /*#__PURE__*/Object.freeze({
|
|
173
|
+
__proto__: null,
|
|
174
|
+
default: MatCheckboxFieldComponent
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
class MatDatepickerFieldComponent {
|
|
178
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
179
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
180
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
181
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
182
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
183
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
184
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
185
|
+
minDate = input(null, { ...(ngDevMode ? { debugName: "minDate" } : {}) });
|
|
186
|
+
maxDate = input(null, { ...(ngDevMode ? { debugName: "maxDate" } : {}) });
|
|
187
|
+
startAt = input(null, { ...(ngDevMode ? { debugName: "startAt" } : {}) });
|
|
188
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
189
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
190
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
191
|
+
effectiveAppearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline', { ...(ngDevMode ? { debugName: "effectiveAppearance" } : {}) });
|
|
192
|
+
effectiveSubscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic', { ...(ngDevMode ? { debugName: "effectiveSubscriptSizing" } : {}) });
|
|
193
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
194
|
+
showErrors = shouldShowErrors(this.field);
|
|
195
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
196
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
197
|
+
// Accessibility
|
|
198
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
199
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
200
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
201
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
202
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
203
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
204
|
+
ariaInvalid = computed(() => {
|
|
205
|
+
const fieldState = this.field()();
|
|
206
|
+
return fieldState.invalid() && fieldState.touched();
|
|
207
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
208
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
209
|
+
ariaRequired = computed(() => {
|
|
210
|
+
return this.field()().required?.() === true ? true : null;
|
|
211
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
212
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
213
|
+
ariaDescribedBy = computed(() => {
|
|
214
|
+
const ids = [];
|
|
215
|
+
if (this.props()?.hint) {
|
|
216
|
+
ids.push(this.hintId());
|
|
217
|
+
}
|
|
218
|
+
const errors = this.errorsToDisplay();
|
|
219
|
+
errors.forEach((_, i) => {
|
|
220
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
221
|
+
});
|
|
222
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
223
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
224
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatDatepickerFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
225
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatDatepickerFieldComponent, isStandalone: true, selector: "df-mat-datepicker", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, minDate: { classPropertyName: "minDate", publicName: "minDate", isSignal: true, isRequired: false, transformFunction: null }, maxDate: { classPropertyName: "maxDate", publicName: "maxDate", isSignal: true, isRequired: false, transformFunction: null }, startAt: { classPropertyName: "startAt", publicName: "startAt", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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()", "attr.hidden": "field()().hidden() || null" } }, providers: [provideNativeDateAdapter()], ngImport: i0, template: `
|
|
226
|
+
@let f = field();
|
|
227
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
228
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
229
|
+
|
|
230
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()" [class]="className() || ''">
|
|
231
|
+
@if (label(); as label) {
|
|
232
|
+
<mat-label>{{ label | dynamicText | async }}</mat-label>
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
<input
|
|
236
|
+
matInput
|
|
237
|
+
[matDatepicker]="picker"
|
|
238
|
+
[field]="f"
|
|
239
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
240
|
+
[attr.tabindex]="tabIndex()"
|
|
241
|
+
[min]="minDate()"
|
|
242
|
+
[max]="maxDate()"
|
|
243
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
244
|
+
[attr.aria-required]="ariaRequired"
|
|
245
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
246
|
+
/>
|
|
247
|
+
|
|
248
|
+
<mat-datepicker-toggle matIconSuffix [for]="$any(picker)" />
|
|
249
|
+
<mat-datepicker #picker [startAt]="startAt()" [startView]="props()?.startView || 'month'" [touchUi]="props()?.touchUi ?? false" />
|
|
250
|
+
|
|
251
|
+
@if (props()?.hint; as hint) {
|
|
252
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
253
|
+
}
|
|
254
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
255
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
256
|
+
}
|
|
257
|
+
</mat-form-field>
|
|
258
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatDatepicker, selector: "mat-datepicker", exportAs: ["matDatepicker"] }, { kind: "directive", type: MatDatepickerInput, selector: "input[matDatepicker]", inputs: ["matDatepicker", "min", "max", "matDatepickerFilter"], exportAs: ["matDatepickerInput"] }, { kind: "component", type: MatDatepickerToggle, selector: "mat-datepicker-toggle", inputs: ["for", "tabIndex", "aria-label", "disabled", "disableRipple"], exportAs: ["matDatepickerToggle"] }, { kind: "directive", type: MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
259
|
+
}
|
|
260
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatDatepickerFieldComponent, decorators: [{
|
|
261
|
+
type: Component,
|
|
262
|
+
args: [{ selector: 'df-mat-datepicker', imports: [
|
|
263
|
+
MatFormField,
|
|
264
|
+
MatLabel,
|
|
265
|
+
MatInput,
|
|
266
|
+
MatHint,
|
|
267
|
+
MatDatepicker,
|
|
268
|
+
MatDatepickerInput,
|
|
269
|
+
MatDatepickerToggle,
|
|
270
|
+
MatSuffix,
|
|
271
|
+
Field,
|
|
272
|
+
MatError$1,
|
|
273
|
+
DynamicTextPipe,
|
|
274
|
+
AsyncPipe,
|
|
275
|
+
], host: {
|
|
276
|
+
'[id]': '`${key()}`',
|
|
277
|
+
'[attr.data-testid]': 'key()',
|
|
278
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
279
|
+
}, template: `
|
|
280
|
+
@let f = field();
|
|
281
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
282
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
283
|
+
|
|
284
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()" [class]="className() || ''">
|
|
285
|
+
@if (label(); as label) {
|
|
286
|
+
<mat-label>{{ label | dynamicText | async }}</mat-label>
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
<input
|
|
290
|
+
matInput
|
|
291
|
+
[matDatepicker]="picker"
|
|
292
|
+
[field]="f"
|
|
293
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
294
|
+
[attr.tabindex]="tabIndex()"
|
|
295
|
+
[min]="minDate()"
|
|
296
|
+
[max]="maxDate()"
|
|
297
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
298
|
+
[attr.aria-required]="ariaRequired"
|
|
299
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
300
|
+
/>
|
|
301
|
+
|
|
302
|
+
<mat-datepicker-toggle matIconSuffix [for]="$any(picker)" />
|
|
303
|
+
<mat-datepicker #picker [startAt]="startAt()" [startView]="props()?.startView || 'month'" [touchUi]="props()?.touchUi ?? false" />
|
|
304
|
+
|
|
305
|
+
@if (props()?.hint; as hint) {
|
|
306
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
307
|
+
}
|
|
308
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
309
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
310
|
+
}
|
|
311
|
+
</mat-form-field>
|
|
312
|
+
`, providers: [provideNativeDateAdapter()], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"] }]
|
|
313
|
+
}], 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 }] }] } });
|
|
314
|
+
|
|
315
|
+
var matDatepicker_component = /*#__PURE__*/Object.freeze({
|
|
316
|
+
__proto__: null,
|
|
317
|
+
default: MatDatepickerFieldComponent
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
class MatInputFieldComponent {
|
|
321
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
322
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
323
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
324
|
+
/**
|
|
325
|
+
* Reference to the native input element.
|
|
326
|
+
* Used to imperatively sync the readonly attribute since Angular Signal Forms'
|
|
327
|
+
* [field] directive doesn't sync FieldState.readonly() to the DOM.
|
|
328
|
+
*/
|
|
329
|
+
inputRef = viewChild('inputRef', { ...(ngDevMode ? { debugName: "inputRef" } : {}) });
|
|
330
|
+
/**
|
|
331
|
+
* Computed signal that extracts the readonly state from the field.
|
|
332
|
+
* Used by the effect to reactively sync the readonly attribute to the DOM.
|
|
333
|
+
*/
|
|
334
|
+
isReadonly = computed(() => this.field()().readonly(), { ...(ngDevMode ? { debugName: "isReadonly" } : {}) });
|
|
335
|
+
/**
|
|
336
|
+
* Workaround: Angular Signal Forms' [field] directive does NOT sync the readonly
|
|
337
|
+
* attribute to the DOM, even though FieldState.readonly() returns the correct value.
|
|
338
|
+
* This effect imperatively sets/removes the readonly attribute on the native input
|
|
339
|
+
* element whenever the readonly state changes.
|
|
340
|
+
*
|
|
341
|
+
* Note: We cannot use [readonly] or [attr.readonly] bindings because Angular throws
|
|
342
|
+
* NG8022: "Binding to '[readonly]' is not allowed on nodes using the '[field]' directive"
|
|
343
|
+
*
|
|
344
|
+
* @see https://github.com/angular/angular/issues/65897
|
|
345
|
+
*/
|
|
346
|
+
syncReadonlyToDom = explicitEffect([this.inputRef, this.isReadonly], ([inputRef, isReadonly]) => {
|
|
347
|
+
if (inputRef?.nativeElement) {
|
|
348
|
+
if (isReadonly) {
|
|
349
|
+
inputRef.nativeElement.setAttribute('readonly', '');
|
|
350
|
+
}
|
|
351
|
+
else {
|
|
352
|
+
inputRef.nativeElement.removeAttribute('readonly');
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
357
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
358
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
359
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
360
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
361
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
362
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
363
|
+
effectiveAppearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline', { ...(ngDevMode ? { debugName: "effectiveAppearance" } : {}) });
|
|
364
|
+
effectiveSubscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic', { ...(ngDevMode ? { debugName: "effectiveSubscriptSizing" } : {}) });
|
|
365
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
366
|
+
showErrors = shouldShowErrors(this.field);
|
|
367
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
368
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
369
|
+
// Accessibility
|
|
370
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
371
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
372
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
373
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
374
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
375
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
376
|
+
ariaInvalid = computed(() => {
|
|
377
|
+
const fieldState = this.field()();
|
|
378
|
+
return fieldState.invalid() && fieldState.touched();
|
|
379
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
380
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
381
|
+
ariaRequired = computed(() => {
|
|
382
|
+
return this.field()().required?.() === true ? true : null;
|
|
383
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
384
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
385
|
+
ariaDescribedBy = computed(() => {
|
|
386
|
+
const ids = [];
|
|
387
|
+
if (this.props()?.hint) {
|
|
388
|
+
ids.push(this.hintId());
|
|
389
|
+
}
|
|
390
|
+
const errors = this.errorsToDisplay();
|
|
391
|
+
errors.forEach((_, i) => {
|
|
392
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
393
|
+
});
|
|
394
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
395
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
396
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatInputFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
397
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatInputFieldComponent, isStandalone: true, selector: "df-mat-input", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "inputRef", first: true, predicate: ["inputRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
398
|
+
@let f = field();
|
|
399
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
400
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
401
|
+
|
|
402
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
403
|
+
@if (label()) {
|
|
404
|
+
<mat-label>{{ label() | dynamicText | async }}</mat-label>
|
|
405
|
+
}
|
|
406
|
+
@switch (props()?.type ?? 'text') {
|
|
407
|
+
@case ('email') {
|
|
408
|
+
<input
|
|
409
|
+
#inputRef
|
|
410
|
+
matInput
|
|
411
|
+
type="email"
|
|
412
|
+
[field]="f"
|
|
413
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
414
|
+
[attr.tabindex]="tabIndex()"
|
|
415
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
416
|
+
[attr.aria-required]="ariaRequired"
|
|
417
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
418
|
+
/>
|
|
419
|
+
}
|
|
420
|
+
@case ('password') {
|
|
421
|
+
<input
|
|
422
|
+
#inputRef
|
|
423
|
+
matInput
|
|
424
|
+
type="password"
|
|
425
|
+
[field]="f"
|
|
426
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
427
|
+
[attr.tabindex]="tabIndex()"
|
|
428
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
429
|
+
[attr.aria-required]="ariaRequired"
|
|
430
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
431
|
+
/>
|
|
432
|
+
}
|
|
433
|
+
@case ('number') {
|
|
434
|
+
<input
|
|
435
|
+
#inputRef
|
|
436
|
+
matInput
|
|
437
|
+
type="number"
|
|
438
|
+
[field]="f"
|
|
439
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
440
|
+
[attr.tabindex]="tabIndex()"
|
|
441
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
442
|
+
[attr.aria-required]="ariaRequired"
|
|
443
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
444
|
+
/>
|
|
445
|
+
}
|
|
446
|
+
@case ('tel') {
|
|
447
|
+
<input
|
|
448
|
+
#inputRef
|
|
449
|
+
matInput
|
|
450
|
+
type="tel"
|
|
451
|
+
[field]="f"
|
|
452
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
453
|
+
[attr.tabindex]="tabIndex()"
|
|
454
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
455
|
+
[attr.aria-required]="ariaRequired"
|
|
456
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
457
|
+
/>
|
|
458
|
+
}
|
|
459
|
+
@case ('url') {
|
|
460
|
+
<input
|
|
461
|
+
#inputRef
|
|
462
|
+
matInput
|
|
463
|
+
type="url"
|
|
464
|
+
[field]="f"
|
|
465
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
466
|
+
[attr.tabindex]="tabIndex()"
|
|
467
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
468
|
+
[attr.aria-required]="ariaRequired"
|
|
469
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
470
|
+
/>
|
|
471
|
+
}
|
|
472
|
+
@default {
|
|
473
|
+
<input
|
|
474
|
+
#inputRef
|
|
475
|
+
matInput
|
|
476
|
+
type="text"
|
|
477
|
+
[field]="f"
|
|
478
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
479
|
+
[attr.tabindex]="tabIndex()"
|
|
480
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
481
|
+
[attr.aria-required]="ariaRequired"
|
|
482
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
483
|
+
/>
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
@if (props()?.hint; as hint) {
|
|
487
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
488
|
+
}
|
|
489
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
490
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
491
|
+
}
|
|
492
|
+
</mat-form-field>
|
|
493
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
494
|
+
}
|
|
495
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatInputFieldComponent, decorators: [{
|
|
496
|
+
type: Component,
|
|
497
|
+
args: [{ selector: 'df-mat-input', imports: [MatFormField, MatLabel, MatInput, MatHint, Field, MatError$1, DynamicTextPipe, AsyncPipe], template: `
|
|
498
|
+
@let f = field();
|
|
499
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
500
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
501
|
+
|
|
502
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
503
|
+
@if (label()) {
|
|
504
|
+
<mat-label>{{ label() | dynamicText | async }}</mat-label>
|
|
505
|
+
}
|
|
506
|
+
@switch (props()?.type ?? 'text') {
|
|
507
|
+
@case ('email') {
|
|
508
|
+
<input
|
|
509
|
+
#inputRef
|
|
510
|
+
matInput
|
|
511
|
+
type="email"
|
|
512
|
+
[field]="f"
|
|
513
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
514
|
+
[attr.tabindex]="tabIndex()"
|
|
515
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
516
|
+
[attr.aria-required]="ariaRequired"
|
|
517
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
518
|
+
/>
|
|
519
|
+
}
|
|
520
|
+
@case ('password') {
|
|
521
|
+
<input
|
|
522
|
+
#inputRef
|
|
523
|
+
matInput
|
|
524
|
+
type="password"
|
|
525
|
+
[field]="f"
|
|
526
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
527
|
+
[attr.tabindex]="tabIndex()"
|
|
528
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
529
|
+
[attr.aria-required]="ariaRequired"
|
|
530
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
531
|
+
/>
|
|
532
|
+
}
|
|
533
|
+
@case ('number') {
|
|
534
|
+
<input
|
|
535
|
+
#inputRef
|
|
536
|
+
matInput
|
|
537
|
+
type="number"
|
|
538
|
+
[field]="f"
|
|
539
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
540
|
+
[attr.tabindex]="tabIndex()"
|
|
541
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
542
|
+
[attr.aria-required]="ariaRequired"
|
|
543
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
544
|
+
/>
|
|
545
|
+
}
|
|
546
|
+
@case ('tel') {
|
|
547
|
+
<input
|
|
548
|
+
#inputRef
|
|
549
|
+
matInput
|
|
550
|
+
type="tel"
|
|
551
|
+
[field]="f"
|
|
552
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
553
|
+
[attr.tabindex]="tabIndex()"
|
|
554
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
555
|
+
[attr.aria-required]="ariaRequired"
|
|
556
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
557
|
+
/>
|
|
558
|
+
}
|
|
559
|
+
@case ('url') {
|
|
560
|
+
<input
|
|
561
|
+
#inputRef
|
|
562
|
+
matInput
|
|
563
|
+
type="url"
|
|
564
|
+
[field]="f"
|
|
565
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
566
|
+
[attr.tabindex]="tabIndex()"
|
|
567
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
568
|
+
[attr.aria-required]="ariaRequired"
|
|
569
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
570
|
+
/>
|
|
571
|
+
}
|
|
572
|
+
@default {
|
|
573
|
+
<input
|
|
574
|
+
#inputRef
|
|
575
|
+
matInput
|
|
576
|
+
type="text"
|
|
577
|
+
[field]="f"
|
|
578
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
579
|
+
[attr.tabindex]="tabIndex()"
|
|
580
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
581
|
+
[attr.aria-required]="ariaRequired"
|
|
582
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
583
|
+
/>
|
|
584
|
+
}
|
|
585
|
+
}
|
|
586
|
+
@if (props()?.hint; as hint) {
|
|
587
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
588
|
+
}
|
|
589
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
590
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
591
|
+
}
|
|
592
|
+
</mat-form-field>
|
|
593
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
594
|
+
'[id]': '`${key()}`',
|
|
595
|
+
'[attr.data-testid]': 'key()',
|
|
596
|
+
'[class]': 'className()',
|
|
597
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
598
|
+
}, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"] }]
|
|
599
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], inputRef: [{ type: i0.ViewChild, args: ['inputRef', { isSignal: 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 }] }] } });
|
|
600
|
+
|
|
601
|
+
var matInput_component = /*#__PURE__*/Object.freeze({
|
|
602
|
+
__proto__: null,
|
|
603
|
+
default: MatInputFieldComponent
|
|
604
|
+
});
|
|
605
|
+
|
|
606
|
+
class ValueInArrayPipe {
|
|
607
|
+
transform(element, array) {
|
|
608
|
+
return array?.includes(element) ?? false;
|
|
609
|
+
}
|
|
610
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ValueInArrayPipe, deps: [], target: i0.ɵɵFactoryTarget.Pipe });
|
|
611
|
+
static ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "21.0.1", ngImport: i0, type: ValueInArrayPipe, isStandalone: true, name: "inArray" });
|
|
612
|
+
}
|
|
613
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: ValueInArrayPipe, decorators: [{
|
|
614
|
+
type: Pipe,
|
|
615
|
+
args: [{
|
|
616
|
+
pure: true,
|
|
617
|
+
name: 'inArray',
|
|
618
|
+
}]
|
|
619
|
+
}] });
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Performs a deep equality comparison between two values
|
|
623
|
+
*/
|
|
624
|
+
function isEqual(a, b) {
|
|
625
|
+
if (a === b)
|
|
626
|
+
return true;
|
|
627
|
+
if (a == null || b == null)
|
|
628
|
+
return false;
|
|
629
|
+
if (typeof a !== typeof b)
|
|
630
|
+
return false;
|
|
631
|
+
if (a instanceof Date && b instanceof Date) {
|
|
632
|
+
return a.getTime() === b.getTime();
|
|
633
|
+
}
|
|
634
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
635
|
+
if (a.length !== b.length)
|
|
636
|
+
return false;
|
|
637
|
+
return a.every((item, index) => isEqual(item, b[index]));
|
|
638
|
+
}
|
|
639
|
+
if (typeof a === 'object' && typeof b === 'object') {
|
|
640
|
+
const keysA = Object.keys(a);
|
|
641
|
+
const keysB = Object.keys(b);
|
|
642
|
+
if (keysA.length !== keysB.length)
|
|
643
|
+
return false;
|
|
644
|
+
return keysA.every((key) => keysB.includes(key) && isEqual(a[key], b[key]));
|
|
645
|
+
}
|
|
646
|
+
return Object.is(a, b);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
class MatMultiCheckboxFieldComponent {
|
|
650
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
651
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
652
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
653
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
654
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
655
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
656
|
+
options = input([], { ...(ngDevMode ? { debugName: "options" } : {}) });
|
|
657
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
658
|
+
valueViewModel = linkedSignal(() => {
|
|
659
|
+
const currentValues = this.field()().value();
|
|
660
|
+
return this.options().filter((option) => currentValues.includes(option.value));
|
|
661
|
+
}, { ...(ngDevMode ? { debugName: "valueViewModel" } : {}), equal: isEqual });
|
|
662
|
+
constructor() {
|
|
663
|
+
explicitEffect([this.valueViewModel], ([selectedOptions]) => {
|
|
664
|
+
const selectedValues = selectedOptions.map((option) => option.value);
|
|
665
|
+
if (!isEqual(selectedValues, this.field()().value())) {
|
|
666
|
+
this.field()().value.set(selectedValues);
|
|
667
|
+
}
|
|
668
|
+
});
|
|
669
|
+
explicitEffect([this.options], ([options]) => {
|
|
670
|
+
const values = options.map((option) => option.value);
|
|
671
|
+
const uniqueValues = new Set(values);
|
|
672
|
+
if (values.length !== uniqueValues.size) {
|
|
673
|
+
const duplicates = values.filter((value, index) => values.indexOf(value) !== index);
|
|
674
|
+
throw new Error(`Duplicate option values detected in mat-multi-checkbox: ${duplicates.join(', ')}`);
|
|
675
|
+
}
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
onCheckboxChange(option, checked) {
|
|
679
|
+
this.valueViewModel.update((currentOptions) => {
|
|
680
|
+
if (checked) {
|
|
681
|
+
return currentOptions.some((opt) => opt.value === option.value) ? currentOptions : [...currentOptions, option];
|
|
682
|
+
}
|
|
683
|
+
else {
|
|
684
|
+
return currentOptions.filter((opt) => opt.value !== option.value);
|
|
685
|
+
}
|
|
686
|
+
});
|
|
687
|
+
}
|
|
688
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
689
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
690
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
691
|
+
showErrors = shouldShowErrors(this.field);
|
|
692
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
693
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
694
|
+
// Accessibility
|
|
695
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
696
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
697
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
698
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
699
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
700
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
701
|
+
ariaInvalid = computed(() => {
|
|
702
|
+
const fieldState = this.field()();
|
|
703
|
+
return fieldState.invalid() && fieldState.touched();
|
|
704
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
705
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
706
|
+
ariaRequired = computed(() => {
|
|
707
|
+
return this.field()().required?.() === true ? true : null;
|
|
708
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
709
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
710
|
+
ariaDescribedBy = computed(() => {
|
|
711
|
+
const ids = [];
|
|
712
|
+
if (this.props()?.hint) {
|
|
713
|
+
ids.push(this.hintId());
|
|
714
|
+
}
|
|
715
|
+
const errors = this.errorsToDisplay();
|
|
716
|
+
errors.forEach((_, i) => {
|
|
717
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
718
|
+
});
|
|
719
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
720
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
721
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatMultiCheckboxFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
722
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatMultiCheckboxFieldComponent, isStandalone: true, selector: "df-mat-multi-checkbox", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
723
|
+
@let f = field();
|
|
724
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
725
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
726
|
+
|
|
727
|
+
@if (label(); as label) {
|
|
728
|
+
<div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
<div
|
|
732
|
+
class="checkbox-group"
|
|
733
|
+
role="group"
|
|
734
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
735
|
+
[attr.aria-required]="ariaRequired"
|
|
736
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
737
|
+
>
|
|
738
|
+
@for (option of options(); track option.value) {
|
|
739
|
+
<mat-checkbox
|
|
740
|
+
[checked]="option | inArray: valueViewModel()"
|
|
741
|
+
[disabled]="f().disabled() || option.disabled"
|
|
742
|
+
[color]="props()?.color || 'primary'"
|
|
743
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
744
|
+
(change)="onCheckboxChange(option, $event.checked)"
|
|
745
|
+
>
|
|
746
|
+
{{ option.label | dynamicText | async }}
|
|
747
|
+
</mat-checkbox>
|
|
748
|
+
}
|
|
749
|
+
</div>
|
|
750
|
+
|
|
751
|
+
@if (props()?.hint; as hint) {
|
|
752
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
753
|
+
}
|
|
754
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
755
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
756
|
+
}
|
|
757
|
+
`, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: ValueInArrayPipe, name: "inArray" }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
758
|
+
}
|
|
759
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatMultiCheckboxFieldComponent, decorators: [{
|
|
760
|
+
type: Component,
|
|
761
|
+
args: [{ selector: 'df-mat-multi-checkbox', imports: [MatCheckbox, ValueInArrayPipe, MatError, DynamicTextPipe, AsyncPipe], template: `
|
|
762
|
+
@let f = field();
|
|
763
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
764
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
765
|
+
|
|
766
|
+
@if (label(); as label) {
|
|
767
|
+
<div class="checkbox-group-label">{{ label | dynamicText | async }}</div>
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
<div
|
|
771
|
+
class="checkbox-group"
|
|
772
|
+
role="group"
|
|
773
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
774
|
+
[attr.aria-required]="ariaRequired"
|
|
775
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
776
|
+
>
|
|
777
|
+
@for (option of options(); track option.value) {
|
|
778
|
+
<mat-checkbox
|
|
779
|
+
[checked]="option | inArray: valueViewModel()"
|
|
780
|
+
[disabled]="f().disabled() || option.disabled"
|
|
781
|
+
[color]="props()?.color || 'primary'"
|
|
782
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
783
|
+
(change)="onCheckboxChange(option, $event.checked)"
|
|
784
|
+
>
|
|
785
|
+
{{ option.label | dynamicText | async }}
|
|
786
|
+
</mat-checkbox>
|
|
787
|
+
}
|
|
788
|
+
</div>
|
|
789
|
+
|
|
790
|
+
@if (props()?.hint; as hint) {
|
|
791
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
792
|
+
}
|
|
793
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
794
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
795
|
+
}
|
|
796
|
+
`, host: {
|
|
797
|
+
'[class]': 'className() || ""',
|
|
798
|
+
'[id]': '`${key()}`',
|
|
799
|
+
'[attr.data-testid]': 'key()',
|
|
800
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
801
|
+
}, providers: [ValueInArrayPipe], changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
|
|
802
|
+
}], 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 }] }] } });
|
|
803
|
+
|
|
804
|
+
var matMultiCheckbox_component = /*#__PURE__*/Object.freeze({
|
|
805
|
+
__proto__: null,
|
|
806
|
+
default: MatMultiCheckboxFieldComponent
|
|
807
|
+
});
|
|
808
|
+
|
|
809
|
+
class MatRadioFieldComponent {
|
|
810
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
811
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
812
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
813
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
814
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
815
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
816
|
+
options = input([], { ...(ngDevMode ? { debugName: "options" } : {}) });
|
|
817
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
818
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
819
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
820
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
821
|
+
showErrors = shouldShowErrors(this.field);
|
|
822
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
823
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
824
|
+
// Accessibility
|
|
825
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
826
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
827
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
828
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
829
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
830
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
831
|
+
ariaInvalid = computed(() => {
|
|
832
|
+
const fieldState = this.field()();
|
|
833
|
+
return fieldState.invalid() && fieldState.touched();
|
|
834
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
835
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
836
|
+
ariaRequired = computed(() => {
|
|
837
|
+
return this.field()().required?.() === true ? true : null;
|
|
838
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
839
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
840
|
+
ariaDescribedBy = computed(() => {
|
|
841
|
+
const ids = [];
|
|
842
|
+
if (this.props()?.hint) {
|
|
843
|
+
ids.push(this.hintId());
|
|
844
|
+
}
|
|
845
|
+
const errors = this.errorsToDisplay();
|
|
846
|
+
errors.forEach((_, i) => {
|
|
847
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
848
|
+
});
|
|
849
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
850
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
851
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatRadioFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
852
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatRadioFieldComponent, isStandalone: true, selector: "df-mat-radio", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
853
|
+
@let f = field();
|
|
854
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
855
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
856
|
+
|
|
857
|
+
@if (label()) {
|
|
858
|
+
<div class="radio-label">{{ label() | dynamicText | async }}</div>
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
<mat-radio-group
|
|
862
|
+
[field]="f"
|
|
863
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
864
|
+
[attr.aria-required]="ariaRequired"
|
|
865
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
866
|
+
>
|
|
867
|
+
@for (option of options(); track option.value) {
|
|
868
|
+
<mat-radio-button
|
|
869
|
+
[value]="option.value"
|
|
870
|
+
[disabled]="option.disabled || false"
|
|
871
|
+
[color]="props()?.color || 'primary'"
|
|
872
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
873
|
+
>
|
|
874
|
+
{{ option.label | dynamicText | async }}
|
|
875
|
+
</mat-radio-button>
|
|
876
|
+
}
|
|
877
|
+
</mat-radio-group>
|
|
878
|
+
|
|
879
|
+
@if (props()?.hint; as hint) {
|
|
880
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
881
|
+
}
|
|
882
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
883
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
884
|
+
}
|
|
885
|
+
`, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "directive", type: MatRadioGroup, selector: "mat-radio-group", inputs: ["color", "name", "labelPosition", "value", "selected", "disabled", "required", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioGroup"] }, { kind: "component", type: MatRadioButton, selector: "mat-radio-button", inputs: ["id", "name", "aria-label", "aria-labelledby", "aria-describedby", "disableRipple", "tabIndex", "checked", "value", "labelPosition", "disabled", "required", "color", "disabledInteractive"], outputs: ["change"], exportAs: ["matRadioButton"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
886
|
+
}
|
|
887
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatRadioFieldComponent, decorators: [{
|
|
888
|
+
type: Component,
|
|
889
|
+
args: [{ selector: 'df-mat-radio', imports: [MatRadioGroup, MatRadioButton, Field, MatError, DynamicTextPipe, AsyncPipe], template: `
|
|
890
|
+
@let f = field();
|
|
891
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
892
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
893
|
+
|
|
894
|
+
@if (label()) {
|
|
895
|
+
<div class="radio-label">{{ label() | dynamicText | async }}</div>
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
<mat-radio-group
|
|
899
|
+
[field]="f"
|
|
900
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
901
|
+
[attr.aria-required]="ariaRequired"
|
|
902
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
903
|
+
>
|
|
904
|
+
@for (option of options(); track option.value) {
|
|
905
|
+
<mat-radio-button
|
|
906
|
+
[value]="option.value"
|
|
907
|
+
[disabled]="option.disabled || false"
|
|
908
|
+
[color]="props()?.color || 'primary'"
|
|
909
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
910
|
+
>
|
|
911
|
+
{{ option.label | dynamicText | async }}
|
|
912
|
+
</mat-radio-button>
|
|
913
|
+
}
|
|
914
|
+
</mat-radio-group>
|
|
915
|
+
|
|
916
|
+
@if (props()?.hint; as hint) {
|
|
917
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
918
|
+
}
|
|
919
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
920
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
921
|
+
}
|
|
922
|
+
`, host: {
|
|
923
|
+
'[class]': 'className() || ""',
|
|
924
|
+
'[id]': '`${key()}`',
|
|
925
|
+
'[attr.data-testid]': 'key()',
|
|
926
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
927
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
|
|
928
|
+
}], 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 }] }] } });
|
|
929
|
+
|
|
930
|
+
var matRadio_component = /*#__PURE__*/Object.freeze({
|
|
931
|
+
__proto__: null,
|
|
932
|
+
default: MatRadioFieldComponent
|
|
933
|
+
});
|
|
934
|
+
|
|
935
|
+
class MatSelectFieldComponent {
|
|
936
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
937
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
938
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
939
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
940
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
941
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
942
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
943
|
+
options = input([], { ...(ngDevMode ? { debugName: "options" } : {}) });
|
|
944
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
945
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
946
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
947
|
+
effectiveAppearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline', { ...(ngDevMode ? { debugName: "effectiveAppearance" } : {}) });
|
|
948
|
+
effectiveSubscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic', { ...(ngDevMode ? { debugName: "effectiveSubscriptSizing" } : {}) });
|
|
949
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
950
|
+
showErrors = shouldShowErrors(this.field);
|
|
951
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
952
|
+
defaultCompare = Object.is;
|
|
953
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
954
|
+
// Accessibility
|
|
955
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
956
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
957
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
958
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
959
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
960
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
961
|
+
ariaInvalid = computed(() => {
|
|
962
|
+
const fieldState = this.field()();
|
|
963
|
+
return fieldState.invalid() && fieldState.touched();
|
|
964
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
965
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
966
|
+
ariaRequired = computed(() => {
|
|
967
|
+
return this.field()().required?.() === true ? true : null;
|
|
968
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
969
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
970
|
+
ariaDescribedBy = computed(() => {
|
|
971
|
+
const ids = [];
|
|
972
|
+
if (this.props()?.hint) {
|
|
973
|
+
ids.push(this.hintId());
|
|
974
|
+
}
|
|
975
|
+
const errors = this.errorsToDisplay();
|
|
976
|
+
errors.forEach((_, i) => {
|
|
977
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
978
|
+
});
|
|
979
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
980
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
981
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatSelectFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
982
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatSelectFieldComponent, isStandalone: true, selector: "df-mat-select", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, options: { classPropertyName: "options", publicName: "options", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
983
|
+
@let f = field();
|
|
984
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
985
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
986
|
+
|
|
987
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
988
|
+
@if (label(); as label) {
|
|
989
|
+
<mat-label>{{ label | dynamicText | async }}</mat-label>
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
<mat-select
|
|
993
|
+
[field]="f"
|
|
994
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
995
|
+
[multiple]="props()?.multiple || false"
|
|
996
|
+
[compareWith]="props()?.compareWith || defaultCompare"
|
|
997
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
998
|
+
[attr.aria-required]="ariaRequired"
|
|
999
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1000
|
+
>
|
|
1001
|
+
@for (option of options(); track option.value) {
|
|
1002
|
+
<mat-option [value]="option.value" [disabled]="option.disabled || false">
|
|
1003
|
+
{{ option.label | dynamicText | async }}
|
|
1004
|
+
</mat-option>
|
|
1005
|
+
}
|
|
1006
|
+
</mat-select>
|
|
1007
|
+
|
|
1008
|
+
@if (props()?.hint; as hint) {
|
|
1009
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
1010
|
+
}
|
|
1011
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1012
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1013
|
+
}
|
|
1014
|
+
</mat-form-field>
|
|
1015
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "component", type: MatSelect, selector: "mat-select", inputs: ["aria-describedby", "panelClass", "disabled", "disableRipple", "tabIndex", "hideSingleSelectionIndicator", "placeholder", "required", "multiple", "disableOptionCentering", "compareWith", "value", "aria-label", "aria-labelledby", "errorStateMatcher", "typeaheadDebounceInterval", "sortComparator", "id", "panelWidth", "canSelectNullableOptions"], outputs: ["openedChange", "opened", "closed", "selectionChange", "valueChange"], exportAs: ["matSelect"] }, { kind: "component", type: MatOption, selector: "mat-option", inputs: ["value", "id", "disabled"], outputs: ["onSelectionChange"], exportAs: ["matOption"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1016
|
+
}
|
|
1017
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatSelectFieldComponent, decorators: [{
|
|
1018
|
+
type: Component,
|
|
1019
|
+
args: [{ selector: 'df-mat-select', imports: [MatFormField, MatLabel, MatSelect, MatOption, MatHint, Field, MatError$1, DynamicTextPipe, AsyncPipe], template: `
|
|
1020
|
+
@let f = field();
|
|
1021
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
1022
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1023
|
+
|
|
1024
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
1025
|
+
@if (label(); as label) {
|
|
1026
|
+
<mat-label>{{ label | dynamicText | async }}</mat-label>
|
|
1027
|
+
}
|
|
1028
|
+
|
|
1029
|
+
<mat-select
|
|
1030
|
+
[field]="f"
|
|
1031
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
1032
|
+
[multiple]="props()?.multiple || false"
|
|
1033
|
+
[compareWith]="props()?.compareWith || defaultCompare"
|
|
1034
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
1035
|
+
[attr.aria-required]="ariaRequired"
|
|
1036
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1037
|
+
>
|
|
1038
|
+
@for (option of options(); track option.value) {
|
|
1039
|
+
<mat-option [value]="option.value" [disabled]="option.disabled || false">
|
|
1040
|
+
{{ option.label | dynamicText | async }}
|
|
1041
|
+
</mat-option>
|
|
1042
|
+
}
|
|
1043
|
+
</mat-select>
|
|
1044
|
+
|
|
1045
|
+
@if (props()?.hint; as hint) {
|
|
1046
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
1047
|
+
}
|
|
1048
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1049
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1050
|
+
}
|
|
1051
|
+
</mat-form-field>
|
|
1052
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1053
|
+
'[id]': '`${key()}`',
|
|
1054
|
+
'[attr.data-testid]': 'key()',
|
|
1055
|
+
'[class]': 'className()',
|
|
1056
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
1057
|
+
}, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"] }]
|
|
1058
|
+
}], 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 }] }] } });
|
|
1059
|
+
|
|
1060
|
+
var matSelect_component = /*#__PURE__*/Object.freeze({
|
|
1061
|
+
__proto__: null,
|
|
1062
|
+
default: MatSelectFieldComponent
|
|
1063
|
+
});
|
|
1064
|
+
|
|
1065
|
+
class MatSliderFieldComponent {
|
|
1066
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
1067
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
1068
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
1069
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
1070
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
1071
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
1072
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
1073
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
1074
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
1075
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
1076
|
+
showErrors = shouldShowErrors(this.field);
|
|
1077
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
1078
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1079
|
+
// Accessibility
|
|
1080
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1081
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
1082
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
1083
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
1084
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
1085
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
1086
|
+
ariaInvalid = computed(() => {
|
|
1087
|
+
const fieldState = this.field()();
|
|
1088
|
+
return fieldState.invalid() && fieldState.touched();
|
|
1089
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
1090
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
1091
|
+
ariaDescribedBy = computed(() => {
|
|
1092
|
+
const ids = [];
|
|
1093
|
+
if (this.props()?.hint) {
|
|
1094
|
+
ids.push(this.hintId());
|
|
1095
|
+
}
|
|
1096
|
+
const errors = this.errorsToDisplay();
|
|
1097
|
+
errors.forEach((_, i) => {
|
|
1098
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
1099
|
+
});
|
|
1100
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
1101
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
1102
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatSliderFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1103
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatSliderFieldComponent, isStandalone: true, selector: "df-mat-slider", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
1104
|
+
@let f = field();
|
|
1105
|
+
@let ariaInvalid = this.ariaInvalid();
|
|
1106
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1107
|
+
|
|
1108
|
+
@if (label(); as label) {
|
|
1109
|
+
<div class="slider-label">{{ label | dynamicText | async }}</div>
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
<mat-slider
|
|
1113
|
+
[min]="f().min?.() ?? 0"
|
|
1114
|
+
[max]="f().max?.() ?? 100"
|
|
1115
|
+
[step]="props()?.step ?? 1"
|
|
1116
|
+
[discrete]="props()?.thumbLabel || props()?.showThumbLabel"
|
|
1117
|
+
[showTickMarks]="props()?.tickInterval !== undefined"
|
|
1118
|
+
[color]="props()?.color || 'primary'"
|
|
1119
|
+
class="slider-container"
|
|
1120
|
+
>
|
|
1121
|
+
<input
|
|
1122
|
+
matSliderThumb
|
|
1123
|
+
[field]="f"
|
|
1124
|
+
[attr.tabindex]="tabIndex()"
|
|
1125
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
1126
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1127
|
+
/>
|
|
1128
|
+
</mat-slider>
|
|
1129
|
+
|
|
1130
|
+
@if (props()?.hint; as hint) {
|
|
1131
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
1132
|
+
}
|
|
1133
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1134
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1135
|
+
}
|
|
1136
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}.slider-container{width:100%}\n"], dependencies: [{ kind: "component", type: MatSlider, selector: "mat-slider", inputs: ["disabled", "discrete", "showTickMarks", "min", "color", "disableRipple", "max", "step", "displayWith"], exportAs: ["matSlider"] }, { kind: "directive", type: MatSliderThumb, selector: "input[matSliderThumb]", inputs: ["value"], outputs: ["valueChange", "dragStart", "dragEnd"], exportAs: ["matSliderThumb"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1137
|
+
}
|
|
1138
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatSliderFieldComponent, decorators: [{
|
|
1139
|
+
type: Component,
|
|
1140
|
+
args: [{ selector: 'df-mat-slider', imports: [MatSlider, MatSliderThumb, MatError, DynamicTextPipe, AsyncPipe, Field], template: `
|
|
1141
|
+
@let f = field();
|
|
1142
|
+
@let ariaInvalid = this.ariaInvalid();
|
|
1143
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1144
|
+
|
|
1145
|
+
@if (label(); as label) {
|
|
1146
|
+
<div class="slider-label">{{ label | dynamicText | async }}</div>
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
<mat-slider
|
|
1150
|
+
[min]="f().min?.() ?? 0"
|
|
1151
|
+
[max]="f().max?.() ?? 100"
|
|
1152
|
+
[step]="props()?.step ?? 1"
|
|
1153
|
+
[discrete]="props()?.thumbLabel || props()?.showThumbLabel"
|
|
1154
|
+
[showTickMarks]="props()?.tickInterval !== undefined"
|
|
1155
|
+
[color]="props()?.color || 'primary'"
|
|
1156
|
+
class="slider-container"
|
|
1157
|
+
>
|
|
1158
|
+
<input
|
|
1159
|
+
matSliderThumb
|
|
1160
|
+
[field]="f"
|
|
1161
|
+
[attr.tabindex]="tabIndex()"
|
|
1162
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
1163
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1164
|
+
/>
|
|
1165
|
+
</mat-slider>
|
|
1166
|
+
|
|
1167
|
+
@if (props()?.hint; as hint) {
|
|
1168
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
1169
|
+
}
|
|
1170
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1171
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1172
|
+
}
|
|
1173
|
+
`, host: {
|
|
1174
|
+
'[class]': 'className()',
|
|
1175
|
+
'[id]': '`${key()}`',
|
|
1176
|
+
'[attr.data-testid]': 'key()',
|
|
1177
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
1178
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}.slider-container{width:100%}\n"] }]
|
|
1179
|
+
}], 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 }] }] } });
|
|
1180
|
+
|
|
1181
|
+
var matSlider_component = /*#__PURE__*/Object.freeze({
|
|
1182
|
+
__proto__: null,
|
|
1183
|
+
default: MatSliderFieldComponent
|
|
1184
|
+
});
|
|
1185
|
+
|
|
1186
|
+
class MatButtonFieldComponent {
|
|
1187
|
+
eventBus = inject(EventBus);
|
|
1188
|
+
arrayContext = inject(ARRAY_CONTEXT, { optional: true });
|
|
1189
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
1190
|
+
label = input.required({ ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
1191
|
+
disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : {}) });
|
|
1192
|
+
hidden = input(false, { ...(ngDevMode ? { debugName: "hidden" } : {}) });
|
|
1193
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
1194
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
1195
|
+
/** Event to dispatch on click. Optional for submit buttons (native form submit handles it). */
|
|
1196
|
+
event = input(undefined, { ...(ngDevMode ? { debugName: "event" } : {}) });
|
|
1197
|
+
eventArgs = input(undefined, { ...(ngDevMode ? { debugName: "eventArgs" } : {}) });
|
|
1198
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
1199
|
+
eventContext = input(undefined, { ...(ngDevMode ? { debugName: "eventContext" } : {}) });
|
|
1200
|
+
/** Resolved button type - defaults to 'button' if not specified in props */
|
|
1201
|
+
buttonType = computed(() => this.props()?.type ?? 'button', { ...(ngDevMode ? { debugName: "buttonType" } : {}) });
|
|
1202
|
+
buttonTestId = computed(() => `${this.buttonType()}-${this.key()}`, { ...(ngDevMode ? { debugName: "buttonTestId" } : {}) });
|
|
1203
|
+
/**
|
|
1204
|
+
* Handle button click.
|
|
1205
|
+
* - For submit buttons (type="submit"): do nothing, native form submit handles it
|
|
1206
|
+
* - For other buttons: dispatch the configured event via EventBus
|
|
1207
|
+
*/
|
|
1208
|
+
onClick() {
|
|
1209
|
+
// Native submit buttons let the form handle submission
|
|
1210
|
+
if (this.buttonType() === 'submit') {
|
|
1211
|
+
return;
|
|
1212
|
+
}
|
|
1213
|
+
// Other buttons dispatch their event (if configured)
|
|
1214
|
+
const event = this.event();
|
|
1215
|
+
if (event) {
|
|
1216
|
+
this.dispatchEvent(event);
|
|
1217
|
+
}
|
|
1218
|
+
}
|
|
1219
|
+
dispatchEvent(event) {
|
|
1220
|
+
const args = this.eventArgs();
|
|
1221
|
+
if (args && args.length > 0) {
|
|
1222
|
+
// Build context from injected ARRAY_CONTEXT (with linkedSignal index) or fallback to eventContext
|
|
1223
|
+
const context = this.arrayContext
|
|
1224
|
+
? {
|
|
1225
|
+
key: this.key(),
|
|
1226
|
+
// Read signal to get current index (automatically updates via linkedSignal)
|
|
1227
|
+
index: this.arrayContext.index(),
|
|
1228
|
+
arrayKey: this.arrayContext.arrayKey,
|
|
1229
|
+
formValue: this.arrayContext.formValue,
|
|
1230
|
+
}
|
|
1231
|
+
: this.eventContext() || { key: this.key() };
|
|
1232
|
+
// Resolve tokens in event args using the provided context
|
|
1233
|
+
const resolvedArgs = resolveTokens(args, context);
|
|
1234
|
+
// Dispatch event with resolved args
|
|
1235
|
+
this.eventBus.dispatch(event, ...resolvedArgs);
|
|
1236
|
+
}
|
|
1237
|
+
else {
|
|
1238
|
+
// No args, dispatch event without arguments
|
|
1239
|
+
this.eventBus.dispatch(event);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatButtonFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1243
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "21.0.1", type: MatButtonFieldComponent, isStandalone: true, selector: "df-mat-button", inputs: { key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: true, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, hidden: { classPropertyName: "hidden", publicName: "hidden", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, event: { classPropertyName: "event", publicName: "event", isSignal: true, isRequired: false, transformFunction: null }, eventArgs: { classPropertyName: "eventArgs", publicName: "eventArgs", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, eventContext: { classPropertyName: "eventContext", publicName: "eventContext", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()" } }, ngImport: i0, template: `
|
|
1244
|
+
<button
|
|
1245
|
+
mat-raised-button
|
|
1246
|
+
[type]="buttonType()"
|
|
1247
|
+
[color]="props()?.color || 'primary'"
|
|
1248
|
+
[disabled]="disabled()"
|
|
1249
|
+
[attr.data-testid]="buttonTestId()"
|
|
1250
|
+
(click)="onClick()"
|
|
1251
|
+
>
|
|
1252
|
+
{{ label() | dynamicText | async }}
|
|
1253
|
+
</button>
|
|
1254
|
+
`, isInline: true, styles: [":host{display:block}button{min-width:fit-content}\n"], dependencies: [{ kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1255
|
+
}
|
|
1256
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatButtonFieldComponent, decorators: [{
|
|
1257
|
+
type: Component,
|
|
1258
|
+
args: [{ selector: 'df-mat-button', imports: [MatButton, DynamicTextPipe, AsyncPipe], host: {
|
|
1259
|
+
'[id]': '`${key()}`',
|
|
1260
|
+
'[attr.data-testid]': 'key()',
|
|
1261
|
+
'[class]': 'className()',
|
|
1262
|
+
}, template: `
|
|
1263
|
+
<button
|
|
1264
|
+
mat-raised-button
|
|
1265
|
+
[type]="buttonType()"
|
|
1266
|
+
[color]="props()?.color || 'primary'"
|
|
1267
|
+
[disabled]="disabled()"
|
|
1268
|
+
[attr.data-testid]="buttonTestId()"
|
|
1269
|
+
(click)="onClick()"
|
|
1270
|
+
>
|
|
1271
|
+
{{ label() | dynamicText | async }}
|
|
1272
|
+
</button>
|
|
1273
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}button{min-width:fit-content}\n"] }]
|
|
1274
|
+
}], propDecorators: { key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: true }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], hidden: [{ type: i0.Input, args: [{ isSignal: true, alias: "hidden", required: false }] }], tabIndex: [{ type: i0.Input, args: [{ isSignal: true, alias: "tabIndex", required: false }] }], className: [{ type: i0.Input, args: [{ isSignal: true, alias: "className", required: false }] }], event: [{ type: i0.Input, args: [{ isSignal: true, alias: "event", required: false }] }], eventArgs: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventArgs", required: false }] }], props: [{ type: i0.Input, args: [{ isSignal: true, alias: "props", required: false }] }], eventContext: [{ type: i0.Input, args: [{ isSignal: true, alias: "eventContext", required: false }] }] } });
|
|
1275
|
+
|
|
1276
|
+
var matButton_component = /*#__PURE__*/Object.freeze({
|
|
1277
|
+
__proto__: null,
|
|
1278
|
+
default: MatButtonFieldComponent
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
// Public API - component
|
|
1282
|
+
|
|
1283
|
+
class MatTextareaFieldComponent {
|
|
1284
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
1285
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
1286
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
1287
|
+
/**
|
|
1288
|
+
* Reference to the native textarea element.
|
|
1289
|
+
* Used to imperatively sync the readonly attribute since Angular Signal Forms'
|
|
1290
|
+
* [field] directive doesn't sync FieldState.readonly() to the DOM.
|
|
1291
|
+
*/
|
|
1292
|
+
textareaRef = viewChild('textareaRef', { ...(ngDevMode ? { debugName: "textareaRef" } : {}) });
|
|
1293
|
+
/**
|
|
1294
|
+
* Computed signal that extracts the readonly state from the field.
|
|
1295
|
+
* Used by the effect to reactively sync the readonly attribute to the DOM.
|
|
1296
|
+
*/
|
|
1297
|
+
isReadonly = computed(() => this.field()().readonly(), { ...(ngDevMode ? { debugName: "isReadonly" } : {}) });
|
|
1298
|
+
/**
|
|
1299
|
+
* Workaround: Angular Signal Forms' [field] directive does NOT sync the readonly
|
|
1300
|
+
* attribute to the DOM, even though FieldState.readonly() returns the correct value.
|
|
1301
|
+
* This effect imperatively sets/removes the readonly attribute on the native textarea
|
|
1302
|
+
* element whenever the readonly state changes.
|
|
1303
|
+
*
|
|
1304
|
+
* Note: We cannot use [readonly] or [attr.readonly] bindings because Angular throws
|
|
1305
|
+
* NG8022: "Binding to '[readonly]' is not allowed on nodes using the '[field]' directive"
|
|
1306
|
+
*
|
|
1307
|
+
* @see https://github.com/angular/angular/issues/65897
|
|
1308
|
+
*/
|
|
1309
|
+
syncReadonlyToDom = explicitEffect([this.textareaRef, this.isReadonly], ([textareaRef, isReadonly]) => {
|
|
1310
|
+
if (textareaRef?.nativeElement) {
|
|
1311
|
+
if (isReadonly) {
|
|
1312
|
+
textareaRef.nativeElement.setAttribute('readonly', '');
|
|
1313
|
+
}
|
|
1314
|
+
else {
|
|
1315
|
+
textareaRef.nativeElement.removeAttribute('readonly');
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
1320
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
1321
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
1322
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
1323
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
1324
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
1325
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
1326
|
+
effectiveAppearance = computed(() => this.props()?.appearance ?? this.materialConfig?.appearance ?? 'outline', { ...(ngDevMode ? { debugName: "effectiveAppearance" } : {}) });
|
|
1327
|
+
effectiveSubscriptSizing = computed(() => this.props()?.subscriptSizing ?? this.materialConfig?.subscriptSizing ?? 'dynamic', { ...(ngDevMode ? { debugName: "effectiveSubscriptSizing" } : {}) });
|
|
1328
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
1329
|
+
showErrors = shouldShowErrors(this.field);
|
|
1330
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
1331
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1332
|
+
// Accessibility
|
|
1333
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1334
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
1335
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
1336
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
1337
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
1338
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
1339
|
+
ariaInvalid = computed(() => {
|
|
1340
|
+
const fieldState = this.field()();
|
|
1341
|
+
return fieldState.invalid() && fieldState.touched();
|
|
1342
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
1343
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
1344
|
+
ariaRequired = computed(() => {
|
|
1345
|
+
return this.field()().required?.() === true ? true : null;
|
|
1346
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
1347
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
1348
|
+
ariaDescribedBy = computed(() => {
|
|
1349
|
+
const ids = [];
|
|
1350
|
+
if (this.props()?.hint) {
|
|
1351
|
+
ids.push(this.hintId());
|
|
1352
|
+
}
|
|
1353
|
+
const errors = this.errorsToDisplay();
|
|
1354
|
+
errors.forEach((_, i) => {
|
|
1355
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
1356
|
+
});
|
|
1357
|
+
return ids.length > 0 ? ids.join(' ') : null;
|
|
1358
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
1359
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatTextareaFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1360
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatTextareaFieldComponent, isStandalone: true, selector: "df-mat-textarea", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, validationMessages: { classPropertyName: "validationMessages", publicName: "validationMessages", isSignal: true, isRequired: false, transformFunction: null }, defaultValidationMessages: { classPropertyName: "defaultValidationMessages", publicName: "defaultValidationMessages", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "id": "`${key()}`", "attr.data-testid": "key()", "class": "className()", "attr.hidden": "field()().hidden() || null" } }, viewQueries: [{ propertyName: "textareaRef", first: true, predicate: ["textareaRef"], descendants: true, isSignal: true }], ngImport: i0, template: `
|
|
1361
|
+
@let f = field();
|
|
1362
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
1363
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1364
|
+
|
|
1365
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
1366
|
+
@if (label()) {
|
|
1367
|
+
<mat-label>{{ label() | dynamicText | async }}</mat-label>
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
<textarea
|
|
1371
|
+
#textareaRef
|
|
1372
|
+
matInput
|
|
1373
|
+
[field]="f"
|
|
1374
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
1375
|
+
[rows]="props()?.rows || 4"
|
|
1376
|
+
[cols]="props()?.cols"
|
|
1377
|
+
[attr.tabindex]="tabIndex()"
|
|
1378
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
1379
|
+
[attr.aria-required]="ariaRequired"
|
|
1380
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1381
|
+
[style.resize]="props()?.resize || 'vertical'"
|
|
1382
|
+
></textarea>
|
|
1383
|
+
|
|
1384
|
+
@if (props()?.hint; as hint) {
|
|
1385
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
1386
|
+
}
|
|
1387
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1388
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1389
|
+
}
|
|
1390
|
+
</mat-form-field>
|
|
1391
|
+
`, isInline: true, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"], dependencies: [{ kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError$1, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1392
|
+
}
|
|
1393
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatTextareaFieldComponent, decorators: [{
|
|
1394
|
+
type: Component,
|
|
1395
|
+
args: [{ selector: 'df-mat-textarea', imports: [MatFormField, MatLabel, MatInput, MatHint, Field, MatError$1, DynamicTextPipe, AsyncPipe], template: `
|
|
1396
|
+
@let f = field();
|
|
1397
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
1398
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1399
|
+
|
|
1400
|
+
<mat-form-field [appearance]="effectiveAppearance()" [subscriptSizing]="effectiveSubscriptSizing()">
|
|
1401
|
+
@if (label()) {
|
|
1402
|
+
<mat-label>{{ label() | dynamicText | async }}</mat-label>
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
<textarea
|
|
1406
|
+
#textareaRef
|
|
1407
|
+
matInput
|
|
1408
|
+
[field]="f"
|
|
1409
|
+
[placeholder]="(placeholder() | dynamicText | async) ?? ''"
|
|
1410
|
+
[rows]="props()?.rows || 4"
|
|
1411
|
+
[cols]="props()?.cols"
|
|
1412
|
+
[attr.tabindex]="tabIndex()"
|
|
1413
|
+
[attr.aria-invalid]="ariaInvalid"
|
|
1414
|
+
[attr.aria-required]="ariaRequired"
|
|
1415
|
+
[attr.aria-describedby]="ariaDescribedBy"
|
|
1416
|
+
[style.resize]="props()?.resize || 'vertical'"
|
|
1417
|
+
></textarea>
|
|
1418
|
+
|
|
1419
|
+
@if (props()?.hint; as hint) {
|
|
1420
|
+
<mat-hint [id]="hintId()">{{ hint | dynamicText | async }}</mat-hint>
|
|
1421
|
+
}
|
|
1422
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1423
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1424
|
+
}
|
|
1425
|
+
</mat-form-field>
|
|
1426
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, host: {
|
|
1427
|
+
'[id]': '`${key()}`',
|
|
1428
|
+
'[attr.data-testid]': 'key()',
|
|
1429
|
+
'[class]': 'className()',
|
|
1430
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
1431
|
+
}, styles: [":host{display:block;width:100%}:host([hidden]){display:none!important}mat-form-field{width:100%}\n"] }]
|
|
1432
|
+
}], propDecorators: { field: [{ type: i0.Input, args: [{ isSignal: true, alias: "field", required: true }] }], key: [{ type: i0.Input, args: [{ isSignal: true, alias: "key", required: true }] }], textareaRef: [{ type: i0.ViewChild, args: ['textareaRef', { isSignal: 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 }] }] } });
|
|
1433
|
+
|
|
1434
|
+
var matTextarea_component = /*#__PURE__*/Object.freeze({
|
|
1435
|
+
__proto__: null,
|
|
1436
|
+
default: MatTextareaFieldComponent
|
|
1437
|
+
});
|
|
1438
|
+
|
|
1439
|
+
class MatToggleFieldComponent {
|
|
1440
|
+
materialConfig = inject(MATERIAL_CONFIG, { optional: true });
|
|
1441
|
+
field = input.required({ ...(ngDevMode ? { debugName: "field" } : {}) });
|
|
1442
|
+
key = input.required({ ...(ngDevMode ? { debugName: "key" } : {}) });
|
|
1443
|
+
label = input(undefined, { ...(ngDevMode ? { debugName: "label" } : {}) });
|
|
1444
|
+
placeholder = input(undefined, { ...(ngDevMode ? { debugName: "placeholder" } : {}) });
|
|
1445
|
+
className = input('', { ...(ngDevMode ? { debugName: "className" } : {}) });
|
|
1446
|
+
tabIndex = input(undefined, { ...(ngDevMode ? { debugName: "tabIndex" } : {}) });
|
|
1447
|
+
props = input(undefined, { ...(ngDevMode ? { debugName: "props" } : {}) });
|
|
1448
|
+
validationMessages = input(undefined, { ...(ngDevMode ? { debugName: "validationMessages" } : {}) });
|
|
1449
|
+
defaultValidationMessages = input(undefined, { ...(ngDevMode ? { debugName: "defaultValidationMessages" } : {}) });
|
|
1450
|
+
effectiveDisableRipple = computed(() => this.props()?.disableRipple ?? this.materialConfig?.disableRipple ?? false, { ...(ngDevMode ? { debugName: "effectiveDisableRipple" } : {}) });
|
|
1451
|
+
resolvedErrors = createResolvedErrorsSignal(this.field, this.validationMessages, this.defaultValidationMessages);
|
|
1452
|
+
showErrors = shouldShowErrors(this.field);
|
|
1453
|
+
errorsToDisplay = computed(() => (this.showErrors() ? this.resolvedErrors() : []), { ...(ngDevMode ? { debugName: "errorsToDisplay" } : {}) });
|
|
1454
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1455
|
+
// Accessibility
|
|
1456
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
1457
|
+
/** Unique ID for the hint element, used for aria-describedby */
|
|
1458
|
+
hintId = computed(() => `${this.key()}-hint`, { ...(ngDevMode ? { debugName: "hintId" } : {}) });
|
|
1459
|
+
/** Base ID for error elements, used for aria-describedby */
|
|
1460
|
+
errorId = computed(() => `${this.key()}-error`, { ...(ngDevMode ? { debugName: "errorId" } : {}) });
|
|
1461
|
+
/** aria-invalid: true when field is invalid AND touched, false otherwise */
|
|
1462
|
+
ariaInvalid = computed(() => {
|
|
1463
|
+
const fieldState = this.field()();
|
|
1464
|
+
return fieldState.invalid() && fieldState.touched();
|
|
1465
|
+
}, { ...(ngDevMode ? { debugName: "ariaInvalid" } : {}) });
|
|
1466
|
+
/** aria-required: true if field is required, null otherwise (to remove attribute) */
|
|
1467
|
+
ariaRequired = computed(() => {
|
|
1468
|
+
return this.field()().required?.() === true ? true : null;
|
|
1469
|
+
}, { ...(ngDevMode ? { debugName: "ariaRequired" } : {}) });
|
|
1470
|
+
/** aria-describedby: links to hint and error messages for screen readers */
|
|
1471
|
+
ariaDescribedBy = computed(() => {
|
|
1472
|
+
const ids = [];
|
|
1473
|
+
if (this.props()?.hint) {
|
|
1474
|
+
ids.push(this.hintId());
|
|
1475
|
+
}
|
|
1476
|
+
const errors = this.errorsToDisplay();
|
|
1477
|
+
errors.forEach((_, i) => {
|
|
1478
|
+
ids.push(`${this.errorId()}-${i}`);
|
|
1479
|
+
});
|
|
1480
|
+
return ids.join(' ');
|
|
1481
|
+
}, { ...(ngDevMode ? { debugName: "ariaDescribedBy" } : {}) });
|
|
1482
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatToggleFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1483
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.0.1", type: MatToggleFieldComponent, isStandalone: true, selector: "df-mat-toggle", inputs: { field: { classPropertyName: "field", publicName: "field", isSignal: true, isRequired: true, transformFunction: null }, key: { classPropertyName: "key", publicName: "key", isSignal: true, isRequired: true, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, className: { classPropertyName: "className", publicName: "className", isSignal: true, isRequired: false, transformFunction: null }, tabIndex: { classPropertyName: "tabIndex", publicName: "tabIndex", isSignal: true, isRequired: false, transformFunction: null }, props: { classPropertyName: "props", publicName: "props", isSignal: true, isRequired: false, transformFunction: null }, 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: `
|
|
1484
|
+
@let f = field();
|
|
1485
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
1486
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1487
|
+
|
|
1488
|
+
<mat-slide-toggle
|
|
1489
|
+
[field]="f"
|
|
1490
|
+
[color]="props()?.color || 'primary'"
|
|
1491
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
1492
|
+
[hideIcon]="props()?.hideIcon || false"
|
|
1493
|
+
[disableRipple]="effectiveDisableRipple()"
|
|
1494
|
+
[required]="!!f().required?.()"
|
|
1495
|
+
[aria-describedby]="ariaDescribedBy"
|
|
1496
|
+
[attr.tabindex]="tabIndex()"
|
|
1497
|
+
class="toggle-container"
|
|
1498
|
+
>
|
|
1499
|
+
{{ label() | dynamicText | async }}
|
|
1500
|
+
</mat-slide-toggle>
|
|
1501
|
+
|
|
1502
|
+
@if (props()?.hint; as hint) {
|
|
1503
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
1504
|
+
}
|
|
1505
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1506
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1507
|
+
}
|
|
1508
|
+
`, isInline: true, styles: [":host{display:block}:host([hidden]){display:none!important}\n"], dependencies: [{ kind: "component", type: MatSlideToggle, selector: "mat-slide-toggle", inputs: ["name", "id", "labelPosition", "aria-label", "aria-labelledby", "aria-describedby", "required", "color", "disabled", "disableRipple", "tabIndex", "checked", "hideIcon", "disabledInteractive"], outputs: ["change", "toggleChange"], exportAs: ["matSlideToggle"] }, { kind: "directive", type: Field, selector: "[field]", inputs: ["field"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "pipe", type: DynamicTextPipe, name: "dynamicText" }, { kind: "pipe", type: AsyncPipe, name: "async" }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
|
|
1509
|
+
}
|
|
1510
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.0.1", ngImport: i0, type: MatToggleFieldComponent, decorators: [{
|
|
1511
|
+
type: Component,
|
|
1512
|
+
args: [{ selector: 'df-mat-toggle', imports: [MatSlideToggle, Field, MatError, DynamicTextPipe, AsyncPipe], template: `
|
|
1513
|
+
@let f = field();
|
|
1514
|
+
@let ariaInvalid = this.ariaInvalid(); @let ariaRequired = this.ariaRequired();
|
|
1515
|
+
@let ariaDescribedBy = this.ariaDescribedBy();
|
|
1516
|
+
|
|
1517
|
+
<mat-slide-toggle
|
|
1518
|
+
[field]="f"
|
|
1519
|
+
[color]="props()?.color || 'primary'"
|
|
1520
|
+
[labelPosition]="props()?.labelPosition || 'after'"
|
|
1521
|
+
[hideIcon]="props()?.hideIcon || false"
|
|
1522
|
+
[disableRipple]="effectiveDisableRipple()"
|
|
1523
|
+
[required]="!!f().required?.()"
|
|
1524
|
+
[aria-describedby]="ariaDescribedBy"
|
|
1525
|
+
[attr.tabindex]="tabIndex()"
|
|
1526
|
+
class="toggle-container"
|
|
1527
|
+
>
|
|
1528
|
+
{{ label() | dynamicText | async }}
|
|
1529
|
+
</mat-slide-toggle>
|
|
1530
|
+
|
|
1531
|
+
@if (props()?.hint; as hint) {
|
|
1532
|
+
<div class="mat-hint" [id]="hintId()">{{ hint | dynamicText | async }}</div>
|
|
1533
|
+
}
|
|
1534
|
+
@for (error of errorsToDisplay(); track error.kind; let i = $index) {
|
|
1535
|
+
<mat-error [id]="errorId() + '-' + i">{{ error.message }}</mat-error>
|
|
1536
|
+
}
|
|
1537
|
+
`, host: {
|
|
1538
|
+
'[class]': 'className()',
|
|
1539
|
+
'[id]': '`${key()}`',
|
|
1540
|
+
'[attr.data-testid]': 'key()',
|
|
1541
|
+
'[attr.hidden]': 'field()().hidden() || null',
|
|
1542
|
+
}, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}:host([hidden]){display:none!important}\n"] }]
|
|
1543
|
+
}], 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 }] }] } });
|
|
1544
|
+
|
|
1545
|
+
var matToggle_component = /*#__PURE__*/Object.freeze({
|
|
1546
|
+
__proto__: null,
|
|
1547
|
+
default: MatToggleFieldComponent
|
|
1548
|
+
});
|
|
1549
|
+
|
|
1550
|
+
// Public exports for material field components and types
|
|
1551
|
+
|
|
1552
|
+
/**
|
|
1553
|
+
* Material Design field type constants
|
|
1554
|
+
* Based on available field components in the /fields folder
|
|
1555
|
+
*/
|
|
1556
|
+
const MatField = {
|
|
1557
|
+
Input: 'input',
|
|
1558
|
+
Select: 'select',
|
|
1559
|
+
Checkbox: 'checkbox',
|
|
1560
|
+
Button: 'button',
|
|
1561
|
+
Submit: 'submit',
|
|
1562
|
+
Next: 'next',
|
|
1563
|
+
Previous: 'previous',
|
|
1564
|
+
AddArrayItem: 'addArrayItem',
|
|
1565
|
+
RemoveArrayItem: 'removeArrayItem',
|
|
1566
|
+
Textarea: 'textarea',
|
|
1567
|
+
Radio: 'radio',
|
|
1568
|
+
MultiCheckbox: 'multi-checkbox',
|
|
1569
|
+
Datepicker: 'datepicker',
|
|
1570
|
+
Slider: 'slider',
|
|
1571
|
+
Toggle: 'toggle',
|
|
1572
|
+
};
|
|
1573
|
+
|
|
1574
|
+
/**
|
|
1575
|
+
* Generic button mapper for custom events or basic buttons.
|
|
1576
|
+
* For specific button types (submit, next, prev, add/remove array items),
|
|
1577
|
+
* use the dedicated field types and their specific mappers.
|
|
1578
|
+
*
|
|
1579
|
+
* @param fieldDef The button field definition
|
|
1580
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1581
|
+
*/
|
|
1582
|
+
function buttonFieldMapper(fieldDef) {
|
|
1583
|
+
// Build base inputs (static, from field definition)
|
|
1584
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1585
|
+
return computed(() => {
|
|
1586
|
+
const inputs = {
|
|
1587
|
+
...baseInputs,
|
|
1588
|
+
};
|
|
1589
|
+
if (fieldDef.disabled !== undefined) {
|
|
1590
|
+
inputs['disabled'] = fieldDef.disabled;
|
|
1591
|
+
}
|
|
1592
|
+
if (fieldDef.hidden !== undefined) {
|
|
1593
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1594
|
+
}
|
|
1595
|
+
// Add event binding for button events
|
|
1596
|
+
if ('event' in fieldDef && fieldDef.event !== undefined) {
|
|
1597
|
+
inputs['event'] = fieldDef.event;
|
|
1598
|
+
}
|
|
1599
|
+
// Add eventArgs binding if provided
|
|
1600
|
+
if ('eventArgs' in fieldDef && fieldDef.eventArgs !== undefined) {
|
|
1601
|
+
inputs['eventArgs'] = fieldDef.eventArgs;
|
|
1602
|
+
}
|
|
1603
|
+
return inputs;
|
|
1604
|
+
});
|
|
1605
|
+
}
|
|
1606
|
+
|
|
1607
|
+
/**
|
|
1608
|
+
* Mapper for submit button - configures native form submission via type="submit"
|
|
1609
|
+
*
|
|
1610
|
+
* Unlike other buttons, submit buttons don't dispatch events directly.
|
|
1611
|
+
* Instead, they trigger native form submission which the form component
|
|
1612
|
+
* intercepts and dispatches to the EventBus.
|
|
1613
|
+
*
|
|
1614
|
+
* Disabled state is resolved using the button-logic-resolver which considers:
|
|
1615
|
+
* 1. Explicit `disabled: true` on the field definition
|
|
1616
|
+
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
1617
|
+
* 3. Form-level `options.submitButton` defaults (disableWhenInvalid, disableWhileSubmitting)
|
|
1618
|
+
*
|
|
1619
|
+
* @param fieldDef The submit button field definition
|
|
1620
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1621
|
+
*/
|
|
1622
|
+
function submitButtonFieldMapper(fieldDef) {
|
|
1623
|
+
// Inject field signal context to access form state and options
|
|
1624
|
+
const fieldSignalContext = inject(FIELD_SIGNAL_CONTEXT);
|
|
1625
|
+
// Build base inputs (static, from field definition)
|
|
1626
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1627
|
+
// Use button-logic-resolver to compute disabled state
|
|
1628
|
+
const fieldWithLogic = fieldDef;
|
|
1629
|
+
const disabledSignal = resolveSubmitButtonDisabled({
|
|
1630
|
+
form: fieldSignalContext.form,
|
|
1631
|
+
formOptions: fieldSignalContext.formOptions,
|
|
1632
|
+
fieldLogic: fieldWithLogic.logic,
|
|
1633
|
+
explicitlyDisabled: fieldDef.disabled,
|
|
1634
|
+
});
|
|
1635
|
+
// Return computed signal - evaluates disabledSignal inside for reactivity
|
|
1636
|
+
return computed(() => {
|
|
1637
|
+
const inputs = {
|
|
1638
|
+
...baseInputs,
|
|
1639
|
+
// No event - native form submit handles it via form's onNativeSubmit
|
|
1640
|
+
// Set type="submit" to trigger native form submission
|
|
1641
|
+
props: { ...fieldDef.props, type: 'submit' },
|
|
1642
|
+
// Evaluate the signal inside the computed - component receives plain boolean
|
|
1643
|
+
disabled: disabledSignal(),
|
|
1644
|
+
};
|
|
1645
|
+
if (fieldDef.hidden !== undefined) {
|
|
1646
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1647
|
+
}
|
|
1648
|
+
return inputs;
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Mapper for next page button - preconfigures NextPageEvent
|
|
1653
|
+
*
|
|
1654
|
+
* Disabled state is resolved using the button-logic-resolver which considers:
|
|
1655
|
+
* 1. Explicit `disabled: true` on the field definition
|
|
1656
|
+
* 2. Field-level `logic` array (if present, overrides form-level defaults)
|
|
1657
|
+
* 3. Form-level `options.nextButton` defaults (disableWhenPageInvalid, disableWhileSubmitting)
|
|
1658
|
+
*
|
|
1659
|
+
* @param fieldDef The next button field definition
|
|
1660
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1661
|
+
*/
|
|
1662
|
+
function nextButtonFieldMapper(fieldDef) {
|
|
1663
|
+
// Inject field signal context to access form state and options
|
|
1664
|
+
const fieldSignalContext = inject(FIELD_SIGNAL_CONTEXT);
|
|
1665
|
+
// Build base inputs (static, from field definition)
|
|
1666
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1667
|
+
// Use button-logic-resolver to compute disabled state
|
|
1668
|
+
const fieldWithLogic = fieldDef;
|
|
1669
|
+
const disabledSignal = resolveNextButtonDisabled({
|
|
1670
|
+
form: fieldSignalContext.form,
|
|
1671
|
+
formOptions: fieldSignalContext.formOptions,
|
|
1672
|
+
fieldLogic: fieldWithLogic.logic,
|
|
1673
|
+
explicitlyDisabled: fieldDef.disabled,
|
|
1674
|
+
currentPageValid: fieldSignalContext.currentPageValid,
|
|
1675
|
+
});
|
|
1676
|
+
// Return computed signal - evaluates disabledSignal inside for reactivity
|
|
1677
|
+
return computed(() => {
|
|
1678
|
+
const inputs = {
|
|
1679
|
+
...baseInputs,
|
|
1680
|
+
event: NextPageEvent,
|
|
1681
|
+
// Evaluate the signal inside the computed - component receives plain boolean
|
|
1682
|
+
disabled: disabledSignal(),
|
|
1683
|
+
};
|
|
1684
|
+
if (fieldDef.hidden !== undefined) {
|
|
1685
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1686
|
+
}
|
|
1687
|
+
return inputs;
|
|
1688
|
+
});
|
|
1689
|
+
}
|
|
1690
|
+
/**
|
|
1691
|
+
* Mapper for previous page button - preconfigures PreviousPageEvent
|
|
1692
|
+
* Note: Does not auto-disable based on validation. Users can explicitly disable if needed.
|
|
1693
|
+
*
|
|
1694
|
+
* @param fieldDef The previous button field definition
|
|
1695
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1696
|
+
*/
|
|
1697
|
+
function previousButtonFieldMapper(fieldDef) {
|
|
1698
|
+
// Build base inputs (static, from field definition)
|
|
1699
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1700
|
+
return computed(() => {
|
|
1701
|
+
const inputs = {
|
|
1702
|
+
...baseInputs,
|
|
1703
|
+
event: PreviousPageEvent,
|
|
1704
|
+
};
|
|
1705
|
+
// Add disabled binding only if explicitly set by user
|
|
1706
|
+
if (fieldDef.disabled !== undefined) {
|
|
1707
|
+
inputs['disabled'] = fieldDef.disabled;
|
|
1708
|
+
}
|
|
1709
|
+
if (fieldDef.hidden !== undefined) {
|
|
1710
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1711
|
+
}
|
|
1712
|
+
return inputs;
|
|
1713
|
+
});
|
|
1714
|
+
}
|
|
1715
|
+
/**
|
|
1716
|
+
* Mapper for add array item button - preconfigures AddArrayItemEvent with array context.
|
|
1717
|
+
*
|
|
1718
|
+
* Supports two modes:
|
|
1719
|
+
* 1. Inside array template: Uses ARRAY_CONTEXT to determine target array
|
|
1720
|
+
* 2. Outside array: Uses `arrayKey` property from field definition
|
|
1721
|
+
*
|
|
1722
|
+
* @param fieldDef The add array item button field definition
|
|
1723
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1724
|
+
*/
|
|
1725
|
+
function addArrayItemButtonFieldMapper(fieldDef) {
|
|
1726
|
+
// Try to get array context (available when inside an array)
|
|
1727
|
+
// Use optional injection so it doesn't fail when outside an array
|
|
1728
|
+
const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
|
|
1729
|
+
// Determine the target array key
|
|
1730
|
+
// Priority: explicit arrayKey from fieldDef > arrayKey from context
|
|
1731
|
+
const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
|
|
1732
|
+
if (!targetArrayKey) {
|
|
1733
|
+
console.warn(`[Dynamic Forms] addArrayItem button "${fieldDef.key}" has no array context. ` +
|
|
1734
|
+
'Either place it inside an array field, or provide an explicit arrayKey property.');
|
|
1735
|
+
}
|
|
1736
|
+
// Build base inputs (static, from field definition)
|
|
1737
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1738
|
+
// Set default eventArgs for AddArrayItemEvent (arrayKey)
|
|
1739
|
+
// User can override by providing eventArgs in field definition
|
|
1740
|
+
const defaultEventArgs = ['$arrayKey'];
|
|
1741
|
+
const eventArgs = 'eventArgs' in fieldDef && fieldDef.eventArgs !== undefined ? fieldDef.eventArgs : defaultEventArgs;
|
|
1742
|
+
return computed(() => {
|
|
1743
|
+
// Read signal value if index is a signal (supports differential updates)
|
|
1744
|
+
const getIndex = () => {
|
|
1745
|
+
if (!arrayContext)
|
|
1746
|
+
return -1;
|
|
1747
|
+
return isSignal(arrayContext.index) ? arrayContext.index() : arrayContext.index;
|
|
1748
|
+
};
|
|
1749
|
+
const inputs = {
|
|
1750
|
+
...baseInputs,
|
|
1751
|
+
event: AddArrayItemEvent,
|
|
1752
|
+
eventArgs,
|
|
1753
|
+
eventContext: {
|
|
1754
|
+
key: fieldDef.key,
|
|
1755
|
+
index: getIndex(),
|
|
1756
|
+
arrayKey: targetArrayKey ?? '',
|
|
1757
|
+
formValue: arrayContext?.formValue ?? {},
|
|
1758
|
+
},
|
|
1759
|
+
};
|
|
1760
|
+
// Add disabled binding only if explicitly set by user
|
|
1761
|
+
if (fieldDef.disabled !== undefined) {
|
|
1762
|
+
inputs['disabled'] = fieldDef.disabled;
|
|
1763
|
+
}
|
|
1764
|
+
if (fieldDef.hidden !== undefined) {
|
|
1765
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1766
|
+
}
|
|
1767
|
+
return inputs;
|
|
1768
|
+
});
|
|
1769
|
+
}
|
|
1770
|
+
/**
|
|
1771
|
+
* Mapper for remove array item button - preconfigures RemoveArrayItemEvent with array context.
|
|
1772
|
+
*
|
|
1773
|
+
* Supports two modes:
|
|
1774
|
+
* 1. Inside array template: Uses ARRAY_CONTEXT to determine target array and removes item at current index
|
|
1775
|
+
* 2. Outside array: Uses `arrayKey` property from field definition, removes last item by default
|
|
1776
|
+
*
|
|
1777
|
+
* @param fieldDef The remove array item button field definition
|
|
1778
|
+
* @returns Signal containing Record of input names to values for ngComponentOutlet
|
|
1779
|
+
*/
|
|
1780
|
+
function removeArrayItemButtonFieldMapper(fieldDef) {
|
|
1781
|
+
// Try to get array context (available when inside an array)
|
|
1782
|
+
// Use optional injection so it doesn't fail when outside an array
|
|
1783
|
+
const arrayContext = inject(ARRAY_CONTEXT, { optional: true });
|
|
1784
|
+
// Determine the target array key
|
|
1785
|
+
// Priority: explicit arrayKey from fieldDef > arrayKey from context
|
|
1786
|
+
const targetArrayKey = fieldDef.arrayKey ?? arrayContext?.arrayKey;
|
|
1787
|
+
if (!targetArrayKey) {
|
|
1788
|
+
console.warn(`[Dynamic Forms] removeArrayItem button "${fieldDef.key}" has no array context. ` +
|
|
1789
|
+
'Either place it inside an array field, or provide an explicit arrayKey property.');
|
|
1790
|
+
}
|
|
1791
|
+
// Build base inputs (static, from field definition)
|
|
1792
|
+
const baseInputs = buildBaseInputs(fieldDef);
|
|
1793
|
+
// Set default eventArgs for RemoveArrayItemEvent (arrayKey, index if inside array)
|
|
1794
|
+
// When outside array, only pass arrayKey (removes last by default)
|
|
1795
|
+
// User can override by providing eventArgs in field definition
|
|
1796
|
+
const defaultEventArgs = arrayContext ? ['$arrayKey', '$index'] : ['$arrayKey'];
|
|
1797
|
+
const eventArgs = 'eventArgs' in fieldDef && fieldDef.eventArgs !== undefined ? fieldDef.eventArgs : defaultEventArgs;
|
|
1798
|
+
return computed(() => {
|
|
1799
|
+
// Read signal value if index is a signal (supports differential updates)
|
|
1800
|
+
const getIndex = () => {
|
|
1801
|
+
if (!arrayContext)
|
|
1802
|
+
return -1; // -1 means remove last (no specific index)
|
|
1803
|
+
return isSignal(arrayContext.index) ? arrayContext.index() : arrayContext.index;
|
|
1804
|
+
};
|
|
1805
|
+
const inputs = {
|
|
1806
|
+
...baseInputs,
|
|
1807
|
+
event: RemoveArrayItemEvent,
|
|
1808
|
+
eventArgs,
|
|
1809
|
+
eventContext: {
|
|
1810
|
+
key: fieldDef.key,
|
|
1811
|
+
index: getIndex(),
|
|
1812
|
+
arrayKey: targetArrayKey ?? '',
|
|
1813
|
+
formValue: arrayContext?.formValue ?? {},
|
|
1814
|
+
},
|
|
1815
|
+
};
|
|
1816
|
+
// Add disabled binding only if explicitly set by user
|
|
1817
|
+
if (fieldDef.disabled !== undefined) {
|
|
1818
|
+
inputs['disabled'] = fieldDef.disabled;
|
|
1819
|
+
}
|
|
1820
|
+
if (fieldDef.hidden !== undefined) {
|
|
1821
|
+
inputs['hidden'] = fieldDef.hidden;
|
|
1822
|
+
}
|
|
1823
|
+
return inputs;
|
|
1824
|
+
});
|
|
1825
|
+
}
|
|
1826
|
+
|
|
1827
|
+
/**
|
|
1828
|
+
* Material Design field type definitions
|
|
1829
|
+
* Follows the FieldTypeDefinition interface for proper registry integration
|
|
1830
|
+
*/
|
|
1831
|
+
const MATERIAL_FIELD_TYPES = [
|
|
1832
|
+
{
|
|
1833
|
+
name: MatField.Input,
|
|
1834
|
+
loadComponent: () => Promise.resolve().then(function () { return matInput_component; }),
|
|
1835
|
+
mapper: valueFieldMapper,
|
|
1836
|
+
},
|
|
1837
|
+
{
|
|
1838
|
+
name: MatField.Select,
|
|
1839
|
+
loadComponent: () => Promise.resolve().then(function () { return matSelect_component; }),
|
|
1840
|
+
mapper: optionsFieldMapper,
|
|
1841
|
+
},
|
|
1842
|
+
{
|
|
1843
|
+
name: MatField.Checkbox,
|
|
1844
|
+
loadComponent: () => Promise.resolve().then(function () { return matCheckbox_component; }),
|
|
1845
|
+
mapper: checkboxFieldMapper,
|
|
1846
|
+
},
|
|
1847
|
+
{
|
|
1848
|
+
name: MatField.Button,
|
|
1849
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1850
|
+
mapper: buttonFieldMapper,
|
|
1851
|
+
valueHandling: 'exclude',
|
|
1852
|
+
},
|
|
1853
|
+
{
|
|
1854
|
+
name: MatField.Submit,
|
|
1855
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1856
|
+
mapper: submitButtonFieldMapper,
|
|
1857
|
+
valueHandling: 'exclude',
|
|
1858
|
+
},
|
|
1859
|
+
{
|
|
1860
|
+
name: MatField.Next,
|
|
1861
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1862
|
+
mapper: nextButtonFieldMapper,
|
|
1863
|
+
valueHandling: 'exclude',
|
|
1864
|
+
},
|
|
1865
|
+
{
|
|
1866
|
+
name: MatField.Previous,
|
|
1867
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1868
|
+
mapper: previousButtonFieldMapper,
|
|
1869
|
+
valueHandling: 'exclude',
|
|
1870
|
+
},
|
|
1871
|
+
{
|
|
1872
|
+
name: MatField.AddArrayItem,
|
|
1873
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1874
|
+
mapper: addArrayItemButtonFieldMapper,
|
|
1875
|
+
valueHandling: 'exclude',
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
name: MatField.RemoveArrayItem,
|
|
1879
|
+
loadComponent: () => Promise.resolve().then(function () { return matButton_component; }),
|
|
1880
|
+
mapper: removeArrayItemButtonFieldMapper,
|
|
1881
|
+
valueHandling: 'exclude',
|
|
1882
|
+
},
|
|
1883
|
+
{
|
|
1884
|
+
name: MatField.Textarea,
|
|
1885
|
+
loadComponent: () => Promise.resolve().then(function () { return matTextarea_component; }),
|
|
1886
|
+
mapper: valueFieldMapper,
|
|
1887
|
+
},
|
|
1888
|
+
{
|
|
1889
|
+
name: MatField.Radio,
|
|
1890
|
+
loadComponent: () => Promise.resolve().then(function () { return matRadio_component; }),
|
|
1891
|
+
mapper: optionsFieldMapper,
|
|
1892
|
+
},
|
|
1893
|
+
{
|
|
1894
|
+
name: MatField.MultiCheckbox,
|
|
1895
|
+
loadComponent: () => Promise.resolve().then(function () { return matMultiCheckbox_component; }),
|
|
1896
|
+
mapper: optionsFieldMapper,
|
|
1897
|
+
},
|
|
1898
|
+
{
|
|
1899
|
+
name: MatField.Datepicker,
|
|
1900
|
+
loadComponent: () => Promise.resolve().then(function () { return matDatepicker_component; }),
|
|
1901
|
+
mapper: datepickerFieldMapper,
|
|
1902
|
+
},
|
|
1903
|
+
{
|
|
1904
|
+
name: MatField.Slider,
|
|
1905
|
+
loadComponent: () => Promise.resolve().then(function () { return matSlider_component; }),
|
|
1906
|
+
mapper: valueFieldMapper,
|
|
1907
|
+
},
|
|
1908
|
+
{
|
|
1909
|
+
name: MatField.Toggle,
|
|
1910
|
+
loadComponent: () => Promise.resolve().then(function () { return matToggle_component; }),
|
|
1911
|
+
mapper: checkboxFieldMapper,
|
|
1912
|
+
},
|
|
1913
|
+
];
|
|
1914
|
+
|
|
1915
|
+
/**
|
|
1916
|
+
* Module augmentation for @ng-forge/dynamic-form
|
|
1917
|
+
* This file augments the FieldRegistryLeaves interface to include
|
|
1918
|
+
* all Material Design field types provided by this library.
|
|
1919
|
+
*/
|
|
1920
|
+
|
|
1921
|
+
/**
|
|
1922
|
+
* Configure dynamic forms with Material Design field types.
|
|
1923
|
+
* Provides all Material Design field types for use with provideDynamicForm.
|
|
1924
|
+
*
|
|
1925
|
+
* @param config - Optional global configuration for Material form fields
|
|
1926
|
+
*
|
|
1927
|
+
* @example
|
|
1928
|
+
* ```typescript
|
|
1929
|
+
* // Application-level setup
|
|
1930
|
+
* import { ApplicationConfig } from '@angular/core';
|
|
1931
|
+
* import { provideDynamicForm } from '@ng-forge/dynamic-form';
|
|
1932
|
+
* import { withMaterialFields } from '@ng-forge/dynamic-form-material';
|
|
1933
|
+
*
|
|
1934
|
+
* export const appConfig: ApplicationConfig = {
|
|
1935
|
+
* providers: [
|
|
1936
|
+
* provideDynamicForm(...withMaterialFields())
|
|
1937
|
+
* ]
|
|
1938
|
+
* };
|
|
1939
|
+
* ```
|
|
1940
|
+
*
|
|
1941
|
+
* @example
|
|
1942
|
+
* ```typescript
|
|
1943
|
+
* // With global configuration
|
|
1944
|
+
* export const appConfig: ApplicationConfig = {
|
|
1945
|
+
* providers: [
|
|
1946
|
+
* provideDynamicForm(
|
|
1947
|
+
* ...withMaterialFields({
|
|
1948
|
+
* appearance: 'fill',
|
|
1949
|
+
* subscriptSizing: 'fixed'
|
|
1950
|
+
* })
|
|
1951
|
+
* )
|
|
1952
|
+
* ]
|
|
1953
|
+
* };
|
|
1954
|
+
* ```
|
|
1955
|
+
*
|
|
1956
|
+
* @returns Array of field type definitions for Material Design components
|
|
1957
|
+
*/
|
|
1958
|
+
function withMaterialFields(config) {
|
|
1959
|
+
const fields = MATERIAL_FIELD_TYPES;
|
|
1960
|
+
if (config) {
|
|
1961
|
+
fields.__configProviders = [
|
|
1962
|
+
{
|
|
1963
|
+
provide: MATERIAL_CONFIG,
|
|
1964
|
+
useValue: config,
|
|
1965
|
+
},
|
|
1966
|
+
];
|
|
1967
|
+
}
|
|
1968
|
+
return fields;
|
|
1969
|
+
}
|
|
1970
|
+
|
|
1971
|
+
// Field components
|
|
1972
|
+
|
|
1973
|
+
/**
|
|
1974
|
+
* Generated bundle index. Do not edit.
|
|
1975
|
+
*/
|
|
1976
|
+
|
|
1977
|
+
export { MATERIAL_CONFIG, MATERIAL_FIELD_TYPES, MatButtonFieldComponent, MatCheckboxFieldComponent, MatDatepickerFieldComponent, MatField, MatInputFieldComponent, MatMultiCheckboxFieldComponent, MatRadioFieldComponent, MatSelectFieldComponent, MatSliderFieldComponent, MatTextareaFieldComponent, MatToggleFieldComponent, withMaterialFields };
|
|
1978
|
+
//# sourceMappingURL=ng-forge-dynamic-forms-material.mjs.map
|