Skip to content

Commit

Permalink
feat: add secsync-react-devtool
Browse files Browse the repository at this point in the history
  • Loading branch information
nikgraf committed Oct 17, 2023
1 parent 881cb88 commit d59300e
Show file tree
Hide file tree
Showing 21 changed files with 405 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ There is a changelog available for each package:
- [secsync](./packages/secsync/CHANGELOG.md)
- [secsync-react-yjs](./packages/secsync-react-yjs/CHANGELOG.md)
- [secsync-react-automerge](./packages/secsync-react-automerge/CHANGELOG.md)
- [secsync-react-devtool](./packages/secsync-react-devtool/CHANGELOG.md)
- [tiptap-extension-y-awareness](./packages/tiptap-extension-y-awareness/CHANGELOG.md)
30 changes: 4 additions & 26 deletions documentation/components/AutomergeTodosExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import * as Automerge from "@automerge/automerge";
import { KeyPair, default as sodium } from "libsodium-wrappers";
import React, { useState } from "react";
import { useAutomergeSync } from "secsync-react-automerge";
import { DevTool } from "secsync-react-devtool";
import { v4 as uuidv4 } from "uuid";

type TodoType = {
Expand Down Expand Up @@ -64,32 +65,6 @@ const AutomergeTodosExample: React.FC<Props> = ({

return (
<>
<div>
{state.matches("connected") && "Connected"}
{state.matches("connecting") && "Connecting …"}
{state.matches("disconnected") && "Disconnected"}
{state.matches("failed") && "Error in loading or sending data"}

<button
disabled={!state.matches("connected")}
onClick={() => {
send({ type: "DISCONNECT" });
}}
>
Disconnect WebSocket
</button>
<button
disabled={!state.matches("disconnected")}
onClick={() => {
send({ type: "CONNECT" });
}}
>
Connect WebSocket
</button>
</div>

<br />

<div className="todoapp">
<form
onSubmit={(event) => {
Expand Down Expand Up @@ -173,6 +148,9 @@ const AutomergeTodosExample: React.FC<Props> = ({
))}
</ul>
</div>

<div className="mt-8" />
<DevTool state={state} send={send} />
</>
);
};
Expand Down
26 changes: 3 additions & 23 deletions documentation/components/YjsProsemirrorExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { schema } from "prosemirror-schema-basic";
import { EditorState } from "prosemirror-state";
import { EditorView } from "prosemirror-view";
import React, { useEffect, useRef, useState } from "react";
import { DevTool } from "secsync-react-devtool";
import { useYjsSync } from "secsync-react-yjs";
import {
redo,
Expand Down Expand Up @@ -118,30 +119,9 @@ const YjsProsemirrorExample: React.FC<Props> = ({

return (
<>
<div>
{state.matches("connected") && "Connected"}
{state.matches("connecting") && "Connecting …"}
{state.matches("disconnected") && "Disconnected"}
{state.matches("failed") && "Error in loading or sending data"}

<button
disabled={!state.matches("connected")}
onClick={() => {
send({ type: "DISCONNECT" });
}}
>
Disconnect WebSocket
</button>
<button
disabled={!state.matches("disconnected")}
onClick={() => {
send({ type: "CONNECT" });
}}
>
Connect WebSocket
</button>
</div>
<div ref={editorRef}>Loading</div>
<div className="mt-8" />
<DevTool state={state} send={send} />
</>
);
};
Expand Down
28 changes: 4 additions & 24 deletions documentation/components/YjsTiptapExample.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { EditorContent, useEditor } from "@tiptap/react";
import StarterKit from "@tiptap/starter-kit";
import sodium, { KeyPair } from "libsodium-wrappers";
import { useRef, useState } from "react";
import { DevTool } from "secsync-react-devtool";
import { useYjsSync } from "secsync-react-yjs";
import { YAwarenessExtension } from "tiptap-extension-y-awareness";
import * as Yjs from "yjs";
Expand Down Expand Up @@ -90,30 +91,6 @@ const YjsTiptapExample: React.FC<Props> = ({ documentId, documentKey }) => {

return (
<>
<div>
{state.matches("connected") && "Connected"}
{state.matches("connecting") && "Connecting …"}
{state.matches("disconnected") && "Disconnected"}
{state.matches("failed") && "Error in loading or sending data"}

<Button
disabled={!state.matches("connected")}
onClick={() => {
send({ type: "DISCONNECT" });
}}
>
Disconnect WebSocket
</Button>
<Button
disabled={!state.matches("disconnected")}
onClick={() => {
send({ type: "CONNECT" });
}}
>
Connect WebSocket
</Button>
</div>

<div className="tiptap-toolbar">
<Button
onClick={() => editor.chain().focus().toggleBold().run()}
Expand Down Expand Up @@ -232,6 +209,9 @@ const YjsTiptapExample: React.FC<Props> = ({ documentId, documentKey }) => {
</div>

<EditorContent editor={editor} />

<div className="mt-8" />
<DevTool state={state} send={send} />
</>
);
};
Expand Down
17 changes: 13 additions & 4 deletions documentation/components/YjsTldrawExample/YjsTldrawExample.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Tldraw } from "@tldraw/tldraw";
import "@tldraw/tldraw/tldraw.css";
import { memo } from "react";
import { DevTool } from "secsync-react-devtool";
import { useYjsSecSyncStore } from "./useYjsSecSyncStore";

const websocketHost =
Expand All @@ -17,11 +18,19 @@ type Props = {
const MemoedTldraw = memo(Tldraw);

const YjsTldrawExample: React.FC<Props> = ({ documentId, documentKey }) => {
const store = useYjsSecSyncStore({ documentId, documentKey, websocketHost });
const [store, state, send] = useYjsSecSyncStore({
documentId,
documentKey,
websocketHost,
});
return (
<div style={{ height: 500 }}>
<MemoedTldraw store={store} />
</div>
<>
<div style={{ height: 500 }}>
<MemoedTldraw store={store} />
</div>
<div className="mt-8" />
<DevTool state={state} send={send} />
</>
);
};

Expand Down
14 changes: 12 additions & 2 deletions documentation/components/YjsTldrawExample/useYjsSecSyncStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,15 @@ import { YKeyValue } from "y-utility/y-keyvalue";
import * as Yjs from "yjs";
import { DEFAULT_STORE } from "./default_store";

type PrependToTuple<T extends any[], U> = [U, ...T];

function prependTLStoreWithStatus<T extends any[]>(
tuple: T,
store: TLStoreWithStatus
): PrependToTuple<T, TLStoreWithStatus> {
return [store, ...tuple];
}

type Params = {
documentId: string;
documentKey: Uint8Array;
Expand All @@ -40,7 +49,7 @@ export function useYjsSecSyncStore({
);
const yStore = new YKeyValue(yArr);

const [state, send, , yAwareness] = useYjsSync({
const syncResult = useYjsSync({
yDoc: yDocRef.current,
documentId,
signatureKeyPair: authorKeyPair,
Expand All @@ -63,6 +72,7 @@ export function useYjsSecSyncStore({
sodium,
logging: "debug",
});
const [state, send, , yAwareness] = syncResult;

const subscribers: (() => void)[] = [];

Expand Down Expand Up @@ -271,5 +281,5 @@ export function useYjsSecSyncStore({
prevStateValueRef.current = state.value;
}, [state.value]);

return storeWithStatus;
return prependTLStoreWithStatus(syncResult, storeWithStatus);
}
10 changes: 9 additions & 1 deletion documentation/components/YjsTodosExample/YjsTodosExample.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import sodium, { KeyPair } from "libsodium-wrappers";
import React, { useRef, useState } from "react";
import { DevTool } from "secsync-react-devtool";
import { useYjsSync } from "secsync-react-yjs";
import * as Yjs from "yjs";
import { useYArray } from "../../hooks/useYArray";
Expand All @@ -11,9 +12,13 @@ const websocketHost =

type Props = {
documentId: string;
showDevTool: boolean;
};

export const YjsTodosExample: React.FC<Props> = ({ documentId }) => {
export const YjsTodosExample: React.FC<Props> = ({
documentId,
showDevTool,
}) => {
const documentKey = sodium.from_base64(
"MTcyipWZ6Kiibd5fATw55i9wyEU7KbdDoTE_MRgDR98"
);
Expand Down Expand Up @@ -89,6 +94,9 @@ export const YjsTodosExample: React.FC<Props> = ({ documentId }) => {
})}
</ul>
</div>

<div className="mt-8" />
<DevTool state={state} send={send} />
</>
);
};
1 change: 1 addition & 0 deletions documentation/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
"secsync": "workspace:^",
"secsync-react-automerge": "workspace:^",
"secsync-react-yjs": "workspace:^",
"secsync-react-devtool": "workspace:^",
"tiptap-extension-y-awareness": "workspace:^",
"uuid": "^8.3.2",
"y-prosemirror": "^1.2.1",
Expand Down
13 changes: 13 additions & 0 deletions documentation/pages/docs/getting-started.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,19 @@ const [state, send] = useYjsSync({

You can try it out here by adding To-Dos and you they will load if you refresh the page since the `documentId` is part of the URL. Once you refresh the last snapshot with all related updates will be downloaded.

## Add Secsync DevTools

In order to make development more transparent we created a `DevTool` component visualizing relevant information from the document.

```tsx
import { DevTool } from "secsync-react-devtool";
```

```tsx
// `state` and `send` from the useYjsSync hook
<DevTool state={state} send={send} />
```

## Example App

import SimpleExampleWrapper from "../../components/SimpleExampleWrapper";
Expand Down
14 changes: 14 additions & 0 deletions packages/secsync-react-devtool/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]

## [0.2.0] - 2023-10-17

### Added

- Initial version
6 changes: 6 additions & 0 deletions packages/secsync-react-devtool/babel.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
module.exports = {
presets: [
["@babel/preset-env", { targets: { node: "current" } }],
"@babel/preset-typescript",
],
};
12 changes: 12 additions & 0 deletions packages/secsync-react-devtool/package-json-build-script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
const fs = require("fs");
const data = fs.readFileSync("./package.json", { encoding: "utf8", flag: "r" });

// Display the file data
const dataJson = JSON.parse(data);

dataJson.module = "index.mjs";
dataJson.types = "index.d.ts";
dataJson.main = "index.js";
dataJson.browser = "index.mjs";

fs.writeFileSync("./dist/package.json", JSON.stringify(dataJson, null, 2));
40 changes: 40 additions & 0 deletions packages/secsync-react-devtool/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
{
"name": "secsync-react-devtool",
"version": "0.2.0",
"main": "src/index",
"types": "src/index",
"scripts": {
"build": "pnpm tsup && pnpm build:package-json",
"build:package-json": "node package-json-build-script.js",
"prepublishOnly": "pnpm run build",
"test": "echo \"No tests\"",
"ts:check": "pnpm tsc --noEmit",
"lint": "echo \"No linting configured\""
},
"dependencies": {},
"peerDependencies": {
"react": "*",
"yjs": "*"
},
"devDependencies": {
"@babel/core": "^7.22.10",
"@babel/preset-env": "^7.22.10",
"@babel/preset-typescript": "^7.22.5",
"@types/jest": "^29.5.3",
"@types/react": "^18.2.20",
"jest": "^29.6.2"
},
"jest": {
"setupFilesAfterEnv": [
"<rootDir>/test/config/jestTestSetup.ts"
]
},
"publishConfig": {
"directory": "dist",
"linkDirectory": false
},
"repository": {
"type": "git",
"url": "git+https://github.com/serenity-kit/secsync.git"
}
}
Loading

0 comments on commit d59300e

Please sign in to comment.