@noya-app/noya-multiplayer-react 0.1.73 → 0.1.74

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noya-app/noya-multiplayer-react",
3
- "version": "0.1.73",
3
+ "version": "0.1.74",
4
4
  "main": "./dist/index.js",
5
5
  "module": "./dist/index.mjs",
6
6
  "types": "./dist/index.d.ts",
@@ -11,7 +11,7 @@
11
11
  "dev": "npm run build -- --watch"
12
12
  },
13
13
  "dependencies": {
14
- "@noya-app/state-manager": "0.1.58",
14
+ "@noya-app/state-manager": "0.1.59",
15
15
  "@noya-app/emitter": "0.1.0",
16
16
  "@noya-app/observable": "0.1.12",
17
17
  "@noya-app/task-runner": "0.1.6",
@@ -1,4 +1,12 @@
1
1
  import { expect, it } from "bun:test";
2
+ import {
3
+ clientId$,
4
+ clientImage$,
5
+ clientName$,
6
+ setClientId,
7
+ setClientImage,
8
+ setClientName,
9
+ } from "@noya-app/state-manager";
2
10
  import { Type } from "..";
3
11
  import { createDefaultAppData, getAppData } from "../noyaApp";
4
12
 
@@ -100,6 +108,38 @@ it("preserves userId from data param", () => {
100
108
  expect(data.isDemo).toBe(true);
101
109
  });
102
110
 
111
+ it("applies client identity from data param", () => {
112
+ setClientId(undefined);
113
+ setClientName(undefined);
114
+ setClientImage(undefined);
115
+
116
+ const existing = {
117
+ theme: "light",
118
+ viewType: "editable",
119
+ initialState: { foo: "bar" },
120
+ inspector: false,
121
+ clientId: "parent-client-id",
122
+ clientName: "Parent Name",
123
+ clientImage: "https://example.com/avatar.svg",
124
+ };
125
+
126
+ getAppData(null as unknown, undefined, {
127
+ window: {
128
+ location: {
129
+ hash: `#data=${encodeURIComponent(JSON.stringify(existing))}`,
130
+ },
131
+ },
132
+ });
133
+
134
+ expect(clientId$.get()).toBe("parent-client-id");
135
+ expect(clientName$.get()).toBe("Parent Name");
136
+ expect(clientImage$.get()).toBe("https://example.com/avatar.svg");
137
+
138
+ setClientId(undefined);
139
+ setClientName(undefined);
140
+ setClientImage(undefined);
141
+ });
142
+
103
143
  // it("enforces schema on data param", () => {
104
144
  // const schema = Type.Object({
105
145
  // foo: Type.String({ default: "bar" }),
@@ -109,6 +109,10 @@ export const StateInspector = memoGeneric(function StateInspector<
109
109
  "noya-multiplayer-react-show-users",
110
110
  true
111
111
  );
112
+ const [showUserDetails, setShowUserDetails] = useLocalStorageState(
113
+ "noya-multiplayer-react-show-user-details",
114
+ false
115
+ );
112
116
  const [showData, setShowData] = useLocalStorageState(
113
117
  "noya-multiplayer-react-show-data",
114
118
  true
@@ -288,21 +292,28 @@ export const StateInspector = memoGeneric(function StateInspector<
288
292
  colorScheme={colorScheme}
289
293
  style={{
290
294
  flex: "0 0 auto",
291
- maxHeight: "200px",
295
+ maxHeight: "50%",
296
+ overflowY: "auto",
292
297
  }}
293
298
  right={
294
- <StateInspectorToggleButton
295
- showInspector={showInspector}
296
- setShowInspector={setShowInspector}
297
- theme={theme}
298
- anchor={anchor}
299
- />
299
+ <span style={{ display: "flex", gap: "10px" }}>
300
+ <StateInspectorButton
301
+ theme={theme}
302
+ onClick={() => setShowUserDetails(!showUserDetails)}
303
+ >
304
+ Toggle details
305
+ </StateInspectorButton>
306
+ <StateInspectorToggleButton
307
+ showInspector={showInspector}
308
+ setShowInspector={setShowInspector}
309
+ theme={theme}
310
+ anchor={anchor}
311
+ />
312
+ </span>
300
313
  }
301
314
  >
302
315
  <StateInspectorDisclosureRowInner style={{ flex: "0 0 auto" }}>
303
316
  {connectedUsers?.map((user, index, array) => {
304
- const identifier = user.userId ?? user.connectionId;
305
-
306
317
  return (
307
318
  <StateInspectorRow
308
319
  key={user.connectionId}
@@ -326,7 +337,11 @@ export const StateInspector = memoGeneric(function StateInspector<
326
337
  }}
327
338
  />
328
339
  )}
329
- {user.name} ({ellipsis(identifier, 8, "middle")})
340
+ {showUserDetails ? (
341
+ <ObjectInspector data={user} theme={theme} />
342
+ ) : (
343
+ user.name
344
+ )}
330
345
  </StateInspectorRow>
331
346
  );
332
347
  })}
package/src/noyaApp.ts CHANGED
@@ -10,6 +10,9 @@ import {
10
10
  NoyaManager,
11
11
  parentFrameSync,
12
12
  PolicyAuthContext,
13
+ setClientId,
14
+ setClientImage,
15
+ setClientName,
13
16
  Static,
14
17
  stubSync,
15
18
  SyncAdapter,
@@ -34,6 +37,9 @@ export type AppData<State> = {
34
37
  userId?: string;
35
38
  isDemo: boolean;
36
39
  access?: AccessType;
40
+ clientId?: string;
41
+ clientName?: string;
42
+ clientImage?: string;
37
43
  };
38
44
 
39
45
  export function createDefaultAppData<State>(
@@ -84,6 +90,24 @@ export function parseAppDataParameter(
84
90
  }
85
91
  }
86
92
 
93
+ function applyClientIdentityFromAppData(appData: {
94
+ clientId?: string;
95
+ clientName?: string;
96
+ clientImage?: string;
97
+ }) {
98
+ if (appData.clientId !== undefined) {
99
+ setClientId(appData.clientId);
100
+ }
101
+
102
+ if (appData.clientName !== undefined) {
103
+ setClientName(appData.clientName);
104
+ }
105
+
106
+ if (appData.clientImage !== undefined) {
107
+ setClientImage(appData.clientImage);
108
+ }
109
+ }
110
+
87
111
  export function getAppData<State>(
88
112
  initialState: State | (() => State),
89
113
  schema?: TSchema,
@@ -106,6 +130,10 @@ export function getAppData<State>(
106
130
  appData.viewType === "editable" ? "write" : "read";
107
131
  appData.access = appData.access ?? fallbackAccess;
108
132
 
133
+ // If the parent frame provided a client identity (embedded mode), make sure
134
+ // this frame adopts it so the clientId/name/image observables stay in sync.
135
+ applyClientIdentityFromAppData(appData);
136
+
109
137
  return appData as AppData<State>;
110
138
  }
111
139