opshot 0.2.1 → 0.3.1
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 +170 -78
- package/dist/index.d.ts +175 -46
- package/dist/index.js +2260 -118
- 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,235 @@ 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
|
+
- Arrow methods on classes (they write to the original object, not the tracked one)
|
|
126
|
+
- Array subclasses (the prototype is lost when copied)
|
|
127
|
+
|
|
128
|
+
Use `ignore` or `unsafeTrack` when dealing with these.
|
|
129
|
+
|
|
130
|
+
## Tracked collections
|
|
106
131
|
|
|
107
|
-
|
|
132
|
+
`TrackedMap`, `TrackedSet`, and `TrackedDate` stand in for the built-ins opshot rejects. They have the exact same API as their counterparts.
|
|
108
133
|
|
|
109
134
|
```ts
|
|
110
|
-
|
|
111
|
-
counter.mutate((mutable) => mutable.count++, { transactionKey: "drag" });
|
|
135
|
+
import { TrackedMap, useMutableState } from "opshot";
|
|
112
136
|
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
137
|
+
const state = useMutableState({ index: new TrackedMap<string, number>() });
|
|
138
|
+
|
|
139
|
+
state.index.set("a", 1);
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Subscribe
|
|
117
143
|
|
|
118
|
-
|
|
119
|
-
counter.op.isSameState(other);
|
|
144
|
+
`subscribe` hears every change to a state.
|
|
120
145
|
|
|
121
|
-
|
|
122
|
-
|
|
146
|
+
```tsx
|
|
147
|
+
import { useEffect } from "react";
|
|
148
|
+
import { subscribe, useMutableState } from "opshot";
|
|
123
149
|
|
|
124
|
-
|
|
125
|
-
counter
|
|
150
|
+
const Counter = () => {
|
|
151
|
+
const counter = useMutableState({ count: 0 });
|
|
152
|
+
|
|
153
|
+
useEffect(
|
|
154
|
+
() =>
|
|
155
|
+
subscribe(counter, (ops, meta) => {
|
|
156
|
+
// ops: [{
|
|
157
|
+
// do: { op: "replace", path: ["count"], value: 1 },
|
|
158
|
+
// undo: { op: "replace", path: ["count"], value: 0 },
|
|
159
|
+
// }]
|
|
160
|
+
// meta: whatever the writer passed, or undefined for bare writes
|
|
161
|
+
}),
|
|
162
|
+
[counter],
|
|
163
|
+
);
|
|
126
164
|
|
|
127
|
-
//
|
|
128
|
-
|
|
165
|
+
// ...
|
|
166
|
+
};
|
|
129
167
|
```
|
|
130
168
|
|
|
131
169
|
## Ops
|
|
132
170
|
|
|
171
|
+
An op is an invertible pair of `Operation` halves. Every half uses one of three verbs:
|
|
172
|
+
|
|
133
173
|
```ts
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
174
|
+
type OperationPath = ReadonlyArray<string | number>;
|
|
175
|
+
|
|
176
|
+
type Operation =
|
|
177
|
+
| { readonly op: "add"; readonly path: OperationPath; readonly value: unknown }
|
|
178
|
+
| { readonly op: "replace"; readonly path: OperationPath; readonly value: unknown }
|
|
179
|
+
| { readonly op: "remove"; readonly path: OperationPath };
|
|
180
|
+
|
|
181
|
+
interface Op {
|
|
182
|
+
readonly do: Operation;
|
|
183
|
+
readonly undo: Operation;
|
|
184
|
+
}
|
|
141
185
|
```
|
|
142
186
|
|
|
143
|
-
|
|
187
|
+
`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
188
|
|
|
145
|
-
|
|
189
|
+
```tsx
|
|
190
|
+
import { useEffect, useRef } from "react";
|
|
191
|
+
import { applyOps, subscribe, useMutableState, type Op } from "opshot";
|
|
146
192
|
|
|
147
|
-
|
|
193
|
+
const replay = {};
|
|
148
194
|
|
|
149
|
-
|
|
195
|
+
const Counter = () => {
|
|
196
|
+
const counter = useMutableState({ count: 0 });
|
|
197
|
+
const history = useRef<Array<ReadonlyArray<Op>>>([]);
|
|
150
198
|
|
|
151
|
-
|
|
199
|
+
useEffect(
|
|
200
|
+
() =>
|
|
201
|
+
subscribe(counter, (ops, meta) => {
|
|
202
|
+
// Skip our own replays, so undo doesn't record itself.
|
|
203
|
+
if (meta === replay) return;
|
|
152
204
|
|
|
153
|
-
|
|
205
|
+
history.current.push(ops);
|
|
206
|
+
}),
|
|
207
|
+
[counter],
|
|
208
|
+
);
|
|
154
209
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
import { createMeta } from "opshot";
|
|
158
|
-
import { useTrackedState } from "opshot/react";
|
|
210
|
+
const undo = () => {
|
|
211
|
+
const ops = history.current.pop();
|
|
159
212
|
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
213
|
+
if (!ops) return;
|
|
214
|
+
|
|
215
|
+
applyOps(
|
|
216
|
+
counter,
|
|
217
|
+
[...ops].reverse().map((op) => op.undo),
|
|
218
|
+
replay,
|
|
219
|
+
);
|
|
220
|
+
};
|
|
163
221
|
|
|
164
|
-
|
|
165
|
-
|
|
222
|
+
return (
|
|
223
|
+
<>
|
|
224
|
+
<button onClick={() => counter.count++}>+</button>
|
|
225
|
+
<button onClick={undo}>Undo</button>
|
|
226
|
+
</>
|
|
227
|
+
);
|
|
228
|
+
};
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
Replay is exact for anything opshot can see: plain data. State behind a constraint is the exception.
|
|
232
|
+
|
|
233
|
+
If your state is JSON serializable, **then ops are too**.
|
|
234
|
+
|
|
235
|
+
## Groups
|
|
236
|
+
|
|
237
|
+
A group creates states and hears every op from the states it created: one stream for history, sync, persistence, etc.
|
|
238
|
+
|
|
239
|
+
```tsx
|
|
240
|
+
import { useEffect } from "react";
|
|
241
|
+
import { subscribe, useGroup, useMutableState } from "opshot";
|
|
166
242
|
|
|
167
243
|
const Editor = () => {
|
|
168
|
-
const
|
|
244
|
+
const group = useGroup();
|
|
169
245
|
|
|
170
|
-
//
|
|
171
|
-
|
|
172
|
-
const
|
|
246
|
+
// Created through the group, so their ops reach the group's subscribers.
|
|
247
|
+
const doc = useMutableState({ items: new Array<string>() }, group);
|
|
248
|
+
const selection = useMutableState({ index: 0 }, group);
|
|
173
249
|
|
|
174
250
|
useEffect(
|
|
175
251
|
() =>
|
|
176
|
-
//
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
if (meta.replay) return;
|
|
180
|
-
|
|
252
|
+
// Fires for doc, selection, and every other state the group created.
|
|
253
|
+
// state is whichever one changed.
|
|
254
|
+
subscribe(group, (state, ops, meta) => {
|
|
181
255
|
// ...
|
|
182
256
|
}),
|
|
183
|
-
[
|
|
257
|
+
[group],
|
|
184
258
|
);
|
|
185
259
|
|
|
186
260
|
// ...
|
|
187
261
|
};
|
|
188
262
|
```
|
|
189
263
|
|
|
190
|
-
##
|
|
264
|
+
## Channels
|
|
191
265
|
|
|
192
|
-
A
|
|
266
|
+
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
267
|
|
|
194
268
|
```tsx
|
|
195
269
|
import { useEffect } from "react";
|
|
196
|
-
import {
|
|
270
|
+
import { createChannel, useMutableState } from "opshot";
|
|
197
271
|
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
272
|
+
interface DocumentMeta {
|
|
273
|
+
replay?: boolean;
|
|
274
|
+
source?: string;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const docChannel = createChannel<DocumentMeta>({ source: "editor" }); // set defaults
|
|
201
278
|
|
|
202
|
-
|
|
203
|
-
const doc =
|
|
279
|
+
const TitleBar = () => {
|
|
280
|
+
const doc = useMutableState({ title: "Untitled" });
|
|
204
281
|
|
|
205
282
|
useEffect(
|
|
206
283
|
() =>
|
|
207
|
-
|
|
208
|
-
|
|
284
|
+
docChannel.subscribe(doc, (ops, context) => {
|
|
285
|
+
// A bare write, or a transact from another channel: meta is unknown.
|
|
286
|
+
if (!context.isTransaction) return;
|
|
287
|
+
|
|
288
|
+
// Own-channel transaction: meta is typed, with defaults merged.
|
|
289
|
+
if (context.meta.replay) return;
|
|
290
|
+
|
|
209
291
|
// ...
|
|
210
292
|
}),
|
|
211
|
-
[
|
|
293
|
+
[doc],
|
|
212
294
|
);
|
|
213
295
|
|
|
296
|
+
const rename = () => {
|
|
297
|
+
docChannel.transact(doc, () => {
|
|
298
|
+
doc.title = "Draft";
|
|
299
|
+
});
|
|
300
|
+
};
|
|
301
|
+
|
|
214
302
|
// ...
|
|
215
303
|
};
|
|
216
304
|
```
|
|
305
|
+
|
|
306
|
+
## License
|
|
307
|
+
|
|
308
|
+
[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 };
|