ng-primitives 0.91.2 → 0.93.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.
Files changed (55) hide show
  1. package/a11y/index.d.ts +3 -1
  2. package/accordion/index.d.ts +8 -1
  3. package/autofill/index.d.ts +4 -0
  4. package/avatar/index.d.ts +11 -2
  5. package/breadcrumbs/index.d.ts +21 -7
  6. package/button/index.d.ts +3 -1
  7. package/checkbox/index.d.ts +3 -1
  8. package/fesm2022/ng-primitives-checkbox.mjs +7 -8
  9. package/fesm2022/ng-primitives-checkbox.mjs.map +1 -1
  10. package/fesm2022/ng-primitives-file-upload.mjs +209 -202
  11. package/fesm2022/ng-primitives-file-upload.mjs.map +1 -1
  12. package/fesm2022/ng-primitives-focus-trap.mjs +107 -138
  13. package/fesm2022/ng-primitives-focus-trap.mjs.map +1 -1
  14. package/fesm2022/ng-primitives-form-field.mjs +323 -399
  15. package/fesm2022/ng-primitives-form-field.mjs.map +1 -1
  16. package/fesm2022/ng-primitives-interactions.mjs +57 -58
  17. package/fesm2022/ng-primitives-interactions.mjs.map +1 -1
  18. package/fesm2022/ng-primitives-listbox.mjs +2 -2
  19. package/fesm2022/ng-primitives-listbox.mjs.map +1 -1
  20. package/fesm2022/ng-primitives-menu.mjs.map +1 -1
  21. package/fesm2022/ng-primitives-portal.mjs +5 -1
  22. package/fesm2022/ng-primitives-portal.mjs.map +1 -1
  23. package/fesm2022/ng-primitives-slider.mjs +4 -5
  24. package/fesm2022/ng-primitives-slider.mjs.map +1 -1
  25. package/fesm2022/ng-primitives-state.mjs +36 -8
  26. package/fesm2022/ng-primitives-state.mjs.map +1 -1
  27. package/fesm2022/ng-primitives-switch.mjs +4 -5
  28. package/fesm2022/ng-primitives-switch.mjs.map +1 -1
  29. package/fesm2022/ng-primitives-tabs.mjs +194 -192
  30. package/fesm2022/ng-primitives-tabs.mjs.map +1 -1
  31. package/fesm2022/ng-primitives-toggle-group.mjs +4 -5
  32. package/fesm2022/ng-primitives-toggle-group.mjs.map +1 -1
  33. package/fesm2022/ng-primitives-toggle.mjs +4 -5
  34. package/fesm2022/ng-primitives-toggle.mjs.map +1 -1
  35. package/fesm2022/ng-primitives-tooltip.mjs +4 -4
  36. package/fesm2022/ng-primitives-tooltip.mjs.map +1 -1
  37. package/fesm2022/ng-primitives-utils.mjs +23 -14
  38. package/fesm2022/ng-primitives-utils.mjs.map +1 -1
  39. package/file-upload/index.d.ts +100 -52
  40. package/focus-trap/index.d.ts +33 -75
  41. package/form-field/index.d.ts +320 -123
  42. package/input/index.d.ts +6 -0
  43. package/interactions/index.d.ts +16 -16
  44. package/package.json +1 -1
  45. package/roving-focus/index.d.ts +6 -2
  46. package/schematics/ng-generate/templates/tabs/tabs.__fileSuffix@dasherize__.ts.template +2 -2
  47. package/slider/index.d.ts +14 -6
  48. package/state/index.d.ts +23 -8
  49. package/switch/index.d.ts +8 -4
  50. package/tabs/index.d.ts +333 -84
  51. package/textarea/index.d.ts +6 -0
  52. package/toggle/index.d.ts +5 -3
  53. package/toggle-group/index.d.ts +6 -2
  54. package/toolbar/index.d.ts +5 -0
  55. package/utils/index.d.ts +1 -1
@@ -1,75 +1,253 @@
1
1
  import * as i0 from '@angular/core';
2
- import { input, effect, Directive, computed, booleanAttribute, afterRenderEffect, signal, contentChild, inject, Injector, untracked, ElementRef, HostListener } from '@angular/core';
3
- import { uniqueId, onBooleanChange, controlStatus, onChange } from 'ng-primitives/utils';
4
- import { createStateToken, createStateProvider, createStateInjector, createState } from 'ng-primitives/state';
2
+ import { inject, Injector, signal, untracked, effect, input, Directive, computed, booleanAttribute, contentChild } from '@angular/core';
3
+ import { onChange, uniqueId, onBooleanChange, controlStatus } from 'ng-primitives/utils';
5
4
  import { injectElementRef, explicitEffect } from 'ng-primitives/internal';
5
+ import { createPrimitive, dataBinding, onDestroy, attrBinding, listener } from 'ng-primitives/state';
6
6
  import { NgControl } from '@angular/forms';
7
7
 
