@mexty/realtime
v2.1.0
Published
React hooks for real-time collaborative features using Yjs and Hocuspocus
Maintainers
Readme
@mexty/realtime
React hooks for real-time collaborative features using Yjs and Hocuspocus.
Installation
npm install @mexty/realtimeUsage
import { useCollabSpace } from "@mexty/realtime";
// 🧠 Example 1: Collaborative JSON document editor
export function DocumentEditor({ blockId }: { blockId: string }) {
const { state, update } = useCollabSpace(`block:${blockId}`, {
document: {
title: "Untitled",
content: "Write something...",
},
game: { weights: [] },
});
// ✅ Partial update usage
const handleTitleChange = (e: React.ChangeEvent<HTMLInputElement>) => {
update({ document: { ...state.document, title: e.target.value } });
};
// ✅ Functional update usage
const resetContent = () => {
update((prev) => ({
...prev,
document: { ...prev.document, content: "" },
}));
};
return (
<div className="p-4 border rounded space-y-3">
<h2 className="text-lg font-bold">Collaborative Document</h2>
<input
type="text"
className="border p-2 w-full"
value={state.document.title}
onChange={handleTitleChange}
/>
<textarea
className="border p-2 w-full h-32"
value={state.document.content}
onChange={(e) =>
update({ document: { ...state.document, content: e.target.value } })
}
/>
<button
onClick={resetContent}
className="bg-blue-500 text-white px-3 py-1 rounded"
>
Reset Content
</button>
</div>
);
}
// 🧩 Example 2: Multiplayer tower game state
export function TowerGame({ blockId }: { blockId: string }) {
const { state, update } = useCollabSpace(`block:${blockId}`, {
document: {},
game: { weights: [] as { team: string; pos: number }[] },
});
// ✅ Append new weight (functional update)
const addWeight = (team: string) => {
update((prev) => ({
...prev,
game: {
...prev.game,
weights: [...prev.game.weights, { team, pos: Math.random() * 100 }],
},
}));
};
// ✅ Clear game state (partial update)
const resetGame = () => {
update({ game: { weights: [] } });
};
return (
<div className="p-4 border rounded space-y-3">
<h2 className="text-lg font-bold">Tower Game</h2>
<button
onClick={() => addWeight("blue")}
className="bg-blue-600 text-white px-3 py-1 rounded"
>
Add Blue Weight
</button>
<button
onClick={() => addWeight("red")}
className="bg-red-600 text-white px-3 py-1 rounded"
>
Add Red Weight
</button>
<button
onClick={resetGame}
className="bg-gray-600 text-white px-3 py-1 rounded"
>
Reset Game
</button>
<pre className="bg-gray-100 p-2 text-sm rounded overflow-auto">
{JSON.stringify(state.game, null, 2)}
</pre>
</div>
);
}API
useCollabSpace(documentName, initialState, options?)
Parameters
documentName: string- Unique identifier for the collaborative documentinitialState: T- Initial state object for the collaborative spaceoptions?: CollabSpaceOptions- Optional configuration
Returns
state: T- Current collaborative stateupdate: (updateFn: UpdateFunction<T>) => void- Function to update stateisConnected: boolean- WebSocket connection statusconnectionStatus: 'connecting' | 'connected' | 'disconnected' | 'error'- Detailed connection statususerId: string- Anonymous user ID (persisted in localStorage)
Options
interface CollabSpaceOptions {
websocketUrl?: string;
onConnect?: () => void;
onDisconnect?: () => void;
onError?: (error: Error) => void;
}Features
- 🔄 Real-time collaborative state synchronization
- 🆔 Anonymous user authentication with persistent IDs
- 🔗 Automatic WebSocket connection management
- 📱 React hooks for easy integration
- 🎯 TypeScript support with full type safety
- 🏗️ Built on Yjs and Hocuspocus for reliability
License
MIT
