"use client"; import { SocketContext1 } from "@/app/SocketContext1"; import { SocketContext2 } from "@/app/SocketContext2"; import CollaborationStatus from "@/app/articles/[slug]/CollaborationStatus"; import CollaborativeEditor from "@/app/articles/[slug]/CollaborativeEditor"; import { HocuspocusProvider, HocuspocusProviderWebsocket, } from "@hocuspocus/provider"; // import { TiptapCollabProvider } from "@tiptap-cloud/provider"; import { useContext, useEffect, useState } from "react"; export default function ArticleEditor({ slug }: { slug: string }) { const socket1 = useContext(SocketContext1); const socket2 = useContext(SocketContext2); const [provider1, setProvider1] = useState(); const [provider2, setProvider2] = useState(); useEffect(() => { if (!socket1 || !socket2) return; // Create separate providers for each editor const _p1 = new HocuspocusProvider({ websocketProvider: socket1, name: slug, onOpen: (data) => console.log("Editor 1 onOpen!", data), onClose: (data) => console.log("Editor 1 onClose!", data), onAuthenticated: (data) => console.log("Editor 1 onAuthenticated!", data), onAuthenticationFailed: (data) => console.log("Editor 1 onAuthenticationFailed", data), onUnsyncedChanges: (data) => console.log("Editor 1 onUnsyncedChanges", data), onStatus(data) { console.log("editor 1 onStatus", data); }, }); const _p2 = new HocuspocusProvider({ websocketProvider: socket2, name: slug, onOpen: (data) => console.log("Editor 2 onOpen!", data), onClose: (data) => console.log("Editor 2 onClose!", data), onAuthenticated: (data) => console.log("Editor 2 onAuthenticated!", data), onAuthenticationFailed: (data) => console.log("Editor 2 onAuthenticationFailed", data), onUnsyncedChanges: (data) => console.log("Editor 2 onUnsyncedChanges", data), onStatus(data) { console.log("editor 2 onStatus", data); }, }); setProvider1(_p1); setProvider2(_p2); return () => { _p1.destroy(); _p2.destroy(); }; }, [socket1, socket2, slug]); if (!provider1 || !provider2) { return <>; } // you need to attach here, to make sure the connection gets properly established due to React strict-mode re-run of hooks provider1.attach(); provider2.attach(); return (
{/* Header */}

Article #{slug}

Real-time collaborative editing - Two editors demonstrating sync

{/* Main content */}
{/* Editors side by side */}
{/* Editor 1 */}

Editor 1

Independent WebSocket connection
{/* Status Panel 1 */} {/* Editor 1 */}
{/* Editor 2 */}

Editor 2

Independent WebSocket connection
{/* Status Panel 2 */} {/* Editor 2 */}
{/* Info panel */}

Real-time Collaboration Demo

Both editors are connected to the same document but use separate WebSocket connections. Changes made in one editor will appear in the other in real-time. Try typing in either editor or use the connection controls to test synchronization behavior.

); }