@legit-sdk/react 0.1.6 → 0.1.8
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 +60 -31
- package/dist/index.d.ts +5 -2
- package/dist/index.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @legit-sdk/react
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
React hooks for `@legit-sdk/core` - local-first file editing with version control.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
@@ -8,32 +8,29 @@ Thin React wrapper around `@legit-sdk/core` providing a provider for SDK initial
|
|
|
8
8
|
pnpm add @legit-sdk/core @legit-sdk/react
|
|
9
9
|
```
|
|
10
10
|
|
|
11
|
-
Peer dependencies
|
|
11
|
+
**Peer dependencies:** `react >=18`
|
|
12
12
|
|
|
13
|
-
##
|
|
14
|
-
|
|
15
|
-
- Wrap your app with `LegitProvider` once.
|
|
16
|
-
- Use `useLegitFile(path)` inside components to read/update a file and access history.
|
|
13
|
+
## Usage
|
|
17
14
|
|
|
18
15
|
```tsx
|
|
19
|
-
import React from 'react';
|
|
20
16
|
import { LegitProvider, useLegitFile } from '@legit-sdk/react';
|
|
21
17
|
|
|
22
18
|
function Editor() {
|
|
23
|
-
const { content, setContent, history, loading
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
const { content, setContent, history, loading } = useLegitFile(
|
|
20
|
+
'/document.txt',
|
|
21
|
+
{ initialContent: 'Hello World' } // auto-create if missing
|
|
22
|
+
);
|
|
23
|
+
const [text, setText] = useState(content || '');
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
if (error) return <div>Error: {error.message}</div>;
|
|
25
|
+
useEffect(() => setText(content || ''), [content]);
|
|
31
26
|
|
|
32
27
|
return (
|
|
33
28
|
<div>
|
|
34
|
-
<
|
|
29
|
+
<textarea value={text} onChange={e => setText(e.target.value)} />
|
|
35
30
|
<button onClick={() => setContent(text)}>Save</button>
|
|
36
|
-
|
|
31
|
+
{history.map(h => (
|
|
32
|
+
<div key={h.oid}>{h.message}</div>
|
|
33
|
+
))}
|
|
37
34
|
</div>
|
|
38
35
|
);
|
|
39
36
|
}
|
|
@@ -49,24 +46,56 @@ export default function App() {
|
|
|
49
46
|
|
|
50
47
|
## API
|
|
51
48
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
49
|
+
### `LegitProvider`
|
|
50
|
+
|
|
51
|
+
Wraps your app and initializes the SDK instance. Polls HEAD for changes.
|
|
52
|
+
|
|
53
|
+
```tsx
|
|
54
|
+
<LegitProvider>
|
|
55
|
+
<YourApp />
|
|
56
|
+
</LegitProvider>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### `useLegitFile(path, options?)`
|
|
60
|
+
|
|
61
|
+
Hook for file operations.
|
|
60
62
|
|
|
61
|
-
|
|
63
|
+
**Options:**
|
|
64
|
+
|
|
65
|
+
- `initialContent?: string` - Auto-create file with this content if missing
|
|
66
|
+
|
|
67
|
+
**Returns:**
|
|
68
|
+
|
|
69
|
+
- `content: string | null` - Current file content
|
|
70
|
+
- `setContent(text: string): Promise<void>` - Save and commit
|
|
71
|
+
- `history: HistoryItem[]` - Commit history
|
|
72
|
+
- `getPastState(oid: string): Promise<string>` - Read file at commit
|
|
73
|
+
- `loading: boolean` - Loading state
|
|
74
|
+
- `error?: Error` - Error state
|
|
75
|
+
|
|
76
|
+
### `useLegitContext()`
|
|
77
|
+
|
|
78
|
+
Access provider context (legitFs, head, loading, error).
|
|
62
79
|
|
|
63
80
|
## Types
|
|
64
81
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
82
|
+
```ts
|
|
83
|
+
interface UseLegitFileOptions {
|
|
84
|
+
initialContent?: string;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
type UseLegitFileReturn = {
|
|
88
|
+
content: string | null;
|
|
89
|
+
setContent: (text: string) => Promise<void>;
|
|
90
|
+
history: HistoryItem[];
|
|
91
|
+
getPastState: (oid: string) => Promise<string>;
|
|
92
|
+
loading: boolean;
|
|
93
|
+
error?: Error;
|
|
94
|
+
legitFs: LegitFs | null;
|
|
95
|
+
};
|
|
96
|
+
```
|
|
68
97
|
|
|
69
|
-
##
|
|
98
|
+
## See Also
|
|
70
99
|
|
|
71
|
-
-
|
|
72
|
-
-
|
|
100
|
+
- [Starter Example](../../examples/react-starter) - Full working example
|
|
101
|
+
- [Spec Documentation](./spec.md) - Detailed API documentation
|
package/dist/index.d.ts
CHANGED
|
@@ -14,6 +14,9 @@ interface LegitProviderProps {
|
|
|
14
14
|
}
|
|
15
15
|
declare const LegitProvider: ({ children }: LegitProviderProps) => react_jsx_runtime.JSX.Element;
|
|
16
16
|
|
|
17
|
+
interface UseLegitFileOptions {
|
|
18
|
+
initialContent?: string;
|
|
19
|
+
}
|
|
17
20
|
type UseLegitFileReturn = {
|
|
18
21
|
content: string | null;
|
|
19
22
|
setContent: (newText: string) => Promise<void>;
|
|
@@ -23,7 +26,7 @@ type UseLegitFileReturn = {
|
|
|
23
26
|
error?: Error;
|
|
24
27
|
legitFs: Awaited<ReturnType<typeof initLegitFs>> | null;
|
|
25
28
|
};
|
|
26
|
-
declare function useLegitFile(path: string): UseLegitFileReturn;
|
|
29
|
+
declare function useLegitFile(path: string, options?: UseLegitFileOptions): UseLegitFileReturn;
|
|
27
30
|
|
|
28
31
|
export { LegitProvider, useLegitContext, useLegitFile };
|
|
29
|
-
export type { LegitContextValue, LegitProviderProps, UseLegitFileReturn };
|
|
32
|
+
export type { LegitContextValue, LegitProviderProps, UseLegitFileOptions, UseLegitFileReturn };
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
// @legit-sdk/react bundle (ESM)
|
|
2
2
|
// Generated by esbuild
|
|
3
3
|
|
|
4
|
-
var
|
|
4
|
+
var T=Object.defineProperty;var s=(i,l)=>T(i,"name",{value:l,configurable:!0});import{createContext as U,useContext as z,useEffect as A,useState as F,useRef as $}from"react";import{initLegitFs as V}from"@legit-sdk/core";import k from"memfs";import{jsx as D}from"react/jsx-runtime";var N=U({legitFs:null,loading:!0,head:null}),E=s(()=>z(N),"useLegitContext"),_=500,J=s(({children:i})=>{let[l,e]=F(null),[x,y]=F(!0),[f,g]=F(),[P,m]=F(null),a=$(null);return A(()=>{let o=!0,d,u="";return s(async()=>{try{let n=await V(k,"/");if(!o)return;e(n),y(!1),d=setInterval(async()=>{if(!(!o||!n))try{let t=await n.promises.readFile("/.legit/branches/main/.legit/head","utf8");t!==u&&t!==a.current&&(u=t,a.current=t,m(t))}catch(t){o&&t?.code!=="ENOENT"&&console.error("Polling head failed:",t)}},_)}catch(n){o&&(g(n),y(!1))}},"initFs")(),()=>{o=!1,d&&clearInterval(d)}},[]),D(N.Provider,{value:{legitFs:l,loading:x,head:P,error:f},children:i})},"LegitProvider");import{useEffect as b,useState as h,useRef as R,useCallback as M}from"react";function q(i,l){let{legitFs:e,error:x,head:y}=E(),[f,g]=h(null),[P,m]=h([]),[a,o]=h(!0),[d,u]=h(),p=R(null),n=R(!1),t=R(!1);b(()=>{if(!e)return;let r=!1;return s(async()=>{o(!0);try{let L=`/.legit/branches/main${i}`,O="/.legit/branches/main/.legit/history",[v,w]=await Promise.allSettled([e.promises.readFile(L,"utf8"),e.promises.readFile(O,"utf8").catch(()=>"")]);if(r)return;let H=v.status==="fulfilled"?v.value:null,S=[];if(w.status==="fulfilled")try{let I=w.value;I&&(S=JSON.parse(I))}catch{}p.current===H&&(p.current=null),g(H),m(S),u(void 0)}catch(L){L?.code!=="ENOENT"?u(L):(g(null),m([]))}finally{r||o(!1)}},"load")(),()=>{r=!0}},[e,i,y]);let C=M(async r=>{if(e)try{p.current=r,await e.promises.writeFile(`/.legit/branches/main${i}`,r,"utf8"),g(r)}catch(c){throw p.current=null,u(c),c}},[e,i]);return b(()=>{n.current||t.current||!a&&f===null&&e&&l?.initialContent&&(t.current=!0,n.current=!0,s(async()=>{try{await C(l.initialContent)}catch(c){console.error("Failed to initialize file:",c),n.current=!1}finally{t.current=!1}},"initialize")())},[a,f,e,l?.initialContent,C]),{content:f,setContent:C,history:P,getPastState:s(async r=>{if(!e)return"";try{return await e.promises.readFile(`/.legit/commits/${r.slice(0,2)}/${r.slice(2)}${i}`,"utf8")}catch{return""}},"getPastState"),loading:a,error:d??x,legitFs:e}}s(q,"useLegitFile");export{J as LegitProvider,E as useLegitContext,q as useLegitFile};
|