@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/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 useEffect4,
277
- useMemo as useMemo4,
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 useEffect3,
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
- useEffect3(() => {
487
+ useEffect2(() => {
559
488
  shouldTrackEvents$.set(showEvents);
560
489
  }, [showEvents]);
561
- useEffect3(() => {
490
+ useEffect2(() => {
562
491
  shouldTrackTasks$.set(showTasks);
563
492
  }, [showTasks]);
564
- useEffect3(() => {
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
- useEffect3(() => {
500
+ useEffect2(() => {
572
501
  if (historyContainerRef.current) {
573
502
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
574
503
  }
575
504
  }, [historySnapshot]);
576
- useEffect3(() => {
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 = useMemo4(() => {
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
- }, [tasks, connectionEvents, connectedUsers, ephemeralUserData, userId]);
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
- useEffect4(() => {
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
- useEffect4(() => {
1216
+ useEffect3(() => {
1269
1217
  trackConnectedUsersCallbackRef.current = (users, userId2) => {
1270
1218
  setConnectedUsers(users);
1271
1219
  setUserId(userId2);
1272
1220
  };
1273
1221
  }, []);
1274
- useEffect4(() => {
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
- useEffect4(() => {
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
- useBroadcastConnectedUsers(connectedUsers);
1314
- return [
1315
- state,
1316
- multiplayerStateManager.setState,
1317
- multiplayerStateManager,
1318
- extras
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
- useNoyaApp,
1383
+ useNoyaAppState,
1340
1384
  useSyncMultiplayerStateManager,
1341
1385
  useSyncStateManager
1342
1386
  };