@e280/strata 0.0.0-6 → 0.0.0-7
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
CHANGED
|
@@ -4,12 +4,11 @@
|
|
|
4
4
|
<br/>
|
|
5
5
|
|
|
6
6
|
# ⛏️ strata
|
|
7
|
-
📦 `npm install @e280/strata`
|
|
8
|
-
probably my tenth state management library, lol
|
|
9
|
-
|
|
10
|
-
<br/>
|
|
11
7
|
|
|
12
8
|
### get in loser, we're managing state
|
|
9
|
+
📦 `npm install @e280/strata`
|
|
10
|
+
🧙♂️ probably my tenth state management library, lol
|
|
11
|
+
|
|
13
12
|
🚦 **signals** — ephemeral view-level state
|
|
14
13
|
🌳 **tree** — persistent app-level state
|
|
15
14
|
🪄 **tracker** — reactivity integration hub
|
|
@@ -23,46 +22,66 @@
|
|
|
23
22
|
<br/>
|
|
24
23
|
|
|
25
24
|
## 🚦 signals — *ephemeral view-level state*
|
|
26
|
-
|
|
25
|
+
```ts
|
|
26
|
+
import {signal, effect, computed} from "@e280/strata"
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
### each signal holds a value
|
|
30
|
+
- **create a signal**
|
|
27
31
|
```ts
|
|
28
|
-
|
|
32
|
+
const count = signal(0)
|
|
29
33
|
```
|
|
30
|
-
- **
|
|
34
|
+
- **read a signal**
|
|
31
35
|
```ts
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
count() // 0
|
|
37
|
+
```
|
|
38
|
+
- **set a signal**
|
|
39
|
+
```ts
|
|
40
|
+
count(1)
|
|
41
|
+
```
|
|
42
|
+
- **set a signal, and await effect propagation**
|
|
43
|
+
```ts
|
|
44
|
+
await count(2)
|
|
45
|
+
```
|
|
46
|
+
- **signals are for auto rerendering your ui.**
|
|
47
|
+
components/views will auto rerender when relevant signals change
|
|
48
|
+
— well only if your ui lib is cool and integrates `tracker`.
|
|
38
49
|
|
|
39
|
-
|
|
40
|
-
|
|
50
|
+
### pick your poison
|
|
51
|
+
- **signals hipster fn syntax**
|
|
52
|
+
```ts
|
|
53
|
+
count() // get
|
|
54
|
+
await count(2) // set
|
|
55
|
+
```
|
|
56
|
+
- **signals get/set syntax**
|
|
57
|
+
```ts
|
|
58
|
+
count.get() // get
|
|
59
|
+
await count.set(2) // set
|
|
60
|
+
```
|
|
61
|
+
- **signals .value accessor syntax**
|
|
62
|
+
```ts
|
|
63
|
+
count.value // get
|
|
64
|
+
count.value = 2 // set
|
|
41
65
|
```
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
- three ways to set it
|
|
51
|
-
```ts
|
|
52
|
-
await count(2)
|
|
53
|
-
await count.set(2)
|
|
54
|
-
count.value = 2
|
|
55
|
-
```
|
|
56
|
-
- using `await` here allows you to wait for downstream effects to finish
|
|
57
|
-
- **effects are run when the relevant signals change**
|
|
66
|
+
value pattern is nice for this vibe
|
|
67
|
+
```ts
|
|
68
|
+
count.value++
|
|
69
|
+
count.value += 1
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### effects
|
|
73
|
+
- **effects run when the relevant signals change**
|
|
58
74
|
```ts
|
|
59
75
|
effect(() => console.log(count()))
|
|
60
|
-
//
|
|
76
|
+
// 1
|
|
77
|
+
// the system detects 'count' is relevant
|
|
61
78
|
|
|
62
79
|
count.value++
|
|
63
|
-
//
|
|
80
|
+
// 2
|
|
81
|
+
// when count is changed, the effect fn is run
|
|
64
82
|
```
|
|
65
|
-
- **computed signals are super lazy**
|
|
83
|
+
- **computed signals are super lazy**
|
|
84
|
+
they only run if and when you get the value
|
|
66
85
|
```ts
|
|
67
86
|
const tenly = computed(() => {
|
|
68
87
|
console.log("recomputed!")
|
|
@@ -71,23 +90,23 @@
|
|
|
71
90
|
|
|
72
91
|
console.log(tenly())
|
|
73
92
|
// "recomputed!"
|
|
74
|
-
//
|
|
93
|
+
// 20
|
|
75
94
|
|
|
76
|
-
await count(
|
|
95
|
+
await count(3)
|
|
77
96
|
|
|
78
97
|
console.log(tenly.value)
|
|
79
98
|
// "recomputed!"
|
|
80
|
-
//
|
|
99
|
+
// 30
|
|
81
100
|
```
|
|
82
101
|
|
|
83
102
|
<br/>
|
|
84
103
|
|
|
85
104
|
## 🌳 tree — *persistent app-level state*
|
|
86
|
-
- `@e280/strata/tree`
|
|
87
105
|
- single-source-of-truth state tree
|
|
88
106
|
- immutable except for `mutate(fn)` calls
|
|
89
107
|
- undo/redo history, cross-tab sync, localStorage persistence
|
|
90
108
|
- no spooky-dookie proxy magic — just god's honest javascript
|
|
109
|
+
- separate but compatible with signals
|
|
91
110
|
|
|
92
111
|
#### `Trunk` is your app's state tree root
|
|
93
112
|
- better stick to json-friendly serializable data
|
|
@@ -186,7 +205,7 @@
|
|
|
186
205
|
})
|
|
187
206
|
```
|
|
188
207
|
- *big-brain moment:* the whole chronicle *itself* is stored in the state.. serializable.. think persistence — user can close their project, reopen, and their undo/redo history is still chillin' — *brat girl summer*
|
|
189
|
-
- second, make a `Chronobranch` which is like a branch
|
|
208
|
+
- second, make a `Chronobranch` which is like a branch, but is concerned with history
|
|
190
209
|
```ts
|
|
191
210
|
const snacks = trunk.chronobranch(64, s => s.snacks)
|
|
192
211
|
// \
|
|
@@ -207,13 +226,15 @@
|
|
|
207
226
|
snacks.undoable // 2
|
|
208
227
|
snacks.redoable // 1
|
|
209
228
|
```
|
|
210
|
-
- chronobranch can have its own
|
|
229
|
+
- chronobranch can have its own branches — all their mutations advance history
|
|
211
230
|
- plz pinky-swear right now, that you won't create a chronobranch under a branch under another chronobranch 💀
|
|
212
231
|
|
|
213
232
|
<br/>
|
|
214
233
|
|
|
215
234
|
## 🪄 tracker — integrations
|
|
216
|
-
-
|
|
235
|
+
- ```ts
|
|
236
|
+
import {tracker} from "@e280/strata/tracker"
|
|
237
|
+
```
|
|
217
238
|
- all reactivity is orchestrated by the `tracker`
|
|
218
239
|
- if you are integrating a new state object, or a new view layer that needs to react to state changes, just read [tracker.ts](./s/tracker/tracker.ts)
|
|
219
240
|
|
package/package.json
CHANGED
|
@@ -2,39 +2,39 @@
|
|
|
2
2
|
import {debounce} from "@e280/stz"
|
|
3
3
|
|
|
4
4
|
import {Trunk} from "../trunk.js"
|
|
5
|
-
import {Treestate, SetupOptions} from "../types.js"
|
|
6
5
|
import {localPersistence} from "../persistence.js"
|
|
6
|
+
import {Treestate, SetupOptions} from "../types.js"
|
|
7
7
|
|
|
8
8
|
export async function trunkSetup<S extends Treestate>(options: SetupOptions<S>) {
|
|
9
9
|
const {
|
|
10
10
|
version,
|
|
11
11
|
initialState,
|
|
12
12
|
saveDebounceTime = 500,
|
|
13
|
-
persistence = localPersistence("
|
|
13
|
+
persistence = localPersistence("strataTree"),
|
|
14
14
|
} = options
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const trunk = new Trunk<S>(initialState)
|
|
17
17
|
|
|
18
18
|
async function load() {
|
|
19
19
|
const pickle = await persistence.store.get()
|
|
20
20
|
if (pickle && pickle.version === version)
|
|
21
|
-
await
|
|
21
|
+
await trunk.overwrite(pickle.state)
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
const save = debounce(saveDebounceTime, async() => persistence.store.set({
|
|
25
25
|
version,
|
|
26
|
-
state:
|
|
26
|
+
state: trunk.state,
|
|
27
27
|
}))
|
|
28
28
|
|
|
29
29
|
// persistence: initial load from store
|
|
30
30
|
await load()
|
|
31
31
|
|
|
32
32
|
// persistence: save to store
|
|
33
|
-
|
|
33
|
+
trunk.watch(save)
|
|
34
34
|
|
|
35
35
|
// cross-tab sync
|
|
36
36
|
const dispose = persistence.onChange(load)
|
|
37
37
|
|
|
38
|
-
return {
|
|
38
|
+
return {trunk, load, save, dispose}
|
|
39
39
|
}
|
|
40
40
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Trunk } from "../trunk.js";
|
|
2
2
|
import { Treestate, SetupOptions } from "../types.js";
|
|
3
3
|
export declare function trunkSetup<S extends Treestate>(options: SetupOptions<S>): Promise<{
|
|
4
|
-
|
|
4
|
+
trunk: Trunk<S>;
|
|
5
5
|
load: () => Promise<void>;
|
|
6
6
|
save: import("@e280/stz").DebounceReturn<() => Promise<void>>;
|
|
7
7
|
dispose: () => void;
|
|
@@ -2,23 +2,23 @@ import { debounce } from "@e280/stz";
|
|
|
2
2
|
import { Trunk } from "../trunk.js";
|
|
3
3
|
import { localPersistence } from "../persistence.js";
|
|
4
4
|
export async function trunkSetup(options) {
|
|
5
|
-
const { version, initialState, saveDebounceTime = 500, persistence = localPersistence("
|
|
6
|
-
const
|
|
5
|
+
const { version, initialState, saveDebounceTime = 500, persistence = localPersistence("strataTree"), } = options;
|
|
6
|
+
const trunk = new Trunk(initialState);
|
|
7
7
|
async function load() {
|
|
8
8
|
const pickle = await persistence.store.get();
|
|
9
9
|
if (pickle && pickle.version === version)
|
|
10
|
-
await
|
|
10
|
+
await trunk.overwrite(pickle.state);
|
|
11
11
|
}
|
|
12
12
|
const save = debounce(saveDebounceTime, async () => persistence.store.set({
|
|
13
13
|
version,
|
|
14
|
-
state:
|
|
14
|
+
state: trunk.state,
|
|
15
15
|
}));
|
|
16
16
|
// persistence: initial load from store
|
|
17
17
|
await load();
|
|
18
18
|
// persistence: save to store
|
|
19
|
-
|
|
19
|
+
trunk.watch(save);
|
|
20
20
|
// cross-tab sync
|
|
21
21
|
const dispose = persistence.onChange(load);
|
|
22
|
-
return {
|
|
22
|
+
return { trunk, load, save, dispose };
|
|
23
23
|
}
|
|
24
24
|
//# sourceMappingURL=setup.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../../s/tree/parts/utils/setup.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAElC,OAAO,EAAC,KAAK,EAAC,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"setup.js","sourceRoot":"","sources":["../../../../s/tree/parts/utils/setup.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,QAAQ,EAAC,MAAM,WAAW,CAAA;AAElC,OAAO,EAAC,KAAK,EAAC,MAAM,aAAa,CAAA;AACjC,OAAO,EAAC,gBAAgB,EAAC,MAAM,mBAAmB,CAAA;AAGlD,MAAM,CAAC,KAAK,UAAU,UAAU,CAAsB,OAAwB;IAC7E,MAAM,EACL,OAAO,EACP,YAAY,EACZ,gBAAgB,GAAG,GAAG,EACtB,WAAW,GAAG,gBAAgB,CAAC,YAAY,CAAC,GAC5C,GAAG,OAAO,CAAA;IAEX,MAAM,KAAK,GAAG,IAAI,KAAK,CAAI,YAAY,CAAC,CAAA;IAExC,KAAK,UAAU,IAAI;QAClB,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC,KAAK,CAAC,GAAG,EAAE,CAAA;QAC5C,IAAI,MAAM,IAAI,MAAM,CAAC,OAAO,KAAK,OAAO;YACvC,MAAM,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,gBAAgB,EAAE,KAAK,IAAG,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,GAAG,CAAC;QACxE,OAAO;QACP,KAAK,EAAE,KAAK,CAAC,KAAK;KAClB,CAAC,CAAC,CAAA;IAEH,uCAAuC;IACvC,MAAM,IAAI,EAAE,CAAA;IAEZ,6BAA6B;IAC7B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAEjB,iBAAiB;IACjB,MAAM,OAAO,GAAG,WAAW,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAE1C,OAAO,EAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAC,CAAA;AACpC,CAAC"}
|