@sylphx/lens-react 1.0.5 → 1.2.0
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/dist/index.d.ts +30 -10
- package/dist/index.js +26 -9
- package/package.json +1 -1
- package/src/hooks.ts +73 -16
- package/src/index.ts +1 -0
package/dist/index.d.ts
CHANGED
|
@@ -45,6 +45,8 @@ declare function LensProvider({ client, children }: LensProviderProps): ReactEle
|
|
|
45
45
|
*/
|
|
46
46
|
declare function useLensClient<TRouter = any>(): LensClient<any, any> & TRouter;
|
|
47
47
|
import { MutationResult, QueryResult } from "@sylphx/lens-client";
|
|
48
|
+
/** Query input - can be a query, null/undefined, or an accessor function */
|
|
49
|
+
type QueryInput<T> = QueryResult<T> | null | undefined | (() => QueryResult<T> | null | undefined);
|
|
48
50
|
/** Result of useQuery hook */
|
|
49
51
|
interface UseQueryResult<T> {
|
|
50
52
|
/** Query data (null if loading or error) */
|
|
@@ -80,7 +82,7 @@ interface UseQueryOptions {
|
|
|
80
82
|
/**
|
|
81
83
|
* Subscribe to a query with reactive updates
|
|
82
84
|
*
|
|
83
|
-
* @param
|
|
85
|
+
* @param queryInput - QueryResult, null/undefined, or accessor function returning QueryResult
|
|
84
86
|
* @param options - Query options
|
|
85
87
|
*
|
|
86
88
|
* @example
|
|
@@ -97,14 +99,23 @@ interface UseQueryOptions {
|
|
|
97
99
|
* return <h1>{user.name}</h1>;
|
|
98
100
|
* }
|
|
99
101
|
*
|
|
100
|
-
* //
|
|
101
|
-
* function
|
|
102
|
+
* // Conditional query (null when condition not met)
|
|
103
|
+
* function SessionInfo({ sessionId }: { sessionId: string | null }) {
|
|
102
104
|
* const client = useLensClient();
|
|
103
105
|
* const { data } = useQuery(
|
|
104
|
-
* client.
|
|
106
|
+
* sessionId ? client.session.get({ id: sessionId }) : null
|
|
105
107
|
* );
|
|
106
|
-
* // data is
|
|
107
|
-
* return <span>{data?.
|
|
108
|
+
* // data is null when sessionId is null
|
|
109
|
+
* return <span>{data?.totalTokens}</span>;
|
|
110
|
+
* }
|
|
111
|
+
*
|
|
112
|
+
* // Accessor function (reactive inputs)
|
|
113
|
+
* function ReactiveQuery({ sessionId }: { sessionId: Signal<string | null> }) {
|
|
114
|
+
* const client = useLensClient();
|
|
115
|
+
* const { data } = useQuery(() =>
|
|
116
|
+
* sessionId.value ? client.session.get({ id: sessionId.value }) : null
|
|
117
|
+
* );
|
|
118
|
+
* return <span>{data?.totalTokens}</span>;
|
|
108
119
|
* }
|
|
109
120
|
*
|
|
110
121
|
* // Skip query conditionally
|
|
@@ -114,7 +125,7 @@ interface UseQueryOptions {
|
|
|
114
125
|
* }
|
|
115
126
|
* ```
|
|
116
127
|
*/
|
|
117
|
-
declare function useQuery<T>(
|
|
128
|
+
declare function useQuery<T>(queryInput: QueryInput<T>, options?: UseQueryOptions): UseQueryResult<T>;
|
|
118
129
|
/** Mutation function type */
|
|
119
130
|
type MutationFn<
|
|
120
131
|
TInput,
|
|
@@ -185,7 +196,7 @@ interface UseLazyQueryResult<T> {
|
|
|
185
196
|
/**
|
|
186
197
|
* Execute a query on demand (not on mount)
|
|
187
198
|
*
|
|
188
|
-
* @param
|
|
199
|
+
* @param queryInput - QueryResult, null/undefined, or accessor function returning QueryResult
|
|
189
200
|
*
|
|
190
201
|
* @example
|
|
191
202
|
* ```tsx
|
|
@@ -214,7 +225,16 @@ interface UseLazyQueryResult<T> {
|
|
|
214
225
|
* </div>
|
|
215
226
|
* );
|
|
216
227
|
* }
|
|
228
|
+
*
|
|
229
|
+
* // With accessor function
|
|
230
|
+
* function LazyReactiveQuery({ sessionId }: { sessionId: Signal<string | null> }) {
|
|
231
|
+
* const client = useLensClient();
|
|
232
|
+
* const { execute, data } = useLazyQuery(() =>
|
|
233
|
+
* sessionId.value ? client.session.get({ id: sessionId.value }) : null
|
|
234
|
+
* );
|
|
235
|
+
* return <button onClick={execute}>Load</button>;
|
|
236
|
+
* }
|
|
217
237
|
* ```
|
|
218
238
|
*/
|
|
219
|
-
declare function useLazyQuery<T>(
|
|
220
|
-
export { useQuery, useMutation, useLensClient, useLazyQuery, UseQueryResult, UseQueryOptions, UseMutationResult, UseLazyQueryResult, MutationFn, LensProviderProps, LensProvider };
|
|
239
|
+
declare function useLazyQuery<T>(queryInput: QueryInput<T>): UseLazyQueryResult<T>;
|
|
240
|
+
export { useQuery, useMutation, useLensClient, useLazyQuery, UseQueryResult, UseQueryOptions, UseMutationResult, UseLazyQueryResult, QueryInput, MutationFn, LensProviderProps, LensProvider };
|
package/dist/index.js
CHANGED
|
@@ -16,16 +16,24 @@ function useLensClient() {
|
|
|
16
16
|
return client;
|
|
17
17
|
}
|
|
18
18
|
// src/hooks.ts
|
|
19
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
20
|
-
function
|
|
19
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
20
|
+
function resolveQuery(input) {
|
|
21
|
+
return typeof input === "function" ? input() : input;
|
|
22
|
+
}
|
|
23
|
+
function useQuery(queryInput, options) {
|
|
24
|
+
const query = useMemo(() => resolveQuery(queryInput), [queryInput]);
|
|
21
25
|
const [data, setData] = useState(null);
|
|
22
|
-
const [loading, setLoading] = useState(!options?.skip);
|
|
26
|
+
const [loading, setLoading] = useState(!options?.skip && query != null);
|
|
23
27
|
const [error, setError] = useState(null);
|
|
24
28
|
const mountedRef = useRef(true);
|
|
29
|
+
const queryRef = useRef(query);
|
|
30
|
+
queryRef.current = query;
|
|
25
31
|
useEffect(() => {
|
|
26
32
|
mountedRef.current = true;
|
|
27
|
-
if (options?.skip) {
|
|
33
|
+
if (query == null || options?.skip) {
|
|
34
|
+
setData(null);
|
|
28
35
|
setLoading(false);
|
|
36
|
+
setError(null);
|
|
29
37
|
return;
|
|
30
38
|
}
|
|
31
39
|
setLoading(true);
|
|
@@ -53,11 +61,12 @@ function useQuery(query, options) {
|
|
|
53
61
|
};
|
|
54
62
|
}, [query, options?.skip]);
|
|
55
63
|
const refetch = useCallback(() => {
|
|
56
|
-
|
|
64
|
+
const currentQuery = queryRef.current;
|
|
65
|
+
if (currentQuery == null || options?.skip)
|
|
57
66
|
return;
|
|
58
67
|
setLoading(true);
|
|
59
68
|
setError(null);
|
|
60
|
-
|
|
69
|
+
currentQuery.then((value) => {
|
|
61
70
|
if (mountedRef.current) {
|
|
62
71
|
setData(value);
|
|
63
72
|
setLoading(false);
|
|
@@ -68,7 +77,7 @@ function useQuery(query, options) {
|
|
|
68
77
|
setLoading(false);
|
|
69
78
|
}
|
|
70
79
|
});
|
|
71
|
-
}, [
|
|
80
|
+
}, [options?.skip]);
|
|
72
81
|
return { data, loading, error, refetch };
|
|
73
82
|
}
|
|
74
83
|
function useMutation(mutationFn) {
|
|
@@ -110,11 +119,13 @@ function useMutation(mutationFn) {
|
|
|
110
119
|
}, []);
|
|
111
120
|
return { mutate, loading, error, data, reset };
|
|
112
121
|
}
|
|
113
|
-
function useLazyQuery(
|
|
122
|
+
function useLazyQuery(queryInput) {
|
|
114
123
|
const [data, setData] = useState(null);
|
|
115
124
|
const [loading, setLoading] = useState(false);
|
|
116
125
|
const [error, setError] = useState(null);
|
|
117
126
|
const mountedRef = useRef(true);
|
|
127
|
+
const queryInputRef = useRef(queryInput);
|
|
128
|
+
queryInputRef.current = queryInput;
|
|
118
129
|
useEffect(() => {
|
|
119
130
|
mountedRef.current = true;
|
|
120
131
|
return () => {
|
|
@@ -122,6 +133,12 @@ function useLazyQuery(query) {
|
|
|
122
133
|
};
|
|
123
134
|
}, []);
|
|
124
135
|
const execute = useCallback(async () => {
|
|
136
|
+
const query = resolveQuery(queryInputRef.current);
|
|
137
|
+
if (query == null) {
|
|
138
|
+
setData(null);
|
|
139
|
+
setLoading(false);
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
125
142
|
setLoading(true);
|
|
126
143
|
setError(null);
|
|
127
144
|
try {
|
|
@@ -141,7 +158,7 @@ function useLazyQuery(query) {
|
|
|
141
158
|
setLoading(false);
|
|
142
159
|
}
|
|
143
160
|
}
|
|
144
|
-
}, [
|
|
161
|
+
}, []);
|
|
145
162
|
const reset = useCallback(() => {
|
|
146
163
|
setLoading(false);
|
|
147
164
|
setError(null);
|
package/package.json
CHANGED
package/src/hooks.ts
CHANGED
|
@@ -25,7 +25,18 @@
|
|
|
25
25
|
*/
|
|
26
26
|
|
|
27
27
|
import type { MutationResult, QueryResult } from "@sylphx/lens-client";
|
|
28
|
-
import { useCallback, useEffect, useRef, useState } from "react";
|
|
28
|
+
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
29
|
+
|
|
30
|
+
// =============================================================================
|
|
31
|
+
// Query Input Types
|
|
32
|
+
// =============================================================================
|
|
33
|
+
|
|
34
|
+
/** Query input - can be a query, null/undefined, or an accessor function */
|
|
35
|
+
export type QueryInput<T> =
|
|
36
|
+
| QueryResult<T>
|
|
37
|
+
| null
|
|
38
|
+
| undefined
|
|
39
|
+
| (() => QueryResult<T> | null | undefined);
|
|
29
40
|
|
|
30
41
|
// =============================================================================
|
|
31
42
|
// Types
|
|
@@ -67,10 +78,15 @@ export interface UseQueryOptions {
|
|
|
67
78
|
// useQuery Hook
|
|
68
79
|
// =============================================================================
|
|
69
80
|
|
|
81
|
+
/** Helper to resolve query input (handles accessor functions) */
|
|
82
|
+
function resolveQuery<T>(input: QueryInput<T>): QueryResult<T> | null | undefined {
|
|
83
|
+
return typeof input === "function" ? input() : input;
|
|
84
|
+
}
|
|
85
|
+
|
|
70
86
|
/**
|
|
71
87
|
* Subscribe to a query with reactive updates
|
|
72
88
|
*
|
|
73
|
-
* @param
|
|
89
|
+
* @param queryInput - QueryResult, null/undefined, or accessor function returning QueryResult
|
|
74
90
|
* @param options - Query options
|
|
75
91
|
*
|
|
76
92
|
* @example
|
|
@@ -87,14 +103,23 @@ export interface UseQueryOptions {
|
|
|
87
103
|
* return <h1>{user.name}</h1>;
|
|
88
104
|
* }
|
|
89
105
|
*
|
|
90
|
-
* //
|
|
91
|
-
* function
|
|
106
|
+
* // Conditional query (null when condition not met)
|
|
107
|
+
* function SessionInfo({ sessionId }: { sessionId: string | null }) {
|
|
92
108
|
* const client = useLensClient();
|
|
93
109
|
* const { data } = useQuery(
|
|
94
|
-
* client.
|
|
110
|
+
* sessionId ? client.session.get({ id: sessionId }) : null
|
|
95
111
|
* );
|
|
96
|
-
* // data is
|
|
97
|
-
* return <span>{data?.
|
|
112
|
+
* // data is null when sessionId is null
|
|
113
|
+
* return <span>{data?.totalTokens}</span>;
|
|
114
|
+
* }
|
|
115
|
+
*
|
|
116
|
+
* // Accessor function (reactive inputs)
|
|
117
|
+
* function ReactiveQuery({ sessionId }: { sessionId: Signal<string | null> }) {
|
|
118
|
+
* const client = useLensClient();
|
|
119
|
+
* const { data } = useQuery(() =>
|
|
120
|
+
* sessionId.value ? client.session.get({ id: sessionId.value }) : null
|
|
121
|
+
* );
|
|
122
|
+
* return <span>{data?.totalTokens}</span>;
|
|
98
123
|
* }
|
|
99
124
|
*
|
|
100
125
|
* // Skip query conditionally
|
|
@@ -104,20 +129,30 @@ export interface UseQueryOptions {
|
|
|
104
129
|
* }
|
|
105
130
|
* ```
|
|
106
131
|
*/
|
|
107
|
-
export function useQuery<T>(
|
|
132
|
+
export function useQuery<T>(queryInput: QueryInput<T>, options?: UseQueryOptions): UseQueryResult<T> {
|
|
133
|
+
// Resolve query (handles accessor functions)
|
|
134
|
+
const query = useMemo(() => resolveQuery(queryInput), [queryInput]);
|
|
135
|
+
|
|
108
136
|
const [data, setData] = useState<T | null>(null);
|
|
109
|
-
const [loading, setLoading] = useState(!options?.skip);
|
|
137
|
+
const [loading, setLoading] = useState(!options?.skip && query != null);
|
|
110
138
|
const [error, setError] = useState<Error | null>(null);
|
|
111
139
|
|
|
112
140
|
// Track mounted state
|
|
113
141
|
const mountedRef = useRef(true);
|
|
114
142
|
|
|
143
|
+
// Store query ref for refetch
|
|
144
|
+
const queryRef = useRef(query);
|
|
145
|
+
queryRef.current = query;
|
|
146
|
+
|
|
115
147
|
// Subscribe to query
|
|
116
148
|
useEffect(() => {
|
|
117
149
|
mountedRef.current = true;
|
|
118
150
|
|
|
119
|
-
|
|
151
|
+
// Handle null/undefined query
|
|
152
|
+
if (query == null || options?.skip) {
|
|
153
|
+
setData(null);
|
|
120
154
|
setLoading(false);
|
|
155
|
+
setError(null);
|
|
121
156
|
return;
|
|
122
157
|
}
|
|
123
158
|
|
|
@@ -156,12 +191,13 @@ export function useQuery<T>(query: QueryResult<T>, options?: UseQueryOptions): U
|
|
|
156
191
|
|
|
157
192
|
// Refetch function
|
|
158
193
|
const refetch = useCallback(() => {
|
|
159
|
-
|
|
194
|
+
const currentQuery = queryRef.current;
|
|
195
|
+
if (currentQuery == null || options?.skip) return;
|
|
160
196
|
|
|
161
197
|
setLoading(true);
|
|
162
198
|
setError(null);
|
|
163
199
|
|
|
164
|
-
|
|
200
|
+
currentQuery.then(
|
|
165
201
|
(value) => {
|
|
166
202
|
if (mountedRef.current) {
|
|
167
203
|
setData(value);
|
|
@@ -175,7 +211,7 @@ export function useQuery<T>(query: QueryResult<T>, options?: UseQueryOptions): U
|
|
|
175
211
|
}
|
|
176
212
|
},
|
|
177
213
|
);
|
|
178
|
-
}, [
|
|
214
|
+
}, [options?.skip]);
|
|
179
215
|
|
|
180
216
|
return { data, loading, error, refetch };
|
|
181
217
|
}
|
|
@@ -309,7 +345,7 @@ export interface UseLazyQueryResult<T> {
|
|
|
309
345
|
/**
|
|
310
346
|
* Execute a query on demand (not on mount)
|
|
311
347
|
*
|
|
312
|
-
* @param
|
|
348
|
+
* @param queryInput - QueryResult, null/undefined, or accessor function returning QueryResult
|
|
313
349
|
*
|
|
314
350
|
* @example
|
|
315
351
|
* ```tsx
|
|
@@ -338,9 +374,18 @@ export interface UseLazyQueryResult<T> {
|
|
|
338
374
|
* </div>
|
|
339
375
|
* );
|
|
340
376
|
* }
|
|
377
|
+
*
|
|
378
|
+
* // With accessor function
|
|
379
|
+
* function LazyReactiveQuery({ sessionId }: { sessionId: Signal<string | null> }) {
|
|
380
|
+
* const client = useLensClient();
|
|
381
|
+
* const { execute, data } = useLazyQuery(() =>
|
|
382
|
+
* sessionId.value ? client.session.get({ id: sessionId.value }) : null
|
|
383
|
+
* );
|
|
384
|
+
* return <button onClick={execute}>Load</button>;
|
|
385
|
+
* }
|
|
341
386
|
* ```
|
|
342
387
|
*/
|
|
343
|
-
export function useLazyQuery<T>(
|
|
388
|
+
export function useLazyQuery<T>(queryInput: QueryInput<T>): UseLazyQueryResult<T> {
|
|
344
389
|
const [data, setData] = useState<T | null>(null);
|
|
345
390
|
const [loading, setLoading] = useState(false);
|
|
346
391
|
const [error, setError] = useState<Error | null>(null);
|
|
@@ -348,6 +393,10 @@ export function useLazyQuery<T>(query: QueryResult<T>): UseLazyQueryResult<T> {
|
|
|
348
393
|
// Track mounted state
|
|
349
394
|
const mountedRef = useRef(true);
|
|
350
395
|
|
|
396
|
+
// Store queryInput ref for execute (so it uses latest value)
|
|
397
|
+
const queryInputRef = useRef(queryInput);
|
|
398
|
+
queryInputRef.current = queryInput;
|
|
399
|
+
|
|
351
400
|
useEffect(() => {
|
|
352
401
|
mountedRef.current = true;
|
|
353
402
|
return () => {
|
|
@@ -357,6 +406,14 @@ export function useLazyQuery<T>(query: QueryResult<T>): UseLazyQueryResult<T> {
|
|
|
357
406
|
|
|
358
407
|
// Execute function
|
|
359
408
|
const execute = useCallback(async (): Promise<T> => {
|
|
409
|
+
const query = resolveQuery(queryInputRef.current);
|
|
410
|
+
|
|
411
|
+
if (query == null) {
|
|
412
|
+
setData(null);
|
|
413
|
+
setLoading(false);
|
|
414
|
+
return null as T;
|
|
415
|
+
}
|
|
416
|
+
|
|
360
417
|
setLoading(true);
|
|
361
418
|
setError(null);
|
|
362
419
|
|
|
@@ -379,7 +436,7 @@ export function useLazyQuery<T>(query: QueryResult<T>): UseLazyQueryResult<T> {
|
|
|
379
436
|
setLoading(false);
|
|
380
437
|
}
|
|
381
438
|
}
|
|
382
|
-
}, [
|
|
439
|
+
}, []);
|
|
383
440
|
|
|
384
441
|
// Reset function
|
|
385
442
|
const reset = useCallback(() => {
|