ngx-easy-state-manager 0.0.4 → 1.0.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.
package/README.md CHANGED
@@ -11,15 +11,21 @@ npm install ngx-easy-state-manager
11
11
  ```
12
12
 
13
13
  ## Versions
14
- | Version | Option |
15
- |----------|-----------------------------|
16
- | ^0.0.4 | Angular 19. |
17
14
 
15
+ | Version | Option |
16
+ | ------- | --------------------------------------------- |
17
+ | ^0.0.4 | Angular 19. |
18
+ | ^1.0.0 | Added angular support from ^18.0.0 to ^21.0.0,|
19
+ | | and converted to use signals. |
18
20
  ## Usage
19
21
 
22
+ EasyStateManagerService (Signals Version)
23
+ A lightweight and resilient state management service for Angular using Signals. It supports dynamic keys, immutable updates, and persistent subscriptions.
24
+
20
25
  1. **Import the EasyStateManagerService**
26
+ This library now supports Angular Signals for better performance. However, the classic Observable-based version is still available for backward compatibility.
21
27
 
22
- First, import the EasyStateManagerService into your component or service where you want to manage the state.
28
+ Signals Version (Recommended for Angular 16+)
23
29
 
24
30
  app.module.ts
25
31
 
@@ -27,111 +33,173 @@ app.module.ts
27
33
  import { EasyStateManagerService } from "ngx-easy-state-manage";
28
34
 
29
35
  @NgModule({
30
- providers: [{ provide: EasyStateManagerService }],
36
+ providers: [EasyStateManagerService], // Simplified registration
31
37
  })
32
38
  export class AppModule {}
33
39
  ```
40
+ Observable Version (Classic)
41
+ If you prefer using RxJS Observables, use the original service:
34
42
 
35
- 2. **Inject the Service**
43
+ ```typescript
44
+ import { EasyStateManagerService } from "ngx-easy-state-manage";
45
+
46
+ @NgModule({
47
+ providers: [EasyStateManagerService],
48
+ })
49
+ export class AppModule {}
50
+ ```
36
51
 
37
- Inject EasyStateManagerService in the constructor of your component or service.
52
+ 2. **Inject the Service**
53
+ Inject the service into your component or another service:
38
54
 
39
55
  ```typescript
40
56
  constructor(private easyStateManager: EasyStateManagerService) {}
41
57
  ```
42
58
 
43
59
  3. **Assign State**
44
-
45
- You can assign a new state using the assignState method. Optionally, you can also associate the state with a specific component name.
60
+ Create or update state using assignState. It automatically handles Immutable updates for objects and arrays (creating new references to trigger change detection).
46
61
 
47
62
  ```typescript
48
- this.easyStateManager.assignState("exampleKey", "exampleValue", "ExampleComponentName");
49
- ```
63
+ // Assign a primitive
64
+ this.easyStateManager.assignState("title", "My App");
50
65
 
51
- 4. **Retrieve State**
66
+ // Assign/Update an object (performs a shallow merge)
67
+ this.easyStateManager.assignState("user", { id: 1, name: "John" });
68
+ ```
52
69
 
53
- To get the current state associated with a specific key, use the getState method.
70
+ 4. **Retrieve State (Snapshot)**
71
+ To get the current value of a state key once (without subscription), use getState:
54
72
 
55
73
  ```typescript
56
- const currentState = this.easyStateManager.getState("exampleKey");
57
- console.log(currentState); // Output: 'exampleValue'
74
+ const currentTitle = this.easyStateManager.getState<string>("title");
75
+ console.log(currentTitle); // Output: 'My App'
58
76
  ```
59
77
 
60
- 5. **Subscribe to State Changes**
61
-
62
- You can subscribe to state changes using the selectStateChange method, which returns an Observable.
78
+ 5. **Subscribe to State Changes (Signals)**
79
+ The selectStateChange method returns a Read-only Signal. It is "resilient": if you delete the key and recreate it later, the signal will automatically reconnect and provide the new values.
63
80
 
64
81
  ```typescript
