@noya-app/noya-multiplayer-react 0.1.40 → 0.1.41
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 +14 -13
- package/CHANGELOG.md +6 -0
- package/dist/index.bundle.js +7 -7
- package/dist/index.d.mts +206 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +14 -28
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +14 -28
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import * as _noya_app_state_manager from '@noya-app/state-manager';
|
|
2
|
+
import { MultiplayerUser, EphemeralUserData, ConnectionEvent, Task, MultiplayerStateManager, AssetManager, StateManager, StateManagerOptions, MultiplayerStateManagerOptions, SyncAdapterOptions, TSchema, Static } from '@noya-app/state-manager';
|
|
3
|
+
export * from '@noya-app/state-manager';
|
|
4
|
+
import React, { ComponentPropsWithoutRef, SetStateAction } from 'react';
|
|
5
|
+
import { GetAtPath, ObservableOptions, PathKey, Observable } from '@noya-app/observable';
|
|
6
|
+
|
|
7
|
+
declare function getAvatarInitials(name: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Create a background color and initials from a name
|
|
10
|
+
*
|
|
11
|
+
* Adapted from https://mui.com/material-ui/react-avatar/
|
|
12
|
+
*/
|
|
13
|
+
declare function getAvatarStyle(name: string): {
|
|
14
|
+
color: string;
|
|
15
|
+
backgroundColor: string;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type Point = {
|
|
19
|
+
x: number;
|
|
20
|
+
y: number;
|
|
21
|
+
};
|
|
22
|
+
type UserPointerData = {
|
|
23
|
+
pointer?: Point;
|
|
24
|
+
};
|
|
25
|
+
type UserPointerProps<E extends UserPointerData> = {
|
|
26
|
+
user: MultiplayerUser;
|
|
27
|
+
ephemeralUserData: EphemeralUserData<E>;
|
|
28
|
+
hideAfter?: number;
|
|
29
|
+
};
|
|
30
|
+
declare const UserPointer_: <E extends UserPointerData>({ user, ephemeralUserData, hideAfter, }: UserPointerProps<E>) => React.JSX.Element | null;
|
|
31
|
+
declare const UserPointer: typeof UserPointer_;
|
|
32
|
+
declare const UserPointerContainer: React.NamedExoticComponent<{
|
|
33
|
+
point: Point;
|
|
34
|
+
children: React.ReactNode;
|
|
35
|
+
show?: boolean;
|
|
36
|
+
}>;
|
|
37
|
+
declare const UserNameTag: React.NamedExoticComponent<{
|
|
38
|
+
background: string;
|
|
39
|
+
children: React.ReactNode;
|
|
40
|
+
}>;
|
|
41
|
+
type UserPointersOverlayProps<E extends UserPointerData> = {
|
|
42
|
+
connectedUsers: MultiplayerUser[];
|
|
43
|
+
ephemeralUserData: EphemeralUserData<E>;
|
|
44
|
+
};
|
|
45
|
+
declare const UserPointersOverlay: React.MemoExoticComponent<(<E extends UserPointerData>({ connectedUsers, ephemeralUserData }: UserPointersOverlayProps<E>) => React.JSX.Element)>;
|
|
46
|
+
declare const UserPointerIcon: React.NamedExoticComponent<{
|
|
47
|
+
color?: string;
|
|
48
|
+
}>;
|
|
49
|
+
|
|
50
|
+
type StateInspectorAnchor = "left" | "right" | "bottom left" | "bottom right";
|
|
51
|
+
type StateInspectorOptions = {
|
|
52
|
+
colorScheme?: "light" | "dark";
|
|
53
|
+
anchor?: StateInspectorAnchor;
|
|
54
|
+
};
|
|
55
|
+
declare const StateInspector: React.MemoExoticComponent<(<S, M, E>({ state, connectionEvents, connectedUsers, tasks, userId, unstyled, colorScheme, multiplayerStateManager, assetManager, ephemeralUserData, anchor, forceInit, ...props }: {
|
|
56
|
+
state: S;
|
|
57
|
+
connectionEvents?: ConnectionEvent<S>[];
|
|
58
|
+
connectedUsers?: MultiplayerUser[];
|
|
59
|
+
tasks?: Task[];
|
|
60
|
+
userId?: string;
|
|
61
|
+
unstyled?: boolean;
|
|
62
|
+
multiplayerStateManager: MultiplayerStateManager<S, M>;
|
|
63
|
+
assetManager: AssetManager;
|
|
64
|
+
ephemeralUserData: EphemeralUserData<E>;
|
|
65
|
+
forceInit: () => void;
|
|
66
|
+
} & StateInspectorOptions & ComponentPropsWithoutRef<"div">) => React.JSX.Element | null)>;
|
|
67
|
+
|
|
68
|
+
declare function useSyncStateManager<S, M>(stateManager: StateManager<S, M>): S;
|
|
69
|
+
declare function useSyncStateManager<S, M, P extends string>(stateManager: StateManager<S, M>, path: P): GetAtPath<S, P>;
|
|
70
|
+
declare function useManagedState<S, 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>];
|
|
71
|
+
declare function useManagedHistory<S, M = void>(stateManager: StateManager<S, M>): _noya_app_state_manager.HistorySnapshot<S, M>;
|
|
72
|
+
declare function useSyncMultiplayerStateManager<S, M = void>(multiplayerStateManager: MultiplayerStateManager<S, M>): S;
|
|
73
|
+
declare function useEphemeralUserData<E>(ephemeralUserData: EphemeralUserData<E>, options?: {
|
|
74
|
+
throttle?: number;
|
|
75
|
+
}): {
|
|
76
|
+
data: Record<string, E | undefined>;
|
|
77
|
+
metadata: Record<string, _noya_app_state_manager.EphemeralUserMetadata | undefined>;
|
|
78
|
+
currentUserId: string | undefined;
|
|
79
|
+
};
|
|
80
|
+
type UseMultiplayerStateOptions<S, M = void, E = void> = MultiplayerStateManagerOptions<S, M> & {
|
|
81
|
+
sync?: (options: Pick<SyncAdapterOptions<S, M, E>, "ms" | "ephemeralUserData" | "assetManager">) => void;
|
|
82
|
+
trackConnectionEvents?: boolean;
|
|
83
|
+
trackTasks?: boolean;
|
|
84
|
+
inspector?: boolean | StateInspectorOptions;
|
|
85
|
+
};
|
|
86
|
+
declare function useMultiplayerState<S, M = void, E = void>(initialState: S | (() => S), options?: UseMultiplayerStateOptions<S, M, E>): readonly [S, (...args: M extends {} ? [metadata: M, action: S | ((prevState: S) => S)] : [action: S | ((prevState: S) => S)]) => void, {
|
|
87
|
+
tasks: Task[];
|
|
88
|
+
userId: string | undefined;
|
|
89
|
+
connectionEvents: ConnectionEvent<S>[] | undefined;
|
|
90
|
+
connectedUsers: MultiplayerUser[];
|
|
91
|
+
ephemeralUserData: EphemeralUserData<E>;
|
|
92
|
+
multiplayerStateManager: MultiplayerStateManager<S, M>;
|
|
93
|
+
assets: _noya_app_state_manager.Asset[];
|
|
94
|
+
assetManager: AssetManager;
|
|
95
|
+
createAsset: (options: _noya_app_state_manager.CreateAssetOptions | Uint8Array | File | Blob) => Promise<_noya_app_state_manager.Asset>;
|
|
96
|
+
deleteAsset: (id: string) => Promise<void>;
|
|
97
|
+
}];
|
|
98
|
+
|
|
99
|
+
type AppViewType = "editable" | "readOnly" | "preview";
|
|
100
|
+
type AppTheme = "light" | "dark";
|
|
101
|
+
type AppData<State> = {
|
|
102
|
+
multiplayerUrl?: string;
|
|
103
|
+
theme: AppTheme;
|
|
104
|
+
viewType: AppViewType;
|
|
105
|
+
initialState: State;
|
|
106
|
+
inspector: boolean | StateInspectorOptions;
|
|
107
|
+
};
|
|
108
|
+
declare function createDefaultAppData<State>(initialState: State): AppData<State>;
|
|
109
|
+
type GetAppDataOptions = {
|
|
110
|
+
window?: {
|
|
111
|
+
location: {
|
|
112
|
+
hash: string;
|
|
113
|
+
};
|
|
114
|
+
};
|
|
115
|
+
overrideExistingState?: boolean;
|
|
116
|
+
};
|
|
117
|
+
declare function enforceSchema<State>(initialState: State, schema?: TSchema): State;
|
|
118
|
+
declare function parseAppDataParameter(options?: GetAppDataOptions): AppData<unknown> | null;
|
|
119
|
+
declare function getAppData<State>(initialState: State | (() => State), schema?: TSchema, options?: GetAppDataOptions): AppData<State>;
|
|
120
|
+
type IframeToHostMessage = {
|
|
121
|
+
type: "application.setMenuItems";
|
|
122
|
+
payload: {
|
|
123
|
+
menuItems: any[];
|
|
124
|
+
};
|
|
125
|
+
} | {
|
|
126
|
+
type: "multiplayer.setUsers";
|
|
127
|
+
payload: {
|
|
128
|
+
users: any[];
|
|
129
|
+
};
|
|
130
|
+
};
|
|
131
|
+
type HostToIframeMessage = {
|
|
132
|
+
type: "application.selectMenuItem";
|
|
133
|
+
payload: {
|
|
134
|
+
value: string;
|
|
135
|
+
};
|
|
136
|
+
};
|
|
137
|
+
declare function useBroadcastConnectedUsers(connectedUsers: MultiplayerUser[]): void;
|
|
138
|
+
declare function useBroadcastMenuItems<T>(menuItems: any[], handleSelectMenuItem: (value: T) => void): void;
|
|
139
|
+
declare function isEmbeddedApp(): boolean;
|
|
140
|
+
type UseNoyaStateOptions<S, M = void, E = void> = UseMultiplayerStateOptions<S, M, E> & {
|
|
141
|
+
offlineStorageKey?: string;
|
|
142
|
+
};
|
|
143
|
+
type UseNoyaStateResult<S, M = void, E = void> = [
|
|
144
|
+
ReturnType<typeof useMultiplayerState<S, M, E>>[0],
|
|
145
|
+
ReturnType<typeof useMultiplayerState<S, M, E>>[1],
|
|
146
|
+
ReturnType<typeof useMultiplayerState<S, M, E>>[2] & {
|
|
147
|
+
theme: AppTheme;
|
|
148
|
+
viewType: AppViewType;
|
|
149
|
+
}
|
|
150
|
+
];
|
|
151
|
+
/**
|
|
152
|
+
* Sync data locally or to a multiplayer server.
|
|
153
|
+
*
|
|
154
|
+
* There are 3 ways to use this hook:
|
|
155
|
+
*
|
|
156
|
+
* 1. Pass an initial state: `useNoyaState(initialState)`
|
|
157
|
+
* 2. Pass an initial state and a schema: `useNoyaState(initialState, { schema })`
|
|
158
|
+
* 3. Pass only a schema, and a conforming initial state is created automatically: `useNoyaState({ schema })`
|
|
159
|
+
*/
|
|
160
|
+
declare function useNoyaState<S, M = void, E = void, O extends UseNoyaStateOptions<S, M, E> = UseNoyaStateOptions<S, M, E>>(...args: [
|
|
161
|
+
initialState: O["schema"] extends TSchema ? Static<O["schema"]> | (() => Static<O["schema"]>) : S | (() => S),
|
|
162
|
+
options?: O
|
|
163
|
+
] | [options: O & {
|
|
164
|
+
schema: TSchema;
|
|
165
|
+
}]): UseNoyaStateResult<O["schema"] extends TSchema ? Static<O["schema"]> : S, M, E>;
|
|
166
|
+
|
|
167
|
+
interface NoyaStateProviderProps<S, M, E> extends Omit<UseNoyaStateOptions<S, M, E>, "schema" | "mergeHistoryEntries"> {
|
|
168
|
+
children: React.ReactNode;
|
|
169
|
+
initialState?: S;
|
|
170
|
+
}
|
|
171
|
+
declare function useAssets(): _noya_app_state_manager.Asset[];
|
|
172
|
+
declare function useAsset(id: string | undefined): _noya_app_state_manager.Asset | undefined;
|
|
173
|
+
declare function useAssetManager(): {
|
|
174
|
+
create: (options: _noya_app_state_manager.CreateAssetOptions | Uint8Array | File | Blob) => Promise<_noya_app_state_manager.Asset>;
|
|
175
|
+
delete: (id: string) => Promise<void>;
|
|
176
|
+
};
|
|
177
|
+
declare function createNoyaContext<Schema extends TSchema, M = void, E = void>({ schema, mergeHistoryEntries, }: {
|
|
178
|
+
schema: Schema;
|
|
179
|
+
mergeHistoryEntries?: StateManagerOptions<Static<Schema>, M>["mergeHistoryEntries"];
|
|
180
|
+
}): {
|
|
181
|
+
Context: React.Context<{
|
|
182
|
+
ms: MultiplayerStateManager<Static<Schema>, M>;
|
|
183
|
+
assetManager: AssetManager;
|
|
184
|
+
} | undefined>;
|
|
185
|
+
Provider: ({ children, initialState, ...options }: NoyaStateProviderProps<Static<Schema>, M, E>) => React.JSX.Element;
|
|
186
|
+
useValue: {
|
|
187
|
+
(): Static<Schema>;
|
|
188
|
+
<A>(selector: (value: Static<Schema>) => A, options?: Pick<ObservableOptions, "isEqual">): A;
|
|
189
|
+
<P extends PathKey[] | string>(path: P): GetAtPath<Static<Schema>, P>;
|
|
190
|
+
};
|
|
191
|
+
useSetValue: {
|
|
192
|
+
(): M extends {} ? (metadata: M, value: SetStateAction<Static<Schema>>) => void : (value: SetStateAction<Static<Schema>>) => void;
|
|
193
|
+
<P extends PathKey[] | string>(path: P): M extends {} ? (metadata: M, value: SetStateAction<GetAtPath<Static<Schema>, P>>) => void : (value: SetStateAction<GetAtPath<Static<Schema>, P>>) => void;
|
|
194
|
+
};
|
|
195
|
+
useValueState: {
|
|
196
|
+
(): [Static<Schema>, M extends {} ? (metadata: M, value: SetStateAction<Static<Schema>>) => void : (value: SetStateAction<Static<Schema>>) => void];
|
|
197
|
+
<A>(selector: (value: Static<Schema>) => A, options?: ObservableOptions): [A, M extends {} ? (metadata: M, value: SetStateAction<Static<Schema>>) => void : (value: SetStateAction<Static<Schema>>) => void];
|
|
198
|
+
<P extends PathKey[] | string>(path?: P): [GetAtPath<Static<Schema>, P>, M extends {} ? (metadata: M, value: SetStateAction<GetAtPath<Static<Schema>, P>>) => void : (value: SetStateAction<GetAtPath<Static<Schema>, P>>) => void];
|
|
199
|
+
};
|
|
200
|
+
useStateManager: () => MultiplayerStateManager<Static<Schema>, M>;
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
declare function useObservable<T>(observable: Observable<T>): T;
|
|
204
|
+
declare function useObservable<T, P extends PathKey[] | string>(observable: Observable<T>, path: P): GetAtPath<T, P>;
|
|
205
|
+
|
|
206
|
+
export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaStateOptions, type UseNoyaStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, createNoyaContext, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useAsset, useAssetManager, useAssets, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
|
package/dist/index.d.ts
CHANGED
|
@@ -203,4 +203,4 @@ declare function createNoyaContext<Schema extends TSchema, M = void, E = void>({
|
|
|
203
203
|
declare function useObservable<T>(observable: Observable<T>): T;
|
|
204
204
|
declare function useObservable<T, P extends PathKey[] | string>(observable: Observable<T>, path: P): GetAtPath<T, P>;
|
|
205
205
|
|
|
206
|
-
export { AppData, AppTheme, AppViewType, GetAppDataOptions, HostToIframeMessage, IframeToHostMessage, StateInspector, StateInspectorAnchor, StateInspectorOptions, UseMultiplayerStateOptions, UseNoyaStateOptions, UseNoyaStateResult, UserNameTag, UserPointer, UserPointerContainer, UserPointerData, UserPointerIcon, UserPointerProps, UserPointersOverlay, UserPointersOverlayProps, createDefaultAppData, createNoyaContext, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useAsset, useAssetManager, useAssets, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
|
|
206
|
+
export { type AppData, type AppTheme, type AppViewType, type GetAppDataOptions, type HostToIframeMessage, type IframeToHostMessage, StateInspector, type StateInspectorAnchor, type StateInspectorOptions, type UseMultiplayerStateOptions, type UseNoyaStateOptions, type UseNoyaStateResult, UserNameTag, UserPointer, UserPointerContainer, type UserPointerData, UserPointerIcon, type UserPointerProps, UserPointersOverlay, type UserPointersOverlayProps, createDefaultAppData, createNoyaContext, enforceSchema, getAppData, getAvatarInitials, getAvatarStyle, isEmbeddedApp, parseAppDataParameter, useAsset, useAssetManager, useAssets, useBroadcastConnectedUsers, useBroadcastMenuItems, useEphemeralUserData, useManagedHistory, useManagedState, useMultiplayerState, useNoyaState, useObservable, useSyncMultiplayerStateManager, useSyncStateManager };
|
package/dist/index.js
CHANGED
|
@@ -139,16 +139,14 @@ var UserPointer_ = function UserPointer({
|
|
|
139
139
|
const [, setForceUpdate] = (0, import_react2.useState)(0);
|
|
140
140
|
const updatedAt = metadata?.updatedAt ?? 0;
|
|
141
141
|
(0, import_react2.useEffect)(() => {
|
|
142
|
-
if (!shouldShow(hideAfter, updatedAt))
|
|
143
|
-
return;
|
|
142
|
+
if (!shouldShow(hideAfter, updatedAt)) return;
|
|
144
143
|
const timeoutId = setTimeout(() => {
|
|
145
144
|
setForceUpdate((prev) => prev + 1);
|
|
146
145
|
}, hideAfter);
|
|
147
146
|
return () => clearTimeout(timeoutId);
|
|
148
147
|
}, [hideAfter, updatedAt]);
|
|
149
148
|
const show = shouldShow(hideAfter, updatedAt);
|
|
150
|
-
if (!data || !data.pointer)
|
|
151
|
-
return null;
|
|
149
|
+
if (!data || !data.pointer) return null;
|
|
152
150
|
return /* @__PURE__ */ import_react2.default.createElement(UserPointerContainer, { key: user.id, point: data.pointer, show }, /* @__PURE__ */ import_react2.default.createElement(UserPointerIcon, { color: avatarStyle.backgroundColor }), /* @__PURE__ */ import_react2.default.createElement(UserNameTag, { background: avatarStyle.backgroundColor }, user.name));
|
|
153
151
|
};
|
|
154
152
|
var UserPointer2 = (0, import_react2.memo)(UserPointer_);
|
|
@@ -204,8 +202,7 @@ var UserNameTag = (0, import_react2.memo)(function UserNameTag2({
|
|
|
204
202
|
var UserPointersOverlay = (0, import_react2.memo)(function UserPointers({ connectedUsers, ephemeralUserData }) {
|
|
205
203
|
const currentUserId = useObservable(ephemeralUserData.currentUserId$);
|
|
206
204
|
return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, connectedUsers.map((user) => {
|
|
207
|
-
if (user.id === currentUserId)
|
|
208
|
-
return null;
|
|
205
|
+
if (user.id === currentUserId) return null;
|
|
209
206
|
return /* @__PURE__ */ import_react2.default.createElement(
|
|
210
207
|
UserPointer2,
|
|
211
208
|
{
|
|
@@ -622,8 +619,7 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
|
|
|
622
619
|
}
|
|
623
620
|
}, [historySnapshot]);
|
|
624
621
|
(0, import_react5.useEffect)(() => {
|
|
625
|
-
if (!historyContainerRef.current)
|
|
626
|
-
return;
|
|
622
|
+
if (!historyContainerRef.current) return;
|
|
627
623
|
const historyEntry = historyContainerRef.current.querySelector(
|
|
628
624
|
`#${HISTORY_ELEMENT_PREFIX}${historySnapshot.historyIndex}`
|
|
629
625
|
);
|
|
@@ -655,8 +651,7 @@ var StateInspector = (0, import_react5.memo)(function StateInspector2({
|
|
|
655
651
|
zIndex: 9999,
|
|
656
652
|
lineHeight: "13px"
|
|
657
653
|
};
|
|
658
|
-
if (!didMount)
|
|
659
|
-
return null;
|
|
654
|
+
if (!didMount) return null;
|
|
660
655
|
if (!showInspector) {
|
|
661
656
|
return /* @__PURE__ */ import_react5.default.createElement(
|
|
662
657
|
"div",
|
|
@@ -1134,8 +1129,7 @@ function pathToString(extendedPath) {
|
|
|
1134
1129
|
).join("");
|
|
1135
1130
|
}
|
|
1136
1131
|
function ellipsis(str, maxLength, position = "end") {
|
|
1137
|
-
if (str.length <= maxLength)
|
|
1138
|
-
return str;
|
|
1132
|
+
if (str.length <= maxLength) return str;
|
|
1139
1133
|
switch (position) {
|
|
1140
1134
|
case "start":
|
|
1141
1135
|
return `\u2026${str.slice(str.length - maxLength)}`;
|
|
@@ -1208,8 +1202,7 @@ function useStateInspector({
|
|
|
1208
1202
|
}) {
|
|
1209
1203
|
const [root, setRoot] = import_react6.default.useState(null);
|
|
1210
1204
|
(0, import_react6.useLayoutEffect)(() => {
|
|
1211
|
-
if (disabled)
|
|
1212
|
-
return;
|
|
1205
|
+
if (disabled) return;
|
|
1213
1206
|
const { host, container } = createShadowRootElement();
|
|
1214
1207
|
const root2 = (0, import_client.createRoot)(container);
|
|
1215
1208
|
document.body.appendChild(host);
|
|
@@ -1219,8 +1212,7 @@ function useStateInspector({
|
|
|
1219
1212
|
};
|
|
1220
1213
|
}, [disabled]);
|
|
1221
1214
|
(0, import_react6.useLayoutEffect)(() => {
|
|
1222
|
-
if (!root)
|
|
1223
|
-
return;
|
|
1215
|
+
if (!root) return;
|
|
1224
1216
|
root.render(
|
|
1225
1217
|
/* @__PURE__ */ import_react6.default.createElement(
|
|
1226
1218
|
StateInspector,
|
|
@@ -1327,8 +1319,7 @@ function throttle(fn, ms) {
|
|
|
1327
1319
|
return (...args) => {
|
|
1328
1320
|
const now = Date.now();
|
|
1329
1321
|
if (now - lastCall < ms) {
|
|
1330
|
-
if (timeoutId)
|
|
1331
|
-
clearTimeout(timeoutId);
|
|
1322
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
1332
1323
|
timeoutId = setTimeout(
|
|
1333
1324
|
() => {
|
|
1334
1325
|
lastCall = now;
|
|
@@ -1467,8 +1458,7 @@ function useMultiplayerState(initialState, options) {
|
|
|
1467
1458
|
});
|
|
1468
1459
|
}, [multiplayerStateManager]);
|
|
1469
1460
|
(0, import_react7.useEffect)(() => {
|
|
1470
|
-
if (!unrecoverableError)
|
|
1471
|
-
return;
|
|
1461
|
+
if (!unrecoverableError) return;
|
|
1472
1462
|
const el = document.createElement("div");
|
|
1473
1463
|
el.id = "noya-multiplayer-react-error-overlay";
|
|
1474
1464
|
document.body.appendChild(el);
|
|
@@ -1516,13 +1506,11 @@ function enforceSchema(initialState, schema) {
|
|
|
1516
1506
|
function parseAppDataParameter(options) {
|
|
1517
1507
|
const window2 = options?.window ?? globalThis;
|
|
1518
1508
|
const location = window2.location;
|
|
1519
|
-
if (!location)
|
|
1520
|
-
return null;
|
|
1509
|
+
if (!location) return null;
|
|
1521
1510
|
const urlHash = (location.hash || "").replace(/^#/, "");
|
|
1522
1511
|
const params = new URLSearchParams(urlHash);
|
|
1523
1512
|
const data = params.get("data");
|
|
1524
|
-
if (!data)
|
|
1525
|
-
return null;
|
|
1513
|
+
if (!data) return null;
|
|
1526
1514
|
try {
|
|
1527
1515
|
return JSON.parse(data);
|
|
1528
1516
|
} catch (e) {
|
|
@@ -1540,8 +1528,7 @@ function getAppData(initialState, schema, options) {
|
|
|
1540
1528
|
}
|
|
1541
1529
|
function useBroadcastConnectedUsers(connectedUsers) {
|
|
1542
1530
|
(0, import_react8.useEffect)(() => {
|
|
1543
|
-
if (!isEmbeddedApp())
|
|
1544
|
-
return;
|
|
1531
|
+
if (!isEmbeddedApp()) return;
|
|
1545
1532
|
const message = {
|
|
1546
1533
|
type: "multiplayer.setUsers",
|
|
1547
1534
|
payload: { users: connectedUsers }
|
|
@@ -1551,8 +1538,7 @@ function useBroadcastConnectedUsers(connectedUsers) {
|
|
|
1551
1538
|
}
|
|
1552
1539
|
function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
|
|
1553
1540
|
(0, import_react8.useEffect)(() => {
|
|
1554
|
-
if (!isEmbeddedApp())
|
|
1555
|
-
return;
|
|
1541
|
+
if (!isEmbeddedApp()) return;
|
|
1556
1542
|
const message = {
|
|
1557
1543
|
type: "application.setMenuItems",
|
|
1558
1544
|
payload: { menuItems }
|