8
- /**
9
- * The state token for the FormField primitive.
10
- */
11
- const NgpFormFieldStateToken = createStateToken('FormField');
12
- /**
13
- * Provides the FormField state.
14
- */
15
- const provideFormFieldState = createStateProvider(NgpFormFieldStateToken);
16
- /**
17
- * Injects the FormField state.
18
- */
19
- const injectFormFieldState = createStateInjector(NgpFormFieldStateToken);
20
- /**
21
- * The FormField state registration function.
22
- */
23
- const formFieldState = createState(NgpFormFieldStateToken);
8
+ const [NgpFormFieldStateToken, ngpFormField, injectFormFieldState, provideFormFieldState] = createPrimitive('NgpFormField', ({ ngControl }) => {
9
+ const element = injectElementRef();
10
+ const injector = inject(Injector);
11
+ // Store the form labels
12
+ const labels = signal([], ...(ngDevMode ? [{ debugName: "labels" }] : []));
13
+ // Store the form descriptions
14
+ const descriptions = signal([], ...(ngDevMode ? [{ debugName: "descriptions" }] : []));
15
+ // Store the id of the associated form control
16
+ const formControl = signal(null, ...(ngDevMode ? [{ debugName: "formControl" }] : []));
17
+ // Store the validation error messages
18
+ const errors = signal([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
19
+ // Form control state signals
20
+ const pristine = signal(null, ...(ngDevMode ? [{ debugName: "pristine" }] : []));
21
+ const touched = signal(null, ...(ngDevMode ? [{ debugName: "touched" }] : []));
22
+ const dirty = signal(null, ...(ngDevMode ? [{ debugName: "dirty" }] : []));
23
+ const valid = signal(null, ...(ngDevMode ? [{ debugName: "valid" }] : []));
24
+ const invalid = signal(null, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
25
+ const pending = signal(null, ...(ngDevMode ? [{ debugName: "pending" }] : []));
26
+ const disabled = signal(null, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
27
+ // Store the current status subscription
28
+ let subscription;
29
+ // Host bindings
30
+ dataBinding(element, 'data-invalid', invalid);
31
+ dataBinding(element, 'data-valid', valid);
32
+ dataBinding(element, 'data-touched', touched);
33
+ dataBinding(element, 'data-pristine', pristine);
34
+ dataBinding(element, 'data-dirty', dirty);
35
+ dataBinding(element, 'data-pending', pending);
36
+ dataBinding(element, 'data-disabled', disabled);
37
+ function updateStatus() {
38
+ const control = ngControl();
39
+ if (!control) {
40
+ return;
41
+ }
42
+ // Wrap in try-catch to handle signal-forms interop controls where
43
+ // the `field` input may not be available yet (throws NG0950).
44
+ // Reading the signal still establishes a dependency, so the effect
45
+ // will re-run when the input becomes available.
46
+ try {
47
+ const controlPristine = control.pristine;
48
+ const controlTouched = control.touched;
49
+ const controlDirty = control.dirty;
50
+ const controlValid = control.valid;
51
+ const controlInvalid = control.invalid;
52
+ const controlPending = control.pending;
53
+ const controlDisabled = control.disabled;
54
+ const controlErrors = control.errors;
55
+ untracked(() => {
56
+ pristine.set(controlPristine);
57
+ touched.set(controlTouched);
58
+ dirty.set(controlDirty);
59
+ valid.set(controlValid);
60
+ invalid.set(controlInvalid);
61
+ pending.set(controlPending);
62
+ disabled.set(controlDisabled);
63
+ errors.set(controlErrors ? Object.keys(controlErrors) : []);
64
+ });
65
+ }
66
+ catch {
67
+ // NG0950: Required input not available yet. The effect will re-run
68
+ // when the signal input becomes available.
69
+ }
70
+ }
71
+ function setupSubscriptions(control) {
72
+ // Unsubscribe from the previous subscriptions.
73
+ subscription?.unsubscribe();
74
+ if (!control) {
75
+ return;
76
+ }
77
+ // For signal-forms interop controls, use an effect to reactively track status.
78
+ // For classic controls, also use an effect but additionally subscribe to events.
79
+ effect(() => {
80
+ updateStatus();
81
+ }, { injector });
82
+ // Classic controls also have an events observable we can subscribe to.
83
+ const underlyingControl = control?.control;
84
+ if (underlyingControl?.events) {
85
+ subscription = underlyingControl.events.subscribe(() => updateStatus());
86
+ }
87
+ }
88
+ // Setup subscriptions when ngControl changes
89
+ onChange(ngControl, setupSubscriptions);
90
+ // Cleanup subscription on destroy
91
+ onDestroy(() => subscription?.unsubscribe());
92
+ // Methods
93
+ function setFormControl(id) {
94
+ formControl.set(id);
95
+ }
96
+ function addLabel(label) {
97
+ if (labels().includes(label)) {
98
+ return;
99
+ }
100
+ labels.update(currentLabels => [...currentLabels, label]);
101
+ }
102
+ function addDescription(description) {
103
+ if (descriptions().includes(description)) {
104
+ return;
105
+ }
106
+ descriptions.update(currentDescriptions => [...currentDescriptions, description]);
107
+ }
108
+ function removeFormControl() {
109
+ formControl.set(null);
110
+ }
111
+ function removeLabel(label) {
112
+ labels.update(currentLabels => currentLabels.filter(l => l !== label));
113
+ }
114
+ function removeDescription(description) {
115
+ descriptions.update(currentDescriptions => currentDescriptions.filter(d => d !== description));
116
+ }
117
+ return {
118
+ labels,
119
+ descriptions,
120
+ formControl,
121
+ errors,
122
+ pristine,
123
+ touched,
124
+ dirty,
125
+ valid,
126
+ invalid,
127
+ pending,
128
+ disabled,
129
+ setFormControl,
130
+ addLabel,
131
+ addDescription,
132
+ removeFormControl,
133
+ removeLabel,
134
+ removeDescription,
135
+ };
136
+ });
137
+
138
+ const [NgpDescriptionStateToken, ngpDescription, injectDescriptionState, provideDescriptionState,] = createPrimitive('NgpDescription', ({ id = signal(uniqueId('ngp-description')) }) => {
139
+ const element = injectElementRef();
140
+ const formField = injectFormFieldState({ optional: true });
141
+ // Host bindings
142
+ attrBinding(element, 'id', id);
143
+ dataBinding(element, 'data-invalid', () => (formField()?.invalid() ? '' : null));
144
+ dataBinding(element, 'data-valid', () => (formField()?.valid() ? '' : null));
145
+ dataBinding(element, 'data-touched', () => (formField()?.touched() ? '' : null));
146
+ dataBinding(element, 'data-pristine', () => (formField()?.pristine() ? '' : null));
147
+ dataBinding(element, 'data-dirty', () => (formField()?.dirty() ? '' : null));
148
+ dataBinding(element, 'data-pending', () => (formField()?.pending() ? '' : null));
149
+ dataBinding(element, 'data-disabled', () => (formField()?.disabled() ? '' : null));
150
+ // Register with form field and cleanup on destroy
151
+ formField()?.addDescription(id());
152
+ onDestroy(() => formField()?.removeDescription(id()));
153
+ onChange(id, (newId, oldId) => {
154
+ if (oldId) {
155
+ formField()?.removeDescription(oldId);
156
+ }
157
+ formField()?.addDescription(newId);
158
+ });
159
+ return { id };
160
+ });
24
161
 
25
162
  /**
26
163
  * The `NgpDescription` directive is used to mark a description element within a form field. There may be multiple descriptions associated with a form control.
27
164
  */
28
165
  class NgpDescription {
166
+ /**
167
+ * The description state.
168
+ */
29
169
  constructor() {
30
170
  /**
31
171
  * The id of the description. If not provided, a unique id will be generated.
32
172
  */
33
173
  this.id = input(uniqueId('ngp-description'), ...(ngDevMode ? [{ debugName: "id" }] : []));
34
- /**
35
- * Access the form field that the description is associated with.
36
- */
37
- this.formField = injectFormFieldState({ optional: true });
38
- effect(onCleanup => {
39
- this.formField()?.addDescription(this.id());
40
- onCleanup(() => this.formField()?.removeDescription(this.id()));
41
- });
174
+ ngpDescription({ id: this.id });
42
175
  }
43
176
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpDescription, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
44
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpDescription, isStandalone: true, selector: "[ngpDescription]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.id": "id()", "attr.data-invalid": "formField()?.invalid() ? \"\" : null", "attr.data-valid": "formField()?.valid() ? \"\" : null", "attr.data-touched": "formField()?.touched() ? \"\" : null", "attr.data-pristine": "formField()?.pristine() ? \"\" : null", "attr.data-dirty": "formField()?.dirty() ? \"\" : null", "attr.data-pending": "formField()?.pending() ? \"\" : null", "attr.data-disabled": "formField()?.disabled() ? \"\" : null" } }, exportAs: ["ngpDescription"], ngImport: i0 }); }
177
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpDescription, isStandalone: true, selector: "[ngpDescription]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideDescriptionState()], exportAs: ["ngpDescription"], ngImport: i0 }); }
45
178
  }
