Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 57 additions & 25 deletions packages/collaboration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,24 +30,31 @@ import {
LiveCursors,
PresenceAvatars,
CommentThread,
type Comment,
type PresenceUser,
} from '@object-ui/collaboration';

declare const broadcastPresence: (user: PresenceUser) => void;
declare const comments: Comment[];
declare const currentUser: { id: string; name: string };

function CollaborativeEditor() {
const { users, updatePresence } = usePresence({
channel: 'document-123',
const { users, updateCursor } = usePresence(broadcastPresence, {
user: { id: 'user-1', name: 'Alice' },
});

const { data, connectionState } = useRealtimeSubscription({
const { lastMessage, connectionState } = useRealtimeSubscription({
channel: 'document-123',
event: 'update',
});

return (
<div>
<div data-connection={connectionState}>
<PresenceAvatars users={users} />
<LiveCursors users={users} />
<Editor data={data} onCursorMove={(pos) => updatePresence({ cursor: pos })} />
<CommentThread threadId="thread-1" />
<div onMouseMove={(event) => updateCursor({ x: event.clientX, y: event.clientY })}>
{lastMessage ? lastMessage.channel : 'waiting for updates'}
</div>
<CommentThread threadId="thread-1" comments={comments} currentUser={currentUser} />
</div>
);
}
Expand All @@ -57,62 +64,87 @@ function CollaborativeEditor() {

### useRealtimeSubscription

Hook for WebSocket data subscriptions:
Hook for WebSocket data subscriptions. `channel` is the only required key, and the
result carries the connection state plus the messages received so far:

```tsx
const { data, connectionState, error } = useRealtimeSubscription({
import { useRealtimeSubscription } from '@object-ui/collaboration';

const { lastMessage, messages, connectionState, error } = useRealtimeSubscription({
channel: 'orders',
event: 'update',
});
```

### usePresence

Hook for tracking user presence:
Hook for tracking user presence. The broadcast callback comes first and the
configuration second; the configuration carries the current user:

```tsx
const { users, updatePresence } = usePresence({
channel: 'document-123',
import { usePresence, type PresenceUser } from '@object-ui/collaboration';

declare const broadcastPresence: (user: PresenceUser) => void;

const { users, updateCursor, currentUser } = usePresence(broadcastPresence, {
user: { id: 'user-1', name: 'Alice' },
});
```

### useConflictResolution

Hook for version history and conflict management:
Hook for version history and conflict management. It is called with the current
user's id, optionally their name:

```tsx
const { versions, conflicts, resolve } = useConflictResolution({
resourceId: 'doc-123',
});
import { useConflictResolution } from '@object-ui/collaboration';

const { versions, conflicts, resolveConflict } = useConflictResolution('user-1', 'Alice');
```

### LiveCursors

Displays remote user cursors on the page:

```tsx
<LiveCursors users={presenceUsers} />
import { LiveCursors, type PresenceUser } from '@object-ui/collaboration';

declare const presenceUsers: PresenceUser[];

const cursors = <LiveCursors users={presenceUsers} />;
```

### PresenceAvatars

Shows avatar badges for active users:

```tsx
<PresenceAvatars users={presenceUsers} maxVisible={5} />
import { PresenceAvatars, type PresenceUser } from '@object-ui/collaboration';

declare const presenceUsers: PresenceUser[];

const avatars = <PresenceAvatars users={presenceUsers} maxVisible={5} />;
```

### CommentThread

Threaded comment component with @mentions:
Threaded comment component with @mentions. `comments` and `currentUser` are
required; new comments arrive through `onAddComment`:

```tsx
<CommentThread
threadId="thread-1"
comments={comments}
onSubmit={(comment) => saveComment(comment)}
/>
import { CommentThread, type Comment } from '@object-ui/collaboration';

declare const comments: Comment[];
declare const currentUser: { id: string; name: string };
declare const saveComment: (content: string, mentions: string[]) => void;

const thread = (
<CommentThread
threadId="thread-1"
comments={comments}
currentUser={currentUser}
onAddComment={(content, mentions) => saveComment(content, mentions)}
/>
);
```

## Links
Expand Down
2 changes: 0 additions & 2 deletions scripts/check-doc-snippet-types.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -705,8 +705,6 @@ const UNGATED_DOCS = {
'what is left is fragment shape, and no gate reads this page\'s import names.',
'packages/auth/README.md':
'1 parse diagnostic(s) — blocks fenced `ts` that are bare object literals or elided bodies; 15 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS2741x1 — candidate real defects, un-triaged',
'packages/collaboration/README.md':
'13 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the page never defines; plus TS2339x2 TS2353x1 TS2554x1 TS2739x1 — candidate real defects, un-triaged',
'packages/core/README.md':
'5 undefined-name diagnostic(s) — blocks continue an earlier block, or use ambient names the ' +
'page never defines; plus TS2339x1 — TRIAGED, and NOT a defect: the remaining one is ' +
Expand Down
Loading