@noya-app/noya-multiplayer-react 0.1.22 → 0.1.23
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 +9 -0
- package/dist/index.d.mts +59 -46
- package/dist/index.d.ts +59 -46
- package/dist/index.js +229 -188
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +138 -94
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/hooks.ts +26 -23
- package/src/index.ts +1 -1
- package/src/inspector/StateInspector.tsx +25 -5
- package/src/{embedded.ts → noyaApp.ts} +58 -7
package/dist/index.mjs
CHANGED
|
@@ -193,77 +193,6 @@ var UserPointerIcon = memo(function CursorIcon({
|
|
|
193
193
|
);
|
|
194
194
|
});
|
|
195
195
|
|
|
196
|
-
// src/embedded.ts
|
|
197
|
-
import { createValue } from "@noya-app/state-manager";
|
|
198
|
-
import { useEffect as useEffect2, useMemo as useMemo3 } from "react";
|
|
199
|
-
function createDefaultAppData(initialState) {
|
|
200
|
-
return {
|
|
201
|
-
theme: "light",
|
|
202
|
-
viewType: "editable",
|
|
203
|
-
initialState,
|
|
204
|
-
inspector: false
|
|
205
|
-
};
|
|
206
|
-
}
|
|
207
|
-
function getAppData(initialState) {
|
|
208
|
-
try {
|
|
209
|
-
const urlHash = (window.location.hash || "").replace(/^#/, "");
|
|
210
|
-
const params = new URLSearchParams(urlHash);
|
|
211
|
-
const data = params.get("data");
|
|
212
|
-
if (!data) {
|
|
213
|
-
return initialState ? createDefaultAppData(initialState) : void 0;
|
|
214
|
-
}
|
|
215
|
-
const parsed = JSON.parse(data);
|
|
216
|
-
if (!parsed.initialState) {
|
|
217
|
-
parsed.initialState = initialState;
|
|
218
|
-
}
|
|
219
|
-
return parsed;
|
|
220
|
-
} catch (e) {
|
|
221
|
-
return initialState ? createDefaultAppData(initialState) : void 0;
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
function useNoyaApp(initialState, { schema } = {}) {
|
|
225
|
-
const appData = useMemo3(() => {
|
|
226
|
-
return getAppData(
|
|
227
|
-
schema ? createValue(schema, initialState) : initialState
|
|
228
|
-
);
|
|
229
|
-
}, [initialState, schema]);
|
|
230
|
-
return appData;
|
|
231
|
-
}
|
|
232
|
-
function useBroadcastConnectedUsers(connectedUsers) {
|
|
233
|
-
useEffect2(() => {
|
|
234
|
-
if (!isEmbeddedApp())
|
|
235
|
-
return;
|
|
236
|
-
const message = {
|
|
237
|
-
type: "multiplayer.setUsers",
|
|
238
|
-
payload: { users: connectedUsers }
|
|
239
|
-
};
|
|
240
|
-
parent?.postMessage(message, "*");
|
|
241
|
-
}, [connectedUsers]);
|
|
242
|
-
}
|
|
243
|
-
function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
|
|
244
|
-
useEffect2(() => {
|
|
245
|
-
if (!isEmbeddedApp())
|
|
246
|
-
return;
|
|
247
|
-
const message = {
|
|
248
|
-
type: "application.setMenuItems",
|
|
249
|
-
payload: { menuItems }
|
|
250
|
-
};
|
|
251
|
-
parent?.postMessage(message, "*");
|
|
252
|
-
const listener = (event) => {
|
|
253
|
-
if (event.data.type === "application.selectMenuItem") {
|
|
254
|
-
handleSelectMenuItem(event.data.payload.value);
|
|
255
|
-
}
|
|
256
|
-
};
|
|
257
|
-
window.addEventListener("message", listener);
|
|
258
|
-
return () => {
|
|
259
|
-
window.removeEventListener("message", listener);
|
|
260
|
-
};
|
|
261
|
-
}, [handleSelectMenuItem, menuItems]);
|
|
262
|
-
}
|
|
263
|
-
function isEmbeddedApp() {
|
|
264
|
-
return window.self !== window.top;
|
|
265
|
-
}
|
|
266
|
-
|
|
267
196
|
// src/hooks.ts
|
|
268
197
|
import {
|
|
269
198
|
EphemeralUserData,
|
|
@@ -273,8 +202,8 @@ import {
|
|
|
273
202
|
} from "@noya-app/state-manager";
|
|
274
203
|
import {
|
|
275
204
|
useCallback,
|
|
276
|
-
useEffect as
|
|
277
|
-
useMemo as
|
|
205
|
+
useEffect as useEffect3,
|
|
206
|
+
useMemo as useMemo3,
|
|
278
207
|
useRef,
|
|
279
208
|
useState as useState2,
|
|
280
209
|
useSyncExternalStore as useSyncExternalStore2
|
|
@@ -292,7 +221,7 @@ import { createRoot } from "react-dom/client";
|
|
|
292
221
|
// src/inspector/StateInspector.tsx
|
|
293
222
|
import React3, {
|
|
294
223
|
memo as memo2,
|
|
295
|
-
useEffect as
|
|
224
|
+
useEffect as useEffect2,
|
|
296
225
|
useLayoutEffect
|
|
297
226
|
} from "react";
|
|
298
227
|
import {
|
|
@@ -555,25 +484,25 @@ var StateInspector = memo2(function StateInspector2({
|
|
|
555
484
|
"noya-multiplayer-react-show-ephemeral",
|
|
556
485
|
false
|
|
557
486
|
);
|
|
558
|
-
|
|
487
|
+
useEffect2(() => {
|
|
559
488
|
shouldTrackEvents$.set(showEvents);
|
|
560
489
|
}, [showEvents]);
|
|
561
|
-
|
|
490
|
+
useEffect2(() => {
|
|
562
491
|
shouldTrackTasks$.set(showTasks);
|
|
563
492
|
}, [showTasks]);
|
|
564
|
-
|
|
493
|
+
useEffect2(() => {
|
|
565
494
|
if (eventsContainerRef.current) {
|
|
566
495
|
eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
|
|
567
496
|
}
|
|
568
497
|
}, [connectionEvents]);
|
|
569
498
|
const ephemeral = useEphemeralUserData(ephemeralUserData);
|
|
570
499
|
const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
|
|
571
|
-
|
|
500
|
+
useEffect2(() => {
|
|
572
501
|
if (historyContainerRef.current) {
|
|
573
502
|
historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
|
|
574
503
|
}
|
|
575
504
|
}, [historySnapshot]);
|
|
576
|
-
|
|
505
|
+
useEffect2(() => {
|
|
577
506
|
if (!historyContainerRef.current)
|
|
578
507
|
return;
|
|
579
508
|
const historyEntry = historyContainerRef.current.querySelector(
|
|
@@ -855,6 +784,17 @@ var StateInspector = memo2(function StateInspector2({
|
|
|
855
784
|
background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
|
|
856
785
|
}
|
|
857
786
|
},
|
|
787
|
+
"name" in entry.metadata && typeof entry.metadata.name === "string" && /* @__PURE__ */ React3.createElement(
|
|
788
|
+
"pre",
|
|
789
|
+
{
|
|
790
|
+
style: {
|
|
791
|
+
fontSize: "11px",
|
|
792
|
+
display: "flex",
|
|
793
|
+
flexWrap: "wrap"
|
|
794
|
+
}
|
|
795
|
+
},
|
|
796
|
+
entry.metadata.name
|
|
797
|
+
),
|
|
858
798
|
entry.redoPatches?.map((patch, j) => /* @__PURE__ */ React3.createElement(
|
|
859
799
|
"pre",
|
|
860
800
|
{
|
|
@@ -1237,13 +1177,14 @@ function useMultiplayerState(initialState, options) {
|
|
|
1237
1177
|
);
|
|
1238
1178
|
const [tasks, setTasks] = useState2([]);
|
|
1239
1179
|
const [userId, setUserId] = useState2();
|
|
1240
|
-
const extras =
|
|
1180
|
+
const extras = useMemo3(() => {
|
|
1241
1181
|
return {
|
|
1242
1182
|
tasks,
|
|
1243
1183
|
userId,
|
|
1244
1184
|
connectionEvents,
|
|
1245
1185
|
connectedUsers,
|
|
1246
|
-
ephemeralUserData
|
|
1186
|
+
ephemeralUserData,
|
|
1187
|
+
multiplayerStateManager
|
|
1247
1188
|
// evaluate: async (code: string) => {
|
|
1248
1189
|
// const payload = await rpcManager.request({ type: "eval", code });
|
|
1249
1190
|
// if (payload.type !== "eval") {
|
|
@@ -1251,7 +1192,14 @@ function useMultiplayerState(initialState, options) {
|
|
|
1251
1192
|
// }
|
|
1252
1193
|
// },
|
|
1253
1194
|
};
|
|
1254
|
-
}, [
|
|
1195
|
+
}, [
|
|
1196
|
+
tasks,
|
|
1197
|
+
userId,
|
|
1198
|
+
connectionEvents,
|
|
1199
|
+
connectedUsers,
|
|
1200
|
+
ephemeralUserData,
|
|
1201
|
+
multiplayerStateManager
|
|
1202
|
+
]);
|
|
1255
1203
|
const globalTrackEvents = useObservable(shouldTrackEvents$);
|
|
1256
1204
|
const globalTrackTasks = useObservable(shouldTrackTasks$);
|
|
1257
1205
|
const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
|
|
@@ -1259,19 +1207,19 @@ function useMultiplayerState(initialState, options) {
|
|
|
1259
1207
|
const trackEventsCallbackRef = useRef();
|
|
1260
1208
|
const trackConnectedUsersCallbackRef = useRef();
|
|
1261
1209
|
const trackTasksCallbackRef = useRef();
|
|
1262
|
-
|
|
1210
|
+
useEffect3(() => {
|
|
1263
1211
|
trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
|
|
1264
1212
|
const updated = events ? [...events, e] : [e];
|
|
1265
1213
|
return updated.length > 50 ? updated.slice(-50) : updated;
|
|
1266
1214
|
}) : void 0;
|
|
1267
1215
|
}, [shouldTrackEvents]);
|
|
1268
|
-
|
|
1216
|
+
useEffect3(() => {
|
|
1269
1217
|
trackConnectedUsersCallbackRef.current = (users, userId2) => {
|
|
1270
1218
|
setConnectedUsers(users);
|
|
1271
1219
|
setUserId(userId2);
|
|
1272
1220
|
};
|
|
1273
1221
|
}, []);
|
|
1274
|
-
|
|
1222
|
+
useEffect3(() => {
|
|
1275
1223
|
trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
|
|
1276
1224
|
setTasks((old) => {
|
|
1277
1225
|
const newIds = new Set(tasks2.map((t) => t.id));
|
|
@@ -1280,7 +1228,7 @@ function useMultiplayerState(initialState, options) {
|
|
|
1280
1228
|
});
|
|
1281
1229
|
} : void 0;
|
|
1282
1230
|
}, [shouldTrackTasks]);
|
|
1283
|
-
|
|
1231
|
+
useEffect3(() => {
|
|
1284
1232
|
if (syncRef.current) {
|
|
1285
1233
|
return syncRef.current({
|
|
1286
1234
|
ms: multiplayerStateManager,
|
|
@@ -1310,13 +1258,108 @@ function useMultiplayerState(initialState, options) {
|
|
|
1310
1258
|
disabled: !options?.inspector,
|
|
1311
1259
|
...typeof options?.inspector === "object" && options.inspector
|
|
1312
1260
|
});
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1261
|
+
return [state, multiplayerStateManager.setState, extras];
|
|
1262
|
+
}
|
|
1263
|
+
|
|
1264
|
+
// src/noyaApp.ts
|
|
1265
|
+
import {
|
|
1266
|
+
createValue,
|
|
1267
|
+
localStorageSync,
|
|
1268
|
+
webSocketSync
|
|
1269
|
+
} from "@noya-app/state-manager";
|
|
1270
|
+
import { useEffect as useEffect4, useMemo as useMemo4, useState as useState3 } from "react";
|
|
1271
|
+
function createDefaultAppData(initialState) {
|
|
1272
|
+
return {
|
|
1273
|
+
theme: "light",
|
|
1274
|
+
viewType: "editable",
|
|
1275
|
+
initialState,
|
|
1276
|
+
inspector: false
|
|
1277
|
+
};
|
|
1278
|
+
}
|
|
1279
|
+
function getAppData(initialState) {
|
|
1280
|
+
try {
|
|
1281
|
+
const urlHash = (window.location.hash || "").replace(/^#/, "");
|
|
1282
|
+
const params = new URLSearchParams(urlHash);
|
|
1283
|
+
const data = params.get("data");
|
|
1284
|
+
if (!data) {
|
|
1285
|
+
return initialState ? createDefaultAppData(initialState) : void 0;
|
|
1286
|
+
}
|
|
1287
|
+
const parsed = JSON.parse(data);
|
|
1288
|
+
if (!parsed.initialState) {
|
|
1289
|
+
parsed.initialState = initialState;
|
|
1290
|
+
}
|
|
1291
|
+
return parsed;
|
|
1292
|
+
} catch (e) {
|
|
1293
|
+
return initialState ? createDefaultAppData(initialState) : void 0;
|
|
1294
|
+
}
|
|
1295
|
+
}
|
|
1296
|
+
function useAppData(initialState, { schema } = {}) {
|
|
1297
|
+
const appData = useMemo4(() => {
|
|
1298
|
+
return getAppData(
|
|
1299
|
+
schema ? createValue(schema, initialState) : initialState
|
|
1300
|
+
);
|
|
1301
|
+
}, [initialState, schema]);
|
|
1302
|
+
return appData;
|
|
1303
|
+
}
|
|
1304
|
+
function useBroadcastConnectedUsers(connectedUsers) {
|
|
1305
|
+
useEffect4(() => {
|
|
1306
|
+
if (!isEmbeddedApp())
|
|
1307
|
+
return;
|
|
1308
|
+
const message = {
|
|
1309
|
+
type: "multiplayer.setUsers",
|
|
1310
|
+
payload: { users: connectedUsers }
|
|
1311
|
+
};
|
|
1312
|
+
parent?.postMessage(message, "*");
|
|
1313
|
+
}, [connectedUsers]);
|
|
1314
|
+
}
|
|
1315
|
+
function useBroadcastMenuItems(menuItems, handleSelectMenuItem) {
|
|
1316
|
+
useEffect4(() => {
|
|
1317
|
+
if (!isEmbeddedApp())
|
|
1318
|
+
return;
|
|
1319
|
+
const message = {
|
|
1320
|
+
type: "application.setMenuItems",
|
|
1321
|
+
payload: { menuItems }
|
|
1322
|
+
};
|
|
1323
|
+
parent?.postMessage(message, "*");
|
|
1324
|
+
const listener = (event) => {
|
|
1325
|
+
if (event.data.type === "application.selectMenuItem") {
|
|
1326
|
+
handleSelectMenuItem(event.data.payload.value);
|
|
1327
|
+
}
|
|
1328
|
+
};
|
|
1329
|
+
window.addEventListener("message", listener);
|
|
1330
|
+
return () => {
|
|
1331
|
+
window.removeEventListener("message", listener);
|
|
1332
|
+
};
|
|
1333
|
+
}, [handleSelectMenuItem, menuItems]);
|
|
1334
|
+
}
|
|
1335
|
+
function isEmbeddedApp() {
|
|
1336
|
+
return window.self !== window.top;
|
|
1337
|
+
}
|
|
1338
|
+
function useNoyaAppState(initialState, options) {
|
|
1339
|
+
const [state] = useState3(initialState);
|
|
1340
|
+
const {
|
|
1341
|
+
multiplayerUrl,
|
|
1342
|
+
inspector,
|
|
1343
|
+
initialState: noyaAppInitialState,
|
|
1344
|
+
theme,
|
|
1345
|
+
viewType
|
|
1346
|
+
} = useAppData(state, {
|
|
1347
|
+
schema: options.schema
|
|
1348
|
+
});
|
|
1349
|
+
const sync = useMemo4(() => {
|
|
1350
|
+
return multiplayerUrl ? webSocketSync(multiplayerUrl) : localStorageSync({ key: options.localStorageKey || "noya-app" });
|
|
1351
|
+
}, [multiplayerUrl, options.localStorageKey]);
|
|
1352
|
+
const result = useMultiplayerState(noyaAppInitialState, {
|
|
1353
|
+
...options,
|
|
1354
|
+
inspector: options.inspector ?? inspector,
|
|
1355
|
+
sync
|
|
1356
|
+
});
|
|
1357
|
+
const [, , extras] = result;
|
|
1358
|
+
useBroadcastConnectedUsers(extras.connectedUsers);
|
|
1359
|
+
const mergedExtras = useMemo4(() => {
|
|
1360
|
+
return { ...extras, theme, viewType };
|
|
1361
|
+
}, [extras, theme, viewType]);
|
|
1362
|
+
return [result[0], result[1], mergedExtras];
|
|
1320
1363
|
}
|
|
1321
1364
|
export {
|
|
1322
1365
|
StateInspector,
|
|
@@ -1330,13 +1373,14 @@ export {
|
|
|
1330
1373
|
getAvatarInitials,
|
|
1331
1374
|
getAvatarStyle,
|
|
1332
1375
|
isEmbeddedApp,
|
|
1376
|
+
useAppData,
|
|
1333
1377
|
useBroadcastConnectedUsers,
|
|
1334
1378
|
useBroadcastMenuItems,
|
|
1335
1379
|
useEphemeralUserData,
|
|
1336
1380
|
useManagedHistory,
|
|
1337
1381
|
useManagedState,
|
|
1338
1382
|
useMultiplayerState,
|
|
1339
|
-
|
|
1383
|
+
useNoyaAppState,
|
|
1340
1384
|
useSyncMultiplayerStateManager,
|
|
1341
1385
|
useSyncStateManager
|
|
1342
1386
|
};
|