@radix-ng/primitives 1.0.0-beta.1 → 1.0.0-beta.2

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 (85) hide show
  1. package/fesm2022/radix-ng-primitives-accordion.mjs +2 -2
  2. package/fesm2022/radix-ng-primitives-accordion.mjs.map +1 -1
  3. package/fesm2022/radix-ng-primitives-calendar.mjs +14 -1
  4. package/fesm2022/radix-ng-primitives-calendar.mjs.map +1 -1
  5. package/fesm2022/radix-ng-primitives-checkbox.mjs +2 -2
  6. package/fesm2022/radix-ng-primitives-checkbox.mjs.map +1 -1
  7. package/fesm2022/radix-ng-primitives-collapsible.mjs +1 -1
  8. package/fesm2022/radix-ng-primitives-collapsible.mjs.map +1 -1
  9. package/fesm2022/radix-ng-primitives-combobox.mjs +1923 -0
  10. package/fesm2022/radix-ng-primitives-combobox.mjs.map +1 -0
  11. package/fesm2022/radix-ng-primitives-context-menu.mjs +1 -1
  12. package/fesm2022/radix-ng-primitives-context-menu.mjs.map +1 -1
  13. package/fesm2022/radix-ng-primitives-core.mjs +480 -469
  14. package/fesm2022/radix-ng-primitives-core.mjs.map +1 -1
  15. package/fesm2022/radix-ng-primitives-cropper.mjs +1 -1
  16. package/fesm2022/radix-ng-primitives-cropper.mjs.map +1 -1
  17. package/fesm2022/radix-ng-primitives-date-field.mjs +11 -0
  18. package/fesm2022/radix-ng-primitives-date-field.mjs.map +1 -1
  19. package/fesm2022/radix-ng-primitives-dialog.mjs +1 -1
  20. package/fesm2022/radix-ng-primitives-dialog.mjs.map +1 -1
  21. package/fesm2022/radix-ng-primitives-drawer.mjs +1 -1
  22. package/fesm2022/radix-ng-primitives-drawer.mjs.map +1 -1
  23. package/fesm2022/radix-ng-primitives-editable.mjs +1 -1
  24. package/fesm2022/radix-ng-primitives-editable.mjs.map +1 -1
  25. package/fesm2022/radix-ng-primitives-field.mjs +86 -6
  26. package/fesm2022/radix-ng-primitives-field.mjs.map +1 -1
  27. package/fesm2022/radix-ng-primitives-fieldset.mjs +1 -1
  28. package/fesm2022/radix-ng-primitives-fieldset.mjs.map +1 -1
  29. package/fesm2022/radix-ng-primitives-focus-scope.mjs +1 -1
  30. package/fesm2022/radix-ng-primitives-focus-scope.mjs.map +1 -1
  31. package/fesm2022/radix-ng-primitives-form.mjs +207 -0
  32. package/fesm2022/radix-ng-primitives-form.mjs.map +1 -0
  33. package/fesm2022/radix-ng-primitives-input.mjs +85 -4
  34. package/fesm2022/radix-ng-primitives-input.mjs.map +1 -1
  35. package/fesm2022/radix-ng-primitives-menu.mjs +4 -4
  36. package/fesm2022/radix-ng-primitives-menu.mjs.map +1 -1
  37. package/fesm2022/radix-ng-primitives-menubar.mjs +1 -1
  38. package/fesm2022/radix-ng-primitives-menubar.mjs.map +1 -1
  39. package/fesm2022/radix-ng-primitives-meter.mjs +1 -1
  40. package/fesm2022/radix-ng-primitives-meter.mjs.map +1 -1
  41. package/fesm2022/radix-ng-primitives-navigation-menu.mjs +1 -1
  42. package/fesm2022/radix-ng-primitives-navigation-menu.mjs.map +1 -1
  43. package/fesm2022/radix-ng-primitives-number-field.mjs +2 -2
  44. package/fesm2022/radix-ng-primitives-number-field.mjs.map +1 -1
  45. package/fesm2022/radix-ng-primitives-popover.mjs +1 -1
  46. package/fesm2022/radix-ng-primitives-popover.mjs.map +1 -1
  47. package/fesm2022/radix-ng-primitives-popper.mjs +1 -1
  48. package/fesm2022/radix-ng-primitives-popper.mjs.map +1 -1
  49. package/fesm2022/radix-ng-primitives-preview-card.mjs +1 -1
  50. package/fesm2022/radix-ng-primitives-preview-card.mjs.map +1 -1
  51. package/fesm2022/radix-ng-primitives-progress.mjs +1 -1
  52. package/fesm2022/radix-ng-primitives-progress.mjs.map +1 -1
  53. package/fesm2022/radix-ng-primitives-roving-focus.mjs +1 -1
  54. package/fesm2022/radix-ng-primitives-roving-focus.mjs.map +1 -1
  55. package/fesm2022/radix-ng-primitives-scroll-area.mjs +3 -3
  56. package/fesm2022/radix-ng-primitives-scroll-area.mjs.map +1 -1
  57. package/fesm2022/radix-ng-primitives-select.mjs +421 -224
  58. package/fesm2022/radix-ng-primitives-select.mjs.map +1 -1
  59. package/fesm2022/radix-ng-primitives-slider.mjs +1 -1
  60. package/fesm2022/radix-ng-primitives-slider.mjs.map +1 -1
  61. package/fesm2022/radix-ng-primitives-switch.mjs +3 -2
  62. package/fesm2022/radix-ng-primitives-switch.mjs.map +1 -1
  63. package/fesm2022/radix-ng-primitives-tabs.mjs +1 -1
  64. package/fesm2022/radix-ng-primitives-tabs.mjs.map +1 -1
  65. package/fesm2022/radix-ng-primitives-time-field.mjs +27 -3
  66. package/fesm2022/radix-ng-primitives-time-field.mjs.map +1 -1
  67. package/fesm2022/radix-ng-primitives-toast.mjs +1 -1
  68. package/fesm2022/radix-ng-primitives-toast.mjs.map +1 -1
  69. package/fesm2022/radix-ng-primitives-toggle-group.mjs +1 -1
  70. package/fesm2022/radix-ng-primitives-toggle-group.mjs.map +1 -1
  71. package/fesm2022/radix-ng-primitives-toolbar.mjs +2 -2
  72. package/fesm2022/radix-ng-primitives-toolbar.mjs.map +1 -1
  73. package/fesm2022/radix-ng-primitives-tooltip.mjs +2 -2
  74. package/fesm2022/radix-ng-primitives-tooltip.mjs.map +1 -1
  75. package/package.json +9 -1
  76. package/schematics/ng-add/index.js +57 -0
  77. package/schematics/ng-add/index.js.map +1 -1
  78. package/schematics/ng-add/schema.d.ts +1 -0
  79. package/schematics/ng-add/schema.json +6 -0
  80. package/types/radix-ng-primitives-combobox.d.ts +1265 -0
  81. package/types/radix-ng-primitives-core.d.ts +148 -56
  82. package/types/radix-ng-primitives-field.d.ts +71 -2
  83. package/types/radix-ng-primitives-form.d.ts +124 -0
  84. package/types/radix-ng-primitives-input.d.ts +75 -5
  85. package/types/radix-ng-primitives-select.d.ts +292 -132
