@noya-app/noya-multiplayer-react 0.1.12 → 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.
@@ -5,14 +5,14 @@
5
5
  CLI Target: esnext
6
6
  CJS Build start
7
7
  ESM Build start
8
- ESM dist/index.mjs 23.51 KB
9
- ESM dist/index.mjs.map 43.29 KB
10
- ESM ⚡️ Build success in 19ms
11
- CJS dist/index.js 27.13 KB
12
- CJS dist/index.js.map 43.09 KB
13
- CJS ⚡️ Build success in 19ms
8
+ ESM dist/index.mjs 25.93 KB
9
+ ESM dist/index.mjs.map 47.90 KB
10
+ ESM ⚡️ Build success in 21ms
11
+ CJS dist/index.js 29.76 KB
12
+ CJS dist/index.js.map 47.69 KB
13
+ CJS ⚡️ Build success in 21ms
14
14
  DTS Build start
15
15
  "ComponentPropsWithoutRef" is imported from external module "react" but never used in "src/inspector/StateInspector.tsx" and "src/hooks.ts".
16
- DTS ⚡️ Build success in 1607ms
17
- DTS dist/index.d.ts 2.50 KB
18
- DTS dist/index.d.mts 2.50 KB
16
+ DTS ⚡️ Build success in 1253ms
17
+ DTS dist/index.d.ts 2.65 KB
18
+ DTS dist/index.d.mts 2.65 KB
package/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @noya-app/state-manager
2
2
 
3
+ ## 0.1.13
4
+
5
+ ### Patch Changes
6
+
7
+ - 149f2f9: Improve multiplayer
8
+ - Updated dependencies [149f2f9]
9
+ - @noya-app/state-manager@0.1.13
10
+
3
11
  ## 0.1.12
4
12
 
5
13
  ### Patch Changes
package/dist/index.d.mts CHANGED
@@ -1,17 +1,18 @@
1
1
  import * as _noya_app_state_manager from '@noya-app/state-manager';
2
- import { ConnectionEvent, MultiplayerUser, StateManager, Get, StateManagerOptions, MultiplayerStateManager, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
2
+ import { ConnectionEvent, MultiplayerUser, Task, MultiplayerStateManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
3
3
  export * from '@noya-app/state-manager';
4
4
  import React, { SetStateAction, ComponentProps } from 'react';
5
5
 
6
- type Anchor = "left" | "right";
7
- declare const StateInspector: React.MemoExoticComponent<(<S extends object, M>({ state, connectionEvents, connectedUsers, userId, unstyled, colorScheme, stateManager, anchor, ...props }: {
6
+ type Anchor = "left" | "right" | "bottom left" | "bottom right";
7
+ declare const StateInspector: React.MemoExoticComponent<(<S extends object, M>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, anchor, ...props }: {
8
8
  state: S;
9
9
  connectionEvents?: ConnectionEvent<S>[] | undefined;
10
10
  connectedUsers?: MultiplayerUser[] | undefined;
11
+ tasks?: Task[] | undefined;
11
12
  userId?: string | undefined;
12
13
  unstyled?: boolean | undefined;
13
14
  colorScheme?: "light" | "dark" | undefined;
14
- stateManager: StateManager<S, M>;
15
+ multiplayerStateManager: MultiplayerStateManager<S, M>;
15
16
  anchor?: Anchor | undefined;
16
17
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">) => React.JSX.Element | null)>;
17
18
 
@@ -20,13 +21,15 @@ declare function useSyncStateManager<S extends object, M, P extends string>(stat
20
21
  declare function useManagedState<S extends object, M = void>(createInitialState: () => S, options?: StateManagerOptions<S, M>): readonly [S, (...args: M extends {} ? [metadata: M, action: SetStateAction<S>] : [action: SetStateAction<S>]) => void, StateManager<S, M>];
21
22
  declare function useManagedHistory<S extends object, M = void>(stateManager: StateManager<S, M>): _noya_app_state_manager.HistorySnapshot<S, M>;
22
23
  declare function useSyncMultiplayerStateManager<S extends object, M = void>(multiplayerStateManager: MultiplayerStateManager<S, M>): S;
23
- declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options: MultiplayerStateManagerOptions<S, M> & {
24
+ declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options?: MultiplayerStateManagerOptions<S, M> & {
24
25
  sync?: (options: {
25
26
  ms: MultiplayerStateManager<S, M>;
26
27
  }) => void;
27
28
  trackConnectionEvents?: boolean;
29
+ trackTasks?: boolean;
28
30
  inspector?: boolean | Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
29
31
  }): readonly [S, (...args: M extends {} ? [metadata: M, action: S | ((prevState: S) => S)] : [action: S | ((prevState: S) => S)]) => void, MultiplayerStateManager<S, M>, {
32
+ tasks: Task[];
30
33
  connectionEvents: ConnectionEvent<S>[] | undefined;
31
34
  connectedUsers: MultiplayerUser[];
32
35
  }];
package/dist/index.d.ts CHANGED
@@ -1,17 +1,18 @@
1
1
  import * as _noya_app_state_manager from '@noya-app/state-manager';
2
- import { ConnectionEvent, MultiplayerUser, StateManager, Get, StateManagerOptions, MultiplayerStateManager, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
2
+ import { ConnectionEvent, MultiplayerUser, Task, MultiplayerStateManager, StateManager, Get, StateManagerOptions, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
3
3
  export * from '@noya-app/state-manager';
4
4
  import React, { SetStateAction, ComponentProps } from 'react';
5
5
 
6
- type Anchor = "left" | "right";
7
- declare const StateInspector: React.MemoExoticComponent<(<S extends object, M>({ state, connectionEvents, connectedUsers, userId, unstyled, colorScheme, stateManager, anchor, ...props }: {
6
+ type Anchor = "left" | "right" | "bottom left" | "bottom right";
7
+ declare const StateInspector: React.MemoExoticComponent<(<S extends object, M>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, anchor, ...props }: {
8
8
  state: S;
9
9
  connectionEvents?: ConnectionEvent<S>[] | undefined;
10
10
  connectedUsers?: MultiplayerUser[] | undefined;
11
+ tasks?: Task[] | undefined;
11
12
  userId?: string | undefined;
12
13
  unstyled?: boolean | undefined;
13
14
  colorScheme?: "light" | "dark" | undefined;
14
- stateManager: StateManager<S, M>;
15
+ multiplayerStateManager: MultiplayerStateManager<S, M>;
15
16
  anchor?: Anchor | undefined;
16
17
  } & Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">) => React.JSX.Element | null)>;
17
18
 
@@ -20,13 +21,15 @@ declare function useSyncStateManager<S extends object, M, P extends string>(stat
20
21
  declare function useManagedState<S extends object, M = void>(createInitialState: () => S, options?: StateManagerOptions<S, M>): readonly [S, (...args: M extends {} ? [metadata: M, action: SetStateAction<S>] : [action: SetStateAction<S>]) => void, StateManager<S, M>];
21
22
  declare function useManagedHistory<S extends object, M = void>(stateManager: StateManager<S, M>): _noya_app_state_manager.HistorySnapshot<S, M>;
22
23
  declare function useSyncMultiplayerStateManager<S extends object, M = void>(multiplayerStateManager: MultiplayerStateManager<S, M>): S;
23
- declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options: MultiplayerStateManagerOptions<S, M> & {
24
+ declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options?: MultiplayerStateManagerOptions<S, M> & {
24
25
  sync?: (options: {
25
26
  ms: MultiplayerStateManager<S, M>;
26
27
  }) => void;
27
28
  trackConnectionEvents?: boolean;
29
+ trackTasks?: boolean;
28
30
  inspector?: boolean | Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
29
31
  }): readonly [S, (...args: M extends {} ? [metadata: M, action: S | ((prevState: S) => S)] : [action: S | ((prevState: S) => S)]) => void, MultiplayerStateManager<S, M>, {
32
+ tasks: Task[];
30
33
  connectionEvents: ConnectionEvent<S>[] | undefined;
31
34
  connectedUsers: MultiplayerUser[];
32
35
  }];
package/dist/index.js CHANGED
@@ -75,7 +75,8 @@ function useObservable(observable) {
75
75
  }, [observable]);
76
76
  return value;
77
77
  }
78
- var trackEvents = new Observable(false);
78
+ var shouldTrackEvents$ = new Observable(false);
79
+ var shouldTrackTasks$ = new Observable(false);
79
80
 
80
81
  // src/inspector/useStateInspector.tsx
81
82
  var import_react4 = __toESM(require("react"));
@@ -241,7 +242,7 @@ function DisclosureSection({
241
242
  }
242
243
  }
243
244
  ),
244
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { flex: "1 1 0" } }, title),
245
+ /* @__PURE__ */ import_react3.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
245
246
  right
246
247
  ),
247
248
  open && children
@@ -292,10 +293,11 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
292
293
  state,
293
294
  connectionEvents,
294
295
  connectedUsers,
296
+ tasks,
295
297
  userId,
296
298
  unstyled,
297
299
  colorScheme = "light",
298
- stateManager,
300
+ multiplayerStateManager,
299
301
  anchor = "right",
300
302
  ...props
301
303
  }) {
@@ -325,15 +327,22 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
325
327
  "noya-multiplayer-react-show-data",
326
328
  true
327
329
  );
330
+ const [showTasks, setShowTasks] = useLocalStorageState(
331
+ "noya-multiplayer-react-show-tasks",
332
+ false
333
+ );
328
334
  (0, import_react3.useEffect)(() => {
329
- trackEvents.set(showEvents);
335
+ shouldTrackEvents$.set(showEvents);
330
336
  }, [showEvents]);
337
+ (0, import_react3.useEffect)(() => {
338
+ shouldTrackTasks$.set(showTasks);
339
+ }, [showTasks]);
331
340
  (0, import_react3.useEffect)(() => {
332
341
  if (eventsContainerRef.current) {
333
342
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
334
343
  }
335
344
  }, [connectionEvents]);
336
- const historySnapshot = useManagedHistory(stateManager);
345
+ const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
337
346
  (0, import_react3.useEffect)(() => {
338
347
  if (historyContainerRef.current) {
339
348
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
@@ -357,7 +366,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
357
366
  const baseStyle = {
358
367
  position: "fixed",
359
368
  top: 12,
360
- ...anchor === "right" ? { right: 12 } : { left: 12 },
369
+ ...anchor.includes("right") ? { right: 12 } : { left: 12 },
361
370
  bottom: 12,
362
371
  width: 400,
363
372
  background: colorScheme === "light" ? "rgba(255,255,255,0.95)" : "rgba(0,0,0,0.95)",
@@ -383,8 +392,8 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
383
392
  style: {
384
393
  ...baseStyle,
385
394
  padding: "4px 10px",
386
- bottom: void 0,
387
- width: void 0
395
+ width: void 0,
396
+ ...anchor.includes("bottom") ? { bottom: 12, top: void 0 } : { bottom: void 0 }
388
397
  },
389
398
  onClick: () => setShowInspector(true)
390
399
  },
@@ -463,17 +472,21 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
463
472
  setOpen: setShowData,
464
473
  open: showData
465
474
  },
466
- /* @__PURE__ */ import_react3.default.createElement(
467
- "div",
475
+ /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
476
+ import_react_inspector.ObjectInspector,
468
477
  {
469
- style: {
470
- ...styles.sectionInner,
471
- gap: "1px",
472
- padding: "1px 12px"
473
- }
474
- },
475
- /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: state, theme })
476
- )
478
+ name: multiplayerStateManager.sm.schema ? "state" : void 0,
479
+ data: state,
480
+ theme
481
+ }
482
+ )), multiplayerStateManager.sm.schema && /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
483
+ import_react_inspector.ObjectInspector,
484
+ {
485
+ name: "schema",
486
+ data: multiplayerStateManager.sm.schema,
487
+ theme
488
+ }
489
+ )))
477
490
  ),
