@noya-app/noya-multiplayer-react 0.1.17 → 0.1.19

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.js CHANGED
@@ -32,6 +32,14 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var src_exports = {};
33
33
  __export(src_exports, {
34
34
  StateInspector: () => StateInspector,
35
+ UserNameTag: () => UserNameTag,
36
+ UserPointer: () => UserPointer2,
37
+ UserPointerContainer: () => UserPointerContainer,
38
+ UserPointerIcon: () => UserPointerIcon,
39
+ UserPointersOverlay: () => UserPointersOverlay,
40
+ getAvatarInitials: () => getAvatarInitials,
41
+ getAvatarStyle: () => getAvatarStyle,
42
+ useEphemeralUserData: () => useEphemeralUserData,
35
43
  useManagedHistory: () => useManagedHistory,
36
44
  useManagedState: () => useManagedState,
37
45
  useMultiplayerState: () => useMultiplayerState,
@@ -41,56 +49,220 @@ __export(src_exports, {
41
49
  module.exports = __toCommonJS(src_exports);
42
50
  __reExport(src_exports, require("@noya-app/state-manager"), module.exports);
43
51
 
44
- // src/hooks.ts
45
- var import_state_manager = require("@noya-app/state-manager");
46
- var import_react5 = require("react");
52
+ // src/avatarStyle.ts
53
+ function hashCode(string) {
54
+ let hash = 0;
55
+ for (const char of string) {
56
+ hash = char.charCodeAt(0) + ((hash << 5) - hash);
57
+ }
58
+ return hash;
59
+ }
60
+ function elementFromHash(array, hash) {
61
+ return array[Math.abs(hash) % array.length];
62
+ }
63
+ function getAvatarInitials(name) {
64
+ return name.split(" ").filter((c) => c.length > 0).map((c) => c[0]).join("").toLocaleUpperCase();
65
+ }
66
+ function getAvatarStyle(name) {
67
+ const hash = hashCode(name);
68
+ const color = elementFromHash(Object.values(colors500), hash);
69
+ return {
70
+ color: "white",
71
+ backgroundColor: color
72
+ // primaryColors: {
73
+ // "500": color,
74
+ // "800": darkerColor,
75
+ // },
76
+ };
77
+ }
78
+ var colors500 = {
79
+ red500: "#ef4444",
80
+ orange500: "#f97316",
81
+ amber500: "#f59e0b",
82
+ yellow500: "#eab308",
83
+ lime500: "#84cc16",
84
+ green500: "#22c55e",
85
+ emerald500: "#10b981",
86
+ teal500: "#14b8a6",
87
+ cyan500: "#06b6d4",
88
+ sky500: "#0ea5e9",
89
+ blue500: "#3b82f6",
90
+ indigo500: "#6366f1",
91
+ violet500: "#8b5cf6",
92
+ purple500: "#a855f7",
93
+ fuchsia500: "#d946ef",
94
+ pink500: "#ec4899",
95
+ rose500: "#f43f5e"
96
+ };
47
97
 
48
- // src/globals.ts
49
- var import_emitter = require("@noya-app/emitter");
98
+ // src/components/UserPointersOverlay.tsx
99
+ var import_react2 = __toESM(require("react"));
100
+
101
+ // src/useObservable.ts
50
102
  var import_react = require("react");
51
- var Observable = class {
52
- value;
53
- emitter = new import_emitter.Emitter();
54
- constructor(value) {
55
- this.value = value;
56
- }
57
- get() {
58
- return this.value;
59
- }
60
- set(value) {
61
- if (this.value === value)
103
+ function useObservable(observable, path) {
104
+ const { get, listen } = (0, import_react.useMemo)(() => {
105
+ const listen2 = path ? (callback) => observable.listen(path, callback) : observable.listen;
106
+ const get2 = path ? () => observable.get(path) : observable.get;
107
+ return { get: get2, listen: listen2 };
108
+ }, [observable, path]);
109
+ return (0, import_react.useSyncExternalStore)(listen, get, get);
110
+ }
111
+
112
+ // src/components/UserPointersOverlay.tsx
113
+ function shouldShow(hideAfter, updatedAt) {
114
+ return !!updatedAt && Date.now() - updatedAt < hideAfter;
115
+ }
116
+ var UserPointer_ = function UserPointer({
117
+ user,
118
+ ephemeralUserData,
119
+ hideAfter = 5e3
120
+ }) {
121
+ const metadata = useObservable(ephemeralUserData.metadata$, [
122
+ user.id
123
+ ]);
124
+ const data = useObservable(ephemeralUserData.data$, [user.id]);
125
+ const avatarStyle = (0, import_react2.useMemo)(() => getAvatarStyle(user.id), [user.id]);
126
+ const [, setForceUpdate] = (0, import_react2.useState)(0);
127
+ const updatedAt = metadata?.updatedAt ?? 0;
128
+ (0, import_react2.useEffect)(() => {
129
+ if (!shouldShow(hideAfter, updatedAt))
62
130
  return;
63
- this.value = value;
64
- this.emitter.emit(value);
65
- }
66
- listen(callback) {
67
- callback(this.value);
68
- return this.emitter.addListener(callback);
69
- }
131
+ const timeoutId = setTimeout(() => {
132
+ setForceUpdate((prev) => prev + 1);
133
+ }, hideAfter);
134
+ return () => clearTimeout(timeoutId);
135
+ }, [hideAfter, updatedAt]);
136
+ const show = shouldShow(hideAfter, updatedAt);
137
+ if (!data || !data.pointer)
138
+ return null;
139
+ 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));
70
140
  };
71
- function useObservable(observable) {
72
- const [value, setValue] = (0, import_react.useState)(observable.get());
73
- (0, import_react.useEffect)(() => {
74
- return observable.listen(setValue);
75
- }, [observable]);
76
- return value;
77
- }
78
- var shouldTrackEvents$ = new Observable(false);
79
- var shouldTrackTasks$ = new Observable(false);
141
+ var UserPointer2 = (0, import_react2.memo)(UserPointer_);
142
+ var UserPointerContainer = (0, import_react2.memo)(function UserPointerContainer2({
143
+ point,
144
+ children,
145
+ show = true
146
+ }) {
147
+ return /* @__PURE__ */ import_react2.default.createElement(
148
+ "div",
149
+ {
150
+ style: {
151
+ position: "absolute",
152
+ top: 0,
153
+ left: 0,
154
+ transform: `translate(${Math.round(point.x)}px, ${Math.round(
155
+ point.y
156
+ )}px)`,
157
+ opacity: show ? 1 : 0,
158
+ transition: "transform 0.1s, opacity 0.2s"
159
+ }
160
+ },
161
+ children
162
+ );
163
+ });
164
+ var UserNameTag = (0, import_react2.memo)(function UserNameTag2({
165
+ background,
166
+ children
167
+ }) {
168
+ return /* @__PURE__ */ import_react2.default.createElement(
169
+ "span",
170
+ {
171
+ style: {
172
+ position: "relative",
173
+ top: "8px",
174
+ left: "15px",
175
+ fontSize: 11,
176
+ lineHeight: "1",
177
+ fontWeight: 500,
178
+ boxShadow: "0 1px 1px rgba(0,0,0,0.1)",
179
+ padding: "2px 4px 3px",
180
+ pointerEvents: "none",
181
+ letterSpacing: "-0.3px",
182
+ outline: `1px solid rgba(255,255,255,0.3)`,
183
+ outlineOffset: "-1px",
184
+ background,
185
+ color: "white"
186
+ }
187
+ },
188
+ children
189
+ );
190
+ });
191
+ var UserPointersOverlay = (0, import_react2.memo)(function UserPointers({ connectedUsers, ephemeralUserData }) {
192
+ const currentUserId = useObservable(ephemeralUserData.currentUserId$);
193
+ return /* @__PURE__ */ import_react2.default.createElement(import_react2.default.Fragment, null, connectedUsers.map((user) => {
194
+ if (user.id === currentUserId)
195
+ return null;
196
+ return /* @__PURE__ */ import_react2.default.createElement(
197
+ UserPointer2,
198
+ {
199
+ key: user.id,
200
+ user,
201
+ ephemeralUserData
202
+ }
203
+ );
204
+ }));
205
+ });
206
+ var UserPointerIcon = (0, import_react2.memo)(function CursorIcon({
207
+ color = "black"
208
+ }) {
209
+ return /* @__PURE__ */ import_react2.default.createElement(
210
+ "svg",
211
+ {
212
+ width: "15",
213
+ height: "15",
214
+ viewBox: "0 0 15 15",
215
+ fill: "none",
216
+ xmlns: "http://www.w3.org/2000/svg",
217
+ style: {
218
+ position: "absolute",
219
+ filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.1))"
220
+ // filter: "drop-shadow(0 1px 1px rgba(0,0,0,0.6))",
221
+ }
222
+ },
223
+ /* @__PURE__ */ import_react2.default.createElement(
224
+ "path",
225
+ {
226
+ fillRule: "evenodd",
227
+ clipRule: "evenodd",
228
+ d: "M3.29227 0.0451998C3.47033 -0.0361222 3.67946 -0.00606629 3.8274 0.122107L12.8587 7.94648C13.0134 8.08054 13.0708 8.29538 13.0035 8.48873C12.9362 8.68208 12.7578 8.81488 12.5533 8.8239L9.21887 8.97096L11.1504 13.2149C11.2648 13.4662 11.1538 13.7626 10.9026 13.877L8.75024 14.8575C8.499 14.972 8.20255 14.8611 8.08802 14.6099L6.15339 10.3665L3.86279 12.7817C3.72196 12.9302 3.50487 12.9779 3.31479 12.9021C3.1247 12.8263 3 12.6423 3 12.4376V0.500008C3 0.304264 3.11422 0.126522 3.29227 0.0451998Z",
229
+ fill: color
230
+ }
231
+ ),
232
+ /* @__PURE__ */ import_react2.default.createElement(
233
+ "path",
234
+ {
235
+ fillRule: "evenodd",
236
+ clipRule: "evenodd",
237
+ d: "M3.29227 0.048984C3.47033 -0.032338 3.67946 -0.00228211 3.8274 0.125891L12.8587 7.95026C13.0134 8.08432 13.0708 8.29916 13.0035 8.49251C12.9362 8.68586 12.7578 8.81866 12.5533 8.82768L9.21887 8.97474L11.1504 13.2187C11.2648 13.47 11.1538 13.7664 10.9026 13.8808L8.75024 14.8613C8.499 14.9758 8.20255 14.8649 8.08802 14.6137L6.15339 10.3703L3.86279 12.7855C3.72196 12.934 3.50487 12.9817 3.31479 12.9059C3.1247 12.8301 3 12.6461 3 12.4414V0.503792C3 0.308048 3.11422 0.130306 3.29227 0.048984ZM4 1.59852V11.1877L5.93799 9.14425C6.05238 9.02363 6.21924 8.96776 6.38319 8.99516C6.54715 9.02256 6.68677 9.12965 6.75573 9.2809L8.79056 13.7441L10.0332 13.178L8.00195 8.71497C7.93313 8.56376 7.94391 8.38824 8.03072 8.24659C8.11753 8.10494 8.26903 8.01566 8.435 8.00834L11.2549 7.88397L4 1.59852Z",
238
+ fill: "rgba(255,255,255,0.5)"
239
+ }
240
+ )
241
+ );
242
+ });
243
+
244
+ // src/hooks.ts
245
+ var import_state_manager = require("@noya-app/state-manager");
246
+ var import_react6 = require("react");
247
+
248
+ // src/globals.ts
249
+ var import_observable = require("@noya-app/observable");
250
+ var shouldTrackEvents$ = new import_observable.Observable(false);
251
+ var shouldTrackTasks$ = new import_observable.Observable(false);
80
252
 
81
253
  // src/inspector/useStateInspector.tsx
82
- var import_react4 = __toESM(require("react"));
254
+ var import_react5 = __toESM(require("react"));
83
255
  var import_client = require("react-dom/client");
84
256
 
85
257
  // src/inspector/StateInspector.tsx
86
- var import_react3 = __toESM(require("react"));
258
+ var import_react4 = __toESM(require("react"));
87
259
  var import_react_inspector = require("react-inspector");
88
260
 
89
261
  // src/inspector/useLocalStorageState.tsx
90
- var import_react2 = __toESM(require("react"));
262
+ var import_react3 = __toESM(require("react"));
91
263
  var localStorage = typeof window !== "undefined" ? window.localStorage : null;
92
264
  function useLocalStorageState(key, defaultValue) {
93
- const [state, setState] = import_react2.default.useState(() => {
265
+ const [state, setState] = import_react3.default.useState(() => {
94
266
  const value = localStorage?.getItem(key);
95
267
  let result = defaultValue;
96
268
  if (value) {
@@ -135,7 +307,7 @@ function ToggleButton({
135
307
  theme,
136
308
  anchor
137
309
  }) {
138
- return /* @__PURE__ */ import_react3.default.createElement(
310
+ return /* @__PURE__ */ import_react4.default.createElement(
139
311
  "span",
140
312
  {
141
313
  role: "button",
@@ -156,7 +328,7 @@ function ToggleButton({
156
328
  setShowInspector(!showInspector);
157
329
  }
158
330
  },
159
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react3.default.createElement(
331
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, showInspector === (anchor === "right") ? /* @__PURE__ */ import_react4.default.createElement(
160
332
  "svg",
161
333
  {
162
334
  xmlns: "http://www.w3.org/2000/svg",
@@ -166,7 +338,7 @@ function ToggleButton({
166
338
  stroke: "currentColor",
167
339
  className: "size-6"
168
340
  },
169
- /* @__PURE__ */ import_react3.default.createElement(
341
+ /* @__PURE__ */ import_react4.default.createElement(
170
342
  "path",
171
343
  {
172
344
  strokeLinecap: "round",
@@ -174,7 +346,7 @@ function ToggleButton({
174
346
  d: "m5.25 4.5 7.5 7.5-7.5 7.5m6-15 7.5 7.5-7.5 7.5"
175
347
  }
176
348
  )
177
- ) : /* @__PURE__ */ import_react3.default.createElement(
349
+ ) : /* @__PURE__ */ import_react4.default.createElement(
178
350
  "svg",
179
351
  {
180
352
  xmlns: "http://www.w3.org/2000/svg",
@@ -184,7 +356,7 @@ function ToggleButton({
184
356
  stroke: "currentColor",
185
357
  className: "size-6"
186
358
  },
187
- /* @__PURE__ */ import_react3.default.createElement(
359
+ /* @__PURE__ */ import_react4.default.createElement(
188
360
  "path",
189
361
  {
190
362
  strokeLinecap: "round",
@@ -207,7 +379,7 @@ function DisclosureSection({
207
379
  }) {
208
380
  const theme = colorScheme === "light" ? lightTheme : darkTheme;
209
381
  const borderColor = colorScheme === "light" ? "rgba(0,0,0,0.1)" : "rgba(255,255,255,0.1)";
210
- return /* @__PURE__ */ import_react3.default.createElement(
382
+ return /* @__PURE__ */ import_react4.default.createElement(
211
383
  "div",
212
384
  {
213
385
  style: {
@@ -217,7 +389,7 @@ function DisclosureSection({
217
389
  ...style
218
390
  }
219
391
  },
220
- /* @__PURE__ */ import_react3.default.createElement(
392
+ /* @__PURE__ */ import_react4.default.createElement(
221
393
  "div",
222
394
  {
223
395
  onClick: () => setOpen?.(!open),
@@ -231,7 +403,7 @@ function DisclosureSection({
231
403
  ...open && { borderBottom: `1px solid ${borderColor}` }
232
404
  }
233
405
  },
234
- setOpen && /* @__PURE__ */ import_react3.default.createElement(
406
+ setOpen && /* @__PURE__ */ import_react4.default.createElement(
235
407
  Arrow,
236
408
  {
237
409
  expanded: open,
@@ -242,7 +414,7 @@ function DisclosureSection({
242
414
  }
243
415
  }
244
416
  ),
245
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
417
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { flex: "1 1 0", userSelect: "none" } }, title),
246
418
  right
247
419
  ),
248
420
  open && children
@@ -256,7 +428,7 @@ function InspectorRow({
256
428
  variant
257
429
  }) {
258
430
  const solidBorderColor = colorScheme === "light" ? "rgb(223 223 223)" : "rgb(29 29 29)";
259
- return /* @__PURE__ */ import_react3.default.createElement(
431
+ return /* @__PURE__ */ import_react4.default.createElement(
260
432
  "div",
261
433
  {
262
434
  style: {
@@ -274,7 +446,7 @@ function InspectorRow({
274
446
  ...style
275
447
  }
276
448
  },
277
- /* @__PURE__ */ import_react3.default.createElement(
449
+ /* @__PURE__ */ import_react4.default.createElement(
278
450
  "span",
279
451
  {
280
452
  style: {
@@ -289,7 +461,7 @@ function InspectorRow({
289
461
  );
290
462
  }
291
463
  var HISTORY_ELEMENT_PREFIX = "noya-multiplayer-history-";
292
- var StateInspector = (0, import_react3.memo)(function StateInspector2({
464
+ var StateInspector = (0, import_react4.memo)(function StateInspector2({
293
465
  state,
294
466
  connectionEvents,
295
467
  connectedUsers,
@@ -298,16 +470,17 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
298
470
  unstyled,
299
471
  colorScheme = "light",
300
472
  multiplayerStateManager,
473
+ ephemeralUserData,
301
474
  anchor = "right",
302
475
  forceInit,
303
476
  ...props
304
477
  }) {
305
- const [didMount, setDidMount] = import_react3.default.useState(false);
306
- (0, import_react3.useLayoutEffect)(() => {
478
+ const [didMount, setDidMount] = import_react4.default.useState(false);
479
+ (0, import_react4.useLayoutEffect)(() => {
307
480
  setDidMount(true);
308
481
  }, []);
309
- const eventsContainerRef = import_react3.default.useRef(null);
310
- const historyContainerRef = import_react3.default.useRef(null);
482
+ const eventsContainerRef = import_react4.default.useRef(null);
483
+ const historyContainerRef = import_react4.default.useRef(null);
311
484
  const [showInspector, setShowInspector] = useLocalStorageState(
312
485
  "noya-multiplayer-react-show-inspector",
313
486
  true
@@ -332,24 +505,29 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
332
505
  "noya-multiplayer-react-show-tasks",
333
506
  false
334
507
  );
335
- (0, import_react3.useEffect)(() => {
508
+ const [showEphemeral, setShowEphemeral] = useLocalStorageState(
509
+ "noya-multiplayer-react-show-ephemeral",
510
+ false
511
+ );
512
+ (0, import_react4.useEffect)(() => {
336
513
  shouldTrackEvents$.set(showEvents);
337
514
  }, [showEvents]);
338
- (0, import_react3.useEffect)(() => {
515
+ (0, import_react4.useEffect)(() => {
339
516
  shouldTrackTasks$.set(showTasks);
340
517
  }, [showTasks]);
341
- (0, import_react3.useEffect)(() => {
518
+ (0, import_react4.useEffect)(() => {
342
519
  if (eventsContainerRef.current) {
343
520
  eventsContainerRef.current.scrollTop = eventsContainerRef.current.scrollHeight;
344
521
  }
345
522
  }, [connectionEvents]);
523
+ const ephemeral = useEphemeralUserData(ephemeralUserData);
346
524
  const historySnapshot = useManagedHistory(multiplayerStateManager.sm);
347
- (0, import_react3.useEffect)(() => {
525
+ (0, import_react4.useEffect)(() => {
348
526
  if (historyContainerRef.current) {
349
527
  historyContainerRef.current.scrollTop = historyContainerRef.current.scrollHeight;
350
528
  }
351
529
  }, [historySnapshot]);
352
- (0, import_react3.useEffect)(() => {
530
+ (0, import_react4.useEffect)(() => {
353
531
  if (!historyContainerRef.current)
354
532
  return;
355
533
  const historyEntry = historyContainerRef.current.querySelector(
@@ -386,7 +564,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
386
564
  if (!didMount)
387
565
  return null;
388
566
  if (!showInspector) {
389
- return /* @__PURE__ */ import_react3.default.createElement(
567
+ return /* @__PURE__ */ import_react4.default.createElement(
390
568
  "div",
391
569
  {
392
570
  ...props,
@@ -398,7 +576,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
398
576
  },
399
577
  onClick: () => setShowInspector(true)
400
578
  },
401
- /* @__PURE__ */ import_react3.default.createElement(
579
+ /* @__PURE__ */ import_react4.default.createElement(
402
580
  ToggleButton,
403
581
  {
404
582
  showInspector,
@@ -409,7 +587,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
409
587
  )
410
588
  );
411
589
  }
412
- return /* @__PURE__ */ import_react3.default.createElement(
590
+ return /* @__PURE__ */ import_react4.default.createElement(
413
591
  "div",
414
592
  {
415
593
  ...props,
@@ -418,7 +596,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
418
596
  ...props.style
419
597
  }
420
598
  },
421
- /* @__PURE__ */ import_react3.default.createElement(
599
+ /* @__PURE__ */ import_react4.default.createElement(
422
600
  DisclosureSection,
423
601
  {
424
602
  isFirst: true,
@@ -430,7 +608,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
430
608
  flex: "0 0 auto",
431
609
  maxHeight: "200px"
432
610
  },
433
- right: /* @__PURE__ */ import_react3.default.createElement(
611
+ right: /* @__PURE__ */ import_react4.default.createElement(
434
612
  ToggleButton,
435
613
  {
436
614
  showInspector,
@@ -440,7 +618,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
440
618
  }
441
619
  )
442
620
  },
443
- /* @__PURE__ */ import_react3.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react3.default.createElement(
621
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: { ...styles.sectionInner, flex: "0 0 auto" } }, connectedUsers?.map((user) => /* @__PURE__ */ import_react4.default.createElement(
444
622
  InspectorRow,
445
623
  {
446
624
  key: user.id,
@@ -451,7 +629,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
451
629
  " (",
452
630
  ellipsis(user.id.toString(), 8, "middle"),
453
631
  ")"
454
- )), !connectedUsers && /* @__PURE__ */ import_react3.default.createElement(
632
+ )), !connectedUsers && /* @__PURE__ */ import_react4.default.createElement(
455
633
  "div",
456
634
  {
457
635
  style: {
@@ -462,17 +640,17 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
462
640
  gap: "4px"
463
641
  }
464
642
  },
465
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No connected users")
643
+ /* @__PURE__ */ import_react4.default.createElement("span", null, "No connected users")
466
644
  ))
467
645
  ),
468
- /* @__PURE__ */ import_react3.default.createElement(
646
+ /* @__PURE__ */ import_react4.default.createElement(
469
647
  DisclosureSection,
470
648
  {
471
649
  title: "Data",
472
650
  colorScheme,
473
651
  setOpen: setShowData,
474
652
  open: showData,
475
- right: /* @__PURE__ */ import_react3.default.createElement(
653
+ right: /* @__PURE__ */ import_react4.default.createElement(
476
654
  "span",
477
655
  {
478
656
  style: {
@@ -480,7 +658,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
480
658
  gap: "4px"
481
659
  }
482
660
  },
483
- /* @__PURE__ */ import_react3.default.createElement(
661
+ /* @__PURE__ */ import_react4.default.createElement(
484
662
  SmallButton,
485
663
  {
486
664
  theme,
@@ -492,14 +670,14 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
492
670
  )
493
671
  )
494
672
  },
495
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
673
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
496
674
  import_react_inspector.ObjectInspector,
497
675
  {
498
676
  name: multiplayerStateManager.schema ? "state" : void 0,
499
677
  data: state,
500
678
  theme
501
679
  }
502
- )), multiplayerStateManager.schema && /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react3.default.createElement(
680
+ )), multiplayerStateManager.schema && /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
503
681
  import_react_inspector.ObjectInspector,
504
682
  {
505
683
  name: "schema",
@@ -508,14 +686,14 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
508
686
  }
509
687
  )))
510
688
  ),
511
- /* @__PURE__ */ import_react3.default.createElement(
689
+ /* @__PURE__ */ import_react4.default.createElement(
512
690
  DisclosureSection,
513
691
  {
514
692
  open: showHistory,
515
693
  setOpen: setShowHistory,
516
694
  title: "History",
517
695
  colorScheme,
518
- right: /* @__PURE__ */ import_react3.default.createElement(
696
+ right: /* @__PURE__ */ import_react4.default.createElement(
519
697
  "span",
520
698
  {
521
699
  style: {
@@ -523,7 +701,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
523
701
  gap: "4px"
524
702
  }
525
703
  },
526
- /* @__PURE__ */ import_react3.default.createElement(
704
+ /* @__PURE__ */ import_react4.default.createElement(
527
705
  SmallButton,
528
706
  {
529
707
  disabled: !historySnapshot.canUndo,
@@ -532,7 +710,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
532
710
  multiplayerStateManager.undo();
533
711
  }
534
712
  },
535
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react3.default.createElement(
713
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
536
714
  "svg",
537
715
  {
538
716
  xmlns: "http://www.w3.org/2000/svg",
@@ -540,7 +718,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
540
718
  height: "1em",
541
719
  viewBox: "0 0 20 20"
542
720
  },
543
- /* @__PURE__ */ import_react3.default.createElement(
721
+ /* @__PURE__ */ import_react4.default.createElement(
544
722
  "path",
545
723
  {
546
724
  fill: "currentColor",
@@ -549,7 +727,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
549
727
  )
550
728
  ))
551
729
  ),
552
- /* @__PURE__ */ import_react3.default.createElement(
730
+ /* @__PURE__ */ import_react4.default.createElement(
553
731
  SmallButton,
554
732
  {
555
733
  disabled: !historySnapshot.canRedo,
@@ -558,7 +736,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
558
736
  multiplayerStateManager.redo();
559
737
  }
560
738
  },
561
- /* @__PURE__ */ import_react3.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react3.default.createElement(
739
+ /* @__PURE__ */ import_react4.default.createElement("span", { style: { width: "12px", height: "12px" } }, /* @__PURE__ */ import_react4.default.createElement(
562
740
  "svg",
563
741
  {
564
742
  xmlns: "http://www.w3.org/2000/svg",
@@ -566,7 +744,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
566
744
  height: "1em",
567
745
  viewBox: "0 0 20 20"
568
746
  },
569
- /* @__PURE__ */ import_react3.default.createElement(
747
+ /* @__PURE__ */ import_react4.default.createElement(
570
748
  "path",
571
749
  {
572
750
  fill: "currentColor",
@@ -577,7 +755,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
577
755
  )
578
756
  )
579
757
  },
580
- /* @__PURE__ */ import_react3.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react3.default.createElement(
758
+ /* @__PURE__ */ import_react4.default.createElement("div", { ref: historyContainerRef, style: styles.sectionInner }, /* @__PURE__ */ import_react4.default.createElement(
581
759
  "div",
582
760
  {
583
761
  id: `${HISTORY_ELEMENT_PREFIX}0`,
@@ -591,7 +769,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
591
769
  background: historySnapshot.historyIndex === 0 ? "rgb(59 130 246 / 15%)" : void 0
592
770
  }
593
771
  },
594
- /* @__PURE__ */ import_react3.default.createElement(
772
+ /* @__PURE__ */ import_react4.default.createElement(
595
773
  "span",
596
774
  {
597
775
  style: {
@@ -603,7 +781,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
603
781
  },
604
782
  "Initial state"
605
783
  )
606
- ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react3.default.createElement(
784
+ ), historySnapshot.history.map((entry, index) => /* @__PURE__ */ import_react4.default.createElement(
607
785
  "div",
608
786
  {
609
787
  id: `${HISTORY_ELEMENT_PREFIX}${index + 1}`,
@@ -614,7 +792,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
614
792
  background: index + 1 === historySnapshot.historyIndex ? "rgb(59 130 246 / 15%)" : void 0
615
793
  }
616
794
  },
617
- entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react3.default.createElement(
795
+ entry.redoPatches?.map((patch, j) => /* @__PURE__ */ import_react4.default.createElement(
618
796
  "pre",
619
797
  {
620
798
  key: j,
@@ -624,14 +802,14 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
624
802
  flexWrap: "wrap"
625
803
  }
626
804
  },
627
- patch.op === "add" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
628
- patch.op === "replace" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
629
- patch.op === "remove" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
630
- patch.op === "move" && /* @__PURE__ */ import_react3.default.createElement(import_react3.default.Fragment, null, /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
805
+ patch.op === "add" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
806
+ patch.op === "replace" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)), " = ", /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectInspector, { data: patch.value, theme })),
807
+ patch.op === "remove" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { color: theme.OBJECT_VALUE_STRING_COLOR } }, "delete", " "), /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path))),
808
+ patch.op === "move" && /* @__PURE__ */ import_react4.default.createElement(import_react4.default.Fragment, null, /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.from)), " -> ", /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, pathToString(patch.path)))
631
809
  ))
632
810
  )))
633
811
  ),
634
- /* @__PURE__ */ import_react3.default.createElement(
812
+ /* @__PURE__ */ import_react4.default.createElement(
635
813
  DisclosureSection,
636
814
  {
637
815
  title: "Tasks",
@@ -639,7 +817,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
639
817
  open: showTasks,
640
818
  setOpen: setShowTasks
641
819
  },
642
- /* @__PURE__ */ import_react3.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react3.default.createElement(
820
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, tasks?.map((task) => /* @__PURE__ */ import_react4.default.createElement(
643
821
  InspectorRow,
644
822
  {
645
823
  key: task.id,
@@ -648,7 +826,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
648
826
  backgroundColor: task.status === "done" ? "rgba(0,255,0,0.2)" : task.status === "error" ? "rgba(255,0,0,0.2)" : void 0
649
827
  }
650
828
  },
651
- /* @__PURE__ */ import_react3.default.createElement(
829
+ /* @__PURE__ */ import_react4.default.createElement(
652
830
  import_react_inspector.ObjectInspector,
653
831
  {
654
832
  name: task.name,
@@ -658,7 +836,25 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
658
836
  )
659
837
  )))
660
838
  ),
661
- /* @__PURE__ */ import_react3.default.createElement(
839
+ /* @__PURE__ */ import_react4.default.createElement(
840
+ DisclosureSection,
841
+ {
842
+ open: showEphemeral,
843
+ setOpen: setShowEphemeral,
844
+ title: "Ephemeral User Data",
845
+ colorScheme
846
+ },
847
+ /* @__PURE__ */ import_react4.default.createElement("div", { style: styles.sectionInner }, Object.entries(ephemeral).map(([key, value]) => /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key, colorScheme }, /* @__PURE__ */ import_react4.default.createElement(
848
+ import_react_inspector.ObjectInspector,
849
+ {
850
+ name: key,
851
+ data: value,
852
+ theme,
853
+ expandLevel: 10
854
+ }
855
+ ))))
856
+ ),
857
+ /* @__PURE__ */ import_react4.default.createElement(
662
858
  DisclosureSection,
663
859
  {
664
860
  open: showEvents,
@@ -666,8 +862,8 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
666
862
  title: "Events",
667
863
  colorScheme
668
864
  },
669
- /* @__PURE__ */ import_react3.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
670
- (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react3.default.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react3.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react3.default.createElement(
865
+ /* @__PURE__ */ import_react4.default.createElement("div", { ref: eventsContainerRef, style: styles.sectionInner }, connectionEvents?.map(
866
+ (event, index) => event.type === "stateChange" ? /* @__PURE__ */ import_react4.default.createElement(InspectorRow, { key: index, colorScheme }, "connection:", " ", /* @__PURE__ */ import_react4.default.createElement("span", { style: { fontStyle: "italic" } }, event.state.toLowerCase())) : /* @__PURE__ */ import_react4.default.createElement(
671
867
  InspectorRow,
672
868
  {
673
869
  key: index,
@@ -677,7 +873,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
677
873
  padding: "0px 12px 1px"
678
874
  }
679
875
  },
680
- /* @__PURE__ */ import_react3.default.createElement(
876
+ /* @__PURE__ */ import_react4.default.createElement(
681
877
  import_react_inspector.ObjectInspector,
682
878
  {
683
879
  data: event.message,
@@ -690,7 +886,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
690
886
  expanded
691
887
  }) => {
692
888
  const direction = event.type === "send" ? "up" : "down";
693
- return depth === 0 ? /* @__PURE__ */ import_react3.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react3.default.createElement(
889
+ return depth === 0 ? /* @__PURE__ */ import_react4.default.createElement(ObjectRootLabel, { direction, data }) : /* @__PURE__ */ import_react4.default.createElement(
694
890
  import_react_inspector.ObjectLabel,
695
891
  {
696
892
  direction,
@@ -703,7 +899,7 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
703
899
  }
704
900
  )
705
901
  )
706
- ), !connectionEvents && /* @__PURE__ */ import_react3.default.createElement(
902
+ ), !connectionEvents && /* @__PURE__ */ import_react4.default.createElement(
707
903
  "div",
708
904
  {
709
905
  style: {
@@ -714,18 +910,18 @@ var StateInspector = (0, import_react3.memo)(function StateInspector2({
714
910
  gap: "4px"
715
911
  }
716
912
  },
717
- /* @__PURE__ */ import_react3.default.createElement("span", null, "No recorded events")
913
+ /* @__PURE__ */ import_react4.default.createElement("span", null, "No recorded events")
718
914
  ))
719
915
  )
720
916
  );
721
917
  });
722
918
  var ObjectRootLabel = ({ name, data, direction }) => {
723
919
  if (typeof name === "string") {
724
- return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectName, { name }), /* @__PURE__ */ import_react3.default.createElement("span", null, ": "), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data }));
920
+ return /* @__PURE__ */ import_react4.default.createElement("span", null, /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectName, { name }), /* @__PURE__ */ import_react4.default.createElement("span", null, ": "), /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data }));
725
921
  }
726
922
  if (direction === "up" || direction === "down") {
727
923
  const arrow = direction === "up" ? "\u2191" : "\u2193";
728
- return /* @__PURE__ */ import_react3.default.createElement("span", null, /* @__PURE__ */ import_react3.default.createElement(
924
+ return /* @__PURE__ */ import_react4.default.createElement("span", null, /* @__PURE__ */ import_react4.default.createElement(
729
925
  "span",
730
926
  {
731
927
  style: {
@@ -742,9 +938,9 @@ var ObjectRootLabel = ({ name, data, direction }) => {
742
938
  }
743
939
  },
744
940
  arrow
745
- ), /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data }));
941
+ ), /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data }));
746
942
  } else {
747
- return /* @__PURE__ */ import_react3.default.createElement(import_react_inspector.ObjectPreview, { data });
943
+ return /* @__PURE__ */ import_react4.default.createElement(import_react_inspector.ObjectPreview, { data });
748
944
  }
749
945
  };
750
946
  function Arrow({
@@ -752,7 +948,7 @@ function Arrow({
752
948
  onClick,
753
949
  style
754
950
  }) {
755
- return /* @__PURE__ */ import_react3.default.createElement(
951
+ return /* @__PURE__ */ import_react4.default.createElement(
756
952
  "span",
757
953
  {
758
954
  role: "button",
@@ -795,7 +991,7 @@ function SmallButton({
795
991
  theme,
796
992
  disabled
797
993
  }) {
798
- return /* @__PURE__ */ import_react3.default.createElement(
994
+ return /* @__PURE__ */ import_react4.default.createElement(
799
995
  "button",
800
996
  {
801
997
  type: "button",
@@ -841,10 +1037,11 @@ function useStateInspector({
841
1037
  colorScheme,
842
1038
  anchor,
843
1039
  multiplayerStateManager,
1040
+ ephemeralUserData,
844
1041
  forceInit
845
1042
  }) {
846
- const [root, setRoot] = import_react4.default.useState(null);
847
- (0, import_react4.useLayoutEffect)(() => {
1043
+ const [root, setRoot] = import_react5.default.useState(null);
1044
+ (0, import_react5.useLayoutEffect)(() => {
848
1045
  if (disabled)
849
1046
  return;
850
1047
  const portalElement = createPortalElement();
@@ -855,11 +1052,11 @@ function useStateInspector({
855
1052
  document.body.removeChild(portalElement);
856
1053
  };
857
1054
  }, [disabled]);
858
- (0, import_react4.useLayoutEffect)(() => {
1055
+ (0, import_react5.useLayoutEffect)(() => {
859
1056
  if (!root)
860
1057
  return;
861
1058
  root.render(
862
- /* @__PURE__ */ import_react4.default.createElement(
1059
+ /* @__PURE__ */ import_react5.default.createElement(
863
1060
  StateInspector,
864
1061
  {
865
1062
  state,
@@ -870,7 +1067,8 @@ function useStateInspector({
870
1067
  colorScheme,
871
1068
  anchor,
872
1069
  forceInit,
873
- multiplayerStateManager
1070
+ multiplayerStateManager,
1071
+ ephemeralUserData
874
1072
  }
875
1073
  )
876
1074
  );
@@ -884,28 +1082,29 @@ function useStateInspector({
884
1082
  multiplayerStateManager,
885
1083
  userId,
886
1084
  tasks,
887
- forceInit
1085
+ forceInit,
1086
+ ephemeralUserData
888
1087
  ]);
889
1088
  }
890
1089
 
891
1090
  // src/hooks.ts
892
1091
  function useSyncStateManager(stateManager, path) {
893
- const getSnapshot = (0, import_react5.useCallback)(
1092
+ const getSnapshot = (0, import_react6.useCallback)(
894
1093
  () => typeof path === "string" ? stateManager.getState(path) : stateManager.getState(),
895
1094
  [stateManager, path]
896
1095
  );
897
- return (0, import_react5.useSyncExternalStore)(
1096
+ return (0, import_react6.useSyncExternalStore)(
898
1097
  stateManager.addListener,
899
1098
  getSnapshot,
900
1099
  getSnapshot
901
1100
  );
902
1101
  }
903
1102
  function useManagedState(createInitialState, options) {
904
- const [stateManager] = (0, import_react5.useState)(
1103
+ const [stateManager] = (0, import_react6.useState)(
905
1104
  () => new import_state_manager.StateManager(createInitialState(), options)
906
1105
  );
907
1106
  const state = useSyncStateManager(stateManager);
908
- const setState = (0, import_react5.useCallback)(
1107
+ const setState = (0, import_react6.useCallback)(
909
1108
  (...args) => {
910
1109
  const [metadata, action] = args.length === 1 ? [void 0, args[0]] : args;
911
1110
  if (metadata === void 0) {
@@ -941,35 +1140,47 @@ function useManagedState(createInitialState, options) {
941
1140
  return [state, setState, stateManager];
942
1141
  }
943
1142
  function useManagedHistory(stateManager) {
944
- return (0, import_react5.useSyncExternalStore)(
1143
+ return (0, import_react6.useSyncExternalStore)(
945
1144
  stateManager.historyEmittor.addListener,
946
1145
  stateManager.getHistorySnapshot,
947
1146
  stateManager.getHistorySnapshot
948
1147
  );
949
1148
  }
950
1149
  function useSyncMultiplayerStateManager(multiplayerStateManager) {
951
- return (0, import_react5.useSyncExternalStore)(
1150
+ return (0, import_react6.useSyncExternalStore)(
952
1151
  multiplayerStateManager.addListener,
953
1152
  multiplayerStateManager.getOptimisticState,
954
1153
  multiplayerStateManager.getOptimisticState
955
1154
  );
956
1155
  }
1156
+ function useEphemeralUserData(ephemeralUserData) {
1157
+ return (0, import_react6.useSyncExternalStore)(
1158
+ ephemeralUserData.addListener,
1159
+ ephemeralUserData.getSnapshot,
1160
+ ephemeralUserData.getSnapshot
1161
+ );
1162
+ }
957
1163
  var defaultStubSync = (0, import_state_manager.stubSync)();
958
1164
  function useMultiplayerState(initialState, options) {
959
1165
  const { sync = defaultStubSync, ...rest } = options ?? {};
960
- const [multiplayerStateManager] = (0, import_react5.useState)(
1166
+ const [multiplayerStateManager] = (0, import_react6.useState)(
961
1167
  () => new import_state_manager.MultiplayerStateManager(initialState, rest)
962
1168
  );
963
- const syncRef = (0, import_react5.useRef)(sync);
964
- const [connectionEvents, setConnectionEvents] = (0, import_react5.useState)();
965
- const [connectedUsers, setConnectedUsers] = (0, import_react5.useState)([]);
966
- const [tasks, setTasks] = (0, import_react5.useState)([]);
967
- const [userId, setUserId] = (0, import_react5.useState)();
968
- const extras = (0, import_react5.useMemo)(() => {
1169
+ const syncRef = (0, import_react6.useRef)(sync);
1170
+ const [connectionEvents, setConnectionEvents] = (0, import_react6.useState)();
1171
+ const [connectedUsers, setConnectedUsers] = (0, import_react6.useState)([]);
1172
+ const [ephemeralUserData] = (0, import_react6.useState)(
1173
+ () => new import_state_manager.EphemeralUserData()
1174
+ );
1175
+ const [tasks, setTasks] = (0, import_react6.useState)([]);
1176
+ const [userId, setUserId] = (0, import_react6.useState)();
1177
+ const extras = (0, import_react6.useMemo)(() => {
969
1178
  return {
970
1179
  tasks,
1180
+ userId,
971
1181
  connectionEvents,
972
- connectedUsers
1182
+ connectedUsers,
1183
+ ephemeralUserData
973
1184
  // evaluate: async (code: string) => {
974
1185
  // const payload = await rpcManager.request({ type: "eval", code });
975
1186
  // if (payload.type !== "eval") {
@@ -977,27 +1188,27 @@ function useMultiplayerState(initialState, options) {
977
1188
  // }
978
1189
  // },
979
1190
  };
980
- }, [tasks, connectionEvents, connectedUsers]);
1191
+ }, [tasks, connectionEvents, connectedUsers, ephemeralUserData, userId]);
981
1192
  const globalTrackEvents = useObservable(shouldTrackEvents$);
982
1193
  const globalTrackTasks = useObservable(shouldTrackTasks$);
983
1194
  const shouldTrackEvents = options?.trackConnectionEvents ?? globalTrackEvents;
984
1195
  const shouldTrackTasks = options?.trackTasks ?? globalTrackTasks;
985
- const trackEventsCallbackRef = (0, import_react5.useRef)();
986
- const trackConnectedUsersCallbackRef = (0, import_react5.useRef)();
987
- const trackTasksCallbackRef = (0, import_react5.useRef)();
988
- (0, import_react5.useEffect)(() => {
1196
+ const trackEventsCallbackRef = (0, import_react6.useRef)();
1197
+ const trackConnectedUsersCallbackRef = (0, import_react6.useRef)();
1198
+ const trackTasksCallbackRef = (0, import_react6.useRef)();
1199
+ (0, import_react6.useEffect)(() => {
989
1200
  trackEventsCallbackRef.current = shouldTrackEvents ? (e) => setConnectionEvents((events) => {
990
1201
  const updated = events ? [...events, e] : [e];
991
1202
  return updated.length > 50 ? updated.slice(-50) : updated;
992
1203
  }) : void 0;
993
1204
  }, [shouldTrackEvents]);
994
- (0, import_react5.useEffect)(() => {
1205
+ (0, import_react6.useEffect)(() => {
995
1206
  trackConnectedUsersCallbackRef.current = (users, userId2) => {
996
1207
  setConnectedUsers(users);
997
1208
  setUserId(userId2);
998
1209
  };
999
1210
  }, []);
1000
- (0, import_react5.useEffect)(() => {
1211
+ (0, import_react6.useEffect)(() => {
1001
1212
  trackTasksCallbackRef.current = shouldTrackTasks ? (tasks2) => {
1002
1213
  setTasks((old) => {
1003
1214
  const newIds = new Set(tasks2.map((t) => t.id));
@@ -1006,24 +1217,26 @@ function useMultiplayerState(initialState, options) {
1006
1217
  });
1007
1218
  } : void 0;
1008
1219
  }, [shouldTrackTasks]);
1009
- (0, import_react5.useEffect)(() => {
1220
+ (0, import_react6.useEffect)(() => {
1010
1221
  if (syncRef.current) {
1011
1222
  return syncRef.current({
1012
1223
  ms: multiplayerStateManager,
1224
+ ephemeralUserData,
1013
1225
  onConnectionEvent: (e) => trackEventsCallbackRef.current?.(e),
1014
1226
  onChangeConnectedUsers: (users, userId2) => trackConnectedUsersCallbackRef.current?.(users, userId2),
1015
1227
  onChangeTasks: (tasks2) => trackTasksCallbackRef.current?.(tasks2)
1016
1228
  });
1017
1229
  }
1018
- }, [multiplayerStateManager]);
1230
+ }, [ephemeralUserData, multiplayerStateManager]);
1019
1231
  const state = useSyncMultiplayerStateManager(multiplayerStateManager);
1020
- const forceInit = (0, import_react5.useCallback)(() => {
1232
+ const forceInit = (0, import_react6.useCallback)(() => {
1021
1233
  const state2 = typeof initialState === "function" ? initialState() : initialState;
1022
1234
  const schema = options?.schema;
1023
1235
  multiplayerStateManager.sm.clearHistory();
1024
1236
  multiplayerStateManager.sendInit({ force: true, state: state2, schema });
1025
1237
  }, [initialState, multiplayerStateManager, options?.schema]);
1026
1238
  useStateInspector({
1239
+ ephemeralUserData,
1027
1240
  multiplayerStateManager,
1028
1241
  state,
1029
1242
  connectionEvents,
@@ -1044,6 +1257,14 @@ function useMultiplayerState(initialState, options) {
1044
1257
  // Annotate the CommonJS export names for ESM import in node:
1045
1258
  0 && (module.exports = {
1046
1259
  StateInspector,
1260
+ UserNameTag,
1261
+ UserPointer,
1262
+ UserPointerContainer,
1263
+ UserPointerIcon,
1264
+ UserPointersOverlay,
1265
+ getAvatarInitials,
1266
+ getAvatarStyle,
1267
+ useEphemeralUserData,
1047
1268
  useManagedHistory,
1048
1269
  useManagedState,
1049
1270
  useMultiplayerState,