46
179
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpDescription, decorators: [{
47
180
  type: Directive,
48
181
  args: [{
49
182
  selector: '[ngpDescription]',
50
183
  exportAs: 'ngpDescription',
51
- host: {
52
- '[attr.id]': 'id()',
53
- '[attr.data-invalid]': 'formField()?.invalid() ? "" : null',
54
- '[attr.data-valid]': 'formField()?.valid() ? "" : null',
55
- '[attr.data-touched]': 'formField()?.touched() ? "" : null',
56
- '[attr.data-pristine]': 'formField()?.pristine() ? "" : null',
57
- '[attr.data-dirty]': 'formField()?.dirty() ? "" : null',
58
- '[attr.data-pending]': 'formField()?.pending() ? "" : null',
59
- '[attr.data-disabled]': 'formField()?.disabled() ? "" : null',
60
- },
184
+ providers: [provideDescriptionState()],
61
185
  }]
62
186
  }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
63
187
 
188
+ const [NgpErrorStateToken, ngpError, injectErrorState, provideErrorState] = createPrimitive('NgpError', ({ id, validator = signal(null) }) => {
189
+ const element = injectElementRef();
190
+ const formField = injectFormFieldState({ optional: true });
191
+ // Determine if there is an error message
192
+ const hasError = computed(() => {
193
+ const errors = formField()?.errors() ?? [];
194
+ const validatorValue = validator();
195
+ return validatorValue ? errors?.includes(validatorValue) : errors?.length > 0;
196
+ }, ...(ngDevMode ? [{ debugName: "hasError" }] : []));
197
+ // Determine whether the validator associated with this error is failing
198
+ const state = computed(() => (hasError() ? 'fail' : 'pass'), ...(ngDevMode ? [{ debugName: "state" }] : []));
199
+ // Host bindings
200
+ attrBinding(element, 'id', id);
201
+ dataBinding(element, 'data-invalid', () => (formField()?.invalid() ? '' : null));
202
+ dataBinding(element, 'data-valid', () => (formField()?.valid() ? '' : null));
203
+ dataBinding(element, 'data-touched', () => (formField()?.touched() ? '' : null));
204
+ dataBinding(element, 'data-pristine', () => (formField()?.pristine() ? '' : null));
205
+ dataBinding(element, 'data-dirty', () => (formField()?.dirty() ? '' : null));
206
+ dataBinding(element, 'data-pending', () => (formField()?.pending() ? '' : null));
207
+ dataBinding(element, 'data-disabled', () => (formField()?.disabled() ? '' : null));
208
+ dataBinding(element, 'data-validator', state);
209
+ let currentId = id();
210
+ // Register/unregister with form field based on error state
211
+ function registerError() {
212
+ formField()?.addDescription(currentId);
213
+ }
214
+ function unregisterError() {
215
+ formField()?.removeDescription(currentId);
216
+ }
217
+ // Update error registration when hasError changes
218
+ onBooleanChange(hasError, registerError, unregisterError);
219
+ function updateIdRegistration(newId, oldId) {
220
+ if (oldId && hasError()) {
221
+ formField()?.removeDescription(oldId);
222
+ }
223
+ currentId = newId;
224
+ if (hasError()) {
225
+ formField()?.addDescription(newId);
226
+ }
227
+ }
228
+ // Watch for id changes to update registration
229
+ explicitEffect([id], () => updateIdRegistration(id(), currentId));
230
+ // Cleanup on destroy
231
+ onDestroy(() => {
232
+ if (hasError()) {
233
+ formField()?.removeDescription(currentId);
234
+ }
235
+ });
236
+ return {
237
+ id,
238
+ hasError,
239
+ state,
240
+ };
241
+ });
242
+
64
243
  /**
65
244
  * The `NgpError` directive is used to mark an error message element within a form field. There may be multiple error messages associated with a form control.
66
245
  */
67
246
  class NgpError {
247
+ /**
248
+ * The error state.
249
+ */
68
250
  constructor() {
69
- /**
70
- * Access the form field that the description is associated with.
71
- */
72
- this.formField = injectFormFieldState({ optional: true });
73
251
  /**
74
252
  * The id of the error message. If not provided, a unique id will be generated.
75
253
  */
@@ -80,67 +258,55 @@ class NgpError {
80
258
  this.validator = input(null, ...(ngDevMode ? [{ debugName: "validator", alias: 'ngpErrorValidator' }] : [{
81
259
  alias: 'ngpErrorValidator',
82
260
  }]));
83
- /**
84
- * Determine if there is an error message.
85
- */
86
- this.hasError = computed(() => {
87
- const errors = this.formField()?.errors() ?? [];
88
- const validator = this.validator();
89
- return validator ? errors?.includes(validator) : errors?.length > 0;
90
- }, ...(ngDevMode ? [{ debugName: "hasError" }] : []));
91
- /**
92
- * Determine whether the validator associated with this error is failing.
93
- */
94
- this.state = computed(() => (this.hasError() ? 'fail' : 'pass'), ...(ngDevMode ? [{ debugName: "state" }] : []));
95
- // add or remove the error message when the error state changes
96
- onBooleanChange(this.hasError, () => this.formField()?.addDescription(this.id()), () => this.formField()?.removeDescription(this.id()));
97
- }
98
- ngOnChanges(changes) {
99
- if ('id' in changes) {
100
- this.formField()?.removeDescription(changes['id'].previousValue);
101
- }
102
- }
103
- ngOnDestroy() {
104
- this.formField()?.removeDescription(this.id());
261
+ ngpError({ id: this.id, validator: this.validator });
105
262
  }
106
263
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpError, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
107
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpError, isStandalone: true, selector: "[ngpError]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, validator: { classPropertyName: "validator", publicName: "ngpErrorValidator", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.id": "id()", "attr.data-invalid": "formField()?.invalid() ? \"\" : null", "attr.data-valid": "formField()?.valid() ? \"\" : null", "attr.data-touched": "formField()?.touched() ? \"\" : null", "attr.data-pristine": "formField()?.pristine() ? \"\" : null", "attr.data-dirty": "formField()?.dirty() ? \"\" : null", "attr.data-pending": "formField()?.pending() ? \"\" : null", "attr.data-disabled": "formField()?.disabled() ? \"\" : null", "attr.data-validator": "state()" } }, exportAs: ["ngpError"], usesOnChanges: true, ngImport: i0 }); }
264
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpError, isStandalone: true, selector: "[ngpError]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, validator: { classPropertyName: "validator", publicName: "ngpErrorValidator", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideErrorState()], exportAs: ["ngpError"], ngImport: i0 }); }
108
265
  }
