@pluv/react 0.17.3 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.turbo/turbo-build.log +8 -8
- package/CHANGELOG.md +157 -0
- package/README.md +12 -2
- package/dist/index.d.mts +13 -7
- package/dist/index.d.ts +13 -7
- package/dist/index.js +35 -54
- package/dist/index.mjs +36 -62
- package/package.json +9 -9
- package/src/createBundle.tsx +4 -14
- package/src/createRoomBundle.tsx +88 -166
- package/src/index.ts +1 -6
- package/src/internal/hooks/useSyncExternalStore.ts +2 -7
- package/src/internal/index.ts +1 -5
- package/src/internal/utils/shallowArrayEqual.ts +1 -4
package/.turbo/turbo-build.log
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
|
|
2
|
-
> @pluv/react@0.
|
|
2
|
+
> @pluv/react@0.18.0 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.77 KB[39m
|
|
12
|
+
[32mCJS[39m ⚡️ Build success in 100ms
|
|
13
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m10.18 KB[39m
|
|
14
|
+
[32mESM[39m ⚡️ Build success in 100ms
|
|
15
15
|
[34mDTS[39m Build start
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m5.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m5.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 3856ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m5.38 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m5.38 KB[39m
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,162 @@
|
|
|
1
1
|
# @pluv/react
|
|
2
2
|
|
|
3
|
+
## 0.18.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- 99b5ca9: ## Breaking Changes
|
|
8
|
+
|
|
9
|
+
- `@pluv/io` has been updated to introduce `PluvProcedure`, `PluvRouter` and `PluvServer`. This change is intended to improve the ergonomics of declaring events and simplifying inferences of event types.
|
|
10
|
+
|
|
11
|
+
### Before:
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
// backend/io.ts
|
|
15
|
+
|
|
16
|
+
import { createIO } from "@pluv/io";
|
|
17
|
+
import { createPluvHandler, platformNode } from "@pluv/platform-node";
|
|
18
|
+
import { z } from "zod";
|
|
19
|
+
|
|
20
|
+
export const io = createIO({
|
|
21
|
+
platform: platformNode(),
|
|
22
|
+
})
|
|
23
|
+
.event("SEND_MESSAGE", {
|
|
24
|
+
input: z.object({ message: z.string() }),
|
|
25
|
+
resolver: ({ message }) => ({ RECEIVE_MESSAGE: { message } }),
|
|
26
|
+
})
|
|
27
|
+
.event("DOUBLE_VALUE", {
|
|
28
|
+
input: z.object({ value: z.number() }),
|
|
29
|
+
resolver: ({ value }) => ({ VALUE_DOUBLED: { value: value * 2 } }),
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const Pluv = createPluvHandler({
|
|
33
|
+
io,
|
|
34
|
+
/* ... */
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// frontend/pluv.ts
|
|
40
|
+
|
|
41
|
+
import { createClient } from "@pluv/react";
|
|
42
|
+
import type { io } from "../backend/io";
|
|
43
|
+
|
|
44
|
+
const client = createClient<typeof io>({
|
|
45
|
+
/* ... */
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Now:
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import { createIO } from "@pluv/io";
|
|
53
|
+
import { createPluvHandler, platformNode } from "@pluv/platform-node";
|
|
54
|
+
import { z } from "zod";
|
|
55
|
+
|
|
56
|
+
const io = createIO({
|
|
57
|
+
platform: platformNode(),
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const router = io.router({
|
|
61
|
+
SEND_MESSAGE: io.procedure
|
|
62
|
+
.input(z.object({ message: z.string() }))
|
|
63
|
+
.broadcast(({ message }) => ({
|
|
64
|
+
RECEIVE_MESSAGE: { message },
|
|
65
|
+
})),
|
|
66
|
+
DOUBLE_VALUE: io.procedure
|
|
67
|
+
.input(z.object({ value: z.number() }))
|
|
68
|
+
.broadcast(({ value }) => ({
|
|
69
|
+
VALUE_DOUBLED: { value: value * 2 },
|
|
70
|
+
})),
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
export const ioServer = io.server({ router });
|
|
74
|
+
|
|
75
|
+
const Pluv = createPluvHandler({
|
|
76
|
+
io: ioServer, // <- This uses the PluvServer now
|
|
77
|
+
/* ... */
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
// frontend/pluv.ts
|
|
83
|
+
|
|
84
|
+
import { createClient } from "@pluv/react";
|
|
85
|
+
import type { ioServer } from "../backend/io";
|
|
86
|
+
|
|
87
|
+
// This users the PluvServer type now
|
|
88
|
+
const client = createClient<typeof ioServer>({
|
|
89
|
+
/* ... */
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
- `PluvRouter` instances can also be merged via the `mergeRouters` method, which effectively performs an `Object.assign` of the events object and returns a new `PluvRouter` with the correct types:
|
|
94
|
+
|
|
95
|
+
```ts
|
|
96
|
+
const router = io.mergeRouters(router1, router2);
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- 07a7725: Added broadcast proxy as a new way to broadcast events to other users.
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
// backend
|
|
103
|
+
|
|
104
|
+
const router = io.router({
|
|
105
|
+
SEND_MESSAGE: io.procedure
|
|
106
|
+
.input(z.object({ message: z.string() }))
|
|
107
|
+
.broadcast(({ message }) => ({ RECEIVE_MESSAGE: { message } })),
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// frontend
|
|
111
|
+
const pluv = createRoomBundle(/* ... */);
|
|
112
|
+
|
|
113
|
+
const broadcast = pluv.useBroadcast();
|
|
114
|
+
|
|
115
|
+
// Both of the examples below are equivalent.
|
|
116
|
+
|
|
117
|
+
broadcast("SEND_MESSAGE", { message: "Hello world~!" });
|
|
118
|
+
|
|
119
|
+
broadcast.SEND_MESSAGE({ message: "Hello world~!" });
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Patch Changes
|
|
123
|
+
|
|
124
|
+
- e587c18: Added event proxy as a new way to listen to events.
|
|
125
|
+
|
|
126
|
+
```tsx
|
|
127
|
+
// backend
|
|
128
|
+
|
|
129
|
+
const router = io.router({
|
|
130
|
+
SEND_MESSAGE: io.procedure
|
|
131
|
+
.input(z.object({ message: z.string() }))
|
|
132
|
+
.broadcast(({ message }) => ({ RECEIVE_MESSAGE: { message } })),
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
// frontend
|
|
136
|
+
const pluv = createRoomBundle(/* ... */);
|
|
137
|
+
|
|
138
|
+
// Both of the examples below are equivalent.
|
|
139
|
+
|
|
140
|
+
pluv.useEvent("RECEIVE_MESSAGE", ({ data }) => {
|
|
141
|
+
const { message } = data;
|
|
142
|
+
|
|
143
|
+
console.log(message);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
pluv.event.RECEIVE_MESSAGE.useEvent(({ data }) => {
|
|
147
|
+
const { message } = data;
|
|
148
|
+
|
|
149
|
+
console.log(message);
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
- Updated dependencies [06c67be]
|
|
154
|
+
- Updated dependencies [99b5ca9]
|
|
155
|
+
- Updated dependencies [df1342c]
|
|
156
|
+
- @pluv/client@0.18.0
|
|
157
|
+
- @pluv/types@0.18.0
|
|
158
|
+
- @pluv/crdt@0.18.0
|
|
159
|
+
|
|
3
160
|
## 0.17.3
|
|
4
161
|
|
|
5
162
|
### Patch Changes
|
package/README.md
CHANGED
|
@@ -76,18 +76,28 @@ export const {
|
|
|
76
76
|
|
|
77
77
|
export const {
|
|
78
78
|
// components
|
|
79
|
+
MockedRoomProvider,
|
|
79
80
|
PluvRoomProvider,
|
|
80
81
|
|
|
82
|
+
// utils
|
|
83
|
+
event,
|
|
84
|
+
|
|
81
85
|
// hooks
|
|
82
86
|
useBroadcast,
|
|
87
|
+
useCanRedo,
|
|
88
|
+
useCanUndo,
|
|
83
89
|
useConnection,
|
|
90
|
+
useDoc,
|
|
84
91
|
useEvent,
|
|
85
92
|
useMyPresence,
|
|
86
93
|
useMyself,
|
|
87
94
|
useOther,
|
|
88
95
|
useOthers,
|
|
96
|
+
useRedo,
|
|
89
97
|
useRoom,
|
|
90
98
|
useStorage,
|
|
99
|
+
useTransact,
|
|
100
|
+
useUndo,
|
|
91
101
|
} = createRoomBundle({
|
|
92
102
|
initialStorage: yjs.doc(() => ({
|
|
93
103
|
messages: yjs.array([
|
|
@@ -120,7 +130,7 @@ export const MyPage: FC<Record<string, never>> = () => {
|
|
|
120
130
|
export const MyRoom: FC<Record<string, never>> = () => {
|
|
121
131
|
const broadcast = useBroadcast();
|
|
122
132
|
|
|
123
|
-
useEvent(
|
|
133
|
+
event.RECEIVE_MESSAGE.useEvent(({ data }) => {
|
|
124
134
|
// data is typed as { message: string }
|
|
125
135
|
console.log(data.message);
|
|
126
136
|
});
|
|
@@ -128,7 +138,7 @@ export const MyRoom: FC<Record<string, never>> = () => {
|
|
|
128
138
|
return (
|
|
129
139
|
<button
|
|
130
140
|
onClick={() => {
|
|
131
|
-
broadcast(
|
|
141
|
+
broadcast.SEND_MESSAGE({
|
|
132
142
|
// TypeScript will require that message is typed as string
|
|
133
143
|
message: "Hello world!",
|
|
134
144
|
});
|
package/dist/index.d.mts
CHANGED
|
@@ -3,7 +3,7 @@ export { ConnectionState, createClient } from '@pluv/client';
|
|
|
3
3
|
import { AbstractCrdtType, AbstractCrdtDocFactory, AbstractCrdtDoc, InferCrdtStorageJson } from '@pluv/crdt';
|
|
4
4
|
export { AbstractCrdtType, InferCrdtStorageJson } from '@pluv/crdt';
|
|
5
5
|
import * as _pluv_types from '@pluv/types';
|
|
6
|
-
import { IOLike, JsonObject, InputZodLike,
|
|
6
|
+
import { IOLike, JsonObject, InputZodLike, Id, InferIOOutput, IOEventMessage, InferIOInput } from '@pluv/types';
|
|
7
7
|
export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
|
|
8
8
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
9
9
|
|
|
@@ -32,19 +32,25 @@ interface SubscriptionHookOptions<T extends unknown> {
|
|
|
32
32
|
isEqual?: (a: T, b: T) => boolean;
|
|
33
33
|
}
|
|
34
34
|
type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
|
|
35
|
+
type BroadcastProxy<TIO extends IOLike> = (<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void) & {
|
|
36
|
+
[event in keyof InferIOInput<TIO>]: (callback: Id<InferIOInput<TIO>[event]>) => void;
|
|
37
|
+
};
|
|
38
|
+
type EventProxy<TIO extends IOLike> = {
|
|
39
|
+
[event in keyof InferIOOutput<TIO>]: {
|
|
40
|
+
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
35
43
|
interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, AbstractCrdtType<any, any>>> {
|
|
36
44
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
37
45
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
38
|
-
|
|
46
|
+
event: EventProxy<TIO>;
|
|
47
|
+
useBroadcast: () => BroadcastProxy<TIO>;
|
|
39
48
|
useCanRedo: () => boolean;
|
|
40
49
|
useCanUndo: () => boolean;
|
|
41
50
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
42
51
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
43
52
|
useEvent: <TType extends keyof InferIOOutput<TIO>>(type: TType, callback: (data: Id<IOEventMessage<TIO, TType>>) => void) => void;
|
|
44
|
-
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [
|
|
45
|
-
myPresence: Id<T>,
|
|
46
|
-
updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>
|
|
47
|
-
];
|
|
53
|
+
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
48
54
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
49
55
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
50
56
|
useOthers: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[], options?: SubscriptionHookOptions<readonly Id<T>[]>) => readonly Id<T>[];
|
|
@@ -64,6 +70,6 @@ interface CreateBundle<TIO extends IOLike> {
|
|
|
64
70
|
PluvProvider: FC<PluvProviderProps>;
|
|
65
71
|
useClient: () => PluvClient<TIO>;
|
|
66
72
|
}
|
|
67
|
-
declare const createBundle: <TIO extends IOLike<_pluv_types.IOAuthorize<any, any, any>, {}
|
|
73
|
+
declare const createBundle: <TIO extends IOLike<_pluv_types.IOAuthorize<any, any, any>, {}>>(client: PluvClient<TIO>) => CreateBundle<TIO>;
|
|
68
74
|
|
|
69
75
|
export { type CreateBundle, type CreateRoomBundle, type CreateRoomBundleOptions, type InferRoomStorage, type PluvProviderProps, type PluvRoomProviderProps, type SubscriptionHookOptions, createBundle };
|
package/dist/index.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ export { ConnectionState, createClient } from '@pluv/client';
|
|
|
3
3
|
import { AbstractCrdtType, AbstractCrdtDocFactory, AbstractCrdtDoc, InferCrdtStorageJson } from '@pluv/crdt';
|
|
4
4
|
export { AbstractCrdtType, InferCrdtStorageJson } from '@pluv/crdt';
|
|
5
5
|
import * as _pluv_types from '@pluv/types';
|
|
6
|
-
import { IOLike, JsonObject, InputZodLike,
|
|
6
|
+
import { IOLike, JsonObject, InputZodLike, Id, InferIOOutput, IOEventMessage, InferIOInput } from '@pluv/types';
|
|
7
7
|
export { BaseUser, EventMessage, EventRecord, IOEventMessage } from '@pluv/types';
|
|
8
8
|
import { FC, Dispatch, ReactNode } from 'react';
|
|
9
9
|
|
|
@@ -32,19 +32,25 @@ interface SubscriptionHookOptions<T extends unknown> {
|
|
|
32
32
|
isEqual?: (a: T, b: T) => boolean;
|
|
33
33
|
}
|
|
34
34
|
type UpdateMyPresenceAction<TPresence extends JsonObject> = Partial<TPresence> | ((oldPresence: TPresence | null) => Partial<TPresence>);
|
|
35
|
+
type BroadcastProxy<TIO extends IOLike> = (<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => void) & {
|
|
36
|
+
[event in keyof InferIOInput<TIO>]: (callback: Id<InferIOInput<TIO>[event]>) => void;
|
|
37
|
+
};
|
|
38
|
+
type EventProxy<TIO extends IOLike> = {
|
|
39
|
+
[event in keyof InferIOOutput<TIO>]: {
|
|
40
|
+
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
41
|
+
};
|
|
42
|
+
};
|
|
35
43
|
interface CreateRoomBundle<TIO extends IOLike, TPresence extends JsonObject, TStorage extends Record<string, AbstractCrdtType<any, any>>> {
|
|
36
44
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
37
45
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
38
|
-
|
|
46
|
+
event: EventProxy<TIO>;
|
|
47
|
+
useBroadcast: () => BroadcastProxy<TIO>;
|
|
39
48
|
useCanRedo: () => boolean;
|
|
40
49
|
useCanUndo: () => boolean;
|
|
41
50
|
useConnection: <T extends unknown = WebSocketConnection>(selector: (connection: WebSocketConnection) => T, options?: SubscriptionHookOptions<Id<T>>) => Id<T>;
|
|
42
51
|
useDoc: () => AbstractCrdtDoc<TStorage>;
|
|
43
52
|
useEvent: <TType extends keyof InferIOOutput<TIO>>(type: TType, callback: (data: Id<IOEventMessage<TIO, TType>>) => void) => void;
|
|
44
|
-
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [
|
|
45
|
-
myPresence: Id<T>,
|
|
46
|
-
updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>
|
|
47
|
-
];
|
|
53
|
+
useMyPresence: <T extends unknown = TPresence>(selector?: (myPresence: TPresence) => T, options?: SubscriptionHookOptions<Id<T> | null>) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
48
54
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
49
55
|
useOther: <T extends unknown = UserInfo<TIO, TPresence>>(connectionId: string, selector?: (other: UserInfo<TIO, TPresence>) => T, options?: SubscriptionHookOptions<Id<T> | null>) => Id<T> | null;
|
|
50
56
|
useOthers: <T extends unknown = UserInfo<TIO, TPresence>>(selector?: (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[], options?: SubscriptionHookOptions<readonly Id<T>[]>) => readonly Id<T>[];
|
|
@@ -64,6 +70,6 @@ interface CreateBundle<TIO extends IOLike> {
|
|
|
64
70
|
PluvProvider: FC<PluvProviderProps>;
|
|
65
71
|
useClient: () => PluvClient<TIO>;
|
|
66
72
|
}
|
|
67
|
-
declare const createBundle: <TIO extends IOLike<_pluv_types.IOAuthorize<any, any, any>, {}
|
|
73
|
+
declare const createBundle: <TIO extends IOLike<_pluv_types.IOAuthorize<any, any, any>, {}>>(client: PluvClient<TIO>) => CreateBundle<TIO>;
|
|
68
74
|
|
|
69
75
|
export { type CreateBundle, type CreateRoomBundle, type CreateRoomBundleOptions, type InferRoomStorage, type PluvProviderProps, type PluvRoomProviderProps, type SubscriptionHookOptions, createBundle };
|
package/dist/index.js
CHANGED
|
@@ -74,13 +74,7 @@ var createRoomBundle = (client, options) => {
|
|
|
74
74
|
const PluvRoomContext = (0, import_react2.createContext)(null);
|
|
75
75
|
const MockedRoomContext = (0, import_react2.createContext)({ room: null });
|
|
76
76
|
const MockedRoomProvider = (0, import_react2.memo)((props) => {
|
|
77
|
-
const {
|
|
78
|
-
children,
|
|
79
|
-
events,
|
|
80
|
-
initialPresence,
|
|
81
|
-
initialStorage,
|
|
82
|
-
room: _room
|
|
83
|
-
} = props;
|
|
77
|
+
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
84
78
|
const [room] = (0, import_react2.useState)(() => {
|
|
85
79
|
return new import_client.MockedRoom(_room, {
|
|
86
80
|
events,
|
|
@@ -93,14 +87,7 @@ var createRoomBundle = (client, options) => {
|
|
|
93
87
|
});
|
|
94
88
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
95
89
|
const PluvRoomProvider = (0, import_react2.memo)((props) => {
|
|
96
|
-
const {
|
|
97
|
-
children,
|
|
98
|
-
debug,
|
|
99
|
-
initialPresence,
|
|
100
|
-
initialStorage,
|
|
101
|
-
onAuthorizationFail,
|
|
102
|
-
room: _room
|
|
103
|
-
} = props;
|
|
90
|
+
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
104
91
|
const rerender = useRerender();
|
|
105
92
|
const { room: mockedRoom } = (0, import_react2.useContext)(MockedRoomContext);
|
|
106
93
|
const [room] = (0, import_react2.useState)(() => {
|
|
@@ -133,41 +120,34 @@ var createRoomBundle = (client, options) => {
|
|
|
133
120
|
const useRoom = () => (0, import_react2.useContext)(PluvRoomContext);
|
|
134
121
|
const useBroadcast = () => {
|
|
135
122
|
const room = useRoom();
|
|
136
|
-
|
|
137
|
-
(
|
|
138
|
-
room.broadcast(
|
|
123
|
+
const broadcast = (0, import_react2.useCallback)(
|
|
124
|
+
(event2, data) => {
|
|
125
|
+
room.broadcast(event2, data);
|
|
139
126
|
},
|
|
140
127
|
[room]
|
|
141
128
|
);
|
|
129
|
+
return (0, import_react2.useMemo)(() => {
|
|
130
|
+
return new Proxy(broadcast, {
|
|
131
|
+
get(fn, prop) {
|
|
132
|
+
return (data) => {
|
|
133
|
+
return fn(prop, data);
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
}, [broadcast]);
|
|
142
138
|
};
|
|
143
139
|
const useCanRedo = () => {
|
|
144
140
|
const room = useRoom();
|
|
145
|
-
const subscribe = (0, import_react2.useCallback)(
|
|
146
|
-
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
147
|
-
[room]
|
|
148
|
-
);
|
|
141
|
+
const subscribe = (0, import_react2.useCallback)((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
149
142
|
const getSnapshot = (0, import_react2.useCallback)(() => room.canRedo(), [room]);
|
|
150
|
-
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
151
|
-
subscribe,
|
|
152
|
-
getSnapshot,
|
|
153
|
-
getSnapshot,
|
|
154
|
-
identity
|
|
155
|
-
);
|
|
143
|
+
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(subscribe, getSnapshot, getSnapshot, identity);
|
|
156
144
|
return canRedo;
|
|
157
145
|
};
|
|
158
146
|
const useCanUndo = () => {
|
|
159
147
|
const room = useRoom();
|
|
160
|
-
const subscribe = (0, import_react2.useCallback)(
|
|
161
|
-
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
162
|
-
[room]
|
|
163
|
-
);
|
|
148
|
+
const subscribe = (0, import_react2.useCallback)((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
164
149
|
const getSnapshot = (0, import_react2.useCallback)(() => room.canUndo(), [room]);
|
|
165
|
-
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
166
|
-
subscribe,
|
|
167
|
-
getSnapshot,
|
|
168
|
-
getSnapshot,
|
|
169
|
-
identity
|
|
170
|
-
);
|
|
150
|
+
const canRedo = (0, import_with_selector.useSyncExternalStoreWithSelector)(subscribe, getSnapshot, getSnapshot, identity);
|
|
171
151
|
return canRedo;
|
|
172
152
|
};
|
|
173
153
|
const useConnection = (selector = identity, options2) => {
|
|
@@ -180,10 +160,7 @@ var createRoomBundle = (client, options) => {
|
|
|
180
160
|
[room]
|
|
181
161
|
);
|
|
182
162
|
const getSnapshot = room.getConnection;
|
|
183
|
-
const _selector = (0, import_react2.useCallback)(
|
|
184
|
-
(snapshot) => selector(snapshot),
|
|
185
|
-
[selector]
|
|
186
|
-
);
|
|
163
|
+
const _selector = (0, import_react2.useCallback)((snapshot) => selector(snapshot), [selector]);
|
|
187
164
|
return (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
188
165
|
subscribe,
|
|
189
166
|
getSnapshot,
|
|
@@ -205,6 +182,17 @@ var createRoomBundle = (client, options) => {
|
|
|
205
182
|
};
|
|
206
183
|
}, [callback, room, type]);
|
|
207
184
|
};
|
|
185
|
+
const event = new Proxy(
|
|
186
|
+
{},
|
|
187
|
+
{
|
|
188
|
+
get(_, prop) {
|
|
189
|
+
const useProxyEvent = (callback) => {
|
|
190
|
+
return useEvent(prop, callback);
|
|
191
|
+
};
|
|
192
|
+
return { useEvent: useProxyEvent };
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
);
|
|
208
196
|
const useMyPresence = (selector = identity, options2) => {
|
|
209
197
|
var _a2;
|
|
210
198
|
const room = useRoom();
|
|
@@ -215,10 +203,7 @@ var createRoomBundle = (client, options) => {
|
|
|
215
203
|
[room]
|
|
216
204
|
);
|
|
217
205
|
const getSnapshot = room.getMyPresence;
|
|
218
|
-
const _selector = (0, import_react2.useCallback)(
|
|
219
|
-
(snapshot) => selector(snapshot),
|
|
220
|
-
[selector]
|
|
221
|
-
);
|
|
206
|
+
const _selector = (0, import_react2.useCallback)((snapshot) => selector(snapshot), [selector]);
|
|
222
207
|
const myPresence = (0, import_with_selector.useSyncExternalStoreWithSelector)(
|
|
223
208
|
subscribe,
|
|
224
209
|
getSnapshot,
|
|
@@ -268,10 +253,7 @@ var createRoomBundle = (client, options) => {
|
|
|
268
253
|
},
|
|
269
254
|
[room, connectionId]
|
|
270
255
|
);
|
|
271
|
-
const getSnapshot = (0, import_react2.useCallback)(
|
|
272
|
-
() => room.getOther(connectionId),
|
|
273
|
-
[room, connectionId]
|
|
274
|
-
);
|
|
256
|
+
const getSnapshot = (0, import_react2.useCallback)(() => room.getOther(connectionId), [room, connectionId]);
|
|
275
257
|
const _selector = (0, import_react2.useCallback)(
|
|
276
258
|
(snapshot) => {
|
|
277
259
|
return !snapshot ? null : selector(snapshot);
|
|
@@ -315,10 +297,7 @@ var createRoomBundle = (client, options) => {
|
|
|
315
297
|
room.subscribe("storage-loaded", () => {
|
|
316
298
|
rerender();
|
|
317
299
|
});
|
|
318
|
-
const subscribe = (0, import_react2.useCallback)(
|
|
319
|
-
(onStoreChange) => room.storage(key, onStoreChange),
|
|
320
|
-
[key, room]
|
|
321
|
-
);
|
|
300
|
+
const subscribe = (0, import_react2.useCallback)((onStoreChange) => room.storage(key, onStoreChange), [key, room]);
|
|
322
301
|
const getSnapshot = (0, import_react2.useCallback)(() => {
|
|
323
302
|
var _a3;
|
|
324
303
|
return (_a3 = room.getStorage(key)) == null ? void 0 : _a3.toJson();
|
|
@@ -351,6 +330,8 @@ var createRoomBundle = (client, options) => {
|
|
|
351
330
|
// components
|
|
352
331
|
MockedRoomProvider,
|
|
353
332
|
PluvRoomProvider,
|
|
333
|
+
// proxies
|
|
334
|
+
event,
|
|
354
335
|
// hooks
|
|
355
336
|
useBroadcast,
|
|
356
337
|
useCanRedo,
|
package/dist/index.mjs
CHANGED
|
@@ -8,14 +8,7 @@ import { createContext as createContext2, memo as memo2, useContext as useContex
|
|
|
8
8
|
import { MockedRoom } from "@pluv/client";
|
|
9
9
|
import { noop } from "@pluv/crdt";
|
|
10
10
|
import fastDeepEqual from "fast-deep-equal";
|
|
11
|
-
import {
|
|
12
|
-
createContext,
|
|
13
|
-
memo,
|
|
14
|
-
useCallback as useCallback2,
|
|
15
|
-
useContext,
|
|
16
|
-
useEffect,
|
|
17
|
-
useState as useState2
|
|
18
|
-
} from "react";
|
|
11
|
+
import { createContext, memo, useCallback as useCallback2, useContext, useEffect, useMemo, useState as useState2 } from "react";
|
|
19
12
|
|
|
20
13
|
// src/internal/hooks/useRerender.ts
|
|
21
14
|
import { useCallback, useState } from "react";
|
|
@@ -45,13 +38,7 @@ var createRoomBundle = (client, options) => {
|
|
|
45
38
|
const PluvRoomContext = createContext(null);
|
|
46
39
|
const MockedRoomContext = createContext({ room: null });
|
|
47
40
|
const MockedRoomProvider = memo((props) => {
|
|
48
|
-
const {
|
|
49
|
-
children,
|
|
50
|
-
events,
|
|
51
|
-
initialPresence,
|
|
52
|
-
initialStorage,
|
|
53
|
-
room: _room
|
|
54
|
-
} = props;
|
|
41
|
+
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
55
42
|
const [room] = useState2(() => {
|
|
56
43
|
return new MockedRoom(_room, {
|
|
57
44
|
events,
|
|
@@ -64,14 +51,7 @@ var createRoomBundle = (client, options) => {
|
|
|
64
51
|
});
|
|
65
52
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
66
53
|
const PluvRoomProvider = memo((props) => {
|
|
67
|
-
const {
|
|
68
|
-
children,
|
|
69
|
-
debug,
|
|
70
|
-
initialPresence,
|
|
71
|
-
initialStorage,
|
|
72
|
-
onAuthorizationFail,
|
|
73
|
-
room: _room
|
|
74
|
-
} = props;
|
|
54
|
+
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
75
55
|
const rerender = useRerender();
|
|
76
56
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
77
57
|
const [room] = useState2(() => {
|
|
@@ -104,41 +84,34 @@ var createRoomBundle = (client, options) => {
|
|
|
104
84
|
const useRoom = () => useContext(PluvRoomContext);
|
|
105
85
|
const useBroadcast = () => {
|
|
106
86
|
const room = useRoom();
|
|
107
|
-
|
|
108
|
-
(
|
|
109
|
-
room.broadcast(
|
|
87
|
+
const broadcast = useCallback2(
|
|
88
|
+
(event2, data) => {
|
|
89
|
+
room.broadcast(event2, data);
|
|
110
90
|
},
|
|
111
91
|
[room]
|
|
112
92
|
);
|
|
93
|
+
return useMemo(() => {
|
|
94
|
+
return new Proxy(broadcast, {
|
|
95
|
+
get(fn, prop) {
|
|
96
|
+
return (data) => {
|
|
97
|
+
return fn(prop, data);
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
});
|
|
101
|
+
}, [broadcast]);
|
|
113
102
|
};
|
|
114
103
|
const useCanRedo = () => {
|
|
115
104
|
const room = useRoom();
|
|
116
|
-
const subscribe = useCallback2(
|
|
117
|
-
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
118
|
-
[room]
|
|
119
|
-
);
|
|
105
|
+
const subscribe = useCallback2((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
120
106
|
const getSnapshot = useCallback2(() => room.canRedo(), [room]);
|
|
121
|
-
const canRedo = useSyncExternalStoreWithSelector(
|
|
122
|
-
subscribe,
|
|
123
|
-
getSnapshot,
|
|
124
|
-
getSnapshot,
|
|
125
|
-
identity
|
|
126
|
-
);
|
|
107
|
+
const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
127
108
|
return canRedo;
|
|
128
109
|
};
|
|
129
110
|
const useCanUndo = () => {
|
|
130
111
|
const room = useRoom();
|
|
131
|
-
const subscribe = useCallback2(
|
|
132
|
-
(onStoreChange) => room.storageRoot(onStoreChange),
|
|
133
|
-
[room]
|
|
134
|
-
);
|
|
112
|
+
const subscribe = useCallback2((onStoreChange) => room.storageRoot(onStoreChange), [room]);
|
|
135
113
|
const getSnapshot = useCallback2(() => room.canUndo(), [room]);
|
|
136
|
-
const canRedo = useSyncExternalStoreWithSelector(
|
|
137
|
-
subscribe,
|
|
138
|
-
getSnapshot,
|
|
139
|
-
getSnapshot,
|
|
140
|
-
identity
|
|
141
|
-
);
|
|
114
|
+
const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
142
115
|
return canRedo;
|
|
143
116
|
};
|
|
144
117
|
const useConnection = (selector = identity, options2) => {
|
|
@@ -151,10 +124,7 @@ var createRoomBundle = (client, options) => {
|
|
|
151
124
|
[room]
|
|
152
125
|
);
|
|
153
126
|
const getSnapshot = room.getConnection;
|
|
154
|
-
const _selector = useCallback2(
|
|
155
|
-
(snapshot) => selector(snapshot),
|
|
156
|
-
[selector]
|
|
157
|
-
);
|
|
127
|
+
const _selector = useCallback2((snapshot) => selector(snapshot), [selector]);
|
|
158
128
|
return useSyncExternalStoreWithSelector(
|
|
159
129
|
subscribe,
|
|
160
130
|
getSnapshot,
|
|
@@ -176,6 +146,17 @@ var createRoomBundle = (client, options) => {
|
|
|
176
146
|
};
|
|
177
147
|
}, [callback, room, type]);
|
|
178
148
|
};
|
|
149
|
+
const event = new Proxy(
|
|
150
|
+
{},
|
|
151
|
+
{
|
|
152
|
+
get(_, prop) {
|
|
153
|
+
const useProxyEvent = (callback) => {
|
|
154
|
+
return useEvent(prop, callback);
|
|
155
|
+
};
|
|
156
|
+
return { useEvent: useProxyEvent };
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
);
|
|
179
160
|
const useMyPresence = (selector = identity, options2) => {
|
|
180
161
|
var _a2;
|
|
181
162
|
const room = useRoom();
|
|
@@ -186,10 +167,7 @@ var createRoomBundle = (client, options) => {
|
|
|
186
167
|
[room]
|
|
187
168
|
);
|
|
188
169
|
const getSnapshot = room.getMyPresence;
|
|
189
|
-
const _selector = useCallback2(
|
|
190
|
-
(snapshot) => selector(snapshot),
|
|
191
|
-
[selector]
|
|
192
|
-
);
|
|
170
|
+
const _selector = useCallback2((snapshot) => selector(snapshot), [selector]);
|
|
193
171
|
const myPresence = useSyncExternalStoreWithSelector(
|
|
194
172
|
subscribe,
|
|
195
173
|
getSnapshot,
|
|
@@ -239,10 +217,7 @@ var createRoomBundle = (client, options) => {
|
|
|
239
217
|
},
|
|
240
218
|
[room, connectionId]
|
|
241
219
|
);
|
|
242
|
-
const getSnapshot = useCallback2(
|
|
243
|
-
() => room.getOther(connectionId),
|
|
244
|
-
[room, connectionId]
|
|
245
|
-
);
|
|
220
|
+
const getSnapshot = useCallback2(() => room.getOther(connectionId), [room, connectionId]);
|
|
246
221
|
const _selector = useCallback2(
|
|
247
222
|
(snapshot) => {
|
|
248
223
|
return !snapshot ? null : selector(snapshot);
|
|
@@ -286,10 +261,7 @@ var createRoomBundle = (client, options) => {
|
|
|
286
261
|
room.subscribe("storage-loaded", () => {
|
|
287
262
|
rerender();
|
|
288
263
|
});
|
|
289
|
-
const subscribe = useCallback2(
|
|
290
|
-
(onStoreChange) => room.storage(key, onStoreChange),
|
|
291
|
-
[key, room]
|
|
292
|
-
);
|
|
264
|
+
const subscribe = useCallback2((onStoreChange) => room.storage(key, onStoreChange), [key, room]);
|
|
293
265
|
const getSnapshot = useCallback2(() => {
|
|
294
266
|
var _a3;
|
|
295
267
|
return (_a3 = room.getStorage(key)) == null ? void 0 : _a3.toJson();
|
|
@@ -322,6 +294,8 @@ var createRoomBundle = (client, options) => {
|
|
|
322
294
|
// components
|
|
323
295
|
MockedRoomProvider,
|
|
324
296
|
PluvRoomProvider,
|
|
297
|
+
// proxies
|
|
298
|
+
event,
|
|
325
299
|
// hooks
|
|
326
300
|
useBroadcast,
|
|
327
301
|
useCanRedo,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pluv/react",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.18.0",
|
|
4
4
|
"description": "@pluv/client React.js bindings",
|
|
5
5
|
"author": "leedavidcs",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,24 +17,24 @@
|
|
|
17
17
|
"access": "public"
|
|
18
18
|
},
|
|
19
19
|
"dependencies": {
|
|
20
|
-
"@types/react": "^18.
|
|
20
|
+
"@types/react": "^18.3.3",
|
|
21
21
|
"@types/use-sync-external-store": "^0.0.6",
|
|
22
22
|
"fast-deep-equal": "^3.1.3",
|
|
23
|
-
"use-sync-external-store": "^1.2.
|
|
24
|
-
"@pluv/client": "^0.
|
|
25
|
-
"@pluv/crdt": "^0.
|
|
26
|
-
"@pluv/types": "^0.
|
|
23
|
+
"use-sync-external-store": "^1.2.2",
|
|
24
|
+
"@pluv/client": "^0.18.0",
|
|
25
|
+
"@pluv/crdt": "^0.18.0",
|
|
26
|
+
"@pluv/types": "^0.18.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"react": "^17.0.0 || ^18.0.0"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
32
32
|
"eslint": "^8.57.0",
|
|
33
|
-
"react": "^18.
|
|
33
|
+
"react": "^18.3.1",
|
|
34
34
|
"tsup": "^8.0.2",
|
|
35
35
|
"typescript": "^5.4.5",
|
|
36
|
-
"@pluv/tsconfig": "^0.
|
|
37
|
-
"eslint-config-pluv": "^0.
|
|
36
|
+
"@pluv/tsconfig": "^0.18.0",
|
|
37
|
+
"eslint-config-pluv": "^0.18.0"
|
|
38
38
|
},
|
|
39
39
|
"scripts": {
|
|
40
40
|
"build": "tsup src/index.ts --format esm,cjs --dts --external react",
|
package/src/createBundle.tsx
CHANGED
|
@@ -3,10 +3,7 @@ import type { AbstractCrdtType } from "@pluv/crdt";
|
|
|
3
3
|
import type { IOLike, JsonObject } from "@pluv/types";
|
|
4
4
|
import type { FC, ReactNode } from "react";
|
|
5
5
|
import { createContext, memo, useContext } from "react";
|
|
6
|
-
import type {
|
|
7
|
-
CreateRoomBundle,
|
|
8
|
-
CreateRoomBundleOptions,
|
|
9
|
-
} from "./createRoomBundle";
|
|
6
|
+
import type { CreateRoomBundle, CreateRoomBundleOptions } from "./createRoomBundle";
|
|
10
7
|
import { createRoomBundle as _createRoomBundle } from "./createRoomBundle";
|
|
11
8
|
|
|
12
9
|
export interface PluvProviderProps {
|
|
@@ -29,9 +26,7 @@ export interface CreateBundle<TIO extends IOLike> {
|
|
|
29
26
|
useClient: () => PluvClient<TIO>;
|
|
30
27
|
}
|
|
31
28
|
|
|
32
|
-
export const createBundle = <TIO extends IOLike>(
|
|
33
|
-
client: PluvClient<TIO>,
|
|
34
|
-
): CreateBundle<TIO> => {
|
|
29
|
+
export const createBundle = <TIO extends IOLike>(client: PluvClient<TIO>): CreateBundle<TIO> => {
|
|
35
30
|
/**
|
|
36
31
|
* !HACK
|
|
37
32
|
* @description We'll let the context error out if client is not provided,
|
|
@@ -44,11 +39,7 @@ export const createBundle = <TIO extends IOLike>(
|
|
|
44
39
|
const PluvProvider = memo<PluvProviderProps>((props) => {
|
|
45
40
|
const { children } = props;
|
|
46
41
|
|
|
47
|
-
return
|
|
48
|
-
<PluvContext.Provider value={client}>
|
|
49
|
-
{children}
|
|
50
|
-
</PluvContext.Provider>
|
|
51
|
-
);
|
|
42
|
+
return <PluvContext.Provider value={client}>{children}</PluvContext.Provider>;
|
|
52
43
|
});
|
|
53
44
|
|
|
54
45
|
PluvProvider.displayName = "PluvProvider";
|
|
@@ -60,8 +51,7 @@ export const createBundle = <TIO extends IOLike>(
|
|
|
60
51
|
TStorage extends Record<string, AbstractCrdtType<any, any>> = {},
|
|
61
52
|
>(
|
|
62
53
|
options: CreateRoomBundleOptions<TIO, TPresence, TStorage>,
|
|
63
|
-
): CreateRoomBundle<TIO, TPresence, TStorage> =>
|
|
64
|
-
_createRoomBundle(client, options);
|
|
54
|
+
): CreateRoomBundle<TIO, TPresence, TStorage> => _createRoomBundle(client, options);
|
|
65
55
|
|
|
66
56
|
return {
|
|
67
57
|
createRoomBundle,
|
package/src/createRoomBundle.tsx
CHANGED
|
@@ -9,38 +9,13 @@ import type {
|
|
|
9
9
|
WebSocketConnection,
|
|
10
10
|
} from "@pluv/client";
|
|
11
11
|
import { MockedRoom } from "@pluv/client";
|
|
12
|
-
import type {
|
|
13
|
-
AbstractCrdtDoc,
|
|
14
|
-
AbstractCrdtDocFactory,
|
|
15
|
-
AbstractCrdtType,
|
|
16
|
-
InferCrdtStorageJson,
|
|
17
|
-
} from "@pluv/crdt";
|
|
12
|
+
import type { AbstractCrdtDoc, AbstractCrdtDocFactory, AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
|
|
18
13
|
import { noop } from "@pluv/crdt";
|
|
19
|
-
import type {
|
|
20
|
-
IOEventMessage,
|
|
21
|
-
IOLike,
|
|
22
|
-
Id,
|
|
23
|
-
InferIOInput,
|
|
24
|
-
InferIOOutput,
|
|
25
|
-
InputZodLike,
|
|
26
|
-
JsonObject,
|
|
27
|
-
} from "@pluv/types";
|
|
14
|
+
import type { IOEventMessage, IOLike, Id, InferIOInput, InferIOOutput, InputZodLike, JsonObject } from "@pluv/types";
|
|
28
15
|
import fastDeepEqual from "fast-deep-equal";
|
|
29
16
|
import type { Dispatch, FC, ReactNode } from "react";
|
|
30
|
-
import {
|
|
31
|
-
|
|
32
|
-
memo,
|
|
33
|
-
useCallback,
|
|
34
|
-
useContext,
|
|
35
|
-
useEffect,
|
|
36
|
-
useState,
|
|
37
|
-
} from "react";
|
|
38
|
-
import {
|
|
39
|
-
identity,
|
|
40
|
-
shallowArrayEqual,
|
|
41
|
-
useRerender,
|
|
42
|
-
useSyncExternalStoreWithSelector,
|
|
43
|
-
} from "./internal";
|
|
17
|
+
import { createContext, memo, useCallback, useContext, useEffect, useMemo, useState } from "react";
|
|
18
|
+
import { identity, shallowArrayEqual, useRerender, useSyncExternalStoreWithSelector } from "./internal";
|
|
44
19
|
|
|
45
20
|
export type CreateRoomBundleOptions<
|
|
46
21
|
TIO extends IOLike,
|
|
@@ -59,9 +34,7 @@ type BaseRoomProviderProps<
|
|
|
59
34
|
children?: ReactNode;
|
|
60
35
|
initialStorage?: keyof TStorage extends never ? never : () => TStorage;
|
|
61
36
|
room: string;
|
|
62
|
-
} & (keyof TPresence extends never
|
|
63
|
-
? { initialPresence?: never }
|
|
64
|
-
: { initialPresence: TPresence });
|
|
37
|
+
} & (keyof TPresence extends never ? { initialPresence?: never } : { initialPresence: TPresence });
|
|
65
38
|
|
|
66
39
|
export type MockedRoomProviderProps<
|
|
67
40
|
TIO extends IOLike,
|
|
@@ -88,6 +61,19 @@ export type UpdateMyPresenceAction<TPresence extends JsonObject> =
|
|
|
88
61
|
| Partial<TPresence>
|
|
89
62
|
| ((oldPresence: TPresence | null) => Partial<TPresence>);
|
|
90
63
|
|
|
64
|
+
export type BroadcastProxy<TIO extends IOLike> = (<TEvent extends keyof InferIOInput<TIO>>(
|
|
65
|
+
event: TEvent,
|
|
66
|
+
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
67
|
+
) => void) & {
|
|
68
|
+
[event in keyof InferIOInput<TIO>]: (callback: Id<InferIOInput<TIO>[event]>) => void;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type EventProxy<TIO extends IOLike> = {
|
|
72
|
+
[event in keyof InferIOOutput<TIO>]: {
|
|
73
|
+
useEvent: (callback: (data: Id<IOEventMessage<TIO, event>>) => void) => void;
|
|
74
|
+
};
|
|
75
|
+
};
|
|
76
|
+
|
|
91
77
|
export interface CreateRoomBundle<
|
|
92
78
|
TIO extends IOLike,
|
|
93
79
|
TPresence extends JsonObject,
|
|
@@ -97,11 +83,11 @@ export interface CreateRoomBundle<
|
|
|
97
83
|
MockedRoomProvider: FC<MockedRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
98
84
|
PluvRoomProvider: FC<PluvRoomProviderProps<TIO, TPresence, TStorage>>;
|
|
99
85
|
|
|
86
|
+
// proxies
|
|
87
|
+
event: EventProxy<TIO>;
|
|
88
|
+
|
|
100
89
|
// hooks
|
|
101
|
-
useBroadcast: () => <
|
|
102
|
-
event: TEvent,
|
|
103
|
-
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
104
|
-
) => void;
|
|
90
|
+
useBroadcast: () => BroadcastProxy<TIO>;
|
|
105
91
|
useCanRedo: () => boolean;
|
|
106
92
|
useCanUndo: () => boolean;
|
|
107
93
|
useConnection: <T extends unknown = WebSocketConnection>(
|
|
@@ -116,10 +102,7 @@ export interface CreateRoomBundle<
|
|
|
116
102
|
useMyPresence: <T extends unknown = TPresence>(
|
|
117
103
|
selector?: (myPresence: TPresence) => T,
|
|
118
104
|
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
119
|
-
) => [
|
|
120
|
-
myPresence: Id<T>,
|
|
121
|
-
updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>,
|
|
122
|
-
];
|
|
105
|
+
) => [myPresence: Id<T>, updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>>];
|
|
123
106
|
useMyself: <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
124
107
|
selector?: (myself: Id<UserInfo<TIO, TPresence>>) => T,
|
|
125
108
|
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
@@ -135,27 +118,17 @@ export interface CreateRoomBundle<
|
|
|
135
118
|
) => readonly Id<T>[];
|
|
136
119
|
useRedo: () => () => void;
|
|
137
120
|
useRoom: () => AbstractRoom<TIO, TPresence, TStorage>;
|
|
138
|
-
useStorage: <
|
|
139
|
-
TKey extends keyof TStorage,
|
|
140
|
-
TData extends unknown = InferCrdtStorageJson<TStorage[TKey]>,
|
|
141
|
-
>(
|
|
121
|
+
useStorage: <TKey extends keyof TStorage, TData extends unknown = InferCrdtStorageJson<TStorage[TKey]>>(
|
|
142
122
|
key: TKey,
|
|
143
123
|
selector?: (data: InferCrdtStorageJson<TStorage[TKey]>) => TData,
|
|
144
124
|
options?: SubscriptionHookOptions<TData | null>,
|
|
145
125
|
) => [data: TData | null, sharedType: TStorage[TKey] | null];
|
|
146
|
-
useTransact: () => (
|
|
147
|
-
fn: (storage: TStorage) => void,
|
|
148
|
-
origin?: string,
|
|
149
|
-
) => void;
|
|
126
|
+
useTransact: () => (fn: (storage: TStorage) => void, origin?: string) => void;
|
|
150
127
|
useUndo: () => () => void;
|
|
151
128
|
}
|
|
152
129
|
|
|
153
|
-
export type InferRoomStorage<
|
|
154
|
-
TRoomBundle extends CreateRoomBundle<any, any,
|
|
155
|
-
> =
|
|
156
|
-
TRoomBundle extends CreateRoomBundle<any, any, infer IStorage>
|
|
157
|
-
? IStorage
|
|
158
|
-
: never;
|
|
130
|
+
export type InferRoomStorage<TRoomBundle extends CreateRoomBundle<any, any, any>> =
|
|
131
|
+
TRoomBundle extends CreateRoomBundle<any, any, infer IStorage> ? IStorage : never;
|
|
159
132
|
|
|
160
133
|
export const createRoomBundle = <
|
|
161
134
|
TIO extends IOLike,
|
|
@@ -165,8 +138,7 @@ export const createRoomBundle = <
|
|
|
165
138
|
client: PluvClient<TIO>,
|
|
166
139
|
options: CreateRoomBundleOptions<TIO, TPresence, TStorage>,
|
|
167
140
|
): CreateRoomBundle<TIO, TPresence, TStorage> => {
|
|
168
|
-
const _initialStorage = (options.initialStorage ??
|
|
169
|
-
noop.doc()) as AbstractCrdtDocFactory<TStorage>;
|
|
141
|
+
const _initialStorage = (options.initialStorage ?? noop.doc()) as AbstractCrdtDocFactory<TStorage>;
|
|
170
142
|
|
|
171
143
|
/**
|
|
172
144
|
* !HACK
|
|
@@ -175,59 +147,36 @@ export const createRoomBundle = <
|
|
|
175
147
|
* @author leedavidcs
|
|
176
148
|
* @date November 11, 2022
|
|
177
149
|
*/
|
|
178
|
-
const PluvRoomContext = createContext<
|
|
179
|
-
AbstractRoom<TIO, TPresence, TStorage>
|
|
180
|
-
>(null as any);
|
|
150
|
+
const PluvRoomContext = createContext<AbstractRoom<TIO, TPresence, TStorage>>(null as any);
|
|
181
151
|
|
|
182
152
|
const MockedRoomContext = createContext<{
|
|
183
153
|
room: AbstractRoom<TIO, TPresence, TStorage> | null;
|
|
184
154
|
}>({ room: null });
|
|
185
155
|
|
|
186
|
-
const MockedRoomProvider = memo<
|
|
187
|
-
|
|
188
|
-
>((props) => {
|
|
189
|
-
const {
|
|
190
|
-
children,
|
|
191
|
-
events,
|
|
192
|
-
initialPresence,
|
|
193
|
-
initialStorage,
|
|
194
|
-
room: _room,
|
|
195
|
-
} = props;
|
|
156
|
+
const MockedRoomProvider = memo<MockedRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
|
|
157
|
+
const { children, events, initialPresence, initialStorage, room: _room } = props;
|
|
196
158
|
|
|
197
159
|
const [room] = useState<MockedRoom<TIO, TPresence, TStorage>>(() => {
|
|
198
160
|
return new MockedRoom<TIO, TPresence, TStorage>(_room, {
|
|
199
161
|
events,
|
|
200
162
|
initialPresence,
|
|
201
163
|
initialStorage:
|
|
202
|
-
typeof initialStorage === "function"
|
|
203
|
-
? _initialStorage.getFactory(initialStorage)
|
|
204
|
-
: _initialStorage,
|
|
164
|
+
typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
205
165
|
presence: options.presence,
|
|
206
166
|
});
|
|
207
167
|
});
|
|
208
168
|
|
|
209
169
|
return (
|
|
210
170
|
<MockedRoomContext.Provider value={{ room }}>
|
|
211
|
-
<PluvRoomContext.Provider value={room}>
|
|
212
|
-
{children}
|
|
213
|
-
</PluvRoomContext.Provider>
|
|
171
|
+
<PluvRoomContext.Provider value={room}>{children}</PluvRoomContext.Provider>
|
|
214
172
|
</MockedRoomContext.Provider>
|
|
215
173
|
);
|
|
216
174
|
});
|
|
217
175
|
|
|
218
176
|
MockedRoomProvider.displayName = "MockedRoomProvider";
|
|
219
177
|
|
|
220
|
-
const PluvRoomProvider = memo<
|
|
221
|
-
|
|
222
|
-
>((props) => {
|
|
223
|
-
const {
|
|
224
|
-
children,
|
|
225
|
-
debug,
|
|
226
|
-
initialPresence,
|
|
227
|
-
initialStorage,
|
|
228
|
-
onAuthorizationFail,
|
|
229
|
-
room: _room,
|
|
230
|
-
} = props;
|
|
178
|
+
const PluvRoomProvider = memo<PluvRoomProviderProps<TIO, TPresence, TStorage>>((props) => {
|
|
179
|
+
const { children, debug, initialPresence, initialStorage, onAuthorizationFail, room: _room } = props;
|
|
231
180
|
|
|
232
181
|
const rerender = useRerender();
|
|
233
182
|
const { room: mockedRoom } = useContext(MockedRoomContext);
|
|
@@ -238,9 +187,7 @@ export const createRoomBundle = <
|
|
|
238
187
|
debug,
|
|
239
188
|
initialPresence,
|
|
240
189
|
initialStorage:
|
|
241
|
-
typeof initialStorage === "function"
|
|
242
|
-
? _initialStorage.getFactory(initialStorage)
|
|
243
|
-
: _initialStorage,
|
|
190
|
+
typeof initialStorage === "function" ? _initialStorage.getFactory(initialStorage) : _initialStorage,
|
|
244
191
|
presence: options.presence,
|
|
245
192
|
onAuthorizationFail,
|
|
246
193
|
});
|
|
@@ -264,50 +211,42 @@ export const createRoomBundle = <
|
|
|
264
211
|
};
|
|
265
212
|
}, [room]);
|
|
266
213
|
|
|
267
|
-
return
|
|
268
|
-
<PluvRoomContext.Provider value={mockedRoom ?? room}>
|
|
269
|
-
{children}
|
|
270
|
-
</PluvRoomContext.Provider>
|
|
271
|
-
);
|
|
214
|
+
return <PluvRoomContext.Provider value={mockedRoom ?? room}>{children}</PluvRoomContext.Provider>;
|
|
272
215
|
});
|
|
273
216
|
|
|
274
217
|
PluvRoomProvider.displayName = "PluvRoomProvider";
|
|
275
218
|
|
|
276
219
|
const useRoom = () => useContext(PluvRoomContext);
|
|
277
220
|
|
|
278
|
-
const useBroadcast = ():
|
|
279
|
-
event: TEvent,
|
|
280
|
-
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
281
|
-
) => void) => {
|
|
221
|
+
const useBroadcast = (): BroadcastProxy<TIO> => {
|
|
282
222
|
const room = useRoom();
|
|
283
223
|
|
|
284
|
-
|
|
285
|
-
<TEvent extends keyof InferIOInput<TIO>>(
|
|
286
|
-
event: TEvent,
|
|
287
|
-
data: Id<InferIOInput<TIO>[TEvent]>,
|
|
288
|
-
) => {
|
|
224
|
+
const broadcast = useCallback(
|
|
225
|
+
<TEvent extends keyof InferIOInput<TIO>>(event: TEvent, data: Id<InferIOInput<TIO>[TEvent]>) => {
|
|
289
226
|
room.broadcast(event, data);
|
|
290
227
|
},
|
|
291
228
|
[room],
|
|
292
229
|
);
|
|
230
|
+
|
|
231
|
+
return useMemo((): BroadcastProxy<TIO> => {
|
|
232
|
+
return new Proxy(broadcast, {
|
|
233
|
+
get(fn, prop) {
|
|
234
|
+
return (data: Id<InferIOInput<TIO>[keyof InferIOInput<TIO>]>): void => {
|
|
235
|
+
return fn(prop as keyof InferIOInput<TIO>, data);
|
|
236
|
+
};
|
|
237
|
+
},
|
|
238
|
+
}) as BroadcastProxy<TIO>;
|
|
239
|
+
}, [broadcast]);
|
|
293
240
|
};
|
|
294
241
|
|
|
295
242
|
const useCanRedo = (): boolean => {
|
|
296
243
|
const room = useRoom();
|
|
297
244
|
|
|
298
|
-
const subscribe = useCallback(
|
|
299
|
-
(onStoreChange: () => void) => room.storageRoot(onStoreChange),
|
|
300
|
-
[room],
|
|
301
|
-
);
|
|
245
|
+
const subscribe = useCallback((onStoreChange: () => void) => room.storageRoot(onStoreChange), [room]);
|
|
302
246
|
|
|
303
247
|
const getSnapshot = useCallback((): boolean => room.canRedo(), [room]);
|
|
304
248
|
|
|
305
|
-
const canRedo = useSyncExternalStoreWithSelector(
|
|
306
|
-
subscribe,
|
|
307
|
-
getSnapshot,
|
|
308
|
-
getSnapshot,
|
|
309
|
-
identity,
|
|
310
|
-
);
|
|
249
|
+
const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
311
250
|
|
|
312
251
|
return canRedo;
|
|
313
252
|
};
|
|
@@ -315,19 +254,11 @@ export const createRoomBundle = <
|
|
|
315
254
|
const useCanUndo = (): boolean => {
|
|
316
255
|
const room = useRoom();
|
|
317
256
|
|
|
318
|
-
const subscribe = useCallback(
|
|
319
|
-
(onStoreChange: () => void) => room.storageRoot(onStoreChange),
|
|
320
|
-
[room],
|
|
321
|
-
);
|
|
257
|
+
const subscribe = useCallback((onStoreChange: () => void) => room.storageRoot(onStoreChange), [room]);
|
|
322
258
|
|
|
323
259
|
const getSnapshot = useCallback((): boolean => room.canUndo(), [room]);
|
|
324
260
|
|
|
325
|
-
const canRedo = useSyncExternalStoreWithSelector(
|
|
326
|
-
subscribe,
|
|
327
|
-
getSnapshot,
|
|
328
|
-
getSnapshot,
|
|
329
|
-
identity,
|
|
330
|
-
);
|
|
261
|
+
const canRedo = useSyncExternalStoreWithSelector(subscribe, getSnapshot, getSnapshot, identity);
|
|
331
262
|
|
|
332
263
|
return canRedo;
|
|
333
264
|
};
|
|
@@ -347,10 +278,7 @@ export const createRoomBundle = <
|
|
|
347
278
|
|
|
348
279
|
const getSnapshot = room.getConnection;
|
|
349
280
|
|
|
350
|
-
const _selector = useCallback(
|
|
351
|
-
(snapshot: WebSocketConnection) => selector(snapshot) as Id<T>,
|
|
352
|
-
[selector],
|
|
353
|
-
);
|
|
281
|
+
const _selector = useCallback((snapshot: WebSocketConnection) => selector(snapshot) as Id<T>, [selector]);
|
|
354
282
|
|
|
355
283
|
return useSyncExternalStoreWithSelector(
|
|
356
284
|
subscribe,
|
|
@@ -382,6 +310,21 @@ export const createRoomBundle = <
|
|
|
382
310
|
}, [callback, room, type]);
|
|
383
311
|
};
|
|
384
312
|
|
|
313
|
+
const event = new Proxy(
|
|
314
|
+
{},
|
|
315
|
+
{
|
|
316
|
+
get(_, prop) {
|
|
317
|
+
const useProxyEvent = (
|
|
318
|
+
callback: (data: Id<IOEventMessage<TIO, keyof InferIOOutput<TIO>>>) => void,
|
|
319
|
+
): void => {
|
|
320
|
+
return useEvent(prop as keyof InferIOOutput<TIO>, callback);
|
|
321
|
+
};
|
|
322
|
+
|
|
323
|
+
return { useEvent: useProxyEvent };
|
|
324
|
+
},
|
|
325
|
+
},
|
|
326
|
+
) as EventProxy<TIO>;
|
|
327
|
+
|
|
385
328
|
const useMyPresence = <T extends unknown = TPresence>(
|
|
386
329
|
selector = identity as (myPresence: TPresence) => T,
|
|
387
330
|
options?: SubscriptionHookOptions<Id<T> | null>,
|
|
@@ -397,10 +340,7 @@ export const createRoomBundle = <
|
|
|
397
340
|
|
|
398
341
|
const getSnapshot = room.getMyPresence;
|
|
399
342
|
|
|
400
|
-
const _selector = useCallback(
|
|
401
|
-
(snapshot: TPresence) => selector(snapshot) as Id<T>,
|
|
402
|
-
[selector],
|
|
403
|
-
);
|
|
343
|
+
const _selector = useCallback((snapshot: TPresence) => selector(snapshot) as Id<T>, [selector]);
|
|
404
344
|
|
|
405
345
|
const myPresence = useSyncExternalStoreWithSelector(
|
|
406
346
|
subscribe,
|
|
@@ -410,18 +350,14 @@ export const createRoomBundle = <
|
|
|
410
350
|
options?.isEqual ?? fastDeepEqual,
|
|
411
351
|
);
|
|
412
352
|
|
|
413
|
-
const updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>> =
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
const presence =
|
|
417
|
-
typeof value === "function"
|
|
418
|
-
? value(room.getMyPresence())
|
|
419
|
-
: value;
|
|
353
|
+
const updateMyPresence: Dispatch<UpdateMyPresenceAction<TPresence>> = useCallback(
|
|
354
|
+
(value: UpdateMyPresenceAction<TPresence>): void => {
|
|
355
|
+
const presence = typeof value === "function" ? value(room.getMyPresence()) : value;
|
|
420
356
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
357
|
+
room.updateMyPresence(presence);
|
|
358
|
+
},
|
|
359
|
+
[room],
|
|
360
|
+
);
|
|
425
361
|
|
|
426
362
|
return [myPresence, updateMyPresence];
|
|
427
363
|
};
|
|
@@ -471,10 +407,7 @@ export const createRoomBundle = <
|
|
|
471
407
|
[room, connectionId],
|
|
472
408
|
);
|
|
473
409
|
|
|
474
|
-
const getSnapshot = useCallback(
|
|
475
|
-
() => room.getOther(connectionId),
|
|
476
|
-
[room, connectionId],
|
|
477
|
-
);
|
|
410
|
+
const getSnapshot = useCallback(() => room.getOther(connectionId), [room, connectionId]);
|
|
478
411
|
|
|
479
412
|
const _selector = useCallback(
|
|
480
413
|
(snapshot: Id<UserInfo<TIO, TPresence>> | null) => {
|
|
@@ -493,9 +426,7 @@ export const createRoomBundle = <
|
|
|
493
426
|
};
|
|
494
427
|
|
|
495
428
|
const useOthers = <T extends unknown = UserInfo<TIO, TPresence>>(
|
|
496
|
-
selector = identity as (
|
|
497
|
-
other: readonly Id<UserInfo<TIO, TPresence>>[],
|
|
498
|
-
) => T[],
|
|
429
|
+
selector = identity as (other: readonly Id<UserInfo<TIO, TPresence>>[]) => T[],
|
|
499
430
|
options?: SubscriptionHookOptions<readonly Id<T>[]>,
|
|
500
431
|
): readonly Id<T>[] => {
|
|
501
432
|
const room = useRoom();
|
|
@@ -513,9 +444,7 @@ export const createRoomBundle = <
|
|
|
513
444
|
subscribe,
|
|
514
445
|
getSnapshot,
|
|
515
446
|
getSnapshot,
|
|
516
|
-
selector as (
|
|
517
|
-
other: readonly Id<UserInfo<TIO, TPresence>>[],
|
|
518
|
-
) => Id<T>[],
|
|
447
|
+
selector as (other: readonly Id<UserInfo<TIO, TPresence>>[]) => Id<T>[],
|
|
519
448
|
options?.isEqual ?? shallowArrayEqual,
|
|
520
449
|
);
|
|
521
450
|
};
|
|
@@ -526,14 +455,9 @@ export const createRoomBundle = <
|
|
|
526
455
|
return room.redo;
|
|
527
456
|
};
|
|
528
457
|
|
|
529
|
-
const useStorage = <
|
|
530
|
-
TKey extends keyof TStorage,
|
|
531
|
-
TData extends unknown = InferCrdtStorageJson<TStorage[TKey]>,
|
|
532
|
-
>(
|
|
458
|
+
const useStorage = <TKey extends keyof TStorage, TData extends unknown = InferCrdtStorageJson<TStorage[TKey]>>(
|
|
533
459
|
key: TKey,
|
|
534
|
-
selector = identity as (
|
|
535
|
-
data: InferCrdtStorageJson<TStorage[TKey]>,
|
|
536
|
-
) => TData,
|
|
460
|
+
selector = identity as (data: InferCrdtStorageJson<TStorage[TKey]>) => TData,
|
|
537
461
|
options?: SubscriptionHookOptions<TData | null>,
|
|
538
462
|
): [data: TData | null, sharedType: TStorage[TKey] | null] => {
|
|
539
463
|
const room = useRoom();
|
|
@@ -543,14 +467,9 @@ export const createRoomBundle = <
|
|
|
543
467
|
rerender();
|
|
544
468
|
});
|
|
545
469
|
|
|
546
|
-
const subscribe = useCallback(
|
|
547
|
-
(onStoreChange: () => void) => room.storage(key, onStoreChange),
|
|
548
|
-
[key, room],
|
|
549
|
-
);
|
|
470
|
+
const subscribe = useCallback((onStoreChange: () => void) => room.storage(key, onStoreChange), [key, room]);
|
|
550
471
|
|
|
551
|
-
const getSnapshot = useCallback((): InferCrdtStorageJson<
|
|
552
|
-
TStorage[TKey]
|
|
553
|
-
> | null => {
|
|
472
|
+
const getSnapshot = useCallback((): InferCrdtStorageJson<TStorage[TKey]> | null => {
|
|
554
473
|
return room.getStorage(key)?.toJson();
|
|
555
474
|
}, [key, room]);
|
|
556
475
|
|
|
@@ -591,6 +510,9 @@ export const createRoomBundle = <
|
|
|
591
510
|
MockedRoomProvider,
|
|
592
511
|
PluvRoomProvider,
|
|
593
512
|
|
|
513
|
+
// proxies
|
|
514
|
+
event,
|
|
515
|
+
|
|
594
516
|
// hooks
|
|
595
517
|
useBroadcast,
|
|
596
518
|
useCanRedo,
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
export { ConnectionState, createClient } from "@pluv/client";
|
|
2
2
|
export type { AbstractCrdtType, InferCrdtStorageJson } from "@pluv/crdt";
|
|
3
|
-
export type {
|
|
4
|
-
BaseUser,
|
|
5
|
-
EventMessage,
|
|
6
|
-
EventRecord,
|
|
7
|
-
IOEventMessage,
|
|
8
|
-
} from "@pluv/types";
|
|
3
|
+
export type { BaseUser, EventMessage, EventRecord, IOEventMessage } from "@pluv/types";
|
|
9
4
|
export { createBundle } from "./createBundle";
|
|
10
5
|
export type { CreateBundle, PluvProviderProps } from "./createBundle";
|
|
11
6
|
export type {
|
|
@@ -4,12 +4,7 @@ import { identity } from "../utils";
|
|
|
4
4
|
export const useSyncExternalStore = <TSnapshot extends unknown>(
|
|
5
5
|
subscribe: (onStoreChange: () => void) => () => void,
|
|
6
6
|
getSnapshot: () => TSnapshot,
|
|
7
|
-
getServerSnapshot: undefined | null | (() => TSnapshot)
|
|
7
|
+
getServerSnapshot: undefined | null | (() => TSnapshot),
|
|
8
8
|
) => {
|
|
9
|
-
return useSyncExternalStoreWithSelector(
|
|
10
|
-
subscribe,
|
|
11
|
-
getSnapshot,
|
|
12
|
-
getServerSnapshot,
|
|
13
|
-
identity
|
|
14
|
-
);
|
|
9
|
+
return useSyncExternalStoreWithSelector(subscribe, getSnapshot, getServerSnapshot, identity);
|
|
15
10
|
};
|
package/src/internal/index.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
export const shallowArrayEqual = <T extends unknown>(
|
|
2
|
-
a: readonly T[] | T[],
|
|
3
|
-
b: readonly T[] | T[]
|
|
4
|
-
): boolean => {
|
|
1
|
+
export const shallowArrayEqual = <T extends unknown>(a: readonly T[] | T[], b: readonly T[] | T[]): boolean => {
|
|
5
2
|
return a.length === b.length && a.every((item, i) => item === b[i]);
|
|
6
3
|
};
|