opshot 0.3.3 → 0.4.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 +33 -33
- package/dist/index.d.ts +435 -42
- package/dist/index.js +2993 -1241
- package/package.json +20 -10
package/README.md
CHANGED
|
@@ -82,23 +82,23 @@ This is how you optimize re-rendering across your component tree: place `scope`
|
|
|
82
82
|
## Creating State
|
|
83
83
|
|
|
84
84
|
```tsx
|
|
85
|
-
import { ignore, unsafeTrack, useMutableState
|
|
85
|
+
import { ignore, unsafeTrack, useMutableState } from "opshot";
|
|
86
86
|
|
|
87
87
|
interface PlayerState {
|
|
88
88
|
position: number;
|
|
89
|
-
element:
|
|
90
|
-
queue:
|
|
89
|
+
element: HTMLAudioElement;
|
|
90
|
+
queue: Playlist;
|
|
91
91
|
seek: (position: number) => void;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
const Player = () => {
|
|
95
|
-
const player = useMutableState
|
|
95
|
+
const player: PlayerState = useMutableState({
|
|
96
96
|
position: 0,
|
|
97
97
|
|
|
98
|
-
// ignore()
|
|
98
|
+
// ignore() on a value in the factory argument makes the edge at that path untracked.
|
|
99
99
|
element: ignore(new Audio()),
|
|
100
100
|
|
|
101
|
-
// unsafeTrack()
|
|
101
|
+
// unsafeTrack() on a value in the factory argument disables strict at and under that path.
|
|
102
102
|
queue: unsafeTrack(new Playlist()),
|
|
103
103
|
|
|
104
104
|
seek(position: number) {
|
|
@@ -120,13 +120,14 @@ opshot tracks plain data.
|
|
|
120
120
|
|
|
121
121
|
It can't track:
|
|
122
122
|
|
|
123
|
-
-
|
|
124
|
-
- #private fields
|
|
125
|
-
-
|
|
123
|
+
- Hidden stores (language-level features like in Map)
|
|
124
|
+
- #private fields
|
|
125
|
+
- Own function properties on class instances
|
|
126
|
+
- Non-writable properties that hold an object
|
|
126
127
|
|
|
127
|
-
|
|
128
|
+
`strict: true` throws at a dangerous edge, at the cause.
|
|
128
129
|
|
|
129
|
-
Use `ignore`
|
|
130
|
+
Use `ignore` on a value in the factory argument to make the edge at that path untracked. Use `unsafeTrack` on a value in the factory argument to disable strict at and under that path.
|
|
130
131
|
|
|
131
132
|
## Tracked collections
|
|
132
133
|
|
|
@@ -155,8 +156,8 @@ const Counter = () => {
|
|
|
155
156
|
() =>
|
|
156
157
|
subscribe(counter, (ops, meta) => {
|
|
157
158
|
// ops: [{
|
|
158
|
-
// do: {
|
|
159
|
-
// undo: {
|
|
159
|
+
// do: { verb: "assign", path: ["count"], value: 1 },
|
|
160
|
+
// undo: { verb: "assign", path: ["count"], value: 0 },
|
|
160
161
|
// }]
|
|
161
162
|
// meta: whatever the writer passed, or undefined for bare writes
|
|
162
163
|
}),
|
|
@@ -169,33 +170,36 @@ const Counter = () => {
|
|
|
169
170
|
|
|
170
171
|
## Ops
|
|
171
172
|
|
|
172
|
-
An op is an invertible pair of
|
|
173
|
+
An op is an invertible pair of halves. Every half uses one of three verbs:
|
|
173
174
|
|
|
174
175
|
```ts
|
|
175
176
|
type OperationPath = ReadonlyArray<string | number>;
|
|
176
177
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
178
|
+
interface Operation {
|
|
179
|
+
readonly do:
|
|
180
|
+
| {
|
|
181
|
+
readonly verb: "assign";
|
|
182
|
+
readonly path: OperationPath;
|
|
183
|
+
readonly value: unknown;
|
|
184
|
+
readonly ids?: ReadonlyArray<number>;
|
|
185
|
+
}
|
|
186
|
+
| { readonly verb: "delete"; readonly path: OperationPath }
|
|
187
|
+
| { readonly verb: "link"; readonly path: OperationPath; readonly ref: number };
|
|
188
|
+
readonly undo: Operation["do"];
|
|
185
189
|
}
|
|
186
190
|
```
|
|
187
191
|
|
|
188
|
-
`
|
|
192
|
+
Ids vend in admission-walk order over the emitted artifact; a departure's undo assign may carry `ids` to rebind that walk, the one naming fact construction cannot re-derive. `applyOperations` puts them back on a state, so a history is a list of ops and an undo is `applyOperations` with `"undo"`.
|
|
189
193
|
|
|
190
194
|
```tsx
|
|
191
195
|
import { useEffect, useRef } from "react";
|
|
192
|
-
import {
|
|
196
|
+
import { applyOperations, subscribe, useMutableState, type Operation } from "opshot";
|
|
193
197
|
|
|
194
198
|
const replay = {};
|
|
195
199
|
|
|
196
200
|
const Counter = () => {
|
|
197
201
|
const counter = useMutableState({ count: 0 });
|
|
198
|
-
const history = useRef<Array<ReadonlyArray<
|
|
202
|
+
const history = useRef<Array<ReadonlyArray<Operation>>>([]);
|
|
199
203
|
|
|
200
204
|
useEffect(
|
|
201
205
|
() =>
|
|
@@ -213,11 +217,7 @@ const Counter = () => {
|
|
|
213
217
|
|
|
214
218
|
if (!ops) return;
|
|
215
219
|
|
|
216
|
-
|
|
217
|
-
counter,
|
|
218
|
-
[...ops].reverse().map((op) => op.undo),
|
|
219
|
-
replay,
|
|
220
|
-
);
|
|
220
|
+
applyOperations(counter, ops, "undo", replay);
|
|
221
221
|
};
|
|
222
222
|
|
|
223
223
|
return (
|
|
@@ -245,8 +245,8 @@ const Editor = () => {
|
|
|
245
245
|
const group = useGroup();
|
|
246
246
|
|
|
247
247
|
// Created through the group, so their ops reach the group's subscribers.
|
|
248
|
-
const doc = useMutableState({ items: new Array<string>() }, group);
|
|
249
|
-
const selection = useMutableState({ index: 0 }, group);
|
|
248
|
+
const doc = useMutableState({ items: new Array<string>() }, { group });
|
|
249
|
+
const selection = useMutableState({ index: 0 }, { group });
|
|
250
250
|
|
|
251
251
|
useEffect(
|
|
252
252
|
() =>
|
|
@@ -264,7 +264,7 @@ const Editor = () => {
|
|
|
264
264
|
|
|
265
265
|
## Channels
|
|
266
266
|
|
|
267
|
-
A channel binds `transact`, `subscribe`, and `
|
|
267
|
+
A channel binds `transact`, `subscribe`, and `applyOperations` to a typed meta convention, so a listener can tell its own writes from everyone else's.
|
|
268
268
|
|
|
269
269
|
```tsx
|
|
270
270
|
import { useEffect } from "react";
|
package/dist/index.d.ts
CHANGED
|
@@ -1,75 +1,424 @@
|
|
|
1
1
|
import { ComponentType, FC } from 'react';
|
|
2
2
|
|
|
3
|
+
declare const ignoreMarker: unique symbol;
|
|
4
|
+
/**
|
|
5
|
+
* A factory-argument marker wrapping `T`.
|
|
6
|
+
*
|
|
7
|
+
* @typeParam T - Value type.
|
|
8
|
+
*/
|
|
9
|
+
interface Ignored<T> {
|
|
10
|
+
readonly [ignoreMarker]: T;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Marks a factory-argument value so the edge at that path is untracked in that state.
|
|
14
|
+
*
|
|
15
|
+
* @typeParam T - Value type.
|
|
16
|
+
* @param value - Value to ignore.
|
|
17
|
+
* @returns A marker consumed at create.
|
|
18
|
+
*/
|
|
19
|
+
declare function ignore<T>(value: T): Ignored<T>;
|
|
20
|
+
|
|
21
|
+
declare const unsafeMarker: unique symbol;
|
|
22
|
+
/**
|
|
23
|
+
* A factory-argument marker wrapping `T`.
|
|
24
|
+
*
|
|
25
|
+
* @typeParam T - Value type.
|
|
26
|
+
*/
|
|
27
|
+
interface UnsafeTracked<T> {
|
|
28
|
+
readonly [unsafeMarker]: T;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Marks a factory-argument value so strict is disabled at and under that path.
|
|
32
|
+
*
|
|
33
|
+
* @typeParam T - Value type.
|
|
34
|
+
* @param value - Value to track without strict.
|
|
35
|
+
* @returns A marker consumed at create.
|
|
36
|
+
*/
|
|
37
|
+
declare function unsafeTrack<T>(value: T): UnsafeTracked<T>;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Schedules when bare writes notify listeners. Call `flush` once.
|
|
41
|
+
*
|
|
42
|
+
* @param flush - Delivers pending ops.
|
|
43
|
+
* @returns Nothing.
|
|
44
|
+
*/
|
|
45
|
+
type EmissionScheduler = (flush: () => void) => void;
|
|
46
|
+
/**
|
|
47
|
+
* State creation options.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* createMutableState({ x: 0 }, { emitOn: (flush) => requestAnimationFrame(flush), strict: false })
|
|
51
|
+
*/
|
|
52
|
+
interface MutableNodeOptions {
|
|
53
|
+
/**
|
|
54
|
+
* When bare writes notify listeners. Defaults to a microtask.
|
|
55
|
+
*/
|
|
56
|
+
readonly emitOn?: EmissionScheduler;
|
|
57
|
+
/**
|
|
58
|
+
* When true, throws at a dangerous edge, at the cause. Defaults to true.
|
|
59
|
+
*/
|
|
60
|
+
readonly strict?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Options for `createMutableState`.
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* createMutableState({ count: 0 }, { group, emitOn, strict: false })
|
|
68
|
+
*/
|
|
69
|
+
interface MutableStateOptions extends MutableNodeOptions {
|
|
70
|
+
/**
|
|
71
|
+
* Group that receives this state's changes.
|
|
72
|
+
*/
|
|
73
|
+
readonly group?: Group;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* The live state shape after factory-argument markers are collapsed.
|
|
77
|
+
*
|
|
78
|
+
* @typeParam T - Factory argument type.
|
|
79
|
+
*/
|
|
80
|
+
type Unmarked<T> = T extends Ignored<infer Inner> ? Unmarked<Inner> : T extends UnsafeTracked<infer Inner> ? Unmarked<Inner> : T extends (...args: never) => unknown ? T : T extends ReadonlyArray<infer Element> ? Array<Unmarked<Element>> : T extends object ? {
|
|
81
|
+
[Key in keyof T]: Unmarked<T[Key]>;
|
|
82
|
+
} : T;
|
|
83
|
+
/**
|
|
84
|
+
* Creates a mutable state object.
|
|
85
|
+
*
|
|
86
|
+
* `ignore()` on a value in the factory argument makes the edge at that path untracked in that state.
|
|
87
|
+
* `unsafeTrack()` on a value in the factory argument disables strict at and under that path.
|
|
88
|
+
*
|
|
89
|
+
* @typeParam T - State shape.
|
|
90
|
+
* @param properties - Initial fields.
|
|
91
|
+
* @param options - Creation options.
|
|
92
|
+
* @returns The state, with factory-argument markers collapsed.
|
|
93
|
+
*/
|
|
94
|
+
declare function createMutableState<T extends object>(properties: T, options?: MutableStateOptions): Unmarked<T>;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Path segments to a value in state.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ["document", "items", 0, "title"]
|
|
101
|
+
*/
|
|
3
102
|
type OperationPath = ReadonlyArray<string | number>;
|
|
4
103
|
|
|
5
|
-
interface
|
|
6
|
-
readonly
|
|
104
|
+
interface DeclarationTrie {
|
|
105
|
+
readonly ignored: boolean;
|
|
106
|
+
readonly unsafe: boolean;
|
|
107
|
+
readonly children: ReadonlyMap<string, DeclarationTrie>;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
interface InEdge {
|
|
111
|
+
readonly parent: object;
|
|
112
|
+
readonly key: string | number;
|
|
113
|
+
}
|
|
114
|
+
interface NodeRecord {
|
|
115
|
+
edges: Array<InEdge>;
|
|
116
|
+
id: number | undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
interface CaptureTables {
|
|
120
|
+
mints: Array<{
|
|
121
|
+
readonly node: object;
|
|
122
|
+
readonly id: number;
|
|
123
|
+
}>;
|
|
124
|
+
binds: Array<{
|
|
125
|
+
readonly node: object;
|
|
126
|
+
readonly id: number;
|
|
127
|
+
}>;
|
|
128
|
+
bindIdByNode: Map<object, number>;
|
|
129
|
+
bindNodeById: Map<number, object>;
|
|
130
|
+
mintIdByNode: Map<object, number>;
|
|
131
|
+
mintNodeById: Map<number, object>;
|
|
132
|
+
nextStagedId: number;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
interface DirtyIndex {
|
|
136
|
+
readonly edges: WeakMap<object, Set<string | symbol>>;
|
|
137
|
+
readonly nodes: WeakSet<object>;
|
|
138
|
+
}
|
|
139
|
+
interface Handle {
|
|
140
|
+
proxy: {
|
|
141
|
+
readonly root: object;
|
|
142
|
+
};
|
|
143
|
+
lastSnapshot: object;
|
|
144
|
+
hasPendingWrites: boolean;
|
|
145
|
+
isFlushScheduled: boolean;
|
|
146
|
+
isFlushHeld: boolean;
|
|
147
|
+
flushGeneration: number;
|
|
148
|
+
subscribers: StateListeners;
|
|
149
|
+
groups?: ReadonlyArray<GroupListeners>;
|
|
150
|
+
disarmWatch?: () => void;
|
|
151
|
+
emitOn?: EmissionScheduler;
|
|
152
|
+
strict: boolean;
|
|
153
|
+
declarations: DeclarationTrie | undefined;
|
|
154
|
+
nodes: WeakMap<object, NodeRecord>;
|
|
155
|
+
byId: Map<number, object>;
|
|
156
|
+
nextInternId: number;
|
|
157
|
+
lastDirty?: DirtyIndex;
|
|
158
|
+
stamp: object;
|
|
159
|
+
version: number;
|
|
160
|
+
replaying: boolean;
|
|
161
|
+
transactionCapture?: CaptureTables;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Assigns a value at a path.
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* { verb: "assign", path: ["count"], value: 1 }
|
|
169
|
+
*/
|
|
170
|
+
interface AssignMutation {
|
|
171
|
+
/**
|
|
172
|
+
* `"assign"`.
|
|
173
|
+
*/
|
|
174
|
+
readonly verb: "assign";
|
|
175
|
+
/**
|
|
176
|
+
* Path to assign.
|
|
177
|
+
*/
|
|
7
178
|
readonly path: OperationPath;
|
|
179
|
+
/**
|
|
180
|
+
* Value to assign.
|
|
181
|
+
*/
|
|
8
182
|
readonly value: unknown;
|
|
183
|
+
/**
|
|
184
|
+
* Walk-ordered intern ids that override deterministic vending when this half re-admits departed material.
|
|
185
|
+
*/
|
|
186
|
+
readonly ids?: ReadonlyArray<number>;
|
|
9
187
|
}
|
|
10
|
-
|
|
11
|
-
|
|
188
|
+
/**
|
|
189
|
+
* Deletes the value at a path.
|
|
190
|
+
*
|
|
191
|
+
* @example
|
|
192
|
+
* { verb: "delete", path: ["temp"] }
|
|
193
|
+
*/
|
|
194
|
+
interface DeleteMutation {
|
|
195
|
+
/**
|
|
196
|
+
* `"delete"`.
|
|
197
|
+
*/
|
|
198
|
+
readonly verb: "delete";
|
|
199
|
+
/**
|
|
200
|
+
* Path to delete.
|
|
201
|
+
*/
|
|
12
202
|
readonly path: OperationPath;
|
|
13
|
-
readonly value: unknown;
|
|
14
203
|
}
|
|
15
|
-
|
|
16
|
-
|
|
204
|
+
/**
|
|
205
|
+
* Links the interned node `ref` into `path`.
|
|
206
|
+
*
|
|
207
|
+
* @example
|
|
208
|
+
* { verb: "link", path: ["alias"], ref: 0 }
|
|
209
|
+
*/
|
|
210
|
+
interface LinkMutation {
|
|
211
|
+
/**
|
|
212
|
+
* `"link"`.
|
|
213
|
+
*/
|
|
214
|
+
readonly verb: "link";
|
|
215
|
+
/**
|
|
216
|
+
* Path to place the linked node.
|
|
217
|
+
*/
|
|
17
218
|
readonly path: OperationPath;
|
|
219
|
+
/**
|
|
220
|
+
* Intern id of the node to link.
|
|
221
|
+
*/
|
|
222
|
+
readonly ref: number;
|
|
18
223
|
}
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
224
|
+
/**
|
|
225
|
+
* An assign, a delete, or a link.
|
|
226
|
+
*
|
|
227
|
+
* @example
|
|
228
|
+
* { verb: "assign", path: ["profile"], value: { name: "Ada" } }
|
|
229
|
+
*/
|
|
230
|
+
type Mutation = AssignMutation | DeleteMutation | LinkMutation;
|
|
231
|
+
/**
|
|
232
|
+
* A change with do and undo halves.
|
|
233
|
+
*
|
|
234
|
+
* @example
|
|
235
|
+
* { do: { verb: "assign", path: ["count"], value: 1 }, undo: { verb: "assign", path: ["count"], value: 0 } }
|
|
236
|
+
*/
|
|
237
|
+
interface Operation {
|
|
238
|
+
/**
|
|
239
|
+
* Forward operation.
|
|
240
|
+
*/
|
|
241
|
+
readonly do: Mutation;
|
|
242
|
+
/**
|
|
243
|
+
* Reverse operation.
|
|
244
|
+
*/
|
|
245
|
+
readonly undo: Mutation;
|
|
23
246
|
}
|
|
24
247
|
|
|
25
|
-
|
|
26
|
-
|
|
248
|
+
/**
|
|
249
|
+
* Listener for one state's changes.
|
|
250
|
+
*
|
|
251
|
+
* @param ops - Ops for the change.
|
|
252
|
+
* @param meta - Writer meta, if any.
|
|
253
|
+
* @returns Nothing.
|
|
254
|
+
*/
|
|
255
|
+
type StateListener = (ops: ReadonlyArray<Operation>, meta: unknown) => void;
|
|
256
|
+
/**
|
|
257
|
+
* Listener for a group's changes.
|
|
258
|
+
*
|
|
259
|
+
* @param state - State that changed.
|
|
260
|
+
* @param ops - Ops for the change.
|
|
261
|
+
* @param meta - Writer meta, if any.
|
|
262
|
+
* @returns Nothing.
|
|
263
|
+
*/
|
|
264
|
+
type GroupListener = (state: object, ops: ReadonlyArray<Operation>, meta: unknown) => void;
|
|
265
|
+
type StateDeliver = (ops: ReadonlyArray<Operation>, meta: unknown, channelId: object | undefined) => void;
|
|
266
|
+
type GroupDeliver = (state: object, ops: ReadonlyArray<Operation>, meta: unknown, channelId: object | undefined) => void;
|
|
267
|
+
type StateListeners = Map<Function, Map<object | undefined, StateDeliver>>;
|
|
268
|
+
type GroupListeners = Map<Function, Map<object | undefined, GroupDeliver>>;
|
|
27
269
|
|
|
270
|
+
/**
|
|
271
|
+
* Creates states and receives their changes on one stream.
|
|
272
|
+
*
|
|
273
|
+
* @example
|
|
274
|
+
* const group = createGroup()
|
|
275
|
+
* const doc = group.createMutableState({ title: "" })
|
|
276
|
+
* subscribe(group, (state, ops, meta) => {})
|
|
277
|
+
*/
|
|
28
278
|
interface Group {
|
|
29
|
-
|
|
279
|
+
/**
|
|
280
|
+
* Creates a state in this group.
|
|
281
|
+
*
|
|
282
|
+
* @typeParam T - State shape.
|
|
283
|
+
* @param properties - Initial fields.
|
|
284
|
+
* @param options - Creation options.
|
|
285
|
+
* @returns The state.
|
|
286
|
+
*/
|
|
287
|
+
createMutableState<T extends object>(properties: T, options?: MutableNodeOptions): Unmarked<T>;
|
|
30
288
|
}
|
|
31
|
-
|
|
289
|
+
/**
|
|
290
|
+
* Creates a group.
|
|
291
|
+
*
|
|
292
|
+
* @param parent - Optional parent group whose listeners hear this group's states.
|
|
293
|
+
* @returns A new group.
|
|
294
|
+
*/
|
|
295
|
+
declare function createGroup(parent?: Group): Group;
|
|
32
296
|
|
|
33
|
-
|
|
297
|
+
/**
|
|
298
|
+
* Listener context from a channel subscription.
|
|
299
|
+
*
|
|
300
|
+
* @typeParam M - Meta type for this channel.
|
|
301
|
+
*/
|
|
302
|
+
type EmissionContext<M> = {
|
|
34
303
|
readonly isTransaction: true;
|
|
35
304
|
readonly meta: M;
|
|
36
305
|
} | {
|
|
37
306
|
readonly isTransaction: false;
|
|
38
307
|
readonly meta: unknown;
|
|
39
308
|
};
|
|
309
|
+
/**
|
|
310
|
+
* Listens for changes from a group's states.
|
|
311
|
+
*
|
|
312
|
+
* @param group - Group to listen to.
|
|
313
|
+
* @param listener - Called on each change.
|
|
314
|
+
* @returns Unsubscribe function.
|
|
315
|
+
*/
|
|
40
316
|
declare function subscribe(group: Group, listener: GroupListener): () => void;
|
|
317
|
+
/**
|
|
318
|
+
* Listens for changes to a state.
|
|
319
|
+
*
|
|
320
|
+
* @param state - State to listen to.
|
|
321
|
+
* @param listener - Called on each change.
|
|
322
|
+
* @returns Unsubscribe function.
|
|
323
|
+
*/
|
|
41
324
|
declare function subscribe(state: object, listener: StateListener): () => void;
|
|
42
325
|
|
|
326
|
+
type ApplyDirection = "do" | "undo";
|
|
327
|
+
|
|
328
|
+
/**
|
|
329
|
+
* Channel-bound `transact`, `subscribe`, and `applyOperations`.
|
|
330
|
+
*
|
|
331
|
+
* @typeParam M - Meta type for this channel.
|
|
332
|
+
*/
|
|
43
333
|
interface Channel<M extends object> {
|
|
334
|
+
/**
|
|
335
|
+
* Runs a transaction with this channel's meta.
|
|
336
|
+
*
|
|
337
|
+
* @param state - State to change.
|
|
338
|
+
* @param mutate - Function that writes the state.
|
|
339
|
+
* @param meta - Meta for this write.
|
|
340
|
+
* @returns Nothing.
|
|
341
|
+
*/
|
|
44
342
|
transact(state: object, mutate: () => void, meta?: Partial<M>): void;
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
343
|
+
/**
|
|
344
|
+
* Listens for changes from a group's states.
|
|
345
|
+
*
|
|
346
|
+
* @param group - Group to listen to.
|
|
347
|
+
* @param listener - Called on each change.
|
|
348
|
+
* @returns Unsubscribe function.
|
|
349
|
+
*/
|
|
350
|
+
subscribe(group: Group, listener: (state: object, ops: ReadonlyArray<Operation>, context: EmissionContext<M>) => void): () => void;
|
|
351
|
+
/**
|
|
352
|
+
* Listens for changes to a state.
|
|
353
|
+
*
|
|
354
|
+
* @param state - State to listen to.
|
|
355
|
+
* @param listener - Called on each change.
|
|
356
|
+
* @returns Unsubscribe function.
|
|
357
|
+
*/
|
|
358
|
+
subscribe(state: object, listener: (ops: ReadonlyArray<Operation>, context: EmissionContext<M>) => void): () => void;
|
|
359
|
+
/**
|
|
360
|
+
* Applies operations with this channel's meta.
|
|
361
|
+
*
|
|
362
|
+
* @param state - State to change.
|
|
363
|
+
* @param operations - Operations to apply.
|
|
364
|
+
* @param direction - `"do"` or `"undo"`.
|
|
365
|
+
* @param meta - Meta for this write.
|
|
366
|
+
* @returns Nothing.
|
|
367
|
+
*/
|
|
368
|
+
applyOperations(state: object, operations: ReadonlyArray<Operation>, direction: ApplyDirection, meta?: Partial<M>): void;
|
|
48
369
|
}
|
|
370
|
+
/**
|
|
371
|
+
* Creates a channel with a typed meta convention.
|
|
372
|
+
*
|
|
373
|
+
* @typeParam M - Meta type for this channel.
|
|
374
|
+
* @param defaults - Default meta for this channel's writes.
|
|
375
|
+
* @returns The channel.
|
|
376
|
+
*/
|
|
49
377
|
declare function createChannel<M extends object>(defaults?: M): Channel<M>;
|
|
50
378
|
|
|
51
|
-
|
|
52
|
-
|
|
379
|
+
/**
|
|
380
|
+
* Returns a stable identity key for a value.
|
|
381
|
+
*
|
|
382
|
+
* @param value - Value to identify.
|
|
383
|
+
* @returns Identity key.
|
|
384
|
+
*/
|
|
53
385
|
declare function identify(value: object): object;
|
|
386
|
+
/**
|
|
387
|
+
* Returns whether two values share the same identity.
|
|
388
|
+
*
|
|
389
|
+
* @param first - First value.
|
|
390
|
+
* @param second - Second value.
|
|
391
|
+
* @returns True if they match.
|
|
392
|
+
*/
|
|
54
393
|
declare function isSameIdentity(first: object, second: object): boolean;
|
|
55
394
|
|
|
395
|
+
/**
|
|
396
|
+
* Returns whether a value is an opshot state.
|
|
397
|
+
*
|
|
398
|
+
* @param value - Value to test.
|
|
399
|
+
* @returns True if it is a state.
|
|
400
|
+
*/
|
|
56
401
|
declare function isState(value: unknown): value is object;
|
|
57
402
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
403
|
+
/**
|
|
404
|
+
* Applies operations to a state.
|
|
405
|
+
*
|
|
406
|
+
* @param state - State to change.
|
|
407
|
+
* @param operations - Operations to apply.
|
|
408
|
+
* @param direction - `"do"` or `"undo"`.
|
|
409
|
+
* @param meta - Passed to listeners.
|
|
410
|
+
* @returns Nothing.
|
|
411
|
+
*/
|
|
412
|
+
declare function applyOperations(state: object, operations: ReadonlyArray<Operation>, direction: ApplyDirection, meta?: unknown): void;
|
|
67
413
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
414
|
+
/**
|
|
415
|
+
* Diffs two plain objects into ops.
|
|
416
|
+
*
|
|
417
|
+
* @param before - Earlier value.
|
|
418
|
+
* @param after - Later value.
|
|
419
|
+
* @returns Ops from before to after.
|
|
420
|
+
*/
|
|
421
|
+
declare function diffObjects(before: object, after: object, handle?: Handle, dirty?: DirtyIndex, capture?: CaptureTables): Array<Operation>;
|
|
73
422
|
|
|
74
423
|
type DateConstructorArgs = [] | [value: number | string] | [
|
|
75
424
|
year: number,
|
|
@@ -80,10 +429,17 @@ type DateConstructorArgs = [] | [value: number | string] | [
|
|
|
80
429
|
seconds?: number,
|
|
81
430
|
milliseconds?: number
|
|
82
431
|
];
|
|
432
|
+
/**
|
|
433
|
+
* Tracked `Date` for use in state.
|
|
434
|
+
*
|
|
435
|
+
* @example
|
|
436
|
+
* createMutableState({ when: new TrackedDate() })
|
|
437
|
+
*/
|
|
83
438
|
declare class TrackedDate {
|
|
84
439
|
private epochMs;
|
|
85
440
|
constructor(...args: DateConstructorArgs);
|
|
86
441
|
private readDate;
|
|
442
|
+
private readEpochMs;
|
|
87
443
|
private write;
|
|
88
444
|
toString(): string;
|
|
89
445
|
toDateString(): string;
|
|
@@ -134,6 +490,12 @@ declare class TrackedDate {
|
|
|
134
490
|
readonly [Symbol.toStringTag]: "TrackedDate";
|
|
135
491
|
}
|
|
136
492
|
|
|
493
|
+
/**
|
|
494
|
+
* Tracked `Map` for use in state.
|
|
495
|
+
*
|
|
496
|
+
* @typeParam K - Key type.
|
|
497
|
+
* @typeParam V - Value type.
|
|
498
|
+
*/
|
|
137
499
|
declare class TrackedMap<K, V> {
|
|
138
500
|
private slots;
|
|
139
501
|
private index;
|
|
@@ -153,6 +515,11 @@ declare class TrackedMap<K, V> {
|
|
|
153
515
|
readonly [Symbol.toStringTag]: "TrackedMap";
|
|
154
516
|
}
|
|
155
517
|
|
|
518
|
+
/**
|
|
519
|
+
* Tracked `Set` for use in state.
|
|
520
|
+
*
|
|
521
|
+
* @typeParam T - Member type.
|
|
522
|
+
*/
|
|
156
523
|
declare class TrackedSet<T> {
|
|
157
524
|
private slots;
|
|
158
525
|
private index;
|
|
@@ -171,15 +538,41 @@ declare class TrackedSet<T> {
|
|
|
171
538
|
readonly [Symbol.toStringTag]: "TrackedSet";
|
|
172
539
|
}
|
|
173
540
|
|
|
541
|
+
/**
|
|
542
|
+
* Runs changes in one batch and notifies listeners with optional `meta`.
|
|
543
|
+
*
|
|
544
|
+
* @param state - State to change.
|
|
545
|
+
* @param mutate - Function that writes the state.
|
|
546
|
+
* @param meta - Passed to listeners.
|
|
547
|
+
* @returns Nothing.
|
|
548
|
+
*/
|
|
174
549
|
declare function transact(state: object, mutate: () => void, meta?: unknown): void;
|
|
175
550
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
551
|
+
/**
|
|
552
|
+
* Wraps a component so it re-renders only when fields it read change.
|
|
553
|
+
*
|
|
554
|
+
* @typeParam P - Props type.
|
|
555
|
+
* @param Component - Component to wrap.
|
|
556
|
+
* @returns The wrapped component.
|
|
557
|
+
*/
|
|
558
|
+
declare function scope<P extends object>(Component: ComponentType<P>): FC<P>;
|
|
180
559
|
|
|
181
|
-
|
|
560
|
+
/**
|
|
561
|
+
* Creates a group for a component.
|
|
562
|
+
*
|
|
563
|
+
* @param parent - Optional parent group whose listeners hear this group's states.
|
|
564
|
+
* @returns The group.
|
|
565
|
+
*/
|
|
566
|
+
declare function useGroup(parent?: Group): Group;
|
|
182
567
|
|
|
183
|
-
|
|
568
|
+
/**
|
|
569
|
+
* Creates mutable state for a component.
|
|
570
|
+
*
|
|
571
|
+
* @typeParam T - State shape.
|
|
572
|
+
* @param properties - Initial fields, or a function that returns them.
|
|
573
|
+
* @param options - Creation options.
|
|
574
|
+
* @returns The state.
|
|
575
|
+
*/
|
|
576
|
+
declare function useMutableState<T extends object>(properties: (() => T) | T, options?: MutableStateOptions): Unmarked<T>;
|
|
184
577
|
|
|
185
|
-
export { type
|
|
578
|
+
export { type Channel, type EmissionContext, type EmissionScheduler, type Group, type GroupListener, type Ignored, type MutableNodeOptions, type MutableStateOptions, type Operation, type OperationPath, type StateListener, TrackedDate, TrackedMap, TrackedSet, type UnsafeTracked, applyOperations, createChannel, createGroup, createMutableState, diffObjects, identify, ignore, isSameIdentity, isState, scope, subscribe, transact, unsafeTrack, useGroup, useMutableState };
|