109
266
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpError, decorators: [{
110
267
  type: Directive,
111
268
  args: [{
112
269
  selector: '[ngpError]',
113
270
  exportAs: 'ngpError',
114
- host: {
115
- '[attr.id]': 'id()',
116
- '[attr.data-invalid]': 'formField()?.invalid() ? "" : null',
117
- '[attr.data-valid]': 'formField()?.valid() ? "" : null',
118
- '[attr.data-touched]': 'formField()?.touched() ? "" : null',
119
- '[attr.data-pristine]': 'formField()?.pristine() ? "" : null',
120
- '[attr.data-dirty]': 'formField()?.dirty() ? "" : null',
121
- '[attr.data-pending]': 'formField()?.pending() ? "" : null',
122
- '[attr.data-disabled]': 'formField()?.disabled() ? "" : null',
123
- '[attr.data-validator]': 'state()',
124
- },
271
+ providers: [provideErrorState()],
125
272
  }]
126
273
  }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], validator: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpErrorValidator", required: false }] }] } });
127
274
 
128
- /**
129
- * The state token for the FormControl primitive.
130
- */
131
- const NgpFormControlStateToken = createStateToken('FormControl');
132
- /**
133
- * Provides the FormControl state.
134
- */
135
- const provideFormControlState = createStateProvider(NgpFormControlStateToken);
136
- /**
137
- * Injects the FormControl state.
138
- */
139
- const injectFormControlState = createStateInjector(NgpFormControlStateToken);
140
- /**
141
- * The FormControl state registration function.
142
- */
143
- const formControlState = createState(NgpFormControlStateToken);
275
+ function ngpFormControl({ id, disabled = signal(false), }) {
276
+ const elementRef = injectElementRef();
277
+ // Access the form field that the form control is associated with.
278
+ const formField = injectFormFieldState({ optional: true });
279
+ // Access the form control status.
280
+ const status = controlStatus();
281
+ // Determine the aria-labelledby attribute value.
282
+ const ariaLabelledBy = computed(() => {
283
+ const labels = formField()?.labels() ?? [];
284
+ return labels.length > 0 ? labels.join(' ') : null;
285
+ }, ...(ngDevMode ? [{ debugName: "ariaLabelledBy" }] : []));
286
+ // Determine the aria-describedby attribute value.
287
+ const ariaDescribedBy = computed(() => {
288
+ const descriptions = formField()?.descriptions() ?? [];
289
+ return descriptions.length > 0 ? descriptions.join(' ') : null;
290
+ }, ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
291
+ const supportsDisabledAttribute = 'disabled' in elementRef.nativeElement;
292
+ // Host bindings
293
+ attrBinding(elementRef, 'disabled', () => (supportsDisabledAttribute && disabled() ? '' : null));
294
+ explicitEffect([id], ([id], onCleanup) => {
295
+ formField()?.setFormControl(id);
296
+ onCleanup(() => formField()?.removeFormControl());
297
+ });
298
+ attrBinding(elementRef, 'id', id);
299
+ attrBinding(elementRef, 'aria-labelledby', ariaLabelledBy);
300
+ attrBinding(elementRef, 'aria-describedby', ariaDescribedBy);
301
+ dataBinding(elementRef, 'data-invalid', () => status().invalid);
302
+ dataBinding(elementRef, 'data-valid', () => status().valid);
303
+ dataBinding(elementRef, 'data-touched', () => status().touched);
304
+ dataBinding(elementRef, 'data-pristine', () => status().pristine);
305
+ dataBinding(elementRef, 'data-dirty', () => status().dirty);
306
+ dataBinding(elementRef, 'data-pending', () => status().pending);
307
+ dataBinding(elementRef, 'data-disabled', () => disabled() || status().disabled);
308
+ return computed(() => ({ ...status(), disabled: status().disabled || disabled() }));
309
+ }
144
310
 
145
311
  /**
146
312
  * Typically this primitive would be not be used directly, but instead a more specific form control primitive would be used (e.g. `ngpInput`). All of our form control primitives use `ngpFormControl` internally so they will have the same accessibility features as described below.
@@ -162,277 +328,38 @@ class NgpFormControl {
162
328
  transform: booleanAttribute,
163
329
  }]));
164
330
  /**
165
- * The element reference.
166
- */
167
- this.elementRef = injectElementRef();
168
- /**
169
- * Whether the element supports the disabled attribute.
331
+ * The status of the form control.
170
332
  */
171
- this.supportsDisabledAttribute = 'disabled' in this.elementRef.nativeElement;
172
- /**
173
- * The state of the form control.
174
- */
175
- this.state = formControlState(this);
176
- // Sync the form control state with the control state.
177
- this.status = ngpFormControl({ id: this.state.id, disabled: this.state.disabled });
333
+ this.status = ngpFormControl({ id: this.id, disabled: this.disabled });
178
334
  }
