Yjs Collaboration

Add real-time collaboration to Spreadsheet 2 using Yjs

There are two ways we can use yjs collaboration

  1. Sending patches to yjs document and synchorizing these patches between users

  2. Saving the entire data, like sheetData, sheets in yjs document. More performance and easy to restore an entire document

You can install Yjs hook as a separate module

yarn add "@rowsncolumns/y-spreadsheet"

Initializing Yjs

This hook uses WebSocketProvider from Yjs to initialize a connection to one of the demo servers wss://demos.yjs.dev

The default provider can be easily switched to WebRTCProvider, but as of right now, WebRTC does not support synced events.

Running yjs locally

HOST=localhost PORT=1234 npx y-websocket
import {
  SheetData,
  useSpreadsheetState,
} from "@rowsncolumns/spreadsheet-state";

// Option 1
import { useYSpreadsheet } from "@rowsncolumns/yjs-spreadsheet"

// Option 2, Same API
import { useYSpreadsheetV2 } from "@rowsncolumns/yjs-spreadsheet"

import { SpreadsheetProvider, CanvasGrid } from '@rowsncolumns/spreadsheet'

const version = "v1"
const yDoc = new Y.Doc({ gc: true });
const yWebsocketProvider = new WebsocketProvider(
  "ws://localhost:1234",
  `y-spreadsheet-${version}`,
  yDoc,
  {
    connect: true,
  }
);

const MySpreadsheet = () => {
  const userId = 'foobar'
  const name = 'foobar'
  const [sheets, onChangeSheets] = useState<Sheet[]>([]);
  const [sheetData, onChangeSheetData] = useState<SheetData<CellData>>({});
  const [tables, onChangeTables] = useState<TableView[]>([]);
  
  const { activeCell, activeSheetId enqueueCalculation, ... } = useSpreadsheetState({
    ....,
    onChangeHistory(patches) {
      onBroadcastPatch(patches);
    },
  })
  
  // Add Yjs hook
  const { users, onBroadcastPatch } = useYSpreadsheet({
    provider: yWebsocketProvider,
    doc: yDoc,
    onChangeSheetData,
    onChangeSheets,
    onChangeTables,
    enqueueCalculation,
    sheetId: activeSheetId,
    activeCell,

    // User info
    userId,
    title: name,
  });


  return (
    <CanvasGrid
      {...}
      users={users}
      userId={userId}
    >
  )

}

const App = () => (
  <SpreadsheetProvider>
    <MySpreadsheet />
  </SpreadsheetProvider>
)

Last updated