{othersConnectionIds.map((connectionId) => (
diff --git a/packages/liveblocks-react-ui/src/components/FloatingComposer.tsx b/packages/liveblocks-react-ui/src/components/FloatingComposer.tsx
index 5d798fbfe3..d5942bae33 100644
--- a/packages/liveblocks-react-ui/src/components/FloatingComposer.tsx
+++ b/packages/liveblocks-react-ui/src/components/FloatingComposer.tsx
@@ -7,6 +7,7 @@ import {
forwardRef,
type ReactNode,
type RefAttributes,
+ useRef,
} from "react";
import { useLiveblocksUiConfig } from "../config";
@@ -17,6 +18,7 @@ import {
import { useOverrides } from "../overrides";
import { cn } from "../utils/cn";
import { useControllableState } from "../utils/use-controllable-state";
+import { useRefs } from "../utils/use-refs";
import type { ComposerProps } from "./Composer";
import { Composer } from "./Composer";
@@ -57,12 +59,15 @@ export const FloatingComposer = forwardRef(
sideOffset = FLOATING_ELEMENT_SIDE_OFFSET,
align = "start",
alignOffset,
+ autoFocus = true,
overrides,
className,
...props
}: FloatingComposerProps
,
forwardedRef: ForwardedRef
) => {
+ const composerRef = useRef(null);
+ const mergedRefs = useRefs(forwardedRef, composerRef);
const $ = useOverrides(overrides);
const { portalContainer } = useLiveblocksUiConfig();
const [isOpen, setIsOpen] = useControllableState(
@@ -83,6 +88,7 @@ export const FloatingComposer = forwardRef(
dir={$.dir}
side={side}
sideOffset={sideOffset}
+ updatePositionStrategy="always"
align={align}
alignOffset={alignOffset}
collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}
@@ -104,13 +110,20 @@ export const FloatingComposer = forwardRef(
event.preventDefault();
}
}}
+ onOpenAutoFocus={(event) => {
+ if (!autoFocus) {
+ event.preventDefault();
+ composerRef.current?.focus();
+ }
+ }}
asChild
>
)}
/>
diff --git a/packages/liveblocks-react-ui/src/components/FloatingThread.tsx b/packages/liveblocks-react-ui/src/components/FloatingThread.tsx
index cd2ac763a4..c092b1f38e 100644
--- a/packages/liveblocks-react-ui/src/components/FloatingThread.tsx
+++ b/packages/liveblocks-react-ui/src/components/FloatingThread.tsx
@@ -81,6 +81,7 @@ export const FloatingThread = forwardRef(
dir={$.dir}
side={side}
sideOffset={sideOffset}
+ updatePositionStrategy="always"
align={align}
alignOffset={alignOffset}
collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}
diff --git a/packages/liveblocks-react-ui/src/components/internal/Dropdown.tsx b/packages/liveblocks-react-ui/src/components/internal/Dropdown.tsx
index 17e560ce64..01e48853ec 100644
--- a/packages/liveblocks-react-ui/src/components/internal/Dropdown.tsx
+++ b/packages/liveblocks-react-ui/src/components/internal/Dropdown.tsx
@@ -55,6 +55,7 @@ export function Dropdown({
)}
sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}
collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}
+ updatePositionStrategy="always"
{...props}
>
{content}
diff --git a/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx b/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx
index 3b60cc2a1a..531950e211 100644
--- a/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx
+++ b/packages/liveblocks-react-ui/src/components/internal/EmojiPicker.tsx
@@ -104,6 +104,7 @@ export const EmojiPicker = forwardRef(
(
)}
side="top"
align="center"
+ updatePositionStrategy="always"
sideOffset={FLOATING_ELEMENT_SIDE_OFFSET}
collisionPadding={FLOATING_ELEMENT_COLLISION_PADDING}
{...props}
diff --git a/packages/liveblocks-react-ui/src/icon.ts b/packages/liveblocks-react-ui/src/icon.ts
index 72640b7a60..055b984ec7 100644
--- a/packages/liveblocks-react-ui/src/icon.ts
+++ b/packages/liveblocks-react-ui/src/icon.ts
@@ -34,6 +34,7 @@ export {
ListOrderedIcon as ListOrdered,
ListUnorderedIcon as ListUnordered,
MentionIcon as Mention,
+ PlusIcon as Plus,
QuestionMarkIcon as QuestionMark,
RedoIcon as Redo,
RetryIcon as Retry,
diff --git a/packages/liveblocks-react-ui/src/icons/Plus.tsx b/packages/liveblocks-react-ui/src/icons/Plus.tsx
new file mode 100644
index 0000000000..51d0ea5d0b
--- /dev/null
+++ b/packages/liveblocks-react-ui/src/icons/Plus.tsx
@@ -0,0 +1,11 @@
+import type { ComponentProps } from "react";
+
+import { Icon } from "../components/internal/Icon";
+
+export function PlusIcon(props: ComponentProps<"svg">) {
+ return (
+
+
+
+ );
+}
diff --git a/packages/liveblocks-react-ui/src/icons/index.ts b/packages/liveblocks-react-ui/src/icons/index.ts
index 5b1a23cb37..8c7a7b096f 100644
--- a/packages/liveblocks-react-ui/src/icons/index.ts
+++ b/packages/liveblocks-react-ui/src/icons/index.ts
@@ -34,6 +34,7 @@ export { ListOrderedIcon } from "./ListOrdered";
export { ListUnorderedIcon } from "./ListUnordered";
export { MentionIcon } from "./Mention";
export { MinusCircleIcon } from "./MinusCircle";
+export { PlusIcon } from "./Plus";
export { QuestionMarkIcon } from "./QuestionMark";
export { RedoIcon } from "./Redo";
export { RestoreIcon } from "./Restore";
diff --git a/packages/liveblocks-react-ui/src/styles/index.css b/packages/liveblocks-react-ui/src/styles/index.css
index a01037d4db..eb2fedb667 100644
--- a/packages/liveblocks-react-ui/src/styles/index.css
+++ b/packages/liveblocks-react-ui/src/styles/index.css
@@ -1056,6 +1056,8 @@
font-weight: 500;
font-size: 35cqi;
white-space: nowrap;
+ pointer-events: none;
+ user-select: none;
/**
* Progressive enhancement: Only show the fallback when container queries are supported
@@ -1171,6 +1173,7 @@
position: relative;
background: var(--lb-dynamic-background);
color: var(--lb-foreground);
+ outline: none;
transition-property: background;
}
@@ -1737,6 +1740,10 @@
border-end-start-radius: 2px;
transform: translate(0, -100%);
}
+
+ :where(.lb-icon) {
+ color: var(--lb-foreground-moderate);
+ }
}
.lb-comment-pin-avatar {
@@ -1750,8 +1757,8 @@
.lb-avatar-stack {
--lb-avatar-stack-size: 24px;
- --lb-avatar-stack-overlap: calc(0.25 * var(--lb-avatar-stack-size));
--lb-avatar-stack-gap: 2px;
+ --lb-avatar-stack-overlap: calc(0.25 * var(--lb-avatar-stack-size));
display: flex;
flex-direction: row;
@@ -1761,7 +1768,7 @@
.lb-avatar-stack-avatar {
position: relative;
z-index: calc(
- var(--lb-avatar-stack-count) - var(--lb-avatar-stack-avatar-index)
+ var(--lb-avatar-stack-count) - 1 - var(--lb-avatar-stack-avatar-index)
);
inline-size: var(--lb-avatar-stack-size);
block-size: var(--lb-avatar-stack-size);
diff --git a/packages/liveblocks-react-ui/src/utils/px.ts b/packages/liveblocks-react-ui/src/utils/px.ts
new file mode 100644
index 0000000000..31b020500e
--- /dev/null
+++ b/packages/liveblocks-react-ui/src/utils/px.ts
@@ -0,0 +1,11 @@
+export function px(value: number | string | undefined): string | undefined {
+ if (value === undefined) {
+ return undefined;
+ }
+
+ if (typeof value === "number") {
+ return `${value}px`;
+ }
+
+ return value;
+}
diff --git a/packages/liveblocks-react/package.json b/packages/liveblocks-react/package.json
index 6df9037796..aebe9cfe39 100644
--- a/packages/liveblocks-react/package.json
+++ b/packages/liveblocks-react/package.json
@@ -1,6 +1,6 @@
{
"name": "@liveblocks/react",
- "version": "3.15.0",
+ "version": "3.15.1",
"description": "A set of React hooks and providers to use Liveblocks declaratively. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
"license": "Apache-2.0",
"author": "Liveblocks Inc.",
@@ -63,8 +63,8 @@
"showdeps": "depcruise src --include-only '^src' --exclude='__tests__' --output-type dot | dot -T svg > /tmp/dependency-graph.svg && open /tmp/dependency-graph.svg"
},
"dependencies": {
- "@liveblocks/client": "3.15.0",
- "@liveblocks/core": "3.15.0"
+ "@liveblocks/client": "3.15.1",
+ "@liveblocks/core": "3.15.1"
},
"peerDependencies": {
"@types/react": "*",
diff --git a/packages/liveblocks-redux/package.json b/packages/liveblocks-redux/package.json
index a4fc9c82d8..b9dafb5b93 100644
--- a/packages/liveblocks-redux/package.json
+++ b/packages/liveblocks-redux/package.json
@@ -1,6 +1,6 @@
{
"name": "@liveblocks/redux",
- "version": "3.15.0",
+ "version": "3.15.1",
"description": "A store enhancer to integrate Liveblocks into Redux stores. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
"license": "Apache-2.0",
"author": "Liveblocks Inc.",
@@ -35,8 +35,8 @@
"test:watch": "vitest"
},
"dependencies": {
- "@liveblocks/client": "3.15.0",
- "@liveblocks/core": "3.15.0"
+ "@liveblocks/client": "3.15.1",
+ "@liveblocks/core": "3.15.1"
},
"peerDependencies": {
"redux": "^4 || ^5"
diff --git a/packages/liveblocks-server/package.json b/packages/liveblocks-server/package.json
index 9a10b72edd..a1142eb948 100644
--- a/packages/liveblocks-server/package.json
+++ b/packages/liveblocks-server/package.json
@@ -58,7 +58,7 @@
"dependencies": {
"@liveblocks/core": "3.14.0",
"async-mutex": "^0.4.0",
- "decoders": "^2.9.0-pre.4",
+ "decoders": "^2.9.0",
"itertools": "^2.3.2",
"js-base64": "^3.7.5",
"nanoid": "^3",
diff --git a/packages/liveblocks-yjs/package.json b/packages/liveblocks-yjs/package.json
index a6186c8b16..3aba148061 100644
--- a/packages/liveblocks-yjs/package.json
+++ b/packages/liveblocks-yjs/package.json
@@ -1,6 +1,6 @@
{
"name": "@liveblocks/yjs",
- "version": "3.15.0",
+ "version": "3.15.1",
"description": "Integrate your existing or new Yjs documents with Liveblocks.",
"license": "Apache-2.0",
"author": "Liveblocks Inc.",
@@ -35,8 +35,8 @@
"test:watch": "vitest"
},
"dependencies": {
- "@liveblocks/client": "3.15.0",
- "@liveblocks/core": "3.15.0",
+ "@liveblocks/client": "3.15.1",
+ "@liveblocks/core": "3.15.1",
"@noble/hashes": "^1.8.0",
"js-base64": "^3.7.7",
"y-indexeddb": "^9.0.12"
diff --git a/packages/liveblocks-zustand/package.json b/packages/liveblocks-zustand/package.json
index 348bb6e37b..8f0b9c63a3 100644
--- a/packages/liveblocks-zustand/package.json
+++ b/packages/liveblocks-zustand/package.json
@@ -1,6 +1,6 @@
{
"name": "@liveblocks/zustand",
- "version": "3.15.0",
+ "version": "3.15.1",
"description": "A middleware for Zustand to automatically synchronize your stores with Liveblocks. Liveblocks is the all-in-one toolkit to build collaborative products like Figma, Notion, and more.",
"license": "Apache-2.0",
"author": "Liveblocks Inc.",
@@ -36,8 +36,8 @@
"test:watch": "vitest"
},
"dependencies": {
- "@liveblocks/client": "3.15.0",
- "@liveblocks/core": "3.15.0"
+ "@liveblocks/client": "3.15.1",
+ "@liveblocks/core": "3.15.1"
},
"peerDependencies": {
"zustand": "^5.0.1"
diff --git a/tools/liveblocks-cli/package.json b/tools/liveblocks-cli/package.json
index 7b30ba5ac7..8455f3b7f2 100644
--- a/tools/liveblocks-cli/package.json
+++ b/tools/liveblocks-cli/package.json
@@ -42,7 +42,7 @@
"@liveblocks/core": "3.14.0",
"@liveblocks/server": "1.0.15",
"@liveblocks/zenrouter": "^1.0.17",
- "decoders": "^2.9.0-pre.4",
+ "decoders": "^2.9.0",
"js-base64": "^3.7.5",
"yjs": "^13.6.10"
}