179
335
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpFormControl, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
180
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpFormControl, isStandalone: true, selector: "[ngpFormControl]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpFormControlDisabled", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "attr.disabled": "supportsDisabledAttribute && status().disabled ? \"\" : null" } }, providers: [provideFormControlState()], exportAs: ["ngpFormControl"], ngImport: i0 }); }
336
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpFormControl, isStandalone: true, selector: "[ngpFormControl]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpFormControlDisabled", isSignal: true, isRequired: false, transformFunction: null } }, exportAs: ["ngpFormControl"], ngImport: i0 }); }
181
337
  }
182
338
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpFormControl, decorators: [{
183
339
  type: Directive,
184
340
  args: [{
185
341
  selector: '[ngpFormControl]',
186
342
  exportAs: 'ngpFormControl',
187
- providers: [provideFormControlState()],
188
- host: {
189
- '[attr.disabled]': 'supportsDisabledAttribute && status().disabled ? "" : null',
190
- },
191
343
  }]
192
- }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpFormControlDisabled", required: false }] }] } });
193
- function ngpFormControl({ id, disabled = signal(false), }) {
194
- const element = injectElementRef().nativeElement;
195
- // Access the form field that the form control is associated with.
196
- const formField = injectFormFieldState({ optional: true });
197
- // Access the form control status.
198
- const status = controlStatus();
199
- // Determine the aria-labelledby attribute value.
200
- const ariaLabelledBy = computed(() => formField()?.labels().join(' '), ...(ngDevMode ? [{ debugName: "ariaLabelledBy" }] : []));
201
- // Determine the aria-describedby attribute value.
202
- const ariaDescribedBy = computed(() => formField()?.descriptions().join(' '), ...(ngDevMode ? [{ debugName: "ariaDescribedBy" }] : []));
203
- explicitEffect([id], ([id], onCleanup) => {
204
- formField()?.setFormControl(id);
205
- onCleanup(() => formField()?.removeFormControl());
206
- });
207
- afterRenderEffect({
208
- write: () => {
209
- setAttribute(element, 'id', id());
210
- setAttribute(element, 'aria-labelledby', ariaLabelledBy());
211
- setAttribute(element, 'aria-describedby', ariaDescribedBy());
212
- setStateAttribute(element, status().invalid, 'data-invalid');
213
- setStateAttribute(element, status().valid, 'data-valid');
214
- setStateAttribute(element, status().touched, 'data-touched');
215
- setStateAttribute(element, status().pristine, 'data-pristine');
216
- setStateAttribute(element, status().dirty, 'data-dirty');
217
- setStateAttribute(element, status().pending, 'data-pending');
218
- setStateAttribute(element, disabled() || status().disabled, 'data-disabled');
219
- },
220
- });
221
- return computed(() => ({ ...status(), disabled: status().disabled || disabled() }));
222
- }
223
- /**
224
- * Sets the attribute on the element. If the value is not empty, the attribute is set to the value.
225
- * If the value is empty, the attribute is removed.
226
- * @param element The element to set the attribute on.
227
- * @param attribute The attribute to set on the element.
228
- * @param value The value to set on the attribute.
229
- */
230
- function setAttribute(element, attribute, value) {
231
- if (value && value.length > 0) {
232
- element.setAttribute(attribute, value);
233
- }
234
- else {
235
- element.removeAttribute(attribute);
236
- }
237
- }
238
- /**
239
- * Sets the attribute on the element based on the state. If the state is true, the attribute
240
- * is set to an empty string. If the state is false, the attribute is removed.
241
- * @param element The element to set the attribute on.
242
- * @param state The state to set the attribute based on.
243
- * @param attribute The attribute to set on the element.
244
- */
245
- function setStateAttribute(element, state, attribute) {
246
- if (state) {
247
- element.setAttribute(attribute, '');
248
- }
249
- else {
250
- element.removeAttribute(attribute);
251
- }
252
- }
344
+ }], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "ngpFormControlDisabled", required: false }] }] } });
253
345
 