@@ -0,0 +1,207 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, ElementRef, input, output, signal, computed, linkedSignal, DestroyRef, Directive, NgModule } from '@angular/core';
3
+ import { createContext } from '@radix-ng/primitives/core';
4
+
5
+ const formRootContext = () => {
6
+ const root = inject(RdxFormRoot);
7
+ return {
8
+ errorsFor: (name) => root.errorsFor(name),
9
+ notifyEdited: (name) => root.notifyEdited(name),
10
+ register: (field) => root.register(field),
11
+ setStateProvider: (provider) => root.setStateProvider(provider),
12
+ hasStateProvider: root.hasStateProvider
13
+ };
14
+ };
15
+ const [injectFormRootContext, provideFormRootContext] = createContext('RdxFormRoot', 'components/form');
16
+ /** Collapses `FormData` into a plain object; repeated names collapse into arrays. */
17
+ function serializeFormData(data) {
18
+ const values = {};
19
+ data.forEach((value, key) => {
20
+ // `Object.hasOwn`, not `key in values` — a control named after an Object.prototype member
21
+ // (`toString`, `constructor`, …) must not be misread as a duplicate.
22
+ if (Object.hasOwn(values, key)) {
23
+ const existing = values[key];
24
+ values[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];
25
+ }
26
+ else {
27
+ values[key] = value;
28
+ }
29
+ });
30
+ return values;
31
+ }
32
+ /**
33
+ * The top of the forms layer cake: a single directive on the native `<form>` element that aggregates
34
+ * field state, maps external (server) errors onto fields by `name`, intercepts submit (values-as-object,
35
+ * focus the first invalid field), and resets field interaction state on native `reset`. It owns no
36
+ * values and runs no validation — Angular form systems (or Field inputs) remain the source of validity.
37
+ *
38
+ * @group Components
39
+ */
40
+ class RdxFormRoot {
41
+ /** Resolve a boolean aggregate: a registered provider's accessor wins, else OR over the registry. */
42
+ aggregate(key) {
43
+ const accessor = this.stateProvider()?.[key];
44
+ return accessor ? accessor() : this.fields().some((field) => field[key]());
45
+ }
46
+ /** Resolves the external messages for a field name (provider source wins over the `errors` input). */
47
+ errorsFor(name) {
48
+ if (!name) {
49
+ return [];
50
+ }
51
+ const provider = this.stateProvider();
52
+ if (provider?.errorsFor) {
53
+ return provider.errorsFor(name);
54
+ }
55
+ return this.effectiveErrors()[name] ?? [];
56
+ }
57
+ /** Clears a field's external error after a user edit, emitting the remaining map. */
58
+ notifyEdited(name) {
59
+ if (!name) {
60
+ return;
61
+ }
62
+ // While a provider owns errors, Signal Forms clears/reapplies them itself — stay inert.
63
+ if (this.stateProvider()?.errorsFor) {
64
+ return;
65
+ }
66
+ const errors = this.errors() ?? {};
67
+ if (!Object.hasOwn(errors, name) || this.clearedNames().has(name)) {
68
+ return;
69
+ }
70
+ this.clearedNames.update((set) => new Set(set).add(name));
71
+ this.onClearErrors.emit(this.remainingErrors());
72
+ }
73
+ register(field) {
74
+ this.fields.update((list) => [...list, field]);
75
+ return () => this.fields.update((list) => list.filter((item) => item !== field));
76
+ }
77
+ /** Register (or clear with `null`) an external owner of form-level state; returns the previous one. */
78
+ setStateProvider(provider) {
79
+ const previous = this.stateProvider();
80
+ this.stateProvider.set(provider);
81
+ return previous;
82
+ }
83
+ onSubmit(event) {
84
+ // SPA submits never navigate; never stopPropagation so Reactive Forms `(ngSubmit)` keeps firing.
85
+ event.preventDefault();
86
+ if (this.aggregate('invalid')) {
87
+ // Focus the first invalid registered field (DOM order); provider-only invalid has none to focus.
88
+ this.fields()
89
+ .find((field) => field.invalid())
90
+ ?.focus();
91
+ return;
92
+ }
93
+ const values = serializeFormData(new FormData(this.form));
94
+ this.onFormSubmit.emit({ values, event });
95
+ }
96
+ onReset() {
97
+ // Don't prevent the native reset — control values revert on their own.
98
+ if (!this.stateProvider()?.errorsFor) {
99
+ const keys = Object.keys(this.errors() ?? {});
100
+ const hadVisible = keys.some((key) => !this.clearedNames().has(key));
101
+ if (keys.length) {
102
+ this.clearedNames.set(new Set(keys));
103
+ }
104
+ if (hadVisible) {
105
+ this.onClearErrors.emit({});
106
+ }
107
+ }
108
+ // Values revert asynchronously relative to the reset event — re-sync field state next macrotask.
109
+ // Read the registry fresh inside the callback (fields may register/unregister in between), and
110
+ // cancel on destroy so resetState never runs against a torn-down field.
111
+ const timer = setTimeout(() => {
112
+ this.resetTimers.delete(timer);
113
+ this.fields().forEach((field) => field.resetState());
114
+ });
115
+ this.resetTimers.add(timer);
116
+ }
117
+ constructor() {
118
+ this.form = inject(ElementRef).nativeElement;
119
+ /** External/server validation errors keyed by `Field.Root` `name`. */
120
+ this.errors = input(...(ngDevMode ? [undefined, { debugName: "errors" }] : /* istanbul ignore next */ []));
121
+ /** Emits the remaining error map after a field's external error is cleared by a user edit (or reset). */
122
+ this.onClearErrors = output();
123
+ /** Emits the serialized form values when a valid form is submitted. */
124
+ this.onFormSubmit = output();
125
+ this.fields = signal([], ...(ngDevMode ? [{ debugName: "fields" }] : /* istanbul ignore next */ []));
126
+ this.stateProvider = signal(null, ...(ngDevMode ? [{ debugName: "stateProvider" }] : /* istanbul ignore next */ []));
127
+ /** Whether an external adapter currently owns form-level state. */
128
+ this.hasStateProvider = computed(() => this.stateProvider() !== null, ...(ngDevMode ? [{ debugName: "hasStateProvider" }] : /* istanbul ignore next */ []));
129
+ /**
130
+ * Names whose external error has been cleared by a user edit. Reset to empty whenever a new `errors`
131
+ * object reference is assigned — the server just spoke, so everything it said is live again.
132
+ */
133
+ this.clearedNames = linkedSignal({ ...(ngDevMode ? { debugName: "clearedNames" } : /* istanbul ignore next */ {}), source: this.errors,
134
+ computation: () => new Set() });
135
+ /** The `errors` input minus cleared names, normalized to `string[]`. */
136
+ this.effectiveErrors = computed(() => {
137
+ const errors = this.errors() ?? {};
138
+ const cleared = this.clearedNames();
139
+ const result = {};
140
+ for (const key of Object.keys(errors)) {
141
+ if (cleared.has(key)) {
142
+ continue;
143
+ }
144
+ const value = errors[key];
145
+ result[key] = Array.isArray(value) ? value : [value];
146
+ }
147
+ return result;
148
+ }, ...(ngDevMode ? [{ debugName: "effectiveErrors" }] : /* istanbul ignore next */ []));
149
+ this.anyInvalid = computed(() => this.aggregate('invalid'), ...(ngDevMode ? [{ debugName: "anyInvalid" }] : /* istanbul ignore next */ []));
150
+ this.anyDirty = computed(() => this.aggregate('dirty'), ...(ngDevMode ? [{ debugName: "anyDirty" }] : /* istanbul ignore next */ []));
151
+ this.anyTouched = computed(() => this.aggregate('touched'), ...(ngDevMode ? [{ debugName: "anyTouched" }] : /* istanbul ignore next */ []));
152
+ this.submitting = computed(() => this.stateProvider()?.submitting?.() ?? false, ...(ngDevMode ? [{ debugName: "submitting" }] : /* istanbul ignore next */ []));
153
+ this.resetTimers = new Set();
154
+ inject(DestroyRef).onDestroy(() => this.resetTimers.forEach((timer) => clearTimeout(timer)));
155
+ }
156
+ remainingErrors() {
157
+ const errors = this.errors() ?? {};
158
+ const cleared = this.clearedNames();
159
+ const result = {};
160
+ for (const key of Object.keys(errors)) {
161
+ if (!cleared.has(key)) {
162
+ result[key] = errors[key];
163
+ }
164
+ }
165
+ return result;
166
+ }
167
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFormRoot, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
168
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxFormRoot, isStandalone: true, selector: "form[rdxFormRoot]", inputs: { errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClearErrors: "onClearErrors", onFormSubmit: "onFormSubmit" }, host: { attributes: { "novalidate": "" }, listeners: { "submit": "onSubmit($event)", "reset": "onReset()" }, properties: { "attr.data-invalid": "anyInvalid() ? \"\" : undefined", "attr.data-dirty": "anyDirty() ? \"\" : undefined", "attr.data-touched": "anyTouched() ? \"\" : undefined", "attr.data-submitting": "submitting() ? \"\" : undefined" } }, providers: [provideFormRootContext(formRootContext)], exportAs: ["rdxFormRoot"], ngImport: i0 }); }
169
+ }
170
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFormRoot, decorators: [{
171
+ type: Directive,
172
+ args: [{
173
+ selector: 'form[rdxFormRoot]',
174
+ exportAs: 'rdxFormRoot',
175
+ providers: [provideFormRootContext(formRootContext)],
176
+ host: {
177
+ novalidate: '',
178
+ '[attr.data-invalid]': 'anyInvalid() ? "" : undefined',
179
+ '[attr.data-dirty]': 'anyDirty() ? "" : undefined',
180
+ '[attr.data-touched]': 'anyTouched() ? "" : undefined',
181
+ '[attr.data-submitting]': 'submitting() ? "" : undefined',
182
+ '(submit)': 'onSubmit($event)',
183
+ '(reset)': 'onReset()'
184
+ }
185
+ }]
186
+ }], ctorParameters: () => [], propDecorators: { errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], onClearErrors: [{ type: i0.Output, args: ["onClearErrors"] }], onFormSubmit: [{ type: i0.Output, args: ["onFormSubmit"] }] } });
187
+
188
+ const _importsForm = [RdxFormRoot];
189
+ class RdxFormModule {
190
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
191
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.9", ngImport: i0, type: RdxFormModule, imports: [RdxFormRoot], exports: [RdxFormRoot] }); }
192
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFormModule }); }
193
+ }
194
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxFormModule, decorators: [{
195
+ type: NgModule,
196
+ args: [{
197
+ imports: [..._importsForm],
198
+ exports: [..._importsForm]
199
+ }]
200
+ }] });
201
+
202
+ /**
203
+ * Generated bundle index. Do not edit.
204
+ */
205
+
206
+ export { RdxFormModule, RdxFormRoot, _importsForm, injectFormRootContext, provideFormRootContext };
207
+ //# sourceMappingURL=radix-ng-primitives-form.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"radix-ng-primitives-form.mjs","sources":["../../../packages/primitives/form/src/form-root.ts","../../../packages/primitives/form/index.ts","../../../packages/primitives/form/radix-ng-primitives-form.ts"],"sourcesContent":["import {\n computed,\n DestroyRef,\n Directive,\n ElementRef,\n inject,\n input,\n linkedSignal,\n output,\n signal\n} from '@angular/core';\nimport { createContext } from '@radix-ng/primitives/core';\n\n/** A normalized external-error map: each field name maps to its message(s) in display order. */\nexport type RdxFormErrors = Record<string, string | string[]>;\n\n/** Payload of {@link RdxFormRoot.onFormSubmit}. */\nexport interface RdxFormSubmitEvent {\n /** The form's values serialized from `FormData` (repeated names collapse into arrays). */\n values: Record<string, FormDataEntryValue | FormDataEntryValue[]>;\n /** The original native submit event (already `preventDefault`-ed). */\n event: SubmitEvent;\n}\n\n/**\n * What a {@link RdxFieldRoot} registers with an enclosing Form. Structural `() =>` accessors keep the\n * Form entry free of any import from `field` (acyclic ng-packagr graph: `field` → `form`).\n */\nexport interface RdxFormFieldRegistration {\n /** The field's `name` (key external errors match against), or `undefined`. */\n name: () => string | undefined;\n /** The field's merged invalid state (includes external errors). */\n invalid: () => boolean;\n /** Whether the field is dirty. */\n dirty: () => boolean;\n /** Whether the field is touched. */\n touched: () => boolean;\n /** Focus the field's control (by its `controlId`). */\n focus: () => void;\n /** Reset the field's interaction state (touched/dirty/focused → false, filled re-sync). */\n resetState: () => void;\n}\n\n/**\n * External owner of form-level state (e.g. a future Signal Forms `[rdxSignalForm]` adapter). Mirrors\n * Field's `RdxFieldState` seam one level up. Each member is optional: a provided accessor wins over the\n * built-in registry/`errors`-input behavior; absent accessors leave the built-in behavior untouched.\n * Kept as framework-free `() =>` accessors (no `@angular/forms/signals` dependency). See ADR 0004.\n */\nexport interface RdxFormState {\n invalid?: () => boolean;\n dirty?: () => boolean;\n touched?: () => boolean;\n submitting?: () => boolean;\n /** Per-name external error source; while provided, the `errors` input + clear-on-edit are inert. */\n errorsFor?: (name: string) => string[];\n}\n\nconst formRootContext = () => {\n const root = inject(RdxFormRoot);\n return {\n errorsFor: (name: string | undefined) => root.errorsFor(name),\n notifyEdited: (name: string | undefined) => root.notifyEdited(name),\n register: (field: RdxFormFieldRegistration) => root.register(field),\n setStateProvider: (provider: RdxFormState | null) => root.setStateProvider(provider),\n hasStateProvider: root.hasStateProvider\n };\n};\n\nexport type RdxFormRootContext = ReturnType<typeof formRootContext>;\n\nexport const [injectFormRootContext, provideFormRootContext] = createContext<RdxFormRootContext>(\n 'RdxFormRoot',\n 'components/form'\n);\n\n/** Collapses `FormData` into a plain object; repeated names collapse into arrays. */\nfunction serializeFormData(data: FormData): Record<string, FormDataEntryValue | FormDataEntryValue[]> {\n const values: Record<string, FormDataEntryValue | FormDataEntryValue[]> = {};\n data.forEach((value, key) => {\n // `Object.hasOwn`, not `key in values` — a control named after an Object.prototype member\n // (`toString`, `constructor`, …) must not be misread as a duplicate.\n if (Object.hasOwn(values, key)) {\n const existing = values[key];\n values[key] = Array.isArray(existing) ? [...existing, value] : [existing, value];\n } else {\n values[key] = value;\n }\n });\n return values;\n}\n\n/**\n * The top of the forms layer cake: a single directive on the native `<form>` element that aggregates\n * field state, maps external (server) errors onto fields by `name`, intercepts submit (values-as-object,\n * focus the first invalid field), and resets field interaction state on native `reset`. It owns no\n * values and runs no validation — Angular form systems (or Field inputs) remain the source of validity.\n *\n * @group Components\n */\n@Directive({\n selector: 'form[rdxFormRoot]',\n exportAs: 'rdxFormRoot',\n providers: [provideFormRootContext(formRootContext)],\n host: {\n novalidate: '',\n '[attr.data-invalid]': 'anyInvalid() ? \"\" : undefined',\n '[attr.data-dirty]': 'anyDirty() ? \"\" : undefined',\n '[attr.data-touched]': 'anyTouched() ? \"\" : undefined',\n '[attr.data-submitting]': 'submitting() ? \"\" : undefined',\n '(submit)': 'onSubmit($event)',\n '(reset)': 'onReset()'\n }\n})\nexport class RdxFormRoot {\n private readonly form = inject<ElementRef<HTMLFormElement>>(ElementRef).nativeElement;\n\n /** External/server validation errors keyed by `Field.Root` `name`. */\n readonly errors = input<RdxFormErrors | null | undefined>();\n\n /** Emits the remaining error map after a field's external error is cleared by a user edit (or reset). */\n readonly onClearErrors = output<RdxFormErrors>();\n\n /** Emits the serialized form values when a valid form is submitted. */\n readonly onFormSubmit = output<RdxFormSubmitEvent>();\n\n private readonly fields = signal<RdxFormFieldRegistration[]>([]);\n\n private readonly stateProvider = signal<RdxFormState | null>(null);\n\n /** Whether an external adapter currently owns form-level state. */\n readonly hasStateProvider = computed(() => this.stateProvider() !== null);\n\n /**\n * Names whose external error has been cleared by a user edit. Reset to empty whenever a new `errors`\n * object reference is assigned — the server just spoke, so everything it said is live again.\n */\n private readonly clearedNames = linkedSignal<RdxFormErrors | null | undefined, Set<string>>({\n source: this.errors,\n computation: () => new Set<string>()\n });\n\n /** The `errors` input minus cleared names, normalized to `string[]`. */\n private readonly effectiveErrors = computed<Record<string, string[]>>(() => {\n const errors = this.errors() ?? {};\n const cleared = this.clearedNames();\n const result: Record<string, string[]> = {};\n for (const key of Object.keys(errors)) {\n if (cleared.has(key)) {\n continue;\n }\n const value = errors[key];\n result[key] = Array.isArray(value) ? value : [value];\n }\n return result;\n });\n\n readonly anyInvalid = computed(() => this.aggregate('invalid'));\n readonly anyDirty = computed(() => this.aggregate('dirty'));\n readonly anyTouched = computed(() => this.aggregate('touched'));\n readonly submitting = computed(() => this.stateProvider()?.submitting?.() ?? false);\n\n /** Resolve a boolean aggregate: a registered provider's accessor wins, else OR over the registry. */\n private aggregate(key: 'invalid' | 'dirty' | 'touched'): boolean {\n const accessor = this.stateProvider()?.[key];\n return accessor ? accessor() : this.fields().some((field) => field[key]());\n }\n\n /** Resolves the external messages for a field name (provider source wins over the `errors` input). */\n errorsFor(name: string | undefined): string[] {\n if (!name) {\n return [];\n }\n const provider = this.stateProvider();\n if (provider?.errorsFor) {\n return provider.errorsFor(name);\n }\n return this.effectiveErrors()[name] ?? [];\n }\n\n /** Clears a field's external error after a user edit, emitting the remaining map. */\n notifyEdited(name: string | undefined): void {\n if (!name) {\n return;\n }\n // While a provider owns errors, Signal Forms clears/reapplies them itself — stay inert.\n if (this.stateProvider()?.errorsFor) {\n return;\n }\n const errors = this.errors() ?? {};\n if (!Object.hasOwn(errors, name) || this.clearedNames().has(name)) {\n return;\n }\n this.clearedNames.update((set) => new Set(set).add(name));\n this.onClearErrors.emit(this.remainingErrors());\n }\n\n register(field: RdxFormFieldRegistration): () => void {\n this.fields.update((list) => [...list, field]);\n return () => this.fields.update((list) => list.filter((item) => item !== field));\n }\n\n /** Register (or clear with `null`) an external owner of form-level state; returns the previous one. */\n setStateProvider(provider: RdxFormState | null): RdxFormState | null {\n const previous = this.stateProvider();\n this.stateProvider.set(provider);\n return previous;\n }\n\n onSubmit(event: SubmitEvent): void {\n // SPA submits never navigate; never stopPropagation so Reactive Forms `(ngSubmit)` keeps firing.\n event.preventDefault();\n\n if (this.aggregate('invalid')) {\n // Focus the first invalid registered field (DOM order); provider-only invalid has none to focus.\n this.fields()\n .find((field) => field.invalid())\n ?.focus();\n return;\n }\n\n const values = serializeFormData(new FormData(this.form));\n this.onFormSubmit.emit({ values, event });\n }\n\n onReset(): void {\n // Don't prevent the native reset — control values revert on their own.\n if (!this.stateProvider()?.errorsFor) {\n const keys = Object.keys(this.errors() ?? {});\n const hadVisible = keys.some((key) => !this.clearedNames().has(key));\n if (keys.length) {\n this.clearedNames.set(new Set(keys));\n }\n if (hadVisible) {\n this.onClearErrors.emit({});\n }\n }\n // Values revert asynchronously relative to the reset event — re-sync field state next macrotask.\n // Read the registry fresh inside the callback (fields may register/unregister in between), and\n // cancel on destroy so resetState never runs against a torn-down field.\n const timer = setTimeout(() => {\n this.resetTimers.delete(timer);\n this.fields().forEach((field) => field.resetState());\n });\n this.resetTimers.add(timer);\n }\n\n private readonly resetTimers = new Set<ReturnType<typeof setTimeout>>();\n\n constructor() {\n inject(DestroyRef).onDestroy(() => this.resetTimers.forEach((timer) => clearTimeout(timer)));\n }\n\n private remainingErrors(): RdxFormErrors {\n const errors = this.errors() ?? {};\n const cleared = this.clearedNames();\n const result: RdxFormErrors = {};\n for (const key of Object.keys(errors)) {\n if (!cleared.has(key)) {\n result[key] = errors[key];\n }\n }\n return result;\n }\n}\n","import { NgModule } from '@angular/core';\nimport { RdxFormRoot } from './src/form-root';\n\nexport * from './src/form-root';\n\nexport const _importsForm = [RdxFormRoot];\n\n@NgModule({\n imports: [..._importsForm],\n exports: [..._importsForm]\n})\nexport class RdxFormModule {}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -4,6 +4,7 @@ import { injectFieldRootContext } from '@radix-ng/primitives/field';
4
4
 
