opshot 0.2.1 → 0.3.3
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/LICENSE +21 -0
- package/README.md +171 -78
- package/dist/index.d.ts +175 -46
- package/dist/index.js +2329 -119
- package/package.json +74 -74
- package/dist/react.d.ts +0 -11
- package/dist/react.js +0 -279
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Matt Cavender
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
# opshot
|
|
4
4
|
|
|
5
|
-
Mutable state for React, with re-render for only the components that read what changed. (It's [valtio](https://github.com/pmndrs/valtio), but not a footgun.)
|
|
5
|
+
Mutable state for React, with re-render for only the components that read what changed. (It's like [valtio](https://github.com/pmndrs/valtio), but not a footgun.)
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
|
@@ -20,12 +20,12 @@ const [user, setUser] = useState({ name: "Ada", age: 36 });
|
|
|
20
20
|
setUser((prev) => ({ ...prev, age: 37 }));
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
opshot state is mutable: you assign the field.
|
|
23
|
+
**opshot** state is a live mutable object: you assign the field.
|
|
24
24
|
|
|
25
25
|
```tsx
|
|
26
|
-
const user =
|
|
26
|
+
const user = useMutableState({ name: "Ada", age: 36 });
|
|
27
27
|
|
|
28
|
-
user.
|
|
28
|
+
user.age = 37;
|
|
29
29
|
```
|
|
30
30
|
|
|
31
31
|
## Bounded re-renders
|
|
@@ -55,13 +55,15 @@ const Parent = () => {
|
|
|
55
55
|
const Child = ({ user }: { user: User }) => <p>{user.age}</p>;
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
opshot re-renders only what read the change. Wrap a child in `
|
|
58
|
+
**opshot** re-renders only what read the change. Wrap a child in `scope` and it subscribes to the fields it reads. **Where the mutation happens doesn't matter** — here Parent writes, and only Child re-renders, because renders follow reads, not writes.
|
|
59
59
|
|
|
60
60
|
```tsx
|
|
61
61
|
const Parent = () => {
|
|
62
|
-
const user =
|
|
62
|
+
const user = useMutableState<User>({ name: "Ada", age: 36 });
|
|
63
63
|
|
|
64
|
-
const birthday = () =>
|
|
64
|
+
const birthday = () => {
|
|
65
|
+
user.age++;
|
|
66
|
+
};
|
|
65
67
|
|
|
66
68
|
// A click re-renders only Child.
|
|
67
69
|
return (
|
|
@@ -72,145 +74,236 @@ const Parent = () => {
|
|
|
72
74
|
);
|
|
73
75
|
};
|
|
74
76
|
|
|
75
|
-
const Child =
|
|
77
|
+
const Child = scope<{ user: User }>(({ user }) => <p>{user.age}</p>);
|
|
76
78
|
```
|
|
77
79
|
|
|
78
|
-
This is how you optimize re-rendering across your component tree: place `
|
|
80
|
+
This is how you optimize re-rendering across your component tree: place `scope` boundaries where you want re-renders contained, and each boundary re-renders only when a field it read changes. `useMutableState` is a boundary itself.
|
|
79
81
|
|
|
80
82
|
## Creating State
|
|
81
83
|
|
|
82
84
|
```tsx
|
|
83
|
-
import {
|
|
84
|
-
|
|
85
|
+
import { ignore, unsafeTrack, useMutableState, type Ignored, type UnsafeTracked } from "opshot";
|
|
86
|
+
|
|
87
|
+
interface PlayerState {
|
|
88
|
+
position: number;
|
|
89
|
+
element: Ignored<HTMLAudioElement>;
|
|
90
|
+
queue: UnsafeTracked<Playlist>;
|
|
91
|
+
seek: (position: number) => void;
|
|
92
|
+
}
|
|
85
93
|
|
|
86
94
|
const Player = () => {
|
|
87
|
-
const player =
|
|
95
|
+
const player = useMutableState<PlayerState>({
|
|
88
96
|
position: 0,
|
|
89
97
|
|
|
90
|
-
//
|
|
91
|
-
element:
|
|
98
|
+
// ignore() keeps a value out of reactivity and ops.
|
|
99
|
+
element: ignore(new Audio()),
|
|
100
|
+
|
|
101
|
+
// unsafeTrack() tracks all the values it can, even if there is weird behaviour
|
|
102
|
+
queue: unsafeTrack(new Playlist()),
|
|
92
103
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
get().element.currentTime = position;
|
|
104
|
+
seek(position: number) {
|
|
105
|
+
this.element.currentTime = position;
|
|
96
106
|
|
|
97
|
-
|
|
107
|
+
if (this.position === position) return;
|
|
108
|
+
|
|
109
|
+
this.position = position;
|
|
98
110
|
},
|
|
99
|
-
})
|
|
111
|
+
});
|
|
100
112
|
|
|
101
113
|
// ...
|
|
102
114
|
};
|
|
103
115
|
```
|
|
104
116
|
|
|
105
|
-
##
|
|
117
|
+
## Constraints
|
|
118
|
+
|
|
119
|
+
opshot tracks plain data.
|
|
120
|
+
|
|
121
|
+
It can't track:
|
|
122
|
+
|
|
123
|
+
- Internal slots (language level features like in Map)
|
|
124
|
+
- #private fields (hidden at the language level)
|
|
125
|
+
- Array subclasses (the prototype is lost when copied)
|
|
126
|
+
|
|
127
|
+
And `this` for arrow methods on classes refers to the original and **not** the tracked state.
|
|
128
|
+
|
|
129
|
+
Use `ignore` or `unsafeTrack` when dealing with these.
|
|
106
130
|
|
|
107
|
-
|
|
131
|
+
## Tracked collections
|
|
132
|
+
|
|
133
|
+
`TrackedMap`, `TrackedSet`, and `TrackedDate` stand in for the built-ins opshot rejects. They have the exact same API as their counterparts.
|
|
108
134
|
|
|
109
135
|
```ts
|
|
110
|
-
|
|
111
|
-
counter.mutate((mutable) => mutable.count++, { transactionKey: "drag" });
|
|
136
|
+
import { TrackedMap, useMutableState } from "opshot";
|
|
112
137
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
138
|
+
const state = useMutableState({ index: new TrackedMap<string, number>() });
|
|
139
|
+
|
|
140
|
+
state.index.set("a", 1);
|
|
141
|
+
```
|
|
117
142
|
|
|
118
|
-
|
|
119
|
-
|
|
143
|
+
## Subscribe
|
|
144
|
+
|
|
145
|
+
`subscribe` hears every change to a state.
|
|
146
|
+
|
|
147
|
+
```tsx
|
|
148
|
+
import { useEffect } from "react";
|
|
149
|
+
import { subscribe, useMutableState } from "opshot";
|
|
120
150
|
|
|
121
|
-
|
|
122
|
-
counter
|
|
151
|
+
const Counter = () => {
|
|
152
|
+
const counter = useMutableState({ count: 0 });
|
|
123
153
|
|
|
124
|
-
|
|
125
|
-
|
|
154
|
+
useEffect(
|
|
155
|
+
() =>
|
|
156
|
+
subscribe(counter, (ops, meta) => {
|
|
157
|
+
// ops: [{
|
|
158
|
+
// do: { op: "replace", path: ["count"], value: 1 },
|
|
159
|
+
// undo: { op: "replace", path: ["count"], value: 0 },
|
|
160
|
+
// }]
|
|
161
|
+
// meta: whatever the writer passed, or undefined for bare writes
|
|
162
|
+
}),
|
|
163
|
+
[counter],
|
|
164
|
+
);
|
|
126
165
|
|
|
127
|
-
//
|
|
128
|
-
|
|
166
|
+
// ...
|
|
167
|
+
};
|
|
129
168
|
```
|
|
130
169
|
|
|
131
170
|
## Ops
|
|
132
171
|
|
|
172
|
+
An op is an invertible pair of `Operation` halves. Every half uses one of three verbs:
|
|
173
|
+
|
|
133
174
|
```ts
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
175
|
+
type OperationPath = ReadonlyArray<string | number>;
|
|
176
|
+
|
|
177
|
+
type Operation =
|
|
178
|
+
| { readonly op: "add"; readonly path: OperationPath; readonly value: unknown }
|
|
179
|
+
| { readonly op: "replace"; readonly path: OperationPath; readonly value: unknown }
|
|
180
|
+
| { readonly op: "remove"; readonly path: OperationPath };
|
|
181
|
+
|
|
182
|
+
interface Op {
|
|
183
|
+
readonly do: Operation;
|
|
184
|
+
readonly undo: Operation;
|
|
185
|
+
}
|
|
141
186
|
```
|
|
142
187
|
|
|
143
|
-
|
|
188
|
+
`applyOps` puts them back on a state, so a history is a list of ops and an undo is their `undo` halves in reverse.
|
|
144
189
|
|
|
145
|
-
|
|
190
|
+
```tsx
|
|
191
|
+
import { useEffect, useRef } from "react";
|
|
192
|
+
import { applyOps, subscribe, useMutableState, type Op } from "opshot";
|
|
146
193
|
|
|
147
|
-
|
|
194
|
+
const replay = {};
|
|
148
195
|
|
|
149
|
-
|
|
196
|
+
const Counter = () => {
|
|
197
|
+
const counter = useMutableState({ count: 0 });
|
|
198
|
+
const history = useRef<Array<ReadonlyArray<Op>>>([]);
|
|
150
199
|
|
|
151
|
-
|
|
200
|
+
useEffect(
|
|
201
|
+
() =>
|
|
202
|
+
subscribe(counter, (ops, meta) => {
|
|
203
|
+
// Skip our own replays, so undo doesn't record itself.
|
|
204
|
+
if (meta === replay) return;
|
|
152
205
|
|
|
153
|
-
|
|
206
|
+
history.current.push(ops);
|
|
207
|
+
}),
|
|
208
|
+
[counter],
|
|
209
|
+
);
|
|
154
210
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
import { createMeta } from "opshot";
|
|
158
|
-
import { useTrackedState } from "opshot/react";
|
|
211
|
+
const undo = () => {
|
|
212
|
+
const ops = history.current.pop();
|
|
159
213
|
|
|
160
|
-
|
|
161
|
-
replay?: boolean;
|
|
162
|
-
}
|
|
214
|
+
if (!ops) return;
|
|
163
215
|
|
|
164
|
-
|
|
165
|
-
|
|
216
|
+
applyOps(
|
|
217
|
+
counter,
|
|
218
|
+
[...ops].reverse().map((op) => op.undo),
|
|
219
|
+
replay,
|
|
220
|
+
);
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
return (
|
|
224
|
+
<>
|
|
225
|
+
<button onClick={() => counter.count++}>+</button>
|
|
226
|
+
<button onClick={undo}>Undo</button>
|
|
227
|
+
</>
|
|
228
|
+
);
|
|
229
|
+
};
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
Replay is exact for anything opshot can see: plain data. State behind a constraint is the exception.
|
|
233
|
+
|
|
234
|
+
If your state is JSON serializable, **then ops are too**.
|
|
235
|
+
|
|
236
|
+
## Groups
|
|
237
|
+
|
|
238
|
+
A group creates states and hears every op from the states it created: one stream for history, sync, persistence, etc.
|
|
239
|
+
|
|
240
|
+
```tsx
|
|
241
|
+
import { useEffect } from "react";
|
|
242
|
+
import { subscribe, useGroup, useMutableState } from "opshot";
|
|
166
243
|
|
|
167
244
|
const Editor = () => {
|
|
168
|
-
const
|
|
245
|
+
const group = useGroup();
|
|
169
246
|
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
const
|
|
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);
|
|
173
250
|
|
|
174
251
|
useEffect(
|
|
175
252
|
() =>
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (meta.replay) return;
|
|
180
|
-
|
|
253
|
+
// Fires for doc, selection, and every other state the group created.
|
|
254
|
+
// state is whichever one changed.
|
|
255
|
+
subscribe(group, (state, ops, meta) => {
|
|
181
256
|
// ...
|
|
182
257
|
}),
|
|
183
|
-
[
|
|
258
|
+
[group],
|
|
184
259
|
);
|
|
185
260
|
|
|
186
261
|
// ...
|
|
187
262
|
};
|
|
188
263
|
```
|
|
189
264
|
|
|
190
|
-
##
|
|
265
|
+
## Channels
|
|
191
266
|
|
|
192
|
-
A
|
|
267
|
+
A channel binds `transact`, `subscribe`, and `applyOps` to a typed meta convention, so a listener can tell its own writes from everyone else's.
|
|
193
268
|
|
|
194
269
|
```tsx
|
|
195
270
|
import { useEffect } from "react";
|
|
196
|
-
import {
|
|
271
|
+
import { createChannel, useMutableState } from "opshot";
|
|
197
272
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
273
|
+
interface DocumentMeta {
|
|
274
|
+
replay?: boolean;
|
|
275
|
+
source?: string;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
const docChannel = createChannel<DocumentMeta>({ source: "editor" }); // set defaults
|
|
201
279
|
|
|
202
|
-
|
|
203
|
-
const doc =
|
|
280
|
+
const TitleBar = () => {
|
|
281
|
+
const doc = useMutableState({ title: "Untitled" });
|
|
204
282
|
|
|
205
283
|
useEffect(
|
|
206
284
|
() =>
|
|
207
|
-
|
|
208
|
-
|
|
285
|
+
docChannel.subscribe(doc, (ops, context) => {
|
|
286
|
+
// A bare write, or a transact from another channel: meta is unknown.
|
|
287
|
+
if (!context.isTransaction) return;
|
|
288
|
+
|
|
289
|
+
// Own-channel transaction: meta is typed, with defaults merged.
|
|
290
|
+
if (context.meta.replay) return;
|
|
291
|
+
|
|
209
292
|
// ...
|
|
210
293
|
}),
|
|
211
|
-
[
|
|
294
|
+
[doc],
|
|
212
295
|
);
|
|
213
296
|
|
|
297
|
+
const rename = () => {
|
|
298
|
+
docChannel.transact(doc, () => {
|
|
299
|
+
doc.title = "Draft";
|
|
300
|
+
});
|
|
301
|
+
};
|
|
302
|
+
|
|
214
303
|
// ...
|
|
215
304
|
};
|
|
216
305
|
```
|
|
306
|
+
|
|
307
|
+
## License
|
|
308
|
+
|
|
309
|
+
[MIT](LICENSE)
|
package/dist/index.d.ts
CHANGED
|
@@ -1,56 +1,185 @@
|
|
|
1
|
-
import {
|
|
2
|
-
export { Snapshot, ref } from 'valtio/vanilla';
|
|
1
|
+
import { ComponentType, FC } from 'react';
|
|
3
2
|
|
|
4
|
-
type
|
|
3
|
+
type OperationPath = ReadonlyArray<string | number>;
|
|
4
|
+
|
|
5
|
+
interface AddOperation {
|
|
5
6
|
readonly op: "add";
|
|
6
|
-
readonly path:
|
|
7
|
+
readonly path: OperationPath;
|
|
7
8
|
readonly value: unknown;
|
|
8
|
-
}
|
|
9
|
+
}
|
|
10
|
+
interface ReplaceOperation {
|
|
9
11
|
readonly op: "replace";
|
|
10
|
-
readonly path:
|
|
12
|
+
readonly path: OperationPath;
|
|
11
13
|
readonly value: unknown;
|
|
12
|
-
}
|
|
14
|
+
}
|
|
15
|
+
interface RemoveOperation {
|
|
13
16
|
readonly op: "remove";
|
|
14
|
-
readonly path:
|
|
15
|
-
}
|
|
17
|
+
readonly path: OperationPath;
|
|
18
|
+
}
|
|
19
|
+
type Operation = AddOperation | ReplaceOperation | RemoveOperation;
|
|
16
20
|
interface Op {
|
|
17
|
-
readonly do:
|
|
18
|
-
readonly undo:
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
type
|
|
23
|
-
|
|
24
|
-
interface
|
|
25
|
-
|
|
26
|
-
readonly [metaIn]?: (value: In) => void;
|
|
27
|
-
}
|
|
28
|
-
type Mutate<T extends object, In extends object = MetaRecord> = (callback: (mutable: T) => void, ...meta: {} extends In ? [meta?: In] : [meta: In]) => void;
|
|
29
|
-
type StateListener<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = (state: State<T, In, Out>, ops: Array<Op>, meta: Out) => void;
|
|
30
|
-
interface OpshotHandle<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> {
|
|
31
|
-
readonly unsafeMutable: object;
|
|
32
|
-
readonly isMutating: boolean;
|
|
33
|
-
readonly subscribe: (listener: StateListener<T, In, Out>) => () => void;
|
|
34
|
-
readonly isSameState: (other: unknown) => boolean;
|
|
35
|
-
readonly unwrap: () => Snapshot<T>;
|
|
36
|
-
}
|
|
37
|
-
type State<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = Snapshot<T> & {
|
|
38
|
-
readonly mutate: Mutate<T, In>;
|
|
39
|
-
readonly op: OpshotHandle<T, In, Out>;
|
|
40
|
-
};
|
|
41
|
-
type DefineCallback<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = (mutate: Mutate<T, In>, get: () => State<T, In, Out>) => T;
|
|
42
|
-
type Define<T extends object, In extends object = MetaRecord, Out extends object = MetaRecord> = DefineCallback<T, In, Out> | T;
|
|
43
|
-
declare function createMeta<M extends object>(): Meta<M, M>;
|
|
44
|
-
declare function createMeta<M extends object>(defaults: M): Meta<Partial<M>, M>;
|
|
45
|
-
declare function createState<T extends object>(define: Define<T>): State<T>;
|
|
46
|
-
declare function createState<T extends object, In extends object, Out extends object>(define: Define<T, In, Out>, meta: Meta<In, Out>): State<T, In, Out>;
|
|
47
|
-
declare function isState(value: unknown): value is State<object>;
|
|
48
|
-
|
|
49
|
-
interface Group<In extends object = MetaRecord, Out extends object = MetaRecord> {
|
|
50
|
-
createState<T extends object>(define: Define<T, In, Out>): State<T, In, Out>;
|
|
51
|
-
subscribe(listener: StateListener<object, In, Out>): () => void;
|
|
21
|
+
readonly do: Operation;
|
|
22
|
+
readonly undo: Operation;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
type StateListener = (ops: ReadonlyArray<Op>, meta: unknown) => void;
|
|
26
|
+
type GroupListener = (state: object, ops: ReadonlyArray<Op>, meta: unknown) => void;
|
|
27
|
+
|
|
28
|
+
interface Group {
|
|
29
|
+
createMutableState<T extends object>(properties: T): T;
|
|
52
30
|
}
|
|
53
31
|
declare function createGroup(): Group;
|
|
54
|
-
declare function createGroup<In extends object, Out extends object>(meta: Meta<In, Out>): Group<In, Out>;
|
|
55
32
|
|
|
56
|
-
|
|
33
|
+
type Context<M> = {
|
|
34
|
+
readonly isTransaction: true;
|
|
35
|
+
readonly meta: M;
|
|
36
|
+
} | {
|
|
37
|
+
readonly isTransaction: false;
|
|
38
|
+
readonly meta: unknown;
|
|
39
|
+
};
|
|
40
|
+
declare function subscribe(group: Group, listener: GroupListener): () => void;
|
|
41
|
+
declare function subscribe(state: object, listener: StateListener): () => void;
|
|
42
|
+
|
|
43
|
+
interface Channel<M extends object> {
|
|
44
|
+
transact(state: object, mutate: () => void, meta?: Partial<M>): void;
|
|
45
|
+
subscribe(group: Group, listener: (state: object, ops: ReadonlyArray<Op>, context: Context<M>) => void): () => void;
|
|
46
|
+
subscribe(state: object, listener: (ops: ReadonlyArray<Op>, context: Context<M>) => void): () => void;
|
|
47
|
+
applyOps(state: object, operations: ReadonlyArray<Operation>, meta?: Partial<M>): void;
|
|
48
|
+
}
|
|
49
|
+
declare function createChannel<M extends object>(defaults?: M): Channel<M>;
|
|
50
|
+
|
|
51
|
+
declare function createMutableState<T extends object>(properties: T, group?: Group): T;
|
|
52
|
+
|
|
53
|
+
declare function identify(value: object): object;
|
|
54
|
+
declare function isSameIdentity(first: object, second: object): boolean;
|
|
55
|
+
|
|
56
|
+
declare function isState(value: unknown): value is object;
|
|
57
|
+
|
|
58
|
+
declare function applyOps(state: object, operations: ReadonlyArray<Operation>, meta?: unknown): void;
|
|
59
|
+
|
|
60
|
+
declare function diffSnapshots(before: object, after: object): Array<Op>;
|
|
61
|
+
|
|
62
|
+
declare const ignoredMarker: unique symbol;
|
|
63
|
+
type Ignored<T extends object> = T & {
|
|
64
|
+
readonly [ignoredMarker]: true;
|
|
65
|
+
};
|
|
66
|
+
declare const ignore: <T extends object>(value: T) => Ignored<T>;
|
|
67
|
+
|
|
68
|
+
declare const unsafeTrackedBrand: unique symbol;
|
|
69
|
+
type UnsafeTracked<T extends object> = T & {
|
|
70
|
+
readonly [unsafeTrackedBrand]: true;
|
|
71
|
+
};
|
|
72
|
+
declare function unsafeTrack<T extends object>(value: T): UnsafeTracked<T>;
|
|
73
|
+
|
|
74
|
+
type DateConstructorArgs = [] | [value: number | string] | [
|
|
75
|
+
year: number,
|
|
76
|
+
monthIndex: number,
|
|
77
|
+
date?: number,
|
|
78
|
+
hours?: number,
|
|
79
|
+
minutes?: number,
|
|
80
|
+
seconds?: number,
|
|
81
|
+
milliseconds?: number
|
|
82
|
+
];
|
|
83
|
+
declare class TrackedDate {
|
|
84
|
+
private epochMs;
|
|
85
|
+
constructor(...args: DateConstructorArgs);
|
|
86
|
+
private readDate;
|
|
87
|
+
private write;
|
|
88
|
+
toString(): string;
|
|
89
|
+
toDateString(): string;
|
|
90
|
+
toTimeString(): string;
|
|
91
|
+
toLocaleString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
|
|
92
|
+
toLocaleDateString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
|
|
93
|
+
toLocaleTimeString(locales?: Intl.LocalesArgument, options?: Intl.DateTimeFormatOptions): string;
|
|
94
|
+
valueOf(): number;
|
|
95
|
+
getTime(): number;
|
|
96
|
+
getFullYear(): number;
|
|
97
|
+
getYear(): number;
|
|
98
|
+
getUTCFullYear(): number;
|
|
99
|
+
getMonth(): number;
|
|
100
|
+
getUTCMonth(): number;
|
|
101
|
+
getDate(): number;
|
|
102
|
+
getUTCDate(): number;
|
|
103
|
+
getDay(): number;
|
|
104
|
+
getUTCDay(): number;
|
|
105
|
+
getHours(): number;
|
|
106
|
+
getUTCHours(): number;
|
|
107
|
+
getMinutes(): number;
|
|
108
|
+
getUTCMinutes(): number;
|
|
109
|
+
getSeconds(): number;
|
|
110
|
+
getUTCSeconds(): number;
|
|
111
|
+
getMilliseconds(): number;
|
|
112
|
+
getUTCMilliseconds(): number;
|
|
113
|
+
getTimezoneOffset(): number;
|
|
114
|
+
setYear(year: number): number;
|
|
115
|
+
setTime(...args: [time: number]): number;
|
|
116
|
+
setMilliseconds(...args: [milliseconds: number]): number;
|
|
117
|
+
setUTCMilliseconds(...args: [milliseconds: number]): number;
|
|
118
|
+
setSeconds(...args: [seconds: number, milliseconds?: number]): number;
|
|
119
|
+
setUTCSeconds(...args: [seconds: number, milliseconds?: number]): number;
|
|
120
|
+
setMinutes(...args: [minutes: number, seconds?: number, milliseconds?: number]): number;
|
|
121
|
+
setUTCMinutes(...args: [minutes: number, seconds?: number, milliseconds?: number]): number;
|
|
122
|
+
setHours(...args: [hours: number, minutes?: number, seconds?: number, milliseconds?: number]): number;
|
|
123
|
+
setUTCHours(...args: [hours: number, minutes?: number, seconds?: number, milliseconds?: number]): number;
|
|
124
|
+
setDate(...args: [dateValue: number]): number;
|
|
125
|
+
setUTCDate(...args: [dateValue: number]): number;
|
|
126
|
+
setMonth(...args: [month: number, dateValue?: number]): number;
|
|
127
|
+
setUTCMonth(...args: [month: number, dateValue?: number]): number;
|
|
128
|
+
setFullYear(...args: [year: number, month?: number, dateValue?: number]): number;
|
|
129
|
+
setUTCFullYear(...args: [year: number, month?: number, dateValue?: number]): number;
|
|
130
|
+
toUTCString(): string;
|
|
131
|
+
toGMTString(): string;
|
|
132
|
+
toISOString(): string;
|
|
133
|
+
[Symbol.toPrimitive](hint: "default" | "string" | "number"): string | number;
|
|
134
|
+
readonly [Symbol.toStringTag]: "TrackedDate";
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
declare class TrackedMap<K, V> {
|
|
138
|
+
private slots;
|
|
139
|
+
private index;
|
|
140
|
+
private count;
|
|
141
|
+
constructor(entries?: Iterable<readonly [K, V]>);
|
|
142
|
+
get size(): number;
|
|
143
|
+
has(key: K): boolean;
|
|
144
|
+
get(key: K): V | undefined;
|
|
145
|
+
set(key: K, value: V): this;
|
|
146
|
+
delete(key: K): boolean;
|
|
147
|
+
clear(): void;
|
|
148
|
+
entries(): IterableIterator<[K, V]>;
|
|
149
|
+
keys(): IterableIterator<K>;
|
|
150
|
+
values(): IterableIterator<V>;
|
|
151
|
+
forEach(callback: (value: V, key: K, map: TrackedMap<K, V>) => void): void;
|
|
152
|
+
[Symbol.iterator](): IterableIterator<[K, V]>;
|
|
153
|
+
readonly [Symbol.toStringTag]: "TrackedMap";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
declare class TrackedSet<T> {
|
|
157
|
+
private slots;
|
|
158
|
+
private index;
|
|
159
|
+
private count;
|
|
160
|
+
constructor(values?: Iterable<T>);
|
|
161
|
+
get size(): number;
|
|
162
|
+
has(value: T): boolean;
|
|
163
|
+
add(value: T): this;
|
|
164
|
+
delete(value: T): boolean;
|
|
165
|
+
clear(): void;
|
|
166
|
+
entries(): IterableIterator<[T, T]>;
|
|
167
|
+
keys(): IterableIterator<T>;
|
|
168
|
+
values(): IterableIterator<T>;
|
|
169
|
+
forEach(callback: (value: T, key: T, set: TrackedSet<T>) => void): void;
|
|
170
|
+
[Symbol.iterator](): IterableIterator<T>;
|
|
171
|
+
readonly [Symbol.toStringTag]: "TrackedSet";
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
declare function transact(state: object, mutate: () => void, meta?: unknown): void;
|
|
175
|
+
|
|
176
|
+
interface ScopeOptions {
|
|
177
|
+
readonly maxDepth?: number;
|
|
178
|
+
}
|
|
179
|
+
declare function scope<P extends object>(Component: ComponentType<P>, options?: ScopeOptions): FC<P>;
|
|
180
|
+
|
|
181
|
+
declare function useGroup(): Group;
|
|
182
|
+
|
|
183
|
+
declare function useMutableState<T extends object>(properties: T, group?: Group): T;
|
|
184
|
+
|
|
185
|
+
export { type AddOperation, type Channel, type Context, type Group, type GroupListener, type Ignored, type Op, type Operation, type OperationPath, type RemoveOperation, type ReplaceOperation, type ScopeOptions, type StateListener, TrackedDate, TrackedMap, TrackedSet, type UnsafeTracked, applyOps, createChannel, createGroup, createMutableState, diffSnapshots, identify, ignore, isSameIdentity, isState, scope, subscribe, transact, unsafeTrack, useGroup, useMutableState };
|