254
346
  /**
255
347
  * The `NgpFormField` directive is a container for form field elements. Any labels, form controls, or descriptions should be placed within this directive.
256
348
  */
257
349
  class NgpFormField {
350
+ /**
351
+ * The form field state.
352
+ */
258
353
  constructor() {
259
- /**
260
- * Store the form label.
261
- * @internal
262
- */
263
- this.labels = signal([], ...(ngDevMode ? [{ debugName: "labels" }] : []));
264
- /**
265
- * Store the form descriptions.
266
- * @internal
267
- */
268
- this.descriptions = signal([], ...(ngDevMode ? [{ debugName: "descriptions" }] : []));
269
- /**
270
- * Store the id of the associated form control.
271
- * @internal
272
- */
273
- this.formControl = signal(null, ...(ngDevMode ? [{ debugName: "formControl" }] : []));
274
354
  /**
275
355
  * Find any NgControl within the form field.
276
356
  * @internal
277
357
  */
278
358
  this.ngControl = contentChild(NgControl, ...(ngDevMode ? [{ debugName: "ngControl" }] : []));
279
- /**
280
- * Store the validation error messages.
281
- * @internal
282
- */
283
- this.errors = signal([], ...(ngDevMode ? [{ debugName: "errors" }] : []));
284
- /**
285
- * Whether the control is pristine.
286
- * @internal
287
- */
288
- this.pristine = signal(null, ...(ngDevMode ? [{ debugName: "pristine" }] : []));
289
- /**
290
- * Whether the control is touched.
291
- * @internal
292
- */
293
- this.touched = signal(null, ...(ngDevMode ? [{ debugName: "touched" }] : []));
294
- /**
295
- * Whether the control is dirty.
296
- * @internal
297
- */
298
- this.dirty = signal(null, ...(ngDevMode ? [{ debugName: "dirty" }] : []));
299
- /**
300
- * Whether the control is valid.
301
- */
302
- this.valid = signal(null, ...(ngDevMode ? [{ debugName: "valid" }] : []));
303
- /**
304
- * Whether the control is invalid.
305
- * @internal
306
- */
307
- this.invalid = signal(null, ...(ngDevMode ? [{ debugName: "invalid" }] : []));
308
- /**
309
- * Whether the control is pending.
310
- * @internal
311
- */
312
- this.pending = signal(null, ...(ngDevMode ? [{ debugName: "pending" }] : []));
313
- /**
314
- * Whether the control is disabled.
315
- * @internal
316
- */
317
- this.disabled = signal(null, ...(ngDevMode ? [{ debugName: "disabled" }] : []));
318
- /**
319
- * Injector for creating effects outside the constructor.
320
- */
321
- this.injector = inject(Injector);
322
- /**
323
- * The form field state.
324
- */
325
- this.state = formFieldState(this);
326
- // any time the ngControl changes, setup the subscriptions.
327
- onChange(this.ngControl, this.setupSubscriptions.bind(this));
328
- }
329
- ngOnDestroy() {
330
- this.subscription?.unsubscribe();
331
- }
332
- /**
333
- * Setup a listener for the form control status.
334
- * @param control
335
- */
336
- setupSubscriptions(control) {
337
- // Unsubscribe from the previous subscriptions.
338
- this.subscription?.unsubscribe();
339
- if (!control) {
340
- return;
341
- }
342
- // For signal-forms interop controls, use an effect to reactively track status.
343
- // For classic controls, also use an effect but additionally subscribe to events.
344
- effect(() => {
345
- this.updateStatus();
346
- }, { injector: this.injector });
347
- // Classic controls also have an events observable we can subscribe to.
348
- const underlyingControl = control?.control;
349
- if (underlyingControl?.events) {
350
- this.subscription = underlyingControl.events.subscribe(() => this.updateStatus());
351
- }
352
- }
353
- updateStatus() {
354
- const control = this.ngControl();
355
- if (!control) {
356
- return;
357
- }
358
- // Wrap in try-catch to handle signal-forms interop controls where
359
- // the `field` input may not be available yet (throws NG0950).
360
- // Reading the signal still establishes a dependency, so the effect
361
- // will re-run when the input becomes available.
362
- try {
363
- const pristine = control.pristine;
364
- const touched = control.touched;
365
- const dirty = control.dirty;
366
- const valid = control.valid;
367
- const invalid = control.invalid;
368
- const pending = control.pending;
369
- const disabled = control.disabled;
370
- const errors = control.errors;
371
- untracked(() => {
372
- this.pristine.set(pristine);
373
- this.touched.set(touched);
374
- this.dirty.set(dirty);
375
- this.valid.set(valid);
376
- this.invalid.set(invalid);
377
- this.pending.set(pending);
378
- this.disabled.set(disabled);
379
- this.errors.set(errors ? Object.keys(errors) : []);
380
- });
381
- }
382
- catch {
383
- // NG0950: Required input not available yet. The effect will re-run
384
- // when the signal input becomes available.
385
- }
386
- }
387
- /**
388
- * Register the id of the associated form control.
389
- * @param id
390
- * @internal
391
- */
392
- setFormControl(id) {
393
- this.formControl.set(id);
394
- }
395
- /**
396
- * Register a label with the form field.
397
- * @param label
398
- * @internal
399
- */
400
- addLabel(label) {
401
- this.labels.update(labels => [...labels, label]);
402
- }
403
- /**
404
- * Register a description with the form field.
405
- * @param description
406
- * @internal
407
- */
408
- addDescription(description) {
409
- this.descriptions.update(descriptions => [...descriptions, description]);
410
- }
411
- /**
412
- * Remove the associated form control.
413
- * @internal
414
- */
415
- removeFormControl() {
416
- this.formControl.set(null);
417
- }
418
- /**
419
- * Remove a label from the form field.
420
- * @param label
421
- * @internal
422
- */
423
- removeLabel(label) {
424
- this.labels.update(labels => labels.filter(l => l !== label));
425
- }
426
- /**
427
- * Remove a description from the form field.
428
- * @param description
429
- * @internal
430
- */
431
- removeDescription(description) {
432
- this.descriptions.update(descriptions => descriptions.filter(d => d !== description));
359
+ ngpFormField({ ngControl: this.ngControl });
433
360
  }
434
361
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpFormField, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
435
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.9", type: NgpFormField, isStandalone: true, selector: "[ngpFormField]", host: { properties: { "attr.data-invalid": "invalid() ? \"\" : null", "attr.data-valid": "valid() ? \"\" : null", "attr.data-touched": "touched() ? \"\" : null", "attr.data-pristine": "pristine() ? \"\" : null", "attr.data-dirty": "dirty() ? \"\" : null", "attr.data-pending": "pending() ? \"\" : null", "attr.data-disabled": "disabled() ? \"\" : null" } }, providers: [provideFormFieldState()], queries: [{ propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], exportAs: ["ngpFormField"], ngImport: i0 }); }
362
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.2.0", version: "20.3.9", type: NgpFormField, isStandalone: true, selector: "[ngpFormField]", providers: [provideFormFieldState()], queries: [{ propertyName: "ngControl", first: true, predicate: NgControl, descendants: true, isSignal: true }], exportAs: ["ngpFormField"], ngImport: i0 }); }
436
363
  }
