@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.
Files changed (65) hide show
  1. package/.github/workflows/pages.yml +46 -0
  2. package/.github/workflows/release.yml +33 -0
  3. package/CHANGELOG.md +30 -0
  4. package/README.md +260 -124
  5. package/assets/statusquo-logo.png +0 -0
  6. package/dist/hooks/state-subscription.d.ts +1 -2
  7. package/dist/hooks/state-subscription.js +8 -9
  8. package/dist/hooks/state-subscription.js.map +1 -1
  9. package/dist/index.d.ts +2 -2
  10. package/dist/index.js +2 -2
  11. package/dist/index.js.map +1 -1
  12. package/dist/store/__tests__/{state-handler.spec.js → observable-state-handler.spec.js} +14 -14
  13. package/dist/store/__tests__/observable-state-handler.spec.js.map +1 -0
  14. package/dist/store/__tests__/signal-state-handler.spec.js +78 -0
  15. package/dist/store/__tests__/signal-state-handler.spec.js.map +1 -0
  16. package/dist/store/base-state-handler.d.ts +30 -0
  17. package/dist/store/base-state-handler.js +84 -0
  18. package/dist/store/base-state-handler.js.map +1 -0
  19. package/dist/store/index.d.ts +3 -1
  20. package/dist/store/index.js +3 -1
  21. package/dist/store/index.js.map +1 -1
  22. package/dist/store/observable-state-handler.d.ts +26 -0
  23. package/dist/store/observable-state-handler.js +55 -0
  24. package/dist/store/observable-state-handler.js.map +1 -0
  25. package/dist/store/signal-state-handler.d.ts +25 -0
  26. package/dist/store/signal-state-handler.js +49 -0
  27. package/dist/store/signal-state-handler.js.map +1 -0
  28. package/dist/types/types.d.ts +2 -2
  29. package/package.json +22 -11
  30. package/playground/index.html +12 -0
  31. package/playground/src/App.tsx +478 -0
  32. package/playground/src/assets/philosophy-agnostic.svg +18 -0
  33. package/playground/src/assets/philosophy-separation.svg +13 -0
  34. package/playground/src/assets/philosophy-swap.svg +17 -0
  35. package/playground/src/assets/statusquo-logo.png +0 -0
  36. package/playground/src/main.tsx +19 -0
  37. package/playground/src/styles.css +411 -0
  38. package/playground/tsconfig.json +12 -0
  39. package/playground/vite.config.ts +18 -0
  40. package/src/hooks/state-subscription.tsx +21 -14
  41. package/src/index.ts +14 -2
  42. package/src/store/__tests__/{state-handler.spec.ts → observable-state-handler.spec.ts} +15 -15
  43. package/src/store/__tests__/signal-state-handler.spec.ts +97 -0
  44. package/src/store/base-state-handler.ts +119 -0
  45. package/src/store/index.ts +3 -1
  46. package/src/store/observable-state-handler.ts +87 -0
  47. package/src/store/signal-state-handler.ts +76 -0
  48. package/src/types/types.ts +2 -3
  49. package/dist/store/__tests__/state-handler.spec.js.map +0 -1
  50. package/dist/store/state-handler.d.ts +0 -36
  51. package/dist/store/state-handler.js +0 -122
  52. package/dist/store/state-handler.js.map +0 -1
  53. package/dist/types/hooks/index.d.ts +0 -2
  54. package/dist/types/hooks/state-factory.d.ts +0 -2
  55. package/dist/types/hooks/state-singleton.d.ts +0 -2
  56. package/dist/types/hooks/state-subscription.d.ts +0 -3
  57. package/dist/types/index.d.ts +0 -6
  58. package/dist/types/store/dev-tools.d.ts +0 -23
  59. package/dist/types/store/index.d.ts +0 -3
  60. package/dist/types/store/state-handler.d.ts +0 -36
  61. package/dist/types/store/state-singleton.d.ts +0 -5
  62. package/dist/types/types/types.d.ts +0 -7
  63. package/src/store/state-handler.ts +0 -181
  64. /package/dist/store/__tests__/{state-handler.spec.d.ts → observable-state-handler.spec.d.ts} +0 -0
  65. /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
