@dvirus-js/angular-signals 0.0.1

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.
package/README.md ADDED
@@ -0,0 +1,174 @@
1
+ # Angular Signals Library
2
+
3
+ `@dvirus-js/angular-signals` provides two things:
4
+
5
+ - `signalForm`: typed Angular signal-based forms with controls, groups, arrays, validators, warnings, and disabled state.
6
+ - signal utilities: helpers for Angular signals, reactive objects, debounced state, reactive `Map`/`Set`, and wrappers for Angular Reactive Forms.
7
+
8
+ ## Install
9
+
10
+ ```bash
11
+ npm install @dvirus-js/angular-signals
12
+ ```
13
+
14
+ Peer dependencies: `@angular/core`, `@angular/forms`, and `rxjs`.
15
+
16
+ ## Main Exports
17
+
18
+ - `signalForm`, `formGroup`, `formControl`, `formArray`: build typed signal-based forms.
19
+ - `signalFormValidators`: built-in validators like `required`, `email`, `min`, `max`, `minLength`, `maxLength`, `pattern`.
20
+ - `controlSignal`, `formGroupSignal`, `formArraySignal`: expose Angular Reactive Forms state as signals.
21
+ - `signalDebounce`, `signalMap`, `signalSet`, `signalObject`, `signalNotifier`: general signal utilities.
22
+ - `toSignalObj`, `fromSignalObj`, `signalOrValue`, `signalOrFunction`, `writableSignal`, `tryCatch`: low-level helpers.
23
+
24
+ ## Examples
25
+
26
+ ### Signal form
27
+
28
+ Use `signalForm` to model nested objects and arrays with reactive value, error, warning, touched, dirty, and disabled state.
29
+
30
+ ```ts
31
+ import { signalForm, signalFormValidators } from '@dvirus-js/angular-signals';
32
+
33
+ const profileForm = signalForm({
34
+ name: {
35
+ value: '',
36
+ validators: [signalFormValidators.required, signalFormValidators.minLength(2)],
37
+ },
38
+ age: {
39
+ value: 18,
40
+ validators: [signalFormValidators.min(0)],
41
+ warnings: [signalFormValidators.max(120)],
42
+ },
43
+ tags: ['angular', 'signals'],
44
+ });
45
+
46
+ profileForm.controls.name.setValue('Ada');
47
+ profileForm.controls.tags.push('forms');
48
+
49
+ profileForm.value();
50
+ profileForm.valid();
51
+ profileForm.controls.name.errors();
52
+ profileForm.controls.age.firstErrorOrWarning();
53
+ ```
54
+
55
+ ### Dynamic disabled and cross-field logic
56
+
57
+ Validators and `disabled` rules can read sibling controls through `getControl`.
58
+
59
+ ```ts
60
+ import { signalForm, signalFormValidators } from '@dvirus-js/angular-signals';
61
+
62
+ const accountForm = signalForm({
63
+ role: 'user',
64
+ adminCode: {
65
+ value: '',
66
+ validators: [
67
+ ({ item, getControl }) =>
68
+ getControl('role').value() === 'admin' && !item.value
69
+ ? { requiredForAdmin: 'Admin code is required' }
70
+ : null,
71
+ ],
72
+ disabled: ({ getControl }) => getControl('role').value() !== 'admin',
73
+ },
74
+ });
75
+
76
+ accountForm.controls.role.setValue('admin');
77
+ accountForm.controls.adminCode.disabled(); // false
78
+ ```
79
+
80
+ ### Angular Reactive Forms bridge
81
+
82
+ Use `controlSignal`, `formGroupSignal`, or `formArraySignal` when you already have `@angular/forms` controls and want signal accessors.
83
+
84
+ ```ts
85
+ import { effect } from '@angular/core';
86
+ import { FormControl, FormGroup } from '@angular/forms';
87
+ import { controlSignal, formGroupSignal } from '@dvirus-js/angular-signals';
88
+
89
+ const nameControl = new FormControl('Ada');
90
+ const nameSig = controlSignal(nameControl);
91
+
92
+ effect(() => {
93
+ console.log(nameSig.value(), nameSig.invalid(), nameSig.touched());
94
+ });
95
+
96
+ const form = new FormGroup({
97
+ firstName: new FormControl('Ada'),
98
+ lastName: new FormControl('Lovelace'),
99
+ });
100
+
101
+ const formSig = formGroupSignal(form);
102
+ console.log(formSig.controls.firstName.value());
103
+ ```
104
+
105
+ ### Signal utilities
106
+
107
+ These helpers cover debounced state, reactive collections, reactive objects, and signal/value conversion.
108
+
109
+ ```ts
110
+ import {
111
+ effect,
112
+ signal,
113
+ } from '@angular/core';
114
+ import {
115
+ fromSignalObj,
116
+ signalDebounce,
117
+ signalMap,
118
+ signalNotifier,
119
+ signalObject,
120
+ signalOrValue,
121
+ signalSet,
122
+ toSignalObj,
123
+ } from '@dvirus-js/angular-signals';
124
+
125
+ const search = signalDebounce({ debounceTime: 300, initialValue: '' });
126
+ search.setDebounced('angular');
127
+ search.isLoading();
128
+
129
+ const selected = signalSet<number>();
130
+ selected.add(1);
131
+ selected.toggle(2);
132
+ selected.toArray();
133
+
134
+ const cache = signalMap<string, number>({ a: 1 });
135
+ cache.set('b', 2);
136
+ cache.toJSON();
137
+
138
+ const person = signalObject({ name: 'Ada', age: 36 });
139
+ person.name = 'Grace';
140
+ person();
141
+
142
+ const notifier = signalNotifier();
143
+ effect(() => {
144
+ notifier();
145
+ });
146
+ notifier.notify();
147
+
148
+ const plain = { count: 1, label: 'ready' };
149
+ const signalObj = toSignalObj(plain);
150
+ const snapshot = fromSignalObj(signalObj);
151
+ const count = signalOrValue(signal(5));
152
+ console.log(snapshot, count);
153
+ ```
154
+
155
+ ### Utility helpers
156
+
157
+ `tryCatch` wraps sync code into `[result, error]`, and `writableSignal` creates a computed-like signal that can still be overridden with `.set()` and `.update()`.
158
+
159
+ ```ts
160
+ import { computed, signal } from '@angular/core';
161
+ import { tryCatch, writableSignal } from '@dvirus-js/angular-signals';
162
+
163
+ const [data, error] = tryCatch(() => JSON.parse('{"ok":true}'));
164
+
165
+ const source = signal(1);
166
+ const derived = writableSignal(() => source() * 2);
167
+
168
+ derived(); // 2
169
+ derived.set(10);
170
+ source.set(3);
171
+ derived(); // 6
172
+
173
+ console.log(data, error);
174
+ ```