@angular-architects/ngrx-toolkit 19.0.1 → 19.1.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 +2 -2
- package/fesm2022/angular-architects-ngrx-toolkit-redux-connector.mjs +3 -3
- package/fesm2022/angular-architects-ngrx-toolkit.mjs +271 -67
- package/fesm2022/angular-architects-ngrx-toolkit.mjs.map +1 -1
- package/index.d.ts +4 -1
- package/lib/devtools/with-devtools.d.ts +0 -1
- package/lib/immutable-state/deep-freeze.d.ts +11 -0
- package/lib/immutable-state/is-dev-mode.d.ts +1 -0
- package/lib/immutable-state/with-immutable-state.d.ts +60 -0
- package/lib/with-conditional.d.ts +50 -0
- package/lib/with-feature-factory.d.ts +26 -0
- package/lib/with-pagination.d.ts +5 -31
- package/lib/with-redux.d.ts +88 -0
- package/package.json +1 -1
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { EmptyFeatureResult, SignalStoreFeature, SignalStoreFeatureResult } from '@ngrx/signals';
|
|
2
|
+
/**
|
|
3
|
+
* The implementation of this feature is a little bit tricky.
|
|
4
|
+
*
|
|
5
|
+
* `signalStore` does a shallow clone in the initial phase, in order to
|
|
6
|
+
* merge all different states together.
|
|
7
|
+
*
|
|
8
|
+
* Shallow cloning also happens in `patchState`.
|
|
9
|
+
*
|
|
10
|
+
* With shallow cloning, the root state object is replaced, which means,
|
|
11
|
+
* the freezing only stays for its nested properties but not for
|
|
12
|
+
* the primitive and immediate properties.
|
|
13
|
+
*
|
|
14
|
+
* For example:
|
|
15
|
+
*
|
|
16
|
+
* ```ts
|
|
17
|
+
* const state = {
|
|
18
|
+
* id: 1,
|
|
19
|
+
* address: {
|
|
20
|
+
* street: 'Main St',
|
|
21
|
+
* city: 'Springfield',
|
|
22
|
+
* }
|
|
23
|
+
* }
|
|
24
|
+
* ```
|
|
25
|
+
*
|
|
26
|
+
* Running `Object.freeze` on `state` will freeze the `address` object, and
|
|
27
|
+
* the `id`. But since `state` is shallow cloned, the "frozing" state of the
|
|
28
|
+
* `id` is lost. `address`, being an object, is still frozen.
|
|
29
|
+
*
|
|
30
|
+
* To overcome that, we run `watchState` and run `deepFreeze`
|
|
31
|
+
* on every change.
|
|
32
|
+
*/
|
|
33
|
+
/**
|
|
34
|
+
* Prevents mutation of the state.
|
|
35
|
+
*
|
|
36
|
+
* This is done by deeply applying `Object.freeze`. Any mutable change within
|
|
37
|
+
* or outside the `SignalStore` will throw an error.
|
|
38
|
+
*
|
|
39
|
+
* @param state the state object
|
|
40
|
+
* @param options enable protection in production (default: false)
|
|
41
|
+
*/
|
|
42
|
+
export declare function withImmutableState<State extends object>(state: State, options?: {
|
|
43
|
+
enableInProduction?: boolean;
|
|
44
|
+
}): SignalStoreFeature<SignalStoreFeatureResult, EmptyFeatureResult & {
|
|
45
|
+
state: State;
|
|
46
|
+
}>;
|
|
47
|
+
/**
|
|
48
|
+
* Prevents mutation of the state.
|
|
49
|
+
*
|
|
50
|
+
* This is done by deeply applying `Object.freeze`. Any mutable change within
|
|
51
|
+
* or outside the `SignalStore` will throw an error.
|
|
52
|
+
*
|
|
53
|
+
* @param stateFactory a function returning the state object
|
|
54
|
+
* @param options enable protection in production (default: false)
|
|
55
|
+
*/
|
|
56
|
+
export declare function withImmutableState<State extends object>(stateFactory: () => State, options?: {
|
|
57
|
+
enableInProduction?: boolean;
|
|
58
|
+
}): SignalStoreFeature<SignalStoreFeatureResult, EmptyFeatureResult & {
|
|
59
|
+
state: State;
|
|
60
|
+
}>;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { SignalStoreFeature, SignalStoreFeatureResult, StateSignals } from '@ngrx/signals';
|
|
2
|
+
/**
|
|
3
|
+
* `withConditional` activates a feature based on a given condition.
|
|
4
|
+
*
|
|
5
|
+
* **Use Cases**
|
|
6
|
+
* - Conditionally activate features based on the **store state** or other criteria.
|
|
7
|
+
* - Choose between **two different implementations** of a feature.
|
|
8
|
+
*
|
|
9
|
+
* **Type Constraints**
|
|
10
|
+
* Both features must have **exactly the same state, props, and methods**.
|
|
11
|
+
* Otherwise, a type error will occur.
|
|
12
|
+
*
|
|
13
|
+
*
|
|
14
|
+
* **Usage**
|
|
15
|
+
*
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const withUser = signalStoreFeature(
|
|
18
|
+
* withState({ id: 1, name: 'Konrad' }),
|
|
19
|
+
* withHooks(store => ({
|
|
20
|
+
* onInit() {
|
|
21
|
+
* // user loading logic
|
|
22
|
+
* }
|
|
23
|
+
* }))
|
|
24
|
+
* );
|
|
25
|
+
*
|
|
26
|
+
* function withFakeUser() {
|
|
27
|
+
* return signalStoreFeature(
|
|
28
|
+
* withState({ id: 0, name: 'anonymous' })
|
|
29
|
+
* );
|
|
30
|
+
* }
|
|
31
|
+
*
|
|
32
|
+
* signalStore(
|
|
33
|
+
* withMethods(() => ({
|
|
34
|
+
* useRealUser: () => true
|
|
35
|
+
* })),
|
|
36
|
+
* withConditional((store) => store.useRealUser(), withUser, withFakeUser)
|
|
37
|
+
* )
|
|
38
|
+
* ```
|
|
39
|
+
*
|
|
40
|
+
* @param condition - A function that determines which feature to activate based on the store state.
|
|
41
|
+
* @param featureIfTrue - The feature to activate if the condition evaluates to `true`.
|
|
42
|
+
* @param featureIfFalse - The feature to activate if the condition evaluates to `false`.
|
|
43
|
+
* @returns A `SignalStoreFeature` that applies the selected feature based on the condition.
|
|
44
|
+
*/
|
|
45
|
+
export declare function withConditional<Input extends SignalStoreFeatureResult, Output extends SignalStoreFeatureResult>(condition: (store: StateSignals<Input['state']> & Input['props'] & Input['methods']) => boolean, featureIfTrue: SignalStoreFeature<NoInfer<Input>, Output>, featureIfFalse: SignalStoreFeature<NoInfer<Input>, NoInfer<Output>>): SignalStoreFeature<Input, Output>;
|
|
46
|
+
export declare const emptyFeature: SignalStoreFeature<import("@ngrx/signals").EmptyFeatureResult, {
|
|
47
|
+
state: {};
|
|
48
|
+
props: {};
|
|
49
|
+
methods: {};
|
|
50
|
+
}>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { SignalStoreFeature, SignalStoreFeatureResult, StateSignals } from '@ngrx/signals';
|
|
2
|
+
type StoreForFactory<Input extends SignalStoreFeatureResult> = StateSignals<Input['state']> & Input['props'] & Input['methods'];
|
|
3
|
+
/**
|
|
4
|
+
* Allows to pass properties, methods, or signals from a SignalStore
|
|
5
|
+
* to a feature.
|
|
6
|
+
*
|
|
7
|
+
* Typically, a `signalStoreFeature` can have input constraints on
|
|
8
|
+
*
|
|
9
|
+
* ```typescript
|
|
10
|
+
* function withSum(a: Signal<number>, b: Signal<number>) {
|
|
11
|
+
* return signalStoreFeature(
|
|
12
|
+
* withComputed(() => ({
|
|
13
|
+
* sum: computed(() => a() + b())
|
|
14
|
+
* }))
|
|
15
|
+
* );
|
|
16
|
+
* }
|
|
17
|
+
*
|
|
18
|
+
* signalStore(
|
|
19
|
+
* withState({ a: 1, b: 2 }),
|
|
20
|
+
* withFeatureFactory((store) => withSum(store.a, store.b))
|
|
21
|
+
* );
|
|
22
|
+
* ```
|
|
23
|
+
* @param factoryFn
|
|
24
|
+
*/
|
|
25
|
+
export declare function withFeatureFactory<Input extends SignalStoreFeatureResult, Output extends SignalStoreFeatureResult>(factoryFn: (store: StoreForFactory<Input>) => SignalStoreFeature<Input, Output>): SignalStoreFeature<Input, Output>;
|
|
26
|
+
export {};
|
package/lib/with-pagination.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { Signal } from '@angular/core';
|
|
9
9
|
import { SignalStoreFeature, EmptyFeatureResult } from '@ngrx/signals';
|
|
10
|
-
import {
|
|
10
|
+
import { MethodsDictionary } from '@ngrx/signals/src/signal-store-models';
|
|
11
11
|
export type Page = {
|
|
12
12
|
label: string | number;
|
|
13
13
|
value: number;
|
|
@@ -46,19 +46,6 @@ export type NamedPaginationServiceSignals<E, Collection extends string> = {
|
|
|
46
46
|
} & {
|
|
47
47
|
[K in Collection as `hasPrevious${Capitalize<K>}Page`]: Signal<boolean>;
|
|
48
48
|
};
|
|
49
|
-
export type NamedPaginationServiceMethods<Collection extends string> = {
|
|
50
|
-
[K in Collection as `set${Capitalize<K>}PageSize`]: (size: number) => void;
|
|
51
|
-
} & {
|
|
52
|
-
[K in Collection as `next${Capitalize<K>}Page`]: () => void;
|
|
53
|
-
} & {
|
|
54
|
-
[K in Collection as `previous${Capitalize<K>}Page`]: () => void;
|
|
55
|
-
} & {
|
|
56
|
-
[K in Collection as `last${Capitalize<K>}Page`]: () => void;
|
|
57
|
-
} & {
|
|
58
|
-
[K in Collection as `first${Capitalize<K>}Page`]: () => void;
|
|
59
|
-
} & {
|
|
60
|
-
[K in Collection as `goto${Capitalize<K>}Page`]: (page: number) => void;
|
|
61
|
-
};
|
|
62
49
|
export type PaginationServiceState<E> = {
|
|
63
50
|
selectedPageEntities: Array<E>;
|
|
64
51
|
currentPage: number;
|
|
@@ -79,32 +66,19 @@ export type PaginationServiceSignals<E> = {
|
|
|
79
66
|
hasNextPage: Signal<boolean>;
|
|
80
67
|
hasPreviousPage: Signal<boolean>;
|
|
81
68
|
};
|
|
82
|
-
export type PaginationServiceMethods = {
|
|
83
|
-
setPageSize: (size: number) => void;
|
|
84
|
-
nextPageKey: () => void;
|
|
85
|
-
previousPage: () => void;
|
|
86
|
-
lastPage: () => void;
|
|
87
|
-
firstPage: () => void;
|
|
88
|
-
gotoPage: (page: number) => void;
|
|
89
|
-
};
|
|
90
69
|
export type SetPaginationState<E, Collection extends string | undefined> = Collection extends string ? NamedPaginationServiceState<E, Collection> : PaginationServiceState<E>;
|
|
91
70
|
export declare function withPagination<E, Collection extends string>(options: {
|
|
92
71
|
entity: E;
|
|
93
72
|
collection: Collection;
|
|
94
|
-
}): SignalStoreFeature<EmptyFeatureResult
|
|
95
|
-
props: NamedEntityComputed<E, Collection>;
|
|
96
|
-
}, {
|
|
73
|
+
}): SignalStoreFeature<EmptyFeatureResult, {
|
|
97
74
|
state: NamedPaginationServiceState<E, Collection>;
|
|
98
75
|
props: NamedPaginationServiceSignals<E, Collection>;
|
|
99
|
-
methods:
|
|
76
|
+
methods: MethodsDictionary;
|
|
100
77
|
}>;
|
|
101
|
-
export declare function withPagination<E>(): SignalStoreFeature<EmptyFeatureResult
|
|
102
|
-
state: EntityState<E>;
|
|
103
|
-
props: EntityComputed<E>;
|
|
104
|
-
}, {
|
|
78
|
+
export declare function withPagination<E>(): SignalStoreFeature<EmptyFeatureResult, {
|
|
105
79
|
state: PaginationServiceState<E>;
|
|
106
80
|
props: PaginationServiceSignals<E>;
|
|
107
|
-
methods:
|
|
81
|
+
methods: MethodsDictionary;
|
|
108
82
|
}>;
|
|
109
83
|
export declare function gotoPage<E, Collection extends string>(page: number, options?: {
|
|
110
84
|
collection: Collection;
|
package/lib/with-redux.d.ts
CHANGED
|
@@ -33,10 +33,98 @@ type ReducerFunction<ReducerAction, State> = (state: State, action: ActionFnPayl
|
|
|
33
33
|
type ReducerFactory<StateActionFns extends ActionFns, State> = (actions: StateActionFns, on: <ReducerAction extends {
|
|
34
34
|
type: string;
|
|
35
35
|
}>(action: ReducerAction, reducerFn: ReducerFunction<ReducerAction, State>) => void) => void;
|
|
36
|
+
/**
|
|
37
|
+
* Creates a reducer function to separate the reducer logic into another file.
|
|
38
|
+
*
|
|
39
|
+
* ```typescript
|
|
40
|
+
* interface FlightState {
|
|
41
|
+
* flights: Flight[];
|
|
42
|
+
* effect1: boolean;
|
|
43
|
+
* effect2: boolean;
|
|
44
|
+
* }
|
|
45
|
+
*
|
|
46
|
+
* const initialState: FlightState = {
|
|
47
|
+
* flights: [],
|
|
48
|
+
* effect1: false,
|
|
49
|
+
* effect2: false,
|
|
50
|
+
* };
|
|
51
|
+
*
|
|
52
|
+
* const actions = {
|
|
53
|
+
* init: noPayload,
|
|
54
|
+
* updateEffect1: payload<{ value: boolean }>(),
|
|
55
|
+
* updateEffect2: payload<{ value: boolean }>(),
|
|
56
|
+
* };
|
|
57
|
+
*
|
|
58
|
+
* const reducer = createReducer<FlightState, typeof actions>((actions, on) => {
|
|
59
|
+
* on(actions.updateEffect1, (state, { value }) => {
|
|
60
|
+
* patchState(state, { effect1: value });
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* on(actions.updateEffect2, (state, { value }) => {
|
|
64
|
+
* patchState(state, { effect2: value });
|
|
65
|
+
* });
|
|
66
|
+
* });
|
|
67
|
+
*
|
|
68
|
+
* signalStore(
|
|
69
|
+
* withState(initialState),
|
|
70
|
+
* withRedux({
|
|
71
|
+
* actions,
|
|
72
|
+
* reducer,
|
|
73
|
+
* })
|
|
74
|
+
* );
|
|
75
|
+
* ```
|
|
76
|
+
* @param reducerFactory
|
|
77
|
+
*/
|
|
78
|
+
export declare function createReducer<State extends object, Actions extends ActionsFnSpecs>(reducerFactory: ReducerFactory<ActionFnsCreator<Actions>, WritableStateSource<State>>): ReducerFactory<ActionFnsCreator<Actions>, WritableStateSource<State>>;
|
|
36
79
|
/** Effect **/
|
|
37
80
|
type EffectsFactory<StateActionFns extends ActionFns> = (actions: StateActionFns, create: <EffectAction extends {
|
|
38
81
|
type: string;
|
|
39
82
|
}>(action: EffectAction) => Observable<ActionFnPayload<EffectAction>>) => Record<string, Observable<unknown>>;
|
|
83
|
+
/**
|
|
84
|
+
* Creates the effects function to separate the effects logic into another file.
|
|
85
|
+
*
|
|
86
|
+
* ```typescript
|
|
87
|
+
* interface FlightState {
|
|
88
|
+
* flights: Flight[];
|
|
89
|
+
* effect1: boolean;
|
|
90
|
+
* effect2: boolean;
|
|
91
|
+
* }
|
|
92
|
+
*
|
|
93
|
+
* const initialState: FlightState = {
|
|
94
|
+
* flights: [],
|
|
95
|
+
* effect1: false,
|
|
96
|
+
* effect2: false,
|
|
97
|
+
* };
|
|
98
|
+
*
|
|
99
|
+
* const actions = {
|
|
100
|
+
* init: noPayload,
|
|
101
|
+
* updateEffect1: payload<{ value: boolean }>(),
|
|
102
|
+
* updateEffect2: payload<{ value: boolean }>(),
|
|
103
|
+
* };
|
|
104
|
+
*
|
|
105
|
+
* const effects = createEffects(actions, (actions, create) => {
|
|
106
|
+
* return {
|
|
107
|
+
* init1$: create(actions.init).pipe(
|
|
108
|
+
* map(() => actions.updateEffect1({ value: true }))
|
|
109
|
+
* ),
|
|
110
|
+
* init2$: create(actions.init).pipe(
|
|
111
|
+
* map(() => actions.updateEffect2({ value: true }))
|
|
112
|
+
* ),
|
|
113
|
+
* };
|
|
114
|
+
* });
|
|
115
|
+
*
|
|
116
|
+
* signalStore(
|
|
117
|
+
* withState(initialState),
|
|
118
|
+
* withRedux({
|
|
119
|
+
* actions,
|
|
120
|
+
* effects,
|
|
121
|
+
* })
|
|
122
|
+
* );
|
|
123
|
+
* ```
|
|
124
|
+
* @param actions
|
|
125
|
+
* @param effectsFactory
|
|
126
|
+
*/
|
|
127
|
+
export declare function createEffects<Actions extends ActionsFnSpecs>(actions: Actions, effectsFactory: EffectsFactory<ActionFnsCreator<Actions>>): EffectsFactory<ActionFnsCreator<Actions>>;
|
|
40
128
|
/**
|
|
41
129
|
* @param redux redux
|
|
42
130
|
*
|