478
491
  /* @__PURE__ */ import_react3.default.createElement(
479
492
  DisclosureSection,
@@ -536,6 +549,33 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
536
549
  ))
537
550
  )))
538
551
  ),
552
+ /* @__PURE__ */ import_react3.default.createElement(
553
+ DisclosureSection,
554
+ {
555
+ title: "Tasks",
556
+ colorScheme,
557
+ open: showTasks,
558
+ setOpen: setShowTasks
559
+ },
560
+ /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react3.default.createElement(
561
+ InspectorRow,
562
+ {
563
+ key: task.id,
564
+ colorScheme,
565
+ style: {
566
+ backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
567
+ }
568
+ },
569
+ /* @__PURE__ */ import_react3.default.createElement(
570
+ import_react_inspector.ObjectInspector,
571
+ {
572
+ name: task.name,
573
+ data: task.payload,
574
+ theme
575
+ }
576
+ )
577
+ )))
578
+ ),
539
579
  /* @__PURE__ */ import_react3.default.createElement(
540
580
  DisclosureSection,
541
581
  {
@@ -677,11 +717,12 @@ function useStateInspector({
677
717
  state,
678
718
  connectionEvents,
679
719
  connectedUsers,
720
+ tasks,
680
721
  userId,
681
722
  disabled = false,
682
723
  colorScheme,
683
724
  anchor,
684
- stateManager
725
+ multiplayerStateManager
685
726
  }) {
686
727
  const [root, setRoot] = import_react4.default.useState(null);
687
728
  (0, import_react4.useLayoutEffect)(() => {
@@ -705,10 +746,11 @@ function useStateInspector({
705
746
  state,
706
747
  connectionEvents,
707
748
  connectedUsers,
749
+ tasks,
708
750
  userId,
709
751
  colorScheme,
710
752
  anchor,
711
- stateManager
753
+ multiplayerStateManager
712
754
  }
713
755
  )
714
756
  );
@@ -719,8 +761,9 @@ function useStateInspector({
719
761
  connectionEvents,
720
762
  root,
721
763
  state,
722
- stateManager,
723
- userId
764
+ multiplayerStateManager,
765
+ userId,
766
+ tasks
724
767
  ]);
725
768
  }
726
769
 
@@ -792,58 +835,80 @@ function useSyncMultiplayerStateManager(multiplayerStateManager) {
792
835
  }
793
836
  var defaultStubSync = (0, import_state_manager.stubSync)();
794
837
  function useMultiplayerState(initialState, options) {
795
- const { sync = defaultStubSync, ...rest } = options;
838
+ const { sync = defaultStubSync, ...rest } = options ?? {};
796
839
  const [multiplayerStateManager] = (0, import_react5.useState)(
797
840
  () => new import_state_manager.MultiplayerStateManager(initialState, rest)
798
841
  );
799
842
  const syncRef = (0, import_react5.useRef)(sync);
800
843
  const [connectionEvents, setConnectionEvents] = (0, import_react5.useState)();
801
844
  const [connectedUsers, setConnectedUsers] = (0, import_react5.useState)([]);
845
+ const [tasks, setTasks] = (0, import_react5.useState)([]);
802
846
  const [userId, setUserId] = (0, import_react5.useState)();
803
847
  const extras = (0, import_react5.useMemo)(() => {
804
848
  return {
849
+ tasks,
805
850
  connectionEvents,
806
851
  connectedUsers
852
+ // evaluate: async (code: string) => {
853
+ // const payload = await rpcManager.request({ type: "eval", code });
854
+ // if (payload.type !== "eval") {
855
+ // throw new Error(`Unexpected rpc response type: ${payload.type}`);
856
+ // }
857
+ // },
807
858
  };
808
- }, [connectionEvents, connectedUsers]);
809
- const globalTrackEvents = useObservable(trackEvents);
810
- const trackConnectionEvents = options.trackConnectionEvents ?? globalTrackEvents;
859
+ }, [tasks, connectionEvents, connectedUsers]);
860
+ const globalTrackEvents = useObservable(shouldTrackEvents$);
861
+ const globalTrackTasks = useObservable(shouldTrackTasks$);
862
+ const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
863
+ const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
811
864
  const trackEventsCallbackRef = (0, import_react5.useRef)();
812
865
  const trackConnectedUsersCallbackRef = (0, import_react5.useRef)();
866
+ const trackTasksCallbackRef = (0, import_react5.useRef)();
813
867
  (0, import_react5.useEffect)(() => {
814
- trackEventsCallbackRef.current = trackConnectionEvents ? (e) => setConnectionEvents((events) => {
868
+ trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
815
869
  const updated = events ? [...events, e] : [e];
816
870
  return updated.length > 50 ? updated.slice(-50) : updated;
817
871
  }) : void 0;
818
- }, [trackConnectionEvents]);
872
+ }, [shouldTrackEvents]);
819
873
  (0, import_react5.useEffect)(() => {
820
874
  trackConnectedUsersCallbackRef.current = (users, userId2) => {
821
875
  setConnectedUsers(users);
822
876
  setUserId(userId2);
823
877
  };
824
- });
878
+ }, []);
879
+ (0, import_react5.useEffect)(() => {
880
+ trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
881
+ setTasks((old) => {
882
+ const newIds = new Set(tasks2.map((t) => t.id));
883
+ const unchanged = old.filter((t) => !newIds.has(t.id));
884
+ return [...unchanged, ...tasks2];
885
+ });
886
+ } : void 0;
887
+ }, [shouldTrackTasks]);
825
888
  (0, import_react5.useEffect)(() => {
826
889
  if (syncRef.current) {
827
890
  return syncRef.current({
828
891
  ms: multiplayerStateManager,
829
892
  onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
830
- onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2)
893
+ onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2),
894
+ onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
831
895
  });
832
896
  }
