@sylphx/lens-react 1.2.4 → 1.2.7
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 +44 -0
- package/package.json +45 -44
- package/src/context.tsx +1 -5
- package/src/hooks.test.tsx +18 -17
- package/src/index.ts +8 -8
package/README.md
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# @sylphx/lens-react
|
|
2
|
+
|
|
3
|
+
React hooks for the Lens API framework.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
bun add @sylphx/lens-react
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { LensProvider, useQuery, useMutation } from "@sylphx/lens-react";
|
|
15
|
+
import { client } from "./client";
|
|
16
|
+
|
|
17
|
+
function App() {
|
|
18
|
+
return (
|
|
19
|
+
<LensProvider client={client}>
|
|
20
|
+
<UserProfile />
|
|
21
|
+
</LensProvider>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function UserProfile() {
|
|
26
|
+
const { data, loading, error } = useQuery(client.user.get({ id: "1" }));
|
|
27
|
+
const [createUser, { loading: creating }] = useMutation(client.user.create);
|
|
28
|
+
|
|
29
|
+
if (loading) return <div>Loading...</div>;
|
|
30
|
+
if (error) return <div>Error: {error.message}</div>;
|
|
31
|
+
|
|
32
|
+
return <div>{data.name}</div>;
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## License
|
|
37
|
+
|
|
38
|
+
MIT
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
Built with [@sylphx/lens-client](https://github.com/SylphxAI/Lens).
|
|
43
|
+
|
|
44
|
+
✨ Powered by Sylphx
|
package/package.json
CHANGED
|
@@ -1,46 +1,47 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
2
|
+
"name": "@sylphx/lens-react",
|
|
3
|
+
"version": "1.2.7",
|
|
4
|
+
"description": "React bindings for Lens API framework",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "bunup",
|
|
16
|
+
"typecheck": "tsc --noEmit",
|
|
17
|
+
"test": "bun test",
|
|
18
|
+
"prepack": "bun run build"
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"dist",
|
|
22
|
+
"src"
|
|
23
|
+
],
|
|
24
|
+
"keywords": [
|
|
25
|
+
"lens",
|
|
26
|
+
"react",
|
|
27
|
+
"hooks",
|
|
28
|
+
"reactive"
|
|
29
|
+
],
|
|
30
|
+
"author": "SylphxAI",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"dependencies": {
|
|
33
|
+
"@sylphx/lens-client": "^1.6.0"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": ">=18.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@happy-dom/global-registrator": "^20.0.10",
|
|
40
|
+
"@testing-library/react": "^16.2.0",
|
|
41
|
+
"@types/react": "^19.1.6",
|
|
42
|
+
"happy-dom": "^20.0.10",
|
|
43
|
+
"react": "^19.1.0",
|
|
44
|
+
"react-dom": "^19.1.0",
|
|
45
|
+
"typescript": "^5.9.3"
|
|
46
|
+
}
|
|
46
47
|
}
|
package/src/context.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import type { LensClient } from "@sylphx/lens-client";
|
|
8
|
-
import { type ReactElement, type ReactNode,
|
|
8
|
+
import { createContext, type ReactElement, type ReactNode, useContext } from "react";
|
|
9
9
|
|
|
10
10
|
// =============================================================================
|
|
11
11
|
// Context
|
|
@@ -15,7 +15,6 @@ import { type ReactElement, type ReactNode, createContext, useContext } from "re
|
|
|
15
15
|
* Context for Lens client
|
|
16
16
|
* Using any for internal storage to avoid type constraint issues
|
|
17
17
|
*/
|
|
18
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
19
18
|
const LensContext = createContext<LensClient<any, any> | null>(null);
|
|
20
19
|
|
|
21
20
|
// =============================================================================
|
|
@@ -24,7 +23,6 @@ const LensContext = createContext<LensClient<any, any> | null>(null);
|
|
|
24
23
|
|
|
25
24
|
export interface LensProviderProps {
|
|
26
25
|
/** Lens client instance */
|
|
27
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
28
26
|
client: LensClient<any, any>;
|
|
29
27
|
/** Children */
|
|
30
28
|
children: ReactNode;
|
|
@@ -74,7 +72,6 @@ export function LensProvider({ client, children }: LensProviderProps): ReactElem
|
|
|
74
72
|
* }
|
|
75
73
|
* ```
|
|
76
74
|
*/
|
|
77
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
78
75
|
export function useLensClient<TRouter = any>(): LensClient<any, any> & TRouter {
|
|
79
76
|
const client = useContext(LensContext);
|
|
80
77
|
|
|
@@ -85,6 +82,5 @@ export function useLensClient<TRouter = any>(): LensClient<any, any> & TRouter {
|
|
|
85
82
|
);
|
|
86
83
|
}
|
|
87
84
|
|
|
88
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
89
85
|
return client as LensClient<any, any> & TRouter;
|
|
90
86
|
}
|
package/src/hooks.test.tsx
CHANGED
|
@@ -1,10 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tests for React Hooks (Operations-based API)
|
|
3
|
+
*
|
|
4
|
+
* NOTE: These tests require DOM environment (happy-dom).
|
|
5
|
+
* Run from packages/react directory: cd packages/react && bun test
|
|
3
6
|
*/
|
|
4
7
|
|
|
5
|
-
|
|
6
|
-
|
|
8
|
+
// Skip all tests if DOM is not available (when run from root)
|
|
9
|
+
const hasDom = typeof document !== "undefined";
|
|
10
|
+
|
|
11
|
+
import { test as bunTest, describe, expect } from "bun:test";
|
|
12
|
+
|
|
13
|
+
const test = hasDom ? bunTest : bunTest.skip;
|
|
14
|
+
|
|
7
15
|
import type { MutationResult, QueryResult } from "@sylphx/lens-client";
|
|
16
|
+
import { signal } from "@sylphx/lens-client";
|
|
8
17
|
import { act, renderHook, waitFor } from "@testing-library/react";
|
|
9
18
|
import { useLazyQuery, useMutation, useQuery } from "./hooks";
|
|
10
19
|
|
|
@@ -17,7 +26,7 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
17
26
|
_setError: (error: Error) => void;
|
|
18
27
|
} {
|
|
19
28
|
let currentValue = initialValue;
|
|
20
|
-
let
|
|
29
|
+
let _currentError: Error | null = null;
|
|
21
30
|
const subscribers: Array<(value: T) => void> = [];
|
|
22
31
|
let resolved = false;
|
|
23
32
|
let resolvePromise: ((value: T) => void) | null = null;
|
|
@@ -66,14 +75,14 @@ function createMockQueryResult<T>(initialValue: T | null = null): QueryResult<T>
|
|
|
66
75
|
result.signal.value = value;
|
|
67
76
|
result.loading.value = false;
|
|
68
77
|
result.error.value = null;
|
|
69
|
-
|
|
78
|
+
for (const cb of subscribers) cb(value);
|
|
70
79
|
if (!resolved && resolvePromise) {
|
|
71
80
|
resolved = true;
|
|
72
81
|
resolvePromise(value);
|
|
73
82
|
}
|
|
74
83
|
},
|
|
75
84
|
_setError(error: Error) {
|
|
76
|
-
|
|
85
|
+
_currentError = error;
|
|
77
86
|
result.loading.value = false;
|
|
78
87
|
result.error.value = error;
|
|
79
88
|
if (!resolved && rejectPromise) {
|
|
@@ -180,9 +189,7 @@ describe("useQuery", () => {
|
|
|
180
189
|
|
|
181
190
|
describe("useMutation", () => {
|
|
182
191
|
test("executes mutation and returns result", async () => {
|
|
183
|
-
const mutationFn = async (input: { name: string }): Promise<
|
|
184
|
-
MutationResult<{ id: string; name: string }>
|
|
185
|
-
> => {
|
|
192
|
+
const mutationFn = async (input: { name: string }): Promise<MutationResult<{ id: string; name: string }>> => {
|
|
186
193
|
return {
|
|
187
194
|
data: { id: "new-id", name: input.name },
|
|
188
195
|
};
|
|
@@ -204,9 +211,7 @@ describe("useMutation", () => {
|
|
|
204
211
|
});
|
|
205
212
|
|
|
206
213
|
test("handles mutation error", async () => {
|
|
207
|
-
const mutationFn = async (_input: { name: string }): Promise<
|
|
208
|
-
MutationResult<{ id: string; name: string }>
|
|
209
|
-
> => {
|
|
214
|
+
const mutationFn = async (_input: { name: string }): Promise<MutationResult<{ id: string; name: string }>> => {
|
|
210
215
|
throw new Error("Mutation failed");
|
|
211
216
|
};
|
|
212
217
|
|
|
@@ -226,9 +231,7 @@ describe("useMutation", () => {
|
|
|
226
231
|
|
|
227
232
|
test("shows loading state during mutation", async () => {
|
|
228
233
|
let resolveMutation: ((value: MutationResult<{ id: string }>) => void) | null = null;
|
|
229
|
-
const mutationFn = async (_input: { name: string }): Promise<
|
|
230
|
-
MutationResult<{ id: string }>
|
|
231
|
-
> => {
|
|
234
|
+
const mutationFn = async (_input: { name: string }): Promise<MutationResult<{ id: string }>> => {
|
|
232
235
|
return new Promise((resolve) => {
|
|
233
236
|
resolveMutation = resolve;
|
|
234
237
|
});
|
|
@@ -255,9 +258,7 @@ describe("useMutation", () => {
|
|
|
255
258
|
});
|
|
256
259
|
|
|
257
260
|
test("reset clears mutation state", async () => {
|
|
258
|
-
const mutationFn = async (input: { name: string }): Promise<
|
|
259
|
-
MutationResult<{ id: string; name: string }>
|
|
260
|
-
> => {
|
|
261
|
+
const mutationFn = async (input: { name: string }): Promise<MutationResult<{ id: string; name: string }>> => {
|
|
261
262
|
return { data: { id: "new-id", name: input.name } };
|
|
262
263
|
};
|
|
263
264
|
|
package/src/index.ts
CHANGED
|
@@ -9,23 +9,23 @@
|
|
|
9
9
|
// Context & Provider
|
|
10
10
|
// =============================================================================
|
|
11
11
|
|
|
12
|
-
export { LensProvider,
|
|
12
|
+
export { LensProvider, type LensProviderProps, useLensClient } from "./context";
|
|
13
13
|
|
|
14
14
|
// =============================================================================
|
|
15
15
|
// Hooks (Operations-based API)
|
|
16
16
|
// =============================================================================
|
|
17
17
|
|
|
18
18
|
export {
|
|
19
|
-
|
|
20
|
-
useQuery,
|
|
21
|
-
useLazyQuery,
|
|
22
|
-
// Mutation hook
|
|
23
|
-
useMutation,
|
|
19
|
+
type MutationFn,
|
|
24
20
|
// Types
|
|
25
21
|
type QueryInput,
|
|
26
|
-
type UseQueryResult,
|
|
27
22
|
type UseLazyQueryResult,
|
|
28
23
|
type UseMutationResult,
|
|
29
24
|
type UseQueryOptions,
|
|
30
|
-
type
|
|
25
|
+
type UseQueryResult,
|
|
26
|
+
useLazyQuery,
|
|
27
|
+
// Mutation hook
|
|
28
|
+
useMutation,
|
|
29
|
+
// Query hooks
|
|
30
|
+
useQuery,
|
|
31
31
|
} from "./hooks";
|