5
5
  let inputId = 0;
6
6
  const attr = (value) => (value ? '' : undefined);
7
+ const numberOrUndefined = (value) => value == null || value === '' ? undefined : Number(value);
7
8
  /**
8
9
  * A headless text input that can integrate with Field for accessible labeling,
9
10
  * descriptions, validation state, and data attributes.
@@ -18,12 +19,20 @@ class RdxInputDirective {
18
19
  this.defaultValueApplied = false;
19
20
  this.filledValue = signal(false, ...(ngDevMode ? [{ debugName: "filledValue" }] : /* istanbul ignore next */ []));
20
21
  this.focusedValue = signal(false, ...(ngDevMode ? [{ debugName: "focusedValue" }] : /* istanbul ignore next */ []));
22
+ this.dirtyValue = signal(false, ...(ngDevMode ? [{ debugName: "dirtyValue" }] : /* istanbul ignore next */ []));
21
23
  /**
22
24
  * The input id. Field labels and descriptions use this value for accessible relationships.
23
25
  *
24
26
  * @group Props
25
27
  */
26
28
  this.id = input(`rdx-input-${inputId++}`, ...(ngDevMode ? [{ debugName: "id" }] : /* istanbul ignore next */ []));
29
+ /**
30
+ * The name of the input, submitted with the form data and used by Form-level
31
+ * error matching.
32
+ *
33
+ * @group Props
34
+ */
35
+ this.name = input(...(ngDevMode ? [undefined, { debugName: "name" }] : /* istanbul ignore next */ []));
27
36
  /**
28
37
  * The controlled input value.
29
38
  *
@@ -42,6 +51,12 @@ class RdxInputDirective {
42
51
  * @group Props
43
52
  */
