@angular-architects/ngrx-toolkit 19.1.0 → 19.2.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/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +8 -8
- package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs.map +1 -1
- package/fesm2022/angular-architects-ngrx-toolkit.mjs +814 -479
- package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -1
- package/index.d.ts +16 -9
- package/lib/devtools/internal/glitch-tracker.service.d.ts +1 -1
- package/lib/devtools/internal/models.d.ts +2 -3
- package/lib/devtools/provide-devtools-config.d.ts +20 -0
- package/lib/devtools/update-state.d.ts +1 -2
- package/lib/devtools/with-devtools.d.ts +2 -7
- package/lib/storage-sync/features/with-indexed-db.d.ts +2 -0
- package/lib/storage-sync/features/with-local-storage.d.ts +3 -0
- package/lib/storage-sync/internal/indexeddb.service.d.ts +29 -0
- package/lib/storage-sync/internal/local-storage.service.d.ts +8 -0
- package/lib/storage-sync/internal/models.d.ts +34 -0
- package/lib/storage-sync/internal/session-storage.service.d.ts +8 -0
- package/lib/storage-sync/with-storage-sync.d.ts +45 -0
- package/lib/with-call-state.d.ts +19 -2
- package/lib/with-data-service.d.ts +5 -5
- package/lib/with-feature-factory.d.ts +2 -0
- package/lib/with-pagination.d.ts +1 -1
- package/lib/with-redux.d.ts +3 -1
- package/lib/with-undo-redo.d.ts +1 -1
- package/package.json +3 -3
- package/redux-connector/src/lib/rxjs-interop/redux-method.d.ts +2 -2
- package/redux-connector/src/lib/signal-redux-store.d.ts +4 -16
- package/lib/with-storage-sync.d.ts +0 -52
|
@@ -1,16 +1,47 @@
|
|
|
1
|
-
import { getState, signalStoreFeature, withMethods, withHooks, watchState, patchState as patchState$1, withState, withComputed, withProps } from '@ngrx/signals';
|
|
2
1
|
import * as i0 from '@angular/core';
|
|
3
|
-
import {
|
|
2
|
+
import { Injectable, InjectionToken, signal, effect, inject, PLATFORM_ID, computed, isSignal, untracked, isDevMode as isDevMode$1 } from '@angular/core';
|
|
3
|
+
import { watchState, getState, signalStoreFeature, withMethods, withHooks, patchState as patchState$1, withState, withComputed, withProps } from '@ngrx/signals';
|
|
4
4
|
import { isPlatformBrowser, isPlatformServer } from '@angular/common';
|
|
5
5
|
import { Subject } from 'rxjs';
|
|
6
|
-
import {
|
|
6
|
+
import { removeEntity, setAllEntities, updateEntity, addEntity } from '@ngrx/signals/entities';
|
|
7
|
+
|
|
8
|
+
const DEVTOOLS_FEATURE = Symbol('DEVTOOLS_FEATURE');
|
|
9
|
+
function createDevtoolsFeature(options) {
|
|
10
|
+
return {
|
|
11
|
+
[DEVTOOLS_FEATURE]: true,
|
|
12
|
+
...options,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
7
15
|
|
|
8
16
|
/**
|
|
9
|
-
*
|
|
17
|
+
* If multiple instances of the same SignalStore class
|
|
18
|
+
* exist, their devtool names are indexed.
|
|
19
|
+
*
|
|
20
|
+
* For example:
|
|
21
|
+
*
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const Store = signalStore(
|
|
24
|
+
* withDevtools('flights')
|
|
25
|
+
* )
|
|
26
|
+
*
|
|
27
|
+
* const store1 = new Store(); // will show up as 'flights'
|
|
28
|
+
* const store2 = new Store(); // will show up as 'flights-1'
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* With adding `withDisabledNameIndices` to the store:
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const Store = signalStore(
|
|
34
|
+
* withDevtools('flights', withDisabledNameIndices())
|
|
35
|
+
* )
|
|
36
|
+
*
|
|
37
|
+
* const store1 = new Store(); // will show up as 'flights'
|
|
38
|
+
* const store2 = new Store(); //💥 throws an error
|
|
39
|
+
* ```
|
|
40
|
+
*
|
|
10
41
|
*/
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
42
|
+
function withDisabledNameIndices() {
|
|
43
|
+
return createDevtoolsFeature({ indexNames: false });
|
|
44
|
+
}
|
|
14
45
|
|
|
15
46
|
function throwIfNull(obj) {
|
|
16
47
|
if (obj === null || obj === undefined) {
|
|
@@ -19,6 +50,182 @@ function throwIfNull(obj) {
|
|
|
19
50
|
return obj;
|
|
20
51
|
}
|
|
21
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Internal Service used by {@link withGlitchTracking}. It does not rely
|
|
55
|
+
* on `effect` as {@link DefaultTracker} does but uses the NgRx function
|
|
56
|
+
* `watchState` to track all state changes.
|
|
57
|
+
*/
|
|
58
|
+
class GlitchTrackerService {
|
|
59
|
+
#stores = {};
|
|
60
|
+
#callback;
|
|
61
|
+
get stores() {
|
|
62
|
+
return Object.entries(this.#stores).reduce((acc, [id, { store }]) => {
|
|
63
|
+
acc[id] = store;
|
|
64
|
+
return acc;
|
|
65
|
+
}, {});
|
|
66
|
+
}
|
|
67
|
+
onChange(callback) {
|
|
68
|
+
this.#callback = callback;
|
|
69
|
+
}
|
|
70
|
+
removeStore(id) {
|
|
71
|
+
this.#stores = Object.entries(this.#stores).reduce((newStore, [storeId, value]) => {
|
|
72
|
+
if (storeId !== id) {
|
|
73
|
+
newStore[storeId] = value;
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
value.destroyWatcher();
|
|
77
|
+
}
|
|
78
|
+
return newStore;
|
|
79
|
+
}, {});
|
|
80
|
+
throwIfNull(this.#callback)({});
|
|
81
|
+
}
|
|
82
|
+
track(id, store) {
|
|
83
|
+
const watcher = watchState(store, (state) => {
|
|
84
|
+
throwIfNull(this.#callback)({ [id]: state });
|
|
85
|
+
});
|
|
86
|
+
this.#stores[id] = { destroyWatcher: watcher.destroy, store };
|
|
87
|
+
}
|
|
88
|
+
notifyRenamedStore(id) {
|
|
89
|
+
if (Object.keys(this.#stores).includes(id) && this.#callback) {
|
|
90
|
+
this.#callback({ [id]: getState(this.#stores[id].store) });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GlitchTrackerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
94
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GlitchTrackerService, providedIn: 'root' }); }
|
|
95
|
+
}
|
|
96
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: GlitchTrackerService, decorators: [{
|
|
97
|
+
type: Injectable,
|
|
98
|
+
args: [{ providedIn: 'root' }]
|
|
99
|
+
}] });
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* It tracks all state changes of the State, including intermediary updates
|
|
103
|
+
* that are typically suppressed by Angular's glitch-free mechanism.
|
|
104
|
+
*
|
|
105
|
+
* This feature is especially useful for debugging.
|
|
106
|
+
*
|
|
107
|
+
* Example:
|
|
108
|
+
*
|
|
109
|
+
* ```typescript
|
|
110
|
+
* const Store = signalStore(
|
|
111
|
+
* { providedIn: 'root' },
|
|
112
|
+
* withState({ count: 0 }),
|
|
113
|
+
* withDevtools('counter', withGlitchTracking()),
|
|
114
|
+
* withMethods((store) => ({
|
|
115
|
+
* increase: () =>
|
|
116
|
+
* patchState(store, (value) => ({ count: value.count + 1 })),
|
|
117
|
+
* }))
|
|
118
|
+
* );
|
|
119
|
+
*
|
|
120
|
+
* // would show up in the DevTools with value 0
|
|
121
|
+
* const store = inject(Store);
|
|
122
|
+
*
|
|
123
|
+
* store.increase(); // would show up in the DevTools with value 1
|
|
124
|
+
* store.increase(); // would show up in the DevTools with value 2
|
|
125
|
+
* store.increase(); // would show up in the DevTools with value 3
|
|
126
|
+
* ```
|
|
127
|
+
*
|
|
128
|
+
* Without `withGlitchTracking`, the DevTools would only show the final value of 3.
|
|
129
|
+
*/
|
|
130
|
+
function withGlitchTracking() {
|
|
131
|
+
return createDevtoolsFeature({ tracker: GlitchTrackerService });
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Allows you to define a function to map the state.
|
|
136
|
+
*
|
|
137
|
+
* It is needed for huge states, that slows down the Devtools and where
|
|
138
|
+
* you don't need to see the whole state or other reasons.
|
|
139
|
+
*
|
|
140
|
+
* Example:
|
|
141
|
+
*
|
|
142
|
+
* ```typescript
|
|
143
|
+
* const initialState = {
|
|
144
|
+
* id: 1,
|
|
145
|
+
* email: 'john.list@host.com',
|
|
146
|
+
* name: 'John List',
|
|
147
|
+
* enteredPassword: ''
|
|
148
|
+
* }
|
|
149
|
+
*
|
|
150
|
+
* const Store = signalStore(
|
|
151
|
+
* withState(initialState),
|
|
152
|
+
* withDevtools(
|
|
153
|
+
* 'user',
|
|
154
|
+
* withMapper(state => ({...state, enteredPassword: '***' }))
|
|
155
|
+
* )
|
|
156
|
+
* )
|
|
157
|
+
* ```
|
|
158
|
+
*
|
|
159
|
+
* @param map function which maps the state
|
|
160
|
+
*/
|
|
161
|
+
function withMapper(map) {
|
|
162
|
+
return createDevtoolsFeature({ map: map });
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Provides the configuration options for connecting to the Redux DevTools Extension.
|
|
167
|
+
*/
|
|
168
|
+
function provideDevtoolsConfig(config) {
|
|
169
|
+
return {
|
|
170
|
+
provide: REDUX_DEVTOOLS_CONFIG,
|
|
171
|
+
useValue: config,
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Injection token for the configuration options for connecting to the Redux DevTools Extension.
|
|
176
|
+
*/
|
|
177
|
+
const REDUX_DEVTOOLS_CONFIG = new InjectionToken('ReduxDevtoolsConfig');
|
|
178
|
+
|
|
179
|
+
class DefaultTracker {
|
|
180
|
+
#stores = signal({});
|
|
181
|
+
get stores() {
|
|
182
|
+
return this.#stores();
|
|
183
|
+
}
|
|
184
|
+
#trackCallback;
|
|
185
|
+
#trackingEffect = effect(() => {
|
|
186
|
+
if (this.#trackCallback === undefined) {
|
|
187
|
+
throw new Error('no callback function defined');
|
|
188
|
+
}
|
|
189
|
+
const stores = this.#stores();
|
|
190
|
+
const fullState = Object.entries(stores).reduce((acc, [id, store]) => {
|
|
191
|
+
return { ...acc, [id]: getState(store) };
|
|
192
|
+
}, {});
|
|
193
|
+
this.#trackCallback(fullState);
|
|
194
|
+
});
|
|
195
|
+
track(id, store) {
|
|
196
|
+
this.#stores.update((value) => ({
|
|
197
|
+
...value,
|
|
198
|
+
[id]: store,
|
|
199
|
+
}));
|
|
200
|
+
}
|
|
201
|
+
onChange(callback) {
|
|
202
|
+
this.#trackCallback = callback;
|
|
203
|
+
}
|
|
204
|
+
removeStore(id) {
|
|
205
|
+
this.#stores.update((stores) => Object.entries(stores).reduce((newStore, [storeId, state]) => {
|
|
206
|
+
if (storeId !== id) {
|
|
207
|
+
newStore[storeId] = state;
|
|
208
|
+
}
|
|
209
|
+
return newStore;
|
|
210
|
+
}, {}));
|
|
211
|
+
}
|
|
212
|
+
notifyRenamedStore(id) {
|
|
213
|
+
if (this.#stores()[id]) {
|
|
214
|
+
this.#stores.update((stores) => {
|
|
215
|
+
return { ...stores };
|
|
216
|
+
});
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DefaultTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
220
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DefaultTracker, providedIn: 'root' }); }
|
|
221
|
+
}
|
|
222
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DefaultTracker, decorators: [{
|
|
223
|
+
type: Injectable,
|
|
224
|
+
args: [{ providedIn: 'root' }]
|
|
225
|
+
}] });
|
|
226
|
+
|
|
227
|
+
const currentActionNames = new Set();
|
|
228
|
+
|
|
22
229
|
const dummyConnection = {
|
|
23
230
|
send: () => void true,
|
|
24
231
|
};
|
|
@@ -41,6 +248,10 @@ class DevtoolsSyncer {
|
|
|
41
248
|
#stores = {};
|
|
42
249
|
#isBrowser = isPlatformBrowser(inject(PLATFORM_ID));
|
|
43
250
|
#trackers = [];
|
|
251
|
+
#devtoolsConfig = {
|
|
252
|
+
name: 'NgRx SignalStore',
|
|
253
|
+
...inject(REDUX_DEVTOOLS_CONFIG, { optional: true }),
|
|
254
|
+
};
|
|
44
255
|
/**
|
|
45
256
|
* Maintains the current states of all stores to avoid conflicts
|
|
46
257
|
* between glitch-free and glitched trackers when used simultaneously.
|
|
@@ -59,19 +270,13 @@ class DevtoolsSyncer {
|
|
|
59
270
|
#currentId = 1;
|
|
60
271
|
#connection = this.#isBrowser
|
|
61
272
|
? window.__REDUX_DEVTOOLS_EXTENSION__
|
|
62
|
-
? window.__REDUX_DEVTOOLS_EXTENSION__.connect(
|
|
63
|
-
name: 'NgRx SignalStore',
|
|
64
|
-
})
|
|
273
|
+
? window.__REDUX_DEVTOOLS_EXTENSION__.connect(this.#devtoolsConfig)
|
|
65
274
|
: dummyConnection
|
|
66
275
|
: dummyConnection;
|
|
67
276
|
constructor() {
|
|
68
277
|
if (!this.#isBrowser) {
|
|
69
278
|
return;
|
|
70
279
|
}
|
|
71
|
-
const isToolkitAvailable = Boolean(window.__REDUX_DEVTOOLS_EXTENSION__);
|
|
72
|
-
if (!isToolkitAvailable) {
|
|
73
|
-
console.info('NgRx Toolkit/DevTools: Redux DevTools Extension is not available.');
|
|
74
|
-
}
|
|
75
280
|
}
|
|
76
281
|
ngOnDestroy() {
|
|
77
282
|
currentActionNames.clear();
|
|
@@ -168,62 +373,14 @@ Enable automatic indexing via withDevTools('${storeName}', { indexNames: true })
|
|
|
168
373
|
}, {});
|
|
169
374
|
this.#trackers.forEach((tracker) => tracker.notifyRenamedStore(id));
|
|
170
375
|
}
|
|
171
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.
|
|
172
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.
|
|
376
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DevtoolsSyncer, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
377
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DevtoolsSyncer, providedIn: 'root' }); }
|
|
173
378
|
}
|
|
174
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.
|
|
379
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DevtoolsSyncer, decorators: [{
|
|
175
380
|
type: Injectable,
|
|
176
381
|
args: [{ providedIn: 'root' }]
|
|
177
382
|
}], ctorParameters: () => [] });
|
|
178
383
|
|
|
179
|
-
class DefaultTracker {
|
|
180
|
-
#stores = signal({});
|
|
181
|
-
get stores() {
|
|
182
|
-
return this.#stores();
|
|
183
|
-
}
|
|
184
|
-
#trackCallback;
|
|
185
|
-
#trackingEffect = effect(() => {
|
|
186
|
-
if (this.#trackCallback === undefined) {
|
|
187
|
-
throw new Error('no callback function defined');
|
|
188
|
-
}
|
|
189
|
-
const stores = this.#stores();
|
|
190
|
-
const fullState = Object.entries(stores).reduce((acc, [id, store]) => {
|
|
191
|
-
return { ...acc, [id]: getState(store) };
|
|
192
|
-
}, {});
|
|
193
|
-
this.#trackCallback(fullState);
|
|
194
|
-
});
|
|
195
|
-
track(id, store) {
|
|
196
|
-
this.#stores.update((value) => ({
|
|
197
|
-
...value,
|
|
198
|
-
[id]: store,
|
|
199
|
-
}));
|
|
200
|
-
}
|
|
201
|
-
onChange(callback) {
|
|
202
|
-
this.#trackCallback = callback;
|
|
203
|
-
}
|
|
204
|
-
removeStore(id) {
|
|
205
|
-
this.#stores.update((stores) => Object.entries(stores).reduce((newStore, [storeId, state]) => {
|
|
206
|
-
if (storeId !== id) {
|
|
207
|
-
newStore[storeId] = state;
|
|
208
|
-
}
|
|
209
|
-
return newStore;
|
|
210
|
-
}, {}));
|
|
211
|
-
}
|
|
212
|
-
notifyRenamedStore(id) {
|
|
213
|
-
if (this.#stores()[id]) {
|
|
214
|
-
this.#stores.update((stores) => {
|
|
215
|
-
return { ...stores };
|
|
216
|
-
});
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: DefaultTracker, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
220
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: DefaultTracker, providedIn: 'root' }); }
|
|
221
|
-
}
|
|
222
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: DefaultTracker, decorators: [{
|
|
223
|
-
type: Injectable,
|
|
224
|
-
args: [{ providedIn: 'root' }]
|
|
225
|
-
}] });
|
|
226
|
-
|
|
227
384
|
const renameDevtoolsMethodName = '___renameDevtoolsName';
|
|
228
385
|
const uniqueDevtoolsId = '___uniqueDevtoolsId';
|
|
229
386
|
const EXISTING_NAMES = new InjectionToken('Array contain existing names for the signal stores', { factory: () => [], providedIn: 'root' });
|
|
@@ -271,154 +428,17 @@ function withDevtools(name, ...features) {
|
|
|
271
428
|
}));
|
|
272
429
|
}
|
|
273
430
|
|
|
274
|
-
const DEVTOOLS_FEATURE = Symbol('DEVTOOLS_FEATURE');
|
|
275
|
-
function createDevtoolsFeature(options) {
|
|
276
|
-
return {
|
|
277
|
-
[DEVTOOLS_FEATURE]: true,
|
|
278
|
-
...options,
|
|
279
|
-
};
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
/**
|
|
283
|
-
* If multiple instances of the same SignalStore class
|
|
284
|
-
* exist, their devtool names are indexed.
|
|
285
|
-
*
|
|
286
|
-
* For example:
|
|
287
|
-
*
|
|
288
|
-
* ```typescript
|
|
289
|
-
* const Store = signalStore(
|
|
290
|
-
* withDevtools('flights')
|
|
291
|
-
* )
|
|
292
|
-
*
|
|
293
|
-
* const store1 = new Store(); // will show up as 'flights'
|
|
294
|
-
* const store2 = new Store(); // will show up as 'flights-1'
|
|
295
|
-
* ```
|
|
296
|
-
*
|
|
297
|
-
* With adding `withDisabledNameIndices` to the store:
|
|
298
|
-
* ```typescript
|
|
299
|
-
* const Store = signalStore(
|
|
300
|
-
* withDevtools('flights', withDisabledNameIndices())
|
|
301
|
-
* )
|
|
302
|
-
*
|
|
303
|
-
* const store1 = new Store(); // will show up as 'flights'
|
|
304
|
-
* const store2 = new Store(); //💥 throws an error
|
|
305
|
-
* ```
|
|
306
|
-
*
|
|
307
|
-
*/
|
|
308
|
-
function withDisabledNameIndices() {
|
|
309
|
-
return createDevtoolsFeature({ indexNames: false });
|
|
310
|
-
}
|
|
311
|
-
|
|
312
431
|
/**
|
|
313
|
-
*
|
|
314
|
-
*
|
|
315
|
-
*
|
|
316
|
-
* you don't need to see the whole state or other reasons.
|
|
317
|
-
*
|
|
318
|
-
* Example:
|
|
319
|
-
*
|
|
320
|
-
* ```typescript
|
|
321
|
-
* const initialState = {
|
|
322
|
-
* id: 1,
|
|
323
|
-
* email: 'john.list@host.com',
|
|
324
|
-
* name: 'John List',
|
|
325
|
-
* enteredPassword: ''
|
|
326
|
-
* }
|
|
327
|
-
*
|
|
328
|
-
* const Store = signalStore(
|
|
329
|
-
* withState(initialState),
|
|
330
|
-
* withDevtools(
|
|
331
|
-
* 'user',
|
|
332
|
-
* withMapper(state => ({...state, enteredPassword: '***' }))
|
|
333
|
-
* )
|
|
334
|
-
* )
|
|
335
|
-
* ```
|
|
336
|
-
*
|
|
337
|
-
* @param map function which maps the state
|
|
338
|
-
*/
|
|
339
|
-
function withMapper(map) {
|
|
340
|
-
return createDevtoolsFeature({ map: map });
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/**
|
|
344
|
-
* Internal Service used by {@link withGlitchTracking}. It does not rely
|
|
345
|
-
* on `effect` as {@link DefaultTracker} does but uses the NgRx function
|
|
346
|
-
* `watchState` to track all state changes.
|
|
432
|
+
* Renames the name of a store how it appears in the Devtools.
|
|
433
|
+
* @param store instance of the SignalStore
|
|
434
|
+
* @param newName new name for the Devtools
|
|
347
435
|
*/
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
return Object.entries(this.#stores).reduce((acc, [id, { store }]) => {
|
|
353
|
-
acc[id] = store;
|
|
354
|
-
return acc;
|
|
355
|
-
}, {});
|
|
356
|
-
}
|
|
357
|
-
onChange(callback) {
|
|
358
|
-
this.#callback = callback;
|
|
359
|
-
}
|
|
360
|
-
removeStore(id) {
|
|
361
|
-
this.#stores = Object.entries(this.#stores).reduce((newStore, [storeId, value]) => {
|
|
362
|
-
if (storeId !== id) {
|
|
363
|
-
newStore[storeId] = value;
|
|
364
|
-
}
|
|
365
|
-
else {
|
|
366
|
-
value.destroyWatcher();
|
|
367
|
-
}
|
|
368
|
-
return newStore;
|
|
369
|
-
}, {});
|
|
370
|
-
throwIfNull(this.#callback)({});
|
|
371
|
-
}
|
|
372
|
-
track(id, store) {
|
|
373
|
-
const watcher = watchState(store, (state) => {
|
|
374
|
-
throwIfNull(this.#callback)({ [id]: state });
|
|
375
|
-
});
|
|
376
|
-
this.#stores[id] = { destroyWatcher: watcher.destroy, store };
|
|
377
|
-
}
|
|
378
|
-
notifyRenamedStore(id) {
|
|
379
|
-
if (Object.keys(this.#stores).includes(id) && this.#callback) {
|
|
380
|
-
this.#callback({ [id]: getState(this.#stores[id].store) });
|
|
381
|
-
}
|
|
436
|
+
function renameDevtoolsName(store, newName) {
|
|
437
|
+
const renameMethod = store[renameDevtoolsMethodName];
|
|
438
|
+
if (!renameMethod) {
|
|
439
|
+
throw new Error("Devtools extensions haven't been added to this store.");
|
|
382
440
|
}
|
|
383
|
-
|
|
384
|
-
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: GlitchTrackerService, providedIn: 'root' }); }
|
|
385
|
-
}
|
|
386
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.4", ngImport: i0, type: GlitchTrackerService, decorators: [{
|
|
387
|
-
type: Injectable,
|
|
388
|
-
args: [{ providedIn: 'root' }]
|
|
389
|
-
}] });
|
|
390
|
-
|
|
391
|
-
/**
|
|
392
|
-
* It tracks all state changes of the State, including intermediary updates
|
|
393
|
-
* that are typically suppressed by Angular's glitch-free mechanism.
|
|
394
|
-
*
|
|
395
|
-
* This feature is especially useful for debugging.
|
|
396
|
-
*
|
|
397
|
-
* Example:
|
|
398
|
-
*
|
|
399
|
-
* ```typescript
|
|
400
|
-
* const Store = signalStore(
|
|
401
|
-
* { providedIn: 'root' },
|
|
402
|
-
* withState({ count: 0 }),
|
|
403
|
-
* withDevtools('counter', withGlitchTracking()),
|
|
404
|
-
* withMethods((store) => ({
|
|
405
|
-
* increase: () =>
|
|
406
|
-
* patchState(store, (value) => ({ count: value.count + 1 })),
|
|
407
|
-
* }))
|
|
408
|
-
* );
|
|
409
|
-
*
|
|
410
|
-
* // would show up in the DevTools with value 0
|
|
411
|
-
* const store = inject(Store);
|
|
412
|
-
*
|
|
413
|
-
* store.increase(); // would show up in the DevTools with value 1
|
|
414
|
-
* store.increase(); // would show up in the DevTools with value 2
|
|
415
|
-
* store.increase(); // would show up in the DevTools with value 3
|
|
416
|
-
* ```
|
|
417
|
-
*
|
|
418
|
-
* Without `withGlitchTracking`, the DevTools would only show the final value of 3.
|
|
419
|
-
*/
|
|
420
|
-
function withGlitchTracking() {
|
|
421
|
-
return createDevtoolsFeature({ tracker: GlitchTrackerService });
|
|
441
|
+
renameMethod(newName);
|
|
422
442
|
}
|
|
423
443
|
|
|
424
444
|
/**
|
|
@@ -440,17 +460,9 @@ function updateState(stateSource, action, ...updaters) {
|
|
|
440
460
|
}
|
|
441
461
|
|
|
442
462
|
/**
|
|
443
|
-
*
|
|
444
|
-
* @param store instance of the SignalStore
|
|
445
|
-
* @param newName new name for the Devtools
|
|
463
|
+
* Stub for DevTools integration. Can be used to disable DevTools in production.
|
|
446
464
|
*/
|
|
447
|
-
|
|
448
|
-
const renameMethod = store[renameDevtoolsMethodName];
|
|
449
|
-
if (!renameMethod) {
|
|
450
|
-
throw new Error("Devtools extensions haven't been added to this store.");
|
|
451
|
-
}
|
|
452
|
-
renameMethod(newName);
|
|
453
|
-
}
|
|
465
|
+
const withDevToolsStub = () => (store) => store;
|
|
454
466
|
|
|
455
467
|
function assertActionFnSpecs(obj) {
|
|
456
468
|
if (!obj || typeof obj !== 'object') {
|
|
@@ -508,6 +520,8 @@ function createReducer(reducerFactory) {
|
|
|
508
520
|
return reducerFactory;
|
|
509
521
|
}
|
|
510
522
|
/**
|
|
523
|
+
* @deprecated Use NgRx's `@ngrx/signals/events` starting in 19.2
|
|
524
|
+
*
|
|
511
525
|
* Creates the effects function to separate the effects logic into another file.
|
|
512
526
|
*
|
|
513
527
|
* ```typescript
|
|
@@ -648,18 +662,58 @@ function withRedux(redux) {
|
|
|
648
662
|
};
|
|
649
663
|
}
|
|
650
664
|
|
|
651
|
-
function
|
|
652
|
-
const prop = config?.collection;
|
|
665
|
+
function deriveCallStateKeys(collection) {
|
|
653
666
|
return {
|
|
654
|
-
callStateKey:
|
|
655
|
-
loadingKey:
|
|
656
|
-
loadedKey:
|
|
657
|
-
errorKey:
|
|
667
|
+
callStateKey: collection ? `${collection}CallState` : 'callState',
|
|
668
|
+
loadingKey: collection ? `${collection}Loading` : 'loading',
|
|
669
|
+
loadedKey: collection ? `${collection}Loaded` : 'loaded',
|
|
670
|
+
errorKey: collection ? `${collection}Error` : 'error',
|
|
658
671
|
};
|
|
659
672
|
}
|
|
673
|
+
function getCallStateKeys(config) {
|
|
674
|
+
const prop = config?.collection;
|
|
675
|
+
return deriveCallStateKeys(prop);
|
|
676
|
+
}
|
|
677
|
+
function getCollectionArray(config) {
|
|
678
|
+
return 'collections' in config
|
|
679
|
+
? config.collections
|
|
680
|
+
: 'collection' in config && config.collection
|
|
681
|
+
? [config.collection]
|
|
682
|
+
: undefined;
|
|
683
|
+
}
|
|
660
684
|
function withCallState(config) {
|
|
661
|
-
|
|
662
|
-
|
|
685
|
+
return signalStoreFeature(withState(() => {
|
|
686
|
+
if (!config) {
|
|
687
|
+
return { callState: 'init' };
|
|
688
|
+
}
|
|
689
|
+
const collections = getCollectionArray(config);
|
|
690
|
+
if (collections) {
|
|
691
|
+
return collections.reduce((acc, cur) => ({
|
|
692
|
+
...acc,
|
|
693
|
+
...{ [cur ? `${cur}CallState` : 'callState']: 'init' },
|
|
694
|
+
}), {});
|
|
695
|
+
}
|
|
696
|
+
return { callState: 'init' };
|
|
697
|
+
}), withComputed((state) => {
|
|
698
|
+
if (config) {
|
|
699
|
+
const collections = getCollectionArray(config);
|
|
700
|
+
if (collections) {
|
|
701
|
+
return collections.reduce((acc, cur) => {
|
|
702
|
+
const { callStateKey, errorKey, loadedKey, loadingKey } = deriveCallStateKeys(cur);
|
|
703
|
+
const callState = state[callStateKey];
|
|
704
|
+
return {
|
|
705
|
+
...acc,
|
|
706
|
+
[loadingKey]: computed(() => callState() === 'loading'),
|
|
707
|
+
[loadedKey]: computed(() => callState() === 'loaded'),
|
|
708
|
+
[errorKey]: computed(() => {
|
|
709
|
+
const v = callState();
|
|
710
|
+
return typeof v === 'object' ? v.error : null;
|
|
711
|
+
}),
|
|
712
|
+
};
|
|
713
|
+
}, {});
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
const { callStateKey, errorKey, loadedKey, loadingKey } = deriveCallStateKeys();
|
|
663
717
|
const callState = state[callStateKey];
|
|
664
718
|
return {
|
|
665
719
|
[loadingKey]: computed(() => callState() === 'loading'),
|
|
@@ -909,228 +963,60 @@ function withDataService(options) {
|
|
|
909
963
|
}));
|
|
910
964
|
}
|
|
911
965
|
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
]
|
|
925
|
-
}
|
|
926
|
-
|
|
966
|
+
/** With pagination comes in two flavors the first one is local pagination or in memory pagination. For example we have 2000 items which we want
|
|
967
|
+
* to display in a table and the response payload is small enough to be stored in the memory. But we can not display all 2000 items at once
|
|
968
|
+
* so we need to paginate the data. The second flavor is server side pagination where the response payload is too large to be stored in the memory
|
|
969
|
+
* and we need to fetch the data from the server in chunks. In the second case we 'could' also cache the data in the memory but that could lead to
|
|
970
|
+
* other problems like memory leaks and stale data. So we will not cache the data in the memory in the second case.
|
|
971
|
+
* This feature implements the local pagination.
|
|
972
|
+
*/
|
|
973
|
+
function withPagination(options) {
|
|
974
|
+
const { pageKey, pageSizeKey, entitiesKey, selectedPageEntitiesKey, totalCountKey, pageCountKey, pageNavigationArrayMaxKey, pageNavigationArrayKey, hasNextPageKey, hasPreviousPageKey, } = createPaginationKeys(options);
|
|
975
|
+
return signalStoreFeature(withState({
|
|
976
|
+
[pageKey]: 0,
|
|
977
|
+
[pageSizeKey]: 10,
|
|
978
|
+
[pageNavigationArrayMaxKey]: 7,
|
|
979
|
+
}), withComputed((store) => {
|
|
980
|
+
const entities = store[entitiesKey];
|
|
981
|
+
const page = store[pageKey];
|
|
982
|
+
const pageSize = store[pageSizeKey];
|
|
983
|
+
const pageNavigationArrayMax = store[pageNavigationArrayMaxKey];
|
|
984
|
+
return {
|
|
985
|
+
// The derived enitites which are displayed on the current page
|
|
986
|
+
[selectedPageEntitiesKey]: computed(() => {
|
|
987
|
+
const pageSizeValue = pageSize();
|
|
988
|
+
const pageValue = page();
|
|
989
|
+
return entities().slice(pageValue * pageSizeValue, (pageValue + 1) * pageSizeValue);
|
|
990
|
+
}),
|
|
991
|
+
[totalCountKey]: computed(() => entities().length),
|
|
992
|
+
[pageCountKey]: computed(() => {
|
|
993
|
+
const totalCountValue = entities().length;
|
|
994
|
+
const pageSizeValue = pageSize();
|
|
995
|
+
if (totalCountValue === 0) {
|
|
996
|
+
return 0;
|
|
997
|
+
}
|
|
998
|
+
return Math.ceil(totalCountValue / pageSizeValue);
|
|
999
|
+
}),
|
|
1000
|
+
[pageNavigationArrayKey]: computed(() => createPageArray(page(), pageSize(), entities().length, pageNavigationArrayMax())),
|
|
1001
|
+
[hasNextPageKey]: computed(() => {
|
|
1002
|
+
return page() < pageSize();
|
|
1003
|
+
}),
|
|
1004
|
+
[hasPreviousPageKey]: computed(() => {
|
|
1005
|
+
return page() > 1;
|
|
1006
|
+
}),
|
|
1007
|
+
};
|
|
1008
|
+
}));
|
|
927
1009
|
}
|
|
928
|
-
function
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
...defaultOptions,
|
|
933
|
-
...options,
|
|
1010
|
+
function gotoPage(page, options) {
|
|
1011
|
+
const { pageKey } = createPaginationKeys(options);
|
|
1012
|
+
return {
|
|
1013
|
+
[pageKey]: page,
|
|
934
1014
|
};
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
const redoStack = [];
|
|
941
|
-
const canUndo = signal(false);
|
|
942
|
-
const canRedo = signal(false);
|
|
943
|
-
const updateInternal = () => {
|
|
944
|
-
canUndo.set(undoStack.length !== 0);
|
|
945
|
-
canRedo.set(redoStack.length !== 0);
|
|
946
|
-
};
|
|
947
|
-
const keys = [...getUndoRedoKeys(normalized.collections), ...normalized.keys];
|
|
948
|
-
return signalStoreFeature(withComputed(() => ({
|
|
949
|
-
canUndo: canUndo.asReadonly(),
|
|
950
|
-
canRedo: canRedo.asReadonly(),
|
|
951
|
-
})), withMethods((store) => ({
|
|
952
|
-
undo() {
|
|
953
|
-
const item = undoStack.pop();
|
|
954
|
-
if (item && previous) {
|
|
955
|
-
redoStack.push(previous);
|
|
956
|
-
}
|
|
957
|
-
if (item) {
|
|
958
|
-
skipOnce = true;
|
|
959
|
-
patchState$1(store, item);
|
|
960
|
-
previous = item;
|
|
961
|
-
}
|
|
962
|
-
updateInternal();
|
|
963
|
-
},
|
|
964
|
-
redo() {
|
|
965
|
-
const item = redoStack.pop();
|
|
966
|
-
if (item && previous) {
|
|
967
|
-
undoStack.push(previous);
|
|
968
|
-
}
|
|
969
|
-
if (item) {
|
|
970
|
-
skipOnce = true;
|
|
971
|
-
patchState$1(store, item);
|
|
972
|
-
previous = item;
|
|
973
|
-
}
|
|
974
|
-
updateInternal();
|
|
975
|
-
},
|
|
976
|
-
clearStack() {
|
|
977
|
-
undoStack.splice(0);
|
|
978
|
-
redoStack.splice(0);
|
|
979
|
-
updateInternal();
|
|
980
|
-
},
|
|
981
|
-
})), withHooks({
|
|
982
|
-
onInit(store) {
|
|
983
|
-
effect(() => {
|
|
984
|
-
const cand = keys.reduce((acc, key) => {
|
|
985
|
-
const s = store[key];
|
|
986
|
-
if (s && isSignal(s)) {
|
|
987
|
-
return {
|
|
988
|
-
...acc,
|
|
989
|
-
[key]: s(),
|
|
990
|
-
};
|
|
991
|
-
}
|
|
992
|
-
return acc;
|
|
993
|
-
}, {});
|
|
994
|
-
if (normalized.skip > 0) {
|
|
995
|
-
normalized.skip--;
|
|
996
|
-
return;
|
|
997
|
-
}
|
|
998
|
-
if (skipOnce) {
|
|
999
|
-
skipOnce = false;
|
|
1000
|
-
return;
|
|
1001
|
-
}
|
|
1002
|
-
//
|
|
1003
|
-
// Deep Comparison to prevent duplicated entries
|
|
1004
|
-
// on the stack. This can e.g. happen after an undo
|
|
1005
|
-
// if the component sends back the undone filter
|
|
1006
|
-
// to the store.
|
|
1007
|
-
//
|
|
1008
|
-
if (JSON.stringify(cand) === JSON.stringify(previous)) {
|
|
1009
|
-
return;
|
|
1010
|
-
}
|
|
1011
|
-
// Clear redoStack after recorded action
|
|
1012
|
-
redoStack.splice(0);
|
|
1013
|
-
if (previous) {
|
|
1014
|
-
undoStack.push(previous);
|
|
1015
|
-
}
|
|
1016
|
-
if (redoStack.length > normalized.maxStackSize) {
|
|
1017
|
-
undoStack.unshift();
|
|
1018
|
-
}
|
|
1019
|
-
previous = cand;
|
|
1020
|
-
// Don't propogate current reactive context
|
|
1021
|
-
untracked(() => updateInternal());
|
|
1022
|
-
});
|
|
1023
|
-
},
|
|
1024
|
-
}));
|
|
1025
|
-
}
|
|
1026
|
-
|
|
1027
|
-
const NOOP = () => void true;
|
|
1028
|
-
const StorageSyncStub = {
|
|
1029
|
-
clearStorage: NOOP,
|
|
1030
|
-
readFromStorage: NOOP,
|
|
1031
|
-
writeToStorage: NOOP,
|
|
1032
|
-
};
|
|
1033
|
-
function withStorageSync(configOrKey) {
|
|
1034
|
-
const { key, autoSync = true, select = (state) => state, parse = JSON.parse, stringify = JSON.stringify, storage: storageFactory = () => localStorage, } = typeof configOrKey === 'string' ? { key: configOrKey } : configOrKey;
|
|
1035
|
-
return signalStoreFeature(withMethods((store, platformId = inject(PLATFORM_ID)) => {
|
|
1036
|
-
if (isPlatformServer(platformId)) {
|
|
1037
|
-
console.warn(`'withStorageSync' provides non-functional implementation due to server-side execution`);
|
|
1038
|
-
return StorageSyncStub;
|
|
1039
|
-
}
|
|
1040
|
-
const storage = storageFactory();
|
|
1041
|
-
return {
|
|
1042
|
-
/**
|
|
1043
|
-
* Removes the item stored in storage.
|
|
1044
|
-
*/
|
|
1045
|
-
clearStorage() {
|
|
1046
|
-
storage.removeItem(key);
|
|
1047
|
-
},
|
|
1048
|
-
/**
|
|
1049
|
-
* Reads item from storage and patches the state.
|
|
1050
|
-
*/
|
|
1051
|
-
readFromStorage() {
|
|
1052
|
-
const stateString = storage.getItem(key);
|
|
1053
|
-
if (stateString) {
|
|
1054
|
-
patchState$1(store, parse(stateString));
|
|
1055
|
-
}
|
|
1056
|
-
},
|
|
1057
|
-
/**
|
|
1058
|
-
* Writes selected portion to storage.
|
|
1059
|
-
*/
|
|
1060
|
-
writeToStorage() {
|
|
1061
|
-
const slicedState = select(getState(store));
|
|
1062
|
-
storage.setItem(key, stringify(slicedState));
|
|
1063
|
-
},
|
|
1064
|
-
};
|
|
1065
|
-
}), withHooks({
|
|
1066
|
-
onInit(store, platformId = inject(PLATFORM_ID)) {
|
|
1067
|
-
if (isPlatformServer(platformId)) {
|
|
1068
|
-
return;
|
|
1069
|
-
}
|
|
1070
|
-
if (autoSync) {
|
|
1071
|
-
store.readFromStorage();
|
|
1072
|
-
effect(() => {
|
|
1073
|
-
store.writeToStorage();
|
|
1074
|
-
});
|
|
1075
|
-
}
|
|
1076
|
-
},
|
|
1077
|
-
}));
|
|
1078
|
-
}
|
|
1079
|
-
|
|
1080
|
-
/** With pagination comes in two flavors the first one is local pagination or in memory pagination. For example we have 2000 items which we want
|
|
1081
|
-
* to display in a table and the response payload is small enough to be stored in the memory. But we can not display all 2000 items at once
|
|
1082
|
-
* so we need to paginate the data. The second flavor is server side pagination where the response payload is too large to be stored in the memory
|
|
1083
|
-
* and we need to fetch the data from the server in chunks. In the second case we 'could' also cache the data in the memory but that could lead to
|
|
1084
|
-
* other problems like memory leaks and stale data. So we will not cache the data in the memory in the second case.
|
|
1085
|
-
* This feature implements the local pagination.
|
|
1086
|
-
*/
|
|
1087
|
-
function withPagination(options) {
|
|
1088
|
-
const { pageKey, pageSizeKey, entitiesKey, selectedPageEntitiesKey, totalCountKey, pageCountKey, pageNavigationArrayMaxKey, pageNavigationArrayKey, hasNextPageKey, hasPreviousPageKey, } = createPaginationKeys(options);
|
|
1089
|
-
return signalStoreFeature(withState({
|
|
1090
|
-
[pageKey]: 0,
|
|
1091
|
-
[pageSizeKey]: 10,
|
|
1092
|
-
[pageNavigationArrayMaxKey]: 7,
|
|
1093
|
-
}), withComputed((store) => {
|
|
1094
|
-
const entities = store[entitiesKey];
|
|
1095
|
-
const page = store[pageKey];
|
|
1096
|
-
const pageSize = store[pageSizeKey];
|
|
1097
|
-
const pageNavigationArrayMax = store[pageNavigationArrayMaxKey];
|
|
1098
|
-
return {
|
|
1099
|
-
// The derived enitites which are displayed on the current page
|
|
1100
|
-
[selectedPageEntitiesKey]: computed(() => {
|
|
1101
|
-
const pageSizeValue = pageSize();
|
|
1102
|
-
const pageValue = page();
|
|
1103
|
-
return entities().slice(pageValue * pageSizeValue, (pageValue + 1) * pageSizeValue);
|
|
1104
|
-
}),
|
|
1105
|
-
[totalCountKey]: computed(() => entities().length),
|
|
1106
|
-
[pageCountKey]: computed(() => {
|
|
1107
|
-
const totalCountValue = entities().length;
|
|
1108
|
-
const pageSizeValue = pageSize();
|
|
1109
|
-
if (totalCountValue === 0) {
|
|
1110
|
-
return 0;
|
|
1111
|
-
}
|
|
1112
|
-
return Math.ceil(totalCountValue / pageSizeValue);
|
|
1113
|
-
}),
|
|
1114
|
-
[pageNavigationArrayKey]: computed(() => createPageArray(page(), pageSize(), entities().length, pageNavigationArrayMax())),
|
|
1115
|
-
[hasNextPageKey]: computed(() => {
|
|
1116
|
-
return page() < pageSize();
|
|
1117
|
-
}),
|
|
1118
|
-
[hasPreviousPageKey]: computed(() => {
|
|
1119
|
-
return page() > 1;
|
|
1120
|
-
}),
|
|
1121
|
-
};
|
|
1122
|
-
}));
|
|
1123
|
-
}
|
|
1124
|
-
function gotoPage(page, options) {
|
|
1125
|
-
const { pageKey } = createPaginationKeys(options);
|
|
1126
|
-
return {
|
|
1127
|
-
[pageKey]: page,
|
|
1128
|
-
};
|
|
1129
|
-
}
|
|
1130
|
-
function setPageSize(pageSize, options) {
|
|
1131
|
-
const { pageSizeKey } = createPaginationKeys(options);
|
|
1132
|
-
return {
|
|
1133
|
-
[pageSizeKey]: pageSize,
|
|
1015
|
+
}
|
|
1016
|
+
function setPageSize(pageSize, options) {
|
|
1017
|
+
const { pageSizeKey } = createPaginationKeys(options);
|
|
1018
|
+
return {
|
|
1019
|
+
[pageSizeKey]: pageSize,
|
|
1134
1020
|
};
|
|
1135
1021
|
}
|
|
1136
1022
|
function nextPage(options) {
|
|
@@ -1273,6 +1159,122 @@ function setResetState(store, state) {
|
|
|
1273
1159
|
store.__setResetState__(state);
|
|
1274
1160
|
}
|
|
1275
1161
|
|
|
1162
|
+
const defaultOptions = {
|
|
1163
|
+
maxStackSize: 100,
|
|
1164
|
+
keys: [],
|
|
1165
|
+
skip: 0,
|
|
1166
|
+
};
|
|
1167
|
+
function getUndoRedoKeys(collections) {
|
|
1168
|
+
if (collections) {
|
|
1169
|
+
return collections.flatMap((c) => [
|
|
1170
|
+
`${c}EntityMap`,
|
|
1171
|
+
`${c}Ids`,
|
|
1172
|
+
`selected${capitalize(c)}Ids`,
|
|
1173
|
+
`${c}Filter`,
|
|
1174
|
+
]);
|
|
1175
|
+
}
|
|
1176
|
+
return ['entityMap', 'ids', 'selectedIds', 'filter'];
|
|
1177
|
+
}
|
|
1178
|
+
function withUndoRedo(options) {
|
|
1179
|
+
let previous = null;
|
|
1180
|
+
let skipOnce = false;
|
|
1181
|
+
const normalized = {
|
|
1182
|
+
...defaultOptions,
|
|
1183
|
+
...options,
|
|
1184
|
+
};
|
|
1185
|
+
//
|
|
1186
|
+
// Design Decision: This feature has its own
|
|
1187
|
+
// internal state.
|
|
1188
|
+
//
|
|
1189
|
+
const undoStack = [];
|
|
1190
|
+
const redoStack = [];
|
|
1191
|
+
const canUndo = signal(false);
|
|
1192
|
+
const canRedo = signal(false);
|
|
1193
|
+
const updateInternal = () => {
|
|
1194
|
+
canUndo.set(undoStack.length !== 0);
|
|
1195
|
+
canRedo.set(redoStack.length !== 0);
|
|
1196
|
+
};
|
|
1197
|
+
const keys = [...getUndoRedoKeys(normalized.collections), ...normalized.keys];
|
|
1198
|
+
return signalStoreFeature(withComputed(() => ({
|
|
1199
|
+
canUndo: canUndo.asReadonly(),
|
|
1200
|
+
canRedo: canRedo.asReadonly(),
|
|
1201
|
+
})), withMethods((store) => ({
|
|
1202
|
+
undo() {
|
|
1203
|
+
const item = undoStack.pop();
|
|
1204
|
+
if (item && previous) {
|
|
1205
|
+
redoStack.push(previous);
|
|
1206
|
+
}
|
|
1207
|
+
if (item) {
|
|
1208
|
+
skipOnce = true;
|
|
1209
|
+
patchState$1(store, item);
|
|
1210
|
+
previous = item;
|
|
1211
|
+
}
|
|
1212
|
+
updateInternal();
|
|
1213
|
+
},
|
|
1214
|
+
redo() {
|
|
1215
|
+
const item = redoStack.pop();
|
|
1216
|
+
if (item && previous) {
|
|
1217
|
+
undoStack.push(previous);
|
|
1218
|
+
}
|
|
1219
|
+
if (item) {
|
|
1220
|
+
skipOnce = true;
|
|
1221
|
+
patchState$1(store, item);
|
|
1222
|
+
previous = item;
|
|
1223
|
+
}
|
|
1224
|
+
updateInternal();
|
|
1225
|
+
},
|
|
1226
|
+
clearStack() {
|
|
1227
|
+
undoStack.splice(0);
|
|
1228
|
+
redoStack.splice(0);
|
|
1229
|
+
previous = null;
|
|
1230
|
+
updateInternal();
|
|
1231
|
+
},
|
|
1232
|
+
})), withHooks({
|
|
1233
|
+
onInit(store) {
|
|
1234
|
+
effect(() => {
|
|
1235
|
+
const cand = keys.reduce((acc, key) => {
|
|
1236
|
+
const s = store[key];
|
|
1237
|
+
if (s && isSignal(s)) {
|
|
1238
|
+
return {
|
|
1239
|
+
...acc,
|
|
1240
|
+
[key]: s(),
|
|
1241
|
+
};
|
|
1242
|
+
}
|
|
1243
|
+
return acc;
|
|
1244
|
+
}, {});
|
|
1245
|
+
if (normalized.skip > 0) {
|
|
1246
|
+
normalized.skip--;
|
|
1247
|
+
return;
|
|
1248
|
+
}
|
|
1249
|
+
if (skipOnce) {
|
|
1250
|
+
skipOnce = false;
|
|
1251
|
+
return;
|
|
1252
|
+
}
|
|
1253
|
+
//
|
|
1254
|
+
// Deep Comparison to prevent duplicated entries
|
|
1255
|
+
// on the stack. This can e.g. happen after an undo
|
|
1256
|
+
// if the component sends back the undone filter
|
|
1257
|
+
// to the store.
|
|
1258
|
+
//
|
|
1259
|
+
if (JSON.stringify(cand) === JSON.stringify(previous)) {
|
|
1260
|
+
return;
|
|
1261
|
+
}
|
|
1262
|
+
// Clear redoStack after recorded action
|
|
1263
|
+
redoStack.splice(0);
|
|
1264
|
+
if (previous) {
|
|
1265
|
+
undoStack.push(previous);
|
|
1266
|
+
}
|
|
1267
|
+
if (redoStack.length > normalized.maxStackSize) {
|
|
1268
|
+
undoStack.unshift();
|
|
1269
|
+
}
|
|
1270
|
+
previous = cand;
|
|
1271
|
+
// Don't propogate current reactive context
|
|
1272
|
+
untracked(() => updateInternal());
|
|
1273
|
+
});
|
|
1274
|
+
},
|
|
1275
|
+
}));
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1276
1278
|
/**
|
|
1277
1279
|
* Deep freezes a state object along its properties with primitive values
|
|
1278
1280
|
* on the first level.
|
|
@@ -1344,38 +1346,335 @@ function withImmutableState(stateOrFactory, options) {
|
|
|
1344
1346
|
})));
|
|
1345
1347
|
}
|
|
1346
1348
|
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
|
|
1374
|
-
|
|
1349
|
+
const keyPath = 'ngrxToolkitKeyPath';
|
|
1350
|
+
const dbName = 'ngrxToolkitDb';
|
|
1351
|
+
const storeName = 'ngrxToolkitStore';
|
|
1352
|
+
const VERSION = 1;
|
|
1353
|
+
class IndexedDBService {
|
|
1354
|
+
/**
|
|
1355
|
+
* write to indexedDB
|
|
1356
|
+
* @param key
|
|
1357
|
+
* @param data
|
|
1358
|
+
*/
|
|
1359
|
+
async setItem(key, data) {
|
|
1360
|
+
const db = await this.openDB();
|
|
1361
|
+
const tx = db.transaction(storeName, 'readwrite');
|
|
1362
|
+
const store = tx.objectStore(storeName);
|
|
1363
|
+
store.put({
|
|
1364
|
+
[keyPath]: key,
|
|
1365
|
+
value: data,
|
|
1366
|
+
});
|
|
1367
|
+
return new Promise((resolve, reject) => {
|
|
1368
|
+
tx.oncomplete = () => {
|
|
1369
|
+
db.close();
|
|
1370
|
+
resolve();
|
|
1371
|
+
};
|
|
1372
|
+
tx.onerror = () => {
|
|
1373
|
+
db.close();
|
|
1374
|
+
reject();
|
|
1375
|
+
};
|
|
1376
|
+
});
|
|
1377
|
+
}
|
|
1378
|
+
/**
|
|
1379
|
+
* read from indexedDB
|
|
1380
|
+
* @param key
|
|
1381
|
+
*/
|
|
1382
|
+
async getItem(key) {
|
|
1383
|
+
const db = await this.openDB();
|
|
1384
|
+
const tx = db.transaction(storeName, 'readonly');
|
|
1385
|
+
const store = tx.objectStore(storeName);
|
|
1386
|
+
const request = store.get(key);
|
|
1387
|
+
return new Promise((resolve, reject) => {
|
|
1388
|
+
request.onsuccess = () => {
|
|
1389
|
+
db.close();
|
|
1390
|
+
// localStorage(sessionStorage) returns null if the key does not exist
|
|
1391
|
+
// Similarly, indexedDB should return null
|
|
1392
|
+
if (request.result === undefined) {
|
|
1393
|
+
resolve(null);
|
|
1394
|
+
}
|
|
1395
|
+
resolve(request.result?.['value']);
|
|
1396
|
+
};
|
|
1397
|
+
request.onerror = () => {
|
|
1398
|
+
db.close();
|
|
1399
|
+
reject();
|
|
1400
|
+
};
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* delete indexedDB
|
|
1405
|
+
* @param key
|
|
1406
|
+
*/
|
|
1407
|
+
async clear(key) {
|
|
1408
|
+
const db = await this.openDB();
|
|
1409
|
+
const tx = db.transaction(storeName, 'readwrite');
|
|
1410
|
+
const store = tx.objectStore(storeName);
|
|
1411
|
+
const request = store.delete(key);
|
|
1412
|
+
return new Promise((resolve, reject) => {
|
|
1413
|
+
request.onsuccess = () => {
|
|
1414
|
+
db.close();
|
|
1415
|
+
resolve();
|
|
1416
|
+
};
|
|
1417
|
+
request.onerror = () => {
|
|
1418
|
+
db.close();
|
|
1419
|
+
reject();
|
|
1420
|
+
};
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
/**
|
|
1424
|
+
* open indexedDB
|
|
1425
|
+
*/
|
|
1426
|
+
async openDB() {
|
|
1427
|
+
return new Promise((resolve, reject) => {
|
|
1428
|
+
const request = indexedDB.open(dbName, VERSION);
|
|
1429
|
+
request.onupgradeneeded = () => {
|
|
1430
|
+
const db = request.result;
|
|
1431
|
+
if (!db.objectStoreNames.contains(storeName)) {
|
|
1432
|
+
db.createObjectStore(storeName, { keyPath });
|
|
1433
|
+
}
|
|
1434
|
+
};
|
|
1435
|
+
request.onsuccess = () => {
|
|
1436
|
+
resolve(request.result);
|
|
1437
|
+
};
|
|
1438
|
+
request.onerror = () => {
|
|
1439
|
+
reject(request.error);
|
|
1440
|
+
};
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: IndexedDBService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1444
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: IndexedDBService, providedIn: 'root' }); }
|
|
1445
|
+
}
|
|
1446
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: IndexedDBService, decorators: [{
|
|
1447
|
+
type: Injectable,
|
|
1448
|
+
args: [{ providedIn: 'root' }]
|
|
1449
|
+
}] });
|
|
1450
|
+
|
|
1451
|
+
const SYNC_STATUS = Symbol('SYNC_STATUS');
|
|
1452
|
+
|
|
1453
|
+
function withIndexedDB() {
|
|
1454
|
+
function factory({ key, parse, select, stringify }, store, useStubs) {
|
|
1455
|
+
if (useStubs) {
|
|
1456
|
+
return {
|
|
1457
|
+
clearStorage: () => Promise.resolve(),
|
|
1458
|
+
readFromStorage: () => Promise.resolve(),
|
|
1459
|
+
writeToStorage: () => Promise.resolve(),
|
|
1460
|
+
};
|
|
1461
|
+
}
|
|
1462
|
+
const indexeddbService = inject(IndexedDBService);
|
|
1463
|
+
function warnOnSyncing(mode) {
|
|
1464
|
+
if (store[SYNC_STATUS]() === 'syncing') {
|
|
1465
|
+
const prettyMode = mode === 'read' ? 'Reading' : 'Writing';
|
|
1466
|
+
console.warn(`${prettyMode} to Store (${key}) happened during an ongoing synchronization process.`, 'Please ensure that the store is not in syncing state via `store.whenSynced()`.', 'Alternatively, you can disable the autoSync by passing `autoSync: false` in the config.');
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
return {
|
|
1470
|
+
/**
|
|
1471
|
+
* Removes the item stored in storage.
|
|
1472
|
+
*/
|
|
1473
|
+
async clearStorage() {
|
|
1474
|
+
warnOnSyncing('write');
|
|
1475
|
+
store[SYNC_STATUS].set('syncing');
|
|
1476
|
+
patchState$1(store, {});
|
|
1477
|
+
await indexeddbService.clear(key);
|
|
1478
|
+
store[SYNC_STATUS].set('synced');
|
|
1479
|
+
},
|
|
1480
|
+
/**
|
|
1481
|
+
* Reads item from storage and patches the state.
|
|
1482
|
+
*/
|
|
1483
|
+
async readFromStorage() {
|
|
1484
|
+
warnOnSyncing('read');
|
|
1485
|
+
store[SYNC_STATUS].set('syncing');
|
|
1486
|
+
const stateString = await indexeddbService.getItem(key);
|
|
1487
|
+
if (stateString) {
|
|
1488
|
+
patchState$1(store, parse(stateString));
|
|
1489
|
+
}
|
|
1490
|
+
store[SYNC_STATUS].set('synced');
|
|
1491
|
+
},
|
|
1492
|
+
/**
|
|
1493
|
+
* Writes selected portion to storage.
|
|
1494
|
+
*/
|
|
1495
|
+
async writeToStorage() {
|
|
1496
|
+
warnOnSyncing('write');
|
|
1497
|
+
store[SYNC_STATUS].set('syncing');
|
|
1498
|
+
const slicedState = select(getState(store));
|
|
1499
|
+
await indexeddbService.setItem(key, stringify(slicedState));
|
|
1500
|
+
store[SYNC_STATUS].set('synced');
|
|
1501
|
+
},
|
|
1375
1502
|
};
|
|
1376
|
-
|
|
1377
|
-
|
|
1503
|
+
}
|
|
1504
|
+
factory.type = 'async';
|
|
1505
|
+
return factory;
|
|
1506
|
+
}
|
|
1507
|
+
|
|
1508
|
+
class LocalStorageService {
|
|
1509
|
+
getItem(key) {
|
|
1510
|
+
return localStorage.getItem(key);
|
|
1511
|
+
}
|
|
1512
|
+
setItem(key, data) {
|
|
1513
|
+
return localStorage.setItem(key, data);
|
|
1514
|
+
}
|
|
1515
|
+
clear(key) {
|
|
1516
|
+
return localStorage.removeItem(key);
|
|
1517
|
+
}
|
|
1518
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1519
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, providedIn: 'root' }); }
|
|
1520
|
+
}
|
|
1521
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: LocalStorageService, decorators: [{
|
|
1522
|
+
type: Injectable,
|
|
1523
|
+
args: [{
|
|
1524
|
+
providedIn: 'root',
|
|
1525
|
+
}]
|
|
1526
|
+
}] });
|
|
1527
|
+
|
|
1528
|
+
class SessionStorageService {
|
|
1529
|
+
getItem(key) {
|
|
1530
|
+
return sessionStorage.getItem(key);
|
|
1531
|
+
}
|
|
1532
|
+
setItem(key, data) {
|
|
1533
|
+
return sessionStorage.setItem(key, data);
|
|
1534
|
+
}
|
|
1535
|
+
clear(key) {
|
|
1536
|
+
return sessionStorage.removeItem(key);
|
|
1537
|
+
}
|
|
1538
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SessionStorageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1539
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SessionStorageService, providedIn: 'root' }); }
|
|
1540
|
+
}
|
|
1541
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: SessionStorageService, decorators: [{
|
|
1542
|
+
type: Injectable,
|
|
1543
|
+
args: [{
|
|
1544
|
+
providedIn: 'root',
|
|
1545
|
+
}]
|
|
1546
|
+
}] });
|
|
1547
|
+
|
|
1548
|
+
function withLocalStorage() {
|
|
1549
|
+
return createSyncMethods(LocalStorageService);
|
|
1550
|
+
}
|
|
1551
|
+
function withSessionStorage() {
|
|
1552
|
+
return createSyncMethods(SessionStorageService);
|
|
1553
|
+
}
|
|
1554
|
+
function createSyncMethods(Storage) {
|
|
1555
|
+
function factory({ key, parse, select, stringify }, store, useStubs) {
|
|
1556
|
+
if (useStubs) {
|
|
1557
|
+
return {
|
|
1558
|
+
clearStorage: () => undefined,
|
|
1559
|
+
readFromStorage: () => undefined,
|
|
1560
|
+
writeToStorage: () => undefined,
|
|
1561
|
+
};
|
|
1562
|
+
}
|
|
1563
|
+
const storage = inject(Storage);
|
|
1564
|
+
return {
|
|
1565
|
+
clearStorage() {
|
|
1566
|
+
storage.clear(key);
|
|
1567
|
+
},
|
|
1568
|
+
readFromStorage() {
|
|
1569
|
+
const stateString = storage.getItem(key);
|
|
1570
|
+
if (stateString) {
|
|
1571
|
+
patchState$1(store, parse(stateString));
|
|
1572
|
+
}
|
|
1573
|
+
},
|
|
1574
|
+
writeToStorage() {
|
|
1575
|
+
const slicedState = select(getState(store));
|
|
1576
|
+
storage.setItem(key, stringify(slicedState));
|
|
1577
|
+
},
|
|
1578
|
+
};
|
|
1579
|
+
}
|
|
1580
|
+
factory.type = 'sync';
|
|
1581
|
+
return factory;
|
|
1582
|
+
}
|
|
1583
|
+
|
|
1584
|
+
function withStorageSync(configOrKey, storageStrategy) {
|
|
1585
|
+
if (typeof configOrKey !== 'string' &&
|
|
1586
|
+
configOrKey.storage &&
|
|
1587
|
+
storageStrategy) {
|
|
1588
|
+
throw new Error('You can either pass a storage strategy or a config with storage, but not both.');
|
|
1589
|
+
}
|
|
1590
|
+
const config = {
|
|
1591
|
+
autoSync: true,
|
|
1592
|
+
select: (state) => state,
|
|
1593
|
+
parse: JSON.parse,
|
|
1594
|
+
stringify: JSON.stringify,
|
|
1595
|
+
storage: () => localStorage,
|
|
1596
|
+
...(typeof configOrKey === 'string' ? { key: configOrKey } : configOrKey),
|
|
1378
1597
|
};
|
|
1598
|
+
const factory = storageStrategy ??
|
|
1599
|
+
(config.storage() === localStorage
|
|
1600
|
+
? withLocalStorage()
|
|
1601
|
+
: withSessionStorage());
|
|
1602
|
+
if (factory.type === 'sync') {
|
|
1603
|
+
return createSyncStorageSync(factory, config);
|
|
1604
|
+
}
|
|
1605
|
+
else {
|
|
1606
|
+
return createAsyncStorageSync(factory, config);
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
function createSyncStorageSync(factory, config) {
|
|
1610
|
+
return signalStoreFeature(withMethods((store, platformId = inject(PLATFORM_ID)) => {
|
|
1611
|
+
return factory(config, store, isPlatformServer(platformId));
|
|
1612
|
+
}), withHooks({
|
|
1613
|
+
onInit(store, platformId = inject(PLATFORM_ID)) {
|
|
1614
|
+
if (isPlatformServer(platformId)) {
|
|
1615
|
+
return;
|
|
1616
|
+
}
|
|
1617
|
+
if (config.autoSync) {
|
|
1618
|
+
store.readFromStorage();
|
|
1619
|
+
watchState(store, () => store.writeToStorage());
|
|
1620
|
+
}
|
|
1621
|
+
},
|
|
1622
|
+
}));
|
|
1623
|
+
}
|
|
1624
|
+
function createAsyncStorageSync(factory, config) {
|
|
1625
|
+
return signalStoreFeature(withProps(() => {
|
|
1626
|
+
const props = {
|
|
1627
|
+
/*
|
|
1628
|
+
// we need to have that as property (and not state)
|
|
1629
|
+
// Otherwise the state watcher fires when updating the sync status
|
|
1630
|
+
*/
|
|
1631
|
+
[SYNC_STATUS]: signal('idle'),
|
|
1632
|
+
};
|
|
1633
|
+
const resolves = [];
|
|
1634
|
+
effect(() => {
|
|
1635
|
+
const syncStatus = props[SYNC_STATUS]();
|
|
1636
|
+
if (syncStatus === 'synced') {
|
|
1637
|
+
resolves.forEach((resolve) => resolve());
|
|
1638
|
+
resolves.splice(0, resolves.length);
|
|
1639
|
+
}
|
|
1640
|
+
});
|
|
1641
|
+
return {
|
|
1642
|
+
...props,
|
|
1643
|
+
isSynced: computed(() => props[SYNC_STATUS]() === 'synced'),
|
|
1644
|
+
whenSynced: () => new Promise((resolve) => {
|
|
1645
|
+
if (props[SYNC_STATUS]() === 'synced') {
|
|
1646
|
+
resolve();
|
|
1647
|
+
}
|
|
1648
|
+
else {
|
|
1649
|
+
resolves.push(resolve);
|
|
1650
|
+
}
|
|
1651
|
+
}),
|
|
1652
|
+
};
|
|
1653
|
+
}), withMethods((store, platformId = inject(PLATFORM_ID)) => {
|
|
1654
|
+
return factory(config, store, isPlatformServer(platformId));
|
|
1655
|
+
}), withHooks({
|
|
1656
|
+
async onInit(store, platformId = inject(PLATFORM_ID)) {
|
|
1657
|
+
if (isPlatformServer(platformId)) {
|
|
1658
|
+
return;
|
|
1659
|
+
}
|
|
1660
|
+
const initialState = getState(store);
|
|
1661
|
+
if (config.autoSync) {
|
|
1662
|
+
let startWatching = false;
|
|
1663
|
+
watchState(store, () => {
|
|
1664
|
+
if (!startWatching) {
|
|
1665
|
+
if (getState(store) === initialState) {
|
|
1666
|
+
return;
|
|
1667
|
+
}
|
|
1668
|
+
console.warn(`Writing to Store (${config.key}) happened before the state was initially read from storage.`, 'Please ensure that the store is not in syncing state via `store.whenSynced()` before writing to the state.', 'Alternatively, you can disable autoSync by passing `autoSync: false` in the config.');
|
|
1669
|
+
return;
|
|
1670
|
+
}
|
|
1671
|
+
return store.writeToStorage();
|
|
1672
|
+
});
|
|
1673
|
+
await store.readFromStorage();
|
|
1674
|
+
startWatching = true;
|
|
1675
|
+
}
|
|
1676
|
+
},
|
|
1677
|
+
}));
|
|
1379
1678
|
}
|
|
1380
1679
|
|
|
1381
1680
|
/**
|
|
@@ -1435,9 +1734,45 @@ function withConditional(condition, featureIfTrue, featureIfFalse) {
|
|
|
1435
1734
|
}
|
|
1436
1735
|
const emptyFeature = signalStoreFeature(withState({}));
|
|
1437
1736
|
|
|
1737
|
+
/**
|
|
1738
|
+
* @deprecated Use `import { withFeature } from '@ngrx/signals'` instead, starting with `ngrx/signals` 19.1: https://ngrx.io/guide/signals/signal-store/custom-store-features#connecting-a-custom-feature-with-the-store
|
|
1739
|
+
*
|
|
1740
|
+
* Allows to pass properties, methods, or signals from a SignalStore
|
|
1741
|
+
* to a feature.
|
|
1742
|
+
*
|
|
1743
|
+
* Typically, a `signalStoreFeature` can have input constraints on
|
|
1744
|
+
*
|
|
1745
|
+
* ```typescript
|
|
1746
|
+
* function withSum(a: Signal<number>, b: Signal<number>) {
|
|
1747
|
+
* return signalStoreFeature(
|
|
1748
|
+
* withComputed(() => ({
|
|
1749
|
+
* sum: computed(() => a() + b())
|
|
1750
|
+
* }))
|
|
1751
|
+
* );
|
|
1752
|
+
* }
|
|
1753
|
+
*
|
|
1754
|
+
* signalStore(
|
|
1755
|
+
* withState({ a: 1, b: 2 }),
|
|
1756
|
+
* withFeatureFactory((store) => withSum(store.a, store.b))
|
|
1757
|
+
* );
|
|
1758
|
+
* ```
|
|
1759
|
+
* @param factoryFn
|
|
1760
|
+
*/
|
|
1761
|
+
function withFeatureFactory(factoryFn) {
|
|
1762
|
+
return (store) => {
|
|
1763
|
+
const storeForFactory = {
|
|
1764
|
+
...store['stateSignals'],
|
|
1765
|
+
...store['props'],
|
|
1766
|
+
...store['methods'],
|
|
1767
|
+
};
|
|
1768
|
+
const feature = factoryFn(storeForFactory);
|
|
1769
|
+
return feature(store);
|
|
1770
|
+
};
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1438
1773
|
/**
|
|
1439
1774
|
* Generated bundle index. Do not edit.
|
|
1440
1775
|
*/
|
|
1441
1776
|
|
|
1442
|
-
export { capitalize, createEffects, createPageArray, createReducer, emptyFeature, firstPage, getCallStateKeys, getDataServiceKeys, getUndoRedoKeys, gotoPage, nextPage, noPayload, patchState, payload, previousPage, renameDevtoolsName, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, updateState, withCallState, withConditional, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withFeatureFactory, withGlitchTracking, withImmutableState, withMapper, withPagination, withRedux, withReset, withStorageSync, withUndoRedo };
|
|
1777
|
+
export { capitalize, createEffects, createPageArray, createReducer, deriveCallStateKeys, emptyFeature, firstPage, getCallStateKeys, getCollectionArray, getDataServiceKeys, getUndoRedoKeys, gotoPage, nextPage, noPayload, patchState, payload, previousPage, provideDevtoolsConfig, renameDevtoolsName, setError, setLoaded, setLoading, setMaxPageNavigationArrayItems, setPageSize, setResetState, updateState, withCallState, withConditional, withDataService, withDevToolsStub, withDevtools, withDisabledNameIndices, withFeatureFactory, withGlitchTracking, withImmutableState, withIndexedDB, withIndexedDB as withIndexeddb, withLocalStorage, withMapper, withPagination, withRedux, withReset, withSessionStorage, withStorageSync, withUndoRedo };
|
|
1443
1778
|
//# sourceMappingURL=angular-architects-ngrx-toolkit.mjs.map
|