65
- this.easyStateManager.selectStateChange("exampleKey").subscribe((newValue) => {
66
- console.log("State has changed:", newValue);
67
- });
82
+ // In your component
83
+ public title = this.easyStateManager.selectStateChange<string>("title");
84
+
85
+ constructor() {
86
+ effect(() => {
87
+ console.log("Title updated:", this.title());
88
+ });
89
+ }
90
+ ```
91
+
92
+ In your HTML template:
93
+
94
+ ```html
95
+ <h1>{{ title() || 'Loading...' }}</h1>
68
96
  ```
69
97
 
70
98
  6. **Delete State**
71
99
 
72
- To delete a state associated with a specific key, use the deleteState method.
100
+ To remove a state key. All active subscribers to this key will immediately receive null.
73
101
 
74
102
  ```typescript
75
- this.easyStateManager.deleteState("exampleKey");
103
+ this.easyStateManager.deleteState("title");
76
104
  ```
77
105
 
78
- ## API
106
+ 7. **Clear All**
107
+ To reset the entire store and notify all active subscribers.
79
108
 
80
- assignState(key: string, value: any, componentName?: string): void
81
- Assigns a value to the state with an optional component name.
82
-
83
- getState(key?: string): any
84
- Retrieves the current value of the state associated with the specified key.
109
+ ```typescript
110
+ this.easyStateManager.clearAll();
111
+ ```
85
112
 
86
- selectStateChange(key: string): Observable<any>
87
- Returns an Observable that emits whenever the state associated with the specified key changes.
113
+ ## API
88
114
 
115
+ assignState<T>(key: string, value: T): void
116
+ Assigns a value to the state.
117
+ Immutable updates: If the value is an object or an array, the service creates a new reference (shallow copy) to ensure Angular's change detection is triggered.
118
+ Dynamic: If the key doesn't exist, it will be created.
119
+ selectStateChange<T>(key: string): Signal<T | null>
120
+ Returns a Read-only Signal for the specified key.
121
+ Resilient: If the state is deleted and then recreated with the same key, this signal will automatically "reconnect" to the new value.
122
+ Reactive: Perfect for use in templates or effect(). Returns null if the key does not exist or was deleted.
123
+ getState<T>(key: string): T | null
124
+ Retrieves a snapshot of the current value associated with the specified key.
125
+ Does not create a subscription.
126
+ Returns null if the key is not found.
89
127
  deleteState(key: string): void
90
- Deletes the state associated with the specified key.
128
+ Removes the state associated with the specified key.
129
+ All active signals created via selectStateChange for this key will be updated to null.
130
+ clearAll(): void
131
+ Completely resets the store.
132
+ All keys are removed, and all active subscribers are notified with null.
133
+
134
+ | Feature | EasyStateManagerServiceSignal | EasyStateManagerService |
135
+ |----------------------------------------------------------------------------|
136
+ |Reactive Type | Signal<T> | Observable<T> |
137
+ |Update Logic |Immutable (Shallow Copy) | Direct / Manual |
138
+ |Resilience |Reconnects after deleteState | Subscription ends on delete*|
139
+ |Template Usage| {{ state() }} | `${{state}}` |
140
+
141
+ Note: The new EasyStateManagerServiceSignal is specifically designed to work with Angular's new reactivity model.
142
+ It provides "resilient" connections, meaning if a key is deleted and recreated, your UI components will automatically pick up the new value without needing to re-subscribe.
91
143
 
92
144
  ## Example
93
145
 
94
- stateTypes
146
+ stateTypes.ts
95
147
 
96
148
  ```typescript
97
149
  export const SELECTED_EMOJI = "selectedEmoji";
150
+
151
+ export interface EmojiState {
152
+ emoji: string;
153
+ }
98
154
  ```
99
155
 
100
156
  app.compoinent
101
157
 
102
158
  ```typescript
103
- import { Component, OnInit } from "@angular/core";
159
+ import { Component, effect, Signal } from "@angular/core";
104
160
  import { EmojiPicker } from "ngx-easy-emoji-picker";
105
- import { EasyStateManagerService } from "ngx-easy-state-manager";
106
-
107
- import { SELECTED_EMOJI } from "./stateTypes";
161
+ import { EasyStateManagerService } from "ngx-easy-state-manage";
162
+ import { SELECTED_EMOJI, EmojiState } from "./stateTypes";
108
163
 