+ }
@@ -1,3 +1,5 @@
1
- export { StateHandler } from './state-handler.js';
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
+ }
@@ -1,7 +1,6 @@
1
- import type { Observable } from 'rxjs';
2
-
3
1
  export interface StateSubscriptionHandler<V, A> {
4
- getObservable: () => Observable<V>;
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":"AAAA,OAAO,EAAE,eAAe,EAAE,uBAAuB,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,oBAAoB,EAAE,MAAM,MAAM,CAAC;AAEhH,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAkB9C,SAAS,0BAA0B;IACjC,OAAO,IAAI,CACP,oBAAoB,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE;QAC5B,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;IACjD,CAAC,CAAC,CACL,CAAC;AACJ,CAAC;AAGD,MAAM,OAAO,GAAG;IACd,uBAAuB,EAAE,0BAA0B,EAAE;CACtD,CAAC;AAEF,MAAM,cAAc,GAAG,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,EAAE,CAAC;AAE5E,MAAM,OAAgB,YAAY;IACf,QAAQ,GAGpB,IAAI,OAAO,EAAE,CAAC;IAEF,MAAM,CAAqB;IAC3B,YAAY,CAAI;IAEzB,QAAQ,GAAoB,IAAI,CAAC;IAEzC,aAAa,GAAkB,EAAE,CAAC;IAElC,YAAsB,EAAE,YAAY,EAAE,OAAO,GAAG,cAAc,EAAwB;QACpF,MAAM,aAAa,GAAG;YACpB,GAAG,cAAc;YACjB,GAAG,OAAO;YACV,QAAQ,EAAE;gBACR,GAAG,cAAc,CAAC,QAAQ;gBAC1B,GAAG,OAAO,EAAE,QAAQ;aACrB;SACF,CAAC;QACF,IAAI,CAAC,YAAY,GAAG,YAAY,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,IAAI,eAAe,CAAI,YAAY,CAAC,CAAC;QACnD,IAAI,CAAC,QAAQ,GAAG,aAAa,CAAC,QAAQ,CAAC,OAAO;YAC5C,CAAC,CAAC,YAAY,CAAC,IAAI,CAAC,YAAY,EAAE;gBAC9B,IAAI,EAAE,aAAa,CAAC,QAAQ,CAAC,SAAS;gBACtC,UAAU,EAAE,aAAa,CAAC,QAAQ,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC;gBAC/E,cAAc,EAAE,IAAI,CAAC,UAAU,EAAE;gBACjC,QAAQ,EAAE;oBACR,KAAK,EAAE,IAAI,EAAE,8CAA8C;oBAC3D,IAAI,EAAE,IAAI,EAAE,mDAAmD;oBAC/D,OAAO,EAAE,KAAK,EAAE,2GAA2G;oBAC3H,MAAM,EAAE,IAAI,EAAE,sCAAsC;oBACpD,MAAM,EAAE,QAAQ,EAAE,wCAAwC;oBAC1D,IAAI,EAAE,IAAI,EAAE,wCAAwC;oBACpD,IAAI,EAAE,IAAI,EAAE,wBAAwB;oBACpC,OAAO,EAAE,IAAI,EAAE,4CAA4C;oBAC3D,QAAQ,EAAE,KAAK,EAAE,6FAA6F;oBAC9G,IAAI,EAAE,KAAK,EAAE,6EAA6E;iBAC3F;aACF,CAAC;YACJ,CAAC,CAAC,IAAI,CAAC;QAET,IAAI,CAAC,oBAAoB,EAAE,CAAC;IAC9B,CAAC;IAED,eAAe;QACb,OAAO,IAAI,CAAC,YAAY,CAAC;IAC3B,CAAC;IAED,QAAQ;QACN,OAAO,IAAI,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC;IAChC,CAAC;IAED,QAAQ,CAAC,QAAoB,EAAE,UAAU,GAAG,QAAQ;QAClD,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;YACjB,KAAK,EAAE,QAAQ;YACf,UAAU;SACX,CAAC,CAAC;IACL,CAAC;IAED,OAAO;QACL,IAAI,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,CAAC,WAAW,EAAE,CAAC,CAAC;IAC3E,CAAC;IAED,wBAAwB,CAAC,GAAY;QACnC,OAAO,IAAI,CAAC,MAAM,CAAC,IAAI,CACrB,uBAAuB,CAAC,GAAG,CAAC,EAC5B,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAC3B,CAAC;IACJ,CAAC;IAED,oBAAoB,CAClB,UAAkC;QAChC,uBAAuB,EAAE,IAAI;KAC9B;QAED,8EAA8E;QAC9E,gGAAgG;QAChG,2DAA2D;QAC3D,OAAO,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC;aACxB,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,SAAyC,CAAC,KAAK,IAAI,CAAC;aAClF,GAAG,CAAC,CAAC,cAAc,EAAE,EAAE,CAAC,OAAO,CAAC,cAA8C,CAAC,CAAC;aAChF,MAAM,CAAC,CAAC,gBAAgB,EAAE,QAAQ,EAAE,EAAE;YACrC,OAAO,gBAAgB,CAAC,IAAI,CAAC,QAAQ,CAAuB,CAAC;QAC/D,CAAC,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;IACpB,CAAC;IAED,iBAAiB,CAAC,GAAY;QAC5B,OAAO,IAAI,CAAC,wBAAwB,CAAC,GAAG,CAAC,CAAC;IAC5C,CAAC;IAEO,oBAAoB;QAC1B,IAAI,CAAC,QAAQ;aACV,IAAI,CACH,IAAI,CACF,CAAC,OAAO,EAAE,OAAO,EAAE,EAAE;YACnB,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,GAAG,OAAO,CAAC;YACpC,MAAM,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;YAEhD,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,GAAG,QAAQ,EAAE,GAAG,QAAQ,EAAE,EAAE,CAAC;QAC7D,CAAC,EACD,EAAE,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,4DAA4D;SAC9G,EACD,GAAG,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,EAAE,EAAE;YAC5B,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,UAAU,EAAE,KAAK,CAAC,CAAC;YAEvC,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CACH;aACA,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1B,IAAI,CAAC,QAAQ,EAAE,SAAS,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACtD,CAAC;IAEO,oBAAoB,GAAG,CAAC,OAAuB,EAAE,EAAE;QACzD,IAAI,OAAO,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;YAChC,QAAQ,OAAO,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;gBAC7B,KAAK,OAAO;oBACV,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;oBACzC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;oBAC5C,MAAM;gBAER,KAAK,QAAQ;oBACX,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;oBAClC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC;oBACrC,MAAM;gBAER,KAAK,eAAe,CAAC;gBACrB,KAAK,gBAAgB;oBACnB,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC;oBAC5C,MAAM;gBAER;oBACE,MAAM;YACV,CAAC;QACH,CAAC;IACH,CAAC,CAAC;IAEF,aAAa;QACX,OAAO,IAAI,CAAC,oBAAoB,EAAE,CAAC;IACrC,CAAC;CAGF"}
@@ -1,2 +0,0 @@
1
- export { useStateFactory } from './state-factory.js';
2
- export { useStateSingleton } from './state-singleton.js';
@@ -1,2 +0,0 @@
1
- import type { StateSubscriptionHandler } from '../types/types.js';
2
- export declare function useStateFactory<V, A, P extends unknown[]>(stateFactoryFunction: (...args: P) => StateSubscriptionHandler<V, A>, params?: P): [V, A];
@@ -1,2 +0,0 @@
1
- import type { StateSingleton } from '../store/state-singleton.js';
2
- export declare function useStateSingleton<V, A>(stateSingleton: StateSingleton<V, A>): [V, A];
@@ -1,3 +0,0 @@
1
- import type { StateSubscriptionHandler } from '../types/types.js';
2
- import type { SetStateAction } from 'react';
3
- export declare function useStateSubscription<V, A>(stateSubscriptionHandler: StateSubscriptionHandler<V, A>): SetStateAction<V>;
@@ -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,3 +0,0 @@
1
- export { StateHandler } from './state-handler.js';
2
- export type { StateSingleton } from './state-singleton.js';
3
- export { makeStateSingleton } from './state-singleton.js';
@@ -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>;
@@ -1,7 +0,0 @@
1
- import type { Observable } from 'rxjs';
2
- export interface StateSubscriptionHandler<V, A> {
3
- getObservable: () => Observable<V>;
4
- destroy: () => void;
5
- getInitialState: () => V;
6
- getActions: () => A;
7
- }