@pluv/react 0.11.1 → 0.12.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/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +255 -0
- package/dist/index.d.mts +9 -4
- package/dist/index.d.ts +9 -4
- package/dist/index.js +56 -6
- package/dist/index.mjs +56 -6
- package/package.json +8 -8
- package/src/createBundle.tsx +5 -5
- package/src/createRoomBundle.tsx +135 -59
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/react@0.
|
|
2
|
+
> @pluv/react@0.12.1 build /home/runner/work/pluv/pluv/packages/react
|
|
3
3
|
> tsup src/index.ts --format esm,cjs --dts --external react
|
|
4
4
|
|
|
5
5
|
[34mCLI[39m Building entry: src/index.ts
|
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
[34mCLI[39m Target: es6
|
|
9
9
|
[34mESM[39m Build start
|
|
10
10
|
[34mCJS[39m Build start
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
14
|
-
[
|
|
11
|
+
[32mCJS[39m [1mdist/index.js [22m[32m12.46 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 102ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m9.88 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 102ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m4.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m4.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 7343ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m4.71 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m4.71 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,260 @@
|
|
|
1
1
|
# @pluv/react
|
|
2
2
|
|
|
3
|
+
## 0.12.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- cae08aa: Updated storage from `getStorage` to never return null
|
|
8
|
+
- Updated dependencies [cae08aa]
|
|
9
|
+
- @pluv/client@0.12.1
|
|
10
|
+
- @pluv/types@0.12.1
|
|
11
|
+
|
|
12
|
+
## 0.12.0
|
|
13
|
+
|
|
14
|
+
### Minor Changes
|
|
15
|
+
|
|
16
|
+
- 436040b: Added ability to undo and redo changes to storage.
|
|
17
|
+
|
|
18
|
+
## @pluv/crdt-yjs
|
|
19
|
+
|
|
20
|
+
`@pluv/crdt-yjs` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `trackOrigins`.
|
|
21
|
+
|
|
22
|
+
Refer to the code-example below to better understand how to undo and redo with your doc.
|
|
23
|
+
|
|
24
|
+
```ts
|
|
25
|
+
// Example
|
|
26
|
+
import { array, doc } from "@pluv/crdt-yjs";
|
|
27
|
+
|
|
28
|
+
// Create your doc with your shared-types
|
|
29
|
+
const myDoc = doc({
|
|
30
|
+
messages: array<string>([]),
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* @description Track origins to enable undos and redos for your document.
|
|
35
|
+
* trackOrigins must be called before any storage mutations, to enable those
|
|
36
|
+
* mutations to be undone/redone.
|
|
37
|
+
*/
|
|
38
|
+
myDoc.trackOrigins({
|
|
39
|
+
/**
|
|
40
|
+
* @description This is the same `captureTimeout` option from yjs's UndoManager.
|
|
41
|
+
* This specifies a number in ms, during which edits are merged together to be
|
|
42
|
+
* undone together. Set this to 0, to track each transacted change individually.
|
|
43
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
44
|
+
* @default 500
|
|
45
|
+
*/
|
|
46
|
+
captureTimeout: 500,
|
|
47
|
+
/**
|
|
48
|
+
* @desription This is the same `trackedOrigins` option from yjs's UndoManager.
|
|
49
|
+
* This specifies transaction origins (strings only) to filter which transactions
|
|
50
|
+
* can be undone.
|
|
51
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
52
|
+
* @default undefined
|
|
53
|
+
*/
|
|
54
|
+
trackedOrigins: ["user-123"],
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @description Check whether calling undo will mutate storage
|
|
59
|
+
* @returns boolean
|
|
60
|
+
*/
|
|
61
|
+
myDoc.canUndo();
|
|
62
|
+
/**
|
|
63
|
+
* @description Check whether calling redo will mutate storage
|
|
64
|
+
* @returns boolean
|
|
65
|
+
*/
|
|
66
|
+
myDoc.canRedo();
|
|
67
|
+
|
|
68
|
+
// Perform a storage mutation within a transaction so that it can be affected
|
|
69
|
+
// by undo/redo operations.
|
|
70
|
+
myDoc.transact(() => {
|
|
71
|
+
myDoc.get("messages").push(["hello world!"]);
|
|
72
|
+
}, "user-123");
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* @description Undoes the last valid mutation to storage
|
|
76
|
+
*/
|
|
77
|
+
myDoc.undo();
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* @description Re-applies the last undone mutation to storage
|
|
81
|
+
*/
|
|
82
|
+
myDoc.redo();
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## @pluv/client
|
|
86
|
+
|
|
87
|
+
`@pluv/client`'s `PluvRoom` and `MockedRoom` now exposes 5 new methods: `canRedo`, `canUndo`, `redo`, `undo` and `transact`.
|
|
88
|
+
|
|
89
|
+
Refer to the code-example below to better understand how to undo and redo with your `PluvRoom`.
|
|
90
|
+
|
|
91
|
+
```ts
|
|
92
|
+
import { createClient, y } from "@pluv/client";
|
|
93
|
+
|
|
94
|
+
const client = createClient({});
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @description When a room is created, undo/redo will automatically
|
|
98
|
+
* be configured to filter for changes made by the connected user
|
|
99
|
+
* (so that users only undo/redo their changes).
|
|
100
|
+
*/
|
|
101
|
+
const room = client.createRoom("my-room", {
|
|
102
|
+
initialStorage: () => ({
|
|
103
|
+
messages: y.array<string>([]),
|
|
104
|
+
}),
|
|
105
|
+
/**
|
|
106
|
+
* @description This is the same `captureTimeout` option from yjs's UndoManager.
|
|
107
|
+
* This specifies a number in ms, during which edits are merged together to be
|
|
108
|
+
* undone together. Set this to 0, to track each transacted change individually.
|
|
109
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
110
|
+
* @default 500
|
|
111
|
+
*/
|
|
112
|
+
captureTimeout: 500,
|
|
113
|
+
/**
|
|
114
|
+
* @desription This is the same `trackedOrigins` option from yjs's UndoManager.
|
|
115
|
+
* This specifies transaction origins (strings only) to filter which transactions
|
|
116
|
+
* can be undone.
|
|
117
|
+
* When omitted, the user's connection id will be tracked. When provided,
|
|
118
|
+
* specifies additional tracked origins besides the user's connection id.
|
|
119
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
120
|
+
* @default undefined
|
|
121
|
+
*/
|
|
122
|
+
trackedOrigins: ["user-123"],
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* @description Check whether calling undo will mutate storage
|
|
127
|
+
* @returns boolean
|
|
128
|
+
*/
|
|
129
|
+
room.canUndo();
|
|
130
|
+
/**
|
|
131
|
+
* @description Check whether calling redo will mutate storage
|
|
132
|
+
* @returns boolean
|
|
133
|
+
*/
|
|
134
|
+
room.canRedo();
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @description Calling transact will enable a storage mutation to be undone/redone.
|
|
138
|
+
* When called without an origin, the origin will default to the user's connection
|
|
139
|
+
* id.
|
|
140
|
+
*
|
|
141
|
+
* You can specify a 2nd parameter to transact with a different transaction origin.
|
|
142
|
+
*/
|
|
143
|
+
room.transact(() => {
|
|
144
|
+
room.get("messages").push(["hello world!"]);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// This will also be undoable because `"user-123"` is a tracked origin.
|
|
148
|
+
room.transact(() => {
|
|
149
|
+
room.get("messages").push(["hello world!"]);
|
|
150
|
+
}, "user-123");
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* @description Undoes the last valid mutation to storage
|
|
154
|
+
*/
|
|
155
|
+
room.undo();
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* @description Re-applies the last undone mutation to storage
|
|
159
|
+
*/
|
|
160
|
+
room.redo();
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## @pluv/react
|
|
164
|
+
|
|
165
|
+
`@pluv/react`'s `createRoomBundle` now exposes 5 new react hooks: `usePluvCanRedo`, `usePluvCanUndo`, `usePluvRedo`, `usePluvUndo` and `usePluvTransact`.
|
|
166
|
+
|
|
167
|
+
Refer to the code-example below to better understand how to undo and redo with your `createRoomBundle`.
|
|
168
|
+
|
|
169
|
+
```tsx
|
|
170
|
+
import { createBundle, createClient, y } from "@pluv/react";
|
|
171
|
+
import { type io } from "./io";
|
|
172
|
+
|
|
173
|
+
const client = createClient<typeof io>();
|
|
174
|
+
|
|
175
|
+
const { createRoomBundle } = createBundle(client);
|
|
176
|
+
|
|
177
|
+
const {
|
|
178
|
+
usePluvCanRedo,
|
|
179
|
+
usePluvCanUndo,
|
|
180
|
+
usePluvRedo,
|
|
181
|
+
usePluvStorage,
|
|
182
|
+
usePluvTransact,
|
|
183
|
+
usePluvUndo,
|
|
184
|
+
} = createRoomBundle({
|
|
185
|
+
initialStorage: () => ({
|
|
186
|
+
messages: y.array<string>([]),
|
|
187
|
+
}),
|
|
188
|
+
/**
|
|
189
|
+
* @description This is the same `captureTimeout` option from yjs's UndoManager.
|
|
190
|
+
* This specifies a number in ms, during which edits are merged together to be
|
|
191
|
+
* undone together. Set this to 0, to track each transacted change individually.
|
|
192
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
193
|
+
* @default 500
|
|
194
|
+
*/
|
|
195
|
+
captureTimeout: 500,
|
|
196
|
+
/**
|
|
197
|
+
* @desription This is the same `trackedOrigins` option from yjs's UndoManager.
|
|
198
|
+
* This specifies transaction origins (strings only) to filter which transactions
|
|
199
|
+
* can be undone.
|
|
200
|
+
* When omitted, the user's connection id will be tracked. When provided,
|
|
201
|
+
* specifies additional tracked origins besides the user's connection id.
|
|
202
|
+
* @see (@link https://docs.yjs.dev/api/undo-manager)
|
|
203
|
+
* @default undefined
|
|
204
|
+
*/
|
|
205
|
+
trackedOrigins: ["user-123"],
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
/**
|
|
209
|
+
* @description Check whether calling undo will mutate storage
|
|
210
|
+
*/
|
|
211
|
+
const canUndo: boolean = usePluvCanUndo();
|
|
212
|
+
/**
|
|
213
|
+
* @description Check whether calling redo will mutate storage
|
|
214
|
+
*/
|
|
215
|
+
const canRedo: boolean = usePluvCanRedo();
|
|
216
|
+
|
|
217
|
+
const [messages, sharedType] = usePluvStorage("messages");
|
|
218
|
+
|
|
219
|
+
/**
|
|
220
|
+
* @description Calling transact will enable a storage mutation to be undone/redone.
|
|
221
|
+
* When called without an origin, the origin will default to the user's connection
|
|
222
|
+
* id.
|
|
223
|
+
*
|
|
224
|
+
* You can specify a 2nd parameter to transact with a different transaction origin.
|
|
225
|
+
*/
|
|
226
|
+
const transact = usePluvTransact();
|
|
227
|
+
|
|
228
|
+
transact(() => {
|
|
229
|
+
sharedType?.push(["hello world!"]);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
// This will also be undoable because `"user-123"` is a tracked origin.
|
|
233
|
+
transact(() => {
|
|
234
|
+
sharedType?.push(["hello world!"]);
|
|
235
|
+
}, "user-123");
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* @description Undoes the last valid mutation to storage
|
|
239
|
+
*/
|
|
240
|
+
const undo = usePluvUndo();
|
|
241
|
+
|
|
242
|
+
undo();
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* @description Re-applies the last undone mutation to storage
|
|
246
|
+
*/
|
|
247
|
+
const redo = usePluvRedo();
|
|
248
|
+
|
|
249
|
+
redo();
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
### Patch Changes
|
|
253
|
+
|
|
254
|
+
- Updated dependencies [436040b]
|
|
255
|
+
- @pluv/client@0.12.0
|
|
256
|
+
- @pluv/types@0.12.0
|
|
257
|
+
|
|
3
258
|
## 0.11.1
|
|
4
259
|
|
|
5
260
|
### Patch Changes
|
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PluvRoomAddon, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, InferYjsSharedTypeJson, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
1
|
+
import { PluvRoomAddon, TrackOriginOptions, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, InferYjsSharedTypeJson, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
2
2
|
export { AbstractType, ConnectionState, createClient, y } from '@pluv/client';
|
|
3
3
|
import * as _pluv_types from '@pluv/types';
|
|
4
4
|
import { IOLike, JsonObject, InputZodLike, InferIOInput, Id, InferIOOutput, IOEventMessage } from '@pluv/types';
|
|
@@ -6,11 +6,11 @@ export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types
|
|
|
6
6
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
7
7
|
import { AbstractType } from 'yjs';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type CreateRoomBundleOptions<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, AbstractType<any>> = {}> = {
|
|
10
10
|
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
11
11
|
initialStorage?: () => TStorage;
|
|
12
12
|
presence?: InputZodLike<TPresence>;
|
|
13
|
-
}
|
|
13
|
+
} & TrackOriginOptions;
|
|
14
14
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, AbstractType<any>>> = {
|
|
15
15
|
children?: ReactNode;
|
|
16
16
|
initialStorage?: keyof TStorage extends never ? never : () => TStorage;
|
|
@@ -35,6 +35,8 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
35
35
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
36
36
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
37
37
|
usePluvBroadcast: () => <TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void;
|
|
38
|
+
usePluvCanRedo: () => boolean;
|
|
39
|
+
usePluvCanUndo: () => boolean;
|
|
38
40
|
usePluvConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
39
41
|
usePluvEvent: <TType extends keyof InferIOOutput<TIO>>(type: TType, callback: (data: Id<IOEventMessage<TIO, TType>>) => void) => void;
|
|
40
42
|
usePluvMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [
|
|
@@ -44,8 +46,11 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
44
46
|
usePluvMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
45
47
|
usePluvOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
46
48
|
usePluvOthers: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[], options?: SubscriptionHookOptions<readonly Id<T>[]>) => readonly Id<T>[];
|
|
49
|
+
usePluvRedo: () => () => void;
|
|
47
50
|
usePluvRoom: () => AbstractRoom<TIO, TPresence, TStorage>;
|
|
48
|
-
usePluvStorage: <TKey extends keyof TStorage, TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>>(key: TKey, selector?: (data: InferYjsSharedTypeJson<TStorage[TKey]>) => TData, options?: SubscriptionHookOptions<TData
|
|
51
|
+
usePluvStorage: <TKey extends keyof TStorage, TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>>(key: TKey, selector?: (data: InferYjsSharedTypeJson<TStorage[TKey]>) => TData, options?: SubscriptionHookOptions<TData>) => [data: TData, sharedType: TStorage[TKey]];
|
|
52
|
+
usePluvTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
53
|
+
usePluvUndo: () => () => void;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
interface PluvProviderProps {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PluvRoomAddon, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, InferYjsSharedTypeJson, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
1
|
+
import { PluvRoomAddon, TrackOriginOptions, PluvRoomDebug, WebSocketConnection, UserInfo, AbstractRoom, InferYjsSharedTypeJson, MockedRoomEvents, PluvClient } from '@pluv/client';
|
|
2
2
|
export { AbstractType, ConnectionState, createClient, y } from '@pluv/client';
|
|
3
3
|
import * as _pluv_types from '@pluv/types';
|
|
4
4
|
import { IOLike, JsonObject, InputZodLike, InferIOInput, Id, InferIOOutput, IOEventMessage } from '@pluv/types';
|
|
@@ -6,11 +6,11 @@ export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types
|
|
|
6
6
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
7
7
|
import { AbstractType } from 'yjs';
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
type CreateRoomBundleOptions<TIO extends IOLike, TPresence extends JsonObject = {}, TStorage extends Record<string, AbstractType<any>> = {}> = {
|
|
10
10
|
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
11
11
|
initialStorage?: () => TStorage;
|
|
12
12
|
presence?: InputZodLike<TPresence>;
|
|
13
|
-
}
|
|
13
|
+
} & TrackOriginOptions;
|
|
14
14
|
type BaseRoomProviderProps<TPresence extends JsonObject, TStorage extends Record<string, AbstractType<any>>> = {
|
|
15
15
|
children?: ReactNode;
|
|
16
16
|
initialStorage?: keyof TStorage extends never ? never : () => TStorage;
|
|
@@ -35,6 +35,8 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
35
35
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
36
36
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
37
37
|
usePluvBroadcast: () => <TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void;
|
|
38
|
+
usePluvCanRedo: () => boolean;
|
|
39
|
+
usePluvCanUndo: () => boolean;
|
|
38
40
|
usePluvConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
39
41
|
usePluvEvent: <TType extends keyof InferIOOutput<TIO>>(type: TType, callback: (data: Id<IOEventMessage<TIO, TType>>) => void) => void;
|
|
40
42
|
usePluvMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [
|
|
@@ -44,8 +46,11 @@ interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TSt
|
|
|
44
46
|
usePluvMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
45
47
|
usePluvOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
46
48
|
usePluvOthers: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[], options?: SubscriptionHookOptions<readonly Id<T>[]>) => readonly Id<T>[];
|
|
49
|
+
usePluvRedo: () => () => void;
|
|
47
50
|
usePluvRoom: () => AbstractRoom<TIO, TPresence, TStorage>;
|
|
48
|
-
usePluvStorage: <TKey extends keyof TStorage, TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>>(key: TKey, selector?: (data: InferYjsSharedTypeJson<TStorage[TKey]>) => TData, options?: SubscriptionHookOptions<TData
|
|
51
|
+
usePluvStorage: <TKey extends keyof TStorage, TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>>(key: TKey, selector?: (data: InferYjsSharedTypeJson<TStorage[TKey]>) => TData, options?: SubscriptionHookOptions<TData>) => [data: TData, sharedType: TStorage[TKey]];
|
|
52
|
+
usePluvTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
53
|
+
usePluvUndo: () => () => void;
|
|
49
54
|
}
|
|
50
55
|
|
|
51
56
|
interface PluvProviderProps {
|
package/dist/index.js
CHANGED
|
@@ -82,10 +82,12 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
82
82
|
} = props;
|
|
83
83
|
const [room] = (0, import_react2.useState)(() => {
|
|
84
84
|
return new import_client.MockedRoom(_room, {
|
|
85
|
+
captureTimeout: options.captureTimeout,
|
|
85
86
|
events,
|
|
86
87
|
initialPresence,
|
|
87
88
|
initialStorage: typeof initialStorage === "function" ? initialStorage : options.initialStorage,
|
|
88
|
-
presence: options.presence
|
|
89
|
+
presence: options.presence,
|
|
90
|
+
trackedOrigins: options.trackedOrigins
|
|
89
91
|
});
|
|
90
92
|
});
|
|
91
93
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PluvRoomContext.Provider, { value: room, children }) });
|
|
@@ -105,11 +107,13 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
105
107
|
const [room] = (0, import_react2.useState)(() => {
|
|
106
108
|
return client.createRoom(_room, {
|
|
107
109
|
addons: options.addons,
|
|
110
|
+
captureTimeout: options.captureTimeout,
|
|
108
111
|
debug,
|
|
109
112
|
initialPresence,
|
|
110
113
|
initialStorage: typeof initialStorage === "function" ? initialStorage : options.initialStorage,
|
|
111
114
|
presence: options.presence,
|
|
112
|
-
onAuthorizationFail
|
|
115
|
+
onAuthorizationFail,
|
|
116
|
+
trackedOrigins: options.trackedOrigins
|
|
113
117
|
});
|
|
114
118
|
});
|
|
115
119
|
(0, import_react2.useEffect)(() => {
|
|
@@ -139,6 +143,36 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
139
143
|
[room]
|
|
140
144
|
);
|
|
141
145
|
};
|
|
146
|
+
const usePluvCanRedo = () => {
|
|
147
|
+
const room = usePluvRoom();
|
|
148
|
+
const subscribe = (0, import_react2.useCallback)(
|
|
149
|
+
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
150
|
+
[room]
|
|
151
|
+
);
|
|
152
|
+
const getSnapshot = (0, import_react2.useCallback)(() => room.canRedo(), [room]);
|
|
153
|
+
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
154
|
+
subscribe,
|
|
155
|
+
getSnapshot,
|
|
156
|
+
getSnapshot,
|
|
157
|
+
identity
|
|
158
|
+
);
|
|
159
|
+
return canRedo;
|
|
160
|
+
};
|
|
161
|
+
const usePluvCanUndo = () => {
|
|
162
|
+
const room = usePluvRoom();
|
|
163
|
+
const subscribe = (0, import_react2.useCallback)(
|
|
164
|
+
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
165
|
+
[room]
|
|
166
|
+
);
|
|
167
|
+
const getSnapshot = (0, import_react2.useCallback)(() => room.canUndo(), [room]);
|
|
168
|
+
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
169
|
+
subscribe,
|
|
170
|
+
getSnapshot,
|
|
171
|
+
getSnapshot,
|
|
172
|
+
identity
|
|
173
|
+
);
|
|
174
|
+
return canRedo;
|
|
175
|
+
};
|
|
142
176
|
const usePluvConnection = (selector = identity, options2) => {
|
|
143
177
|
var _a;
|
|
144
178
|
const room = usePluvRoom();
|
|
@@ -269,6 +303,10 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
269
303
|
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : shallowArrayEqual
|
|
270
304
|
);
|
|
271
305
|
};
|
|
306
|
+
const usePluvRedo = () => {
|
|
307
|
+
const room = usePluvRoom();
|
|
308
|
+
return room.redo;
|
|
309
|
+
};
|
|
272
310
|
const usePluvStorage = (key, selector = identity, options2) => {
|
|
273
311
|
var _a;
|
|
274
312
|
const room = usePluvRoom();
|
|
@@ -277,12 +315,11 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
277
315
|
[key, room]
|
|
278
316
|
);
|
|
279
317
|
const getSnapshot = (0, import_react2.useCallback)(() => {
|
|
280
|
-
|
|
281
|
-
return (_b = (_a2 = room.getStorage(key)) == null ? void 0 : _a2.toJSON()) != null ? _b : null;
|
|
318
|
+
return room.getStorage(key).toJSON();
|
|
282
319
|
}, [key, room]);
|
|
283
320
|
const _selector = (0, import_react2.useCallback)(
|
|
284
321
|
(snapshot) => {
|
|
285
|
-
return
|
|
322
|
+
return selector(snapshot);
|
|
286
323
|
},
|
|
287
324
|
[selector]
|
|
288
325
|
);
|
|
@@ -296,20 +333,33 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
296
333
|
const sharedType = room.getStorage(key);
|
|
297
334
|
return [data, sharedType];
|
|
298
335
|
};
|
|
336
|
+
const usePluvTransact = () => {
|
|
337
|
+
const room = usePluvRoom();
|
|
338
|
+
return room.transact;
|
|
339
|
+
};
|
|
340
|
+
const usePluvUndo = () => {
|
|
341
|
+
const room = usePluvRoom();
|
|
342
|
+
return room.undo;
|
|
343
|
+
};
|
|
299
344
|
return {
|
|
300
345
|
// components
|
|
301
346
|
MockedRoomProvider,
|
|
302
347
|
PluvRoomProvider,
|
|
303
348
|
// hooks
|
|
304
349
|
usePluvBroadcast,
|
|
350
|
+
usePluvCanRedo,
|
|
351
|
+
usePluvCanUndo,
|
|
305
352
|
usePluvConnection,
|
|
306
353
|
usePluvEvent,
|
|
307
354
|
usePluvMyPresence,
|
|
308
355
|
usePluvMyself,
|
|
309
356
|
usePluvOther,
|
|
310
357
|
usePluvOthers,
|
|
358
|
+
usePluvRedo,
|
|
311
359
|
usePluvRoom,
|
|
312
|
-
usePluvStorage
|
|
360
|
+
usePluvStorage,
|
|
361
|
+
usePluvTransact,
|
|
362
|
+
usePluvUndo
|
|
313
363
|
};
|
|
314
364
|
};
|
|
315
365
|
|
package/dist/index.mjs
CHANGED
|
@@ -52,10 +52,12 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
52
52
|
} = props;
|
|
53
53
|
const [room] = useState2(() => {
|
|
54
54
|
return new MockedRoom(_room, {
|
|
55
|
+
captureTimeout: options.captureTimeout,
|
|
55
56
|
events,
|
|
56
57
|
initialPresence,
|
|
57
58
|
initialStorage: typeof initialStorage === "function" ? initialStorage : options.initialStorage,
|
|
58
|
-
presence: options.presence
|
|
59
|
+
presence: options.presence,
|
|
60
|
+
trackedOrigins: options.trackedOrigins
|
|
59
61
|
});
|
|
60
62
|
});
|
|
61
63
|
return /* @__PURE__ */ jsx(MockedRoomContext.Provider, { value: { room }, children: /* @__PURE__ */ jsx(PluvRoomContext.Provider, { value: room, children }) });
|
|
@@ -75,11 +77,13 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
75
77
|
const [room] = useState2(() => {
|
|
76
78
|
return client.createRoom(_room, {
|
|
77
79
|
addons: options.addons,
|
|
80
|
+
captureTimeout: options.captureTimeout,
|
|
78
81
|
debug,
|
|
79
82
|
initialPresence,
|
|
80
83
|
initialStorage: typeof initialStorage === "function" ? initialStorage : options.initialStorage,
|
|
81
84
|
presence: options.presence,
|
|
82
|
-
onAuthorizationFail
|
|
85
|
+
onAuthorizationFail,
|
|
86
|
+
trackedOrigins: options.trackedOrigins
|
|
83
87
|
});
|
|
84
88
|
});
|
|
85
89
|
useEffect(() => {
|
|
@@ -109,6 +113,36 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
109
113
|
[room]
|
|
110
114
|
);
|
|
111
115
|
};
|
|
116
|
+
const usePluvCanRedo = () => {
|
|
117
|
+
const room = usePluvRoom();
|
|
118
|
+
const subscribe = useCallback2(
|
|
119
|
+
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
120
|
+
[room]
|
|
121
|
+
);
|
|
122
|
+
const getSnapshot = useCallback2(() => room.canRedo(), [room]);
|
|
123
|
+
const canRedo = useSyncExternalStoreWithSelector(
|
|
124
|
+
subscribe,
|
|
125
|
+
getSnapshot,
|
|
126
|
+
getSnapshot,
|
|
127
|
+
identity
|
|
128
|
+
);
|
|
129
|
+
return canRedo;
|
|
130
|
+
};
|
|
131
|
+
const usePluvCanUndo = () => {
|
|
132
|
+
const room = usePluvRoom();
|
|
133
|
+
const subscribe = useCallback2(
|
|
134
|
+
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
135
|
+
[room]
|
|
136
|
+
);
|
|
137
|
+
const getSnapshot = useCallback2(() => room.canUndo(), [room]);
|
|
138
|
+
const canRedo = useSyncExternalStoreWithSelector(
|
|
139
|
+
subscribe,
|
|
140
|
+
getSnapshot,
|
|
141
|
+
getSnapshot,
|
|
142
|
+
identity
|
|
143
|
+
);
|
|
144
|
+
return canRedo;
|
|
145
|
+
};
|
|
112
146
|
const usePluvConnection = (selector = identity, options2) => {
|
|
113
147
|
var _a;
|
|
114
148
|
const room = usePluvRoom();
|
|
@@ -239,6 +273,10 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
239
273
|
(_a = options2 == null ? void 0 : options2.isEqual) != null ? _a : shallowArrayEqual
|
|
240
274
|
);
|
|
241
275
|
};
|
|
276
|
+
const usePluvRedo = () => {
|
|
277
|
+
const room = usePluvRoom();
|
|
278
|
+
return room.redo;
|
|
279
|
+
};
|
|
242
280
|
const usePluvStorage = (key, selector = identity, options2) => {
|
|
243
281
|
var _a;
|
|
244
282
|
const room = usePluvRoom();
|
|
@@ -247,12 +285,11 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
247
285
|
[key, room]
|
|
248
286
|
);
|
|
249
287
|
const getSnapshot = useCallback2(() => {
|
|
250
|
-
|
|
251
|
-
return (_b = (_a2 = room.getStorage(key)) == null ? void 0 : _a2.toJSON()) != null ? _b : null;
|
|
288
|
+
return room.getStorage(key).toJSON();
|
|
252
289
|
}, [key, room]);
|
|
253
290
|
const _selector = useCallback2(
|
|
254
291
|
(snapshot) => {
|
|
255
|
-
return
|
|
292
|
+
return selector(snapshot);
|
|
256
293
|
},
|
|
257
294
|
[selector]
|
|
258
295
|
);
|
|
@@ -266,20 +303,33 @@ var createRoomBundle = (client, options = {}) => {
|
|
|
266
303
|
const sharedType = room.getStorage(key);
|
|
267
304
|
return [data, sharedType];
|
|
268
305
|
};
|
|
306
|
+
const usePluvTransact = () => {
|
|
307
|
+
const room = usePluvRoom();
|
|
308
|
+
return room.transact;
|
|
309
|
+
};
|
|
310
|
+
const usePluvUndo = () => {
|
|
311
|
+
const room = usePluvRoom();
|
|
312
|
+
return room.undo;
|
|
313
|
+
};
|
|
269
314
|
return {
|
|
270
315
|
// components
|
|
271
316
|
MockedRoomProvider,
|
|
272
317
|
PluvRoomProvider,
|
|
273
318
|
// hooks
|
|
274
319
|
usePluvBroadcast,
|
|
320
|
+
usePluvCanRedo,
|
|
321
|
+
usePluvCanUndo,
|
|
275
322
|
usePluvConnection,
|
|
276
323
|
usePluvEvent,
|
|
277
324
|
usePluvMyPresence,
|
|
278
325
|
usePluvMyself,
|
|
279
326
|
usePluvOther,
|
|
280
327
|
usePluvOthers,
|
|
328
|
+
usePluvRedo,
|
|
281
329
|
usePluvRoom,
|
|
282
|
-
usePluvStorage
|
|
330
|
+
usePluvStorage,
|
|
331
|
+
usePluvTransact,
|
|
332
|
+
usePluvUndo
|
|
283
333
|
};
|
|
284
334
|
};
|
|
285
335
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.1",
|
|
4
4
|
"description": "@pluv/client React.js bindings",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,25 +17,25 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@types/react": "18.2.
|
|
20
|
+
"@types/react": "18.2.23",
|
|
21
21
|
"@types/use-sync-external-store": "^0.0.4",
|
|
22
22
|
"fast-deep-equal": "^3.1.3",
|
|
23
23
|
"use-sync-external-store": "^1.2.0",
|
|
24
|
-
"@pluv/client": "^0.
|
|
25
|
-
"@pluv/types": "^0.
|
|
24
|
+
"@pluv/client": "^0.12.1",
|
|
25
|
+
"@pluv/types": "^0.12.1"
|
|
26
26
|
},
|
|
27
27
|
"peerDependencies": {
|
|
28
28
|
"react": "^17.0.0 || ^18.0.0",
|
|
29
29
|
"yjs": "^13.0.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
|
-
"eslint": "^8.
|
|
32
|
+
"eslint": "^8.50.0",
|
|
33
33
|
"react": "18.2.0",
|
|
34
34
|
"tsup": "^7.2.0",
|
|
35
35
|
"typescript": "^5.2.2",
|
|
36
|
-
"yjs": "^13.6.
|
|
37
|
-
"@pluv/tsconfig": "^0.
|
|
38
|
-
"eslint-config-pluv": "^0.
|
|
36
|
+
"yjs": "^13.6.8",
|
|
37
|
+
"@pluv/tsconfig": "^0.12.1",
|
|
38
|
+
"eslint-config-pluv": "^0.12.1"
|
|
39
39
|
},
|
|
40
40
|
"scripts": {
|
|
41
41
|
"build": "tsup src/index.ts --format esm,cjs --dts --external react",
|
package/src/createBundle.tsx
CHANGED
|
@@ -17,9 +17,9 @@ export interface CreateBundle<TIO extends IOLike> {
|
|
|
17
17
|
// factories
|
|
18
18
|
createRoomBundle: <
|
|
19
19
|
TPresence extends JsonObject = {},
|
|
20
|
-
TStorage extends Record<string, AbstractType<any>> = {}
|
|
20
|
+
TStorage extends Record<string, AbstractType<any>> = {},
|
|
21
21
|
>(
|
|
22
|
-
options?: CreateRoomBundleOptions<TIO, TPresence, TStorage
|
|
22
|
+
options?: CreateRoomBundleOptions<TIO, TPresence, TStorage>,
|
|
23
23
|
) => CreateRoomBundle<TIO, TPresence, TStorage>;
|
|
24
24
|
|
|
25
25
|
// components
|
|
@@ -30,7 +30,7 @@ export interface CreateBundle<TIO extends IOLike> {
|
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
export const createBundle = <TIO extends IOLike>(
|
|
33
|
-
client: PluvClient<TIO
|
|
33
|
+
client: PluvClient<TIO>,
|
|
34
34
|
): CreateBundle<TIO> => {
|
|
35
35
|
/**
|
|
36
36
|
* !HACK
|
|
@@ -57,9 +57,9 @@ export const createBundle = <TIO extends IOLike>(
|
|
|
57
57
|
|
|
58
58
|
const createRoomBundle = <
|
|
59
59
|
TPresence extends JsonObject = {},
|
|
60
|
-
TStorage extends Record<string, AbstractType<any>> = {}
|
|
60
|
+
TStorage extends Record<string, AbstractType<any>> = {},
|
|
61
61
|
>(
|
|
62
|
-
options: CreateRoomBundleOptions<TIO, TPresence, TStorage> = {}
|
|
62
|
+
options: CreateRoomBundleOptions<TIO, TPresence, TStorage> = {},
|
|
63
63
|
): CreateRoomBundle<TIO, TPresence, TStorage> =>
|
|
64
64
|
_createRoomBundle(client, options);
|
|
65
65
|
|
package/src/createRoomBundle.tsx
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
PluvRoom,
|
|
7
7
|
PluvRoomAddon,
|
|
8
8
|
PluvRoomDebug,
|
|
9
|
+
TrackOriginOptions,
|
|
9
10
|
UserInfo,
|
|
10
11
|
WebSocketConnection,
|
|
11
12
|
} from "@pluv/client";
|
|
@@ -37,19 +38,19 @@ import {
|
|
|
37
38
|
useSyncExternalStoreWithSelector,
|
|
38
39
|
} from "./internal";
|
|
39
40
|
|
|
40
|
-
export
|
|
41
|
+
export type CreateRoomBundleOptions<
|
|
41
42
|
TIO extends IOLike,
|
|
42
43
|
TPresence extends JsonObject = {},
|
|
43
|
-
TStorage extends Record<string, AbstractType<any>> = {}
|
|
44
|
-
> {
|
|
44
|
+
TStorage extends Record<string, AbstractType<any>> = {},
|
|
45
|
+
> = {
|
|
45
46
|
addons?: readonly PluvRoomAddon<TIO, TPresence, TStorage>[];
|
|
46
47
|
initialStorage?: () => TStorage;
|
|
47
48
|
presence?: InputZodLike<TPresence>;
|
|
48
|
-
}
|
|
49
|
+
} & TrackOriginOptions;
|
|
49
50
|
|
|
50
51
|
type BaseRoomProviderProps<
|
|
51
52
|
TPresence extends JsonObject,
|
|
52
|
-
TStorage extends Record<string, AbstractType<any
|
|
53
|
+
TStorage extends Record<string, AbstractType<any>>,
|
|
53
54
|
> = {
|
|
54
55
|
children?: ReactNode;
|
|
55
56
|
initialStorage?: keyof TStorage extends never ? never : () => TStorage;
|
|
@@ -61,7 +62,7 @@ type BaseRoomProviderProps<
|
|
|
61
62
|
export type MockedRoomProviderProps<
|
|
62
63
|
TIO extends IOLike,
|
|
63
64
|
TPresence extends JsonObject,
|
|
64
|
-
TStorage extends Record<string, AbstractType<any
|
|
65
|
+
TStorage extends Record<string, AbstractType<any>>,
|
|
65
66
|
> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
66
67
|
events?: MockedRoomEvents<TIO>;
|
|
67
68
|
};
|
|
@@ -69,7 +70,7 @@ export type MockedRoomProviderProps<
|
|
|
69
70
|
export type PluvRoomProviderProps<
|
|
70
71
|
TIO extends IOLike,
|
|
71
72
|
TPresence extends JsonObject,
|
|
72
|
-
TStorage extends Record<string, AbstractType<any
|
|
73
|
+
TStorage extends Record<string, AbstractType<any>>,
|
|
73
74
|
> = BaseRoomProviderProps<TPresence, TStorage> & {
|
|
74
75
|
debug?: boolean | PluvRoomDebug<TIO>;
|
|
75
76
|
onAuthorizationFail?: (error: Error) => void;
|
|
@@ -86,7 +87,7 @@ export type UpdateMyPresenceAction<TPresence extends JsonObject> =
|
|
|
86
87
|
export interface CreateRoomBundle<
|
|
87
88
|
TIO extends IOLike,
|
|
88
89
|
TPresence extends JsonObject,
|
|
89
|
-
TStorage extends Record<string, AbstractType<any
|
|
90
|
+
TStorage extends Record<string, AbstractType<any>>,
|
|
90
91
|
> {
|
|
91
92
|
// components
|
|
92
93
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
@@ -95,54 +96,62 @@ export interface CreateRoomBundle<
|
|
|
95
96
|
// hooks
|
|
96
97
|
usePluvBroadcast: () => <TEvent extends keyof InferIOInput<TIO>>(
|
|
97
98
|
event: TEvent,
|
|
98
|
-
data: Id<InferIOInput<TIO>[TEvent]
|
|
99
|
+
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
99
100
|
) => void;
|
|
101
|
+
usePluvCanRedo: () => boolean;
|
|
102
|
+
usePluvCanUndo: () => boolean;
|
|
100
103
|
usePluvConnection: <T extends unknown = WebSocketConnection>(
|
|
101
104
|
selector: (connection: WebSocketConnection) => T,
|
|
102
|
-
options?: SubscriptionHookOptions<Id<T
|
|
105
|
+
options?: SubscriptionHookOptions<Id<T>>,
|
|
103
106
|
) => Id<T>;
|
|
104
107
|
usePluvEvent: <TType extends keyof InferIOOutput<TIO>>(
|
|
105
108
|
type: TType,
|
|
106
|
-
callback: (data: Id<IOEventMessage<TIO, TType>>) => void
|
|
109
|
+
callback: (data: Id<IOEventMessage<TIO, TType>>) => void,
|
|
107
110
|
) => void;
|
|
108
111
|
usePluvMyPresence: <T extends unknown = TPresence>(
|
|
109
112
|
selector?: (myPresence: TPresence) => T,
|
|
110
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
113
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
111
114
|
) => [
|
|
112
115
|
myPresence: Id<T>,
|
|
113
|
-
updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence
|
|
116
|
+
updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>,
|
|
114
117
|
];
|
|
115
118
|
usePluvMyself: <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
116
119
|
selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T,
|
|
117
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
120
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
118
121
|
) => Id<T> | null;
|
|
119
122
|
usePluvOther: <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
120
123
|
connectionId: string,
|
|
121
124
|
selector?: (other: UserInfo<TIO, TPresence>) => T,
|
|
122
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
125
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
123
126
|
) => Id<T> | null;
|
|
124
127
|
usePluvOthers: <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
125
128
|
selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[],
|
|
126
|
-
options?: SubscriptionHookOptions<readonly Id<T>[]
|
|
129
|
+
options?: SubscriptionHookOptions<readonly Id<T>[]>,
|
|
127
130
|
) => readonly Id<T>[];
|
|
131
|
+
usePluvRedo: () => () => void;
|
|
128
132
|
usePluvRoom: () => AbstractRoom<TIO, TPresence, TStorage>;
|
|
129
133
|
usePluvStorage: <
|
|
130
134
|
TKey extends keyof TStorage,
|
|
131
|
-
TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]
|
|
135
|
+
TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>,
|
|
132
136
|
>(
|
|
133
137
|
key: TKey,
|
|
134
138
|
selector?: (data: InferYjsSharedTypeJson<TStorage[TKey]>) => TData,
|
|
135
|
-
options?: SubscriptionHookOptions<TData
|
|
136
|
-
) => [data: TData
|
|
139
|
+
options?: SubscriptionHookOptions<TData>,
|
|
140
|
+
) => [data: TData, sharedType: TStorage[TKey]];
|
|
141
|
+
usePluvTransact: () => (
|
|
142
|
+
fn: (storage: TStorage) => void,
|
|
143
|
+
origin?: string,
|
|
144
|
+
) => void;
|
|
145
|
+
usePluvUndo: () => () => void;
|
|
137
146
|
}
|
|
138
147
|
|
|
139
148
|
export const createRoomBundle = <
|
|
140
149
|
TIO extends IOLike,
|
|
141
150
|
TPresence extends JsonObject = {},
|
|
142
|
-
TStorage extends Record<string, AbstractType<any>> = {}
|
|
151
|
+
TStorage extends Record<string, AbstractType<any>> = {},
|
|
143
152
|
>(
|
|
144
153
|
client: PluvClient<TIO>,
|
|
145
|
-
options: CreateRoomBundleOptions<TIO, TPresence, TStorage> = {}
|
|
154
|
+
options: CreateRoomBundleOptions<TIO, TPresence, TStorage> = {},
|
|
146
155
|
): CreateRoomBundle<TIO, TPresence, TStorage> => {
|
|
147
156
|
/**
|
|
148
157
|
* !HACK
|
|
@@ -172,6 +181,7 @@ export const createRoomBundle = <
|
|
|
172
181
|
|
|
173
182
|
const [room] = useState<MockedRoom<TIO, TPresence, TStorage>>(() => {
|
|
174
183
|
return new MockedRoom<TIO, TPresence, TStorage>(_room, {
|
|
184
|
+
captureTimeout: options.captureTimeout,
|
|
175
185
|
events,
|
|
176
186
|
initialPresence,
|
|
177
187
|
initialStorage:
|
|
@@ -179,6 +189,7 @@ export const createRoomBundle = <
|
|
|
179
189
|
? initialStorage
|
|
180
190
|
: options.initialStorage,
|
|
181
191
|
presence: options.presence,
|
|
192
|
+
trackedOrigins: options.trackedOrigins,
|
|
182
193
|
});
|
|
183
194
|
});
|
|
184
195
|
|
|
@@ -211,6 +222,7 @@ export const createRoomBundle = <
|
|
|
211
222
|
const [room] = useState<PluvRoom<TIO, TPresence, TStorage>>(() => {
|
|
212
223
|
return client.createRoom<TPresence, TStorage>(_room, {
|
|
213
224
|
addons: options.addons,
|
|
225
|
+
captureTimeout: options.captureTimeout,
|
|
214
226
|
debug,
|
|
215
227
|
initialPresence,
|
|
216
228
|
initialStorage:
|
|
@@ -219,6 +231,7 @@ export const createRoomBundle = <
|
|
|
219
231
|
: options.initialStorage,
|
|
220
232
|
presence: options.presence,
|
|
221
233
|
onAuthorizationFail,
|
|
234
|
+
trackedOrigins: options.trackedOrigins,
|
|
222
235
|
});
|
|
223
236
|
});
|
|
224
237
|
|
|
@@ -253,24 +266,64 @@ export const createRoomBundle = <
|
|
|
253
266
|
|
|
254
267
|
const usePluvBroadcast = (): (<TEvent extends keyof InferIOInput<TIO>>(
|
|
255
268
|
event: TEvent,
|
|
256
|
-
data: Id<InferIOInput<TIO>[TEvent]
|
|
269
|
+
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
257
270
|
) => void) => {
|
|
258
271
|
const room = usePluvRoom();
|
|
259
272
|
|
|
260
273
|
return useCallback(
|
|
261
274
|
<TEvent extends keyof InferIOInput<TIO>>(
|
|
262
275
|
event: TEvent,
|
|
263
|
-
data: Id<InferIOInput<TIO>[TEvent]
|
|
276
|
+
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
264
277
|
) => {
|
|
265
278
|
room.broadcast(event, data);
|
|
266
279
|
},
|
|
267
|
-
[room]
|
|
280
|
+
[room],
|
|
281
|
+
);
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
const usePluvCanRedo = (): boolean => {
|
|
285
|
+
const room = usePluvRoom();
|
|
286
|
+
|
|
287
|
+
const subscribe = useCallback(
|
|
288
|
+
(onStoreChange: () => void) => room.storageRoot(onStoreChange),
|
|
289
|
+
[room],
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
const getSnapshot = useCallback((): boolean => room.canRedo(), [room]);
|
|
293
|
+
|
|
294
|
+
const canRedo = useSyncExternalStoreWithSelector(
|
|
295
|
+
subscribe,
|
|
296
|
+
getSnapshot,
|
|
297
|
+
getSnapshot,
|
|
298
|
+
identity,
|
|
299
|
+
);
|
|
300
|
+
|
|
301
|
+
return canRedo;
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
const usePluvCanUndo = (): boolean => {
|
|
305
|
+
const room = usePluvRoom();
|
|
306
|
+
|
|
307
|
+
const subscribe = useCallback(
|
|
308
|
+
(onStoreChange: () => void) => room.storageRoot(onStoreChange),
|
|
309
|
+
[room],
|
|
268
310
|
);
|
|
311
|
+
|
|
312
|
+
const getSnapshot = useCallback((): boolean => room.canUndo(), [room]);
|
|
313
|
+
|
|
314
|
+
const canRedo = useSyncExternalStoreWithSelector(
|
|
315
|
+
subscribe,
|
|
316
|
+
getSnapshot,
|
|
317
|
+
getSnapshot,
|
|
318
|
+
identity,
|
|
319
|
+
);
|
|
320
|
+
|
|
321
|
+
return canRedo;
|
|
269
322
|
};
|
|
270
323
|
|
|
271
324
|
const usePluvConnection = <T extends unknown = WebSocketConnection>(
|
|
272
325
|
selector = identity as (connection: WebSocketConnection) => T,
|
|
273
|
-
options?: SubscriptionHookOptions<Id<T
|
|
326
|
+
options?: SubscriptionHookOptions<Id<T>>,
|
|
274
327
|
): Id<T> => {
|
|
275
328
|
const room = usePluvRoom();
|
|
276
329
|
|
|
@@ -278,14 +331,14 @@ export const createRoomBundle = <
|
|
|
278
331
|
(onStoreChange: () => void) => {
|
|
279
332
|
return room.subscribe("connection", onStoreChange);
|
|
280
333
|
},
|
|
281
|
-
[room]
|
|
334
|
+
[room],
|
|
282
335
|
);
|
|
283
336
|
|
|
284
337
|
const getSnapshot = room.getConnection;
|
|
285
338
|
|
|
286
339
|
const _selector = useCallback(
|
|
287
340
|
(snapshot: WebSocketConnection) => selector(snapshot) as Id<T>,
|
|
288
|
-
[selector]
|
|
341
|
+
[selector],
|
|
289
342
|
);
|
|
290
343
|
|
|
291
344
|
return useSyncExternalStoreWithSelector(
|
|
@@ -293,13 +346,13 @@ export const createRoomBundle = <
|
|
|
293
346
|
getSnapshot,
|
|
294
347
|
getSnapshot,
|
|
295
348
|
_selector,
|
|
296
|
-
options?.isEqual ?? fastDeepEqual
|
|
349
|
+
options?.isEqual ?? fastDeepEqual,
|
|
297
350
|
);
|
|
298
351
|
};
|
|
299
352
|
|
|
300
353
|
const usePluvEvent = <TType extends keyof InferIOOutput<TIO>>(
|
|
301
354
|
type: TType,
|
|
302
|
-
callback: (data: Id<IOEventMessage<TIO, TType>>) => void
|
|
355
|
+
callback: (data: Id<IOEventMessage<TIO, TType>>) => void,
|
|
303
356
|
): void => {
|
|
304
357
|
const room = usePluvRoom();
|
|
305
358
|
|
|
@@ -314,7 +367,7 @@ export const createRoomBundle = <
|
|
|
314
367
|
|
|
315
368
|
const usePluvMyPresence = <T extends unknown = TPresence>(
|
|
316
369
|
selector = identity as (myPresence: TPresence) => T,
|
|
317
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
370
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
318
371
|
): [Id<T>, Dispatch<UpdateMyPresenceAction<TPresence>>] => {
|
|
319
372
|
const room = usePluvRoom();
|
|
320
373
|
|
|
@@ -322,14 +375,14 @@ export const createRoomBundle = <
|
|
|
322
375
|
(onStoreChange: () => void) => {
|
|
323
376
|
return room.subscribe("my-presence", onStoreChange);
|
|
324
377
|
},
|
|
325
|
-
[room]
|
|
378
|
+
[room],
|
|
326
379
|
);
|
|
327
380
|
|
|
328
381
|
const getSnapshot = room.getMyPresence;
|
|
329
382
|
|
|
330
383
|
const _selector = useCallback(
|
|
331
384
|
(snapshot: TPresence) => selector(snapshot) as Id<T>,
|
|
332
|
-
[selector]
|
|
385
|
+
[selector],
|
|
333
386
|
);
|
|
334
387
|
|
|
335
388
|
const myPresence = useSyncExternalStoreWithSelector(
|
|
@@ -337,7 +390,7 @@ export const createRoomBundle = <
|
|
|
337
390
|
getSnapshot,
|
|
338
391
|
getSnapshot,
|
|
339
392
|
_selector,
|
|
340
|
-
options?.isEqual ?? fastDeepEqual
|
|
393
|
+
options?.isEqual ?? fastDeepEqual,
|
|
341
394
|
);
|
|
342
395
|
|
|
343
396
|
const updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>> =
|
|
@@ -350,7 +403,7 @@ export const createRoomBundle = <
|
|
|
350
403
|
|
|
351
404
|
room.updateMyPresence(presence);
|
|
352
405
|
},
|
|
353
|
-
[room]
|
|
406
|
+
[room],
|
|
354
407
|
);
|
|
355
408
|
|
|
356
409
|
return [myPresence, updateMyPresence];
|
|
@@ -358,7 +411,7 @@ export const createRoomBundle = <
|
|
|
358
411
|
|
|
359
412
|
const usePluvMyself = <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
360
413
|
selector = identity as (myself: Id<UserInfo<TIO, TPresence>>) => T,
|
|
361
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
414
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
362
415
|
): Id<T> | null => {
|
|
363
416
|
const room = usePluvRoom();
|
|
364
417
|
|
|
@@ -366,7 +419,7 @@ export const createRoomBundle = <
|
|
|
366
419
|
(onStoreChange: () => void) => {
|
|
367
420
|
return room.subscribe("myself", onStoreChange);
|
|
368
421
|
},
|
|
369
|
-
[room]
|
|
422
|
+
[room],
|
|
370
423
|
);
|
|
371
424
|
|
|
372
425
|
const getSnapshot = room.getMyself;
|
|
@@ -375,7 +428,7 @@ export const createRoomBundle = <
|
|
|
375
428
|
(snapshot: Id<UserInfo<TIO, TPresence>> | null) => {
|
|
376
429
|
return !snapshot ? null : (selector(snapshot) as Id<T>);
|
|
377
430
|
},
|
|
378
|
-
[selector]
|
|
431
|
+
[selector],
|
|
379
432
|
);
|
|
380
433
|
|
|
381
434
|
return useSyncExternalStoreWithSelector(
|
|
@@ -383,14 +436,14 @@ export const createRoomBundle = <
|
|
|
383
436
|
getSnapshot,
|
|
384
437
|
getSnapshot,
|
|
385
438
|
_selector,
|
|
386
|
-
options?.isEqual ?? fastDeepEqual
|
|
439
|
+
options?.isEqual ?? fastDeepEqual,
|
|
387
440
|
);
|
|
388
441
|
};
|
|
389
442
|
|
|
390
443
|
const usePluvOther = <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
391
444
|
connectionId: string,
|
|
392
445
|
selector = identity as (other: UserInfo<TIO, TPresence>) => T,
|
|
393
|
-
options?: SubscriptionHookOptions<Id<T> | null
|
|
446
|
+
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
394
447
|
): Id<T> | null => {
|
|
395
448
|
const room = usePluvRoom();
|
|
396
449
|
|
|
@@ -398,19 +451,19 @@ export const createRoomBundle = <
|
|
|
398
451
|
(onStoreChange: () => void) => {
|
|
399
452
|
return room.other(connectionId, onStoreChange);
|
|
400
453
|
},
|
|
401
|
-
[room, connectionId]
|
|
454
|
+
[room, connectionId],
|
|
402
455
|
);
|
|
403
456
|
|
|
404
457
|
const getSnapshot = useCallback(
|
|
405
458
|
() => room.getOther(connectionId),
|
|
406
|
-
[room, connectionId]
|
|
459
|
+
[room, connectionId],
|
|
407
460
|
);
|
|
408
461
|
|
|
409
462
|
const _selector = useCallback(
|
|
410
463
|
(snapshot: Id<UserInfo<TIO, TPresence>> | null) => {
|
|
411
464
|
return !snapshot ? null : (selector(snapshot) as Id<T>);
|
|
412
465
|
},
|
|
413
|
-
[selector]
|
|
466
|
+
[selector],
|
|
414
467
|
);
|
|
415
468
|
|
|
416
469
|
return useSyncExternalStoreWithSelector(
|
|
@@ -418,15 +471,15 @@ export const createRoomBundle = <
|
|
|
418
471
|
getSnapshot,
|
|
419
472
|
getSnapshot,
|
|
420
473
|
_selector,
|
|
421
|
-
options?.isEqual ?? fastDeepEqual
|
|
474
|
+
options?.isEqual ?? fastDeepEqual,
|
|
422
475
|
);
|
|
423
476
|
};
|
|
424
477
|
|
|
425
478
|
const usePluvOthers = <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
426
479
|
selector = identity as (
|
|
427
|
-
other: readonly Id<UserInfo<TIO, TPresence>>[]
|
|
480
|
+
other: readonly Id<UserInfo<TIO, TPresence>>[],
|
|
428
481
|
) => T[],
|
|
429
|
-
options?: SubscriptionHookOptions<readonly Id<T>[]
|
|
482
|
+
options?: SubscriptionHookOptions<readonly Id<T>[]>,
|
|
430
483
|
): readonly Id<T>[] => {
|
|
431
484
|
const room = usePluvRoom();
|
|
432
485
|
|
|
@@ -434,7 +487,7 @@ export const createRoomBundle = <
|
|
|
434
487
|
(onStoreChange: () => void) => {
|
|
435
488
|
return room.subscribe("others", onStoreChange);
|
|
436
489
|
},
|
|
437
|
-
[room]
|
|
490
|
+
[room],
|
|
438
491
|
);
|
|
439
492
|
|
|
440
493
|
const getSnapshot = room.getOthers;
|
|
@@ -444,40 +497,46 @@ export const createRoomBundle = <
|
|
|
444
497
|
getSnapshot,
|
|
445
498
|
getSnapshot,
|
|
446
499
|
selector as (
|
|
447
|
-
other: readonly Id<UserInfo<TIO, TPresence>>[]
|
|
500
|
+
other: readonly Id<UserInfo<TIO, TPresence>>[],
|
|
448
501
|
) => Id<T>[],
|
|
449
|
-
options?.isEqual ?? shallowArrayEqual
|
|
502
|
+
options?.isEqual ?? shallowArrayEqual,
|
|
450
503
|
);
|
|
451
504
|
};
|
|
452
505
|
|
|
506
|
+
const usePluvRedo = () => {
|
|
507
|
+
const room = usePluvRoom();
|
|
508
|
+
|
|
509
|
+
return room.redo;
|
|
510
|
+
};
|
|
511
|
+
|
|
453
512
|
const usePluvStorage = <
|
|
454
513
|
TKey extends keyof TStorage,
|
|
455
|
-
TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]
|
|
514
|
+
TData extends unknown = InferYjsSharedTypeJson<TStorage[TKey]>,
|
|
456
515
|
>(
|
|
457
516
|
key: TKey,
|
|
458
517
|
selector = identity as (
|
|
459
|
-
data: InferYjsSharedTypeJson<TStorage[TKey]
|
|
518
|
+
data: InferYjsSharedTypeJson<TStorage[TKey]>,
|
|
460
519
|
) => TData,
|
|
461
|
-
options?: SubscriptionHookOptions<TData
|
|
462
|
-
): [data: TData
|
|
520
|
+
options?: SubscriptionHookOptions<TData>,
|
|
521
|
+
): [data: TData, sharedType: TStorage[TKey]] => {
|
|
463
522
|
const room = usePluvRoom();
|
|
464
523
|
|
|
465
524
|
const subscribe = useCallback(
|
|
466
525
|
(onStoreChange: () => void) => room.storage(key, onStoreChange),
|
|
467
|
-
[key, room]
|
|
526
|
+
[key, room],
|
|
468
527
|
);
|
|
469
528
|
|
|
470
529
|
const getSnapshot = useCallback((): InferYjsSharedTypeJson<
|
|
471
530
|
TStorage[TKey]
|
|
472
|
-
>
|
|
473
|
-
return room.getStorage(key)
|
|
531
|
+
> => {
|
|
532
|
+
return room.getStorage(key).toJSON();
|
|
474
533
|
}, [key, room]);
|
|
475
534
|
|
|
476
535
|
const _selector = useCallback(
|
|
477
|
-
(snapshot: InferYjsSharedTypeJson<TStorage[TKey]>
|
|
478
|
-
return
|
|
536
|
+
(snapshot: InferYjsSharedTypeJson<TStorage[TKey]>) => {
|
|
537
|
+
return selector(snapshot);
|
|
479
538
|
},
|
|
480
|
-
[selector]
|
|
539
|
+
[selector],
|
|
481
540
|
);
|
|
482
541
|
|
|
483
542
|
const data = useSyncExternalStoreWithSelector(
|
|
@@ -485,7 +544,7 @@ export const createRoomBundle = <
|
|
|
485
544
|
getSnapshot,
|
|
486
545
|
getSnapshot,
|
|
487
546
|
_selector,
|
|
488
|
-
options?.isEqual ?? fastDeepEqual
|
|
547
|
+
options?.isEqual ?? fastDeepEqual,
|
|
489
548
|
);
|
|
490
549
|
|
|
491
550
|
const sharedType = room.getStorage(key);
|
|
@@ -493,6 +552,18 @@ export const createRoomBundle = <
|
|
|
493
552
|
return [data, sharedType];
|
|
494
553
|
};
|
|
495
554
|
|
|
555
|
+
const usePluvTransact = () => {
|
|
556
|
+
const room = usePluvRoom();
|
|
557
|
+
|
|
558
|
+
return room.transact;
|
|
559
|
+
};
|
|
560
|
+
|
|
561
|
+
const usePluvUndo = () => {
|
|
562
|
+
const room = usePluvRoom();
|
|
563
|
+
|
|
564
|
+
return room.undo;
|
|
565
|
+
};
|
|
566
|
+
|
|
496
567
|
return {
|
|
497
568
|
// components
|
|
498
569
|
MockedRoomProvider,
|
|
@@ -500,13 +571,18 @@ export const createRoomBundle = <
|
|
|
500
571
|
|
|
501
572
|
// hooks
|
|
502
573
|
usePluvBroadcast,
|
|
574
|
+
usePluvCanRedo,
|
|
575
|
+
usePluvCanUndo,
|
|
503
576
|
usePluvConnection,
|
|
504
577
|
usePluvEvent,
|
|
505
578
|
usePluvMyPresence,
|
|
506
579
|
usePluvMyself,
|
|
507
580
|
usePluvOther,
|
|
508
581
|
usePluvOthers,
|
|
582
|
+
usePluvRedo,
|
|
509
583
|
usePluvRoom,
|
|
510
584
|
usePluvStorage,
|
|
585
|
+
usePluvTransact,
|
|
586
|
+
usePluvUndo,
|
|
511
587
|
};
|
|
512
588
|
};
|