@veams/status-quo 0.1.0 → 1.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/.github/workflows/pages.yml +46 -0
- package/.github/workflows/release.yml +33 -0
- package/CHANGELOG.md +30 -0
- package/README.md +260 -124
- package/assets/statusquo-logo.png +0 -0
- package/dist/hooks/state-subscription.d.ts +1 -2
- package/dist/hooks/state-subscription.js +8 -9
- package/dist/hooks/state-subscription.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/index.js.map +1 -1
- package/dist/store/__tests__/{state-handler.spec.js → observable-state-handler.spec.js} +14 -14
- package/dist/store/__tests__/observable-state-handler.spec.js.map +1 -0
- package/dist/store/__tests__/signal-state-handler.spec.js +78 -0
- package/dist/store/__tests__/signal-state-handler.spec.js.map +1 -0
- package/dist/store/base-state-handler.d.ts +30 -0
- package/dist/store/base-state-handler.js +84 -0
- package/dist/store/base-state-handler.js.map +1 -0
- package/dist/store/index.d.ts +3 -1
- package/dist/store/index.js +3 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/observable-state-handler.d.ts +26 -0
- package/dist/store/observable-state-handler.js +55 -0
- package/dist/store/observable-state-handler.js.map +1 -0
- package/dist/store/signal-state-handler.d.ts +25 -0
- package/dist/store/signal-state-handler.js +49 -0
- package/dist/store/signal-state-handler.js.map +1 -0
- package/dist/types/types.d.ts +2 -2
- package/package.json +22 -11
- package/playground/index.html +12 -0
- package/playground/src/App.tsx +478 -0
- package/playground/src/assets/philosophy-agnostic.svg +18 -0
- package/playground/src/assets/philosophy-separation.svg +13 -0
- package/playground/src/assets/philosophy-swap.svg +17 -0
- package/playground/src/assets/statusquo-logo.png +0 -0
- package/playground/src/main.tsx +19 -0
- package/playground/src/styles.css +411 -0
- package/playground/tsconfig.json +12 -0
- package/playground/vite.config.ts +18 -0
- package/src/hooks/state-subscription.tsx +21 -14
- package/src/index.ts +14 -2
- package/src/store/__tests__/{state-handler.spec.ts → observable-state-handler.spec.ts} +15 -15
- package/src/store/__tests__/signal-state-handler.spec.ts +97 -0
- package/src/store/base-state-handler.ts +119 -0
- package/src/store/index.ts +3 -1
- package/src/store/observable-state-handler.ts +87 -0
- package/src/store/signal-state-handler.ts +76 -0
- package/src/types/types.ts +2 -3
- package/dist/store/__tests__/state-handler.spec.js.map +0 -1
- package/dist/store/state-handler.d.ts +0 -36
- package/dist/store/state-handler.js +0 -122
- package/dist/store/state-handler.js.map +0 -1
- package/dist/types/hooks/index.d.ts +0 -2
- package/dist/types/hooks/state-factory.d.ts +0 -2
- package/dist/types/hooks/state-singleton.d.ts +0 -2
- package/dist/types/hooks/state-subscription.d.ts +0 -3
- package/dist/types/index.d.ts +0 -6
- package/dist/types/store/dev-tools.d.ts +0 -23
- package/dist/types/store/index.d.ts +0 -3
- package/dist/types/store/state-handler.d.ts +0 -36
- package/dist/types/store/state-singleton.d.ts +0 -5
- package/dist/types/types/types.d.ts +0 -7
- package/src/store/state-handler.ts +0 -181
- /package/dist/store/__tests__/{state-handler.spec.d.ts → observable-state-handler.spec.d.ts} +0 -0
- /package/dist/{types/store/__tests__/state-handler.spec.d.ts → store/__tests__/signal-state-handler.spec.d.ts} +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { withDevTools } from './dev-tools.js';
|
|
2
|
+
|
|
3
|
+
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
4
|
+
import type { DevTools, MessagePayload } from './dev-tools.js';
|
|
5
|
+
|
|
6
|
+
type DevToolsOptions = {
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
namespace: string;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
const defaultDevToolsOptions = { enabled: false, namespace: 'Store' };
|
|
12
|
+
|
|
13
|
+
const devToolsFeatures = {
|
|
14
|
+
pause: true,
|
|
15
|
+
lock: true,
|
|
16
|
+
persist: false,
|
|
17
|
+
export: true,
|
|
18
|
+
import: 'custom',
|
|
19
|
+
jump: true,
|
|
20
|
+
skip: true,
|
|
21
|
+
reorder: true,
|
|
22
|
+
dispatch: false,
|
|
23
|
+
test: false,
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
export abstract class BaseStateHandler<S, A> implements StateSubscriptionHandler<S, A> {
|
|
27
|
+
protected readonly initialState: S;
|
|
28
|
+
protected devTools: DevTools | null = null;
|
|
29
|
+
|
|
30
|
+
subscriptions: Array<{ unsubscribe: () => void }> = [];
|
|
31
|
+
|
|
32
|
+
protected constructor(initialState: S) {
|
|
33
|
+
this.initialState = initialState;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected initDevTools(devToolsOptions?: DevToolsOptions) {
|
|
37
|
+
const mergedOptions = {
|
|
38
|
+
...defaultDevToolsOptions,
|
|
39
|
+
...devToolsOptions,
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
if (!mergedOptions.enabled) {
|
|
43
|
+
this.devTools = null;
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
this.devTools = withDevTools(this.initialState, {
|
|
48
|
+
name: mergedOptions.namespace,
|
|
49
|
+
instanceId: mergedOptions.namespace.toLowerCase().replaceAll(' ', '-'),
|
|
50
|
+
actionCreators: this.getActions(),
|
|
51
|
+
features: devToolsFeatures,
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
this.devTools?.subscribe(this.handleDevToolsEvents);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getInitialState() {
|
|
58
|
+
return this.initialState;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
getState() {
|
|
62
|
+
return this.getStateValue();
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
getSnapshot() {
|
|
66
|
+
return this.getState();
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
setState(newState: Partial<S>, actionName = 'change') {
|
|
70
|
+
const nextState = { ...this.getState(), ...newState };
|
|
71
|
+
this.setStateValue(nextState);
|
|
72
|
+
this.devTools?.send(actionName, nextState);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
destroy(): void {
|
|
76
|
+
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
protected abstract getStateValue(): S;
|
|
80
|
+
protected abstract setStateValue(nextState: S): void;
|
|
81
|
+
protected bindSubscribable<T>(
|
|
82
|
+
service: { subscribe: (listener: (value: T) => void) => () => void; getSnapshot?: () => T },
|
|
83
|
+
onChange: (value: T) => void
|
|
84
|
+
) {
|
|
85
|
+
const unsubscribe = service.subscribe(onChange);
|
|
86
|
+
this.subscriptions = [...(this.subscriptions ?? []), { unsubscribe }];
|
|
87
|
+
|
|
88
|
+
if (service.getSnapshot) onChange(service.getSnapshot());
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
abstract subscribe(listener: () => void): () => void;
|
|
92
|
+
abstract getActions(): A;
|
|
93
|
+
|
|
94
|
+
private handleDevToolsEvents = (message: MessagePayload) => {
|
|
95
|
+
if (message.type !== 'DISPATCH') {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
switch (message.payload.type) {
|
|
100
|
+
case 'RESET':
|
|
101
|
+
this.setStateValue(this.getInitialState());
|
|
102
|
+
this.devTools?.init(this.getInitialState());
|
|
103
|
+
break;
|
|
104
|
+
|
|
105
|
+
case 'COMMIT':
|
|
106
|
+
this.setStateValue(this.getState());
|
|
107
|
+
this.devTools?.init(this.getState());
|
|
108
|
+
break;
|
|
109
|
+
|
|
110
|
+
case 'JUMP_TO_STATE':
|
|
111
|
+
case 'JUMP_TO_ACTION':
|
|
112
|
+
this.setStateValue(JSON.parse(message.state));
|
|
113
|
+
break;
|
|
114
|
+
|
|
115
|
+
default:
|
|
116
|
+
break;
|
|
117
|
+
}
|
|
118
|
+
};
|
|
119
|
+
}
|
package/src/store/index.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { BaseStateHandler } from './base-state-handler.js';
|
|
2
|
+
export { ObservableStateHandler } from './observable-state-handler.js';
|
|
3
|
+
export { SignalStateHandler } from './signal-state-handler.js';
|
|
2
4
|
export type { StateSingleton } from './state-singleton.js';
|
|
3
5
|
export { makeStateSingleton } from './state-singleton.js';
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { BehaviorSubject, distinctUntilKeyChanged, map, pipe, distinctUntilChanged } from 'rxjs';
|
|
2
|
+
|
|
3
|
+
import { BaseStateHandler } from './base-state-handler.js';
|
|
4
|
+
|
|
5
|
+
import type { Observable } from 'rxjs';
|
|
6
|
+
|
|
7
|
+
type ObservableStateHandlerProps<S> = {
|
|
8
|
+
initialState: S;
|
|
9
|
+
options?: {
|
|
10
|
+
devTools?: {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
namespace: string;
|
|
13
|
+
};
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
type StateObservableOptions = { useDistinctUntilChanged?: boolean };
|
|
18
|
+
|
|
19
|
+
function distinctUntilChangedAsJson<T>() {
|
|
20
|
+
return pipe<Observable<T>, Observable<T>>(
|
|
21
|
+
distinctUntilChanged((a, b) => {
|
|
22
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
23
|
+
})
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const pipeMap = {
|
|
28
|
+
useDistinctUntilChanged: distinctUntilChangedAsJson(),
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export abstract class ObservableStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
32
|
+
private readonly state$: BehaviorSubject<S>;
|
|
33
|
+
|
|
34
|
+
protected constructor({ initialState, options }: ObservableStateHandlerProps<S>) {
|
|
35
|
+
super(initialState);
|
|
36
|
+
this.state$ = new BehaviorSubject<S>(initialState);
|
|
37
|
+
this.initDevTools(options?.devTools);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
protected getStateValue() {
|
|
41
|
+
return this.state$.getValue();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
protected setStateValue(nextState: S) {
|
|
45
|
+
this.state$.next(nextState);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
getStateItemAsObservable(key: keyof S) {
|
|
49
|
+
return this.state$.pipe(
|
|
50
|
+
distinctUntilKeyChanged(key),
|
|
51
|
+
map((state) => state[key])
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
getStateAsObservable(
|
|
56
|
+
options: StateObservableOptions = {
|
|
57
|
+
useDistinctUntilChanged: true,
|
|
58
|
+
}
|
|
59
|
+
) {
|
|
60
|
+
// Unfortunately we cannot add pipe operators conditionally in an easy manner.
|
|
61
|
+
// That's why we use a simple object to attach operators to a new state observable via reduce().
|
|
62
|
+
// This way we can easily extend our default operators map.
|
|
63
|
+
return Object.keys(options)
|
|
64
|
+
.filter((optionKey) => options[optionKey as keyof StateObservableOptions] === true)
|
|
65
|
+
.map((enabledOptions) => pipeMap[enabledOptions as keyof StateObservableOptions])
|
|
66
|
+
.reduce((stateObservable$, operator) => {
|
|
67
|
+
return stateObservable$.pipe(operator) as BehaviorSubject<S>;
|
|
68
|
+
}, this.state$);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
getObservableItem(key: keyof S) {
|
|
72
|
+
return this.getStateItemAsObservable(key);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
subscribe(listener: () => void) {
|
|
76
|
+
let initialized = false;
|
|
77
|
+
const subscription = this.getStateAsObservable().subscribe(() => {
|
|
78
|
+
if (!initialized) {
|
|
79
|
+
initialized = true;
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
listener();
|
|
84
|
+
});
|
|
85
|
+
return () => subscription.unsubscribe();
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { signal } from '@preact/signals-core';
|
|
2
|
+
|
|
3
|
+
import { BaseStateHandler } from './base-state-handler.js';
|
|
4
|
+
|
|
5
|
+
import type { Signal } from '@preact/signals-core';
|
|
6
|
+
|
|
7
|
+
type SignalStateHandlerProps<S> = {
|
|
8
|
+
initialState: S;
|
|
9
|
+
options?: {
|
|
10
|
+
devTools?: {
|
|
11
|
+
enabled?: boolean;
|
|
12
|
+
namespace: string;
|
|
13
|
+
};
|
|
14
|
+
useDistinctUntilChanged?: boolean;
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Listener = () => void;
|
|
19
|
+
|
|
20
|
+
const defaultOptions = {
|
|
21
|
+
useDistinctUntilChanged: true,
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
function isEqualAsJson(a: unknown, b: unknown) {
|
|
25
|
+
return JSON.stringify(a) === JSON.stringify(b);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export abstract class SignalStateHandler<S, A> extends BaseStateHandler<S, A> {
|
|
29
|
+
private readonly state: Signal<S>;
|
|
30
|
+
private readonly listeners = new Map<Listener, S>();
|
|
31
|
+
private readonly useDistinctUntilChanged: boolean;
|
|
32
|
+
|
|
33
|
+
protected constructor({ initialState, options = defaultOptions }: SignalStateHandlerProps<S>) {
|
|
34
|
+
super(initialState);
|
|
35
|
+
const mergedOptions = {
|
|
36
|
+
...defaultOptions,
|
|
37
|
+
...options,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
this.state = signal<S>(initialState);
|
|
41
|
+
this.useDistinctUntilChanged = mergedOptions.useDistinctUntilChanged ?? true;
|
|
42
|
+
this.initDevTools(options?.devTools);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getSignal() {
|
|
46
|
+
return this.state;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
subscribe(listener: Listener) {
|
|
50
|
+
this.listeners.set(listener, this.state.value);
|
|
51
|
+
|
|
52
|
+
return () => {
|
|
53
|
+
this.listeners.delete(listener);
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
protected getStateValue() {
|
|
58
|
+
return this.state.value;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
protected setStateValue(nextState: S) {
|
|
62
|
+
this.state.value = nextState;
|
|
63
|
+
this.notify(nextState);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
private notify(nextState: S) {
|
|
67
|
+
for (const [listener, lastSnapshot] of this.listeners.entries()) {
|
|
68
|
+
if (this.useDistinctUntilChanged && isEqualAsJson(nextState, lastSnapshot)) {
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
this.listeners.set(listener, nextState);
|
|
73
|
+
listener();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
package/src/types/types.ts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type { Observable } from 'rxjs';
|
|
2
|
-
|
|
3
1
|
export interface StateSubscriptionHandler<V, A> {
|
|
4
|
-
|
|
2
|
+
subscribe: (listener: () => void) => () => void;
|
|
3
|
+
getSnapshot: () => V;
|
|
5
4
|
destroy: () => void;
|
|
6
5
|
getInitialState: () => V;
|
|
7
6
|
getActions: () => A;
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"state-handler.spec.js","sourceRoot":"","sources":["../../../src/store/__tests__/state-handler.spec.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
3
|
-
import type { Observable, Subscription } from 'rxjs';
|
|
4
|
-
type Subscriptions = Subscription[];
|
|
5
|
-
type StateHandlerProps<S> = {
|
|
6
|
-
initialState: S;
|
|
7
|
-
options?: {
|
|
8
|
-
devTools: {
|
|
9
|
-
enabled?: boolean;
|
|
10
|
-
namespace: string;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
type StateObservableOptions = {
|
|
15
|
-
useDistinctUntilChanged?: boolean;
|
|
16
|
-
};
|
|
17
|
-
export declare abstract class StateHandler<S, A> implements StateSubscriptionHandler<S, A> {
|
|
18
|
-
private readonly updates$;
|
|
19
|
-
private readonly state$;
|
|
20
|
-
private readonly initialState;
|
|
21
|
-
private devTools;
|
|
22
|
-
subscriptions: Subscriptions;
|
|
23
|
-
protected constructor({ initialState, options }: StateHandlerProps<S>);
|
|
24
|
-
getInitialState(): S;
|
|
25
|
-
getState(): S;
|
|
26
|
-
setState(newState: Partial<S>, actionName?: string): void;
|
|
27
|
-
destroy(): void;
|
|
28
|
-
getStateItemAsObservable(key: keyof S): Observable<S[keyof S]>;
|
|
29
|
-
getStateAsObservable(options?: StateObservableOptions): BehaviorSubject<S>;
|
|
30
|
-
getObservableItem(key: keyof S): Observable<S[keyof S]>;
|
|
31
|
-
private bindUpdatesAndEvents;
|
|
32
|
-
private handleDevToolsEvents;
|
|
33
|
-
getObservable(): Observable<S>;
|
|
34
|
-
abstract getActions(): A;
|
|
35
|
-
}
|
|
36
|
-
export {};
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject, distinctUntilKeyChanged, map, scan, Subject, pipe, distinctUntilChanged } from 'rxjs';
|
|
2
|
-
import { withDevTools } from './dev-tools.js';
|
|
3
|
-
function distinctUntilChangedAsJson() {
|
|
4
|
-
return pipe(distinctUntilChanged((a, b) => {
|
|
5
|
-
return JSON.stringify(a) === JSON.stringify(b);
|
|
6
|
-
}));
|
|
7
|
-
}
|
|
8
|
-
const pipeMap = {
|
|
9
|
-
useDistinctUntilChanged: distinctUntilChangedAsJson(),
|
|
10
|
-
};
|
|
11
|
-
const defaultOptions = { devTools: { enabled: false, namespace: 'Store' } };
|
|
12
|
-
export class StateHandler {
|
|
13
|
-
updates$ = new Subject();
|
|
14
|
-
state$;
|
|
15
|
-
initialState;
|
|
16
|
-
devTools = null;
|
|
17
|
-
subscriptions = [];
|
|
18
|
-
constructor({ initialState, options = defaultOptions }) {
|
|
19
|
-
const mergedOptions = {
|
|
20
|
-
...defaultOptions,
|
|
21
|
-
...options,
|
|
22
|
-
devTools: {
|
|
23
|
-
...defaultOptions.devTools,
|
|
24
|
-
...options?.devTools,
|
|
25
|
-
},
|
|
26
|
-
};
|
|
27
|
-
this.initialState = initialState;
|
|
28
|
-
this.state$ = new BehaviorSubject(initialState);
|
|
29
|
-
this.devTools = mergedOptions.devTools.enabled
|
|
30
|
-
? withDevTools(this.initialState, {
|
|
31
|
-
name: mergedOptions.devTools.namespace,
|
|
32
|
-
instanceId: mergedOptions.devTools.namespace.toLowerCase().replaceAll(' ', '-'),
|
|
33
|
-
actionCreators: this.getActions(),
|
|
34
|
-
features: {
|
|
35
|
-
pause: true, // start/pause recording of dispatched actions
|
|
36
|
-
lock: true, // lock/unlock dispatching actions and side effects
|
|
37
|
-
persist: false, // persist states on page reloading (Using action creators under the hood which are not bound to our state)
|
|
38
|
-
export: true, // export history of actions in a file
|
|
39
|
-
import: 'custom', // import history of actions from a file
|
|
40
|
-
jump: true, // jump back and forth (time travelling)
|
|
41
|
-
skip: true, // skip (cancel) actions
|
|
42
|
-
reorder: true, // drag and drop actions in the history list
|
|
43
|
-
dispatch: false, // dispatch custom actions or action creators (This is only working in redux reducer context)
|
|
44
|
-
test: false, // generate tests for the selected actions (Reducer like tests make no sense)
|
|
45
|
-
},
|
|
46
|
-
})
|
|
47
|
-
: null;
|
|
48
|
-
this.bindUpdatesAndEvents();
|
|
49
|
-
}
|
|
50
|
-
getInitialState() {
|
|
51
|
-
return this.initialState;
|
|
52
|
-
}
|
|
53
|
-
getState() {
|
|
54
|
-
return this.state$.getValue();
|
|
55
|
-
}
|
|
56
|
-
setState(newState, actionName = 'change') {
|
|
57
|
-
this.updates$.next({
|
|
58
|
-
state: newState,
|
|
59
|
-
actionName,
|
|
60
|
-
});
|
|
61
|
-
}
|
|
62
|
-
destroy() {
|
|
63
|
-
this.subscriptions.forEach((subscription) => subscription.unsubscribe());
|
|
64
|
-
}
|
|
65
|
-
getStateItemAsObservable(key) {
|
|
66
|
-
return this.state$.pipe(distinctUntilKeyChanged(key), map((state) => state[key]));
|
|
67
|
-
}
|
|
68
|
-
getStateAsObservable(options = {
|
|
69
|
-
useDistinctUntilChanged: true,
|
|
70
|
-
}) {
|
|
71
|
-
// Unfortunately we cannot add pipe operators conditionally in an easy manner.
|
|
72
|
-
// That's why we use a simple object to attach operators to a new state observable via reduce().
|
|
73
|
-
// This way we can easily extend our default operators map.
|
|
74
|
-
return Object.keys(options)
|
|
75
|
-
.filter((optionKey) => options[optionKey] === true)
|
|
76
|
-
.map((enabledOptions) => pipeMap[enabledOptions])
|
|
77
|
-
.reduce((stateObservable$, operator) => {
|
|
78
|
-
return stateObservable$.pipe(operator);
|
|
79
|
-
}, this.state$);
|
|
80
|
-
}
|
|
81
|
-
getObservableItem(key) {
|
|
82
|
-
return this.getStateItemAsObservable(key);
|
|
83
|
-
}
|
|
84
|
-
bindUpdatesAndEvents() {
|
|
85
|
-
this.updates$
|
|
86
|
-
.pipe(scan((current, updated) => {
|
|
87
|
-
const { state: oldState } = current;
|
|
88
|
-
const { state: newState, actionName } = updated;
|
|
89
|
-
return { actionName, state: { ...oldState, ...newState } };
|
|
90
|
-
}, { actionName: 'init', state: this.initialState } // Initial event object which is changed by this.setState().
|
|
91
|
-
), map(({ actionName, state }) => {
|
|
92
|
-
this.devTools?.send(actionName, state);
|
|
93
|
-
return state;
|
|
94
|
-
}))
|
|
95
|
-
.subscribe(this.state$);
|
|
96
|
-
this.devTools?.subscribe(this.handleDevToolsEvents);
|
|
97
|
-
}
|
|
98
|
-
handleDevToolsEvents = (message) => {
|
|
99
|
-
if (message.type === 'DISPATCH') {
|
|
100
|
-
switch (message.payload.type) {
|
|
101
|
-
case 'RESET':
|
|
102
|
-
this.state$.next(this.getInitialState());
|
|
103
|
-
this.devTools?.init(this.getInitialState());
|
|
104
|
-
break;
|
|
105
|
-
case 'COMMIT':
|
|
106
|
-
this.state$.next(this.getState());
|
|
107
|
-
this.devTools?.init(this.getState());
|
|
108
|
-
break;
|
|
109
|
-
case 'JUMP_TO_STATE':
|
|
110
|
-
case 'JUMP_TO_ACTION':
|
|
111
|
-
this.state$.next(JSON.parse(message.state));
|
|
112
|
-
break;
|
|
113
|
-
default:
|
|
114
|
-
break;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
};
|
|
118
|
-
getObservable() {
|
|
119
|
-
return this.getStateAsObservable();
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
//# sourceMappingURL=state-handler.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"state-handler.js","sourceRoot":"","sources":["../../src/store/state-handler.ts"],"names":[],"mappings":"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"}
|
package/dist/types/index.d.ts
DELETED
|
@@ -1,6 +0,0 @@
|
|
|
1
|
-
import { useStateFactory, useStateSingleton } from './hooks/index.js';
|
|
2
|
-
import { makeStateSingleton, StateHandler } from './store/index.js';
|
|
3
|
-
import type { StateSingleton } from './store/index.js';
|
|
4
|
-
import type { StateSubscriptionHandler } from './types/types.js';
|
|
5
|
-
export { makeStateSingleton, StateHandler, useStateFactory, useStateSingleton };
|
|
6
|
-
export type { StateSingleton, StateSubscriptionHandler };
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
declare global {
|
|
2
|
-
interface Window {
|
|
3
|
-
__REDUX_DEVTOOLS_EXTENSION__?: {
|
|
4
|
-
connect: (opts: Record<string, unknown>) => DevTools;
|
|
5
|
-
};
|
|
6
|
-
}
|
|
7
|
-
}
|
|
8
|
-
export type MessagePayload = {
|
|
9
|
-
type: string;
|
|
10
|
-
payload: {
|
|
11
|
-
type: string;
|
|
12
|
-
actionId: number;
|
|
13
|
-
};
|
|
14
|
-
state: string;
|
|
15
|
-
id: string;
|
|
16
|
-
source: '@devtools-extension';
|
|
17
|
-
};
|
|
18
|
-
export type DevTools = {
|
|
19
|
-
init: (state: unknown) => void;
|
|
20
|
-
send: (action: string, state: unknown) => void;
|
|
21
|
-
subscribe: (cb: (message: MessagePayload) => void) => void;
|
|
22
|
-
};
|
|
23
|
-
export declare function withDevTools<S>(initialState: S, options?: {}): DevTools | null;
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { BehaviorSubject } from 'rxjs';
|
|
2
|
-
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
3
|
-
import type { Observable, Subscription } from 'rxjs';
|
|
4
|
-
type Subscriptions = Subscription[];
|
|
5
|
-
type StateHandlerProps<S> = {
|
|
6
|
-
initialState: S;
|
|
7
|
-
options?: {
|
|
8
|
-
devTools: {
|
|
9
|
-
enabled?: boolean;
|
|
10
|
-
namespace: string;
|
|
11
|
-
};
|
|
12
|
-
};
|
|
13
|
-
};
|
|
14
|
-
type StateObservableOptions = {
|
|
15
|
-
useDistinctUntilChanged?: boolean;
|
|
16
|
-
};
|
|
17
|
-
export declare abstract class StateHandler<S, A> implements StateSubscriptionHandler<S, A> {
|
|
18
|
-
private readonly updates$;
|
|
19
|
-
private readonly state$;
|
|
20
|
-
private readonly initialState;
|
|
21
|
-
private devTools;
|
|
22
|
-
subscriptions: Subscriptions;
|
|
23
|
-
protected constructor({ initialState, options }: StateHandlerProps<S>);
|
|
24
|
-
getInitialState(): S;
|
|
25
|
-
getState(): S;
|
|
26
|
-
setState(newState: Partial<S>, actionName?: string): void;
|
|
27
|
-
destroy(): void;
|
|
28
|
-
getStateItemAsObservable(key: keyof S): Observable<S[keyof S]>;
|
|
29
|
-
getStateAsObservable(options?: StateObservableOptions): BehaviorSubject<S>;
|
|
30
|
-
getObservableItem(key: keyof S): Observable<S[keyof S]>;
|
|
31
|
-
private bindUpdatesAndEvents;
|
|
32
|
-
private handleDevToolsEvents;
|
|
33
|
-
getObservable(): Observable<S>;
|
|
34
|
-
abstract getActions(): A;
|
|
35
|
-
}
|
|
36
|
-
export {};
|
|
@@ -1,5 +0,0 @@
|
|
|
1
|
-
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
2
|
-
export interface StateSingleton<V, A> {
|
|
3
|
-
getInstance: () => StateSubscriptionHandler<V, A>;
|
|
4
|
-
}
|
|
5
|
-
export declare function makeStateSingleton<S, A>(stateHandlerFactory: () => StateSubscriptionHandler<S, A>): StateSingleton<S, A>;
|