-
-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 8e29a0d
Showing
38 changed files
with
5,980 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = { | ||
env: { browser: true, es2020: true }, | ||
ignorePatterns: ["**/dist/*", "node_modules/*"], | ||
parser: "@typescript-eslint/parser", | ||
extends: ["eslint:recommended", "plugin:@typescript-eslint/recommended"], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# These are supported funding model platforms | ||
|
||
github: nikgraf |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,37 @@ | ||
name: Deploy Example | ||
env: | ||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | ||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | ||
on: | ||
push: | ||
branches: | ||
- main | ||
jobs: | ||
Deploy: | ||
defaults: | ||
run: | ||
working-directory: ./examples/app | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: pnpm/action-setup@v3 | ||
with: | ||
version: 9 | ||
- name: Use Node.js | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
cache: "pnpm" | ||
- name: Install dependencies | ||
run: pnpm install --frozen-lockfile | ||
- name: Build Library and Example | ||
working-directory: ./ | ||
run: pnpm build:react-yjs | ||
- name: Install Vercel CLI | ||
run: npm install --global vercel@latest | ||
- name: Pull Vercel Environment Information | ||
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} | ||
- name: Build Project Artifacts | ||
run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} | ||
- name: Deploy Project Artifacts to Vercel | ||
run: vercel deploy --prebuilt --prod --token=${{ secrets.VERCEL_TOKEN }} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
name: Tests and Checks | ||
|
||
on: [push] | ||
|
||
jobs: | ||
lint: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: pnpm/action-setup@v3 | ||
with: | ||
version: 9 | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm lint:check | ||
test: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: pnpm/action-setup@v3 | ||
with: | ||
version: 9 | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm build:react-yjs | ||
- run: pnpm test | ||
build: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- uses: pnpm/action-setup@v3 | ||
with: | ||
version: 9 | ||
- run: pnpm install --frozen-lockfile | ||
- run: pnpm build |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
node_modules | ||
.node_modules | ||
.idea/ | ||
.DS_Store | ||
|
||
.envrc.local | ||
|
||
tmp* | ||
dist | ||
|
||
*.tsbuildinfo | ||
|
||
*.log | ||
|
||
*.db | ||
|
||
.direnv | ||
.wrangler | ||
.vercel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
package-manager-strict=false | ||
dedupe-direct-deps=true | ||
prefer-workspace-packages=true |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
## Development Setup | ||
|
||
```bash | ||
pnpm install | ||
``` | ||
|
||
## Development | ||
|
||
```bash | ||
cd packages/react-yjs | ||
pnpm dev # runs the typescript compiler for the package | ||
``` | ||
|
||
To run the example app: | ||
|
||
```bash | ||
cd examples/app | ||
pnpm dev | ||
``` | ||
|
||
## Testing | ||
|
||
```bash | ||
pnpm test | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
MIT License | ||
|
||
Copyright (c) 2024 Nikolaus Graf | ||
|
||
Permission is hereby granted, free of charge, to any person obtaining a copy | ||
of this software and associated documentation files (the "Software"), to deal | ||
in the Software without restriction, including without limitation the rights | ||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||
copies of the Software, and to permit persons to whom the Software is | ||
furnished to do so, subject to the following conditions: | ||
|
||
The above copyright notice and this permission notice shall be included in all | ||
copies or substantial portions of the Software. | ||
|
||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
SOFTWARE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,128 @@ | ||
# react-yjs | ||
|
||
React hook for Yjs. | ||
|
||
The hook automatically subscribes to changes in the Yjs data-structure and re-renders the component when the data changes. In addition it returns the result of the `.toJSON` from the Yjs data-structure. | ||
|
||
```bash | ||
npm install react-yjs | ||
``` | ||
|
||
```tsx | ||
import { useY } from "react-yjs"; | ||
|
||
export const MyComponent = ({ yArray }) => { | ||
const names = useY(yArray) | ||
|
||
return ( | ||
… | ||
) | ||
} | ||
|
||
``` | ||
|
||
## Simple Usage | ||
|
||
```tsx | ||
import { useY } from 'react-yjs'; | ||
import * as Y from 'yjs'; | ||
|
||
const yDoc = new Y.Doc(); | ||
const yNames = doc.getArray<string>('names'); | ||
|
||
export const MyComponent = () => { | ||
const names = useY(yNames); | ||
|
||
return ( | ||
{names.map(name => <div>{name}</div>)} | ||
) | ||
} | ||
``` | ||
|
||
## More Examples | ||
|
||
### Listening to a nested Yjs data-structure | ||
|
||
```tsx | ||
const yDoc = new Y.Doc(); | ||
const yTodos = yDoc.getArray<Y.Map<string | boolean>>("todos"); | ||
|
||
// Any change of the todos (e.g. change checked) will trigger a re-render | ||
const todos = useY(yTodos); | ||
``` | ||
|
||
Change Todos: | ||
|
||
```tsx | ||
// add a Todo | ||
const todo = new Y.Map<string | boolean>(); | ||
todo.set("checked", false); | ||
todo.set("text", newTodo); | ||
yTodos.push([todo]); | ||
|
||
// update the first Todo | ||
yTodos.get(0).set("checked", true); | ||
``` | ||
|
||
See the working example at [https://react-yjs-example.vercel.app/](https://react-yjs-example.vercel.app/). | ||
The code is available at [examples/app/src/components/Todos.tsx](./examples/app/src/components/Todos.tsx). | ||
|
||
### Listening to a subset of a Yjs data-structure | ||
|
||
```tsx | ||
const yDoc = new Y.Doc(); | ||
const yPosts = yDoc.getArray<Y.Map<string | Y.Array<string>>>("posts"); | ||
const yPost = new Y.Map<string | Y.Array<string>>(); | ||
yPosts.push([yPost]); | ||
yPost.set("title", "Notes"); | ||
const yTags = new Y.Array<string>(); | ||
yTags.push(["cooking", "vegetables"]); | ||
yPost.set("tags", yTags); | ||
|
||
// Makes sure to listen only to changes of the tags of the first post | ||
const yTagsOfFirstPost = yPosts.get(0).get("tags") as Y.Array<string>; | ||
const tagsOfFirstPost = useY(yTagsOfFirstPost); | ||
``` | ||
|
||
Remove a tag on the first post: | ||
|
||
```tsx | ||
const tags = yPosts.get(0).get("tags") as Y.Array<string>; | ||
tags.delete(index); | ||
``` | ||
|
||
See the working example at [https://react-yjs-example.vercel.app/](https://react-yjs-example.vercel.app/). | ||
The code is available at [examples/app/src/components/DeepStructure.tsx](./examples/app/src/components/DeepStructure.tsx). | ||
|
||
## Architecture Decisions | ||
|
||
The `useY` hook | ||
|
||
The goals for this project are | ||
|
||
- trigger a re-render when the Yjs data changes | ||
- make use of `useSyncExternalStore` to avoid [tearing](https://github.com/reactwg/react-18/discussions/69) | ||
- allow listening to a subset of the Yjs data-structure | ||
- allow listening to deeply nested data-structures | ||
- simple API | ||
|
||
This resulted in creating a single hook that does a `observeDeep` the Yjs data-structure. This allows to expose one single hook to listen to deeply nested data-structures. | ||
|
||
Still by passing in only a specific selector of a Yjs data-structure, the hook will only listen to that specific part of the data-structure. | ||
|
||
### Why not listen directly to the Y.Doc? | ||
|
||
Yjs doesn't provide the APIs to do this on the Doc level. It would be possible to work around that, but sticking to the Yjs philosophy felt like a better option. | ||
|
||
### Types | ||
|
||
The Yjs types could be much better https://github.com/yjs/yjs/pull/614. Once this is release we can improve the types. | ||
|
||
## Sponsorship | ||
|
||
Please contribute to the project financially - especially if your company relies | ||
on it. [https://github.com/sponsors/nikgraf](https://github.com/sponsors/nikgraf) | ||
|
||
## License | ||
|
||
The project is [MIT licensed](./LICENSE). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module.exports = { | ||
root: true, | ||
env: { browser: true, es2020: true }, | ||
extends: [ | ||
'eslint:recommended', | ||
'plugin:@typescript-eslint/recommended', | ||
'plugin:react-hooks/recommended', | ||
], | ||
ignorePatterns: ['dist', '.eslintrc.cjs'], | ||
parser: '@typescript-eslint/parser', | ||
plugins: ['react-refresh'], | ||
rules: { | ||
'react-refresh/only-export-components': [ | ||
'warn', | ||
{ allowConstantExport: true }, | ||
], | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
# Logs | ||
logs | ||
*.log | ||
npm-debug.log* | ||
yarn-debug.log* | ||
yarn-error.log* | ||
pnpm-debug.log* | ||
lerna-debug.log* | ||
|
||
node_modules | ||
dist | ||
dist-ssr | ||
*.local | ||
|
||
# Editor directories and files | ||
.vscode/* | ||
!.vscode/extensions.json | ||
.idea | ||
.DS_Store | ||
*.suo | ||
*.ntvs* | ||
*.njsproj | ||
*.sln | ||
*.sw? | ||
.vercel |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
```bash | ||
pnpm | ||
pnpm dev | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
<!doctype html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>react-yjs</title> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="module" src="/src/main.tsx"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
{ | ||
"name": "app", | ||
"private": true, | ||
"version": "0.0.0", | ||
"type": "module", | ||
"scripts": { | ||
"dev": "vite", | ||
"build": "tsc && vite build", | ||
"lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0", | ||
"preview": "vite preview" | ||
}, | ||
"dependencies": { | ||
"react": "^18.2.0", | ||
"react-dom": "^18.2.0", | ||
"react-yjs": "workspace:*", | ||
"yjs": "^13.6.16" | ||
}, | ||
"devDependencies": { | ||
"@types/react": "^18.2.66", | ||
"@types/react-dom": "^18.2.22", | ||
"@typescript-eslint/eslint-plugin": "^7.2.0", | ||
"@typescript-eslint/parser": "^7.2.0", | ||
"@vitejs/plugin-react": "^4.2.1", | ||
"eslint": "^8.57.0", | ||
"eslint-plugin-react-hooks": "^4.6.0", | ||
"eslint-plugin-react-refresh": "^0.4.6", | ||
"typescript": "^5.2.2", | ||
"vite": "^5.2.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import React from "react"; | ||
import { DeepStructure } from "./DeepStructure"; | ||
import { Settings } from "./Settings"; | ||
import { Todos } from "./Todos"; | ||
|
||
export const App: React.FC = () => { | ||
return ( | ||
<> | ||
<h2>Settings Example</h2> | ||
<Settings /> | ||
<hr /> | ||
<h2>Todos Example</h2> | ||
<Todos /> | ||
<hr /> | ||
<h2>Deep Structure Example</h2> | ||
<DeepStructure /> | ||
</> | ||
); | ||
}; |
Oops, something went wrong.