437
364
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpFormField, decorators: [{
438
365
  type: Directive,
@@ -440,59 +367,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImpor
440
367
  selector: '[ngpFormField]',
441
368
  exportAs: 'ngpFormField',
442
369
  providers: [provideFormFieldState()],
443
- host: {
444
- '[attr.data-invalid]': 'invalid() ? "" : null',
445
- '[attr.data-valid]': 'valid() ? "" : null',
446
- '[attr.data-touched]': 'touched() ? "" : null',
447
- '[attr.data-pristine]': 'pristine() ? "" : null',
448
- '[attr.data-dirty]': 'dirty() ? "" : null',
449
- '[attr.data-pending]': 'pending() ? "" : null',
450
- '[attr.data-disabled]': 'disabled() ? "" : null',
451
- },
452
370
  }]
453
371
  }], ctorParameters: () => [], propDecorators: { ngControl: [{ type: i0.ContentChild, args: [i0.forwardRef(() => NgControl), { isSignal: true }] }] } });
454
372
 
455
- /**
456
- * The `NgpLabel` directive is used to mark a label element within a form field. Preferably, there should use an HTML `<label>` element.
457
- */
458
- class NgpLabel {
459
- constructor() {
460
- /**
461
- * The id of the label. If not provided, a unique id will be generated.
462
- */
463
- this.id = input(uniqueId('ngp-label'), ...(ngDevMode ? [{ debugName: "id" }] : []));
464
- /**
465
- * Access the form field that the label is associated with.
466
- */
467
- this.formField = injectFormFieldState({ optional: true });
468
- /**
469
- * Derive the for attribute value if the label is an HTML label element.
470
- */
471
- this.htmlFor = computed(() => this.formField()?.formControl(), ...(ngDevMode ? [{ debugName: "htmlFor" }] : []));
472
- /**
473
- * Access the element that the label is associated with.
474
- */
475
- this.elementRef = inject(ElementRef);
476
- /**
477
- * Determine if the label is an HTML label element.
478
- */
479
- this.isLabel = this.elementRef.nativeElement instanceof HTMLLabelElement;
480
- effect(onCleanup => {
481
- this.formField()?.addLabel(this.id());
482
- onCleanup(() => this.formField()?.removeLabel(this.id()));
483
- });
484
- }
485
- onClick(event) {
373
+ const [NgpLabelStateToken, ngpLabel, injectLabelState, provideLabelState] = createPrimitive('NgpLabel', ({ id }) => {
374
+ const element = injectElementRef();
375
+ const formField = injectFormFieldState({ optional: true });
376
+ // Derive the for attribute value if the label is an HTML label element
377
+ const htmlFor = computed(() => formField()?.formControl() ?? null, ...(ngDevMode ? [{ debugName: "htmlFor" }] : []));
378
+ // Determine if the label is an HTML label element
379
+ const isLabel = element.nativeElement instanceof HTMLLabelElement;
380
+ // Host bindings
381
+ attrBinding(element, 'id', id);
382
+ attrBinding(element, 'for', htmlFor);
383
+ dataBinding(element, 'data-invalid', () => (formField()?.invalid() ? '' : null));
384
+ dataBinding(element, 'data-valid', () => (formField()?.valid() ? '' : null));
385
+ dataBinding(element, 'data-touched', () => (formField()?.touched() ? '' : null));
386
+ dataBinding(element, 'data-pristine', () => (formField()?.pristine() ? '' : null));
387
+ dataBinding(element, 'data-dirty', () => (formField()?.dirty() ? '' : null));
388
+ dataBinding(element, 'data-pending', () => (formField()?.pending() ? '' : null));
389
+ dataBinding(element, 'data-disabled', () => (formField()?.disabled() ? '' : null));
390
+ function onClick(event) {
486
391
  // by default a label will perform a click on the associated form control, however
487
392
  // this only works if the associated form control is an input element which may not always
488
393
  // be the case, so we prevent the default behavior and handle the click event ourselves.
489
394
  // This was inspired by the HeadlessUI approach:
490
395
  // https://github.com/tailwindlabs/headlessui/blob/main/packages/%40headlessui-react/src/components/label/label.tsx#L58
491
- if (this.isLabel) {
396
+ if (isLabel) {
492
397
  event.preventDefault();
493
398
  }
494
399
  // to find the associated form control we can lookup via the known id
495
- const targetId = this.htmlFor();
400
+ const targetId = htmlFor();
496
401
  if (!targetId) {
497
402
  return;
498
403
  }
@@ -518,34 +423,53 @@ class NgpLabel {
518
423
  // bound element is now focused.
519
424
  target.focus({ preventScroll: true });
520
425
  }
426
+ // Event listeners
427
+ listener(element, 'click', onClick);
428
+ // Register with form field and cleanup on destroy
429
+ formField()?.addLabel(id());
430
+ onDestroy(() => formField()?.removeLabel(id()));
431
+ // any time the id changes we need to update the registration with the form field
432
+ onChange(id, (newId, oldId) => {
433
+ if (oldId) {
434
+ formField()?.removeLabel(oldId);
435
+ }
436
+ formField()?.addLabel(newId);
437
+ });
438
+ return {
439
+ id,
440
+ htmlFor,
441
+ };
442
+ });
443
+
444
+ /**
445
+ * The `NgpLabel` directive is used to mark a label element within a form field. Preferably, there should use an HTML `<label>` element.
446
+ */
447
+ class NgpLabel {
448
+ /**
449
+ * The label state.
450
+ */
451
+ constructor() {
452
+ /**
453
+ * The id of the label. If not provided, a unique id will be generated.
454
+ */
455
+ this.id = input(uniqueId('ngp-label'), ...(ngDevMode ? [{ debugName: "id" }] : []));
456
+ ngpLabel({ id: this.id });
457
+ }
521
458
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpLabel, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
522
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpLabel, isStandalone: true, selector: "[ngpLabel]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, host: { listeners: { "click": "onClick($event)" }, properties: { "attr.id": "id()", "attr.for": "htmlFor()", "attr.data-invalid": "formField()?.invalid() ? \"\" : null", "attr.data-valid": "formField()?.valid() ? \"\" : null", "attr.data-touched": "formField()?.touched() ? \"\" : null", "attr.data-pristine": "formField()?.pristine() ? \"\" : null", "attr.data-dirty": "formField()?.dirty() ? \"\" : null", "attr.data-pending": "formField()?.pending() ? \"\" : null", "attr.data-disabled": "formField()?.disabled() ? \"\" : null" } }, exportAs: ["ngpLabel"], ngImport: i0 }); }
459
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "20.3.9", type: NgpLabel, isStandalone: true, selector: "[ngpLabel]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null } }, providers: [provideLabelState()], exportAs: ["ngpLabel"], ngImport: i0 }); }
523
460
  }
