@noya-app/noya-multiplayer-react 0.1.11 → 0.1.13
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 +9 -9
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +14 -6
- package/dist/index.d.ts +14 -6
- package/dist/index.js +305 -172
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +305 -172
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/globals.ts +2 -1
- package/src/hooks.ts +74 -18
- package/src/inspector/StateInspector.tsx +242 -172
- package/src/inspector/useLocalStorageState.tsx +2 -0
- package/src/inspector/useStateInspector.tsx +33 -5
|
@@ -1,7 +1,11 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
1
3
|
import {
|
|
2
4
|
ConnectionEvent,
|
|
3
5
|
ExtendedPathKey,
|
|
4
|
-
|
|
6
|
+
MultiplayerStateManager,
|
|
7
|
+
MultiplayerUser,
|
|
8
|
+
Task,
|
|
5
9
|
} from "@noya-app/state-manager";
|
|
6
10
|
import React, {
|
|
7
11
|
CSSProperties,
|
|
@@ -19,7 +23,7 @@ import {
|
|
|
19
23
|
chromeDark,
|
|
20
24
|
chromeLight,
|
|
21
25
|
} from "react-inspector";
|
|
22
|
-
import {
|
|
26
|
+
import { shouldTrackEvents$, shouldTrackTasks$ } from "../globals";
|
|
23
27
|
import { useManagedHistory } from "../hooks";
|
|
24
28
|
import { useLocalStorageState } from "./useLocalStorageState";
|
|
25
29
|
|
|
@@ -35,6 +39,16 @@ const darkTheme = {
|
|
|
35
39
|
OBJECT_NAME_COLOR: "rgba(255,255,255,0.7)",
|
|
36
40
|
} as any;
|
|
37
41
|
|
|
42
|
+
const styles = {
|
|
43
|
+
sectionInner: {
|
|
44
|
+
flex: "1 1 0",
|
|
45
|
+
overflowY: "auto",
|
|
46
|
+
overflowX: "hidden",
|
|
47
|
+
display: "flex",
|
|
48
|
+
flexDirection: "column",
|
|
49
|
+
},
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
38
52
|
function ToggleButton({
|
|
39
53
|
showInspector,
|
|
40
54
|
setShowInspector,
|
|
@@ -61,7 +75,11 @@ function ToggleButton({
|
|
|
61
75
|
justifyContent: "center",
|
|
62
76
|
padding: "2px 0",
|
|
63
77
|
}}
|
|
64
|
-
onClick={() =>
|
|
78
|
+
onClick={(event) => {
|
|
79
|
+
event.stopPropagation();
|
|
80
|
+
|
|
81
|
+
setShowInspector(!showInspector);
|
|
82
|
+
}}
|
|
65
83
|
>
|
|
66
84
|
<span style={{ width: "12px", height: "12px" }}>
|
|
67
85
|
{showInspector === (anchor === "right") ? (
|
|
@@ -108,6 +126,7 @@ function DisclosureSection({
|
|
|
108
126
|
children,
|
|
109
127
|
colorScheme,
|
|
110
128
|
isFirst,
|
|
129
|
+
style,
|
|
111
130
|
}: {
|
|
112
131
|
open: boolean;
|
|
113
132
|
setOpen?: (value: boolean) => void;
|
|
@@ -116,6 +135,7 @@ function DisclosureSection({
|
|
|
116
135
|
children: React.ReactNode;
|
|
117
136
|
colorScheme: "light" | "dark";
|
|
118
137
|
isFirst?: boolean;
|
|
138
|
+
style?: CSSProperties;
|
|
119
139
|
}) {
|
|
120
140
|
const theme = colorScheme === "light" ? lightTheme : darkTheme;
|
|
121
141
|
|
|
@@ -128,6 +148,7 @@ function DisclosureSection({
|
|
|
128
148
|
flex: open ? "1 1 0" : "0",
|
|
129
149
|
display: "flex",
|
|
130
150
|
flexDirection: "column",
|
|
151
|
+
...style,
|
|
131
152
|
}}
|
|
132
153
|
>
|
|
133
154
|
<div
|
|
@@ -152,7 +173,7 @@ function DisclosureSection({
|
|
|
152
173
|
}}
|
|
153
174
|
/>
|
|
154
175
|
)}
|
|
155
|
-
<span style={{ flex: "1 1 0" }}>{title}</span>
|
|
176
|
+
<span style={{ flex: "1 1 0", userSelect: "none" }}>{title}</span>
|
|
156
177
|
{right}
|
|
157
178
|
</div>
|
|
158
179
|
{open && children}
|
|
@@ -160,9 +181,63 @@ function DisclosureSection({
|
|
|
160
181
|
);
|
|
161
182
|
}
|
|
162
183
|
|
|
184
|
+
function InspectorRow({
|
|
185
|
+
children,
|
|
186
|
+
colorScheme,
|
|
187
|
+
selected,
|
|
188
|
+
style,
|
|
189
|
+
variant,
|
|
190
|
+
}: {
|
|
191
|
+
children: React.ReactNode;
|
|
192
|
+
colorScheme: "light" | "dark";
|
|
193
|
+
selected?: boolean;
|
|
194
|
+
style?: CSSProperties;
|
|
195
|
+
variant?: "up" | "down";
|
|
196
|
+
}) {
|
|
197
|
+
const solidBorderColor =
|
|
198
|
+
colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
<div
|
|
202
|
+
style={{
|
|
203
|
+
borderBottom: `1px solid ${solidBorderColor}`,
|
|
204
|
+
fontSize: "12px",
|
|
205
|
+
fontFamily: "Menlo, monospace",
|
|
206
|
+
padding: "2px 12px 1px",
|
|
207
|
+
display: "flex",
|
|
208
|
+
alignItems: "center",
|
|
209
|
+
background:
|
|
210
|
+
variant === "up"
|
|
211
|
+
? "rgba(0,255,0,0.1)"
|
|
212
|
+
: variant === "down"
|
|
213
|
+
? "rgba(255,0,0,0.1)"
|
|
214
|
+
: selected
|
|
215
|
+
? "rgb(59 130 246 / 15%)"
|
|
216
|
+
: undefined,
|
|
217
|
+
// background:
|
|
218
|
+
// colorScheme === "light"
|
|
219
|
+
// ? "rgba(0,0,0,0.05)"
|
|
220
|
+
// : "rgba(255,255,255,0.05)",
|
|
221
|
+
...style,
|
|
222
|
+
}}
|
|
223
|
+
>
|
|
224
|
+
<span
|
|
225
|
+
style={{
|
|
226
|
+
fontFamily: "Menlo, monospace",
|
|
227
|
+
fontSize: "11px",
|
|
228
|
+
borderRadius: 4,
|
|
229
|
+
display: "inline-block",
|
|
230
|
+
}}
|
|
231
|
+
>
|
|
232
|
+
{children}
|
|
233
|
+
</span>
|
|
234
|
+
</div>
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
163
238
|
const HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
|
|
164
239
|
|
|
165
|
-
type Anchor = "left" | "right";
|
|
240
|
+
type Anchor = "left" | "right" | "bottom left" | "bottom right";
|
|
166
241
|
|
|
167
242
|
export const StateInspector = memo(function StateInspector<
|
|
168
243
|
S extends object,
|
|
@@ -170,17 +245,23 @@ export const StateInspector = memo(function StateInspector<
|
|
|
170
245
|
>({
|
|
171
246
|
state,
|
|
172
247
|
connectionEvents,
|
|
248
|
+
connectedUsers,
|
|
249
|
+
tasks,
|
|
250
|
+
userId,
|
|
173
251
|
unstyled,
|
|
174
252
|
colorScheme = "light",
|
|
175
|
-
|
|
253
|
+
multiplayerStateManager,
|
|
176
254
|
anchor = "right",
|
|
177
255
|
...props
|
|
178
256
|
}: {
|
|
179
257
|
state: S;
|
|
180
258
|
connectionEvents?: ConnectionEvent<S>[];
|
|
259
|
+
connectedUsers?: MultiplayerUser[];
|
|
260
|
+
tasks?: Task[];
|
|
261
|
+
userId?: string;
|
|
181
262
|
unstyled?: boolean;
|
|
182
263
|
colorScheme?: "light" | "dark";
|
|
183
|
-
|
|
264
|
+
multiplayerStateManager: MultiplayerStateManager<S, M>;
|
|
184
265
|
anchor?: Anchor;
|
|
185
266
|
} & ComponentPropsWithoutRef<"div">) {
|
|
186
267
|
const [didMount, setDidMount] = React.useState(false);
|
|
@@ -204,11 +285,27 @@ export const StateInspector = memo(function StateInspector<
|
|
|
204
285
|
"noya-multiplayer-react-show-history",
|
|
205
286
|
false
|
|
206
287
|
);
|
|
288
|
+
const [showUsers, setShowUsers] = useLocalStorageState(
|
|
289
|
+
"noya-multiplayer-react-show-users",
|
|
290
|
+
true
|
|
291
|
+
);
|
|
292
|
+
const [showData, setShowData] = useLocalStorageState(
|
|
293
|
+
"noya-multiplayer-react-show-data",
|
|
294
|
+
true
|
|
295
|
+
);
|
|
296
|
+
const [showTasks, setShowTasks] = useLocalStorageState(
|
|
297
|
+
"noya-multiplayer-react-show-tasks",
|
|
298
|
+
false
|
|
299
|
+
);
|
|
207
300
|
|
|
208
301
|
useEffect(() => {
|
|
209
|
-
|
|
302
|
+
shouldTrackEvents$.set(showEvents);
|
|
210
303
|
}, [showEvents]);
|
|
211
304
|
|
|
305
|
+
useEffect(() => {
|
|
306
|
+
shouldTrackTasks$.set(showTasks);
|
|
307
|
+
}, [showTasks]);
|
|
308
|
+
|
|
212
309
|
useEffect(() => {
|
|
213
310
|
if (eventsContainerRef.current) {
|
|
214
311
|
eventsContainerRef.current.scrollTop =
|
|
@@ -216,7 +313,7 @@ export const StateInspector = memo(function StateInspector<
|
|
|
216
313
|
}
|
|
217
314
|
}, [connectionEvents]);
|
|
218
315
|
|
|
219
|
-
const historySnapshot = useManagedHistory(
|
|
316
|
+
const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
|
|
220
317
|
|
|
221
318
|
useEffect(() => {
|
|
222
319
|
if (historyContainerRef.current) {
|
|
@@ -242,15 +339,15 @@ export const StateInspector = memo(function StateInspector<
|
|
|
242
339
|
}, [historySnapshot.historyIndex]);
|
|
243
340
|
|
|
244
341
|
const theme = colorScheme === "light" ? lightTheme : darkTheme;
|
|
245
|
-
const borderColor =
|
|
246
|
-
|
|
342
|
+
// const borderColor =
|
|
343
|
+
// colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
|
|
247
344
|
const solidBorderColor =
|
|
248
345
|
colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
|
|
249
346
|
|
|
250
347
|
const baseStyle: CSSProperties = {
|
|
251
348
|
position: "fixed",
|
|
252
349
|
top: 12,
|
|
253
|
-
...(anchor
|
|
350
|
+
...(anchor.includes("right") ? { right: 12 } : { left: 12 }),
|
|
254
351
|
bottom: 12,
|
|
255
352
|
width: 400,
|
|
256
353
|
background:
|
|
@@ -277,8 +374,10 @@ export const StateInspector = memo(function StateInspector<
|
|
|
277
374
|
style={{
|
|
278
375
|
...baseStyle,
|
|
279
376
|
padding: "4px 10px",
|
|
280
|
-
bottom: undefined,
|
|
281
377
|
width: undefined,
|
|
378
|
+
...(anchor.includes("bottom")
|
|
379
|
+
? { bottom: 12, top: undefined }
|
|
380
|
+
: { bottom: undefined }),
|
|
282
381
|
}}
|
|
283
382
|
onClick={() => setShowInspector(true)}
|
|
284
383
|
>
|
|
@@ -300,12 +399,16 @@ export const StateInspector = memo(function StateInspector<
|
|
|
300
399
|
...props.style,
|
|
301
400
|
}}
|
|
302
401
|
>
|
|
303
|
-
{/* <div style={{ flex: "0", fontSize: "12px" }}>User ID: {userId}</div> */}
|
|
304
402
|
<DisclosureSection
|
|
305
|
-
open
|
|
306
|
-
title="Data"
|
|
307
|
-
colorScheme={colorScheme}
|
|
308
403
|
isFirst
|
|
404
|
+
open={showUsers}
|
|
405
|
+
setOpen={setShowUsers}
|
|
406
|
+
title="Users"
|
|
407
|
+
colorScheme={colorScheme}
|
|
408
|
+
style={{
|
|
409
|
+
flex: "0 0 auto",
|
|
410
|
+
maxHeight: "200px",
|
|
411
|
+
}}
|
|
309
412
|
right={
|
|
310
413
|
<ToggleButton
|
|
311
414
|
showInspector={showInspector}
|
|
@@ -315,17 +418,54 @@ export const StateInspector = memo(function StateInspector<
|
|
|
315
418
|
/>
|
|
316
419
|
}
|
|
317
420
|
>
|
|
318
|
-
<div
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
421
|
+
<div style={{ ...styles.sectionInner, flex: "0 0 auto" }}>
|
|
422
|
+
{connectedUsers?.map((user) => (
|
|
423
|
+
<InspectorRow
|
|
424
|
+
key={user.id}
|
|
425
|
+
colorScheme={colorScheme}
|
|
426
|
+
variant={user.id === userId ? "up" : undefined}
|
|
427
|
+
>
|
|
428
|
+
{user.name} ({ellipsis(user.id.toString(), 8, "middle")})
|
|
429
|
+
</InspectorRow>
|
|
430
|
+
))}
|
|
431
|
+
{!connectedUsers && (
|
|
432
|
+
<div
|
|
433
|
+
style={{
|
|
434
|
+
padding: "12px",
|
|
435
|
+
fontSize: "12px",
|
|
436
|
+
display: "flex",
|
|
437
|
+
flexDirection: "column",
|
|
438
|
+
gap: "4px",
|
|
439
|
+
}}
|
|
440
|
+
>
|
|
441
|
+
<span>No connected users</span>
|
|
442
|
+
</div>
|
|
443
|
+
)}
|
|
444
|
+
</div>
|
|
445
|
+
</DisclosureSection>
|
|
446
|
+
<DisclosureSection
|
|
447
|
+
title="Data"
|
|
448
|
+
colorScheme={colorScheme}
|
|
449
|
+
setOpen={setShowData}
|
|
450
|
+
open={showData}
|
|
451
|
+
>
|
|
452
|
+
<div style={styles.sectionInner}>
|
|
453
|
+
<InspectorRow colorScheme={colorScheme}>
|
|
454
|
+
<ObjectInspector
|
|
455
|
+
name={multiplayerStateManager.sm.schema ? "state" : undefined}
|
|
456
|
+
data={state}
|
|
457
|
+
theme={theme}
|
|
458
|
+
/>
|
|
459
|
+
</InspectorRow>
|
|
460
|
+
{multiplayerStateManager.sm.schema && (
|
|
461
|
+
<InspectorRow colorScheme={colorScheme}>
|
|
462
|
+
<ObjectInspector
|
|
463
|
+
name="schema"
|
|
464
|
+
data={multiplayerStateManager.sm.schema}
|
|
465
|
+
theme={theme}
|
|
466
|
+
/>
|
|
467
|
+
</InspectorRow>
|
|
468
|
+
)}
|
|
329
469
|
</div>
|
|
330
470
|
</DisclosureSection>
|
|
331
471
|
<DisclosureSection
|
|
@@ -334,16 +474,7 @@ export const StateInspector = memo(function StateInspector<
|
|
|
334
474
|
title="History"
|
|
335
475
|
colorScheme={colorScheme}
|
|
336
476
|
>
|
|
337
|
-
<div
|
|
338
|
-
ref={historyContainerRef}
|
|
339
|
-
style={{
|
|
340
|
-
flex: "1 1 0",
|
|
341
|
-
overflowY: "auto",
|
|
342
|
-
overflowX: "hidden",
|
|
343
|
-
display: "flex",
|
|
344
|
-
flexDirection: "column",
|
|
345
|
-
}}
|
|
346
|
-
>
|
|
477
|
+
<div ref={historyContainerRef} style={styles.sectionInner}>
|
|
347
478
|
<div
|
|
348
479
|
id={`${HISTORY_ELEMENT_PREFIX}0`}
|
|
349
480
|
style={{
|
|
@@ -427,91 +558,85 @@ export const StateInspector = memo(function StateInspector<
|
|
|
427
558
|
</div>
|
|
428
559
|
</DisclosureSection>
|
|
429
560
|
<DisclosureSection
|
|
430
|
-
|
|
431
|
-
setOpen={setShowEvents}
|
|
432
|
-
title="Events"
|
|
561
|
+
title="Tasks"
|
|
433
562
|
colorScheme={colorScheme}
|
|
563
|
+
open={showTasks}
|
|
564
|
+
setOpen={setShowTasks}
|
|
434
565
|
>
|
|
435
|
-
<div
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
display: "flex",
|
|
441
|
-
flexDirection: "column",
|
|
442
|
-
}}
|
|
443
|
-
>
|
|
444
|
-
{connectionEvents?.map((event, index) => (
|
|
445
|
-
<div
|
|
446
|
-
key={index}
|
|
566
|
+
<div style={styles.sectionInner}>
|
|
567
|
+
{tasks?.map((task) => (
|
|
568
|
+
<InspectorRow
|
|
569
|
+
key={task.id}
|
|
570
|
+
colorScheme={colorScheme}
|
|
447
571
|
style={{
|
|
448
|
-
|
|
572
|
+
backgroundColor:
|
|
573
|
+
task.status === "done"
|
|
574
|
+
? "rgba(0,255,0,0.2)"
|
|
575
|
+
: task.status === "error"
|
|
576
|
+
? "rgba(255,0,0,0.2)"
|
|
577
|
+
: undefined,
|
|
449
578
|
}}
|
|
450
579
|
>
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
? "rgba(0,0,0,0.05)"
|
|
458
|
-
: "rgba(255,255,255,0.05)",
|
|
459
|
-
display: "flex",
|
|
460
|
-
alignItems: "center",
|
|
461
|
-
}}
|
|
462
|
-
>
|
|
463
|
-
<span
|
|
464
|
-
style={{
|
|
465
|
-
fontFamily: "Menlo, monospace",
|
|
466
|
-
fontSize: "11px",
|
|
467
|
-
borderRadius: 4,
|
|
468
|
-
display: "inline-block",
|
|
469
|
-
}}
|
|
470
|
-
>
|
|
471
|
-
connection:{" "}
|
|
472
|
-
<span style={{ fontStyle: "italic" }}>
|
|
473
|
-
{event.state.toLowerCase()}
|
|
474
|
-
</span>
|
|
475
|
-
</span>
|
|
476
|
-
</div>
|
|
477
|
-
) : (
|
|
478
|
-
<div
|
|
479
|
-
style={{
|
|
480
|
-
padding: "0px 12px 1px",
|
|
481
|
-
background:
|
|
482
|
-
event.type === "send"
|
|
483
|
-
? "rgba(0,255,0,0.1)"
|
|
484
|
-
: "rgba(255,0,0,0.1)",
|
|
485
|
-
}}
|
|
486
|
-
>
|
|
487
|
-
<ObjectInspector
|
|
488
|
-
data={event.message}
|
|
489
|
-
theme={theme}
|
|
490
|
-
nodeRenderer={({
|
|
491
|
-
depth,
|
|
492
|
-
name,
|
|
493
|
-
data,
|
|
494
|
-
isNonenumerable,
|
|
495
|
-
expanded,
|
|
496
|
-
}: any) => {
|
|
497
|
-
const direction = event.type === "send" ? "up" : "down";
|
|
498
|
-
|
|
499
|
-
return depth === 0 ? (
|
|
500
|
-
<ObjectRootLabel direction={direction} data={data} />
|
|
501
|
-
) : (
|
|
502
|
-
<ObjectLabel
|
|
503
|
-
direction={direction}
|
|
504
|
-
name={name}
|
|
505
|
-
data={data}
|
|
506
|
-
isNonenumerable={isNonenumerable}
|
|
507
|
-
/>
|
|
508
|
-
);
|
|
509
|
-
}}
|
|
510
|
-
/>
|
|
511
|
-
</div>
|
|
512
|
-
)}
|
|
513
|
-
</div>
|
|
580
|
+
<ObjectInspector
|
|
581
|
+
name={task.name}
|
|
582
|
+
data={task.payload}
|
|
583
|
+
theme={theme}
|
|
584
|
+
/>
|
|
585
|
+
</InspectorRow>
|
|
514
586
|
))}
|
|
587
|
+
</div>
|
|
588
|
+
</DisclosureSection>
|
|
589
|
+
<DisclosureSection
|
|
590
|
+
open={showEvents}
|
|
591
|
+
setOpen={setShowEvents}
|
|
592
|
+
title="Events"
|
|
593
|
+
colorScheme={colorScheme}
|
|
594
|
+
>
|
|
595
|
+
<div ref={eventsContainerRef} style={styles.sectionInner}>
|
|
596
|
+
{connectionEvents?.map((event, index) =>
|
|
597
|
+
event.type === "stateChange" ? (
|
|
598
|
+
<InspectorRow key={index} colorScheme={colorScheme}>
|
|
599
|
+
connection:{" "}
|
|
600
|
+
<span style={{ fontStyle: "italic" }}>
|
|
601
|
+
{event.state.toLowerCase()}
|
|
602
|
+
</span>
|
|
603
|
+
</InspectorRow>
|
|
604
|
+
) : (
|
|
605
|
+
<InspectorRow
|
|
606
|
+
key={index}
|
|
607
|
+
colorScheme={colorScheme}
|
|
608
|
+
variant={event.type === "send" ? "up" : "down"}
|
|
609
|
+
style={{
|
|
610
|
+
padding: "0px 12px 1px",
|
|
611
|
+
}}
|
|
612
|
+
>
|
|
613
|
+
<ObjectInspector
|
|
614
|
+
data={event.message}
|
|
615
|
+
theme={theme}
|
|
616
|
+
nodeRenderer={({
|
|
617
|
+
depth,
|
|
618
|
+
name,
|
|
619
|
+
data,
|
|
620
|
+
isNonenumerable,
|
|
621
|
+
expanded,
|
|
622
|
+
}: any) => {
|
|
623
|
+
const direction = event.type === "send" ? "up" : "down";
|
|
624
|
+
|
|
625
|
+
return depth === 0 ? (
|
|
626
|
+
<ObjectRootLabel direction={direction} data={data} />
|
|
627
|
+
) : (
|
|
628
|
+
<ObjectLabel
|
|
629
|
+
direction={direction}
|
|
630
|
+
name={name}
|
|
631
|
+
data={data}
|
|
632
|
+
isNonenumerable={isNonenumerable}
|
|
633
|
+
/>
|
|
634
|
+
);
|
|
635
|
+
}}
|
|
636
|
+
/>
|
|
637
|
+
</InspectorRow>
|
|
638
|
+
)
|
|
639
|
+
)}
|
|
515
640
|
{!connectionEvents && (
|
|
516
641
|
<div
|
|
517
642
|
style={{
|
|
@@ -604,61 +729,6 @@ function Arrow({
|
|
|
604
729
|
);
|
|
605
730
|
}
|
|
606
731
|
|
|
607
|
-
// <div className="flex py-px flex-col-reverse">
|
|
608
|
-
// <button
|
|
609
|
-
// type="button"
|
|
610
|
-
// className={cx(
|
|
611
|
-
// "px-4 py-2 cursor-pointer text-left",
|
|
612
|
-
// 0 === historySnapshot.historyIndex && "bg-orange-500/25"
|
|
613
|
-
// )}
|
|
614
|
-
// onClick={() => {
|
|
615
|
-
// // stateManager.goToHistoryIndex(0);
|
|
616
|
-
// }}
|
|
617
|
-
// >
|
|
618
|
-
// <div className="flex justify-between gap-2">
|
|
619
|
-
// <span>Initial State</span>
|
|
620
|
-
// </div>
|
|
621
|
-
// </button>
|
|
622
|
-
// {historySnapshot.history.map((entry, index) => (
|
|
623
|
-
// <button
|
|
624
|
-
// key={index}
|
|
625
|
-
// type="button"
|
|
626
|
-
// className={cx(
|
|
627
|
-
// "px-4 py-2 cursor-pointer text-left",
|
|
628
|
-
// index === historySnapshot.historyIndex - 1 &&
|
|
629
|
-
// "bg-orange-500/25"
|
|
630
|
-
// )}
|
|
631
|
-
// onClick={() => {
|
|
632
|
-
// // stateManager.goToHistoryIndex(index + 1);
|
|
633
|
-
// }}
|
|
634
|
-
// >
|
|
635
|
-
// <div className="flex justify-between gap-2">
|
|
636
|
-
// <span>
|
|
637
|
-
// {index + 1}. {entry.metadata.name}
|
|
638
|
-
// </span>
|
|
639
|
-
// <span>
|
|
640
|
-
// {new Date(
|
|
641
|
-
// entry.metadata.timestamp
|
|
642
|
-
// ).toLocaleTimeString()}
|
|
643
|
-
// </span>
|
|
644
|
-
// </div>
|
|
645
|
-
// <div className="font-mono text-xs">
|
|
646
|
-
// {entry.redoPatches?.map((patch, index) => (
|
|
647
|
-
// <pre key={index} className="max-w-full">
|
|
648
|
-
// {patch.op === "remove"
|
|
649
|
-
// ? `Delete ${pathToString(patch.path)}`
|
|
650
|
-
// : `${pathToString(patch.path)} = ${JSON.stringify(
|
|
651
|
-
// patch.value,
|
|
652
|
-
// null,
|
|
653
|
-
// 2
|
|
654
|
-
// )}`}
|
|
655
|
-
// </pre>
|
|
656
|
-
// ))}
|
|
657
|
-
// </div>
|
|
658
|
-
// </button>
|
|
659
|
-
// ))}
|
|
660
|
-
// </div>
|
|
661
|
-
|
|
662
732
|
function pathToString(extendedPath: ExtendedPathKey[]) {
|
|
663
733
|
return extendedPath
|
|
664
734
|
.map((key) =>
|
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ConnectionEvent,
|
|
5
|
+
MultiplayerStateManager,
|
|
6
|
+
MultiplayerUser,
|
|
7
|
+
Task,
|
|
8
|
+
} from "@noya-app/state-manager";
|
|
2
9
|
import React, { ComponentProps, useLayoutEffect } from "react";
|
|
3
10
|
import { createRoot } from "react-dom/client";
|
|
4
11
|
|
|
@@ -14,15 +21,21 @@ function createPortalElement() {
|
|
|
14
21
|
export function useStateInspector<S extends object, M>({
|
|
15
22
|
state,
|
|
16
23
|
connectionEvents,
|
|
24
|
+
connectedUsers,
|
|
25
|
+
tasks,
|
|
26
|
+
userId,
|
|
17
27
|
disabled = false,
|
|
18
28
|
colorScheme,
|
|
19
29
|
anchor,
|
|
20
|
-
|
|
30
|
+
multiplayerStateManager,
|
|
21
31
|
}: {
|
|
22
32
|
state: S;
|
|
23
33
|
connectionEvents?: ConnectionEvent<S>[];
|
|
34
|
+
connectedUsers?: MultiplayerUser[];
|
|
35
|
+
tasks?: Task[];
|
|
36
|
+
userId?: string;
|
|
24
37
|
disabled: boolean;
|
|
25
|
-
|
|
38
|
+
multiplayerStateManager: MultiplayerStateManager<S, M>;
|
|
26
39
|
} & Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">) {
|
|
27
40
|
const [root, setRoot] = React.useState<Root | null>(null);
|
|
28
41
|
|
|
@@ -49,10 +62,25 @@ export function useStateInspector<S extends object, M>({
|
|
|
49
62
|
<StateInspector
|
|
50
63
|
state={state}
|
|
51
64
|
connectionEvents={connectionEvents}
|
|
65
|
+
connectedUsers={connectedUsers}
|
|
66
|
+
tasks={tasks}
|
|
67
|
+
userId={userId}
|
|
52
68
|
colorScheme={colorScheme}
|
|
53
69
|
anchor={anchor}
|
|
54
|
-
|
|
70
|
+
multiplayerStateManager={
|
|
71
|
+
multiplayerStateManager as MultiplayerStateManager<any, any>
|
|
72
|
+
}
|
|
55
73
|
/>
|
|
56
74
|
);
|
|
57
|
-
}, [
|
|
75
|
+
}, [
|
|
76
|
+
anchor,
|
|
77
|
+
colorScheme,
|
|
78
|
+
connectedUsers,
|
|
79
|
+
connectionEvents,
|
|
80
|
+
root,
|
|
81
|
+
state,
|
|
82
|
+
multiplayerStateManager,
|
|
83
|
+
userId,
|
|
84
|
+
tasks,
|
|
85
|
+
]);
|
|
58
86
|
}
|