@noya-app/noya-multiplayer-react 0.1.12 → 0.1.14
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 +9 -5
- package/dist/index.d.ts +9 -5
- package/dist/index.js +228 -36
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +228 -36
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/globals.ts +2 -1
- package/src/hooks.ts +60 -16
- package/src/inspector/StateInspector.tsx +185 -18
- package/src/inspector/useLocalStorageState.tsx +2 -0
- package/src/inspector/useStateInspector.tsx +18 -5
package/dist/index.mjs
CHANGED
|
@@ -46,7 +46,8 @@ function useObservable(observable) {
|
|
|
46
46
|
}, [observable]);
|
|
47
47
|
return value;
|
|
48
48
|
}
|
|
49
|
-
var
|
|
49
|
+
var shouldTrackEvents$ = new Observable(false);
|
|
50
|
+
var shouldTrackTasks$ = new Observable(false);
|
|
50
51
|
|
|
51
52
|
// src/inspector/useStateInspector.tsx
|
|
52
53
|
import React3, { useLayoutEffect as useLayoutEffect2 } from "react";
|
|
@@ -223,7 +224,7 @@ function DisclosureSection({
|
|
|
223
224
|
}
|
|
224
225
|
}
|
|
225
226
|
),
|
|
226
|
-
/* @__PURE__ */ React2.createElement("span", { style: { flex: "1 1 0" } }, title),
|
|
227
|
+
/* @__PURE__ */ React2.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
|
|
227
228
|
right
|
|
228
229
|
),
|
|
229
230
|
open && children
|
|
@@ -274,11 +275,13 @@ var StateInspector = memo(function StateInspector2({
|
|
|
274
275
|
state,
|
|
275
276
|
connectionEvents,
|
|
276
277
|
connectedUsers,
|
|
278
|
+
tasks,
|
|
277
279
|
userId,
|
|
278
280
|
unstyled,
|
|
279
281
|
colorScheme = "light",
|
|
280
|
-
|
|
282
|
+
multiplayerStateManager,
|
|
281
283
|
anchor = "right",
|
|
284
|
+
forceInit,
|
|
282
285
|
...props
|
|
283
286
|
}) {
|
|
284
287
|
const [didMount, setDidMount] = React2.useState(false);
|
|
@@ -307,15 +310,22 @@ var StateInspector = memo(function StateInspector2({
|
|
|
307
310
|
"noya-multiplayer-react-show-data",
|
|
308
311
|
true
|
|
309
312
|
);
|
|
313
|
+
const [showTasks, setShowTasks] = useLocalStorageState(
|
|
314
|
+
"noya-multiplayer-react-show-tasks",
|
|
315
|
+
false
|
|
316
|
+
);
|
|
310
317
|
useEffect2(() => {
|
|
311
|
-
|
|
318
|
+
shouldTrackEvents$.set(showEvents);
|
|
312
319
|
}, [showEvents]);
|
|
320
|
+
useEffect2(() => {
|
|
321
|
+
shouldTrackTasks$.set(showTasks);
|
|
322
|
+
}, [showTasks]);
|
|
313
323
|
useEffect2(() => {
|
|
314
324
|
if (eventsContainerRef.current) {
|
|
315
325
|
eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
|
|
316
326
|
}
|
|
317
327
|
}, [connectionEvents]);
|
|
318
|
-
const historySnapshot = useManagedHistory(
|
|
328
|
+
const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
|
|
319
329
|
useEffect2(() => {
|
|
320
330
|
if (historyContainerRef.current) {
|
|
321
331
|
historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
|
|
@@ -339,7 +349,7 @@ var StateInspector = memo(function StateInspector2({
|
|
|
339
349
|
const baseStyle = {
|
|
340
350
|
position: "fixed",
|
|
341
351
|
top: 12,
|
|
342
|
-
...anchor
|
|
352
|
+
...anchor.includes("right") ? { right: 12 } : { left: 12 },
|
|
343
353
|
bottom: 12,
|
|
344
354
|
width: 400,
|
|
345
355
|
background: colorScheme === "light" ? "rgba(255,255,255,0.95)" : "rgba(0,0,0,0.95)",
|
|
@@ -365,8 +375,8 @@ var StateInspector = memo(function StateInspector2({
|
|
|
365
375
|
style: {
|
|
366
376
|
...baseStyle,
|
|
367
377
|
padding: "4px 10px",
|
|
368
|
-
|
|
369
|
-
|
|
378
|
+
width: void 0,
|
|
379
|
+
...anchor.includes("bottom") ? { bottom: 12, top: void 0 } : { bottom: void 0 }
|
|
370
380
|
},
|
|
371
381
|
onClick: () => setShowInspector(true)
|
|
372
382
|
},
|
|
@@ -443,19 +453,42 @@ var StateInspector = memo(function StateInspector2({
|
|
|
443
453
|
title: "Data",
|
|
444
454
|
colorScheme,
|
|
445
455
|
setOpen: setShowData,
|
|
446
|
-
open: showData
|
|
456
|
+
open: showData,
|
|
457
|
+
right: /* @__PURE__ */ React2.createElement(
|
|
458
|
+
"span",
|
|
459
|
+
{
|
|
460
|
+
style: {
|
|
461
|
+
display: "flex",
|
|
462
|
+
gap: "4px"
|
|
463
|
+
}
|
|
464
|
+
},
|
|
465
|
+
/* @__PURE__ */ React2.createElement(
|
|
466
|
+
SmallButton,
|
|
467
|
+
{
|
|
468
|
+
theme,
|
|
469
|
+
onClick: () => {
|
|
470
|
+
forceInit();
|
|
471
|
+
}
|
|
472
|
+
},
|
|
473
|
+
"Reset"
|
|
474
|
+
)
|
|
475
|
+
)
|
|
447
476
|
},
|
|
448
|
-
/* @__PURE__ */ React2.createElement(
|
|
449
|
-
|
|
477
|
+
/* @__PURE__ */ React2.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ React2.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React2.createElement(
|
|
478
|
+
ObjectInspector,
|
|
450
479
|
{
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
480
|
+
name: multiplayerStateManager.sm.schema ? "state" : void 0,
|
|
481
|
+
data: state,
|
|
482
|
+
theme
|
|
483
|
+
}
|
|
484
|
+
)), multiplayerStateManager.sm.schema && /* @__PURE__ */ React2.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ React2.createElement(
|
|
485
|
+
ObjectInspector,
|
|
486
|
+
{
|
|
487
|
+
name: "schema",
|
|
488
|
+
data: multiplayerStateManager.sm.schema,
|
|
489
|
+
theme
|
|
490
|
+
}
|
|
491
|
+
)))
|
|
459
492
|
),
|
|
460
493
|
/* @__PURE__ */ React2.createElement(
|
|
461
494
|
DisclosureSection,
|
|
@@ -463,7 +496,68 @@ var StateInspector = memo(function StateInspector2({
|
|
|
463
496
|
open: showHistory,
|
|
464
497
|
setOpen: setShowHistory,
|
|
465
498
|
title: "History",
|
|
466
|
-
colorScheme
|
|
499
|
+
colorScheme,
|
|
500
|
+
right: /* @__PURE__ */ React2.createElement(
|
|
501
|
+
"span",
|
|
502
|
+
{
|
|
503
|
+
style: {
|
|
504
|
+
display: "flex",
|
|
505
|
+
gap: "4px"
|
|
506
|
+
}
|
|
507
|
+
},
|
|
508
|
+
/* @__PURE__ */ React2.createElement(
|
|
509
|
+
SmallButton,
|
|
510
|
+
{
|
|
511
|
+
disabled: !historySnapshot.canUndo,
|
|
512
|
+
theme,
|
|
513
|
+
onClick: () => {
|
|
514
|
+
multiplayerStateManager.sm.undo();
|
|
515
|
+
}
|
|
516
|
+
},
|
|
517
|
+
/* @__PURE__ */ React2.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React2.createElement(
|
|
518
|
+
"svg",
|
|
519
|
+
{
|
|
520
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
521
|
+
width: "1em",
|
|
522
|
+
height: "1em",
|
|
523
|
+
viewBox: "0 0 20 20"
|
|
524
|
+
},
|
|
525
|
+
/* @__PURE__ */ React2.createElement(
|
|
526
|
+
"path",
|
|
527
|
+
{
|
|
528
|
+
fill: "currentColor",
|
|
529
|
+
d: "M12 5H7V2L1 6l6 4V7h5c2.2 0 4 1.8 4 4s-1.8 4-4 4H7v2h5c3.3 0 6-2.7 6-6s-2.7-6-6-6"
|
|
530
|
+
}
|
|
531
|
+
)
|
|
532
|
+
))
|
|
533
|
+
),
|
|
534
|
+
/* @__PURE__ */ React2.createElement(
|
|
535
|
+
SmallButton,
|
|
536
|
+
{
|
|
537
|
+
disabled: !historySnapshot.canRedo,
|
|
538
|
+
theme,
|
|
539
|
+
onClick: () => {
|
|
540
|
+
multiplayerStateManager.sm.redo();
|
|
541
|
+
}
|
|
542
|
+
},
|
|
543
|
+
/* @__PURE__ */ React2.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ React2.createElement(
|
|
544
|
+
"svg",
|
|
545
|
+
{
|
|
546
|
+
xmlns: "http://www.w3.org/2000/svg",
|
|
547
|
+
width: "1em",
|
|
548
|
+
height: "1em",
|
|
549
|
+
viewBox: "0 0 20 20"
|
|
550
|
+
},
|
|
551
|
+
/* @__PURE__ */ React2.createElement(
|
|
552
|
+
"path",
|
|
553
|
+
{
|
|
554
|
+
fill: "currentColor",
|
|
555
|
+
d: "M8 5h5V2l6 4l-6 4V7H8c-2.2 0-4 1.8-4 4s1.8 4 4 4h5v2H8c-3.3 0-6-2.7-6-6s2.7-6 6-6"
|
|
556
|
+
}
|
|
557
|
+
)
|
|
558
|
+
))
|
|
559
|
+
)
|
|
560
|
+
)
|
|
467
561
|
},
|
|
468
562
|
/* @__PURE__ */ React2.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ React2.createElement(
|
|
469
563
|
"div",
|
|
@@ -518,6 +612,33 @@ var StateInspector = memo(function StateInspector2({
|
|
|
518
612
|
))
|
|
519
613
|
)))
|
|
520
614
|
),
|
|
615
|
+
/* @__PURE__ */ React2.createElement(
|
|
616
|
+
DisclosureSection,
|
|
617
|
+
{
|
|
618
|
+
title: "Tasks",
|
|
619
|
+
colorScheme,
|
|
620
|
+
open: showTasks,
|
|
621
|
+
setOpen: setShowTasks
|
|
622
|
+
},
|
|
623
|
+
/* @__PURE__ */ React2.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ React2.createElement(
|
|
624
|
+
InspectorRow,
|
|
625
|
+
{
|
|
626
|
+
key: task.id,
|
|
627
|
+
colorScheme,
|
|
628
|
+
style: {
|
|
629
|
+
backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
|
|
630
|
+
}
|
|
631
|
+
},
|
|
632
|
+
/* @__PURE__ */ React2.createElement(
|
|
633
|
+
ObjectInspector,
|
|
634
|
+
{
|
|
635
|
+
name: task.name,
|
|
636
|
+
data: task.payload,
|
|
637
|
+
theme
|
|
638
|
+
}
|
|
639
|
+
)
|
|
640
|
+
)))
|
|
641
|
+
),
|
|
521
642
|
/* @__PURE__ */ React2.createElement(
|
|
522
643
|
DisclosureSection,
|
|
523
644
|
{
|
|
@@ -648,6 +769,42 @@ function ellipsis(str, maxLength, position = "end") {
|
|
|
648
769
|
return `${str.slice(0, maxLength)}\u2026`;
|
|
649
770
|
}
|
|
650
771
|
}
|
|
772
|
+
function SmallButton({
|
|
773
|
+
children,
|
|
774
|
+
onClick,
|
|
775
|
+
style,
|
|
776
|
+
theme,
|
|
777
|
+
disabled
|
|
778
|
+
}) {
|
|
779
|
+
return /* @__PURE__ */ React2.createElement(
|
|
780
|
+
"button",
|
|
781
|
+
{
|
|
782
|
+
type: "button",
|
|
783
|
+
disabled,
|
|
784
|
+
onClick: (event) => {
|
|
785
|
+
event.stopPropagation();
|
|
786
|
+
onClick();
|
|
787
|
+
},
|
|
788
|
+
style: {
|
|
789
|
+
flex: "0",
|
|
790
|
+
appearance: "none",
|
|
791
|
+
background: "none",
|
|
792
|
+
color: theme.BASE_COLOR,
|
|
793
|
+
opacity: disabled ? 0.25 : 1,
|
|
794
|
+
border: "none",
|
|
795
|
+
fontSize: "12px",
|
|
796
|
+
whiteSpace: "nowrap",
|
|
797
|
+
display: "inline-flex",
|
|
798
|
+
alignItems: "center",
|
|
799
|
+
justifyContent: "center",
|
|
800
|
+
padding: "2px 0",
|
|
801
|
+
cursor: "pointer",
|
|
802
|
+
...style
|
|
803
|
+
}
|
|
804
|
+
},
|
|
805
|
+
children
|
|
806
|
+
);
|
|
807
|
+
}
|
|
651
808
|
|
|
652
809
|
// src/inspector/useStateInspector.tsx
|
|
653
810
|
function createPortalElement() {
|
|
@@ -659,11 +816,13 @@ function useStateInspector({
|
|
|
659
816
|
state,
|
|
660
817
|
connectionEvents,
|
|
661
818
|
connectedUsers,
|
|
819
|
+
tasks,
|
|
662
820
|
userId,
|
|
663
821
|
disabled = false,
|
|
664
822
|
colorScheme,
|
|
665
823
|
anchor,
|
|
666
|
-
|
|
824
|
+
multiplayerStateManager,
|
|
825
|
+
forceInit
|
|
667
826
|
}) {
|
|
668
827
|
const [root, setRoot] = React3.useState(null);
|
|
669
828
|
useLayoutEffect2(() => {
|
|
@@ -687,10 +846,12 @@ function useStateInspector({
|
|
|
687
846
|
state,
|
|
688
847
|
connectionEvents,
|
|
689
848
|
connectedUsers,
|
|
849
|
+
tasks,
|
|
690
850
|
userId,
|
|
691
851
|
colorScheme,
|
|
692
852
|
anchor,
|
|
693
|
-
|
|
853
|
+
forceInit,
|
|
854
|
+
multiplayerStateManager
|
|
694
855
|
}
|
|
695
856
|
)
|
|
696
857
|
);
|
|
@@ -701,8 +862,10 @@ function useStateInspector({
|
|
|
701
862
|
connectionEvents,
|
|
702
863
|
root,
|
|
703
864
|
state,
|
|
704
|
-
|
|
705
|
-
userId
|
|
865
|
+
multiplayerStateManager,
|
|
866
|
+
userId,
|
|
867
|
+
tasks,
|
|
868
|
+
forceInit
|
|
706
869
|
]);
|
|
707
870
|
}
|
|
708
871
|
|
|
@@ -774,58 +937,87 @@ function useSyncMultiplayerStateManager(multiplayerStateManager) {
|
|
|
774
937
|
}
|
|
775
938
|
var defaultStubSync = stubSync();
|
|
776
939
|
function useMultiplayerState(initialState, options) {
|
|
777
|
-
const { sync = defaultStubSync, ...rest } = options;
|
|
940
|
+
const { sync = defaultStubSync, ...rest } = options ?? {};
|
|
778
941
|
const [multiplayerStateManager] = useState2(
|
|
779
942
|
() => new MultiplayerStateManager(initialState, rest)
|
|
780
943
|
);
|
|
781
944
|
const syncRef = useRef(sync);
|
|
782
945
|
const [connectionEvents, setConnectionEvents] = useState2();
|
|
783
946
|
const [connectedUsers, setConnectedUsers] = useState2([]);
|
|
947
|
+
const [tasks, setTasks] = useState2([]);
|
|
784
948
|
const [userId, setUserId] = useState2();
|
|
785
949
|
const extras = useMemo(() => {
|
|
786
950
|
return {
|
|
951
|
+
tasks,
|
|
787
952
|
connectionEvents,
|
|
788
953
|
connectedUsers
|
|
954
|
+
// evaluate: async (code: string) => {
|
|
955
|
+
// const payload = await rpcManager.request({ type: "eval", code });
|
|
956
|
+
// if (payload.type !== "eval") {
|
|
957
|
+
// throw new Error(`Unexpected rpc response type: ${payload.type}`);
|
|
958
|
+
// }
|
|
959
|
+
// },
|
|
789
960
|
};
|
|
790
|
-
}, [connectionEvents, connectedUsers]);
|
|
791
|
-
const globalTrackEvents = useObservable(
|
|
792
|
-
const
|
|
961
|
+
}, [tasks, connectionEvents, connectedUsers]);
|
|
962
|
+
const globalTrackEvents = useObservable(shouldTrackEvents$);
|
|
963
|
+
const globalTrackTasks = useObservable(shouldTrackTasks$);
|
|
964
|
+
const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
|
|
965
|
+
const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
|
|
793
966
|
const trackEventsCallbackRef = useRef();
|
|
794
967
|
const trackConnectedUsersCallbackRef = useRef();
|
|
968
|
+
const trackTasksCallbackRef = useRef();
|
|
795
969
|
useEffect3(() => {
|
|
796
|
-
trackEventsCallbackRef.current =
|
|
970
|
+
trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
|
|
797
971
|
const updated = events ? [...events, e] : [e];
|
|
798
972
|
return updated.length > 50 ? updated.slice(-50) : updated;
|
|
799
973
|
}) : void 0;
|
|
800
|
-
}, [
|
|
974
|
+
}, [shouldTrackEvents]);
|
|
801
975
|
useEffect3(() => {
|
|
802
976
|
trackConnectedUsersCallbackRef.current = (users, userId2) => {
|
|
803
977
|
setConnectedUsers(users);
|
|
804
978
|
setUserId(userId2);
|
|
805
979
|
};
|
|
806
|
-
});
|
|
980
|
+
}, []);
|
|
981
|
+
useEffect3(() => {
|
|
982
|
+
trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
|
|
983
|
+
setTasks((old) => {
|
|
984
|
+
const newIds = new Set(tasks2.map((t) => t.id));
|
|
985
|
+
const unchanged = old.filter((t) => !newIds.has(t.id));
|
|
986
|
+
return [...unchanged, ...tasks2];
|
|
987
|
+
});
|
|
988
|
+
} : void 0;
|
|
989
|
+
}, [shouldTrackTasks]);
|
|
807
990
|
useEffect3(() => {
|
|
808
991
|
if (syncRef.current) {
|
|
809
992
|
return syncRef.current({
|
|
810
993
|
ms: multiplayerStateManager,
|
|
811
994
|
onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
|
|
812
|
-
onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2)
|
|
995
|
+
onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2),
|
|
996
|
+
onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
|
|
813
997
|
});
|
|
814
998
|
}
|
|
815
999
|
}, [multiplayerStateManager]);
|
|
816
1000
|
const state = useSyncMultiplayerStateManager(multiplayerStateManager);
|
|
1001
|
+
const forceInit = useCallback(() => {
|
|
1002
|
+
const state2 = typeof initialState === "function" ? initialState() : initialState;
|
|
1003
|
+
const schema = options?.schema;
|
|
1004
|
+
multiplayerStateManager.sm.clearHistory();
|
|
1005
|
+
multiplayerStateManager.sendInit({ force: true, state: state2, schema });
|
|
1006
|
+
}, [initialState, multiplayerStateManager, options?.schema]);
|
|
817
1007
|
useStateInspector({
|
|
818
|
-
|
|
1008
|
+
multiplayerStateManager,
|
|
819
1009
|
state,
|
|
820
1010
|
connectionEvents,
|
|
821
1011
|
connectedUsers,
|
|
1012
|
+
tasks,
|
|
822
1013
|
userId,
|
|
823
|
-
|
|
824
|
-
|
|
1014
|
+
forceInit,
|
|
1015
|
+
disabled: !options?.inspector,
|
|
1016
|
+
...typeof options?.inspector === "object" && options.inspector
|
|
825
1017
|
});
|
|
826
1018
|
return [
|
|
827
1019
|
state,
|
|
828
|
-
multiplayerStateManager.
|
|
1020
|
+
multiplayerStateManager.setState,
|
|
829
1021
|
multiplayerStateManager,
|
|
830
1022
|
extras
|
|
831
1023
|
];
|