@noya-app/noya-multiplayer-react 0.1.10 → 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/.turbo/turbo-build.log +9 -9
- package/CHANGELOG.md +8 -0
- package/dist/index.d.mts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +5 -5
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +5 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/hooks.ts +8 -8
- package/src/inspector/StateInspector.tsx +26 -28
package/.turbo/turbo-build.log
CHANGED
|
@@ -5,14 +5,14 @@
|
|
|
5
5
|
[34mCLI[39m Target: esnext
|
|
6
6
|
[34mCJS[39m Build start
|
|
7
7
|
[34mESM[39m Build start
|
|
8
|
-
[
|
|
9
|
-
[
|
|
10
|
-
[
|
|
11
|
-
[
|
|
12
|
-
[
|
|
13
|
-
[
|
|
8
|
+
[32mCJS[39m [1mdist/index.js [22m[32m25.32 KB[39m
|
|
9
|
+
[32mCJS[39m [1mdist/index.js.map [22m[32m40.59 KB[39m
|
|
10
|
+
[32mCJS[39m ⚡️ Build success in 18ms
|
|
11
|
+
[32mESM[39m [1mdist/index.mjs [22m[32m21.85 KB[39m
|
|
12
|
+
[32mESM[39m [1mdist/index.mjs.map [22m[32m40.79 KB[39m
|
|
13
|
+
[32mESM[39m ⚡️ Build success in 18ms
|
|
14
14
|
[34mDTS[39m Build start
|
|
15
15
|
"ComponentPropsWithoutRef" is imported from external module "react" but never used in "src/inspector/StateInspector.tsx" and "src/hooks.ts".
|
|
16
|
-
[32mDTS[39m ⚡️ Build success in
|
|
17
|
-
[32mDTS[39m [1mdist/index.d.ts [22m[32m2.
|
|
18
|
-
[32mDTS[39m [1mdist/index.d.mts [22m[32m2.
|
|
16
|
+
[32mDTS[39m ⚡️ Build success in 1599ms
|
|
17
|
+
[32mDTS[39m [1mdist/index.d.ts [22m[32m2.32 KB[39m
|
|
18
|
+
[32mDTS[39m [1mdist/index.d.mts [22m[32m2.32 KB[39m
|
package/CHANGELOG.md
CHANGED
package/dist/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _noya_app_state_manager from '@noya-app/state-manager';
|
|
2
|
-
import { ConnectionEvent, StateManager, Get, StateManagerOptions, MultiplayerStateManager,
|
|
2
|
+
import { ConnectionEvent, StateManager, Get, StateManagerOptions, MultiplayerStateManager, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
|
|
3
3
|
export * from '@noya-app/state-manager';
|
|
4
4
|
import React, { SetStateAction, ComponentProps } from 'react';
|
|
5
5
|
|
|
@@ -17,12 +17,12 @@ declare function useSyncStateManager<S extends object, M>(stateManager: StateMan
|
|
|
17
17
|
declare function useSyncStateManager<S extends object, M, P extends string>(stateManager: StateManager<S, M>, path: P): Get<S, P, unknown>;
|
|
18
18
|
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>];
|
|
19
19
|
declare function useManagedHistory<S extends object, M = void>(stateManager: StateManager<S, M>): _noya_app_state_manager.HistorySnapshot<S, M>;
|
|
20
|
-
declare function useSyncMultiplayerStateManager<S extends object>(multiplayerStateManager: MultiplayerStateManager<S>): S;
|
|
21
|
-
declare function useMultiplayerState<S extends object>(initialState: S | (() => S), options:
|
|
22
|
-
sync?: (self: MultiplayerStateManager<S>) => void;
|
|
20
|
+
declare function useSyncMultiplayerStateManager<S extends object, M = void>(multiplayerStateManager: MultiplayerStateManager<S, M>): S;
|
|
21
|
+
declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options: MultiplayerStateManagerOptions<S, M> & {
|
|
22
|
+
sync?: (self: MultiplayerStateManager<S, M>) => void;
|
|
23
23
|
trackConnectionEvents?: boolean;
|
|
24
24
|
inspector?: boolean | Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
|
|
25
|
-
}): readonly [S, (metadata:
|
|
25
|
+
}): readonly [S, (...args: M extends {} ? [metadata: M, action: S | ((prevState: S) => S)] : [action: S | ((prevState: S) => S)]) => void, MultiplayerStateManager<S, M>, {
|
|
26
26
|
connectionEvents: ConnectionEvent<S>[] | undefined;
|
|
27
27
|
}];
|
|
28
28
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as _noya_app_state_manager from '@noya-app/state-manager';
|
|
2
|
-
import { ConnectionEvent, StateManager, Get, StateManagerOptions, MultiplayerStateManager,
|
|
2
|
+
import { ConnectionEvent, StateManager, Get, StateManagerOptions, MultiplayerStateManager, MultiplayerStateManagerOptions } from '@noya-app/state-manager';
|
|
3
3
|
export * from '@noya-app/state-manager';
|
|
4
4
|
import React, { SetStateAction, ComponentProps } from 'react';
|
|
5
5
|
|
|
@@ -17,12 +17,12 @@ declare function useSyncStateManager<S extends object, M>(stateManager: StateMan
|
|
|
17
17
|
declare function useSyncStateManager<S extends object, M, P extends string>(stateManager: StateManager<S, M>, path: P): Get<S, P, unknown>;
|
|
18
18
|
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>];
|
|
19
19
|
declare function useManagedHistory<S extends object, M = void>(stateManager: StateManager<S, M>): _noya_app_state_manager.HistorySnapshot<S, M>;
|
|
20
|
-
declare function useSyncMultiplayerStateManager<S extends object>(multiplayerStateManager: MultiplayerStateManager<S>): S;
|
|
21
|
-
declare function useMultiplayerState<S extends object>(initialState: S | (() => S), options:
|
|
22
|
-
sync?: (self: MultiplayerStateManager<S>) => void;
|
|
20
|
+
declare function useSyncMultiplayerStateManager<S extends object, M = void>(multiplayerStateManager: MultiplayerStateManager<S, M>): S;
|
|
21
|
+
declare function useMultiplayerState<S extends object, M = void>(initialState: S | (() => S), options: MultiplayerStateManagerOptions<S, M> & {
|
|
22
|
+
sync?: (self: MultiplayerStateManager<S, M>) => void;
|
|
23
23
|
trackConnectionEvents?: boolean;
|
|
24
24
|
inspector?: boolean | Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
|
|
25
|
-
}): readonly [S, (metadata:
|
|
25
|
+
}): readonly [S, (...args: M extends {} ? [metadata: M, action: S | ((prevState: S) => S)] : [action: S | ((prevState: S) => S)]) => void, MultiplayerStateManager<S, M>, {
|
|
26
26
|
connectionEvents: ConnectionEvent<S>[] | undefined;
|
|
27
27
|
}];
|
|
28
28
|
|
package/dist/index.js
CHANGED
|
@@ -279,7 +279,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
|
|
|
279
279
|
if (!historyContainerRef.current)
|
|
280
280
|
return;
|
|
281
281
|
const historyEntry = historyContainerRef.current.querySelector(
|
|
282
|
-
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex
|
|
282
|
+
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
|
|
283
283
|
);
|
|
284
284
|
if (historyEntry) {
|
|
285
285
|
historyEntry.scrollIntoView({
|
|
@@ -397,7 +397,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
|
|
|
397
397
|
flexDirection: "column"
|
|
398
398
|
}
|
|
399
399
|
},
|
|
400
|
-
|
|
400
|
+
/* @__PURE__ */ import_react3.default.createElement(
|
|
401
401
|
"div",
|
|
402
402
|
{
|
|
403
403
|
id: `${HISTORY_ELEMENT_PREFIX}0`,
|
|
@@ -424,15 +424,15 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
|
|
|
424
424
|
"Initial state"
|
|
425
425
|
)
|
|
426
426
|
),
|
|
427
|
-
historySnapshot.history.
|
|
427
|
+
historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react3.default.createElement(
|
|
428
428
|
"div",
|
|
429
429
|
{
|
|
430
|
-
id:
|
|
430
|
+
id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
|
|
431
431
|
key: index,
|
|
432
432
|
style: {
|
|
433
433
|
padding: "0px 12px 1px",
|
|
434
434
|
borderBottom: `1px solid ${solidBorderColor}`,
|
|
435
|
-
background: index === historySnapshot.historyIndex
|
|
435
|
+
background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
|
|
436
436
|
}
|
|
437
437
|
},
|
|
438
438
|
entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react3.default.createElement(
|
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 MultiplayerPatchMetadata,\n MultiplayerStateManager,\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>(\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?:\n | boolean\n | Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">;\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 ...(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 - 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 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 {historySnapshot.history.length < 50 && (\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 )}\n {historySnapshot.history.slice(-50).map((entry, index) => (\n <div\n id={`noya-multiplayer-history-${index}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index === historySnapshot.historyIndex - 1\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":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,wBAAc,oCAAd;;;ACAA,2BAUO;AACP,IAAAA,gBASO;;;ACpBP,qBAAwB;AACxB,mBAAoC;AAEpC,IAAM,aAAN,MAAoB;AAAA,EACV;AAAA,EACA,UAAU,IAAI,uBAAa;AAAA,EAEnC,YAAY,OAAU;AACpB,SAAK,QAAQ;AAAA,EACf;AAAA,EAEA,MAAM;AACJ,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,OAAU;AACZ,QAAI,KAAK,UAAU;AAAO;AAE1B,SAAK,QAAQ;AAEb,SAAK,QAAQ,KAAK,KAAK;AAAA,EACzB;AAAA,EAEA,OAAO,UAA8B;AACnC,aAAS,KAAK,KAAK;AAEnB,WAAO,KAAK,QAAQ,YAAY,QAAQ;AAAA,EAC1C;AACF;AAEO,SAAS,cAAiB,YAA2B;AAC1D,QAAM,CAAC,OAAO,QAAQ,QAAI,uBAAS,WAAW,IAAI,CAAC;AAEnD,8BAAU,MAAM;AACd,WAAO,WAAW,OAAO,QAAQ;AAAA,EACnC,GAAG,CAAC,UAAU,CAAC;AAEf,SAAO;AACT;AAEO,IAAM,cAAc,IAAI,WAAW,KAAK;;;ACvC/C,IAAAC,gBAAuD;AACvD,oBAA2B;;;ACG3B,IAAAC,gBAOO;AACP,6BAOO;;;ACpBP,IAAAC,gBAAkB;AAElB,IAAM,eAAe,OAAO,WAAW,cAAc,OAAO,eAAe;AAEpE,SAAS,qBACd,KACA,cACyB;AACzB,QAAM,CAAC,OAAO,QAAQ,IAAI,cAAAC,QAAM,SAAY,MAAM;AAChD,UAAM,QAAQ,cAAc,QAAQ,GAAG;AACvC,QAAI,SAAS;AACb,QAAI,OAAO;AACT,UAAI;AACF,iBAAS,KAAK,MAAM,KAAK;AAAA,MAC3B,SAAS,OAAO;AACd,gBAAQ,MAAM,oCAAoC,KAAK;AAAA,MACzD;AAAA,IACF;AACA,WAAO;AAAA,EACT,CAAC;AAED,QAAM,uBAAuB,CAAC,UAAa;AACzC,kBAAc,QAAQ,KAAK,KAAK,UAAU,KAAK,CAAC;AAChD,aAAS,KAAK;AAAA,EAChB;AAEA,SAAO,CAAC,OAAO,oBAAoB;AACrC;;;ADFA,IAAM,aAAa;AAAA,EACjB,GAAG;AAAA,EACH,uBAAuB;AAAA,EACvB,mBAAmB;AACrB;AAEA,IAAM,YAAY;AAAA,EAChB,GAAG;AAAA,EACH,uBAAuB;AAAA,EACvB,mBAAmB;AACrB;AAEA,SAAS,aAAa;AAAA,EACpB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAKG;AACD,SACE,8BAAAC,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL,OAAO;AAAA,QACL,MAAM;AAAA,QACN,YAAY;AAAA,QACZ,OAAO,MAAM;AAAA,QACb,QAAQ;AAAA,QACR,UAAU;AAAA,QACV,YAAY;AAAA,QACZ,SAAS;AAAA,QACT,YAAY;AAAA,QACZ,gBAAgB;AAAA,QAChB,SAAS;AAAA,MACX;AAAA,MACA,SAAS,MAAM,iBAAiB,CAAC,aAAa;AAAA;AAAA,IAE9C,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,OAAO,QAAQ,QAAQ,OAAO,KAC1C,mBAAmB,WAAW,WAC7B,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,aAAa;AAAA,QACb,QAAO;AAAA,QACP,WAAU;AAAA;AAAA,MAEV,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,GAAE;AAAA;AAAA,MACJ;AAAA,IACF,IAEA,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAM;AAAA,QACN,MAAK;AAAA,QACL,SAAQ;AAAA,QACR,aAAa;AAAA,QACb,QAAO;AAAA,QACP,WAAU;AAAA;AAAA,MAEV,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,eAAc;AAAA,UACd,gBAAe;AAAA,UACf,GAAE;AAAA;AAAA,MACJ;AAAA,IACF,CAEJ;AAAA,EACF;AAEJ;AAEA,SAAS,kBAAkB;AAAA,EACzB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,GAQG;AACD,QAAM,QAAQ,gBAAgB,UAAU,aAAa;AAErD,QAAM,cACJ,gBAAgB,UAAU,oBAAoB;AAEhD,SACE,8BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,OAAO;AAAA,QACL,MAAM,OAAO,UAAU;AAAA,QACvB,SAAS;AAAA,QACT,eAAe;AAAA,MACjB;AAAA;AAAA,IAEA,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,SAAS,MAAM,UAAU,CAAC,IAAI;AAAA,QAC9B,OAAO;AAAA,UACL,QAAQ;AAAA,UACR,UAAU;AAAA,UACV,SAAS;AAAA,UACT,SAAS;AAAA,UACT,YAAY;AAAA,UACZ,GAAI,CAAC,WAAW,EAAE,WAAW,aAAa,WAAW,GAAG;AAAA,UACxD,GAAI,QAAQ,EAAE,cAAc,aAAa,WAAW,GAAG;AAAA,QACzD;AAAA;AAAA,MAEC,WACC,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,UAAU;AAAA,UACV,OAAO;AAAA,YACL,UAAU,MAAM;AAAA,YAChB,aAAa,MAAM,qBAAqB;AAAA,YACxC,OAAO,MAAM;AAAA,UACf;AAAA;AAAA,MACF;AAAA,MAEF,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,MAAM,QAAQ,KAAI,KAAM;AAAA,MACtC;AAAA,IACH;AAAA,IACC,QAAQ;AAAA,EACX;AAEJ;AAEA,IAAM,yBAAyB;AAIxB,IAAM,qBAAiB,oBAAK,SAASC,gBAG1C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,cAAc;AAAA,EACd;AAAA,EACA,SAAS;AAAA,EACT,GAAG;AACL,GAOqC;AACnC,QAAM,CAAC,UAAU,WAAW,IAAI,cAAAD,QAAM,SAAS,KAAK;AAEpD,qCAAgB,MAAM;AACpB,gBAAY,IAAI;AAAA,EAClB,GAAG,CAAC,CAAC;AAEL,QAAM,qBAAqB,cAAAA,QAAM,OAAuB,IAAI;AAC5D,QAAM,sBAAsB,cAAAA,QAAM,OAAuB,IAAI;AAE7D,QAAM,CAAC,eAAe,gBAAgB,IAAI;AAAA,IACxC;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,YAAY,aAAa,IAAI;AAAA,IAClC;AAAA,IACA;AAAA,EACF;AACA,QAAM,CAAC,aAAa,cAAc,IAAI;AAAA,IACpC;AAAA,IACA;AAAA,EACF;AAEA,+BAAU,MAAM;AACd,gBAAY,IAAI,UAAU;AAAA,EAC5B,GAAG,CAAC,UAAU,CAAC;AAEf,+BAAU,MAAM;AACd,QAAI,mBAAmB,SAAS;AAC9B,yBAAmB,QAAQ,YACzB,mBAAmB,QAAQ;AAAA,IAC/B;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,kBAAkB,kBAAkB,YAAY;AAEtD,+BAAU,MAAM;AACd,QAAI,oBAAoB,SAAS;AAC/B,0BAAoB,QAAQ,YAC1B,oBAAoB,QAAQ;AAAA,IAChC;AAAA,EACF,GAAG,CAAC,eAAe,CAAC;AAGpB,+BAAU,MAAM;AACd,QAAI,CAAC,oBAAoB;AAAS;AAElC,UAAM,eAAe,oBAAoB,QAAQ;AAAA,MAC/C,IAAI,sBAAsB,GAAG,gBAAgB,eAAe,CAAC;AAAA,IAC/D;AAEA,QAAI,cAAc;AAChB,mBAAa,eAAe;AAAA,QAC1B,OAAO;AAAA,QACP,QAAQ;AAAA,MACV,CAAC;AAAA,IACH;AAAA,EACF,GAAG,CAAC,gBAAgB,YAAY,CAAC;AAEjC,QAAM,QAAQ,gBAAgB,UAAU,aAAa;AACrD,QAAM,cACJ,gBAAgB,UAAU,oBAAoB;AAChD,QAAM,mBACJ,gBAAgB,UAAU,qBAAqB;AAEjD,QAAM,YAA2B;AAAA,IAC/B,UAAU;AAAA,IACV,KAAK;AAAA,IACL,GAAI,WAAW,UAAU,EAAE,OAAO,GAAG,IAAI,EAAE,MAAM,GAAG;AAAA,IACpD,QAAQ;AAAA,IACR,OAAO;AAAA,IACP,YACE,gBAAgB,UAAU,2BAA2B;AAAA,IACvD,gBAAgB;AAAA,IAChB,QAAQ,aAAa,gBAAgB;AAAA;AAAA,IAErC,cAAc;AAAA,IACd,SAAS;AAAA,IACT,eAAe;AAAA;AAAA,IAEf,OAAO,MAAM;AAAA,IACb,UAAU;AAAA,IACV,QAAQ;AAAA,IACR,YAAY;AAAA,EACd;AAEA,MAAI,CAAC;AAAU,WAAO;AAEtB,MAAI,CAAC,eAAe;AAClB,WACE,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACE,GAAG;AAAA,QACJ,OAAO;AAAA,UACL,GAAG;AAAA,UACH,SAAS;AAAA,UACT,QAAQ;AAAA,UACR,OAAO;AAAA,QACT;AAAA,QACA,SAAS,MAAM,iBAAiB,IAAI;AAAA;AAAA,MAEpC,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IACF;AAAA,EAEJ;AAEA,SACE,8BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACE,GAAG;AAAA,MACJ,OAAO;AAAA,QACL,GAAI,CAAC,YAAY;AAAA,QACjB,GAAG,MAAM;AAAA,MACX;AAAA;AAAA,IAGA,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAI;AAAA,QACJ,OAAM;AAAA,QACN;AAAA,QACA,SAAO;AAAA,QACP,OACE,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YACC;AAAA,YACA;AAAA,YACA;AAAA,YACA;AAAA;AAAA,QACF;AAAA;AAAA,MAGF,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,OAAO;AAAA,YACL,MAAM;AAAA,YACN,WAAW;AAAA,YACX,SAAS;AAAA,YACT,eAAe;AAAA,YACf,KAAK;AAAA,YACL,SAAS;AAAA,UACX;AAAA;AAAA,QAEA,8BAAAA,QAAA,cAAC,0CAAgB,MAAM,OAAO,OAAc;AAAA,MAC9C;AAAA,IACF;AAAA,IACA,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAM;AAAA,QACN;AAAA;AAAA,MAEA,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,OAAO;AAAA,YACL,MAAM;AAAA,YACN,WAAW;AAAA,YACX,WAAW;AAAA,YACX,SAAS;AAAA,YACT,eAAe;AAAA,UACjB;AAAA;AAAA,QAEC,gBAAgB,QAAQ,SAAS,MAChC,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAI,GAAG,sBAAsB;AAAA,YAC7B,OAAO;AAAA,cACL,cAAc,aAAa,gBAAgB;AAAA,cAC3C,UAAU;AAAA,cACV,YAAY;AAAA,cACZ,SAAS;AAAA,cACT,SAAS;AAAA,cACT,YAAY;AAAA,cACZ,YACE,gBAAgB,iBAAiB,IAC7B,0BACA;AAAA,YACR;AAAA;AAAA,UAEA,8BAAAA,QAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,YAAY;AAAA,gBACZ,UAAU;AAAA,gBACV,cAAc;AAAA,gBACd,SAAS;AAAA,cACX;AAAA;AAAA,YACD;AAAA,UAED;AAAA,QACF;AAAA,QAED,gBAAgB,QAAQ,MAAM,GAAG,EAAE,IAAI,CAAC,OAAO,UAC9C,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YACC,IAAI,4BAA4B,KAAK;AAAA,YACrC,KAAK;AAAA,YACL,OAAO;AAAA,cACL,SAAS;AAAA,cACT,cAAc,aAAa,gBAAgB;AAAA,cAC3C,YACE,UAAU,gBAAgB,eAAe,IACrC,0BACA;AAAA,YACR;AAAA;AAAA,UAEC,MAAM,aAAa,IAAI,CAAC,OAAO,MAC9B,8BAAAA,QAAA;AAAA,YAAC;AAAA;AAAA,cACC,KAAK;AAAA,cACL,OAAO;AAAA,gBACL,UAAU;AAAA,gBACV,SAAS;AAAA,gBACT,UAAU;AAAA,cACZ;AAAA;AAAA,YAEC,MAAM,OAAO,SACZ,8BAAAA,QAAA,4BAAAA,QAAA,gBACE,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,WAAW,SAAS,KAChC,aAAa,MAAM,IAAI,CAC1B,GACC,OACD,8BAAAA,QAAA,cAAC,0CAAgB,MAAM,MAAM,OAAO,OAAc,CACpD;AAAA,YAED,MAAM,OAAO,aACZ,8BAAAA,QAAA,4BAAAA,QAAA,gBACE,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,WAAW,SAAS,KAChC,aAAa,MAAM,IAAI,CAC1B,GACC,OACD,8BAAAA,QAAA,cAAC,0CAAgB,MAAM,MAAM,OAAO,OAAc,CACpD;AAAA,YAED,MAAM,OAAO,YACZ,8BAAAA,QAAA,4BAAAA,QAAA,gBACE,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,OAAO,MAAM,0BAA0B,KAAG,UAChD,GACT,GACA,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,WAAW,SAAS,KAChC,aAAa,MAAM,IAAI,CAC1B,CACF;AAAA,UAEJ,CACD;AAAA,QACH,CACD;AAAA,MACH;AAAA,IACF;AAAA,IACA,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,MAAM;AAAA,QACN,SAAS;AAAA,QACT,OAAM;AAAA,QACN;AAAA;AAAA,MAEA,8BAAAA,QAAA;AAAA,QAAC;AAAA;AAAA,UACC,KAAK;AAAA,UACL,OAAO;AAAA,YACL,MAAM;AAAA,YACN,WAAW;AAAA,YACX,SAAS;AAAA,YACT,eAAe;AAAA,UACjB;AAAA;AAAA,QAEC,kBAAkB,IAAI,CAAC,OAAO,UAC7B,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YACC,KAAK;AAAA,YACL,OAAO;AAAA,cACL,cAAc,aAAa,WAAW;AAAA,YACxC;AAAA;AAAA,UAEC,MAAM,SAAS,gBACd,8BAAAA,QAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YACE,gBAAgB,UACZ,qBACA;AAAA,gBACN,SAAS;AAAA,gBACT,YAAY;AAAA,cACd;AAAA;AAAA,YAEA,8BAAAA,QAAA;AAAA,cAAC;AAAA;AAAA,gBACC,OAAO;AAAA,kBACL,YAAY;AAAA,kBACZ,UAAU;AAAA,kBACV,cAAc;AAAA,kBACd,SAAS;AAAA,gBACX;AAAA;AAAA,cACD;AAAA,cACa;AAAA,cACZ,8BAAAA,QAAA,cAAC,UAAK,OAAO,EAAE,WAAW,SAAS,KAChC,MAAM,MAAM,YAAY,CAC3B;AAAA,YACF;AAAA,UACF,IAEA,8BAAAA,QAAA;AAAA,YAAC;AAAA;AAAA,cACC,OAAO;AAAA,gBACL,SAAS;AAAA,gBACT,YACE,MAAM,SAAS,SACX,sBACA;AAAA,cACR;AAAA;AAAA,YAEA,8BAAAA,QAAA;AAAA,cAAC;AAAA;AAAA,gBACC,MAAM,MAAM;AAAA,gBACZ;AAAA,gBACA,cAAc,CAAC;AAAA,kBACb;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,kBACA;AAAA,gBACF,MAAW;AACT,wBAAM,YAAY,MAAM,SAAS,SAAS,OAAO;AAEjD,yBAAO,UAAU,IACf,8BAAAA,QAAA,cAAC,mBAAgB,WAAsB,MAAY,IAEnD,8BAAAA,QAAA;AAAA,oBAAC;AAAA;AAAA,sBACC;AAAA,sBACA;AAAA,sBACA;AAAA,sBACA;AAAA;AAAA,kBACF;AAAA,gBAEJ;AAAA;AAAA,YACF;AAAA,UACF;AAAA,QAEJ,CACD;AAAA,QACA,CAAC,oBACA,8BAAAA,QAAA;AAAA,UAAC;AAAA;AAAA,YACC,OAAO;AAAA,cACL,SAAS;AAAA,cACT,UAAU;AAAA,cACV,SAAS;AAAA,cACT,eAAe;AAAA,cACf,KAAK;AAAA,YACP;AAAA;AAAA,UAEA,8BAAAA,QAAA,cAAC,cAAK,oBAAkB;AAAA,QAC1B;AAAA,MAEJ;AAAA,IACF;AAAA,EACF;AAEJ,CAAC;AAID,IAAM,kBAID,CAAC,EAAE,MAAM,MAAM,UAAU,MAAM;AAClC,MAAI,OAAO,SAAS,UAAU;AAC5B,WACE,8BAAAA,QAAA,cAAC,cACC,8BAAAA,QAAA,cAAC,qCAAW,MAAY,GACxB,8BAAAA,QAAA,cAAC,cAAK,IAAE,GACR,8BAAAA,QAAA,cAAC,wCAAc,MAAY,CAC7B;AAAA,EAEJ;AACA,MAAI,cAAc,QAAQ,cAAc,QAAQ;AAC9C,UAAM,QAAQ,cAAc,OAAO,WAAM;AAEzC,WACE,8BAAAA,QAAA,cAAC,cACC,8BAAAA,QAAA;AAAA,MAAC;AAAA;AAAA,QACC,OAAO;AAAA,UACL,YACE,cAAc,OAAO,sBAAsB;AAAA;AAAA,UAE7C,OAAO;AAAA,UACP,QAAQ;AAAA,UACR,cAAc;AAAA,UACd,SAAS;AAAA,UACT,gBAAgB;AAAA,UAChB,YAAY;AAAA,UACZ,aAAa;AAAA,UACb,YAAY;AAAA,QACd;AAAA;AAAA,MAEC;AAAA,IACH,GACA,8BAAAA,QAAA,cAAC,wCAAc,MAAY,CAC7B;AAAA,EAEJ,OAAO;AACL,WAAO,8BAAAA,QAAA,cAAC,wCAAc,MAAY;AAAA,EACpC;AACF;AAGA,SAAS,MAAM;AAAA,EACb;AAAA,EACA;AAAA,EACA;AACF,GAIG;AACD,SACE,8BAAAA,QAAA;AAAA,IAAC;AAAA;AAAA,MACC,MAAK;AAAA,MACL;AAAA,MACA,OAAO;AAAA,QACL,SAAS;AAAA,QACT,WAAW;AAAA,QACX,WAAW,WAAW,iBAAiB;AAAA,QACvC,YAAY;AAAA,QACZ,GAAG;AAAA,MACL;AAAA;AAAA,IAEC;AAAA,EACH;AAEJ;AAyDA,SAAS,aAAa,cAAiC;AACrD,SAAO,aACJ;AAAA,IAAI,CAAC,QACJ,OAAO,QAAQ,WACX,IAAI,SAAS,IAAI,GAAG,SAAS,GAAG,GAAG,QAAQ,CAAC,KAC5C;AAAA,EACN,EACC;AAAA,IAAI,CAAC,KAAK,UACT,UAAU,KAAM,OAAO,QAAQ,YAAY,IAAI,WAAW,GAAG,IACzD,MACA,IAAI,GAAG;AAAA,EACb,EACC,KAAK,EAAE;AACZ;AAIA,SAAS,SACP,KACA,WACA,WAA6B,OAC7B;AACA,MAAI,IAAI,UAAU;AAAW,WAAO;AAEpC,UAAQ,UAAU;AAAA,IAChB,KAAK;AACH,aAAO,SAAI,IAAI,MAAM,IAAI,SAAS,SAAS,CAAC;AAAA,IAC9C,KAAK;AACH,YAAM,aAAa,KAAK,MAAM,YAAY,CAAC;AAC3C,aAAO,GAAG,IAAI,MAAM,GAAG,UAAU,CAAC,SAAI,IAAI,MAAM,IAAI,SAAS,UAAU,CAAC;AAAA,IAC1E,KAAK;AACH,aAAO,GAAG,IAAI,MAAM,GAAG,SAAS,CAAC;AAAA,EACrC;AACF;;;ADjrBA,SAAS,sBAAsB;AAC7B,QAAM,KAAK,SAAS,cAAc,KAAK;AACvC,KAAG,KAAK;AACR,SAAO;AACT;AAEO,SAAS,kBAAuC;AAAA,EACrD;AAAA,EACA;AAAA,EACA,WAAW;AAAA,EACX;AAAA,EACA;AAAA,EACA;AACF,GAK2E;AACzE,QAAM,CAAC,MAAM,OAAO,IAAI,cAAAE,QAAM,SAAsB,IAAI;AAExD,qCAAgB,MAAM;AACpB,QAAI;AAAU;AAEd,UAAM,gBAAgB,oBAAoB;AAE1C,UAAMC,YAAO,0BAAW,aAAa;AAErC,aAAS,KAAK,YAAY,aAAa;AAEvC,YAAQA,KAAI;AAEZ,WAAO,MAAM;AACX,eAAS,KAAK,YAAY,aAAa;AAAA,IACzC;AAAA,EACF,GAAG,CAAC,QAAQ,CAAC;AAEb,qCAAgB,MAAM;AACpB,QAAI,CAAC;AAAM;AAEX,SAAK;AAAA,MACH,8BAAAD,QAAA;AAAA,QAAC;AAAA;AAAA,UACC;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA,UACA;AAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF,GAAG,CAAC,QAAQ,aAAa,kBAAkB,MAAM,OAAO,YAAY,CAAC;AACvE;;;AFzBO,SAAS,oBACd,cACA,MACA;AACA,QAAM,kBAAc;AAAA,IAClB,MACE,OAAO,SAAS,WACZ,aAAa,SAAS,IAAI,IAC1B,aAAa,SAAS;AAAA,IAC5B,CAAC,cAAc,IAAI;AAAA,EACrB;AAEA,aAAO;AAAA,IACL,aAAa;AAAA,IACb;AAAA,IACA;AAAA,EACF;AACF;AAEO,SAAS,gBACd,oBACA,SACA;AACA,QAAM,CAAC,YAAY,QAAI;AAAA,IACrB,MAAM,IAAI,kCAAmB,mBAAmB,GAAG,OAAO;AAAA,EAC5D;AAEA,QAAM,QAAQ,oBAAoB,YAAY;AAE9C,QAAM,eAAW;AAAA,IACf,IACK,SAGA;AACH,YAAM,CAAC,UAAU,MAAM,IACrB,KAAK,WAAW,IAAI,CAAC,QAAW,KAAK,CAAC,CAAC,IAAI;AAE7C,UAAI,aAAa,QAAW;AAC1B,cAAM,0BAA0B,aAAa;AAI7C,YAAI,OAAO,WAAW,YAAY;AAChC,kCAAwB;AAAA,YACtB,KAAK;AAAA,YACL,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AACL,kCAAwB;AAAA,YACtB,KAAK,MAAM;AAAA,YACX,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF,OAAO;AACL,cAAM,4BAA4B,aAAa;AAK/C,YAAI,OAAO,WAAW,YAAY;AAChC,oCAA0B,UAAU;AAAA,YAClC,KAAK;AAAA,YACL,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH,OAAO;AACL,oCAA0B,UAAU;AAAA,YAClC,KAAK,MAAM;AAAA,YACX,MAAM,MAAM;AAAA,UACd,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,IACA,CAAC,OAAO,YAAY;AAAA,EACtB;AAEA,SAAO,CAAC,OAAO,UAAU,YAAY;AACvC;AAEO,SAAS,kBACd,cACA;AACA,aAAO;AAAA,IACL,aAAa,eAAe;AAAA,IAC5B,aAAa;AAAA,IACb,aAAa;AAAA,EACf;AACF;AAEO,SAAS,+BACd,yBACA;AACA,aAAO;AAAA,IACL,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,IACxB,wBAAwB;AAAA,EAC1B;AACF;AAEA,IAAM,sBAAkB,+BAAS;AAE1B,SAAS,oBACd,cACA,SAOA;AACA,QAAM,EAAE,OAAO,iBAA8C,GAAG,KAAK,IACnE;AAEF,QAAM,CAAC,uBAAuB,QAAI;AAAA,IAChC,MAAM,IAAI,6CAA2B,cAAc,IAAI;AAAA,EACzD;AAEA,QAAM,cAAU,sBAAO,IAAI;AAE3B,QAAM,CAAC,kBAAkB,mBAAmB,QAAI,wBAE9C;AAEF,QAAM,aAAS,uBAAQ,MAAM;AAC3B,WAAO;AAAA,MACL;AAAA,IACF;AAAA,EACF,GAAG,CAAC,gBAAgB,CAAC;AAErB,QAAM,oBAAoB,cAAc,WAAW;AACnD,QAAM,wBACJ,QAAQ,yBAAyB;AAEnC,QAAM,6BAAyB,sBAE7B;AAEF,+BAAU,MAAM;AACd,2BAAuB,UAAU,wBAC7B,CAAC,MACC,oBAAoB,CAAC,WAAW;AAC9B,YAAM,UAAU,SAAS,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;AAC5C,aAAO,QAAQ,SAAS,KAAK,QAAQ,MAAM,GAAG,IAAI;AAAA,IACpD,CAAC,IACH;AAAA,EACN,GAAG,CAAC,qBAAqB,CAAC;AAE1B,+BAAU,MAAM;AACd,QAAI,QAAQ,SAAS;AACnB,aAAO,QAAQ;AAAA,QAAQ;AAAA,QAAyB,CAAC,MAC/C,uBAAuB,UAAU,CAAC;AAAA,MACpC;AAAA,IACF;AAAA,EACF,GAAG,CAAC,uBAAuB,CAAC;AAE5B,QAAM,QAAQ,+BAA+B,uBAAuB;AAEpE,oBAAkB;AAAA,IAChB,cAAc,wBAAwB;AAAA,IACtC;AAAA,IACA;AAAA,IACA,UAAU,CAAC,QAAQ;AAAA,IACnB,GAAI,OAAO,QAAQ,cAAc,YAAY,QAAQ;AAAA,EACvD,CAAC;AAED,SAAO;AAAA,IACL;AAAA,IACA,wBAAwB;AAAA,IACxB;AAAA,IACA;AAAA,EACF;AACF;","names":["import_react","import_react","import_react","import_react","React","React","StateInspector","React","root"]}
|
|
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":["import_react","import_react","import_react","import_react","React","React","StateInspector","React","root"]}
|
package/dist/index.mjs
CHANGED
|
@@ -261,7 +261,7 @@ var StateInspector = memo(function StateInspector2({
|
|
|
261
261
|
if (!historyContainerRef.current)
|
|
262
262
|
return;
|
|
263
263
|
const historyEntry = historyContainerRef.current.querySelector(
|
|
264
|
-
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex
|
|
264
|
+
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
|
|
265
265
|
);
|
|
266
266
|
if (historyEntry) {
|
|
267
267
|
historyEntry.scrollIntoView({
|
|
@@ -379,7 +379,7 @@ var StateInspector = memo(function StateInspector2({
|
|
|
379
379
|
flexDirection: "column"
|
|
380
380
|
}
|
|
381
381
|
},
|
|
382
|
-
|
|
382
|
+
/* @__PURE__ */ React2.createElement(
|
|
383
383
|
"div",
|
|
384
384
|
{
|
|
385
385
|
id: `${HISTORY_ELEMENT_PREFIX}0`,
|
|
@@ -406,15 +406,15 @@ var StateInspector = memo(function StateInspector2({
|
|
|
406
406
|
"Initial state"
|
|
407
407
|
)
|
|
408
408
|
),
|
|
409
|
-
historySnapshot.history.
|
|
409
|
+
historySnapshot.history.map((entry, index) => /* @__PURE__ */ React2.createElement(
|
|
410
410
|
"div",
|
|
411
411
|
{
|
|
412
|
-
id:
|
|
412
|
+
id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
|
|
413
413
|
key: index,
|
|
414
414
|
style: {
|
|
415
415
|
padding: "0px 12px 1px",
|
|
416
416
|
borderBottom: `1px solid ${solidBorderColor}`,
|
|
417
|
-
background: index === historySnapshot.historyIndex
|
|
417
|
+
background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
|
|
418
418
|
}
|
|
419
419
|
},
|
|
420
420
|
entry.redoPatches?.map((patch, j) => /* @__PURE__ */ React2.createElement(
|
package/dist/index.mjs.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 MultiplayerPatchMetadata,\n MultiplayerStateManager,\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>(\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?:\n | boolean\n | Pick<ComponentProps<typeof StateInspector>, \"colorScheme\" | \"anchor\">;\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 ...(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 - 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 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 {historySnapshot.history.length < 50 && (\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 )}\n {historySnapshot.history.slice(-50).map((entry, index) => (\n <div\n id={`noya-multiplayer-history-${index}`}\n key={index}\n style={{\n padding: \"0px 12px 1px\",\n borderBottom: `1px solid ${solidBorderColor}`,\n background:\n index === historySnapshot.historyIndex - 1\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"]}
|
|
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.
|
|
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.
|
|
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,8 +2,8 @@ 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,
|
|
@@ -119,8 +119,8 @@ export function useManagedHistory<S extends object, M = void>(
|
|
|
119
119
|
);
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
export function useSyncMultiplayerStateManager<S extends object>(
|
|
123
|
-
multiplayerStateManager: MultiplayerStateManager<S>
|
|
122
|
+
export function useSyncMultiplayerStateManager<S extends object, M = void>(
|
|
123
|
+
multiplayerStateManager: MultiplayerStateManager<S, M>
|
|
124
124
|
) {
|
|
125
125
|
return useSyncExternalStore(
|
|
126
126
|
multiplayerStateManager.addListener,
|
|
@@ -131,21 +131,21 @@ export function useSyncMultiplayerStateManager<S extends object>(
|
|
|
131
131
|
|
|
132
132
|
const defaultStubSync = stubSync();
|
|
133
133
|
|
|
134
|
-
export function useMultiplayerState<S extends object>(
|
|
134
|
+
export function useMultiplayerState<S extends object, M = void>(
|
|
135
135
|
initialState: S | (() => S),
|
|
136
|
-
options:
|
|
137
|
-
sync?: (self: MultiplayerStateManager<S>) => void;
|
|
136
|
+
options: MultiplayerStateManagerOptions<S, M> & {
|
|
137
|
+
sync?: (self: MultiplayerStateManager<S, M>) => void;
|
|
138
138
|
trackConnectionEvents?: boolean;
|
|
139
139
|
inspector?:
|
|
140
140
|
| boolean
|
|
141
141
|
| Pick<ComponentProps<typeof StateInspector>, "colorScheme" | "anchor">;
|
|
142
142
|
}
|
|
143
143
|
) {
|
|
144
|
-
const { sync = defaultStubSync as unknown as SyncAdapter<S>, ...rest } =
|
|
144
|
+
const { sync = defaultStubSync as unknown as SyncAdapter<S, M>, ...rest } =
|
|
145
145
|
options;
|
|
146
146
|
|
|
147
147
|
const [multiplayerStateManager] = useState(
|
|
148
|
-
() => new MultiplayerStateManager<S>(initialState, rest)
|
|
148
|
+
() => new MultiplayerStateManager<S, M>(initialState, rest)
|
|
149
149
|
);
|
|
150
150
|
|
|
151
151
|
const syncRef = useRef(sync);
|
|
@@ -230,7 +230,7 @@ export const StateInspector = memo(function StateInspector<
|
|
|
230
230
|
if (!historyContainerRef.current) return;
|
|
231
231
|
|
|
232
232
|
const historyEntry = historyContainerRef.current.querySelector(
|
|
233
|
-
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex
|
|
233
|
+
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
|
|
234
234
|
);
|
|
235
235
|
|
|
236
236
|
if (historyEntry) {
|
|
@@ -344,43 +344,41 @@ export const StateInspector = memo(function StateInspector<
|
|
|
344
344
|
flexDirection: "column",
|
|
345
345
|
}}
|
|
346
346
|
>
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
347
|
+
<div
|
|
348
|
+
id={`${HISTORY_ELEMENT_PREFIX}0`}
|
|
349
|
+
style={{
|
|
350
|
+
borderBottom: `1px solid ${solidBorderColor}`,
|
|
351
|
+
fontSize: "12px",
|
|
352
|
+
fontFamily: "Menlo, monospace",
|
|
353
|
+
padding: "2px 12px 1px",
|
|
354
|
+
display: "flex",
|
|
355
|
+
alignItems: "center",
|
|
356
|
+
background:
|
|
357
|
+
historySnapshot.historyIndex === 0
|
|
358
|
+
? "rgb(59 130 246 / 15%)"
|
|
359
|
+
: undefined,
|
|
360
|
+
}}
|
|
361
|
+
>
|
|
362
|
+
<span
|
|
350
363
|
style={{
|
|
351
|
-
borderBottom: `1px solid ${solidBorderColor}`,
|
|
352
|
-
fontSize: "12px",
|
|
353
364
|
fontFamily: "Menlo, monospace",
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
background:
|
|
358
|
-
historySnapshot.historyIndex === 0
|
|
359
|
-
? "rgb(59 130 246 / 15%)"
|
|
360
|
-
: undefined,
|
|
365
|
+
fontSize: "11px",
|
|
366
|
+
borderRadius: 4,
|
|
367
|
+
display: "inline-block",
|
|
361
368
|
}}
|
|
362
369
|
>
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
borderRadius: 4,
|
|
368
|
-
display: "inline-block",
|
|
369
|
-
}}
|
|
370
|
-
>
|
|
371
|
-
Initial state
|
|
372
|
-
</span>
|
|
373
|
-
</div>
|
|
374
|
-
)}
|
|
375
|
-
{historySnapshot.history.slice(-50).map((entry, index) => (
|
|
370
|
+
Initial state
|
|
371
|
+
</span>
|
|
372
|
+
</div>
|
|
373
|
+
{historySnapshot.history.map((entry, index) => (
|
|
376
374
|
<div
|
|
377
|
-
id={
|
|
375
|
+
id={`${HISTORY_ELEMENT_PREFIX}${index + 1}`}
|
|
378
376
|
key={index}
|
|
379
377
|
style={{
|
|
380
378
|
padding: "0px 12px 1px",
|
|
381
379
|
borderBottom: `1px solid ${solidBorderColor}`,
|
|
382
380
|
background:
|
|
383
|
-
index === historySnapshot.historyIndex
|
|
381
|
+
index + 1 === historySnapshot.historyIndex
|
|
384
382
|
? "rgb(59 130 246 / 15%)"
|
|
385
383
|
: undefined,
|
|
386
384
|
}}
|