@liveblocks/react-ui 3.16.0-flow1 → 3.16.0-flow3

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.
@@ -8,6 +8,7 @@ var react$1 = require('react');
8
8
  var cn = require('../utils/cn.cjs');
9
9
  var cursorSpring = require('../utils/cursor-spring.cjs');
10
10
  var useRefs = require('../utils/use-refs.cjs');
11
+ var useStableComponent = require('../utils/use-stable-component.cjs');
11
12
  var useWindowFocus = require('../utils/use-window-focus.cjs');
12
13
  var Cursor = require('./Cursor.cjs');
13
14
 
@@ -21,19 +22,25 @@ function $coordinates(value) {
21
22
  }
22
23
  return void 0;
23
24
  }
25
+ function DefaultCursorWithUserInfo({ userId }) {
26
+ const { user, isLoading } = react.useUser(userId ?? "");
27
+ const color = $string(user?.color);
28
+ const name = $string(user?.name);
29
+ if (isLoading) {
30
+ return null;
31
+ }
32
+ return /* @__PURE__ */ jsxRuntime.jsx(Cursor.Cursor, { color, label: name });
33
+ }
24
34
  function PresenceCursor({
25
35
  connectionId,
26
36
  presenceKey,
27
37
  sizeRef,
28
- sizeEvents
38
+ sizeEvents,
39
+ Cursor: Cursor$1
29
40
  }) {
30
41
  const room = react.useRoom();
31
42
  const cursorRef = react$1.useRef(null);
32
43
  const userId = react.useOther(connectionId, (other) => $string(other.id));
33
- const { user, isLoading } = react.useUser(userId ?? "");
34
- const hasUserInfo = userId !== void 0 && !isLoading;
35
- const color = $string(user?.color);
36
- const name = $string(user?.name);
37
44
  _private.useLayoutEffect(() => {
38
45
  const spring = cursorSpring.makeCursorSpring();
39
46
  function update() {
@@ -42,7 +49,7 @@ function PresenceCursor({
42
49
  if (!element) {
43
50
  return;
44
51
  }
45
- if (!hasUserInfo || coordinates === null) {
52
+ if (coordinates === null) {
46
53
  element.style.transform = "translate3d(0, 0, 0)";
47
54
  element.style.display = "none";
48
55
  return;
@@ -66,19 +73,21 @@ function PresenceCursor({
66
73
  unsubscribeSize();
67
74
  unsubscribeOther();
68
75
  };
69
- }, [room, connectionId, presenceKey, sizeRef, sizeEvents, hasUserInfo]);
70
- return /* @__PURE__ */ jsxRuntime.jsx(
71
- Cursor.Cursor,
72
- {
73
- color,
74
- label: name,
75
- ref: cursorRef,
76
- style: { display: "none" }
77
- }
78
- );
76
+ }, [room, connectionId, presenceKey, sizeRef, sizeEvents]);
77
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { ref: cursorRef, style: { display: "none" }, children: userId ? /* @__PURE__ */ jsxRuntime.jsx(Cursor$1, { userId, connectionId }) : /* @__PURE__ */ jsxRuntime.jsx(Cursor.Cursor, {}) });
79
78
  }
80
79
  const Cursors = react$1.forwardRef(
81
- ({ className, children, presenceKey = DEFAULT_PRESENCE_KEY, ...props }, forwardedRef) => {
80
+ ({
81
+ className,
82
+ children,
83
+ presenceKey = DEFAULT_PRESENCE_KEY,
84
+ components,
85
+ ...props
86
+ }, forwardedRef) => {
87
+ const Cursor = useStableComponent.useStableComponent(
88
+ components?.Cursor,
89
+ DefaultCursorWithUserInfo
90
+ );
82
91
  const containerRef = react$1.useRef(null);
83
92
  const mergedRefs = useRefs.useRefs(forwardedRef, containerRef);
84
93
  const updateMyPresence = react.useUpdateMyPresence();
@@ -160,7 +169,8 @@ const Cursors = react$1.forwardRef(
160
169
  connectionId,
161
170
  presenceKey,
162
171
  sizeRef,
163
- sizeEvents
172
+ sizeEvents,
173
+ Cursor
164
174
  },
165
175
  connectionId
166
176
  )) }),
@@ -1 +1 @@
1
- {"version":3,"file":"Cursors.cjs","sources":["../../src/components/Cursors.tsx"],"sourcesContent":["import type { EventSource } from \"@liveblocks/core\";\nimport { isPlainObject, makeEventSource } from \"@liveblocks/core\";\nimport {\n useOther,\n useOthersConnectionIds,\n useRoom,\n useUpdateMyPresence,\n useUser,\n} from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n MutableRefObject,\n PointerEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"../utils/cn\";\nimport { makeCursorSpring } from \"../utils/cursor-spring\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Cursor } from \"./Cursor\";\n\nconst DEFAULT_PRESENCE_KEY = \"cursor\";\n\nexport interface CursorsProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The key used to store the cursors in users' Presence.\n * This can be used to have multiple `Cursors` in a single room.\n *\n * Defaults to `\"cursor\"`.\n */\n presenceKey?: string;\n}\n\ntype Coordinates = {\n x: number;\n y: number;\n};\n\ntype Size = {\n width: number;\n height: number;\n};\n\nfunction $string(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction $coordinates(value: unknown): Coordinates | undefined {\n if (\n isPlainObject(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n ) {\n return value as Coordinates;\n }\n\n return undefined;\n}\n\nfunction PresenceCursor({\n connectionId,\n presenceKey,\n sizeRef,\n sizeEvents,\n}: {\n connectionId: number;\n presenceKey: string;\n sizeRef: MutableRefObject<Size | null>;\n sizeEvents: EventSource<void>;\n}) {\n const room = useRoom();\n const cursorRef = useRef<HTMLDivElement>(null);\n const userId = useOther(connectionId, (other) => $string(other.id));\n const { user, isLoading } = useUser(userId ?? \"\");\n const hasUserInfo = userId !== undefined && !isLoading;\n const color = $string(user?.color);\n const name = $string(user?.name);\n\n useLayoutEffect(() => {\n const spring = makeCursorSpring();\n\n function update() {\n const element = cursorRef.current;\n const coordinates = spring.get();\n\n if (!element) {\n return;\n }\n\n if (!hasUserInfo || coordinates === null) {\n element.style.transform = \"translate3d(0, 0, 0)\";\n element.style.display = \"none\";\n return;\n }\n\n if (sizeRef.current) {\n element.style.transform = `translate3d(${coordinates.x * sizeRef.current.width}px, ${coordinates.y * sizeRef.current.height}px, 0)`;\n }\n\n element.style.display = \"\";\n }\n\n const unsubscribeSpring = spring.subscribe(update);\n const unsubscribeSize = sizeEvents.subscribe(update);\n update();\n\n const unsubscribeOther = room.events.others.subscribe(({ others }) => {\n const other = others.find((other) => other.connectionId === connectionId);\n const cursor = $coordinates(other?.presence[presenceKey]);\n\n spring.set(cursor ?? null);\n });\n\n return () => {\n spring.dispose();\n unsubscribeSpring();\n unsubscribeSize();\n unsubscribeOther();\n };\n }, [room, connectionId, presenceKey, sizeRef, sizeEvents, hasUserInfo]);\n\n return (\n <Cursor\n color={color}\n label={name}\n ref={cursorRef}\n style={{ display: \"none\" }}\n />\n );\n}\n\n/**\n * Displays multiplayer cursors.\n */\nexport const Cursors = forwardRef<HTMLDivElement, CursorsProps>(\n (\n { className, children, presenceKey = DEFAULT_PRESENCE_KEY, ...props },\n forwardedRef\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, containerRef);\n const updateMyPresence = useUpdateMyPresence();\n const othersConnectionIds = useOthersConnectionIds();\n const sizeRef = useRef<Size | null>(null);\n const [sizeEvents] = useState(() => makeEventSource<void>());\n const isWindowFocused = useWindowFocus();\n\n useEffect(() => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n function setSize(size: Size) {\n sizeRef.current = size;\n sizeEvents.notify();\n }\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === container) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }\n });\n\n setSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [sizeEvents]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n const bounds = container.getBoundingClientRect();\n\n if (bounds.width === 0 || bounds.height === 0) {\n return;\n }\n\n updateMyPresence({\n [presenceKey]: {\n x: (event.clientX - bounds.left) / bounds.width,\n y: (event.clientY - bounds.top) / bounds.height,\n },\n });\n },\n [updateMyPresence, presenceKey]\n );\n\n const handlePointerLeave = useCallback(() => {\n updateMyPresence({\n [presenceKey]: null,\n });\n }, [updateMyPresence, presenceKey]);\n\n useEffect(() => {\n if (!isWindowFocused) {\n updateMyPresence({\n [presenceKey]: null,\n });\n }\n }, [isWindowFocused, updateMyPresence, presenceKey]);\n\n return (\n <div\n className={cn(\"lb-root lb-cursors\", className)}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerLeave={handlePointerLeave}\n ref={mergedRefs}\n >\n <div className=\"lb-cursors-container\">\n {othersConnectionIds.map((connectionId) => (\n <PresenceCursor\n key={connectionId}\n connectionId={connectionId}\n presenceKey={presenceKey}\n sizeRef={sizeRef}\n sizeEvents={sizeEvents}\n />\n ))}\n </div>\n\n {children}\n </div>\n );\n }\n);\n"],"names":["isPlainObject","useRoom","useRef","useOther","useUser","useLayoutEffect","makeCursorSpring","other","jsx","Cursor","forwardRef","useRefs","useUpdateMyPresence","useOthersConnectionIds","useState","makeEventSource","useWindowFocus","useEffect","useCallback","jsxs","cn"],"mappings":"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"}
1
+ {"version":3,"file":"Cursors.cjs","sources":["../../src/components/Cursors.tsx"],"sourcesContent":["import type { EventSource } from \"@liveblocks/core\";\nimport { isPlainObject, makeEventSource } from \"@liveblocks/core\";\nimport {\n useOther,\n useOthersConnectionIds,\n useRoom,\n useUpdateMyPresence,\n useUser,\n} from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n MutableRefObject,\n PointerEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { cn } from \"../utils/cn\";\nimport { makeCursorSpring } from \"../utils/cursor-spring\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useStableComponent } from \"../utils/use-stable-component\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Cursor as DefaultCursor } from \"./Cursor\";\n\nconst DEFAULT_PRESENCE_KEY = \"cursor\";\n\nexport interface CursorsCursorProps {\n /**\n * The user ID for this cursor.\n */\n userId: string;\n\n /**\n * The connection ID for this cursor.\n */\n connectionId: number;\n}\n\ninterface CursorsComponents {\n /**\n * The component used to display each cursor.\n */\n Cursor: ComponentType<CursorsCursorProps>;\n}\n\nexport interface CursorsProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The key used to store the cursors in users' Presence.\n * This can be used to have multiple `Cursors` in a single room.\n *\n * Defaults to `\"cursor\"`.\n */\n presenceKey?: string;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & CursorsComponents>;\n}\n\ntype Coordinates = {\n x: number;\n y: number;\n};\n\ntype Size = {\n width: number;\n height: number;\n};\n\nfunction $string(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction $coordinates(value: unknown): Coordinates | undefined {\n if (\n isPlainObject(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n ) {\n return value as Coordinates;\n }\n\n return undefined;\n}\n\nfunction DefaultCursorWithUserInfo({ userId }: CursorsCursorProps) {\n const { user, isLoading } = useUser(userId ?? \"\");\n const color = $string(user?.color);\n const name = $string(user?.name);\n\n if (isLoading) {\n return null;\n }\n\n return <DefaultCursor color={color} label={name} />;\n}\n\nfunction PresenceCursor({\n connectionId,\n presenceKey,\n sizeRef,\n sizeEvents,\n Cursor,\n}: {\n connectionId: number;\n presenceKey: string;\n sizeRef: MutableRefObject<Size | null>;\n sizeEvents: EventSource<void>;\n Cursor: ComponentType<CursorsCursorProps>;\n}) {\n const room = useRoom();\n const cursorRef = useRef<HTMLDivElement>(null);\n const userId = useOther(connectionId, (other) => $string(other.id));\n\n useLayoutEffect(() => {\n const spring = makeCursorSpring();\n\n function update() {\n const element = cursorRef.current;\n const coordinates = spring.get();\n\n if (!element) {\n return;\n }\n\n if (coordinates === null) {\n element.style.transform = \"translate3d(0, 0, 0)\";\n element.style.display = \"none\";\n return;\n }\n\n if (sizeRef.current) {\n element.style.transform = `translate3d(${coordinates.x * sizeRef.current.width}px, ${coordinates.y * sizeRef.current.height}px, 0)`;\n }\n\n element.style.display = \"\";\n }\n\n const unsubscribeSpring = spring.subscribe(update);\n const unsubscribeSize = sizeEvents.subscribe(update);\n update();\n\n const unsubscribeOther = room.events.others.subscribe(({ others }) => {\n const other = others.find((other) => other.connectionId === connectionId);\n const cursor = $coordinates(other?.presence[presenceKey]);\n\n spring.set(cursor ?? null);\n });\n\n return () => {\n spring.dispose();\n unsubscribeSpring();\n unsubscribeSize();\n unsubscribeOther();\n };\n }, [room, connectionId, presenceKey, sizeRef, sizeEvents]);\n\n return (\n <div ref={cursorRef} style={{ display: \"none\" }}>\n {userId ? (\n <Cursor userId={userId} connectionId={connectionId} />\n ) : (\n <DefaultCursor />\n )}\n </div>\n );\n}\n\n/**\n * Displays multiplayer cursors.\n */\nexport const Cursors = forwardRef<HTMLDivElement, CursorsProps>(\n (\n {\n className,\n children,\n presenceKey = DEFAULT_PRESENCE_KEY,\n components,\n ...props\n },\n forwardedRef\n ) => {\n const Cursor = useStableComponent(\n components?.Cursor,\n DefaultCursorWithUserInfo\n );\n const containerRef = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, containerRef);\n const updateMyPresence = useUpdateMyPresence();\n const othersConnectionIds = useOthersConnectionIds();\n const sizeRef = useRef<Size | null>(null);\n const [sizeEvents] = useState(() => makeEventSource<void>());\n const isWindowFocused = useWindowFocus();\n\n useEffect(() => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n function setSize(size: Size) {\n sizeRef.current = size;\n sizeEvents.notify();\n }\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === container) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }\n });\n\n setSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [sizeEvents]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n const bounds = container.getBoundingClientRect();\n\n if (bounds.width === 0 || bounds.height === 0) {\n return;\n }\n\n updateMyPresence({\n [presenceKey]: {\n x: (event.clientX - bounds.left) / bounds.width,\n y: (event.clientY - bounds.top) / bounds.height,\n },\n });\n },\n [updateMyPresence, presenceKey]\n );\n\n const handlePointerLeave = useCallback(() => {\n updateMyPresence({\n [presenceKey]: null,\n });\n }, [updateMyPresence, presenceKey]);\n\n useEffect(() => {\n if (!isWindowFocused) {\n updateMyPresence({\n [presenceKey]: null,\n });\n }\n }, [isWindowFocused, updateMyPresence, presenceKey]);\n\n return (\n <div\n className={cn(\"lb-root lb-cursors\", className)}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerLeave={handlePointerLeave}\n ref={mergedRefs}\n >\n <div className=\"lb-cursors-container\">\n {othersConnectionIds.map((connectionId) => (\n <PresenceCursor\n key={connectionId}\n connectionId={connectionId}\n presenceKey={presenceKey}\n sizeRef={sizeRef}\n sizeEvents={sizeEvents}\n Cursor={Cursor}\n />\n ))}\n </div>\n\n {children}\n </div>\n );\n }\n);\n"],"names":["isPlainObject","useUser","jsx","DefaultCursor","Cursor","useRoom","useRef","useOther","useLayoutEffect","makeCursorSpring","other","forwardRef","useStableComponent","useRefs","useUpdateMyPresence","useOthersConnectionIds","useState","makeEventSource","useWindowFocus","useEffect","useCallback","jsxs","cn"],"mappings":"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"}
@@ -1,11 +1,12 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import { isPlainObject, makeEventSource } from '@liveblocks/core';
3
- import { useRoom, useOther, useUser, useUpdateMyPresence, useOthersConnectionIds } from '@liveblocks/react';
3
+ import { useUser, useRoom, useOther, useUpdateMyPresence, useOthersConnectionIds } from '@liveblocks/react';
4
4
  import { useLayoutEffect } from '@liveblocks/react/_private';
5
5
  import { useRef, forwardRef, useState, useEffect, useCallback } from 'react';
6
6
  import { cn } from '../utils/cn.js';
7
7
  import { makeCursorSpring } from '../utils/cursor-spring.js';
8
8
  import { useRefs } from '../utils/use-refs.js';
9
+ import { useStableComponent } from '../utils/use-stable-component.js';
9
10
  import { useWindowFocus } from '../utils/use-window-focus.js';
10
11
  import { Cursor } from './Cursor.js';
11
12
 
@@ -19,19 +20,25 @@ function $coordinates(value) {
19
20
  }
20
21
  return void 0;
21
22
  }
23
+ function DefaultCursorWithUserInfo({ userId }) {
24
+ const { user, isLoading } = useUser(userId ?? "");
25
+ const color = $string(user?.color);
26
+ const name = $string(user?.name);
27
+ if (isLoading) {
28
+ return null;
29
+ }
30
+ return /* @__PURE__ */ jsx(Cursor, { color, label: name });
31
+ }
22
32
  function PresenceCursor({
23
33
  connectionId,
24
34
  presenceKey,
25
35
  sizeRef,
26
- sizeEvents
36
+ sizeEvents,
37
+ Cursor: Cursor$1
27
38
  }) {
28
39
  const room = useRoom();
29
40
  const cursorRef = useRef(null);
30
41
  const userId = useOther(connectionId, (other) => $string(other.id));
31
- const { user, isLoading } = useUser(userId ?? "");
32
- const hasUserInfo = userId !== void 0 && !isLoading;
33
- const color = $string(user?.color);
34
- const name = $string(user?.name);
35
42
  useLayoutEffect(() => {
36
43
  const spring = makeCursorSpring();
37
44
  function update() {
@@ -40,7 +47,7 @@ function PresenceCursor({
40
47
  if (!element) {
41
48
  return;
42
49
  }
43
- if (!hasUserInfo || coordinates === null) {
50
+ if (coordinates === null) {
44
51
  element.style.transform = "translate3d(0, 0, 0)";
45
52
  element.style.display = "none";
46
53
  return;
@@ -64,19 +71,21 @@ function PresenceCursor({
64
71
  unsubscribeSize();
65
72
  unsubscribeOther();
66
73
  };
67
- }, [room, connectionId, presenceKey, sizeRef, sizeEvents, hasUserInfo]);
68
- return /* @__PURE__ */ jsx(
69
- Cursor,
70
- {
71
- color,
72
- label: name,
73
- ref: cursorRef,
74
- style: { display: "none" }
75
- }
76
- );
74
+ }, [room, connectionId, presenceKey, sizeRef, sizeEvents]);
75
+ return /* @__PURE__ */ jsx("div", { ref: cursorRef, style: { display: "none" }, children: userId ? /* @__PURE__ */ jsx(Cursor$1, { userId, connectionId }) : /* @__PURE__ */ jsx(Cursor, {}) });
77
76
  }
78
77
  const Cursors = forwardRef(
79
- ({ className, children, presenceKey = DEFAULT_PRESENCE_KEY, ...props }, forwardedRef) => {
78
+ ({
79
+ className,
80
+ children,
81
+ presenceKey = DEFAULT_PRESENCE_KEY,
82
+ components,
83
+ ...props
84
+ }, forwardedRef) => {
85
+ const Cursor = useStableComponent(
86
+ components?.Cursor,
87
+ DefaultCursorWithUserInfo
88
+ );
80
89
  const containerRef = useRef(null);
81
90
  const mergedRefs = useRefs(forwardedRef, containerRef);
82
91
  const updateMyPresence = useUpdateMyPresence();
@@ -158,7 +167,8 @@ const Cursors = forwardRef(
158
167
  connectionId,
159
168
  presenceKey,
160
169
  sizeRef,
161
- sizeEvents
170
+ sizeEvents,
171
+ Cursor
162
172
  },
163
173
  connectionId
164
174
  )) }),
@@ -1 +1 @@
1
- {"version":3,"file":"Cursors.js","sources":["../../src/components/Cursors.tsx"],"sourcesContent":["import type { EventSource } from \"@liveblocks/core\";\nimport { isPlainObject, makeEventSource } from \"@liveblocks/core\";\nimport {\n useOther,\n useOthersConnectionIds,\n useRoom,\n useUpdateMyPresence,\n useUser,\n} from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n MutableRefObject,\n PointerEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n\nimport { cn } from \"../utils/cn\";\nimport { makeCursorSpring } from \"../utils/cursor-spring\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Cursor } from \"./Cursor\";\n\nconst DEFAULT_PRESENCE_KEY = \"cursor\";\n\nexport interface CursorsProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The key used to store the cursors in users' Presence.\n * This can be used to have multiple `Cursors` in a single room.\n *\n * Defaults to `\"cursor\"`.\n */\n presenceKey?: string;\n}\n\ntype Coordinates = {\n x: number;\n y: number;\n};\n\ntype Size = {\n width: number;\n height: number;\n};\n\nfunction $string(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction $coordinates(value: unknown): Coordinates | undefined {\n if (\n isPlainObject(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n ) {\n return value as Coordinates;\n }\n\n return undefined;\n}\n\nfunction PresenceCursor({\n connectionId,\n presenceKey,\n sizeRef,\n sizeEvents,\n}: {\n connectionId: number;\n presenceKey: string;\n sizeRef: MutableRefObject<Size | null>;\n sizeEvents: EventSource<void>;\n}) {\n const room = useRoom();\n const cursorRef = useRef<HTMLDivElement>(null);\n const userId = useOther(connectionId, (other) => $string(other.id));\n const { user, isLoading } = useUser(userId ?? \"\");\n const hasUserInfo = userId !== undefined && !isLoading;\n const color = $string(user?.color);\n const name = $string(user?.name);\n\n useLayoutEffect(() => {\n const spring = makeCursorSpring();\n\n function update() {\n const element = cursorRef.current;\n const coordinates = spring.get();\n\n if (!element) {\n return;\n }\n\n if (!hasUserInfo || coordinates === null) {\n element.style.transform = \"translate3d(0, 0, 0)\";\n element.style.display = \"none\";\n return;\n }\n\n if (sizeRef.current) {\n element.style.transform = `translate3d(${coordinates.x * sizeRef.current.width}px, ${coordinates.y * sizeRef.current.height}px, 0)`;\n }\n\n element.style.display = \"\";\n }\n\n const unsubscribeSpring = spring.subscribe(update);\n const unsubscribeSize = sizeEvents.subscribe(update);\n update();\n\n const unsubscribeOther = room.events.others.subscribe(({ others }) => {\n const other = others.find((other) => other.connectionId === connectionId);\n const cursor = $coordinates(other?.presence[presenceKey]);\n\n spring.set(cursor ?? null);\n });\n\n return () => {\n spring.dispose();\n unsubscribeSpring();\n unsubscribeSize();\n unsubscribeOther();\n };\n }, [room, connectionId, presenceKey, sizeRef, sizeEvents, hasUserInfo]);\n\n return (\n <Cursor\n color={color}\n label={name}\n ref={cursorRef}\n style={{ display: \"none\" }}\n />\n );\n}\n\n/**\n * Displays multiplayer cursors.\n */\nexport const Cursors = forwardRef<HTMLDivElement, CursorsProps>(\n (\n { className, children, presenceKey = DEFAULT_PRESENCE_KEY, ...props },\n forwardedRef\n ) => {\n const containerRef = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, containerRef);\n const updateMyPresence = useUpdateMyPresence();\n const othersConnectionIds = useOthersConnectionIds();\n const sizeRef = useRef<Size | null>(null);\n const [sizeEvents] = useState(() => makeEventSource<void>());\n const isWindowFocused = useWindowFocus();\n\n useEffect(() => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n function setSize(size: Size) {\n sizeRef.current = size;\n sizeEvents.notify();\n }\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === container) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }\n });\n\n setSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [sizeEvents]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n const bounds = container.getBoundingClientRect();\n\n if (bounds.width === 0 || bounds.height === 0) {\n return;\n }\n\n updateMyPresence({\n [presenceKey]: {\n x: (event.clientX - bounds.left) / bounds.width,\n y: (event.clientY - bounds.top) / bounds.height,\n },\n });\n },\n [updateMyPresence, presenceKey]\n );\n\n const handlePointerLeave = useCallback(() => {\n updateMyPresence({\n [presenceKey]: null,\n });\n }, [updateMyPresence, presenceKey]);\n\n useEffect(() => {\n if (!isWindowFocused) {\n updateMyPresence({\n [presenceKey]: null,\n });\n }\n }, [isWindowFocused, updateMyPresence, presenceKey]);\n\n return (\n <div\n className={cn(\"lb-root lb-cursors\", className)}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerLeave={handlePointerLeave}\n ref={mergedRefs}\n >\n <div className=\"lb-cursors-container\">\n {othersConnectionIds.map((connectionId) => (\n <PresenceCursor\n key={connectionId}\n connectionId={connectionId}\n presenceKey={presenceKey}\n sizeRef={sizeRef}\n sizeEvents={sizeEvents}\n />\n ))}\n </div>\n\n {children}\n </div>\n );\n }\n);\n"],"names":["other"],"mappings":"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"}
1
+ {"version":3,"file":"Cursors.js","sources":["../../src/components/Cursors.tsx"],"sourcesContent":["import type { EventSource } from \"@liveblocks/core\";\nimport { isPlainObject, makeEventSource } from \"@liveblocks/core\";\nimport {\n useOther,\n useOthersConnectionIds,\n useRoom,\n useUpdateMyPresence,\n useUser,\n} from \"@liveblocks/react\";\nimport { useLayoutEffect } from \"@liveblocks/react/_private\";\nimport type {\n ComponentPropsWithoutRef,\n ComponentType,\n MutableRefObject,\n PointerEvent,\n} from \"react\";\nimport { forwardRef, useCallback, useEffect, useRef, useState } from \"react\";\n\nimport type { GlobalComponents } from \"../components\";\nimport { cn } from \"../utils/cn\";\nimport { makeCursorSpring } from \"../utils/cursor-spring\";\nimport { useRefs } from \"../utils/use-refs\";\nimport { useStableComponent } from \"../utils/use-stable-component\";\nimport { useWindowFocus } from \"../utils/use-window-focus\";\nimport { Cursor as DefaultCursor } from \"./Cursor\";\n\nconst DEFAULT_PRESENCE_KEY = \"cursor\";\n\nexport interface CursorsCursorProps {\n /**\n * The user ID for this cursor.\n */\n userId: string;\n\n /**\n * The connection ID for this cursor.\n */\n connectionId: number;\n}\n\ninterface CursorsComponents {\n /**\n * The component used to display each cursor.\n */\n Cursor: ComponentType<CursorsCursorProps>;\n}\n\nexport interface CursorsProps extends ComponentPropsWithoutRef<\"div\"> {\n /**\n * The key used to store the cursors in users' Presence.\n * This can be used to have multiple `Cursors` in a single room.\n *\n * Defaults to `\"cursor\"`.\n */\n presenceKey?: string;\n\n /**\n * Override the component's components.\n */\n components?: Partial<GlobalComponents & CursorsComponents>;\n}\n\ntype Coordinates = {\n x: number;\n y: number;\n};\n\ntype Size = {\n width: number;\n height: number;\n};\n\nfunction $string(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction $coordinates(value: unknown): Coordinates | undefined {\n if (\n isPlainObject(value) &&\n typeof value.x === \"number\" &&\n typeof value.y === \"number\"\n ) {\n return value as Coordinates;\n }\n\n return undefined;\n}\n\nfunction DefaultCursorWithUserInfo({ userId }: CursorsCursorProps) {\n const { user, isLoading } = useUser(userId ?? \"\");\n const color = $string(user?.color);\n const name = $string(user?.name);\n\n if (isLoading) {\n return null;\n }\n\n return <DefaultCursor color={color} label={name} />;\n}\n\nfunction PresenceCursor({\n connectionId,\n presenceKey,\n sizeRef,\n sizeEvents,\n Cursor,\n}: {\n connectionId: number;\n presenceKey: string;\n sizeRef: MutableRefObject<Size | null>;\n sizeEvents: EventSource<void>;\n Cursor: ComponentType<CursorsCursorProps>;\n}) {\n const room = useRoom();\n const cursorRef = useRef<HTMLDivElement>(null);\n const userId = useOther(connectionId, (other) => $string(other.id));\n\n useLayoutEffect(() => {\n const spring = makeCursorSpring();\n\n function update() {\n const element = cursorRef.current;\n const coordinates = spring.get();\n\n if (!element) {\n return;\n }\n\n if (coordinates === null) {\n element.style.transform = \"translate3d(0, 0, 0)\";\n element.style.display = \"none\";\n return;\n }\n\n if (sizeRef.current) {\n element.style.transform = `translate3d(${coordinates.x * sizeRef.current.width}px, ${coordinates.y * sizeRef.current.height}px, 0)`;\n }\n\n element.style.display = \"\";\n }\n\n const unsubscribeSpring = spring.subscribe(update);\n const unsubscribeSize = sizeEvents.subscribe(update);\n update();\n\n const unsubscribeOther = room.events.others.subscribe(({ others }) => {\n const other = others.find((other) => other.connectionId === connectionId);\n const cursor = $coordinates(other?.presence[presenceKey]);\n\n spring.set(cursor ?? null);\n });\n\n return () => {\n spring.dispose();\n unsubscribeSpring();\n unsubscribeSize();\n unsubscribeOther();\n };\n }, [room, connectionId, presenceKey, sizeRef, sizeEvents]);\n\n return (\n <div ref={cursorRef} style={{ display: \"none\" }}>\n {userId ? (\n <Cursor userId={userId} connectionId={connectionId} />\n ) : (\n <DefaultCursor />\n )}\n </div>\n );\n}\n\n/**\n * Displays multiplayer cursors.\n */\nexport const Cursors = forwardRef<HTMLDivElement, CursorsProps>(\n (\n {\n className,\n children,\n presenceKey = DEFAULT_PRESENCE_KEY,\n components,\n ...props\n },\n forwardedRef\n ) => {\n const Cursor = useStableComponent(\n components?.Cursor,\n DefaultCursorWithUserInfo\n );\n const containerRef = useRef<HTMLDivElement>(null);\n const mergedRefs = useRefs(forwardedRef, containerRef);\n const updateMyPresence = useUpdateMyPresence();\n const othersConnectionIds = useOthersConnectionIds();\n const sizeRef = useRef<Size | null>(null);\n const [sizeEvents] = useState(() => makeEventSource<void>());\n const isWindowFocused = useWindowFocus();\n\n useEffect(() => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n function setSize(size: Size) {\n sizeRef.current = size;\n sizeEvents.notify();\n }\n\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n if (entry.target === container) {\n setSize({\n width: entry.contentRect.width,\n height: entry.contentRect.height,\n });\n }\n }\n });\n\n setSize({\n width: container.clientWidth,\n height: container.clientHeight,\n });\n\n observer.observe(container);\n\n return () => {\n observer.disconnect();\n };\n }, [sizeEvents]);\n\n const handlePointerMove = useCallback(\n (event: PointerEvent) => {\n const container = containerRef.current;\n\n if (!container) {\n return;\n }\n\n const bounds = container.getBoundingClientRect();\n\n if (bounds.width === 0 || bounds.height === 0) {\n return;\n }\n\n updateMyPresence({\n [presenceKey]: {\n x: (event.clientX - bounds.left) / bounds.width,\n y: (event.clientY - bounds.top) / bounds.height,\n },\n });\n },\n [updateMyPresence, presenceKey]\n );\n\n const handlePointerLeave = useCallback(() => {\n updateMyPresence({\n [presenceKey]: null,\n });\n }, [updateMyPresence, presenceKey]);\n\n useEffect(() => {\n if (!isWindowFocused) {\n updateMyPresence({\n [presenceKey]: null,\n });\n }\n }, [isWindowFocused, updateMyPresence, presenceKey]);\n\n return (\n <div\n className={cn(\"lb-root lb-cursors\", className)}\n {...props}\n onPointerMove={handlePointerMove}\n onPointerLeave={handlePointerLeave}\n ref={mergedRefs}\n >\n <div className=\"lb-cursors-container\">\n {othersConnectionIds.map((connectionId) => (\n <PresenceCursor\n key={connectionId}\n connectionId={connectionId}\n presenceKey={presenceKey}\n sizeRef={sizeRef}\n sizeEvents={sizeEvents}\n Cursor={Cursor}\n />\n ))}\n </div>\n\n {children}\n </div>\n );\n }\n);\n"],"names":["DefaultCursor","Cursor","other"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n AiChatComponents,\n AiChatComponentsEmptyProps,\n AiChatComponentsLoadingProps,\n AiChatProps,\n} from \"./components/AiChat\";\nexport { AiChat } from \"./components/AiChat\";\nexport type { AiToolIconProps, AiToolProps } from \"./components/AiTool\";\nexport { AiTool } from \"./components/AiTool\";\nexport type { AvatarStackProps } from \"./components/AvatarStack\";\nexport { AvatarStack } from \"./components/AvatarStack\";\nexport type {\n CommentAuthorProps,\n CommentAvatarProps,\n CommentDateProps,\n CommentDropdownItemProps,\n CommentProps,\n} from \"./components/Comment\";\nexport { Comment } from \"./components/Comment\";\nexport type { CommentPinProps } from \"./components/CommentPin\";\nexport { CommentPin } from \"./components/CommentPin\";\nexport type { ComposerProps } from \"./components/Composer\";\nexport { Composer } from \"./components/Composer\";\nexport type { CursorProps } from \"./components/Cursor\";\nexport { Cursor } from \"./components/Cursor\";\nexport type { CursorsProps } from \"./components/Cursors\";\nexport { Cursors } from \"./components/Cursors\";\nexport type { FloatingComposerProps } from \"./components/FloatingComposer\";\nexport { FloatingComposer } from \"./components/FloatingComposer\";\nexport type { FloatingThreadProps } from \"./components/FloatingThread\";\nexport { FloatingThread } from \"./components/FloatingThread\";\nexport type { HistoryVersionSummaryProps } from \"./components/HistoryVersionSummary\";\nexport { HistoryVersionSummary } from \"./components/HistoryVersionSummary\";\nexport type { HistoryVersionSummaryListProps } from \"./components/HistoryVersionSummaryList\";\nexport { HistoryVersionSummaryList } from \"./components/HistoryVersionSummaryList\";\nexport type {\n InboxNotificationAvatarProps,\n InboxNotificationCustomKindProps,\n InboxNotificationCustomProps,\n InboxNotificationIconProps,\n InboxNotificationInspectorProps,\n InboxNotificationProps,\n InboxNotificationTextMentionKindProps,\n InboxNotificationTextMentionProps,\n InboxNotificationThreadKindProps,\n InboxNotificationThreadProps,\n} from \"./components/InboxNotification\";\nexport { InboxNotification } from \"./components/InboxNotification\";\nexport type { InboxNotificationListProps } from \"./components/InboxNotificationList\";\nexport { InboxNotificationList } from \"./components/InboxNotificationList\";\nexport type { ThreadProps } from \"./components/Thread\";\nexport { Thread } from \"./components/Thread\";\nexport { LiveblocksUiConfig } from \"./config\";\nexport * as Icon from \"./icon\";\nexport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n LocalizationOverrides,\n Overrides,\n ThreadOverrides,\n} from \"./overrides\";\nexport { useOverrides } from \"./overrides\";\nexport type {\n AiComposerSubmitMessage,\n ComposerSubmitComment,\n} from \"./primitives\";\nexport type {\n CommentAttachmentArgs,\n ComposerBodyMark,\n ComposerBodyMarks,\n} from \"./types\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n AiChatComponents,\n AiChatComponentsEmptyProps,\n AiChatComponentsLoadingProps,\n AiChatProps,\n} from \"./components/AiChat\";\nexport { AiChat } from \"./components/AiChat\";\nexport type { AiToolIconProps, AiToolProps } from \"./components/AiTool\";\nexport { AiTool } from \"./components/AiTool\";\nexport type { AvatarStackProps } from \"./components/AvatarStack\";\nexport { AvatarStack } from \"./components/AvatarStack\";\nexport type {\n CommentAuthorProps,\n CommentAvatarProps,\n CommentDateProps,\n CommentDropdownItemProps,\n CommentProps,\n} from \"./components/Comment\";\nexport { Comment } from \"./components/Comment\";\nexport type { CommentPinProps } from \"./components/CommentPin\";\nexport { CommentPin } from \"./components/CommentPin\";\nexport type { ComposerProps } from \"./components/Composer\";\nexport { Composer } from \"./components/Composer\";\nexport type { CursorProps } from \"./components/Cursor\";\nexport { Cursor } from \"./components/Cursor\";\nexport type { CursorsCursorProps, CursorsProps } from \"./components/Cursors\";\nexport { Cursors } from \"./components/Cursors\";\nexport type { FloatingComposerProps } from \"./components/FloatingComposer\";\nexport { FloatingComposer } from \"./components/FloatingComposer\";\nexport type { FloatingThreadProps } from \"./components/FloatingThread\";\nexport { FloatingThread } from \"./components/FloatingThread\";\nexport type { HistoryVersionSummaryProps } from \"./components/HistoryVersionSummary\";\nexport { HistoryVersionSummary } from \"./components/HistoryVersionSummary\";\nexport type { HistoryVersionSummaryListProps } from \"./components/HistoryVersionSummaryList\";\nexport { HistoryVersionSummaryList } from \"./components/HistoryVersionSummaryList\";\nexport type {\n InboxNotificationAvatarProps,\n InboxNotificationCustomKindProps,\n InboxNotificationCustomProps,\n InboxNotificationIconProps,\n InboxNotificationInspectorProps,\n InboxNotificationProps,\n InboxNotificationTextMentionKindProps,\n InboxNotificationTextMentionProps,\n InboxNotificationThreadKindProps,\n InboxNotificationThreadProps,\n} from \"./components/InboxNotification\";\nexport { InboxNotification } from \"./components/InboxNotification\";\nexport type { InboxNotificationListProps } from \"./components/InboxNotificationList\";\nexport { InboxNotificationList } from \"./components/InboxNotificationList\";\nexport type { ThreadProps } from \"./components/Thread\";\nexport { Thread } from \"./components/Thread\";\nexport { LiveblocksUiConfig } from \"./config\";\nexport * as Icon from \"./icon\";\nexport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n LocalizationOverrides,\n Overrides,\n ThreadOverrides,\n} from \"./overrides\";\nexport { useOverrides } from \"./overrides\";\nexport type {\n AiComposerSubmitMessage,\n ComposerSubmitComment,\n} from \"./primitives\";\nexport type {\n CommentAttachmentArgs,\n ComposerBodyMark,\n ComposerBodyMarks,\n} from \"./types\";\n"],"names":["detectDupes","PKG_NAME","PKG_VERSION","PKG_FORMAT"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAIAA,gBAAY,CAAAC,gBAAA,EAAUC,qBAAaC,kBAAU,CAAA;;;;;;;;;;;;;;;;;;;;;"}
package/dist/index.d.cts CHANGED
@@ -1259,6 +1259,22 @@ interface CursorProps extends ComponentPropsWithoutRef<"div"> {
1259
1259
  */
1260
1260
  declare const Cursor: react.ForwardRefExoticComponent<CursorProps & react.RefAttributes<HTMLDivElement>>;
1261
1261
 
1262
+ interface CursorsCursorProps {
1263
+ /**
1264
+ * The user ID for this cursor.
1265
+ */
1266
+ userId: string;
1267
+ /**
1268
+ * The connection ID for this cursor.
1269
+ */
1270
+ connectionId: number;
1271
+ }
1272
+ interface CursorsComponents {
1273
+ /**
1274
+ * The component used to display each cursor.
1275
+ */
1276
+ Cursor: ComponentType<CursorsCursorProps>;
1277
+ }
1262
1278
  interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
1263
1279
  /**
1264
1280
  * The key used to store the cursors in users' Presence.
@@ -1267,6 +1283,10 @@ interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
1267
1283
  * Defaults to `"cursor"`.
1268
1284
  */
1269
1285
  presenceKey?: string;
1286
+ /**
1287
+ * Override the component's components.
1288
+ */
1289
+ components?: Partial<GlobalComponents & CursorsComponents>;
1270
1290
  }
1271
1291
  /**
1272
1292
  * Displays multiplayer cursors.
@@ -1829,4 +1849,4 @@ declare namespace icon {
1829
1849
  };
1830
1850
  }
1831
1851
 
1832
- export { AiChat, AiChatComponents, AiChatComponentsEmptyProps, AiChatComponentsLoadingProps, AiChatProps, AiComposerSubmitMessage, AiTool, AiToolIconProps, AiToolProps, AvatarStack, AvatarStackProps, Comment, CommentAttachmentArgs, CommentAuthorProps, CommentAvatarProps, CommentDateProps, CommentDropdownItemProps, CommentOverrides, CommentPin, CommentPinProps, CommentProps, Composer, ComposerBodyMark, ComposerBodyMarks, ComposerOverrides, ComposerProps, ComposerSubmitComment, Cursor, CursorProps, Cursors, CursorsProps, FloatingComposer, FloatingComposerProps, FloatingThread, FloatingThreadProps, GlobalOverrides, HistoryVersionSummary, HistoryVersionSummaryList, HistoryVersionSummaryListProps, HistoryVersionSummaryProps, icon as Icon, InboxNotification, InboxNotificationAvatarProps, InboxNotificationCustomKindProps, InboxNotificationCustomProps, InboxNotificationIconProps, InboxNotificationInspectorProps, InboxNotificationList, InboxNotificationListProps, InboxNotificationOverrides, InboxNotificationProps, InboxNotificationTextMentionKindProps, InboxNotificationTextMentionProps, InboxNotificationThreadKindProps, InboxNotificationThreadProps, LiveblocksUiConfig, LocalizationOverrides, Overrides, Thread, ThreadOverrides, ThreadProps, useOverrides };
1852
+ export { AiChat, AiChatComponents, AiChatComponentsEmptyProps, AiChatComponentsLoadingProps, AiChatProps, AiComposerSubmitMessage, AiTool, AiToolIconProps, AiToolProps, AvatarStack, AvatarStackProps, Comment, CommentAttachmentArgs, CommentAuthorProps, CommentAvatarProps, CommentDateProps, CommentDropdownItemProps, CommentOverrides, CommentPin, CommentPinProps, CommentProps, Composer, ComposerBodyMark, ComposerBodyMarks, ComposerOverrides, ComposerProps, ComposerSubmitComment, Cursor, CursorProps, Cursors, CursorsCursorProps, CursorsProps, FloatingComposer, FloatingComposerProps, FloatingThread, FloatingThreadProps, GlobalOverrides, HistoryVersionSummary, HistoryVersionSummaryList, HistoryVersionSummaryListProps, HistoryVersionSummaryProps, icon as Icon, InboxNotification, InboxNotificationAvatarProps, InboxNotificationCustomKindProps, InboxNotificationCustomProps, InboxNotificationIconProps, InboxNotificationInspectorProps, InboxNotificationList, InboxNotificationListProps, InboxNotificationOverrides, InboxNotificationProps, InboxNotificationTextMentionKindProps, InboxNotificationTextMentionProps, InboxNotificationThreadKindProps, InboxNotificationThreadProps, LiveblocksUiConfig, LocalizationOverrides, Overrides, Thread, ThreadOverrides, ThreadProps, useOverrides };
package/dist/index.d.ts CHANGED
@@ -1259,6 +1259,22 @@ interface CursorProps extends ComponentPropsWithoutRef<"div"> {
1259
1259
  */
1260
1260
  declare const Cursor: react.ForwardRefExoticComponent<CursorProps & react.RefAttributes<HTMLDivElement>>;
1261
1261
 
1262
+ interface CursorsCursorProps {
1263
+ /**
1264
+ * The user ID for this cursor.
1265
+ */
1266
+ userId: string;
1267
+ /**
1268
+ * The connection ID for this cursor.
1269
+ */
1270
+ connectionId: number;
1271
+ }
1272
+ interface CursorsComponents {
1273
+ /**
1274
+ * The component used to display each cursor.
1275
+ */
1276
+ Cursor: ComponentType<CursorsCursorProps>;
1277
+ }
1262
1278
  interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
1263
1279
  /**
1264
1280
  * The key used to store the cursors in users' Presence.
@@ -1267,6 +1283,10 @@ interface CursorsProps extends ComponentPropsWithoutRef<"div"> {
1267
1283
  * Defaults to `"cursor"`.
1268
1284
  */
1269
1285
  presenceKey?: string;
1286
+ /**
1287
+ * Override the component's components.
1288
+ */
1289
+ components?: Partial<GlobalComponents & CursorsComponents>;
1270
1290
  }
1271
1291
  /**
1272
1292
  * Displays multiplayer cursors.
@@ -1829,4 +1849,4 @@ declare namespace icon {
1829
1849
  };
1830
1850
  }
1831
1851
 
1832
- export { AiChat, AiChatComponents, AiChatComponentsEmptyProps, AiChatComponentsLoadingProps, AiChatProps, AiComposerSubmitMessage, AiTool, AiToolIconProps, AiToolProps, AvatarStack, AvatarStackProps, Comment, CommentAttachmentArgs, CommentAuthorProps, CommentAvatarProps, CommentDateProps, CommentDropdownItemProps, CommentOverrides, CommentPin, CommentPinProps, CommentProps, Composer, ComposerBodyMark, ComposerBodyMarks, ComposerOverrides, ComposerProps, ComposerSubmitComment, Cursor, CursorProps, Cursors, CursorsProps, FloatingComposer, FloatingComposerProps, FloatingThread, FloatingThreadProps, GlobalOverrides, HistoryVersionSummary, HistoryVersionSummaryList, HistoryVersionSummaryListProps, HistoryVersionSummaryProps, icon as Icon, InboxNotification, InboxNotificationAvatarProps, InboxNotificationCustomKindProps, InboxNotificationCustomProps, InboxNotificationIconProps, InboxNotificationInspectorProps, InboxNotificationList, InboxNotificationListProps, InboxNotificationOverrides, InboxNotificationProps, InboxNotificationTextMentionKindProps, InboxNotificationTextMentionProps, InboxNotificationThreadKindProps, InboxNotificationThreadProps, LiveblocksUiConfig, LocalizationOverrides, Overrides, Thread, ThreadOverrides, ThreadProps, useOverrides };
1852
+ export { AiChat, AiChatComponents, AiChatComponentsEmptyProps, AiChatComponentsLoadingProps, AiChatProps, AiComposerSubmitMessage, AiTool, AiToolIconProps, AiToolProps, AvatarStack, AvatarStackProps, Comment, CommentAttachmentArgs, CommentAuthorProps, CommentAvatarProps, CommentDateProps, CommentDropdownItemProps, CommentOverrides, CommentPin, CommentPinProps, CommentProps, Composer, ComposerBodyMark, ComposerBodyMarks, ComposerOverrides, ComposerProps, ComposerSubmitComment, Cursor, CursorProps, Cursors, CursorsCursorProps, CursorsProps, FloatingComposer, FloatingComposerProps, FloatingThread, FloatingThreadProps, GlobalOverrides, HistoryVersionSummary, HistoryVersionSummaryList, HistoryVersionSummaryListProps, HistoryVersionSummaryProps, icon as Icon, InboxNotification, InboxNotificationAvatarProps, InboxNotificationCustomKindProps, InboxNotificationCustomProps, InboxNotificationIconProps, InboxNotificationInspectorProps, InboxNotificationList, InboxNotificationListProps, InboxNotificationOverrides, InboxNotificationProps, InboxNotificationTextMentionKindProps, InboxNotificationTextMentionProps, InboxNotificationThreadKindProps, InboxNotificationThreadProps, LiveblocksUiConfig, LocalizationOverrides, Overrides, Thread, ThreadOverrides, ThreadProps, useOverrides };
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n AiChatComponents,\n AiChatComponentsEmptyProps,\n AiChatComponentsLoadingProps,\n AiChatProps,\n} from \"./components/AiChat\";\nexport { AiChat } from \"./components/AiChat\";\nexport type { AiToolIconProps, AiToolProps } from \"./components/AiTool\";\nexport { AiTool } from \"./components/AiTool\";\nexport type { AvatarStackProps } from \"./components/AvatarStack\";\nexport { AvatarStack } from \"./components/AvatarStack\";\nexport type {\n CommentAuthorProps,\n CommentAvatarProps,\n CommentDateProps,\n CommentDropdownItemProps,\n CommentProps,\n} from \"./components/Comment\";\nexport { Comment } from \"./components/Comment\";\nexport type { CommentPinProps } from \"./components/CommentPin\";\nexport { CommentPin } from \"./components/CommentPin\";\nexport type { ComposerProps } from \"./components/Composer\";\nexport { Composer } from \"./components/Composer\";\nexport type { CursorProps } from \"./components/Cursor\";\nexport { Cursor } from \"./components/Cursor\";\nexport type { CursorsProps } from \"./components/Cursors\";\nexport { Cursors } from \"./components/Cursors\";\nexport type { FloatingComposerProps } from \"./components/FloatingComposer\";\nexport { FloatingComposer } from \"./components/FloatingComposer\";\nexport type { FloatingThreadProps } from \"./components/FloatingThread\";\nexport { FloatingThread } from \"./components/FloatingThread\";\nexport type { HistoryVersionSummaryProps } from \"./components/HistoryVersionSummary\";\nexport { HistoryVersionSummary } from \"./components/HistoryVersionSummary\";\nexport type { HistoryVersionSummaryListProps } from \"./components/HistoryVersionSummaryList\";\nexport { HistoryVersionSummaryList } from \"./components/HistoryVersionSummaryList\";\nexport type {\n InboxNotificationAvatarProps,\n InboxNotificationCustomKindProps,\n InboxNotificationCustomProps,\n InboxNotificationIconProps,\n InboxNotificationInspectorProps,\n InboxNotificationProps,\n InboxNotificationTextMentionKindProps,\n InboxNotificationTextMentionProps,\n InboxNotificationThreadKindProps,\n InboxNotificationThreadProps,\n} from \"./components/InboxNotification\";\nexport { InboxNotification } from \"./components/InboxNotification\";\nexport type { InboxNotificationListProps } from \"./components/InboxNotificationList\";\nexport { InboxNotificationList } from \"./components/InboxNotificationList\";\nexport type { ThreadProps } from \"./components/Thread\";\nexport { Thread } from \"./components/Thread\";\nexport { LiveblocksUiConfig } from \"./config\";\nexport * as Icon from \"./icon\";\nexport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n LocalizationOverrides,\n Overrides,\n ThreadOverrides,\n} from \"./overrides\";\nexport { useOverrides } from \"./overrides\";\nexport type {\n AiComposerSubmitMessage,\n ComposerSubmitComment,\n} from \"./primitives\";\nexport type {\n CommentAttachmentArgs,\n ComposerBodyMark,\n ComposerBodyMarks,\n} from \"./types\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
1
+ {"version":3,"file":"index.js","sources":["../src/index.ts"],"sourcesContent":["import { detectDupes } from \"@liveblocks/core\";\n\nimport { PKG_FORMAT, PKG_NAME, PKG_VERSION } from \"./version\";\n\ndetectDupes(PKG_NAME, PKG_VERSION, PKG_FORMAT);\n\nexport type {\n AiChatComponents,\n AiChatComponentsEmptyProps,\n AiChatComponentsLoadingProps,\n AiChatProps,\n} from \"./components/AiChat\";\nexport { AiChat } from \"./components/AiChat\";\nexport type { AiToolIconProps, AiToolProps } from \"./components/AiTool\";\nexport { AiTool } from \"./components/AiTool\";\nexport type { AvatarStackProps } from \"./components/AvatarStack\";\nexport { AvatarStack } from \"./components/AvatarStack\";\nexport type {\n CommentAuthorProps,\n CommentAvatarProps,\n CommentDateProps,\n CommentDropdownItemProps,\n CommentProps,\n} from \"./components/Comment\";\nexport { Comment } from \"./components/Comment\";\nexport type { CommentPinProps } from \"./components/CommentPin\";\nexport { CommentPin } from \"./components/CommentPin\";\nexport type { ComposerProps } from \"./components/Composer\";\nexport { Composer } from \"./components/Composer\";\nexport type { CursorProps } from \"./components/Cursor\";\nexport { Cursor } from \"./components/Cursor\";\nexport type { CursorsCursorProps, CursorsProps } from \"./components/Cursors\";\nexport { Cursors } from \"./components/Cursors\";\nexport type { FloatingComposerProps } from \"./components/FloatingComposer\";\nexport { FloatingComposer } from \"./components/FloatingComposer\";\nexport type { FloatingThreadProps } from \"./components/FloatingThread\";\nexport { FloatingThread } from \"./components/FloatingThread\";\nexport type { HistoryVersionSummaryProps } from \"./components/HistoryVersionSummary\";\nexport { HistoryVersionSummary } from \"./components/HistoryVersionSummary\";\nexport type { HistoryVersionSummaryListProps } from \"./components/HistoryVersionSummaryList\";\nexport { HistoryVersionSummaryList } from \"./components/HistoryVersionSummaryList\";\nexport type {\n InboxNotificationAvatarProps,\n InboxNotificationCustomKindProps,\n InboxNotificationCustomProps,\n InboxNotificationIconProps,\n InboxNotificationInspectorProps,\n InboxNotificationProps,\n InboxNotificationTextMentionKindProps,\n InboxNotificationTextMentionProps,\n InboxNotificationThreadKindProps,\n InboxNotificationThreadProps,\n} from \"./components/InboxNotification\";\nexport { InboxNotification } from \"./components/InboxNotification\";\nexport type { InboxNotificationListProps } from \"./components/InboxNotificationList\";\nexport { InboxNotificationList } from \"./components/InboxNotificationList\";\nexport type { ThreadProps } from \"./components/Thread\";\nexport { Thread } from \"./components/Thread\";\nexport { LiveblocksUiConfig } from \"./config\";\nexport * as Icon from \"./icon\";\nexport type {\n CommentOverrides,\n ComposerOverrides,\n GlobalOverrides,\n InboxNotificationOverrides,\n LocalizationOverrides,\n Overrides,\n ThreadOverrides,\n} from \"./overrides\";\nexport { useOverrides } from \"./overrides\";\nexport type {\n AiComposerSubmitMessage,\n ComposerSubmitComment,\n} from \"./primitives\";\nexport type {\n CommentAttachmentArgs,\n ComposerBodyMark,\n ComposerBodyMarks,\n} from \"./types\";\n"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;AAIA,WAAY,CAAA,QAAA,EAAU,aAAa,UAAU,CAAA"}
package/dist/version.cjs CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
 
3
3
  const PKG_NAME = "@liveblocks/react-ui";
4
- const PKG_VERSION = typeof "3.16.0-flow1" === "string" && "3.16.0-flow1";
4
+ const PKG_VERSION = typeof "3.16.0-flow3" === "string" && "3.16.0-flow3";
5
5
  const PKG_FORMAT = typeof "cjs" === "string" && "cjs";
6
6
 
7
7
  exports.PKG_FORMAT = PKG_FORMAT;
package/dist/version.js CHANGED
@@ -1,5 +1,5 @@
1
1
  const PKG_NAME = "@liveblocks/react-ui";
2
- const PKG_VERSION = typeof "3.16.0-flow1" === "string" && "3.16.0-flow1";
2
+ const PKG_VERSION = typeof "3.16.0-flow3" === "string" && "3.16.0-flow3";
3
3
  const PKG_FORMAT = typeof "esm" === "string" && "esm";
4
4
 
5
5
  export { PKG_FORMAT, PKG_NAME, PKG_VERSION };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@liveblocks/react-ui",
3
- "version": "3.16.0-flow1",
3
+ "version": "3.16.0-flow3",
4
4
  "description": "A set of React pre-built components for the Liveblocks products. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Liveblocks Inc.",
@@ -71,16 +71,16 @@
71
71
  "format": "eslint --fix src/; stylelint --fix src/styles/; prettier --write src/",
72
72
  "lint": "eslint src/; stylelint src/styles/",
73
73
  "lint:package": "publint --strict && attw --pack",
74
- "test": "npx liveblocks dev -c 'vitest run'",
74
+ "test": "npx liveblocks dev -p 1154 -c 'vitest run'",
75
75
  "test:ci": "vitest run",
76
76
  "test:types": "ls test-d/* | xargs -n1 tsd --files",
77
77
  "test:watch": "vitest"
78
78
  },
79
79
  "dependencies": {
80
80
  "@floating-ui/react-dom": "^2.1.0",
81
- "@liveblocks/client": "3.16.0-flow1",
82
- "@liveblocks/core": "3.16.0-flow1",
83
- "@liveblocks/react": "3.16.0-flow1",
81
+ "@liveblocks/client": "3.16.0-flow3",
82
+ "@liveblocks/core": "3.16.0-flow3",
83
+ "@liveblocks/react": "3.16.0-flow3",
84
84
  "frimousse": "^0.2.0",
85
85
  "marked": "^15.0.11",
86
86
  "radix-ui": "^1.4.0",
@@ -1788,6 +1788,10 @@
1788
1788
  black calc(var(--lb-avatar-stack-mask-size) + 0.375px)
1789
1789
  );
1790
1790
  }
1791
+
1792
+ &:where(:last-child) {
1793
+ margin-inline-end: 0;
1794
+ }
1791
1795
  }
1792
1796
 
1793
1797
  /*************************************