44
53
  this.disabled = input(false, { ...(ngDevMode ? { debugName: "disabled" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
54
+ /**
55
+ * Whether the input is read-only.
56
+ *
57
+ * @group Props
58
+ */
59
+ this.readonly = input(false, { ...(ngDevMode ? { debugName: "readonly" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
45
60
  /**
46
61
  * Whether the input is required.
47
62
  *
@@ -54,17 +69,72 @@ class RdxInputDirective {
54
69
  * @group Props
55
70
  */
56
71
  this.invalid = input(false, { ...(ngDevMode ? { debugName: "invalid" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
72
+ /**
73
+ * Whether the input has been touched. A two-way model: the input sets it on
74
+ * blur (emitting `touchedChange`, which Signal Forms' `[formField]` listens
75
+ * to), and a form system can write it back.
76
+ *
77
+ * @group Props
78
+ */
79
+ this.touched = model(false, ...(ngDevMode ? [{ debugName: "touched" }] : /* istanbul ignore next */ []));
80
+ /**
81
+ * Whether the input value has changed from its initial value. Merged with the
82
+ * internally tracked state; a form system can own it through this input.
83
+ *
84
+ * @group Props
85
+ */
86
+ this.dirty = input(false, { ...(ngDevMode ? { debugName: "dirty" } : /* istanbul ignore next */ {}), transform: booleanAttribute });
87
+ /**
88
+ * Validation errors for the input. A non-empty list marks the input invalid.
89
+ *
90
+ * @group Props
91
+ */
92
+ this.errors = input([], ...(ngDevMode ? [{ debugName: "errors" }] : /* istanbul ignore next */ []));
93
+ /**
94
+ * Minimum number of characters.
95
+ *
96
+ * @group Props
97
+ */
98
+ this.minLength = input(undefined, { ...(ngDevMode ? { debugName: "minLength" } : /* istanbul ignore next */ {}), transform: numberOrUndefined });
99
+ /**
100
+ * Maximum number of characters.
101
+ *
102
+ * @group Props
103
+ */
104
+ this.maxLength = input(undefined, { ...(ngDevMode ? { debugName: "maxLength" } : /* istanbul ignore next */ {}), transform: numberOrUndefined });
105
+ /**
106
+ * Patterns the value must match. Reflected to the native `pattern` attribute
107
+ * only when exactly one pattern is provided (the attribute holds a single regex).
108
+ *
109
+ * @group Props
110
+ */
111
+ this.pattern = input([], ...(ngDevMode ? [{ debugName: "pattern" }] : /* istanbul ignore next */ []));
57
112
  /**
58
113
  * Emits when the input value changes.
59
114
  *
60
115
  * @group Emits
61
116
  */
62
117
  this.onValueChange = output();
63
- this.invalidState = computed(() => this.invalid() || Boolean(this.fieldRootContext?.invalidState()), ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
118
+ /**
119
+ * Emits on blur, notifying a form system the input was touched. Stable
120
+ * Angular 22 Signal Forms listens to this `touch` output; the 21.x
121
+ * experimental implementation listens to the `touched` model's
122
+ * `touchedChange` instead — both are emitted, covering either version.
123
+ *
124
+ * @group Emits
125
+ */
126
+ this.touch = output();
127
+ this.invalidState = computed(() => this.invalid() || (this.errors()?.length ?? 0) > 0 || Boolean(this.fieldRootContext?.invalidState()), ...(ngDevMode ? [{ debugName: "invalidState" }] : /* istanbul ignore next */ []));
64
128
  this.disabledState = computed(() => this.disabled() || Boolean(this.fieldRootContext?.disabledState()), ...(ngDevMode ? [{ debugName: "disabledState" }] : /* istanbul ignore next */ []));
65
129
  this.requiredState = computed(() => this.required() || Boolean(this.fieldRootContext?.requiredState()), ...(ngDevMode ? [{ debugName: "requiredState" }] : /* istanbul ignore next */ []));
66
130
  this.filledState = computed(() => this.filledValue() || Boolean(this.fieldRootContext?.filledState()), ...(ngDevMode ? [{ debugName: "filledState" }] : /* istanbul ignore next */ []));
67
131
  this.focusedState = computed(() => this.focusedValue() || Boolean(this.fieldRootContext?.focusedState()), ...(ngDevMode ? [{ debugName: "focusedState" }] : /* istanbul ignore next */ []));
132
+ this.touchedState = computed(() => this.touched() || Boolean(this.fieldRootContext?.touchedState()), ...(ngDevMode ? [{ debugName: "touchedState" }] : /* istanbul ignore next */ []));
133
+ this.dirtyState = computed(() => this.dirty() || this.dirtyValue() || Boolean(this.fieldRootContext?.dirtyState()), ...(ngDevMode ? [{ debugName: "dirtyState" }] : /* istanbul ignore next */ []));
134
+ this.patternAttr = computed(() => {
135
+ const patterns = this.pattern();
136
+ return patterns?.length === 1 ? patterns[0].source : undefined;
137
+ }, ...(ngDevMode ? [{ debugName: "patternAttr" }] : /* istanbul ignore next */ []));
68
138
  this.describedBy = computed(() => {
69
139
  if (!this.fieldRootContext) {
70
140
  return undefined;
@@ -103,6 +173,8 @@ class RdxInputDirective {
103
173
  }
104
174
  onBlur() {
105
175
  this.focusedValue.set(false);
176
+ this.touched.set(true);
177
+ this.touch.emit();
106
178
  this.fieldRootContext?.setFocused(false);
107
179
  this.fieldRootContext?.setTouched(true);
108
180
  }
@@ -127,15 +199,16 @@ class RdxInputDirective {
127
199
  syncFieldState() {
128
200
  const value = this.element.value;
129
201
  this.filledValue.set(value !== '');
202
+ this.dirtyValue.set(value !== this.initialValue);
130
203
  this.fieldRootContext?.setFilled(value !== '');
131
204
  this.fieldRootContext?.setDirty(value !== this.initialValue);
132
205
  }
133
206
  writeValue(value) {
134
- this.element.value = Array.isArray(value) ? value.join(',') : String(value);
207
+ this.element.value = value;
135
208
  this.syncFieldState();
136
209
  }
137
210
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxInputDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
138
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxInputDirective, isStandalone: true, selector: "input[rdxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", onValueChange: "onValueChange" }, host: { listeners: { "focus": "onFocus()", "blur": "onBlur()", "input": "onInput($event)", "change": "syncFieldState()" }, properties: { "attr.id": "id()", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "invalidState() ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "attr.data-invalid": "dataAttr(invalidState())", "attr.data-valid": "dataAttr(!invalidState())", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())" } }, exportAs: ["rdxInput"], ngImport: i0 }); }
211
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.9", type: RdxInputDirective, isStandalone: true, selector: "input[rdxInput]", inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, value: { classPropertyName: "value", publicName: "value", isSignal: true, isRequired: false, transformFunction: null }, defaultValue: { classPropertyName: "defaultValue", publicName: "defaultValue", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, readonly: { classPropertyName: "readonly", publicName: "readonly", isSignal: true, isRequired: false, transformFunction: null }, required: { classPropertyName: "required", publicName: "required", isSignal: true, isRequired: false, transformFunction: null }, invalid: { classPropertyName: "invalid", publicName: "invalid", isSignal: true, isRequired: false, transformFunction: null }, touched: { classPropertyName: "touched", publicName: "touched", isSignal: true, isRequired: false, transformFunction: null }, dirty: { classPropertyName: "dirty", publicName: "dirty", isSignal: true, isRequired: false, transformFunction: null }, errors: { classPropertyName: "errors", publicName: "errors", isSignal: true, isRequired: false, transformFunction: null }, minLength: { classPropertyName: "minLength", publicName: "minLength", isSignal: true, isRequired: false, transformFunction: null }, maxLength: { classPropertyName: "maxLength", publicName: "maxLength", isSignal: true, isRequired: false, transformFunction: null }, pattern: { classPropertyName: "pattern", publicName: "pattern", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { value: "valueChange", touched: "touchedChange", onValueChange: "onValueChange", touch: "touch" }, host: { listeners: { "focus": "onFocus()", "blur": "onBlur()", "input": "onInput($event)", "change": "syncFieldState()" }, properties: { "attr.id": "id()", "attr.name": "name() || undefined", "attr.aria-describedby": "describedBy()", "attr.aria-invalid": "invalidState() ? \"true\" : undefined", "attr.aria-required": "requiredState() ? \"true\" : undefined", "attr.aria-disabled": "disabledState() ? \"true\" : undefined", "attr.disabled": "disabledState() ? \"\" : undefined", "attr.required": "requiredState() ? \"\" : undefined", "attr.readonly": "readonly() ? \"\" : undefined", "attr.minlength": "minLength() ?? undefined", "attr.maxlength": "maxLength() ?? undefined", "attr.pattern": "patternAttr()", "attr.data-invalid": "dataAttr(invalidState())", "attr.data-valid": "dataAttr(!invalidState())", "attr.data-disabled": "dataAttr(disabledState())", "attr.data-required": "dataAttr(requiredState())", "attr.data-readonly": "dataAttr(readonly())", "attr.data-filled": "dataAttr(filledState())", "attr.data-focused": "dataAttr(focusedState())", "attr.data-touched": "dataAttr(touchedState())", "attr.data-dirty": "dataAttr(dirtyState())" } }, exportAs: ["rdxInput"], ngImport: i0 }); }
139
212
  }
140
213
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: RdxInputDirective, decorators: [{
141
214
  type: Directive,
@@ -144,25 +217,33 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
144
217
  exportAs: 'rdxInput',
145
218
  host: {
146
219
  '[attr.id]': 'id()',
220
+ '[attr.name]': 'name() || undefined',
147
221
  '[attr.aria-describedby]': 'describedBy()',
148
222
  '[attr.aria-invalid]': 'invalidState() ? "true" : undefined',
149
223
  '[attr.aria-required]': 'requiredState() ? "true" : undefined',
150
224
  '[attr.aria-disabled]': 'disabledState() ? "true" : undefined',
151
225
  '[attr.disabled]': 'disabledState() ? "" : undefined',
152
226
  '[attr.required]': 'requiredState() ? "" : undefined',
227
+ '[attr.readonly]': 'readonly() ? "" : undefined',
228
+ '[attr.minlength]': 'minLength() ?? undefined',
229
+ '[attr.maxlength]': 'maxLength() ?? undefined',
230
+ '[attr.pattern]': 'patternAttr()',
153
231
  '[attr.data-invalid]': 'dataAttr(invalidState())',
154
232
  '[attr.data-valid]': 'dataAttr(!invalidState())',
155
233
  '[attr.data-disabled]': 'dataAttr(disabledState())',
156
234
  '[attr.data-required]': 'dataAttr(requiredState())',
235
+ '[attr.data-readonly]': 'dataAttr(readonly())',
157
236
  '[attr.data-filled]': 'dataAttr(filledState())',
158
237
  '[attr.data-focused]': 'dataAttr(focusedState())',
238
+ '[attr.data-touched]': 'dataAttr(touchedState())',
239
+ '[attr.data-dirty]': 'dataAttr(dirtyState())',
159
240
  '(focus)': 'onFocus()',
160
241
  '(blur)': 'onBlur()',
161
242
  '(input)': 'onInput($event)',
162
243
  '(change)': 'syncFieldState()'
163
244
  }
164
245
  }]
165
- }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
246
+ }], ctorParameters: () => [], propDecorators: { id: [{ type: i0.Input, args: [{ isSignal: true, alias: "id", required: false }] }], name: [{ type: i0.Input, args: [{ isSignal: true, alias: "name", required: false }] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], defaultValue: [{ type: i0.Input, args: [{ isSignal: true, alias: "defaultValue", required: false }] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }], readonly: [{ type: i0.Input, args: [{ isSignal: true, alias: "readonly", required: false }] }], required: [{ type: i0.Input, args: [{ isSignal: true, alias: "required", required: false }] }], invalid: [{ type: i0.Input, args: [{ isSignal: true, alias: "invalid", required: false }] }], touched: [{ type: i0.Input, args: [{ isSignal: true, alias: "touched", required: false }] }, { type: i0.Output, args: ["touchedChange"] }], dirty: [{ type: i0.Input, args: [{ isSignal: true, alias: "dirty", required: false }] }], errors: [{ type: i0.Input, args: [{ isSignal: true, alias: "errors", required: false }] }], minLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "minLength", required: false }] }], maxLength: [{ type: i0.Input, args: [{ isSignal: true, alias: "maxLength", required: false }] }], pattern: [{ type: i0.Input, args: [{ isSignal: true, alias: "pattern", required: false }] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }], touch: [{ type: i0.Output, args: ["touch"] }] } });
166
247
 
