@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,46 @@
|
|
|
1
|
+
name: Deploy Docs
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [master]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: read
|
|
10
|
+
pages: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
concurrency:
|
|
14
|
+
group: pages
|
|
15
|
+
cancel-in-progress: true
|
|
16
|
+
|
|
17
|
+
jobs:
|
|
18
|
+
build:
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
steps:
|
|
21
|
+
- name: Checkout
|
|
22
|
+
uses: actions/checkout@v4
|
|
23
|
+
- name: Setup Node
|
|
24
|
+
uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: 20
|
|
27
|
+
cache: npm
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: npm ci
|
|
30
|
+
- name: Build docs
|
|
31
|
+
run: npm run docs:build
|
|
32
|
+
- name: Upload artifact
|
|
33
|
+
uses: actions/upload-pages-artifact@v3
|
|
34
|
+
with:
|
|
35
|
+
path: ./docs
|
|
36
|
+
|
|
37
|
+
deploy:
|
|
38
|
+
runs-on: ubuntu-latest
|
|
39
|
+
needs: build
|
|
40
|
+
environment:
|
|
41
|
+
name: github-pages
|
|
42
|
+
url: ${{ steps.deployment.outputs.page_url }}
|
|
43
|
+
steps:
|
|
44
|
+
- name: Deploy
|
|
45
|
+
id: deployment
|
|
46
|
+
uses: actions/deploy-pages@v4
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
|
|
8
|
+
permissions:
|
|
9
|
+
contents: write
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
release:
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
steps:
|
|
15
|
+
- name: Checkout
|
|
16
|
+
uses: actions/checkout@v4
|
|
17
|
+
- name: Setup Node
|
|
18
|
+
uses: actions/setup-node@v4
|
|
19
|
+
with:
|
|
20
|
+
node-version: 20
|
|
21
|
+
cache: npm
|
|
22
|
+
- name: Install dependencies
|
|
23
|
+
run: npm ci
|
|
24
|
+
- name: Build dist
|
|
25
|
+
run: npm run build
|
|
26
|
+
- name: Package dist
|
|
27
|
+
run: |
|
|
28
|
+
zip -r "dist-${{ github.ref_name }}.zip" dist
|
|
29
|
+
- name: Create GitHub release
|
|
30
|
+
uses: softprops/action-gh-release@v2
|
|
31
|
+
with:
|
|
32
|
+
files: dist-${{ github.ref_name }}.zip
|
|
33
|
+
generate_release_notes: true
|
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
|
|
6
|
+
|
|
7
|
+
## [1.0.0] - 2026-02-17
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- `SignalStateHandler` (signals-backed state handler).
|
|
11
|
+
- `BaseStateHandler` to share devtools and lifecycle APIs.
|
|
12
|
+
- `bindSubscribable` helper for managing external subscriptions.
|
|
13
|
+
- Playground/demo with GitHub Pages deployment.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
- `StateHandler` renamed to `ObservableStateHandler`.
|
|
17
|
+
- `StateSubscriptionHandler` now uses `subscribe/getSnapshot` (no `getObservable`).
|
|
18
|
+
- Devtools options moved under `options.devTools`.
|
|
19
|
+
|
|
20
|
+
### Migration
|
|
21
|
+
- Update imports:
|
|
22
|
+
- From: `StateHandler`
|
|
23
|
+
- To: `ObservableStateHandler`
|
|
24
|
+
- Implement `subscribe()` and `getSnapshot()` on custom handlers.
|
|
25
|
+
- Replace `getObservable()` usage with `subscribe()` in custom integrations.
|
|
26
|
+
- Update devtools config:
|
|
27
|
+
- From: `super({ initialState, devTools: { ... } })`
|
|
28
|
+
- To: `super({ initialState, options: { devTools: { ... } } })`
|
|
29
|
+
|
|
30
|
+
[1.0.0]: https://github.com/Veams/status-quo/releases/tag/v1.0.0
|
package/README.md
CHANGED
|
@@ -1,176 +1,312 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @veams/status-quo
|
|
2
|
+
[](https://www.npmjs.com/package/@veams/status-quo)
|
|
2
3
|
|
|
3
|
-
|
|
4
|
+
<center>
|
|
5
|
+
<img src="assets/statusquo-logo.png" width="200" alt="StatusQuo Logo" style="margin: 0 auto;">
|
|
6
|
+
</center>
|
|
4
7
|
|
|
5
|
-
|
|
8
|
+
The manager to rule your state.
|
|
6
9
|
|
|
7
|
-
|
|
10
|
+
This page mirrors the demo content and adds a full API reference.
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
2. [Example](#example)
|
|
12
|
+
## Table of Contents
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
1. [Overview](#overview)
|
|
15
|
+
2. [Philosophy](#philosophy)
|
|
16
|
+
3. [Demo](#demo)
|
|
17
|
+
4. [Quickstart](#quickstart)
|
|
18
|
+
5. [Handlers](#handlers)
|
|
19
|
+
6. [Hooks](#hooks)
|
|
20
|
+
7. [Singletons](#singletons)
|
|
21
|
+
8. [Composition](#composition)
|
|
22
|
+
9. [Devtools](#devtools)
|
|
23
|
+
10. [Cleanup](#cleanup)
|
|
24
|
+
11. [API Reference](#api-reference)
|
|
25
|
+
12. [Migration](#migration)
|
|
13
26
|
|
|
14
|
-
##
|
|
27
|
+
## Overview
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
1. Use actions and state in your component
|
|
18
|
-
1. When using React, initialize the state handler with a custom hook called `useStateFactory()` (or `useStateSingleton()` for Singleton states)
|
|
29
|
+
StatusQuo is a small, framework-agnostic state layer that focuses on explicit lifecycle, clear action APIs, and a minimal subscription surface. It ships two handler implementations with the same public interface: RxJS-backed observables and signals-backed stores.
|
|
19
30
|
|
|
31
|
+
## Philosophy
|
|
20
32
|
|
|
21
|
-
|
|
33
|
+
- Swap the engine, keep the API. Your UI code stays the same when you switch from RxJS to Signals.
|
|
34
|
+
- Separate view and state. Handlers own transitions and expose actions; views subscribe to snapshots.
|
|
35
|
+
- Framework-agnostic core. Business logic lives outside the UI library; hooks provide the glue.
|
|
22
36
|
|
|
23
|
-
|
|
24
|
-
_Please keep in mind that dependencies for the hook needs to be flattened and cannot be used as an object due to how React works._
|
|
37
|
+
## Demo
|
|
25
38
|
|
|
26
|
-
|
|
39
|
+
Live docs and demo:
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
41
|
+
[https://veams.github.io/status-quo/](https://veams.github.io/status-quo/)
|
|
42
|
+
|
|
43
|
+
## Quickstart
|
|
44
|
+
|
|
45
|
+
Install:
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm install @veams/status-quo rxjs @preact/signals-core
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Create a store and use it in a component:
|
|
30
52
|
|
|
31
53
|
```ts
|
|
32
|
-
import {
|
|
54
|
+
import { ObservableStateHandler, useStateFactory } from '@veams/status-quo';
|
|
55
|
+
|
|
56
|
+
type CounterState = { count: number };
|
|
33
57
|
|
|
34
|
-
type CounterState = {
|
|
35
|
-
count: number;
|
|
36
|
-
};
|
|
37
58
|
type CounterActions = {
|
|
38
59
|
increase: () => void;
|
|
39
60
|
decrease: () => void;
|
|
40
61
|
};
|
|
41
62
|
|
|
42
|
-
class
|
|
43
|
-
constructor(
|
|
44
|
-
super({ initialState: { count:
|
|
63
|
+
class CounterStore extends ObservableStateHandler<CounterState, CounterActions> {
|
|
64
|
+
constructor() {
|
|
65
|
+
super({ initialState: { count: 0 } });
|
|
45
66
|
}
|
|
46
|
-
|
|
47
|
-
getActions() {
|
|
67
|
+
|
|
68
|
+
getActions(): CounterActions {
|
|
48
69
|
return {
|
|
49
|
-
increase() {
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
})
|
|
53
|
-
},
|
|
54
|
-
decrease() {
|
|
55
|
-
const currentState = this.getState();
|
|
56
|
-
|
|
57
|
-
if (currentState.count > 0) {
|
|
58
|
-
this.setState({
|
|
59
|
-
count: currentState - 1
|
|
60
|
-
})
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
}
|
|
70
|
+
increase: () => this.setState({ count: this.getState().count + 1 }),
|
|
71
|
+
decrease: () => this.setState({ count: this.getState().count - 1 }),
|
|
72
|
+
};
|
|
64
73
|
}
|
|
65
74
|
}
|
|
66
75
|
|
|
67
|
-
|
|
68
|
-
return new CounterStateHandler(...args);
|
|
69
|
-
}
|
|
76
|
+
const [state, actions] = useStateFactory(() => new CounterStore(), []);
|
|
70
77
|
```
|
|
71
78
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return (
|
|
82
|
-
<div>
|
|
83
|
-
<h2>Counter: {state}</h2>
|
|
84
|
-
<button onClick={actions.increase}>Increase</button>
|
|
85
|
-
<button onClick={actions.decrease}>Decrease</button>
|
|
86
|
-
</div>
|
|
87
|
-
)
|
|
88
|
-
}
|
|
89
|
-
```
|
|
79
|
+
## Handlers
|
|
80
|
+
|
|
81
|
+
StatusQuo provides two handler implementations with the same public interface:
|
|
82
|
+
|
|
83
|
+
- `ObservableStateHandler` (RxJS-backed)
|
|
84
|
+
- `SignalStateHandler` (Signals-backed)
|
|
85
|
+
|
|
86
|
+
Both are built on `BaseStateHandler`, which provides the shared lifecycle and devtools support.
|
|
90
87
|
|
|
91
|
-
|
|
88
|
+
## Hooks
|
|
92
89
|
|
|
93
|
-
|
|
90
|
+
- `useStateFactory(factory, deps)`
|
|
91
|
+
- Creates a handler instance per component and subscribes to its snapshot.
|
|
92
|
+
- Suitable for per-component or per-instance state.
|
|
93
|
+
- `useStateSingleton(singleton)`
|
|
94
|
+
- Uses a shared singleton handler across components.
|
|
95
|
+
|
|
96
|
+
## Singletons
|
|
94
97
|
|
|
95
98
|
```ts
|
|
96
|
-
import { makeStateSingleton } from '@veams/status-quo';
|
|
99
|
+
import { makeStateSingleton, useStateSingleton } from '@veams/status-quo';
|
|
97
100
|
|
|
98
|
-
|
|
101
|
+
const CounterSingleton = makeStateSingleton(() => new CounterStore());
|
|
99
102
|
|
|
100
|
-
|
|
103
|
+
const [state, actions] = useStateSingleton(CounterSingleton);
|
|
101
104
|
```
|
|
102
105
|
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
)
|
|
106
|
+
## Composition
|
|
107
|
+
|
|
108
|
+
Use only the slice you need. RxJS makes multi-source composition powerful and declarative with operators like `combineLatest`, `switchMap`, or `debounceTime`. Signals can derive values with `computed` and wire them into a parent store via `bindSubscribable`.
|
|
109
|
+
|
|
110
|
+
```ts
|
|
111
|
+
import { combineLatest } from 'rxjs';
|
|
112
|
+
|
|
113
|
+
// RxJS: combine handler streams (RxJS shines here)
|
|
114
|
+
class AppSignalStore extends SignalStateHandler<AppState, AppActions> {
|
|
115
|
+
private counter$ = CounterObservableStore.getInstance().getStateAsObservable();
|
|
116
|
+
private card$ = new CardObservableHandler();
|
|
117
|
+
|
|
118
|
+
constructor() {
|
|
119
|
+
super({ initialState: { counter: 0, cardTitle: '' }});
|
|
120
|
+
|
|
121
|
+
this.subscriptions.push(
|
|
122
|
+
combineLatest([
|
|
123
|
+
this.counter$,
|
|
124
|
+
this.card$,
|
|
125
|
+
]).subscribe(([counterState, cardState]) => {
|
|
126
|
+
this.setState({
|
|
127
|
+
counter: counterState,
|
|
128
|
+
cardTitle: cardState.title,
|
|
129
|
+
}, 'sync-combined');
|
|
130
|
+
})
|
|
131
|
+
)
|
|
132
|
+
}
|
|
133
|
+
|
|
116
134
|
}
|
|
117
135
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
136
|
+
// Signals: combine derived values via computed + bindSubscribable
|
|
137
|
+
import { computed } from '@preact/signals-core';
|
|
138
|
+
|
|
139
|
+
class AppSignalStore extends SignalStateHandler<AppState, AppActions> {
|
|
140
|
+
private counter = CounterSignalHandler.getInstance();
|
|
141
|
+
private card = new CardSignalHandler();
|
|
142
|
+
private combined$ = computed(() => ({
|
|
143
|
+
counter: this.counter.getSignal().value,
|
|
144
|
+
cardTitle: this.card.getSignal().value.title,
|
|
145
|
+
}));
|
|
146
|
+
|
|
147
|
+
constructor() {
|
|
148
|
+
super({ initialState: { counter: 0, cardTitle: '' }});
|
|
149
|
+
|
|
150
|
+
this.bindSubscribable(
|
|
151
|
+
{ subscribe: this.combined.subscribe.bind(this.combined), getSnapshot: () => this.combined.value },
|
|
152
|
+
(nextState) => this.setState(nextState, 'sync-combined')
|
|
153
|
+
);
|
|
154
|
+
}
|
|
126
155
|
}
|
|
127
156
|
```
|
|
128
157
|
|
|
129
|
-
|
|
158
|
+
## Devtools
|
|
130
159
|
|
|
131
|
-
|
|
132
|
-
You can enable the devtools in an easy way:
|
|
160
|
+
Enable Redux Devtools integration with `options.devTools`:
|
|
133
161
|
|
|
134
162
|
```ts
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
constructor([startCount = 0]) {
|
|
163
|
+
class CounterStore extends ObservableStateHandler<CounterState, CounterActions> {
|
|
164
|
+
constructor() {
|
|
138
165
|
super({
|
|
139
|
-
initialState: { count:
|
|
140
|
-
devTools: { enabled: true, namespace: 'Counter' },
|
|
166
|
+
initialState: { count: 0 },
|
|
167
|
+
options: { devTools: { enabled: true, namespace: 'Counter' } },
|
|
141
168
|
});
|
|
142
169
|
}
|
|
170
|
+
}
|
|
171
|
+
```
|
|
143
172
|
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
173
|
+
## Cleanup
|
|
174
|
+
|
|
175
|
+
Handlers expose `subscribe`, `getSnapshot`, and `destroy` for custom integrations:
|
|
176
|
+
|
|
177
|
+
```ts
|
|
178
|
+
const unsubscribe = store.subscribe(() => {
|
|
179
|
+
console.log(store.getSnapshot());
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
unsubscribe();
|
|
183
|
+
store.destroy();
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
## API Reference
|
|
187
|
+
|
|
188
|
+
### `StateSubscriptionHandler<V, A>`
|
|
189
|
+
|
|
190
|
+
Required interface implemented by all handlers.
|
|
191
|
+
|
|
192
|
+
```ts
|
|
193
|
+
interface StateSubscriptionHandler<V, A> {
|
|
194
|
+
subscribe: (listener: () => void) => () => void;
|
|
195
|
+
getSnapshot: () => V;
|
|
196
|
+
destroy: () => void;
|
|
197
|
+
getInitialState: () => V;
|
|
198
|
+
getActions: () => A;
|
|
168
199
|
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### `BaseStateHandler<S, A>`
|
|
203
|
+
|
|
204
|
+
Shared base class for all handlers.
|
|
205
|
+
|
|
206
|
+
Constructor:
|
|
207
|
+
|
|
208
|
+
```ts
|
|
209
|
+
protected constructor(initialState: S)
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
Public methods:
|
|
213
|
+
|
|
214
|
+
- `getInitialState(): S`
|
|
215
|
+
- `getState(): S`
|
|
216
|
+
- `getSnapshot(): S`
|
|
217
|
+
- `setState(next: Partial<S>, actionName = 'change'): void`
|
|
218
|
+
- `subscribe(listener: () => void): () => void` (abstract)
|
|
219
|
+
- `destroy(): void`
|
|
220
|
+
- `getActions(): A` (abstract)
|
|
221
|
+
|
|
222
|
+
Protected helpers:
|
|
223
|
+
|
|
224
|
+
- `getStateValue(): S` (abstract)
|
|
225
|
+
- `setStateValue(next: S): void` (abstract)
|
|
226
|
+
- `initDevTools(options?: { enabled?: boolean; namespace: string }): void`
|
|
227
|
+
- `bindSubscribable<T>(service: { subscribe: (listener: (value: T) => void) => () => void; getSnapshot?: () => T }, onChange: (value: T) => void): void`
|
|
228
|
+
- Registers the subscription on `this.subscriptions` and invokes `onChange` with the current snapshot when available.
|
|
229
|
+
|
|
230
|
+
### `ObservableStateHandler<S, A>`
|
|
231
|
+
|
|
232
|
+
RxJS-backed handler. Extends `BaseStateHandler`.
|
|
233
|
+
|
|
234
|
+
Constructor:
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
protected constructor({
|
|
238
|
+
initialState,
|
|
239
|
+
options
|
|
240
|
+
}: {
|
|
241
|
+
initialState: S;
|
|
242
|
+
options?: {
|
|
243
|
+
devTools?: { enabled?: boolean; namespace: string };
|
|
244
|
+
};
|
|
245
|
+
})
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
Public methods:
|
|
249
|
+
|
|
250
|
+
- `getStateAsObservable(options?: { useDistinctUntilChanged?: boolean }): Observable<S>`
|
|
251
|
+
- `getStateItemAsObservable(key: keyof S): Observable<S[keyof S]>`
|
|
252
|
+
- `getObservableItem(key: keyof S): Observable<S[keyof S]>`
|
|
253
|
+
- `subscribe(listener: () => void): () => void`
|
|
254
|
+
|
|
255
|
+
Notes:
|
|
256
|
+
- The observable stream uses `distinctUntilChanged` by default (JSON compare).
|
|
257
|
+
- `subscribe` does not fire for the initial value; it only fires on subsequent changes.
|
|
258
|
+
|
|
259
|
+
### `SignalStateHandler<S, A>`
|
|
260
|
+
|
|
261
|
+
Signals-backed handler. Extends `BaseStateHandler`.
|
|
262
|
+
|
|
263
|
+
Constructor:
|
|
264
|
+
|
|
265
|
+
```ts
|
|
266
|
+
protected constructor({
|
|
267
|
+
initialState,
|
|
268
|
+
options
|
|
269
|
+
}: {
|
|
270
|
+
initialState: S;
|
|
271
|
+
options?: {
|
|
272
|
+
devTools?: { enabled?: boolean; namespace: string };
|
|
273
|
+
useDistinctUntilChanged?: boolean;
|
|
274
|
+
};
|
|
275
|
+
})
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
Public methods:
|
|
279
|
+
|
|
280
|
+
- `getSignal(): Signal<S>`
|
|
281
|
+
- `subscribe(listener: () => void): () => void`
|
|
282
|
+
|
|
283
|
+
Notes:
|
|
284
|
+
- `useDistinctUntilChanged` defaults to `true` (JSON compare).
|
|
285
|
+
|
|
286
|
+
### `makeStateSingleton`
|
|
169
287
|
|
|
170
|
-
|
|
171
|
-
|
|
288
|
+
```ts
|
|
289
|
+
function makeStateSingleton<S, A>(
|
|
290
|
+
factory: () => StateSubscriptionHandler<S, A>
|
|
291
|
+
): {
|
|
292
|
+
getInstance: () => StateSubscriptionHandler<S, A>;
|
|
172
293
|
}
|
|
173
294
|
```
|
|
174
295
|
|
|
175
|
-
|
|
176
|
-
|
|
296
|
+
### Hooks
|
|
297
|
+
|
|
298
|
+
- `useStateFactory<V, A, P extends unknown[]>(factory: (...args: P) => StateSubscriptionHandler<V, A>, params?: P)`
|
|
299
|
+
- Returns `[state, actions]`.
|
|
300
|
+
- `useStateSingleton<V, A>(singleton: StateSingleton<V, A>)`
|
|
301
|
+
- Returns `[state, actions]`.
|
|
302
|
+
|
|
303
|
+
## Migration
|
|
304
|
+
|
|
305
|
+
From pre-1.0 releases:
|
|
306
|
+
|
|
307
|
+
1. Rename `StateHandler` -> `ObservableStateHandler`.
|
|
308
|
+
2. Implement `subscribe()` and `getSnapshot()` on custom handlers.
|
|
309
|
+
3. Replace `getObservable()` usage with `subscribe()` in custom integrations.
|
|
310
|
+
4. Update devtools config:
|
|
311
|
+
- From: `super({ initialState, devTools: { ... } })`
|
|
312
|
+
- To: `super({ initialState, options: { devTools: { ... } } })`
|
|
Binary file
|
|
@@ -1,3 +1,2 @@
|
|
|
1
1
|
import type { StateSubscriptionHandler } from '../types/types.js';
|
|
2
|
-
|
|
3
|
-
export declare function useStateSubscription<V, A>(stateSubscriptionHandler: StateSubscriptionHandler<V, A>): SetStateAction<V>;
|
|
2
|
+
export declare function useStateSubscription<V, A>(stateSubscriptionHandler: StateSubscriptionHandler<V, A>): V;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { useCallback, useSyncExternalStore } from 'react';
|
|
2
2
|
export function useStateSubscription(stateSubscriptionHandler) {
|
|
3
|
-
const
|
|
4
|
-
|
|
5
|
-
const state$ = stateSubscriptionHandler.getObservable().subscribe((data) => {
|
|
6
|
-
setSubscriptionState(data);
|
|
7
|
-
});
|
|
3
|
+
const subscribe = useCallback((listener) => {
|
|
4
|
+
const unsubscribe = stateSubscriptionHandler.subscribe(listener);
|
|
8
5
|
return () => {
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
unsubscribe();
|
|
7
|
+
stateSubscriptionHandler.destroy();
|
|
11
8
|
};
|
|
12
9
|
}, [stateSubscriptionHandler]);
|
|
13
|
-
|
|
10
|
+
const getSnapshot = useCallback(() => stateSubscriptionHandler.getSnapshot(), [stateSubscriptionHandler]);
|
|
11
|
+
const getServerSnapshot = useCallback(() => stateSubscriptionHandler.getInitialState(), [stateSubscriptionHandler]);
|
|
12
|
+
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
14
13
|
}
|
|
15
14
|
//# sourceMappingURL=state-subscription.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"state-subscription.js","sourceRoot":"","sources":["../../src/hooks/state-subscription.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"state-subscription.js","sourceRoot":"","sources":["../../src/hooks/state-subscription.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,OAAO,CAAC;AAK1D,MAAM,UAAU,oBAAoB,CAClC,wBAAwD;IAExD,MAAM,SAAS,GAAG,WAAW,CAC3B,CAAC,QAAkB,EAAE,EAAE;QACrB,MAAM,WAAW,GAAG,wBAAwB,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAEjE,OAAO,GAAG,EAAE;YACV,WAAW,EAAE,CAAC;YACd,wBAAwB,CAAC,OAAO,EAAE,CAAC;QACrC,CAAC,CAAC;IACJ,CAAC,EACD,CAAC,wBAAwB,CAAC,CAC3B,CAAC;IAEF,MAAM,WAAW,GAAG,WAAW,CAC7B,GAAG,EAAE,CAAC,wBAAwB,CAAC,WAAW,EAAE,EAC5C,CAAC,wBAAwB,CAAC,CAC3B,CAAC;IAEF,MAAM,iBAAiB,GAAG,WAAW,CACnC,GAAG,EAAE,CAAC,wBAAwB,CAAC,eAAe,EAAE,EAChD,CAAC,wBAAwB,CAAC,CAC3B,CAAC;IAEF,OAAO,oBAAoB,CAAC,SAAS,EAAE,WAAW,EAAE,iBAAiB,CAAC,CAAC;AACzE,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useStateFactory, useStateSingleton } from './hooks/index.js';
|
|
2
|
-
import { makeStateSingleton,
|
|
2
|
+
import { BaseStateHandler, makeStateSingleton, ObservableStateHandler, SignalStateHandler } from './store/index.js';
|
|
3
3
|
import type { StateSingleton } from './store/index.js';
|
|
4
4
|
import type { StateSubscriptionHandler } from './types/types.js';
|
|
5
|
-
export { makeStateSingleton,
|
|
5
|
+
export { BaseStateHandler, makeStateSingleton, ObservableStateHandler, SignalStateHandler, useStateFactory, useStateSingleton, };
|
|
6
6
|
export type { StateSingleton, StateSubscriptionHandler };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { useStateFactory, useStateSingleton } from './hooks/index.js';
|
|
2
|
-
import { makeStateSingleton,
|
|
3
|
-
export { makeStateSingleton,
|
|
2
|
+
import { BaseStateHandler, makeStateSingleton, ObservableStateHandler, SignalStateHandler, } from './store/index.js';
|
|
3
|
+
export { BaseStateHandler, makeStateSingleton, ObservableStateHandler, SignalStateHandler, useStateFactory, useStateSingleton, };
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACtE,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,GACnB,MAAM,kBAAkB,CAAC;AAK1B,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,sBAAsB,EACtB,kBAAkB,EAClB,eAAe,EACf,iBAAiB,GAClB,CAAC"}
|