@automerge/automerge-repo-react-hooks 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # React Hooks for Automerge Repo
2
+
3
+ ## Example usage
4
+
5
+ ### App Setup
6
+
7
+ ```ts
8
+ import React, { StrictMode } from "react"
9
+ import ReactDOM from "react-dom/client"
10
+ import localforage from "localforage"
11
+
12
+ import { Repo, DocCollection } from "@automerge/automerge-repo"
13
+
14
+ import { BroadcastChannelNetworkAdapter } from "@automerge/automerge-repo-network-broadcastchannel"
15
+ import { LocalFirstRelayNetworkAdapter } from "@automerge/automerge-repo-network-localfirstrelay"
16
+
17
+ import App, { RootDocument } from "./App.js"
18
+ import { RepoContext } from "@automerge/automerge-repo-react-hooks"
19
+
20
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
21
+ const sharedWorker = new SharedWorker(
22
+ new URL("./shared-worker.js", import.meta.url),
23
+ { type: "module", name: "@automerge/automerge-repo-shared-worker" }
24
+ )
25
+
26
+ async function getRepo(url: string): Promise<DocCollection> {
27
+ return await Repo({
28
+ network: [
29
+ new BroadcastChannelNetworkAdapter(),
30
+ new LocalFirstRelayNetworkAdapter("wss://local-first-relay.glitch.me/"),
31
+ ],
32
+ sharePolicy: peerId => peerId.includes("shared-worker"),
33
+ })
34
+ }
35
+
36
+ async function getRootDocument(repo: DocCollection, initFunction: any) {
37
+ let docId: string | null = window.location.hash.replace(/^#/, "")
38
+ if (!docId) {
39
+ docId = await localforage.getItem("root")
40
+ }
41
+ let rootHandle
42
+
43
+ if (!docId) {
44
+ rootHandle = repo.create()
45
+ rootHandle.change(initFunction)
46
+ await localforage.setItem("root", rootHandle.documentId)
47
+ } else {
48
+ rootHandle = await repo.find(docId)
49
+ window.location.hash = docId
50
+ }
51
+ return rootHandle
52
+ }
53
+
54
+ const initFunction = (d: RootDocument) => {
55
+ d.items = []
56
+ }
57
+
58
+ const queryString = window.location.search // Returns:'?q=123'
59
+
60
+ // Further parsing:
61
+ const params = new URLSearchParams(queryString)
62
+ const hostname = params.get("host") || "automerge-storage-demo.glitch.me"
63
+
64
+ getRepo(`wss://${hostname}`).then(repo => {
65
+ getRootDocument(repo, initFunction).then(rootDoc => {
66
+ const rootElem = document.getElementById("root")
67
+ if (!rootElem) {
68
+ throw new Error("The 'root' element wasn't found in the host HTML doc.")
69
+ }
70
+ const root = ReactDOM.createRoot(rootElem)
71
+ root.render(
72
+ <StrictMode>
73
+ <RepoContext.Provider value={repo}>
74
+ <App rootDocumentId={rootDoc.documentId} />
75
+ </RepoContext.Provider>
76
+ </StrictMode>
77
+ )
78
+ })
79
+ })
80
+ ```
@@ -0,0 +1,4 @@
1
+ export { useDocument } from "./useDocument.js";
2
+ export { useHandle } from "./useHandle.js";
3
+ export { RepoContext, useRepo } from "./useRepo.js";
4
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAA;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAA;AAC1C,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,MAAM,cAAc,CAAA"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { useDocument } from "./useDocument.js";
2
+ export { useHandle } from "./useHandle.js";
3
+ export { RepoContext, useRepo } from "./useRepo.js";
@@ -0,0 +1,4 @@
1
+ import { Doc, ChangeFn } from "@automerge/automerge";
2
+ import { DocumentId } from "@automerge/automerge-repo";
3
+ export declare function useDocument<T>(documentId?: DocumentId): [Doc<T>, (changeFn: ChangeFn<T>) => void];
4
+ //# sourceMappingURL=useDocument.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useDocument.d.ts","sourceRoot":"","sources":["../src/useDocument.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAA;AACpD,OAAO,EAAE,UAAU,EAAyB,MAAM,2BAA2B,CAAA;AAI7E,wBAAgB,WAAW,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU,uBAyBL,SAAS,CAAC,CAAC,KAAK,IAAI,EACpE"}
@@ -0,0 +1,24 @@
1
+ import { useEffect, useState } from "react";
2
+ import { useRepo } from "./useRepo";
3
+ export function useDocument(documentId) {
4
+ const [doc, setDoc] = useState();
5
+ const repo = useRepo();
6
+ const handle = documentId ? repo.find(documentId) : null;
7
+ useEffect(() => {
8
+ if (!handle)
9
+ return;
10
+ handle.value().then(v => setDoc(v));
11
+ const onPatch = (h) => setDoc(h.after);
12
+ handle.on("patch", onPatch);
13
+ const cleanup = () => {
14
+ handle.removeListener("patch", onPatch);
15
+ };
16
+ return cleanup;
17
+ }, [handle]);
18
+ const changeDoc = (changeFn) => {
19
+ if (!handle)
20
+ return;
21
+ handle.change(changeFn);
22
+ };
23
+ return [doc, changeDoc];
24
+ }
@@ -0,0 +1,3 @@
1
+ import { DocHandle, DocumentId } from "@automerge/automerge-repo";
2
+ export declare function useHandle<T>(documentId: DocumentId): DocHandle<T>;
3
+ //# sourceMappingURL=useHandle.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHandle.d.ts","sourceRoot":"","sources":["../src/useHandle.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,2BAA2B,CAAA;AAIjE,wBAAgB,SAAS,CAAC,CAAC,EAAE,UAAU,EAAE,UAAU,GAAG,SAAS,CAAC,CAAC,CAAC,CAIjE"}
@@ -0,0 +1,7 @@
1
+ import { useState } from "react";
2
+ import { useRepo } from "./useRepo.js";
3
+ export function useHandle(documentId) {
4
+ const repo = useRepo();
5
+ const [handle] = useState(repo.find(documentId));
6
+ return handle;
7
+ }
@@ -0,0 +1,5 @@
1
+ /// <reference types="react" />
2
+ import { Repo } from "@automerge/automerge-repo";
3
+ export declare const RepoContext: import("react").Context<Repo>;
4
+ export declare function useRepo(): Repo;
5
+ //# sourceMappingURL=useRepo.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useRepo.d.ts","sourceRoot":"","sources":["../src/useRepo.ts"],"names":[],"mappings":";AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,2BAA2B,CAAA;AAGhD,eAAO,MAAM,WAAW,+BAAmC,CAAA;AAE3D,wBAAgB,OAAO,IAAI,IAAI,CAI9B"}
@@ -0,0 +1,8 @@
1
+ import { createContext, useContext } from "react";
2
+ export const RepoContext = createContext(null);
3
+ export function useRepo() {
4
+ const repo = useContext(RepoContext);
5
+ if (!repo)
6
+ throw new Error("Repo was not found on RepoContext.");
7
+ return repo;
8
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@automerge/automerge-repo-react-hooks",
3
+ "version": "0.0.1",
4
+ "description": "Hooks to access an Automerge Repo from your react app.",
5
+ "repository": "https://github.com/pvh/automerge-repo",
6
+ "author": "Peter van Hardenberg <pvh@pvh.ca>",
7
+ "license": "MIT",
8
+ "private": false,
9
+ "type": "module",
10
+ "main": "dist/index.js",
11
+ "scripts": {
12
+ "build": "tsc",
13
+ "watch": "npm-watch"
14
+ },
15
+ "dependencies": {
16
+ "@automerge/automerge-repo": "^0.0.1"
17
+ },
18
+ "watch": {
19
+ "build": {
20
+ "patterns": "./src/**/*",
21
+ "extensions": [
22
+ ".ts"
23
+ ]
24
+ }
25
+ },
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "gitHead": "e572f26ae416140b025c3ba557d9f781abbdada1"
30
+ }
package/src/index.ts ADDED
@@ -0,0 +1,3 @@
1
+ export { useDocument } from "./useDocument.js"
2
+ export { useHandle } from "./useHandle.js"
3
+ export { RepoContext, useRepo } from "./useRepo.js"
@@ -0,0 +1,32 @@
1
+ import { Doc, ChangeFn } from "@automerge/automerge"
2
+ import { DocumentId, DocHandlePatchPayload } from "@automerge/automerge-repo"
3
+ import { useEffect, useState } from "react"
4
+ import { useRepo } from "./useRepo"
5
+
6
+ export function useDocument<T>(documentId?: DocumentId) {
7
+ const [doc, setDoc] = useState<Doc<T>>()
8
+ const repo = useRepo()
9
+
10
+ const handle = documentId ? repo.find<T>(documentId) : null
11
+
12
+ useEffect(() => {
13
+ if (!handle) return
14
+
15
+ handle.value().then(v => setDoc(v))
16
+
17
+ const onPatch = (h: DocHandlePatchPayload<T>) => setDoc(h.after)
18
+ handle.on("patch", onPatch)
19
+ const cleanup = () => {
20
+ handle.removeListener("patch", onPatch)
21
+ }
22
+
23
+ return cleanup
24
+ }, [handle])
25
+
26
+ const changeDoc = (changeFn: ChangeFn<T>) => {
27
+ if (!handle) return
28
+ handle.change(changeFn)
29
+ }
30
+
31
+ return [doc, changeDoc] as [Doc<T>, (changeFn: ChangeFn<T>) => void]
32
+ }
@@ -0,0 +1,9 @@
1
+ import { DocHandle, DocumentId } from "@automerge/automerge-repo"
2
+ import { useState } from "react"
3
+ import { useRepo } from "./useRepo.js"
4
+
5
+ export function useHandle<T>(documentId: DocumentId): DocHandle<T> {
6
+ const repo = useRepo()
7
+ const [handle] = useState<DocHandle<T>>(repo.find(documentId))
8
+ return handle
9
+ }
package/src/useRepo.ts ADDED
@@ -0,0 +1,10 @@
1
+ import { Repo } from "@automerge/automerge-repo"
2
+ import { createContext, useContext } from "react"
3
+
4
+ export const RepoContext = createContext<Repo | null>(null)
5
+
6
+ export function useRepo(): Repo {
7
+ const repo = useContext(RepoContext)
8
+ if (!repo) throw new Error("Repo was not found on RepoContext.")
9
+ return repo
10
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,16 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ESNext",
4
+ "jsx": "react",
5
+ "module": "ESNext",
6
+ "moduleResolution": "node",
7
+ "declaration": true,
8
+ "declarationMap": true,
9
+ "outDir": "./dist",
10
+ "esModuleInterop": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "strict": false,
13
+ "skipLibCheck": true
14
+ },
15
+ "include": ["src/**/*.ts"]
16
+ }