524
461
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.9", ngImport: i0, type: NgpLabel, decorators: [{
525
462
  type: Directive,
526
463
  args: [{
527
464
  selector: '[ngpLabel]',
528
465
  exportAs: 'ngpLabel',
529
- host: {
530
- '[attr.id]': 'id()',
531
- '[attr.for]': 'htmlFor()',
532
- '[attr.data-invalid]': 'formField()?.invalid() ? "" : null',
533
- '[attr.data-valid]': 'formField()?.valid() ? "" : null',
534
- '[attr.data-touched]': 'formField()?.touched() ? "" : null',
535
- '[attr.data-pristine]': 'formField()?.pristine() ? "" : null',
536
- '[attr.data-dirty]': 'formField()?.dirty() ? "" : null',
537
- '[attr.data-pending]': 'formField()?.pending() ? "" : null',
538
- '[attr.data-disabled]': 'formField()?.disabled() ? "" : null',
539
- },
466
+ providers: [provideLabelState()],
540
467
  }]
541
- }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], onClick: [{
542
- type: HostListener,
543
- args: ['click', ['$event']]
544
- }] } });
468
+ }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }] } });
545
469
 
546
470
  /**
547
471
  * Generated bundle index. Do not edit.
548
472
  */
549
473
 
550
- export { NgpDescription, NgpError, NgpFormControl, NgpFormField, NgpLabel, injectFormControlState, injectFormFieldState, ngpFormControl, provideFormControlState, provideFormFieldState };
474
+ export { NgpDescription, NgpError, NgpFormControl, NgpFormField, NgpLabel, injectDescriptionState, injectErrorState, injectFormFieldState, injectLabelState, ngpDescription, ngpError, ngpFormControl, ngpFormField, ngpLabel, provideDescriptionState, provideErrorState, provideFormFieldState, provideLabelState };
551
475
  //# sourceMappingURL=ng-primitives-form-field.mjs.map