109
164
  @Component({
110
165
  selector: "app-root",
111
166
  standalone: true,
112
167
  imports: [EmojiPicker],
113
- templateUrl: "./app.component.html",
114
- styleUrl: "./app.component.css",
115
- providers: [EasyStateManagerService],
168
+ template: `
169
+ <!-- Direct usage of signal in template -->
170
+ <div class="display">Selected: {{ emojiState()?.emoji || "None" }}</div>
171
+
172
+ <ngx-easy-emoji-picker (onEmojiSelected)="onEmojiSelected($event)">
173
+ </ngx-easy-emoji-picker>
174
+ `,
175
+ // Service is providedIn: 'root', but can be added to providers if needed locally
116
176
  })
117
- export class AppComponent implements OnInit {
118
- title = "my-project";
119
-
120
- selectedEmoji = "";
121
-
122
- constructor(private _stateManager: EasyStateManagerService) {}
123
-
124
- ngOnInit() {
125
- this._stateManager.selectStateChange(SELECTED_EMOJI).subscribe((state) => {
126
- if (state) this.selectedEmoji = state.emoji;
127
-
128
- console.log("Selected emoji:", this.selectedEmoji);
177
+ export class AppComponent {
178
+ // 1. Get a Read-only Signal for the state
179
+ public emojiState: Signal<EmojiState | null>;
180
+
181
+ constructor(private _stateManager: EasyStateManagerService) {
182
+ this.emojiState =
183
+ this._stateManager.selectStateChange<EmojiState>(SELECTED_EMOJI);
184
+
185
+ // 2. React to changes in logic (optional)
186
+ effect(() => {
187
+ const current = this.emojiState();
188
+ if (current) {
189
+ console.log("Emoji updated in state:", current.emoji);
190
+ }
129
191
  });
130
192
  }
131
193
 
132
194
  onEmojiSelected(emoji: string) {
195
+ // 3. Assign new state (it will trigger the signal above)
133
196
  this._stateManager.assignState(SELECTED_EMOJI, { emoji: emoji });
134
197
  }
198
+
199
+ removeEmoji() {
200
+ // 4. Delete state - emojiState() will automatically become 'null'
201
+ this._stateManager.deleteState(SELECTED_EMOJI);
202
+ }
135
203
  }
136
204
  ```
137
205
 
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable } from '@angular/core';
2
+ import { Injectable, signal, computed } from '@angular/core';
3
3
  import { BehaviorSubject } from 'rxjs';
4
4
 
5
5
  class EasyStateManagerService {
@@ -37,16 +37,103 @@ class EasyStateManagerService {
37
37
  delete this._store[key];
38
38
  }
39
39
  }
40
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EasyStateManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
41
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EasyStateManagerService, providedIn: "root" }); }
40
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
41
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerService, providedIn: "root" }); }
42
42
  }
43
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImport: i0, type: EasyStateManagerService, decorators: [{
43
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerService, decorators: [{
44
44
  type: Injectable,
45
45
  args: [{
46
46
  providedIn: "root",
47
47
  }]
48
48
  }] });
49
49
 
50
+ class EasyStateManagerServiceSignal {
51
+ constructor() {
52
+ /**
53
+ * Main store holding signals for each state key.
54
+ * Wrapped in a signal to track adding/removing keys dynamically.
55
+ */
56
+ this._store = signal({}, ...(ngDevMode ? [{ debugName: "_store" }] : []));
57
+ }
58
+ /**
59
+ * Sets or updates state for a specific key.
60
+ * Implements immutable update logic for objects and arrays to ensure change detection.
61
+ * @param key Unique identifier for the state slice.
62
+ * @param value New value to assign or merge.
63
+ */
64
+ assignState(key, value) {
65
+ const currentStore = this._store();
66
+ const existingSignal = currentStore[key];
67
+ if (existingSignal) {
68
+ // If signal exists, update its value using immutable patterns
69
+ existingSignal.update(oldValue => {
70
+ if (Array.isArray(value))
71
+ return [...value];
72
+ if (value !== null && typeof value === 'object') {
73
+ return { ...oldValue, ...value };
74
+ }
75
+ return value;
76
+ });
77
+ }
78
+ else {
79
+ // Create a new signal and trigger store structure update
80
+ const newSignal = signal(value, ...(ngDevMode ? [{ debugName: "newSignal" }] : []));
81
+ this._store.update(store => ({
82
+ ...store,
83
+ [key]: newSignal
84
+ }));
85
+ }
86
+ }
87
+ /**
88
+ * Returns a "resilient" Read-only signal for a specific key.
89
+ * It tracks the store structure: if a key is deleted and recreated,
90
+ * the subscriber automatically reconnects to the new signal.
91
+ * @param key Key to watch.
92
+ */
93
+ selectStateChange(key) {
94
+ return computed(() => {
95
+ // Subscribes to the store's dictionary changes
96
+ const s = this._store()[key];
97
+ // Returns signal value if key exists, otherwise null
98
+ return s ? s() : null;
99
+ });
100
+ }
101
+ /**
102
+ * Returns a current snapshot of the state without subscription.
103
+ */
104
+ getState(key) {
105
+ const s = this._store()[key];
106
+ return s ? s() : null;
107
+ }
108
+ /**
109
+ * Removes a key from the store.
110
+ * All subscribers to this key will immediately receive 'null'.
111
+ */
112
+ deleteState(key) {
113
+ if (this._store()[key]) {
114
+ this._store.update(store => {
115
+ const newStore = { ...store };
116
+ delete newStore[key];
117
+ return newStore;
118
+ });
119
+ }
120
+ }
121
+ /**
122
+ * Resets the entire store to an empty state.
123
+ */
124
+ clearAll() {
125
+ this._store.set({});
126
+ }
127
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerServiceSignal, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
128
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerServiceSignal, providedIn: 'root' }); }
129
+ }
130
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.16", ngImport: i0, type: EasyStateManagerServiceSignal, decorators: [{
131
+ type: Injectable,
132
+ args: [{
133
+ providedIn: 'root'
134
+ }]
135
+ }] });
136
+
50
137
  /*
51
138
  * Public API Surface of ngx-easy-state-manager
52
139
  */
@@ -55,5 +142,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.18", ngImpo
55
142
  * Generated bundle index. Do not edit.
56
143
  */
57
144
 
58
- export { EasyStateManagerService };
145
+ export { EasyStateManagerService, EasyStateManagerServiceSignal };
59
146
  //# sourceMappingURL=ngx-easy-state-manager.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ngx-easy-state-manager.mjs","sources":["../../../projects/ngx-easy-state-manager/src/lib/ngx-easy-state-manager.service.ts","../../../projects/ngx-easy-state-manager/src/public-api.ts","../../../projects/ngx-easy-state-manager/src/ngx-easy-state-manager.ts"],"sourcesContent":["import { Injectable } from \"@angular/core\";\r\nimport { BehaviorSubject, Observable } from \"rxjs\";\r\n\r\n@Injectable({\r\n providedIn: \"root\",\r\n})\r\nexport class EasyStateManagerService {\r\n private _store: Store = {};\r\n\r\n public assignState<T>(key: string, value: T): void {\r\n if ((key as string) in this._store) {\r\n const storeValue = this._store[key].value;\r\n // check type mismatch\r\n if (storeValue && typeof storeValue !== typeof value) {\r\n throw new Error(\r\n `Type mismatch: ${typeof this._store[key].value} !== ${typeof value}`\r\n );\r\n }\r\n\r\n this._store[key].next(value);\r\n } else {\r\n this._store[key] = new BehaviorSubject<T>(value);\r\n }\r\n }\r\n\r\n public getState<T>(key?: string): T | undefined {\r\n if (key && (key as string) in this._store) {\r\n return this._store[key].value;\r\n }\r\n return undefined;\r\n }\r\n\r\n public selectStateChange<T>(key: string): BehaviorSubject<any> {\r\n if (key in this._store) {\r\n return this._store[key] as BehaviorSubject<T>;\r\n }\r\n\r\n this._store[key] = new BehaviorSubject<T>(null as T);\r\n\r\n return this._store[key];\r\n }\r\n\r\n public deleteState(key: string): void {\r\n if (key in this._store) {\r\n delete this._store[key];\r\n }\r\n }\r\n}\r\n\r\ntype Store = {\r\n [key: string]: BehaviorSubject<any>;\r\n};\r\n","/*\r\n * Public API Surface of ngx-easy-state-manager\r\n */\r\n\r\nexport * from './lib/ngx-easy-state-manager.service';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAMa,uBAAuB,CAAA;AAHpC,IAAA,WAAA,GAAA;QAIU,IAAM,CAAA,MAAA,GAAU,EAAE;AAwC3B;IAtCQ,WAAW,CAAI,GAAW,EAAE,KAAQ,EAAA;AACzC,QAAA,IAAK,GAAc,IAAI,IAAI,CAAC,MAAM,EAAE;YAClC,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;;YAEzC,IAAI,UAAU,IAAI,OAAO,UAAU,KAAK,OAAO,KAAK,EAAE;AACpD,gBAAA,MAAM,IAAI,KAAK,CACb,kBAAkB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAA,KAAA,EAAQ,OAAO,KAAK,CAAA,CAAE,CACtE;;YAGH,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;;aACvB;YACL,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,eAAe,CAAI,KAAK,CAAC;;;AAI7C,IAAA,QAAQ,CAAI,GAAY,EAAA;QAC7B,IAAI,GAAG,IAAK,GAAc,IAAI,IAAI,CAAC,MAAM,EAAE;YACzC,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;;AAE/B,QAAA,OAAO,SAAS;;AAGX,IAAA,iBAAiB,CAAI,GAAW,EAAA;AACrC,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;AACtB,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAuB;;QAG/C,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,eAAe,CAAI,IAAS,CAAC;AAEpD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;;AAGlB,IAAA,WAAW,CAAC,GAAW,EAAA;AAC5B,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;AACtB,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;;;+GAtChB,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,cAFtB,MAAM,EAAA,CAAA,CAAA;;4FAEP,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAHnC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;ACLD;;AAEG;;ACFH;;AAEG;;;;"}
1
+ {"version":3,"file":"ngx-easy-state-manager.mjs","sources":["../../../projects/ngx-easy-state-manager/src/lib/ngx-easy-state-manager.service.ts","../../../projects/ngx-easy-state-manager/src/lib/ngx-easy-state-manager-signal.service.ts","../../../projects/ngx-easy-state-manager/src/public-api.ts","../../../projects/ngx-easy-state-manager/src/ngx-easy-state-manager.ts"],"sourcesContent":["import { Injectable } from \"@angular/core\";\r\nimport { BehaviorSubject } from \"rxjs\";\r\n\r\n@Injectable({\r\n providedIn: \"root\",\r\n})\r\nexport class EasyStateManagerService {\r\n private _store: Store = {};\r\n\r\n public assignState<T>(key: string, value: T): void {\r\n if (key in this._store) {\r\n const storeValue = this._store[key].value;\r\n // check type mismatch\r\n if (storeValue && typeof storeValue !== typeof value) {\r\n throw new Error(\r\n `Type mismatch: ${typeof this._store[key].value} !== ${typeof value}`\r\n );\r\n }\r\n\r\n this._store[key].next(value);\r\n } else {\r\n this._store[key] = new BehaviorSubject<T>(value);\r\n }\r\n }\r\n\r\n public getState<T>(key?: string): T | undefined {\r\n if (key && key in this._store) {\r\n return this._store[key].value;\r\n }\r\n return undefined;\r\n }\r\n\r\n public selectStateChange<T>(key: string): BehaviorSubject<any> {\r\n if (key in this._store) {\r\n return this._store[key] as BehaviorSubject<T>;\r\n }\r\n\r\n this._store[key] = new BehaviorSubject<T>(null as T);\r\n\r\n return this._store[key];\r\n }\r\n\r\n public deleteState(key: string): void {\r\n if (key in this._store) {\r\n delete this._store[key];\r\n }\r\n }\r\n}\r\n\r\ntype Store = {\r\n [key: string]: BehaviorSubject<any>;\r\n};\r\n","import { Injectable, signal, computed, Signal, WritableSignal } from '@angular/core';\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class EasyStateManagerServiceSignal {\r\n /**\r\n * Main store holding signals for each state key.\r\n * Wrapped in a signal to track adding/removing keys dynamically.\r\n */\r\n private readonly _store = signal<Record<string, WritableSignal<any>>>({});\r\n\r\n /**\r\n * Sets or updates state for a specific key.\r\n * Implements immutable update logic for objects and arrays to ensure change detection.\r\n * @param key Unique identifier for the state slice.\r\n * @param value New value to assign or merge.\r\n */\r\n public assignState<T>(key: string, value: T): void {\r\n const currentStore = this._store();\r\n const existingSignal = currentStore[key];\r\n\r\n if (existingSignal) {\r\n // If signal exists, update its value using immutable patterns\r\n existingSignal.update(oldValue => {\r\n if (Array.isArray(value)) return [...value];\r\n if (value !== null && typeof value === 'object') {\r\n return { ...oldValue, ...value };\r\n }\r\n return value;\r\n });\r\n } else {\r\n // Create a new signal and trigger store structure update\r\n const newSignal = signal(value);\r\n this._store.update(store => ({\r\n ...store,\r\n [key]: newSignal\r\n }));\r\n }\r\n }\r\n\r\n /**\r\n * Returns a \"resilient\" Read-only signal for a specific key.\r\n * It tracks the store structure: if a key is deleted and recreated, \r\n * the subscriber automatically reconnects to the new signal.\r\n * @param key Key to watch.\r\n */\r\n public selectStateChange<T>(key: string): Signal<T | null> {\r\n return computed(() => {\r\n // Subscribes to the store's dictionary changes\r\n const s = this._store()[key];\r\n // Returns signal value if key exists, otherwise null\r\n return s ? s() : null;\r\n });\r\n }\r\n\r\n /**\r\n * Returns a current snapshot of the state without subscription.\r\n */\r\n public getState<T>(key: string): T | null {\r\n const s = this._store()[key];\r\n return s ? s() : null;\r\n }\r\n\r\n /**\r\n * Removes a key from the store.\r\n * All subscribers to this key will immediately receive 'null'.\r\n */\r\n public deleteState(key: string): void {\r\n if (this._store()[key]) {\r\n this._store.update(store => {\r\n const newStore = { ...store };\r\n delete newStore[key];\r\n return newStore;\r\n });\r\n }\r\n }\r\n\r\n /**\r\n * Resets the entire store to an empty state.\r\n */\r\n public clearAll(): void {\r\n this._store.set({});\r\n }\r\n}\r\n","/*\r\n * Public API Surface of ngx-easy-state-manager\r\n */\r\n\r\nexport * from './lib/ngx-easy-state-manager.service';\r\nexport * from './lib/ngx-easy-state-manager-signal.service';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":";;;;MAMa,uBAAuB,CAAA;AAHpC,IAAA,WAAA,GAAA;QAIU,IAAA,CAAA,MAAM,GAAU,EAAE;AAwC3B,IAAA;IAtCQ,WAAW,CAAI,GAAW,EAAE,KAAQ,EAAA;AACzC,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;YACtB,MAAM,UAAU,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;;YAEzC,IAAI,UAAU,IAAI,OAAO,UAAU,KAAK,OAAO,KAAK,EAAE;AACpD,gBAAA,MAAM,IAAI,KAAK,CACb,kBAAkB,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAA,KAAA,EAAQ,OAAO,KAAK,CAAA,CAAE,CACtE;YACH;YAEA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC;QAC9B;aAAO;YACL,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,eAAe,CAAI,KAAK,CAAC;QAClD;IACF;AAEO,IAAA,QAAQ,CAAI,GAAY,EAAA;QAC7B,IAAI,GAAG,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;YAC7B,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK;QAC/B;AACA,QAAA,OAAO,SAAS;IAClB;AAEO,IAAA,iBAAiB,CAAI,GAAW,EAAA;AACrC,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;AACtB,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAuB;QAC/C;QAEA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,eAAe,CAAI,IAAS,CAAC;AAEpD,QAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;IACzB;AAEO,IAAA,WAAW,CAAC,GAAW,EAAA;AAC5B,QAAA,IAAI,GAAG,IAAI,IAAI,CAAC,MAAM,EAAE;AACtB,YAAA,OAAO,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC;QACzB;IACF;+GAxCW,uBAAuB,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAAvB,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,uBAAuB,cAFtB,MAAM,EAAA,CAAA,CAAA;;4FAEP,uBAAuB,EAAA,UAAA,EAAA,CAAA;kBAHnC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE,MAAM;AACnB,iBAAA;;;MCAY,6BAA6B,CAAA;AAH1C,IAAA,WAAA,GAAA;AAIE;;;AAGG;AACc,QAAA,IAAA,CAAA,MAAM,GAAG,MAAM,CAAsC,EAAE,kDAAC;AA0E1E,IAAA;AAxEC;;;;;AAKG;IACI,WAAW,CAAI,GAAW,EAAE,KAAQ,EAAA;AACzC,QAAA,MAAM,YAAY,GAAG,IAAI,CAAC,MAAM,EAAE;AAClC,QAAA,MAAM,cAAc,GAAG,YAAY,CAAC,GAAG,CAAC;QAExC,IAAI,cAAc,EAAE;;AAElB,YAAA,cAAc,CAAC,MAAM,CAAC,QAAQ,IAAG;AAC/B,gBAAA,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;AAAE,oBAAA,OAAO,CAAC,GAAG,KAAK,CAAC;gBAC3C,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE;AAC/C,oBAAA,OAAO,EAAE,GAAG,QAAQ,EAAE,GAAG,KAAK,EAAE;gBAClC;AACA,gBAAA,OAAO,KAAK;AACd,YAAA,CAAC,CAAC;QACJ;aAAO;;AAEL,YAAA,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,qDAAC;YAC/B,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,KAAK;AAC3B,gBAAA,GAAG,KAAK;gBACR,CAAC,GAAG,GAAG;AACR,aAAA,CAAC,CAAC;QACL;IACF;AAEA;;;;;AAKG;AACI,IAAA,iBAAiB,CAAI,GAAW,EAAA;QACrC,OAAO,QAAQ,CAAC,MAAK;;YAEnB,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC;;YAE5B,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI;AACvB,QAAA,CAAC,CAAC;IACJ;AAEA;;AAEG;AACI,IAAA,QAAQ,CAAI,GAAW,EAAA;QAC5B,MAAM,CAAC,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC;QAC5B,OAAO,CAAC,GAAG,CAAC,EAAE,GAAG,IAAI;IACvB;AAEA;;;AAGG;AACI,IAAA,WAAW,CAAC,GAAW,EAAA;QAC5B,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,EAAE;AACtB,YAAA,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,IAAG;AACzB,gBAAA,MAAM,QAAQ,GAAG,EAAE,GAAG,KAAK,EAAE;AAC7B,gBAAA,OAAO,QAAQ,CAAC,GAAG,CAAC;AACpB,gBAAA,OAAO,QAAQ;AACjB,YAAA,CAAC,CAAC;QACJ;IACF;AAEA;;AAEG;IACI,QAAQ,GAAA;AACb,QAAA,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC;IACrB;+GA9EW,6BAA6B,EAAA,IAAA,EAAA,EAAA,EAAA,MAAA,EAAA,EAAA,CAAA,eAAA,CAAA,UAAA,EAAA,CAAA,CAAA;AAA7B,IAAA,SAAA,IAAA,CAAA,KAAA,GAAA,EAAA,CAAA,qBAAA,CAAA,EAAA,UAAA,EAAA,QAAA,EAAA,OAAA,EAAA,SAAA,EAAA,QAAA,EAAA,EAAA,EAAA,IAAA,EAAA,6BAA6B,cAF5B,MAAM,EAAA,CAAA,CAAA;;4FAEP,6BAA6B,EAAA,UAAA,EAAA,CAAA;kBAHzC,UAAU;AAAC,YAAA,IAAA,EAAA,CAAA;AACV,oBAAA,UAAU,EAAE;AACb,iBAAA;;;ACJD;;AAEG;;ACFH;;AAEG;;;;"}
package/index.d.ts CHANGED
@@ -1,5 +1,52 @@
1
- /**
2
- * Generated bundle index. Do not edit.
3
- */
4
- /// <amd-module name="ngx-easy-state-manager" />
5
- export * from './public-api';
1
+ import { BehaviorSubject } from 'rxjs';
2
+ import * as i0 from '@angular/core';
3
+ import { Signal } from '@angular/core';
4
+
5
+ declare class EasyStateManagerService {
6
+ private _store;
7
+ assignState<T>(key: string, value: T): void;
8
+ getState<T>(key?: string): T | undefined;
9
+ selectStateChange<T>(key: string): BehaviorSubject<any>;
10
+ deleteState(key: string): void;
11
+ static ɵfac: i0.ɵɵFactoryDeclaration<EasyStateManagerService, never>;
12
+ static ɵprov: i0.ɵɵInjectableDeclaration<EasyStateManagerService>;
13
+ }
14
+
15
+ declare class EasyStateManagerServiceSignal {
16
+ /**
17
+ * Main store holding signals for each state key.
18
+ * Wrapped in a signal to track adding/removing keys dynamically.
19
+ */
20
+ private readonly _store;
21
+ /**
22
+ * Sets or updates state for a specific key.
23
+ * Implements immutable update logic for objects and arrays to ensure change detection.
24
+ * @param key Unique identifier for the state slice.
25
+ * @param value New value to assign or merge.
26
+ */
27
+ assignState<T>(key: string, value: T): void;
28
+ /**
29
+ * Returns a "resilient" Read-only signal for a specific key.
30
+ * It tracks the store structure: if a key is deleted and recreated,
31
+ * the subscriber automatically reconnects to the new signal.
32
+ * @param key Key to watch.
33
+ */
34
+ selectStateChange<T>(key: string): Signal<T | null>;
35
+ /**
36
+ * Returns a current snapshot of the state without subscription.
37
+ */
38
+ getState<T>(key: string): T | null;
39
+ /**
40
+ * Removes a key from the store.
41
+ * All subscribers to this key will immediately receive 'null'.
42
+ */
43
+ deleteState(key: string): void;
44
+ /**
45
+ * Resets the entire store to an empty state.
46
+ */
47
+ clearAll(): void;
48
+ static ɵfac: i0.ɵɵFactoryDeclaration<EasyStateManagerServiceSignal, never>;
49
+ static ɵprov: i0.ɵɵInjectableDeclaration<EasyStateManagerServiceSignal>;
50
+ }
51
+
52
+ export { EasyStateManagerService, EasyStateManagerServiceSignal };
package/package.json CHANGED
@@ -1,11 +1,13 @@
1
1
  {
2
2
  "name": "ngx-easy-state-manager",
3
- "version": "0.0.4",
3
+ "version": "1.0.0",
4
4
  "author": "Alex Voronin <alex.varonin@gmail.com>",
5
5
  "license": "MIT",
6
6
  "peerDependencies": {
7
- "@angular/common": "^19.0.0",
8
- "@angular/core": "^19.0.0"
7
+ "@angular/common": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
8
+ "@angular/core": "^18.0.0 || ^19.0.0 || ^20.0.0 || ^21.0.0",
9
+ "rxjs": "^7.8.0",
10
+ "zone.js": "~0.14.0 || ~0.15.0"
9
11
  },
10
12
  "description": "ngx-easy-state-manager is a lightweight, intuitive library for managing state in Angular applications. It simplifies state management by providing a straightforward API for creating, updating, and accessing state, without the complexity of traditional approaches.",
11
13
  "dependencies": {
@@ -1,11 +0,0 @@
1
- import { BehaviorSubject } from "rxjs";
2
- import * as i0 from "@angular/core";
3
- export declare class EasyStateManagerService {
4
- private _store;
5
- assignState<T>(key: string, value: T): void;
6
- getState<T>(key?: string): T | undefined;
7
- selectStateChange<T>(key: string): BehaviorSubject<any>;
8
- deleteState(key: string): void;
9
- static ɵfac: i0.ɵɵFactoryDeclaration<EasyStateManagerService, never>;
10
- static ɵprov: i0.ɵɵInjectableDeclaration<EasyStateManagerService>;
11
- }
package/public-api.d.ts DELETED
@@ -1 +0,0 @@
1
- export * from './lib/ngx-easy-state-manager.service';