167
248
  /**
168
249
  * Generated bundle index. Do not edit.
@@ -1 +1 @@
1
- {"version":3,"file":"radix-ng-primitives-input.mjs","sources":["../../../packages/primitives/input/src/input.directive.ts","../../../packages/primitives/input/radix-ng-primitives-input.ts"],"sourcesContent":["import {\n afterNextRender,\n booleanAttribute,\n computed,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n model,\n output,\n signal\n} from '@angular/core';\nimport { BooleanInput, RdxFormValueControl } from '@radix-ng/primitives/core';\nimport { injectFieldRootContext } from '@radix-ng/primitives/field';\n\nlet inputId = 0;\n\nconst attr = (value: boolean) => (value ? '' : undefined);\n\nexport type RdxInputValue = string | number | readonly string[];\n\nexport interface RdxInputValueChangeEventDetails {\n event: Event;\n cancel: () => void;\n isCanceled: () => boolean;\n}\n\nexport interface RdxInputValueChangeEvent {\n value: string;\n eventDetails: RdxInputValueChangeEventDetails;\n}\n\n/**\n * A headless text input that can integrate with Field for accessible labeling,\n * descriptions, validation state, and data attributes.\n *\n * @group Components\n */\n@Directive({\n selector: 'input[rdxInput]',\n exportAs: 'rdxInput',\n host: {\n '[attr.id]': 'id()',\n '[attr.aria-describedby]': 'describedBy()',\n '[attr.aria-invalid]': 'invalidState() ? \"true\" : undefined',\n '[attr.aria-required]': 'requiredState() ? \"true\" : undefined',\n '[attr.aria-disabled]': 'disabledState() ? \"true\" : undefined',\n '[attr.disabled]': 'disabledState() ? \"\" : undefined',\n '[attr.required]': 'requiredState() ? \"\" : undefined',\n '[attr.data-invalid]': 'dataAttr(invalidState())',\n '[attr.data-valid]': 'dataAttr(!invalidState())',\n '[attr.data-disabled]': 'dataAttr(disabledState())',\n '[attr.data-required]': 'dataAttr(requiredState())',\n '[attr.data-filled]': 'dataAttr(filledState())',\n '[attr.data-focused]': 'dataAttr(focusedState())',\n '(focus)': 'onFocus()',\n '(blur)': 'onBlur()',\n '(input)': 'onInput($event)',\n '(change)': 'syncFieldState()'\n }\n})\nexport class RdxInputDirective implements RdxFormValueControl<RdxInputValue | undefined> {\n private readonly element = inject<ElementRef<HTMLInputElement>>(ElementRef).nativeElement;\n private readonly fieldRootContext = injectFieldRootContext(true);\n private initialValue = '';\n private defaultValueApplied = false;\n private readonly filledValue = signal(false);\n private readonly focusedValue = signal(false);\n\n /**\n * The input id. Field labels and descriptions use this value for accessible relationships.\n *\n * @group Props\n */\n readonly id = input(`rdx-input-${inputId++}`);\n\n /**\n * The controlled input value.\n *\n * @group Props\n */\n readonly value = model<RdxInputValue | undefined>(undefined);\n\n /**\n * The initial value when the input is uncontrolled.\n *\n * @group Props\n */\n readonly defaultValue = input<RdxInputValue | undefined>(undefined);\n\n /**\n * Whether the input is disabled.\n *\n * @group Props\n */\n readonly disabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input is required.\n *\n * @group Props\n */\n readonly required = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input is invalid.\n *\n * @group Props\n */\n readonly invalid = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Emits when the input value changes.\n *\n * @group Emits\n */\n readonly onValueChange = output<RdxInputValueChangeEvent>();\n\n protected readonly invalidState = computed(() => this.invalid() || Boolean(this.fieldRootContext?.invalidState()));\n protected readonly disabledState = computed(\n () => this.disabled() || Boolean(this.fieldRootContext?.disabledState())\n );\n protected readonly requiredState = computed(\n () => this.required() || Boolean(this.fieldRootContext?.requiredState())\n );\n protected readonly filledState = computed(\n () => this.filledValue() || Boolean(this.fieldRootContext?.filledState())\n );\n protected readonly focusedState = computed(\n () => this.focusedValue() || Boolean(this.fieldRootContext?.focusedState())\n );\n\n protected readonly describedBy = computed(() => {\n if (!this.fieldRootContext) {\n return undefined;\n }\n\n const ids = [\n ...this.fieldRootContext.descriptionIds(),\n ...(this.fieldRootContext.invalidState() ? this.fieldRootContext.errorIds() : [])\n ];\n\n return ids.length ? ids.join(' ') : undefined;\n });\n\n constructor() {\n effect(() => {\n const value = this.value();\n\n if (value !== undefined) {\n this.writeValue(value);\n }\n });\n\n effect(() => {\n const defaultValue = this.defaultValue();\n\n if (this.value() === undefined && defaultValue !== undefined && !this.defaultValueApplied) {\n this.defaultValueApplied = true;\n this.writeValue(defaultValue);\n }\n });\n\n effect(() => {\n this.fieldRootContext?.setControlId(this.id());\n });\n\n afterNextRender(() => {\n this.initialValue = this.element.value;\n this.syncFieldState();\n });\n }\n\n onFocus(): void {\n this.focusedValue.set(true);\n this.fieldRootContext?.setFocused(true);\n }\n\n onBlur(): void {\n this.focusedValue.set(false);\n this.fieldRootContext?.setFocused(false);\n this.fieldRootContext?.setTouched(true);\n }\n\n onInput(event: Event): void {\n const nextValue = this.element.value;\n let canceled = false;\n\n const eventDetails: RdxInputValueChangeEventDetails = {\n event,\n cancel: () => {\n canceled = true;\n },\n isCanceled: () => canceled\n };\n\n this.onValueChange.emit({ value: nextValue, eventDetails });\n\n if (canceled) {\n this.writeValue(this.value() ?? this.defaultValue() ?? '');\n return;\n }\n\n this.value.set(nextValue);\n this.syncFieldState();\n }\n\n syncFieldState(): void {\n const value = this.element.value;\n\n this.filledValue.set(value !== '');\n this.fieldRootContext?.setFilled(value !== '');\n this.fieldRootContext?.setDirty(value !== this.initialValue);\n }\n\n private writeValue(value: RdxInputValue): void {\n this.element.value = Array.isArray(value) ? value.join(',') : String(value);\n this.syncFieldState();\n }\n\n protected readonly dataAttr = attr;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"radix-ng-primitives-input.mjs","sources":["../../../packages/primitives/input/src/input.directive.ts","../../../packages/primitives/input/radix-ng-primitives-input.ts"],"sourcesContent":["import {\n afterNextRender,\n booleanAttribute,\n computed,\n Directive,\n effect,\n ElementRef,\n inject,\n input,\n model,\n output,\n signal\n} from '@angular/core';\nimport { BooleanInput, NumberInput, RdxFormValueControl, RdxValidationError } from '@radix-ng/primitives/core';\nimport { injectFieldRootContext } from '@radix-ng/primitives/field';\n\nlet inputId = 0;\n\nconst attr = (value: boolean) => (value ? '' : undefined);\nconst numberOrUndefined = (value: unknown): number | undefined =>\n value == null || value === '' ? undefined : Number(value);\n\n/**\n * The input value. Native text inputs always produce strings, so the model is\n * `string` — matching Signal Forms' `FormValueControl<string>` round-trip.\n */\nexport type RdxInputValue = string;\n\nexport interface RdxInputValueChangeEventDetails {\n event: Event;\n cancel: () => void;\n isCanceled: () => boolean;\n}\n\nexport interface RdxInputValueChangeEvent {\n value: string;\n eventDetails: RdxInputValueChangeEventDetails;\n}\n\n/**\n * A headless text input that can integrate with Field for accessible labeling,\n * descriptions, validation state, and data attributes.\n *\n * @group Components\n */\n@Directive({\n selector: 'input[rdxInput]',\n exportAs: 'rdxInput',\n host: {\n '[attr.id]': 'id()',\n '[attr.name]': 'name() || undefined',\n '[attr.aria-describedby]': 'describedBy()',\n '[attr.aria-invalid]': 'invalidState() ? \"true\" : undefined',\n '[attr.aria-required]': 'requiredState() ? \"true\" : undefined',\n '[attr.aria-disabled]': 'disabledState() ? \"true\" : undefined',\n '[attr.disabled]': 'disabledState() ? \"\" : undefined',\n '[attr.required]': 'requiredState() ? \"\" : undefined',\n '[attr.readonly]': 'readonly() ? \"\" : undefined',\n '[attr.minlength]': 'minLength() ?? undefined',\n '[attr.maxlength]': 'maxLength() ?? undefined',\n '[attr.pattern]': 'patternAttr()',\n '[attr.data-invalid]': 'dataAttr(invalidState())',\n '[attr.data-valid]': 'dataAttr(!invalidState())',\n '[attr.data-disabled]': 'dataAttr(disabledState())',\n '[attr.data-required]': 'dataAttr(requiredState())',\n '[attr.data-readonly]': 'dataAttr(readonly())',\n '[attr.data-filled]': 'dataAttr(filledState())',\n '[attr.data-focused]': 'dataAttr(focusedState())',\n '[attr.data-touched]': 'dataAttr(touchedState())',\n '[attr.data-dirty]': 'dataAttr(dirtyState())',\n '(focus)': 'onFocus()',\n '(blur)': 'onBlur()',\n '(input)': 'onInput($event)',\n '(change)': 'syncFieldState()'\n }\n})\nexport class RdxInputDirective implements RdxFormValueControl<RdxInputValue | undefined> {\n private readonly element = inject<ElementRef<HTMLInputElement>>(ElementRef).nativeElement;\n private readonly fieldRootContext = injectFieldRootContext(true);\n private initialValue = '';\n private defaultValueApplied = false;\n private readonly filledValue = signal(false);\n private readonly focusedValue = signal(false);\n private readonly dirtyValue = signal(false);\n\n /**\n * The input id. Field labels and descriptions use this value for accessible relationships.\n *\n * @group Props\n */\n readonly id = input(`rdx-input-${inputId++}`);\n\n /**\n * The name of the input, submitted with the form data and used by Form-level\n * error matching.\n *\n * @group Props\n */\n readonly name = input<string>();\n\n /**\n * The controlled input value.\n *\n * @group Props\n */\n readonly value = model<RdxInputValue | undefined>(undefined);\n\n /**\n * The initial value when the input is uncontrolled.\n *\n * @group Props\n */\n readonly defaultValue = input<RdxInputValue | undefined>(undefined);\n\n /**\n * Whether the input is disabled.\n *\n * @group Props\n */\n readonly disabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input is read-only.\n *\n * @group Props\n */\n readonly readonly = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input is required.\n *\n * @group Props\n */\n readonly required = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input is invalid.\n *\n * @group Props\n */\n readonly invalid = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Whether the input has been touched. A two-way model: the input sets it on\n * blur (emitting `touchedChange`, which Signal Forms' `[formField]` listens\n * to), and a form system can write it back.\n *\n * @group Props\n */\n readonly touched = model<boolean>(false);\n\n /**\n * Whether the input value has changed from its initial value. Merged with the\n * internally tracked state; a form system can own it through this input.\n *\n * @group Props\n */\n readonly dirty = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n /**\n * Validation errors for the input. A non-empty list marks the input invalid.\n *\n * @group Props\n */\n readonly errors = input<readonly RdxValidationError[]>([]);\n\n /**\n * Minimum number of characters.\n *\n * @group Props\n */\n readonly minLength = input<number | undefined, NumberInput>(undefined, { transform: numberOrUndefined });\n\n /**\n * Maximum number of characters.\n *\n * @group Props\n */\n readonly maxLength = input<number | undefined, NumberInput>(undefined, { transform: numberOrUndefined });\n\n /**\n * Patterns the value must match. Reflected to the native `pattern` attribute\n * only when exactly one pattern is provided (the attribute holds a single regex).\n *\n * @group Props\n */\n readonly pattern = input<readonly RegExp[]>([]);\n\n /**\n * Emits when the input value changes.\n *\n * @group Emits\n */\n readonly onValueChange = output<RdxInputValueChangeEvent>();\n\n /**\n * Emits on blur, notifying a form system the input was touched. Stable\n * Angular 22 Signal Forms listens to this `touch` output; the 21.x\n * experimental implementation listens to the `touched` model's\n * `touchedChange` instead — both are emitted, covering either version.\n *\n * @group Emits\n */\n readonly touch = output<void>();\n\n protected readonly invalidState = computed(\n () => this.invalid() || (this.errors()?.length ?? 0) > 0 || Boolean(this.fieldRootContext?.invalidState())\n );\n protected readonly disabledState = computed(\n () => this.disabled() || Boolean(this.fieldRootContext?.disabledState())\n );\n protected readonly requiredState = computed(\n () => this.required() || Boolean(this.fieldRootContext?.requiredState())\n );\n protected readonly filledState = computed(\n () => this.filledValue() || Boolean(this.fieldRootContext?.filledState())\n );\n protected readonly focusedState = computed(\n () => this.focusedValue() || Boolean(this.fieldRootContext?.focusedState())\n );\n protected readonly touchedState = computed(() => this.touched() || Boolean(this.fieldRootContext?.touchedState()));\n protected readonly dirtyState = computed(\n () => this.dirty() || this.dirtyValue() || Boolean(this.fieldRootContext?.dirtyState())\n );\n\n protected readonly patternAttr = computed(() => {\n const patterns = this.pattern();\n return patterns?.length === 1 ? patterns[0].source : undefined;\n });\n\n protected readonly describedBy = computed(() => {\n if (!this.fieldRootContext) {\n return undefined;\n }\n\n const ids = [\n ...this.fieldRootContext.descriptionIds(),\n ...(this.fieldRootContext.invalidState() ? this.fieldRootContext.errorIds() : [])\n ];\n\n return ids.length ? ids.join(' ') : undefined;\n });\n\n constructor() {\n effect(() => {\n const value = this.value();\n\n if (value !== undefined) {\n this.writeValue(value);\n }\n });\n\n effect(() => {\n const defaultValue = this.defaultValue();\n\n if (this.value() === undefined && defaultValue !== undefined && !this.defaultValueApplied) {\n this.defaultValueApplied = true;\n this.writeValue(defaultValue);\n }\n });\n\n effect(() => {\n this.fieldRootContext?.setControlId(this.id());\n });\n\n afterNextRender(() => {\n this.initialValue = this.element.value;\n this.syncFieldState();\n });\n }\n\n onFocus(): void {\n this.focusedValue.set(true);\n this.fieldRootContext?.setFocused(true);\n }\n\n onBlur(): void {\n this.focusedValue.set(false);\n this.touched.set(true);\n this.touch.emit();\n this.fieldRootContext?.setFocused(false);\n this.fieldRootContext?.setTouched(true);\n }\n\n onInput(event: Event): void {\n const nextValue = this.element.value;\n let canceled = false;\n\n const eventDetails: RdxInputValueChangeEventDetails = {\n event,\n cancel: () => {\n canceled = true;\n },\n isCanceled: () => canceled\n };\n\n this.onValueChange.emit({ value: nextValue, eventDetails });\n\n if (canceled) {\n this.writeValue(this.value() ?? this.defaultValue() ?? '');\n return;\n }\n\n this.value.set(nextValue);\n this.syncFieldState();\n }\n\n syncFieldState(): void {\n const value = this.element.value;\n\n this.filledValue.set(value !== '');\n this.dirtyValue.set(value !== this.initialValue);\n this.fieldRootContext?.setFilled(value !== '');\n this.fieldRootContext?.setDirty(value !== this.initialValue);\n }\n\n private writeValue(value: RdxInputValue): void {\n this.element.value = value;\n this.syncFieldState();\n }\n\n protected readonly dataAttr = attr;\n}\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":[],"mappings":"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"}
@@ -12,7 +12,7 @@ import * as i1$1 from '@radix-ng/primitives/portal';
12
12
  import { RdxPortal } from '@radix-ng/primitives/portal';
13
13
  import { isPlatformBrowser } from '@angular/common';
14
14
 
15
- const [injectRdxMenuRootContext, provideRdxMenuRootContext] = createContext('RdxMenuRootContext');
15
+ const [injectRdxMenuRootContext, provideRdxMenuRootContext] = createContext('RdxMenuRootContext', 'components/menu');
16
16
  function buildContext(instance) {
17
17
  return {
18
18
  isOpen: instance.open,
@@ -254,7 +254,7 @@ function getCheckedState(checked) {
254
254
  return isIndeterminate(checked) ? 'indeterminate' : checked ? 'checked' : 'unchecked';
255
255
  }
256
256
 
257
- const [injectRdxMenuCheckboxItemContext, provideRdxMenuCheckboxItemContext] = createContext('RdxMenuCheckboxItemContext');
257
+ const [injectRdxMenuCheckboxItemContext, provideRdxMenuCheckboxItemContext] = createContext('RdxMenuCheckboxItemContext', 'components/menu');
258
258
  const checkboxItemContextFactory = () => {
259
259
  const instance = inject(RdxMenuCheckboxItem);
260
260
  return {
@@ -993,7 +993,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
993
993
  }]
994
994
  }], propDecorators: { anchor: [{ type: i0.Input, args: [{ isSignal: true, alias: "anchor", required: false }] }], side: [{ type: i0.Input, args: [{ isSignal: true, alias: "side", required: false }] }], sideOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "sideOffset", required: false }] }], align: [{ type: i0.Input, args: [{ isSignal: true, alias: "align", required: false }] }], alignOffset: [{ type: i0.Input, args: [{ isSignal: true, alias: "alignOffset", required: false }] }], arrowPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "arrowPadding", required: false }] }], avoidCollisions: [{ type: i0.Input, args: [{ isSignal: true, alias: "avoidCollisions", required: false }] }], collisionBoundary: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionBoundary", required: false }] }], collisionPadding: [{ type: i0.Input, args: [{ isSignal: true, alias: "collisionPadding", required: false }] }], sticky: [{ type: i0.Input, args: [{ isSignal: true, alias: "sticky", required: false }] }], hideWhenDetached: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideWhenDetached", required: false }] }], positionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionStrategy", required: false }] }], updatePositionStrategy: [{ type: i0.Input, args: [{ isSignal: true, alias: "updatePositionStrategy", required: false }] }], placed: [{ type: i0.Output, args: ["placed"] }] } });
995
995
 
996
- const [injectRdxMenuRadioGroupContext, provideRdxMenuRadioGroupContext] = createContext('RdxMenuRadioGroupContext');
996
+ const [injectRdxMenuRadioGroupContext, provideRdxMenuRadioGroupContext] = createContext('RdxMenuRadioGroupContext', 'components/menu');
997
997
  const radioGroupContextFactory = () => {
998
998
  const instance = inject(RdxMenuRadioGroup);
999
999
  return {
@@ -1034,7 +1034,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
1034
1034
  }]
1035
1035
  }], propDecorators: { value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], onValueChange: [{ type: i0.Output, args: ["onValueChange"] }] } });
1036
1036
 
1037
- const [injectRdxMenuRadioItemContext, provideRdxMenuRadioItemContext] = createContext('RdxMenuRadioItemContext');
1037
+ const [injectRdxMenuRadioItemContext, provideRdxMenuRadioItemContext] = createContext('RdxMenuRadioItemContext', 'components/menu');
1038
1038
  const radioItemContextFactory = () => {
1039
1039
  const instance = inject(RdxMenuRadioItem);
1040
1040
  return {