@noya-app/noya-multiplayer-react 0.1.9 → 0.1.11

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/dist/index.mjs CHANGED
@@ -104,7 +104,8 @@ var darkTheme = {
104
104
  function ToggleButton({
105
105
  showInspector,
106
106
  setShowInspector,
107
- theme
107
+ theme,
108
+ anchor
108
109
  }) {
109
110
  return /* @__PURE__ */ React2.createElement(
110
111
  "span",
@@ -114,7 +115,6 @@ function ToggleButton({
114
115
  flex: "0",
115
116
  appearance: "none",
116
117
  color: theme.BASE_COLOR,
117
- background: "rgba(0,0,0,0.1)",
118
118
  border: "none",
119
119
  fontSize: "12px",
120
120
  whiteSpace: "nowrap",
@@ -125,7 +125,7 @@ function ToggleButton({
125
125
  },
126
126
  onClick: () => setShowInspector(!showInspector)
127
127
  },
128
- /* @__PURE__ */ React2.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector ? /* @__PURE__ */ React2.createElement(
128
+ /* @__PURE__ */ React2.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ React2.createElement(
129
129
  "svg",
130
130
  {
131
131
  xmlns: "http://www.w3.org/2000/svg",
@@ -193,6 +193,7 @@ function DisclosureSection({
193
193
  fontSize: "12px",
194
194
  padding: "4px 10px",
195
195
  display: "flex",
196
+ alignItems: "center",
196
197
  ...!isFirst && { borderTop: `1px solid ${borderColor}` },
197
198
  ...open && { borderBottom: `1px solid ${borderColor}` }
198
199
  }
@@ -202,9 +203,8 @@ function DisclosureSection({
202
203
  {
203
204
  expanded: open,
204
205
  style: {
205
- fontSize: "11px",
206
- // fontSize: theme.ARROW_FONT_SIZE,
207
- marginRight: theme.ARROW_MARGIN_RIGHT,
206
+ fontSize: theme.ARROW_FONT_SIZE,
207
+ marginRight: theme.ARROW_MARGIN_RIGHT + 1,
208
208
  color: theme.ARROW_COLOR
209
209
  }
210
210
  }
@@ -215,12 +215,14 @@ function DisclosureSection({
215
215
  open && children
216
216
  );
217
217
  }
218
+ var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
218
219
  var StateInspector = memo(function StateInspector2({
219
220
  state,
220
221
  connectionEvents,
221
222
  unstyled,
222
223
  colorScheme = "light",
223
224
  stateManager,
225
+ anchor = "right",
224
226
  ...props
225
227
  }) {
226
228
  const [didMount, setDidMount] = React2.useState(false);
@@ -259,7 +261,7 @@ var StateInspector = memo(function StateInspector2({
259
261
  if (!historyContainerRef.current)
260
262
  return;
261
263
  const historyEntry = historyContainerRef.current.querySelector(
262
- `#history-${historySnapshot.historyIndex - 1}`
264
+ `#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
263
265
  );
264
266
  if (historyEntry) {
265
267
  historyEntry.scrollIntoView({
@@ -270,15 +272,16 @@ var StateInspector = memo(function StateInspector2({
270
272
  }, [historySnapshot.historyIndex]);
271
273
  const theme = colorScheme === "light" ? lightTheme : darkTheme;
272
274
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
275
+ const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
273
276
  const baseStyle = {
274
277
  position: "fixed",
275
278
  top: 12,
276
- right: 12,
279
+ ...anchor === "right" ? { right: 12 } : { left: 12 },
277
280
  bottom: 12,
278
281
  width: 400,
279
282
  background: colorScheme === "light" ? "rgba(255,255,255,0.95)" : "rgba(0,0,0,0.95)",
280
283
  backdropFilter: "blur(48px)",
281
- border: `1px solid ${borderColor}`,
284
+ border: `1px solid ${solidBorderColor}`,
282
285
  // outlineOffset: -1,
283
286
  borderRadius: 4,
284
287
  display: "flex",
@@ -286,7 +289,8 @@ var StateInspector = memo(function StateInspector2({
286
289
  // gap: 12,
287
290
  color: theme.BASE_COLOR,
288
291
  overflow: "hidden",
289
- zIndex: 9999
292
+ zIndex: 9999,
293
+ lineHeight: "13px"
290
294
  };
291
295
  if (!didMount)
292
296
  return null;
@@ -298,17 +302,18 @@ var StateInspector = memo(function StateInspector2({
298
302
  style: {
299
303
  ...baseStyle,
300
304
  padding: "4px 10px",
301
- borderRadius: 8,
302
305
  bottom: void 0,
303
306
  width: void 0
304
- }
307
+ },
308
+ onClick: () => setShowInspector(true)
305
309
  },
306
310
  /* @__PURE__ */ React2.createElement(
307
311
  ToggleButton,
308
312
  {
309
313
  showInspector,
310
314
  setShowInspector,
311
- theme
315
+ theme,
316
+ anchor
312
317
  }
313
318
  )
314
319
  );
@@ -334,7 +339,8 @@ var StateInspector = memo(function StateInspector2({
334
339
  {
335
340
  showInspector,
336
341
  setShowInspector,
337
- theme
342
+ theme,
343
+ anchor
338
344
  }
339
345
  )
340
346
  },
@@ -373,18 +379,18 @@ var StateInspector = memo(function StateInspector2({
373
379
  flexDirection: "column"
374
380
  }
375
381
  },
376
- historySnapshot.history.length < 50 && /* @__PURE__ */ React2.createElement(
382
+ /* @__PURE__ */ React2.createElement(
377
383
  "div",
378
384
  {
379
- id: `history-${0}`,
385
+ id: `${HISTORY_ELEMENT_PREFIX}0`,
380
386
  style: {
381
- borderBottom: `1px solid ${borderColor}`,
387
+ borderBottom: `1px solid ${solidBorderColor}`,
382
388
  fontSize: "12px",
383
389
  fontFamily: "Menlo, monospace",
384
390
  padding: "2px 12px 1px",
385
391
  display: "flex",
386
392
  alignItems: "center",
387
- background: historySnapshot.historyIndex === 0 ? colorScheme === "light" ? "rgba(0,0,0,0.2)" : "rgb(59 130 246 / 38%)" : void 0
393
+ background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
388
394
  }
389
395
  },
390
396
  /* @__PURE__ */ React2.createElement(
@@ -400,15 +406,15 @@ var StateInspector = memo(function StateInspector2({
400
406
  "Initial state"
401
407
  )
402
408
  ),
403
- historySnapshot.history.slice(-50).map((entry, index) => /* @__PURE__ */ React2.createElement(
409
+ historySnapshot.history.map((entry, index) => /* @__PURE__ */ React2.createElement(
404
410
  "div",
405
411
  {
406
- id: `history-${index}`,
412
+ id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
407
413
  key: index,
408
414
  style: {
409
415
  padding: "0px 12px 1px",
410
- borderBottom: `1px solid ${borderColor}`,
411
- background: index === historySnapshot.historyIndex - 1 ? colorScheme === "light" ? "rgba(0,0,0,0.2)" : "rgb(59 130 246 / 15%)" : void 0
416
+ borderBottom: `1px solid ${solidBorderColor}`,
417
+ background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
412
418
  }
413
419
  },
414
420
  entry.redoPatches?.map((patch, j) => /* @__PURE__ */ React2.createElement(
@@ -573,6 +579,7 @@ function Arrow({
573
579
  display: "inline-block",
574
580
  textAlign: "center",
575
581
  transform: expanded ? "rotate(0deg)" : "rotate(-90deg)",
582
+ fontFamily: "Menlo, monospace",
576
583
  ...style
577
584
  }
578
585
  },
@@ -611,6 +618,7 @@ function useStateInspector({
611
618
  connectionEvents,
612
619
  disabled = false,
613
620
  colorScheme,
621
+ anchor,
614
622
  stateManager
615
623
  }) {
616
624
  const [root, setRoot] = React3.useState(null);
@@ -635,11 +643,12 @@ function useStateInspector({
635
643
  state,
636
644
  connectionEvents,
637
645
  colorScheme,
646
+ anchor,
638
647
  stateManager
639
648
  }
640
649
  )
641
650
  );
642
- }, [colorScheme, connectionEvents, root, state, stateManager]);
651
+ }, [anchor, colorScheme, connectionEvents, root, state, stateManager]);
643
652
  }
644
653
 
645
654
  // src/hooks.ts
@@ -744,7 +753,7 @@ function useMultiplayerState(initialState, options) {
744
753
  state,
745
754
  connectionEvents,
746
755
  disabled: !options.inspector,
747
- colorScheme: typeof options.inspector === "object" ? options.inspector.colorScheme : void 0
756
+ ...typeof options.inspector === "object" && options.inspector
748
757
  });
749
758
  return [
750
759
  state,
@@ -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 MultiplayerPatchMetadata,\n MultiplayerStateManager,\n StateManager,\n StateManagerOptions,\n SyncAdapter,\n stubSync,\n} from \"@noya-app/state-manager\";\nimport {\n SetStateAction,\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from \"react\";\nimport { trackEvents, useObservable } from \"./globals\";\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>(\n multiplayerStateManager: MultiplayerStateManager<S>\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>(\n initialState: S | (() => S),\n options: StateManagerOptions<S, MultiplayerPatchMetadata> & {\n sync?: (self: MultiplayerStateManager<S>) => void;\n trackConnectionEvents?: boolean;\n inspector?: boolean | { colorScheme?: \"dark\" | \"light\" };\n }\n) {\n const { sync = defaultStubSync as unknown as SyncAdapter<S>, ...rest } =\n options;\n\n const [multiplayerStateManager] = useState(\n () => new MultiplayerStateManager<S>(initialState, rest)\n );\n\n const syncRef = useRef(sync);\n\n const [connectionEvents, setConnectionEvents] = useState<\n ConnectionEvent<S>[] | undefined\n >();\n\n const extras = useMemo(() => {\n return {\n connectionEvents,\n };\n }, [connectionEvents]);\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 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 if (syncRef.current) {\n return syncRef.current(multiplayerStateManager, (e) =>\n trackEventsCallbackRef.current?.(e)\n );\n }\n }, [multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n useStateInspector({\n stateManager: multiplayerStateManager.sm,\n state,\n connectionEvents,\n disabled: !options.inspector,\n colorScheme:\n typeof options.inspector === \"object\"\n ? options.inspector.colorScheme\n : undefined,\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 { ConnectionEvent, StateManager } 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 disabled = false,\n colorScheme,\n stateManager,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n disabled: boolean;\n colorScheme: ComponentProps<typeof StateInspector>[\"colorScheme\"];\n stateManager: StateManager<S, M>;\n}) {\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 colorScheme={colorScheme}\n stateManager={stateManager as StateManager<any, any>}\n />\n );\n }, [colorScheme, connectionEvents, root, state, stateManager]);\n}\n","import {\n ConnectionEvent,\n ExtendedPathKey,\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\nfunction ToggleButton({\n showInspector,\n setShowInspector,\n theme,\n}: {\n showInspector: boolean;\n setShowInspector: (value: boolean) => void;\n theme: typeof chromeLight;\n}) {\n return (\n <span\n role=\"button\"\n style={{\n flex: \"0\",\n appearance: \"none\",\n color: theme.BASE_COLOR,\n background: \"rgba(0,0,0,0.1)\",\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={() => setShowInspector(!showInspector)}\n >\n <span style={{ width: \"12px\", height: \"12px\" }}>\n {showInspector ? (\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}: {\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}) {\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 }}\n >\n <div\n onClick={() => setOpen?.(!open)}\n style={{\n cursor: \"default\",\n fontSize: \"12px\",\n padding: \"4px 10px\",\n display: \"flex\",\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: \"11px\",\n // fontSize: theme.ARROW_FONT_SIZE,\n marginRight: theme.ARROW_MARGIN_RIGHT,\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\nexport const StateInspector = memo(function StateInspector<\n S extends object,\n M,\n>({\n state,\n connectionEvents,\n unstyled,\n colorScheme = \"light\",\n stateManager,\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\n unstyled?: boolean;\n colorScheme?: \"light\" | \"dark\";\n stateManager: StateManager<S, M>;\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\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-${historySnapshot.historyIndex - 1}`\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\n const baseStyle: CSSProperties = {\n position: \"fixed\",\n top: 12,\n right: 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 ${borderColor}`,\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 };\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 borderRadius: 8,\n bottom: undefined,\n width: undefined,\n }}\n >\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n />\n </div>\n );\n }\n\n return (\n <div\n {...props}\n style={{\n ...(!unstyled && baseStyle),\n ...props.style,\n }}\n >\n {/* <div style={{ flex: \"0\", fontSize: \"12px\" }}>User ID: {userId}</div> */}\n <DisclosureSection\n open\n title=\"Data\"\n colorScheme={colorScheme}\n isFirst\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n />\n }\n >\n <div\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\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\n ref={historyContainerRef}\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {historySnapshot.history.length < 50 && (\n <div\n id={`history-${0}`}\n style={{\n borderBottom: `1px solid ${borderColor}`,\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 ? colorScheme === \"light\"\n ? \"rgba(0,0,0,0.2)\"\n : \"rgb(59 130 246 / 38%)\"\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 )}\n {historySnapshot.history.slice(-50).map((entry, index) => (\n <div\n id={`history-${index}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${borderColor}`,\n background:\n index === historySnapshot.historyIndex - 1\n ? colorScheme === \"light\"\n ? \"rgba(0,0,0,0.2)\"\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\n ref={eventsContainerRef}\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {connectionEvents?.map((event, index) => (\n <div\n key={index}\n style={{\n borderBottom: `1px solid ${borderColor}`,\n }}\n >\n {event.type === \"stateChange\" ? (\n <div\n style={{\n padding: \"2px 12px\",\n background:\n colorScheme === \"light\"\n ? \"rgba(0,0,0,0.05)\"\n : \"rgba(255,255,255,0.05)\",\n display: \"flex\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </span>\n </div>\n ) : (\n <div\n style={{\n padding: \"0px 12px 1px\",\n background:\n event.type === \"send\"\n ? \"rgba(0,255,0,0.1)\"\n : \"rgba(255,0,0,0.1)\",\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 </div>\n )}\n </div>\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 ...style,\n }}\n >\n {\"▼\"}\n </span>\n );\n}\n\n// <div className=\"flex py-px flex-col-reverse\">\n// <button\n// type=\"button\"\n// className={cx(\n// \"px-4 py-2 cursor-pointer text-left\",\n// 0 === historySnapshot.historyIndex && \"bg-orange-500/25\"\n// )}\n// onClick={() => {\n// // stateManager.goToHistoryIndex(0);\n// }}\n// >\n// <div className=\"flex justify-between gap-2\">\n// <span>Initial State</span>\n// </div>\n// </button>\n// {historySnapshot.history.map((entry, index) => (\n// <button\n// key={index}\n// type=\"button\"\n// className={cx(\n// \"px-4 py-2 cursor-pointer text-left\",\n// index === historySnapshot.historyIndex - 1 &&\n// \"bg-orange-500/25\"\n// )}\n// onClick={() => {\n// // stateManager.goToHistoryIndex(index + 1);\n// }}\n// >\n// <div className=\"flex justify-between gap-2\">\n// <span>\n// {index + 1}. {entry.metadata.name}\n// </span>\n// <span>\n// {new Date(\n// entry.metadata.timestamp\n// ).toLocaleTimeString()}\n// </span>\n// </div>\n// <div className=\"font-mono text-xs\">\n// {entry.redoPatches?.map((patch, index) => (\n// <pre key={index} className=\"max-w-full\">\n// {patch.op === \"remove\"\n// ? `Delete ${pathToString(patch.path)}`\n// : `${pathToString(patch.path)} = ${JSON.stringify(\n// patch.value,\n// null,\n// 2\n// )}`}\n// </pre>\n// ))}\n// </div>\n// </button>\n// ))}\n// </div>\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":["useEffect","useState","React","useLayoutEffect","React","useEffect","React","StateInspector","useEffect","React","useLayoutEffect","root","useState","useEffect"]}
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 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?: (self: 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 extras = useMemo(() => {\n return {\n connectionEvents,\n };\n }, [connectionEvents]);\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 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 if (syncRef.current) {\n return syncRef.current(multiplayerStateManager, (e) =>\n trackEventsCallbackRef.current?.(e)\n );\n }\n }, [multiplayerStateManager]);\n\n const state = useSyncMultiplayerStateManager(multiplayerStateManager);\n\n useStateInspector({\n stateManager: multiplayerStateManager.sm,\n state,\n connectionEvents,\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 { ConnectionEvent, StateManager } 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 disabled = false,\n colorScheme,\n anchor,\n stateManager,\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\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 colorScheme={colorScheme}\n anchor={anchor}\n stateManager={stateManager as StateManager<any, any>}\n />\n );\n }, [anchor, colorScheme, connectionEvents, root, state, stateManager]);\n}\n","import {\n ConnectionEvent,\n ExtendedPathKey,\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\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={() => setShowInspector(!showInspector)}\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}: {\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}) {\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 }}\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\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 unstyled,\n colorScheme = \"light\",\n stateManager,\n anchor = \"right\",\n ...props\n}: {\n state: S;\n connectionEvents?: ConnectionEvent<S>[];\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\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 {/* <div style={{ flex: \"0\", fontSize: \"12px\" }}>User ID: {userId}</div> */}\n <DisclosureSection\n open\n title=\"Data\"\n colorScheme={colorScheme}\n isFirst\n right={\n <ToggleButton\n showInspector={showInspector}\n setShowInspector={setShowInspector}\n theme={theme}\n anchor={anchor}\n />\n }\n >\n <div\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\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\n ref={historyContainerRef}\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n overflowX: \"hidden\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\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\n ref={eventsContainerRef}\n style={{\n flex: \"1 1 0\",\n overflowY: \"auto\",\n display: \"flex\",\n flexDirection: \"column\",\n }}\n >\n {connectionEvents?.map((event, index) => (\n <div\n key={index}\n style={{\n borderBottom: `1px solid ${borderColor}`,\n }}\n >\n {event.type === \"stateChange\" ? (\n <div\n style={{\n padding: \"2px 12px\",\n background:\n colorScheme === \"light\"\n ? \"rgba(0,0,0,0.05)\"\n : \"rgba(255,255,255,0.05)\",\n display: \"flex\",\n alignItems: \"center\",\n }}\n >\n <span\n style={{\n fontFamily: \"Menlo, monospace\",\n fontSize: \"11px\",\n borderRadius: 4,\n display: \"inline-block\",\n }}\n >\n connection:{\" \"}\n <span style={{ fontStyle: \"italic\" }}>\n {event.state.toLowerCase()}\n </span>\n </span>\n </div>\n ) : (\n <div\n style={{\n padding: \"0px 12px 1px\",\n background:\n event.type === \"send\"\n ? \"rgba(0,255,0,0.1)\"\n : \"rgba(255,0,0,0.1)\",\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 </div>\n )}\n </div>\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\n// <div className=\"flex py-px flex-col-reverse\">\n// <button\n// type=\"button\"\n// className={cx(\n// \"px-4 py-2 cursor-pointer text-left\",\n// 0 === historySnapshot.historyIndex && \"bg-orange-500/25\"\n// )}\n// onClick={() => {\n// // stateManager.goToHistoryIndex(0);\n// }}\n// >\n// <div className=\"flex justify-between gap-2\">\n// <span>Initial State</span>\n// </div>\n// </button>\n// {historySnapshot.history.map((entry, index) => (\n// <button\n// key={index}\n// type=\"button\"\n// className={cx(\n// \"px-4 py-2 cursor-pointer text-left\",\n// index === historySnapshot.historyIndex - 1 &&\n// \"bg-orange-500/25\"\n// )}\n// onClick={() => {\n// // stateManager.goToHistoryIndex(index + 1);\n// }}\n// >\n// <div className=\"flex justify-between gap-2\">\n// <span>\n// {index + 1}. {entry.metadata.name}\n// </span>\n// <span>\n// {new Date(\n// entry.metadata.timestamp\n// ).toLocaleTimeString()}\n// </span>\n// </div>\n// <div className=\"font-mono text-xs\">\n// {entry.redoPatches?.map((patch, index) => (\n// <pre key={index} className=\"max-w-full\">\n// {patch.op === \"remove\"\n// ? `Delete ${pathToString(patch.path)}`\n// : `${pathToString(patch.path)} = ${JSON.stringify(\n// patch.value,\n// null,\n// 2\n// )}`}\n// </pre>\n// ))}\n// </div>\n// </button>\n// ))}\n// </div>\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":["useEffect","useState","React","useLayoutEffect","React","useEffect","React","StateInspector","useEffect","React","useLayoutEffect","root","useState","useEffect"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noya-app/noya-multiplayer-react",
3
- "version": "0.1.9",
3
+ "version": "0.1.11",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -9,7 +9,7 @@
9
9
  "dev": "npm run build -- --watch"
10
10
  },
11
11
  "dependencies": {
12
- "@noya-app/state-manager": "0.1.9",
12
+ "@noya-app/state-manager": "0.1.11",
13
13
  "@noya-app/emitter": "0.1.0",
14
14
  "react-inspector": "6.0.2"
15
15
  },
package/src/hooks.ts CHANGED
@@ -2,14 +2,15 @@ import {
2
2
  ActionHandler,
3
3
  ConnectionEvent,
4
4
  Get,
5
- MultiplayerPatchMetadata,
6
5
  MultiplayerStateManager,
6
+ MultiplayerStateManagerOptions,
7
7
  StateManager,
8
8
  StateManagerOptions,
9
9
  SyncAdapter,
10
10
  stubSync,
11
11
  } from "@noya-app/state-manager";
12
12
  import {
13
+ ComponentProps,
13
14
  SetStateAction,
14
15
  useCallback,
15
16
  useEffect,
@@ -19,6 +20,7 @@ import {
19
20
  useSyncExternalStore,
20
21
  } from "react";
21
22
  import { trackEvents, useObservable } from "./globals";
23
+ import { StateInspector } from "./inspector/StateInspector";
22
24
  import { useStateInspector } from "./inspector/useStateInspector";
23
25
 
24
26
  export function useSyncStateManager<S extends object, M>(
@@ -117,8 +119,8 @@ export function useManagedHistory<S extends object, M = void>(
117
119
  );
118
120
  }
119
121
 
120
- export function useSyncMultiplayerStateManager<S extends object>(
121
- multiplayerStateManager: MultiplayerStateManager<S>
122
+ export function useSyncMultiplayerStateManager<S extends object, M = void>(
123
+ multiplayerStateManager: MultiplayerStateManager<S, M>
122
124
  ) {
123
125
  return useSyncExternalStore(
124
126
  multiplayerStateManager.addListener,
@@ -129,19 +131,21 @@ export function useSyncMultiplayerStateManager<S extends object>(
129
131
 
130
132
  const defaultStubSync = stubSync();
131
133
 
132
- export function useMultiplayerState<S extends object>(
134
+ export function useMultiplayerState<S extends object, M = void>(
133
135
  initialState: S | (() => S),
134
- options: StateManagerOptions<S, MultiplayerPatchMetadata> & {
135
- sync?: (self: MultiplayerStateManager<S>) => void;
136
+ options: MultiplayerStateManagerOptions<S, M> & {
137
+ sync?: (self: MultiplayerStateManager<S, M>) => void;
136
138
  trackConnectionEvents?: boolean;
137
- inspector?: boolean | { colorScheme?: "dark" | "light" };
139
+ inspector?:
140
+ | boolean
141
+ | Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
138
142
  }
139
143
  ) {
140
- const { sync = defaultStubSync as unknown as SyncAdapter<S>, ...rest } =
144
+ const { sync = defaultStubSync as unknown as SyncAdapter<S, M>, ...rest } =
141
145
  options;
142
146
 
143
147
  const [multiplayerStateManager] = useState(
144
- () => new MultiplayerStateManager<S>(initialState, rest)
148
+ () => new MultiplayerStateManager<S, M>(initialState, rest)
145
149
  );
146
150
 
147
151
  const syncRef = useRef(sync);
@@ -189,10 +193,7 @@ export function useMultiplayerState<S extends object>(
189
193
  state,
190
194
  connectionEvents,
191
195
  disabled: !options.inspector,
192
- colorScheme:
193
- typeof options.inspector === "object"
194
- ? options.inspector.colorScheme
195
- : undefined,
196
+ ...(typeof options.inspector === "object" && options.inspector),
196
197
  });
197
198
 
198
199
  return [