833
897
  }, [multiplayerStateManager]);
834
898
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
835
899
  useStateInspector({
836
- stateManager: multiplayerStateManager.sm,
900
+ multiplayerStateManager,
837
901
  state,
838
902
  connectionEvents,
839
903
  connectedUsers,
904
+ tasks,
840
905
  userId,
841
- disabled: !options.inspector,
842
- ...typeof options.inspector === "object" && options.inspector
906
+ disabled: !options?.inspector,
907
+ ...typeof options?.inspector === "object" && options.inspector
843
908
  });
844
909
  return [
845
910
  state,
846
- multiplayerStateManager.setOptimisticState,
911
+ multiplayerStateManager.setState,
847
912
  multiplayerStateManager,
848
913
  extras
849
914
  ];
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/hooks.ts","../src/globals.ts","../src/inspector/useStateInspector.tsx","../src/inspector/StateInspector.tsx","../src/inspector/useLocalStorageState.tsx"],"sourcesContent":["export * from \"@noya-app/state-manager\";\nexport * from \"./hooks\";\nexport * from \"./inspector/StateInspector\";\n","import {\n ActionHandler,\n ConnectionEvent,\n Get,\n MultiplayerStateManager,\n MultiplayerStateManagerOptions,\n MultiplayerUser,\n StateManager,\n StateManagerOptions,\n SyncAdapter,\n stubSync,\n} from \"@noya-app/state-manager\";\nimport {\n ComponentProps,\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { trackEvents, useObservable } from \"./globals\";\nimport { StateInspector } from \"./inspector/StateInspector\";\nimport { useStateInspector } from \"./inspector/useStateInspector\";\n\nexport function useSyncStateManager<S extends object, M>(\n stateManager: StateManager<S, M>\n): S;\nexport function useSyncStateManager<S extends object, M, P extends string>(\n stateManager: StateManager<S, M>,\n path: P\n): Get<S, P, unknown>;\nexport function useSyncStateManager<S extends object, M>(\n stateManager: StateManager<S, M>,\n path?: string\n) {\n const getSnapshot = useCallback(\n () =>\n typeof path === \"string\"\n ? stateManager.getState(path)\n : stateManager.getState(),\n [stateManager, path]\n );\n\n return useSyncExternalStore(\n stateManager.addListener,\n getSnapshot,\n getSnapshot\n );\n}\n\nexport function useManagedState<S extends object, M = void>(\n createInitialState: () => S,\n options?: StateManagerOptions<S, M>\n) {\n const [stateManager] = useState(\n () => new StateManager<S, M>(createInitialState(), options)\n );\n\n const state = useSyncStateManager(stateManager);\n\n const setState = useCallback(\n (\n ...args: M extends {}\n ? [metadata: M, action: SetStateAction<S>]\n : [action: SetStateAction<S>]\n ) => {\n const [metadata, action] =\n args.length === 1 ? [undefined, args[0]] : args;\n\n if (metadata === undefined) {\n const performActionNoMetadata = stateManager.performAction as (\n handler: ActionHandler<S>\n ) => void;\n\n if (typeof action === \"function\") {\n performActionNoMetadata({\n run: action,\n undo: () => state,\n });\n } else {\n performActionNoMetadata({\n run: () => action,\n undo: () => state,\n });\n }\n } else {\n const performActionWithMetadata = stateManager.performAction as (\n metadata: M,\n handler: ActionHandler<S>\n ) => void;\n\n if (typeof action === \"function\") {\n performActionWithMetadata(metadata, {\n run: action,\n undo: () => state,\n });\n } else {\n performActionWithMetadata(metadata, {\n run: () => action,\n undo: () => state,\n });\n }\n }\n },\n [state, stateManager]\n );\n\n return [state, setState, stateManager] as const;\n}\n\nexport function useManagedHistory<S extends object, M = void>(\n stateManager: StateManager<S, M>\n) {\n return useSyncExternalStore(\n stateManager.historyEmittor.addListener,\n stateManager.getHistorySnapshot,\n stateManager.getHistorySnapshot\n );\n}\n\nexport function useSyncMultiplayerStateManager<S extends object, M = void>(\n multiplayerStateManager: MultiplayerStateManager<S, M>\n) {\n return useSyncExternalStore(\n multiplayerStateManager.addListener,\n multiplayerStateManager.getOptimisticState,\n multiplayerStateManager.getOptimisticState\n );\n}\n\nconst defaultStubSync = stubSync();\n\nexport function useMultiplayerState<S extends object, M = void>(\n initialState: S | (() => S),\n options: MultiplayerStateManagerOptions<S, M> & {\n sync?: (options: { ms: MultiplayerStateManager<S, M> }) => void;\n trackConnectionEvents?: boolean;\n inspector?:\n | boolean\n | Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">;\n }\n) {\n const { sync = defaultStubSync as unknown as SyncAdapter<S, M>, ...rest } =\n options;\n\n const [multiplayerStateManager] = useState(\n () => new MultiplayerStateManager<S, M>(initialState, rest)\n );\n\n const syncRef = useRef(sync);\n\n const [connectionEvents, setConnectionEvents] = useState<\n ConnectionEvent<S>[] | undefined\n >();\n\n const [connectedUsers, setConnectedUsers] = useState<MultiplayerUser[]>([]);\n const [userId, setUserId] = useState<string | undefined>();\n\n const extras = useMemo(() => {\n return {\n connectionEvents,\n connectedUsers,\n };\n }, [connectionEvents, connectedUsers]);\n\n const globalTrackEvents = useObservable(trackEvents);\n const trackConnectionEvents =\n options.trackConnectionEvents ?? globalTrackEvents;\n\n const trackEventsCallbackRef = useRef<\n ((e: ConnectionEvent<S>) => void) | undefined\n >();\n\n const trackConnectedUsersCallbackRef = useRef<\n ((users: MultiplayerUser[], userId: string) => void) | undefined\n >();\n\n useEffect(() => {\n trackEventsCallbackRef.current = trackConnectionEvents\n ? (e) =>\n setConnectionEvents((events) => {\n const updated = events ? [...events, e] : [e];\n return updated.length > 50 ? updated.slice(-50) : updated;\n })\n : undefined;\n }, [trackConnectionEvents]);\n\n useEffect(() => {\n trackConnectedUsersCallbackRef.current = (users, userId) => {\n setConnectedUsers(users);\n setUserId(userId);\n };\n });\n\n useEffect(() => {\n if (syncRef.current) {\n return syncRef.current({\n ms: multiplayerStateManager,\n onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),\n onChangeConnectedUsers: (users, userId) =>\n trackConnectedUsersCallbackRef.current?.(users, userId),\n });\n }\n }, [multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n useStateInspector({\n stateManager: multiplayerStateManager.sm,\n state,\n connectionEvents,\n connectedUsers,\n userId,\n disabled: !options.inspector,\n ...(typeof options.inspector === \"object\" && options.inspector),\n });\n\n return [\n state,\n multiplayerStateManager.setOptimisticState,\n multiplayerStateManager,\n extras,\n ] as const;\n}\n","import { Emitter } from \"@noya-app/emitter\";\nimport { useEffect, useState } from \"react\";\n\nclass Observable<T> {\n private value: T;\n private emitter = new Emitter<[T]>();\n\n constructor(value: T) {\n this.value = value;\n }\n\n get() {\n return this.value;\n }\n\n set(value: T) {\n if (this.value === value) return;\n\n this.value = value;\n\n this.emitter.emit(value);\n }\n\n listen(callback: (value: T) => void) {\n callback(this.value);\n\n return this.emitter.addListener(callback);\n }\n}\n\nexport function useObservable<T>(observable: Observable<T>) {\n const [value, setValue] = useState(observable.get());\n\n useEffect(() => {\n return observable.listen(setValue);\n }, [observable]);\n\n return value;\n}\n\nexport const trackEvents = new Observable(false);\n","import {\n ConnectionEvent,\n MultiplayerUser,\n StateManager,\n} from \"@noya-app/state-manager\";\nimport React, { ComponentProps, useLayoutEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nimport { Root } from \"react-dom/client\";\nimport { StateInspector } from \"./StateInspector\";\n\nfunction createPortalElement() {\n const el = document.createElement(\"div\");\n el.id = \"noya-multiplayer-react-inspector-portal\";\n return el;\n}\n\nexport function useStateInspector<S extends object, M>({\n state,\n connectionEvents,\n connectedUsers,\n userId,\n disabled = false,\n colorScheme,\n anchor,\n stateManager,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n userId?: string;\n disabled: boolean;\n stateManager: StateManager<S, M>;\n} & Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">) {\n const [root, setRoot] = React.useState<Root | null>(null);\n\n useLayoutEffect(() => {\n if (disabled) return;\n\n const portalElement = createPortalElement();\n\n const root = createRoot(portalElement);\n\n document.body.appendChild(portalElement);\n\n setRoot(root);\n\n return () => {\n document.body.removeChild(portalElement);\n };\n }, [disabled]);\n\n useLayoutEffect(() => {\n if (!root) return;\n\n root.render(\n <StateInspector\n state={state}\n connectionEvents={connectionEvents}\n connectedUsers={connectedUsers}\n userId={userId}\n colorScheme={colorScheme}\n anchor={anchor}\n stateManager={stateManager as StateManager<any, any>}\n />\n );\n }, [\n anchor,\n colorScheme,\n connectedUsers,\n connectionEvents,\n root,\n state,\n stateManager,\n userId,\n ]);\n}\n","import {\n ConnectionEvent,\n ExtendedPathKey,\n MultiplayerUser,\n StateManager,\n} from \"@noya-app/state-manager\";\nimport React, {\n CSSProperties,\n ComponentPropsWithoutRef,\n FC,\n memo,\n useEffect,\n useLayoutEffect,\n} from \"react\";\nimport {\n ObjectInspector,\n ObjectLabel,\n ObjectName,\n ObjectPreview,\n chromeDark,\n chromeLight,\n} from \"react-inspector\";\nimport { trackEvents } from \"../globals\";\nimport { useManagedHistory } from \"../hooks\";\nimport { useLocalStorageState } from \"./useLocalStorageState\";\n\nconst lightTheme = {\n ...chromeLight,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(0,0,0,0.7)\",\n} as any;\n\nconst darkTheme = {\n ...chromeDark,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(255,255,255,0.7)\",\n} as any;\n\nconst styles = {\n sectionInner: {\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n} as const;\n\nfunction ToggleButton({\n showInspector,\n setShowInspector,\n theme,\n anchor,\n}: {\n showInspector: boolean;\n setShowInspector: (value: boolean) => void;\n theme: typeof chromeLight;\n anchor: Anchor;\n}) {\n return (\n <span\n role=\"button\"\n style={{\n flex: \"0\",\n appearance: \"none\",\n color: theme.BASE_COLOR,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2px 0\",\n }}\n onClick={(event) => {\n event.stopPropagation();\n\n setShowInspector(!showInspector);\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n {showInspector === (anchor === \"right\") ? (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\"\n />\n </svg>\n ) : (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\"\n />\n </svg>\n )}\n </span>\n </span>\n );\n}\n\nfunction DisclosureSection({\n open,\n setOpen,\n title,\n right,\n children,\n colorScheme,\n isFirst,\n style,\n}: {\n open: boolean;\n setOpen?: (value: boolean) => void;\n title: string;\n right?: React.ReactNode;\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n isFirst?: boolean;\n style?: CSSProperties;\n}) {\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n\n const borderColor =\n colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n\n return (\n <div\n style={{\n flex: open ? \"1 1 0\" : \"0\",\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n <div\n onClick={() => setOpen?.(!open)}\n style={{\n cursor: \"default\",\n fontSize: \"12px\",\n padding: \"4px 10px\",\n display: \"flex\",\n alignItems: \"center\",\n ...(!isFirst && { borderTop: `1px solid ${borderColor}` }),\n ...(open && { borderBottom: `1px solid ${borderColor}` }),\n }}\n >\n {setOpen && (\n <Arrow\n expanded={open}\n style={{\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT + 1,\n color: theme.ARROW_COLOR,\n }}\n />\n )}\n <span style={{ flex: \"1 1 0\" }}>{title}</span>\n {right}\n </div>\n {open && children}\n </div>\n );\n}\n\nfunction InspectorRow({\n children,\n colorScheme,\n selected,\n style,\n variant,\n}: {\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n selected?: boolean;\n style?: CSSProperties;\n variant?: \"up\" | \"down\";\n}) {\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n return (\n <div\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n variant === \"up\"\n ? \"rgba(0,255,0,0.1)\"\n : variant === \"down\"\n ? \"rgba(255,0,0,0.1)\"\n : selected\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n // background:\n // colorScheme === \"light\"\n // ? \"rgba(0,0,0,0.05)\"\n // : \"rgba(255,255,255,0.05)\",\n ...style,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n {children}\n </span>\n </div>\n );\n}\n\nconst HISTORY_ELEMENT_PREFIX = \"noya-multiplayer-history-\";\n\ntype Anchor = \"left\" | \"right\";\n\nexport const StateInspector = memo(function StateInspector<\n S extends object,\n M,\n>({\n state,\n connectionEvents,\n connectedUsers,\n userId,\n unstyled,\n colorScheme = \"light\",\n stateManager,\n anchor = \"right\",\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n userId?: string;\n unstyled?: boolean;\n colorScheme?: \"light\" | \"dark\";\n stateManager: StateManager<S, M>;\n anchor?: Anchor;\n} & ComponentPropsWithoutRef<\"div\">) {\n const [didMount, setDidMount] = React.useState(false);\n\n useLayoutEffect(() => {\n setDidMount(true);\n }, []);\n\n const eventsContainerRef = React.useRef<HTMLDivElement>(null);\n const historyContainerRef = React.useRef<HTMLDivElement>(null);\n\n const [showInspector, setShowInspector] = useLocalStorageState(\n \"noya-multiplayer-react-show-inspector\",\n true\n );\n const [showEvents, setShowEvents] = useLocalStorageState(\n \"noya-multiplayer-react-show-events\",\n false\n );\n const [showHistory, setShowHistory] = useLocalStorageState(\n \"noya-multiplayer-react-show-history\",\n false\n );\n const [showUsers, setShowUsers] = useLocalStorageState(\n \"noya-multiplayer-react-show-users\",\n true\n );\n const [showData, setShowData] = useLocalStorageState(\n \"noya-multiplayer-react-show-data\",\n true\n );\n\n useEffect(() => {\n trackEvents.set(showEvents);\n }, [showEvents]);\n\n useEffect(() => {\n if (eventsContainerRef.current) {\n eventsContainerRef.current.scrollTop =\n eventsContainerRef.current.scrollHeight;\n }\n }, [connectionEvents]);\n\n const historySnapshot = useManagedHistory(stateManager);\n\n useEffect(() => {\n if (historyContainerRef.current) {\n historyContainerRef.current.scrollTop =\n historyContainerRef.current.scrollHeight;\n }\n }, [historySnapshot]);\n\n // If history index changes, scroll to the new history entry into view\n useEffect(() => {\n if (!historyContainerRef.current) return;\n\n const historyEntry = historyContainerRef.current.querySelector(\n `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`\n );\n\n if (historyEntry) {\n historyEntry.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n }\n }, [historySnapshot.historyIndex]);\n\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n // const borderColor =\n // colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n const baseStyle: CSSProperties = {\n position: \"fixed\",\n top: 12,\n ...(anchor === \"right\" ? { right: 12 } : { left: 12 }),\n bottom: 12,\n width: 400,\n background:\n colorScheme === \"light\" ? \"rgba(255,255,255,0.95)\" : \"rgba(0,0,0,0.95)\",\n backdropFilter: \"blur(48px)\",\n border: `1px solid ${solidBorderColor}`,\n // outlineOffset: -1,\n borderRadius: 4,\n display: \"flex\",\n flexDirection: \"column\",\n // gap: 12,\n color: theme.BASE_COLOR,\n overflow: \"hidden\",\n zIndex: 9999,\n lineHeight: \"13px\",\n };\n\n if (!didMount) return null;\n\n if (!showInspector) {\n return (\n <div\n {...props}\n style={{\n ...baseStyle,\n padding: \"4px 10px\",\n bottom: undefined,\n width: undefined,\n }}\n onClick={() => setShowInspector(true)}\n >\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n </div>\n );\n }\n\n return (\n <div\n {...props}\n style={{\n ...(!unstyled && baseStyle),\n ...props.style,\n }}\n >\n <DisclosureSection\n isFirst\n open={showUsers}\n setOpen={setShowUsers}\n title=\"Users\"\n colorScheme={colorScheme}\n style={{\n flex: \"0 0 auto\",\n maxHeight: \"200px\",\n }}\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n }\n >\n <div style={{ ...styles.sectionInner, flex: \"0 0 auto\" }}>\n {connectedUsers?.map((user) => (\n <InspectorRow\n key={user.id}\n colorScheme={colorScheme}\n variant={user.id === userId ? \"up\" : undefined}\n >\n {user.name} ({ellipsis(user.id.toString(), 8, \"middle\")})\n </InspectorRow>\n ))}\n {!connectedUsers && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No connected users</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Data\"\n colorScheme={colorScheme}\n setOpen={setShowData}\n open={showData}\n >\n <div\n style={{\n ...styles.sectionInner,\n gap: \"1px\",\n padding: \"1px 12px\",\n }}\n >\n <ObjectInspector data={state} theme={theme} />\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showHistory}\n setOpen={setShowHistory}\n title=\"History\"\n colorScheme={colorScheme}\n >\n <div ref={historyContainerRef} style={styles.sectionInner}>\n <div\n id={`${HISTORY_ELEMENT_PREFIX}0`}\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n historySnapshot.historyIndex === 0\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n Initial state\n </span>\n </div>\n {historySnapshot.history.map((entry, index) => (\n <div\n id={`${HISTORY_ELEMENT_PREFIX}${index + 1}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index + 1 === historySnapshot.historyIndex\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n {entry.redoPatches?.map((patch, j) => (\n <pre\n key={j}\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {patch.op === \"add\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"replace\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"remove\" && (\n <>\n <span style={{ color: theme.OBJECT_VALUE_STRING_COLOR }}>\n delete{\" \"}\n </span>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n </pre>\n ))}\n </div>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEvents}\n setOpen={setShowEvents}\n title=\"Events\"\n colorScheme={colorScheme}\n >\n <div ref={eventsContainerRef} style={styles.sectionInner}>\n {connectionEvents?.map((event, index) =>\n event.type === \"stateChange\" ? (\n <InspectorRow key={index} colorScheme={colorScheme}>\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </InspectorRow>\n ) : (\n <InspectorRow\n key={index}\n colorScheme={colorScheme}\n variant={event.type === \"send\" ? \"up\" : \"down\"}\n style={{\n padding: \"0px 12px 1px\",\n }}\n >\n <ObjectInspector\n data={event.message}\n theme={theme}\n nodeRenderer={({\n depth,\n name,\n data,\n isNonenumerable,\n expanded,\n }: any) => {\n const direction = event.type === \"send\" ? \"up\" : \"down\";\n\n return depth === 0 ? (\n <ObjectRootLabel direction={direction} data={data} />\n ) : (\n <ObjectLabel\n direction={direction}\n name={name}\n data={data}\n isNonenumerable={isNonenumerable}\n />\n );\n }}\n />\n </InspectorRow>\n )\n )}\n {!connectionEvents && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No recorded events</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n </div>\n );\n});\n\ntype MessageDirection = \"up\" | \"down\";\n\nconst ObjectRootLabel: FC<{\n name?: string;\n data: any;\n direction?: MessageDirection;\n}> = ({ name, data, direction }) => {\n if (typeof name === \"string\") {\n return (\n <span>\n <ObjectName name={name} />\n <span>: </span>\n <ObjectPreview data={data} />\n </span>\n );\n }\n if (direction === \"up\" || direction === \"down\") {\n const arrow = direction === \"up\" ? \"↑\" : \"↓\";\n\n return (\n <span>\n <span\n style={{\n background:\n direction === \"up\" ? \"rgba(0,255,0,0.2)\" : \"rgba(255,0,0,0.2)\",\n // color: \"white\",\n width: 12,\n height: 12,\n borderRadius: 2,\n display: \"inline-flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginRight: 4,\n lineHeight: \"12px\",\n }}\n >\n {arrow}\n </span>\n <ObjectPreview data={data} />\n </span>\n );\n } else {\n return <ObjectPreview data={data} />;\n }\n};\n\n// Rotates ▶️ or ▼ based on expanded state\nfunction Arrow({\n expanded,\n onClick,\n style,\n}: {\n expanded: boolean;\n onClick?: () => void;\n style?: CSSProperties;\n}) {\n return (\n <span\n role=\"button\"\n onClick={onClick}\n style={{\n display: \"inline-block\",\n textAlign: \"center\",\n transform: expanded ? \"rotate(0deg)\" : \"rotate(-90deg)\",\n fontFamily: \"Menlo, monospace\",\n ...style,\n }}\n >\n {\"▼\"}\n </span>\n );\n}\n\nfunction pathToString(extendedPath: ExtendedPathKey[]) {\n return extendedPath\n .map((key) =>\n typeof key === \"object\"\n ? `:${ellipsis(key.id.toString(), 8, \"middle\")}`\n : key\n )\n .map((key, index) =>\n index === 0 || (typeof key === \"string\" && key.startsWith(\":\"))\n ? key\n : `.${key}`\n )\n .join(\"\");\n}\n\ntype EllipsisPosition = \"start\" | \"middle\" | \"end\";\n\nfunction ellipsis(\n str: string,\n maxLength: number,\n position: EllipsisPosition = \"end\"\n) {\n if (str.length <= maxLength) return str;\n\n switch (position) {\n case \"start\":\n return `…${str.slice(str.length - maxLength)}`;\n case \"middle\":\n const halfLength = Math.floor(maxLength / 2);\n return `${str.slice(0, halfLength)}…${str.slice(str.length - halfLength)}`;\n case \"end\":\n return `${str.slice(0, maxLength)}…`;\n }\n}\n","import React from \"react\";\n\nconst localStorage = typeof window !== \"undefined\" ? window.localStorage : null;\n\nexport function useLocalStorageState<S>(\n key: string,\n defaultValue: S\n): [S, (value: S) => void] {\n const [state, setState] = React.useState<S>(() => {\n const value = localStorage?.getItem(key);\n let result = defaultValue;\n if (value) {\n try {\n result = JSON.parse(value);\n } catch (error) {\n console.error(\"Error parsing localStorage value\", error);\n }\n }\n return result;\n });\n\n const setLocalStorageState = (value: S) => {\n localStorage?.setItem(key, JSON.stringify(value));\n setState(value);\n };\n\n return [state, setLocalStorageState];\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","React","React","StateInspector","React","root","userId"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/hooks.ts","../src/globals.ts","../src/inspector/useStateInspector.tsx","../src/inspector/StateInspector.tsx","../src/inspector/useLocalStorageState.tsx"],"sourcesContent":["export * from \"@noya-app/state-manager\";\nexport * from \"./hooks\";\nexport * from \"./inspector/StateInspector\";\n","\"use client\";\n\nimport {\n ActionHandler,\n ConnectionEvent,\n Get,\n MultiplayerStateManager,\n MultiplayerStateManagerOptions,\n MultiplayerUser,\n StateManager,\n StateManagerOptions,\n SyncAdapter,\n Task,\n stubSync,\n} from \"@noya-app/state-manager\";\nimport {\n ComponentProps,\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport {\n shouldTrackEvents$,\n shouldTrackTasks$,\n useObservable,\n} from \"./globals\";\nimport { StateInspector } from \"./inspector/StateInspector\";\nimport { useStateInspector } from \"./inspector/useStateInspector\";\n\nexport function useSyncStateManager<S extends object, M>(\n stateManager: StateManager<S, M>\n): S;\nexport function useSyncStateManager<S extends object, M, P extends string>(\n stateManager: StateManager<S, M>,\n path: P\n): Get<S, P, unknown>;\nexport function useSyncStateManager<S extends object, M>(\n stateManager: StateManager<S, M>,\n path?: string\n) {\n const getSnapshot = useCallback(\n () =>\n typeof path === \"string\"\n ? stateManager.getState(path)\n : stateManager.getState(),\n [stateManager, path]\n );\n\n return useSyncExternalStore(\n stateManager.addListener,\n getSnapshot,\n getSnapshot\n );\n}\n\nexport function useManagedState<S extends object, M = void>(\n createInitialState: () => S,\n options?: StateManagerOptions<S, M>\n) {\n const [stateManager] = useState(\n () => new StateManager<S, M>(createInitialState(), options)\n );\n\n const state = useSyncStateManager(stateManager);\n\n const setState = useCallback(\n (\n ...args: M extends {}\n ? [metadata: M, action: SetStateAction<S>]\n : [action: SetStateAction<S>]\n ) => {\n const [metadata, action] =\n args.length === 1 ? [undefined, args[0]] : args;\n\n if (metadata === undefined) {\n const performActionNoMetadata = stateManager.performAction as (\n handler: ActionHandler<S>\n ) => void;\n\n if (typeof action === \"function\") {\n performActionNoMetadata({\n run: action,\n undo: () => state,\n });\n } else {\n performActionNoMetadata({\n run: () => action,\n undo: () => state,\n });\n }\n } else {\n const performActionWithMetadata = stateManager.performAction as (\n metadata: M,\n handler: ActionHandler<S>\n ) => void;\n\n if (typeof action === \"function\") {\n performActionWithMetadata(metadata, {\n run: action,\n undo: () => state,\n });\n } else {\n performActionWithMetadata(metadata, {\n run: () => action,\n undo: () => state,\n });\n }\n }\n },\n [state, stateManager]\n );\n\n return [state, setState, stateManager] as const;\n}\n\nexport function useManagedHistory<S extends object, M = void>(\n stateManager: StateManager<S, M>\n) {\n return useSyncExternalStore(\n stateManager.historyEmittor.addListener,\n stateManager.getHistorySnapshot,\n stateManager.getHistorySnapshot\n );\n}\n\nexport function useSyncMultiplayerStateManager<S extends object, M = void>(\n multiplayerStateManager: MultiplayerStateManager<S, M>\n) {\n return useSyncExternalStore(\n multiplayerStateManager.addListener,\n multiplayerStateManager.getOptimisticState,\n multiplayerStateManager.getOptimisticState\n );\n}\n\nconst defaultStubSync = stubSync();\n\nexport function useMultiplayerState<S extends object, M = void>(\n initialState: S | (() => S),\n options?: MultiplayerStateManagerOptions<S, M> & {\n sync?: (options: { ms: MultiplayerStateManager<S, M> }) => void;\n trackConnectionEvents?: boolean;\n trackTasks?: boolean;\n inspector?:\n | boolean\n | Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">;\n }\n) {\n const { sync = defaultStubSync as unknown as SyncAdapter<S, M>, ...rest } =\n options ?? {};\n\n const [multiplayerStateManager] = useState(\n () => new MultiplayerStateManager<S, M>(initialState, rest)\n );\n const syncRef = useRef(sync);\n\n const [connectionEvents, setConnectionEvents] = useState<\n ConnectionEvent<S>[] | undefined\n >();\n\n const [connectedUsers, setConnectedUsers] = useState<MultiplayerUser[]>([]);\n const [tasks, setTasks] = useState<Task[]>([]);\n const [userId, setUserId] = useState<string | undefined>();\n\n const extras = useMemo(() => {\n return {\n tasks,\n connectionEvents,\n connectedUsers,\n // evaluate: async (code: string) => {\n // const payload = await rpcManager.request({ type: \"eval\", code });\n\n // if (payload.type !== \"eval\") {\n // throw new Error(`Unexpected rpc response type: ${payload.type}`);\n // }\n // },\n };\n }, [tasks, connectionEvents, connectedUsers]);\n\n const globalTrackEvents = useObservable(shouldTrackEvents$);\n const globalTrackTasks = useObservable(shouldTrackTasks$);\n\n const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;\n const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;\n\n const trackEventsCallbackRef = useRef<\n ((e: ConnectionEvent<S>) => void) | undefined\n >();\n const trackConnectedUsersCallbackRef = useRef<\n ((users: MultiplayerUser[], userId: string) => void) | undefined\n >();\n const trackTasksCallbackRef = useRef<((tasks: Task[]) => void) | undefined>();\n\n useEffect(() => {\n trackEventsCallbackRef.current = shouldTrackEvents\n ? (e) =>\n setConnectionEvents((events) => {\n const updated = events ? [...events, e] : [e];\n return updated.length > 50 ? updated.slice(-50) : updated;\n })\n : undefined;\n }, [shouldTrackEvents]);\n\n useEffect(() => {\n trackConnectedUsersCallbackRef.current = (users, userId) => {\n setConnectedUsers(users);\n setUserId(userId);\n };\n }, []);\n\n useEffect(() => {\n trackTasksCallbackRef.current = shouldTrackTasks\n ? (tasks) => {\n setTasks((old) => {\n const newIds = new Set(tasks.map((t) => t.id));\n\n // merge old and new tasks, preferring new tasks\n const unchanged = old.filter((t) => !newIds.has(t.id));\n\n return [...unchanged, ...tasks];\n });\n }\n : undefined;\n }, [shouldTrackTasks]);\n\n useEffect(() => {\n if (syncRef.current) {\n return syncRef.current({\n ms: multiplayerStateManager,\n onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),\n onChangeConnectedUsers: (users, userId) =>\n trackConnectedUsersCallbackRef.current?.(users, userId),\n onChangeTasks: (tasks) => trackTasksCallbackRef.current?.(tasks),\n });\n }\n }, [multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n useStateInspector({\n multiplayerStateManager,\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n disabled: !options?.inspector,\n ...(typeof options?.inspector === \"object\" && options.inspector),\n });\n\n return [\n state,\n multiplayerStateManager.setState,\n multiplayerStateManager,\n extras,\n ] as const;\n}\n","import { Emitter } from \"@noya-app/emitter\";\nimport { useEffect, useState } from \"react\";\n\nclass Observable<T> {\n private value: T;\n private emitter = new Emitter<[T]>();\n\n constructor(value: T) {\n this.value = value;\n }\n\n get() {\n return this.value;\n }\n\n set(value: T) {\n if (this.value === value) return;\n\n this.value = value;\n\n this.emitter.emit(value);\n }\n\n listen(callback: (value: T) => void) {\n callback(this.value);\n\n return this.emitter.addListener(callback);\n }\n}\n\nexport function useObservable<T>(observable: Observable<T>) {\n const [value, setValue] = useState(observable.get());\n\n useEffect(() => {\n return observable.listen(setValue);\n }, [observable]);\n\n return value;\n}\n\nexport const shouldTrackEvents$ = new Observable(false);\nexport const shouldTrackTasks$ = new Observable(false);\n","\"use client\";\n\nimport {\n ConnectionEvent,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, { ComponentProps, useLayoutEffect } from \"react\";\nimport { createRoot } from \"react-dom/client\";\n\nimport { Root } from \"react-dom/client\";\nimport { StateInspector } from \"./StateInspector\";\n\nfunction createPortalElement() {\n const el = document.createElement(\"div\");\n el.id = \"noya-multiplayer-react-inspector-portal\";\n return el;\n}\n\nexport function useStateInspector<S extends object, M>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n disabled = false,\n colorScheme,\n anchor,\n multiplayerStateManager,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n disabled: boolean;\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n} & Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">) {\n const [root, setRoot] = React.useState<Root | null>(null);\n\n useLayoutEffect(() => {\n if (disabled) return;\n\n const portalElement = createPortalElement();\n\n const root = createRoot(portalElement);\n\n document.body.appendChild(portalElement);\n\n setRoot(root);\n\n return () => {\n document.body.removeChild(portalElement);\n };\n }, [disabled]);\n\n useLayoutEffect(() => {\n if (!root) return;\n\n root.render(\n <StateInspector\n state={state}\n connectionEvents={connectionEvents}\n connectedUsers={connectedUsers}\n tasks={tasks}\n userId={userId}\n colorScheme={colorScheme}\n anchor={anchor}\n multiplayerStateManager={\n multiplayerStateManager as MultiplayerStateManager<any, any>\n }\n />\n );\n }, [\n anchor,\n colorScheme,\n connectedUsers,\n connectionEvents,\n root,\n state,\n multiplayerStateManager,\n userId,\n tasks,\n ]);\n}\n","\"use client\";\n\nimport {\n ConnectionEvent,\n ExtendedPathKey,\n MultiplayerStateManager,\n MultiplayerUser,\n Task,\n} from \"@noya-app/state-manager\";\nimport React, {\n CSSProperties,\n ComponentPropsWithoutRef,\n FC,\n memo,\n useEffect,\n useLayoutEffect,\n} from \"react\";\nimport {\n ObjectInspector,\n ObjectLabel,\n ObjectName,\n ObjectPreview,\n chromeDark,\n chromeLight,\n} from \"react-inspector\";\nimport { shouldTrackEvents$, shouldTrackTasks$ } from \"../globals\";\nimport { useManagedHistory } from \"../hooks\";\nimport { useLocalStorageState } from \"./useLocalStorageState\";\n\nconst lightTheme = {\n ...chromeLight,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(0,0,0,0.7)\",\n} as any;\n\nconst darkTheme = {\n ...chromeDark,\n BASE_BACKGROUND_COLOR: \"transparent\",\n OBJECT_NAME_COLOR: \"rgba(255,255,255,0.7)\",\n} as any;\n\nconst styles = {\n sectionInner: {\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n },\n} as const;\n\nfunction ToggleButton({\n showInspector,\n setShowInspector,\n theme,\n anchor,\n}: {\n showInspector: boolean;\n setShowInspector: (value: boolean) => void;\n theme: typeof chromeLight;\n anchor: Anchor;\n}) {\n return (\n <span\n role=\"button\"\n style={{\n flex: \"0\",\n appearance: \"none\",\n color: theme.BASE_COLOR,\n border: \"none\",\n fontSize: \"12px\",\n whiteSpace: \"nowrap\",\n display: \"inline-flex\",\n alignItems: \"center\",\n justifyContent: \"center\",\n padding: \"2px 0\",\n }}\n onClick={(event) => {\n event.stopPropagation();\n\n setShowInspector(!showInspector);\n }}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n {showInspector === (anchor === \"right\") ? (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5\"\n />\n </svg>\n ) : (\n <svg\n xmlns=\"http://www.w3.org/2000/svg\"\n fill=\"none\"\n viewBox=\"0 0 24 24\"\n strokeWidth={1.5}\n stroke=\"currentColor\"\n className=\"size-6\"\n >\n <path\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n d=\"m18.75 4.5-7.5 7.5 7.5 7.5m-6-15L5.25 12l7.5 7.5\"\n />\n </svg>\n )}\n </span>\n </span>\n );\n}\n\nfunction DisclosureSection({\n open,\n setOpen,\n title,\n right,\n children,\n colorScheme,\n isFirst,\n style,\n}: {\n open: boolean;\n setOpen?: (value: boolean) => void;\n title: string;\n right?: React.ReactNode;\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n isFirst?: boolean;\n style?: CSSProperties;\n}) {\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n\n const borderColor =\n colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n\n return (\n <div\n style={{\n flex: open ? \"1 1 0\" : \"0\",\n display: \"flex\",\n flexDirection: \"column\",\n ...style,\n }}\n >\n <div\n onClick={() => setOpen?.(!open)}\n style={{\n cursor: \"default\",\n fontSize: \"12px\",\n padding: \"4px 10px\",\n display: \"flex\",\n alignItems: \"center\",\n ...(!isFirst && { borderTop: `1px solid ${borderColor}` }),\n ...(open && { borderBottom: `1px solid ${borderColor}` }),\n }}\n >\n {setOpen && (\n <Arrow\n expanded={open}\n style={{\n fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT + 1,\n color: theme.ARROW_COLOR,\n }}\n />\n )}\n <span style={{ flex: \"1 1 0\", userSelect: \"none\" }}>{title}</span>\n {right}\n </div>\n {open && children}\n </div>\n );\n}\n\nfunction InspectorRow({\n children,\n colorScheme,\n selected,\n style,\n variant,\n}: {\n children: React.ReactNode;\n colorScheme: \"light\" | \"dark\";\n selected?: boolean;\n style?: CSSProperties;\n variant?: \"up\" | \"down\";\n}) {\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n return (\n <div\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n variant === \"up\"\n ? \"rgba(0,255,0,0.1)\"\n : variant === \"down\"\n ? \"rgba(255,0,0,0.1)\"\n : selected\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n // background:\n // colorScheme === \"light\"\n // ? \"rgba(0,0,0,0.05)\"\n // : \"rgba(255,255,255,0.05)\",\n ...style,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n {children}\n </span>\n </div>\n );\n}\n\nconst HISTORY_ELEMENT_PREFIX = \"noya-multiplayer-history-\";\n\ntype Anchor = \"left\" | \"right\" | \"bottom left\" | \"bottom right\";\n\nexport const StateInspector = memo(function StateInspector<\n S extends object,\n M,\n>({\n state,\n connectionEvents,\n connectedUsers,\n tasks,\n userId,\n unstyled,\n colorScheme = \"light\",\n multiplayerStateManager,\n anchor = \"right\",\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n connectedUsers?: MultiplayerUser[];\n tasks?: Task[];\n userId?: string;\n unstyled?: boolean;\n colorScheme?: \"light\" | \"dark\";\n multiplayerStateManager: MultiplayerStateManager<S, M>;\n anchor?: Anchor;\n} & ComponentPropsWithoutRef<\"div\">) {\n const [didMount, setDidMount] = React.useState(false);\n\n useLayoutEffect(() => {\n setDidMount(true);\n }, []);\n\n const eventsContainerRef = React.useRef<HTMLDivElement>(null);\n const historyContainerRef = React.useRef<HTMLDivElement>(null);\n\n const [showInspector, setShowInspector] = useLocalStorageState(\n \"noya-multiplayer-react-show-inspector\",\n true\n );\n const [showEvents, setShowEvents] = useLocalStorageState(\n \"noya-multiplayer-react-show-events\",\n false\n );\n const [showHistory, setShowHistory] = useLocalStorageState(\n \"noya-multiplayer-react-show-history\",\n false\n );\n const [showUsers, setShowUsers] = useLocalStorageState(\n \"noya-multiplayer-react-show-users\",\n true\n );\n const [showData, setShowData] = useLocalStorageState(\n \"noya-multiplayer-react-show-data\",\n true\n );\n const [showTasks, setShowTasks] = useLocalStorageState(\n \"noya-multiplayer-react-show-tasks\",\n false\n );\n\n useEffect(() => {\n shouldTrackEvents$.set(showEvents);\n }, [showEvents]);\n\n useEffect(() => {\n shouldTrackTasks$.set(showTasks);\n }, [showTasks]);\n\n useEffect(() => {\n if (eventsContainerRef.current) {\n eventsContainerRef.current.scrollTop =\n eventsContainerRef.current.scrollHeight;\n }\n }, [connectionEvents]);\n\n const historySnapshot = useManagedHistory(multiplayerStateManager.sm);\n\n useEffect(() => {\n if (historyContainerRef.current) {\n historyContainerRef.current.scrollTop =\n historyContainerRef.current.scrollHeight;\n }\n }, [historySnapshot]);\n\n // If history index changes, scroll to the new history entry into view\n useEffect(() => {\n if (!historyContainerRef.current) return;\n\n const historyEntry = historyContainerRef.current.querySelector(\n `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`\n );\n\n if (historyEntry) {\n historyEntry.scrollIntoView({\n block: \"nearest\",\n inline: \"nearest\",\n });\n }\n }, [historySnapshot.historyIndex]);\n\n const theme = colorScheme === \"light\" ? lightTheme : darkTheme;\n // const borderColor =\n // colorScheme === \"light\" ? \"rgba(0,0,0,0.1)\" : \"rgba(255,255,255,0.1)\";\n const solidBorderColor =\n colorScheme === \"light\" ? \"rgb(223 223 223)\" : \"rgb(29 29 29)\";\n\n const baseStyle: CSSProperties = {\n position: \"fixed\",\n top: 12,\n ...(anchor.includes(\"right\") ? { right: 12 } : { left: 12 }),\n bottom: 12,\n width: 400,\n background:\n colorScheme === \"light\" ? \"rgba(255,255,255,0.95)\" : \"rgba(0,0,0,0.95)\",\n backdropFilter: \"blur(48px)\",\n border: `1px solid ${solidBorderColor}`,\n // outlineOffset: -1,\n borderRadius: 4,\n display: \"flex\",\n flexDirection: \"column\",\n // gap: 12,\n color: theme.BASE_COLOR,\n overflow: \"hidden\",\n zIndex: 9999,\n lineHeight: \"13px\",\n };\n\n if (!didMount) return null;\n\n if (!showInspector) {\n return (\n <div\n {...props}\n style={{\n ...baseStyle,\n padding: \"4px 10px\",\n width: undefined,\n ...(anchor.includes(\"bottom\")\n ? { bottom: 12, top: undefined }\n : { bottom: undefined }),\n }}\n onClick={() => setShowInspector(true)}\n >\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n </div>\n );\n }\n\n return (\n <div\n {...props}\n style={{\n ...(!unstyled && baseStyle),\n ...props.style,\n }}\n >\n <DisclosureSection\n isFirst\n open={showUsers}\n setOpen={setShowUsers}\n title=\"Users\"\n colorScheme={colorScheme}\n style={{\n flex: \"0 0 auto\",\n maxHeight: \"200px\",\n }}\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n }\n >\n <div style={{ ...styles.sectionInner, flex: \"0 0 auto\" }}>\n {connectedUsers?.map((user) => (\n <InspectorRow\n key={user.id}\n colorScheme={colorScheme}\n variant={user.id === userId ? \"up\" : undefined}\n >\n {user.name} ({ellipsis(user.id.toString(), 8, \"middle\")})\n </InspectorRow>\n ))}\n {!connectedUsers && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No connected users</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Data\"\n colorScheme={colorScheme}\n setOpen={setShowData}\n open={showData}\n >\n <div style={styles.sectionInner}>\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name={multiplayerStateManager.sm.schema ? \"state\" : undefined}\n data={state}\n theme={theme}\n />\n </InspectorRow>\n {multiplayerStateManager.sm.schema && (\n <InspectorRow colorScheme={colorScheme}>\n <ObjectInspector\n name=\"schema\"\n data={multiplayerStateManager.sm.schema}\n theme={theme}\n />\n </InspectorRow>\n )}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showHistory}\n setOpen={setShowHistory}\n title=\"History\"\n colorScheme={colorScheme}\n >\n <div ref={historyContainerRef} style={styles.sectionInner}>\n <div\n id={`${HISTORY_ELEMENT_PREFIX}0`}\n style={{\n borderBottom: `1px solid ${solidBorderColor}`,\n fontSize: \"12px\",\n fontFamily: \"Menlo, monospace\",\n padding: \"2px 12px 1px\",\n display: \"flex\",\n alignItems: \"center\",\n background:\n historySnapshot.historyIndex === 0\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n Initial state\n </span>\n </div>\n {historySnapshot.history.map((entry, index) => (\n <div\n id={`${HISTORY_ELEMENT_PREFIX}${index + 1}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index + 1 === historySnapshot.historyIndex\n ? \"rgb(59 130 246 / 15%)\"\n : undefined,\n }}\n >\n {entry.redoPatches?.map((patch, j) => (\n <pre\n key={j}\n style={{\n fontSize: \"11px\",\n display: \"flex\",\n flexWrap: \"wrap\",\n }}\n >\n {patch.op === \"add\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"replace\" && (\n <>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n {\" = \"}\n <ObjectInspector data={patch.value} theme={theme} />\n </>\n )}\n {patch.op === \"remove\" && (\n <>\n <span style={{ color: theme.OBJECT_VALUE_STRING_COLOR }}>\n delete{\" \"}\n </span>\n <span style={{ fontStyle: \"italic\" }}>\n {pathToString(patch.path)}\n </span>\n </>\n )}\n </pre>\n ))}\n </div>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n title=\"Tasks\"\n colorScheme={colorScheme}\n open={showTasks}\n setOpen={setShowTasks}\n >\n <div style={styles.sectionInner}>\n {tasks?.map((task) => (\n <InspectorRow\n key={task.id}\n colorScheme={colorScheme}\n style={{\n backgroundColor:\n task.status === \"done\"\n ? \"rgba(0,255,0,0.2)\"\n : task.status === \"error\"\n ? \"rgba(255,0,0,0.2)\"\n : undefined,\n }}\n >\n <ObjectInspector\n name={task.name}\n data={task.payload}\n theme={theme}\n />\n </InspectorRow>\n ))}\n </div>\n </DisclosureSection>\n <DisclosureSection\n open={showEvents}\n setOpen={setShowEvents}\n title=\"Events\"\n colorScheme={colorScheme}\n >\n <div ref={eventsContainerRef} style={styles.sectionInner}>\n {connectionEvents?.map((event, index) =>\n event.type === \"stateChange\" ? (\n <InspectorRow key={index} colorScheme={colorScheme}>\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </InspectorRow>\n ) : (\n <InspectorRow\n key={index}\n colorScheme={colorScheme}\n variant={event.type === \"send\" ? \"up\" : \"down\"}\n style={{\n padding: \"0px 12px 1px\",\n }}\n >\n <ObjectInspector\n data={event.message}\n theme={theme}\n nodeRenderer={({\n depth,\n name,\n data,\n isNonenumerable,\n expanded,\n }: any) => {\n const direction = event.type === \"send\" ? \"up\" : \"down\";\n\n return depth === 0 ? (\n <ObjectRootLabel direction={direction} data={data} />\n ) : (\n <ObjectLabel\n direction={direction}\n name={name}\n data={data}\n isNonenumerable={isNonenumerable}\n />\n );\n }}\n />\n </InspectorRow>\n )\n )}\n {!connectionEvents && (\n <div\n style={{\n padding: \"12px\",\n fontSize: \"12px\",\n display: \"flex\",\n flexDirection: \"column\",\n gap: \"4px\",\n }}\n >\n <span>No recorded events</span>\n </div>\n )}\n </div>\n </DisclosureSection>\n </div>\n );\n});\n\ntype MessageDirection = \"up\" | \"down\";\n\nconst ObjectRootLabel: FC<{\n name?: string;\n data: any;\n direction?: MessageDirection;\n}> = ({ name, data, direction }) => {\n if (typeof name === \"string\") {\n return (\n <span>\n <ObjectName name={name} />\n <span>: </span>\n <ObjectPreview data={data} />\n </span>\n );\n }\n if (direction === \"up\" || direction === \"down\") {\n const arrow = direction === \"up\" ? \"↑\" : \"↓\";\n\n return (\n <span>\n <span\n style={{\n background:\n direction === \"up\" ? \"rgba(0,255,0,0.2)\" : \"rgba(255,0,0,0.2)\",\n // color: \"white\",\n width: 12,\n height: 12,\n borderRadius: 2,\n display: \"inline-flex\",\n justifyContent: \"center\",\n alignItems: \"center\",\n marginRight: 4,\n lineHeight: \"12px\",\n }}\n >\n {arrow}\n </span>\n <ObjectPreview data={data} />\n </span>\n );\n } else {\n return <ObjectPreview data={data} />;\n }\n};\n\n// Rotates ▶️ or ▼ based on expanded state\nfunction Arrow({\n expanded,\n onClick,\n style,\n}: {\n expanded: boolean;\n onClick?: () => void;\n style?: CSSProperties;\n}) {\n return (\n <span\n role=\"button\"\n onClick={onClick}\n style={{\n display: \"inline-block\",\n textAlign: \"center\",\n transform: expanded ? \"rotate(0deg)\" : \"rotate(-90deg)\",\n fontFamily: \"Menlo, monospace\",\n ...style,\n }}\n >\n {\"▼\"}\n </span>\n );\n}\n\nfunction pathToString(extendedPath: ExtendedPathKey[]) {\n return extendedPath\n .map((key) =>\n typeof key === \"object\"\n ? `:${ellipsis(key.id.toString(), 8, \"middle\")}`\n : key\n )\n .map((key, index) =>\n index === 0 || (typeof key === \"string\" && key.startsWith(\":\"))\n ? key\n : `.${key}`\n )\n .join(\"\");\n}\n\ntype EllipsisPosition = \"start\" | \"middle\" | \"end\";\n\nfunction ellipsis(\n str: string,\n maxLength: number,\n position: EllipsisPosition = \"end\"\n) {\n if (str.length <= maxLength) return str;\n\n switch (position) {\n case \"start\":\n return `…${str.slice(str.length - maxLength)}`;\n case \"middle\":\n const halfLength = Math.floor(maxLength / 2);\n return `${str.slice(0, halfLength)}…${str.slice(str.length - halfLength)}`;\n case \"end\":\n return `${str.slice(0, maxLength)}…`;\n }\n}\n","\"use client\";\n\nimport React from \"react\";\n\nconst localStorage = typeof window !== \"undefined\" ? window.localStorage : null;\n\nexport function useLocalStorageState<S>(\n key: string,\n defaultValue: S\n): [S, (value: S) => void] {\n const [state, setState] = React.useState<S>(() => {\n const value = localStorage?.getItem(key);\n let result = defaultValue;\n if (value) {\n try {\n result = JSON.parse(value);\n } catch (error) {\n console.error(\"Error parsing localStorage value\", error);\n }\n }\n return result;\n });\n\n const setLocalStorageState = (value: S) => {\n localStorage?.setItem(key, JSON.stringify(value));\n setState(value);\n };\n\n return [state, setLocalStorageState];\n}\n"],"mappings":"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","names":["import_react","import_react","import_react","import_react","React","React","StateInspector","React","root","userId","tasks"]}