@epoch32/visage 0.0.0-stage → 0.0.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/LICENSE +373 -0
- package/README.md +110 -2
- package/dist/bundle.dev.js +4875 -0
- package/dist/index.js +9633 -0
- package/dist/src/api/index.js +4002 -0
- package/dist/src/charts/index.js +2717 -0
- package/dist/src/devtools/index.js +4677 -0
- package/dist/src/dom/index.js +1550 -0
- package/dist/src/form/index.js +1415 -0
- package/dist/src/index.js +11826 -0
- package/dist/src/jsx-runtime/index.js +1630 -0
- package/dist/src/query/index.js +2422 -0
- package/dist/src/router/index.js +1856 -0
- package/dist/src/rpc/index.js +3484 -0
- package/dist/src/server/index.js +1173 -0
- package/dist/src/signals/index.js +1077 -0
- package/dist/src/style/index.js +2340 -0
- package/dist/src/template/index.js +1149 -0
- package/dist/src/ui/index.js +4155 -0
- package/dist/src/virtual/index.js +1955 -0
- package/dist/src/vite/index.js +984 -0
- package/dist/vite/index.js +707 -0
- package/package.json +140 -4
- package/src/api/client.ts +371 -0
- package/src/api/file-router.ts +183 -0
- package/src/api/handler.ts +326 -0
- package/src/api/index.ts +71 -0
- package/src/api/middleware.ts +54 -0
- package/src/api/pragma.ts +155 -0
- package/src/api/procedure.ts +172 -0
- package/src/api/types.ts +249 -0
- package/src/charts/Area.tsx +111 -0
- package/src/charts/Axis.tsx +126 -0
- package/src/charts/Bar.tsx +86 -0
- package/src/charts/CartesianGrid.tsx +72 -0
- package/src/charts/Chart.tsx +269 -0
- package/src/charts/Cursor.tsx +42 -0
- package/src/charts/Legend.tsx +56 -0
- package/src/charts/Line.tsx +106 -0
- package/src/charts/Pie.tsx +88 -0
- package/src/charts/Tooltip.tsx +127 -0
- package/src/charts/context.ts +30 -0
- package/src/charts/index.ts +14 -0
- package/src/charts/path.ts +155 -0
- package/src/charts/scale.ts +133 -0
- package/src/charts/types.ts +50 -0
- package/src/devtools/DomTab.tsx +134 -0
- package/src/devtools/GraphInspector.tsx +196 -0
- package/src/devtools/GraphTab.tsx +315 -0
- package/src/devtools/QueryTab.tsx +200 -0
- package/src/devtools/RpcTab.tsx +190 -0
- package/src/devtools/SignalsTab.tsx +129 -0
- package/src/devtools/component.tsx +243 -0
- package/src/devtools/highlighter.ts +134 -0
- package/src/devtools/hub.ts +175 -0
- package/src/devtools/index.ts +20 -0
- package/src/devtools/styles.ts +313 -0
- package/src/devtools/types.ts +45 -0
- package/src/dom/async.ts +232 -0
- package/src/dom/control-flow.ts +353 -0
- package/src/dom/index.ts +32 -0
- package/src/dom/lazy.ts +82 -0
- package/src/dom/render.ts +286 -0
- package/src/dom/resource.ts +120 -0
- package/src/form/form.ts +218 -0
- package/src/form/index.ts +17 -0
- package/src/form/schema.ts +299 -0
- package/src/index.ts +413 -0
- package/src/jsx-dev-runtime/index.ts +1 -0
- package/src/jsx-runtime/index.ts +112 -0
- package/src/jsx-runtime/jsx.d.ts +278 -0
- package/src/query/create-mutation.ts +64 -0
- package/src/query/create-query.ts +426 -0
- package/src/query/focus-manager.ts +68 -0
- package/src/query/index.ts +63 -0
- package/src/query/mutation-cache.ts +138 -0
- package/src/query/online-manager.ts +67 -0
- package/src/query/query-cache.ts +369 -0
- package/src/query/query-client.ts +248 -0
- package/src/query/types.ts +221 -0
- package/src/query/utils.ts +132 -0
- package/src/router/index.ts +19 -0
- package/src/router/router.tsx +352 -0
- package/src/rpc/client.ts +317 -0
- package/src/rpc/error.ts +70 -0
- package/src/rpc/index.ts +52 -0
- package/src/rpc/procedure.ts +88 -0
- package/src/rpc/router.ts +105 -0
- package/src/rpc/server.ts +511 -0
- package/src/rpc/types.ts +328 -0
- package/src/server/hydrate.ts +21 -0
- package/src/server/index.ts +10 -0
- package/src/server/render-to-stream.ts +31 -0
- package/src/server/render-to-string.ts +125 -0
- package/src/signals/computed.ts +217 -0
- package/src/signals/context.ts +89 -0
- package/src/signals/effect.ts +161 -0
- package/src/signals/index.ts +57 -0
- package/src/signals/scope.ts +132 -0
- package/src/signals/signal.ts +203 -0
- package/src/signals/store.ts +163 -0
- package/src/signals/system.ts +124 -0
- package/src/signals/types.ts +64 -0
- package/src/style/component.tsx +122 -0
- package/src/style/create-style.ts +229 -0
- package/src/style/cx.ts +75 -0
- package/src/style/hash.ts +19 -0
- package/src/style/index.ts +8 -0
- package/src/style/layout.tsx +406 -0
- package/src/style/manager.ts +87 -0
- package/src/style/parser.ts +257 -0
- package/src/style/scale.ts +237 -0
- package/src/template/index.ts +4 -0
- package/src/template/template.ts +126 -0
- package/src/ui/accordion.tsx +286 -0
- package/src/ui/command-dialog.tsx +49 -0
- package/src/ui/command.tsx +400 -0
- package/src/ui/data-table.tsx +322 -0
- package/src/ui/dialog.tsx +362 -0
- package/src/ui/dropdown-menu.tsx +381 -0
- package/src/ui/icon.tsx +69 -0
- package/src/ui/index.ts +138 -0
- package/src/ui/layout.tsx +13 -0
- package/src/ui/popover.tsx +249 -0
- package/src/ui/switch.tsx +114 -0
- package/src/ui/tabs.tsx +297 -0
- package/src/ui/toast.tsx +280 -0
- package/src/ui/tooltip.tsx +262 -0
- package/src/ui/utils.ts +110 -0
- package/src/virtual/index.ts +12 -0
- package/src/virtual/virtual-list.tsx +185 -0
- package/src/virtual/virtualizer.ts +274 -0
- package/src/vite/hmr.ts +38 -0
- package/src/vite/index.ts +3 -0
- package/src/vite/lucide.ts +124 -0
- package/src/vite/plugin.ts +102 -0
- package/src/vite/rpc-middleware.ts +82 -0
- package/src/vite/types.ts +65 -0
|
@@ -0,0 +1,426 @@
|
|
|
1
|
+
import { SuspenseContext } from "../dom/async";
|
|
2
|
+
import {
|
|
3
|
+
COMPUTED_BRAND,
|
|
4
|
+
computed,
|
|
5
|
+
effect,
|
|
6
|
+
onCleanup,
|
|
7
|
+
type ReadonlySignal,
|
|
8
|
+
SIGNAL_BRAND,
|
|
9
|
+
signal,
|
|
10
|
+
untrack,
|
|
11
|
+
type WritableSignal
|
|
12
|
+
} from "../signals";
|
|
13
|
+
import { useContext } from "../signals/context";
|
|
14
|
+
import { focusManager } from "./focus-manager";
|
|
15
|
+
import type { Query, QueryObserver } from "./query-cache";
|
|
16
|
+
import { type QueryClient, useQueryClient } from "./query-client";
|
|
17
|
+
import type {
|
|
18
|
+
CreateQueryOptions,
|
|
19
|
+
FetchStatus,
|
|
20
|
+
InfiniteData,
|
|
21
|
+
InfiniteQueryOptions,
|
|
22
|
+
InfiniteQueryResult,
|
|
23
|
+
QueryKey,
|
|
24
|
+
QueryResult,
|
|
25
|
+
QueryStatus,
|
|
26
|
+
RefetchOptions
|
|
27
|
+
} from "./types";
|
|
28
|
+
|
|
29
|
+
export function createQuery<
|
|
30
|
+
TData = unknown,
|
|
31
|
+
TError = any,
|
|
32
|
+
TSelected = TData,
|
|
33
|
+
TQueryKey extends QueryKey = QueryKey
|
|
34
|
+
>(
|
|
35
|
+
options:
|
|
36
|
+
| CreateQueryOptions<TData, TError, TSelected, TQueryKey>
|
|
37
|
+
| (() => CreateQueryOptions<TData, TError, TSelected, TQueryKey>),
|
|
38
|
+
client?: QueryClient
|
|
39
|
+
): QueryResult<TSelected, TError> {
|
|
40
|
+
const queryClient = useQueryClient(client);
|
|
41
|
+
const resolveOptions = () => (typeof options === "function" ? options() : options);
|
|
42
|
+
|
|
43
|
+
const currentQuery = signal<Query<TData, TError> | null>(null);
|
|
44
|
+
const version: WritableSignal<number> = signal(0);
|
|
45
|
+
let activeObserver: QueryObserver<TData, TError> | null = null;
|
|
46
|
+
let intervalTimer: any = null;
|
|
47
|
+
|
|
48
|
+
const clearIntervalTimer = () => {
|
|
49
|
+
if (intervalTimer !== null) {
|
|
50
|
+
clearInterval(intervalTimer);
|
|
51
|
+
intervalTimer = null;
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
effect(() => {
|
|
56
|
+
const rawOpts = resolveOptions();
|
|
57
|
+
const defaults = queryClient.getDefaultOptions().queries ?? {};
|
|
58
|
+
const mergedOpts: CreateQueryOptions<TData, TError, TSelected, TQueryKey> = {
|
|
59
|
+
...defaults,
|
|
60
|
+
...rawOpts
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const isEnabled =
|
|
64
|
+
typeof mergedOpts.enabled === "function"
|
|
65
|
+
? mergedOpts.enabled()
|
|
66
|
+
: mergedOpts.enabled !== false;
|
|
67
|
+
|
|
68
|
+
const targetQuery = queryClient.queryCache.build<TData, TError>(queryClient, mergedOpts);
|
|
69
|
+
|
|
70
|
+
if (untrack(currentQuery) !== targetQuery || !activeObserver) {
|
|
71
|
+
const prevQ = untrack(currentQuery);
|
|
72
|
+
if (prevQ && activeObserver) {
|
|
73
|
+
prevQ.removeObserver(activeObserver);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const observer: QueryObserver<TData, TError> = {
|
|
77
|
+
options: mergedOpts,
|
|
78
|
+
onQueryUpdate: () => {
|
|
79
|
+
version.update((v) => v + 1);
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
targetQuery.addObserver(observer);
|
|
84
|
+
activeObserver = observer;
|
|
85
|
+
currentQuery.set(targetQuery);
|
|
86
|
+
} else if (activeObserver) {
|
|
87
|
+
activeObserver.options = mergedOpts;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
clearIntervalTimer();
|
|
91
|
+
const refetchInterval =
|
|
92
|
+
typeof mergedOpts.refetchInterval === "function"
|
|
93
|
+
? mergedOpts.refetchInterval()
|
|
94
|
+
: mergedOpts.refetchInterval;
|
|
95
|
+
|
|
96
|
+
if (refetchInterval && refetchInterval > 0) {
|
|
97
|
+
intervalTimer = setInterval(() => {
|
|
98
|
+
if (focusManager.isFocused() || mergedOpts.refetchIntervalInBackground) {
|
|
99
|
+
targetQuery.fetch(mergedOpts).catch(() => {});
|
|
100
|
+
}
|
|
101
|
+
}, refetchInterval);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
if (isEnabled) {
|
|
105
|
+
untrack(() => {
|
|
106
|
+
if (targetQuery.isStale(mergedOpts.staleTime) && targetQuery.fetchStatus() === "idle") {
|
|
107
|
+
const fetchPromise = targetQuery.fetch(mergedOpts);
|
|
108
|
+
fetchPromise.catch(() => {});
|
|
109
|
+
const suspense = useContext(SuspenseContext);
|
|
110
|
+
if (suspense) {
|
|
111
|
+
suspense.registerPromise(fetchPromise);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
onCleanup(() => {
|
|
119
|
+
clearIntervalTimer();
|
|
120
|
+
if (currentQuery() && activeObserver) {
|
|
121
|
+
currentQuery()!.removeObserver(activeObserver);
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
const data: ReadonlySignal<TSelected | undefined> = computed(() => {
|
|
126
|
+
version(); // subscribe to reactive updates
|
|
127
|
+
const q = currentQuery();
|
|
128
|
+
const rawOpts = resolveOptions();
|
|
129
|
+
const rawData = q?.data();
|
|
130
|
+
|
|
131
|
+
if (rawData !== undefined) {
|
|
132
|
+
if (rawOpts.select) {
|
|
133
|
+
return rawOpts.select(rawData);
|
|
134
|
+
}
|
|
135
|
+
return rawData as unknown as TSelected;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (rawOpts.placeholderData !== undefined) {
|
|
139
|
+
return (
|
|
140
|
+
typeof rawOpts.placeholderData === "function"
|
|
141
|
+
? (rawOpts.placeholderData as (prev: any) => any)(undefined)
|
|
142
|
+
: rawOpts.placeholderData
|
|
143
|
+
) as TSelected;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
return undefined;
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
const error: ReadonlySignal<TError | null> = computed(() => {
|
|
150
|
+
version();
|
|
151
|
+
return currentQuery()?.error() ?? null;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const status: ReadonlySignal<QueryStatus> = computed(() => {
|
|
155
|
+
version();
|
|
156
|
+
return currentQuery()?.status() ?? "pending";
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const fetchStatus: ReadonlySignal<FetchStatus> = computed(() => {
|
|
160
|
+
version();
|
|
161
|
+
return currentQuery()?.fetchStatus() ?? "idle";
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
const isLoading: ReadonlySignal<boolean> = computed(() => {
|
|
165
|
+
return status() === "pending" && fetchStatus() === "fetching";
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
const isFetching: ReadonlySignal<boolean> = computed(() => {
|
|
169
|
+
return fetchStatus() === "fetching";
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
const isSuccess: ReadonlySignal<boolean> = computed(() => {
|
|
173
|
+
return status() === "success";
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
const isError: ReadonlySignal<boolean> = computed(() => {
|
|
177
|
+
return status() === "error";
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const isStale: ReadonlySignal<boolean> = computed(() => {
|
|
181
|
+
version();
|
|
182
|
+
const q = currentQuery();
|
|
183
|
+
const rawOpts = resolveOptions();
|
|
184
|
+
return q?.isStale(rawOpts.staleTime) ?? true;
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
const dataUpdatedAt: ReadonlySignal<number> = computed(() => {
|
|
188
|
+
version();
|
|
189
|
+
return currentQuery()?.dataUpdatedAt() ?? 0;
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
const errorUpdatedAt: ReadonlySignal<number> = computed(() => {
|
|
193
|
+
version();
|
|
194
|
+
return currentQuery()?.errorUpdatedAt() ?? 0;
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
const refetch = async (refetchOpts?: RefetchOptions): Promise<TSelected | undefined> => {
|
|
198
|
+
const q = untrack(() => currentQuery());
|
|
199
|
+
if (!q) return undefined;
|
|
200
|
+
const rawOpts = resolveOptions();
|
|
201
|
+
const defaults = queryClient.getDefaultOptions().queries ?? {};
|
|
202
|
+
const mergedOpts = { ...defaults, ...rawOpts };
|
|
203
|
+
|
|
204
|
+
const rawResult = await q.fetch(mergedOpts, { cancelRefetch: refetchOpts?.cancelRefetch });
|
|
205
|
+
if (rawOpts.select) {
|
|
206
|
+
return rawOpts.select(rawResult);
|
|
207
|
+
}
|
|
208
|
+
return rawResult as unknown as TSelected;
|
|
209
|
+
};
|
|
210
|
+
|
|
211
|
+
const accessor = ((): TSelected | undefined => {
|
|
212
|
+
const q = currentQuery();
|
|
213
|
+
const rawOpts = resolveOptions();
|
|
214
|
+
|
|
215
|
+
if ((rawOpts.suspense || status() === "pending") && q?.promise) {
|
|
216
|
+
const suspense = useContext(SuspenseContext);
|
|
217
|
+
if (suspense) {
|
|
218
|
+
suspense.registerPromise(q.promise);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return data();
|
|
223
|
+
}) as QueryResult<TSelected, TError>;
|
|
224
|
+
|
|
225
|
+
Object.defineProperties(accessor, {
|
|
226
|
+
[SIGNAL_BRAND]: { value: true },
|
|
227
|
+
[COMPUTED_BRAND]: { value: true },
|
|
228
|
+
value: { get: () => data() },
|
|
229
|
+
data: { get: () => data },
|
|
230
|
+
error: { get: () => error },
|
|
231
|
+
status: { get: () => status },
|
|
232
|
+
fetchStatus: { get: () => fetchStatus },
|
|
233
|
+
isLoading: { get: () => isLoading },
|
|
234
|
+
isFetching: { get: () => isFetching },
|
|
235
|
+
isSuccess: { get: () => isSuccess },
|
|
236
|
+
isError: { get: () => isError },
|
|
237
|
+
isStale: { get: () => isStale },
|
|
238
|
+
dataUpdatedAt: { get: () => dataUpdatedAt },
|
|
239
|
+
errorUpdatedAt: { get: () => errorUpdatedAt },
|
|
240
|
+
refetch: { value: refetch }
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
return accessor;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function createInfiniteQuery<
|
|
247
|
+
TData = unknown,
|
|
248
|
+
TError = any,
|
|
249
|
+
TPageParam = unknown,
|
|
250
|
+
TSelected = InfiniteData<TData, TPageParam>,
|
|
251
|
+
TQueryKey extends QueryKey = QueryKey
|
|
252
|
+
>(
|
|
253
|
+
options:
|
|
254
|
+
| InfiniteQueryOptions<TData, TError, TPageParam, TSelected, TQueryKey>
|
|
255
|
+
| (() => InfiniteQueryOptions<TData, TError, TPageParam, TSelected, TQueryKey>),
|
|
256
|
+
client?: QueryClient
|
|
257
|
+
): InfiniteQueryResult<TData, TError, TPageParam> {
|
|
258
|
+
const queryClient = useQueryClient(client);
|
|
259
|
+
const resolveOptions = () => (typeof options === "function" ? options() : options);
|
|
260
|
+
|
|
261
|
+
const isFetchingNextPage: WritableSignal<boolean> = signal(false);
|
|
262
|
+
const isFetchingPreviousPage: WritableSignal<boolean> = signal(false);
|
|
263
|
+
|
|
264
|
+
const baseQuery = createQuery<
|
|
265
|
+
InfiniteData<TData, TPageParam>,
|
|
266
|
+
TError,
|
|
267
|
+
InfiniteData<TData, TPageParam>,
|
|
268
|
+
TQueryKey
|
|
269
|
+
>(() => {
|
|
270
|
+
const rawOpts = resolveOptions();
|
|
271
|
+
return {
|
|
272
|
+
...rawOpts,
|
|
273
|
+
queryFn: async (ctx) => {
|
|
274
|
+
const pageParam = ctx.pageParam ?? rawOpts.initialPageParam;
|
|
275
|
+
const page = await (rawOpts.queryFn as any)({
|
|
276
|
+
...ctx,
|
|
277
|
+
pageParam
|
|
278
|
+
});
|
|
279
|
+
return {
|
|
280
|
+
pages: [page],
|
|
281
|
+
pageParams: [pageParam]
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
select: undefined
|
|
285
|
+
};
|
|
286
|
+
}, queryClient);
|
|
287
|
+
|
|
288
|
+
const hasNextPage = computed(() => {
|
|
289
|
+
const current = baseQuery.data();
|
|
290
|
+
if (!current || current.pages.length === 0) return false;
|
|
291
|
+
const rawOpts = resolveOptions();
|
|
292
|
+
const lastPage = current.pages[current.pages.length - 1];
|
|
293
|
+
const lastParam = current.pageParams[current.pageParams.length - 1];
|
|
294
|
+
const nextParam = rawOpts.getNextPageParam(
|
|
295
|
+
lastPage!,
|
|
296
|
+
current.pages,
|
|
297
|
+
lastParam!,
|
|
298
|
+
current.pageParams
|
|
299
|
+
);
|
|
300
|
+
return nextParam !== undefined && nextParam !== null;
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
const hasPreviousPage = computed(() => {
|
|
304
|
+
const current = baseQuery.data();
|
|
305
|
+
if (!current || current.pages.length === 0) return false;
|
|
306
|
+
const rawOpts = resolveOptions();
|
|
307
|
+
if (!rawOpts.getPreviousPageParam) return false;
|
|
308
|
+
const firstPage = current.pages[0];
|
|
309
|
+
const firstParam = current.pageParams[0];
|
|
310
|
+
const prevParam = rawOpts.getPreviousPageParam(
|
|
311
|
+
firstPage!,
|
|
312
|
+
current.pages,
|
|
313
|
+
firstParam!,
|
|
314
|
+
current.pageParams
|
|
315
|
+
);
|
|
316
|
+
return prevParam !== undefined && prevParam !== null;
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
const fetchNextPage = async (): Promise<InfiniteData<TData, TPageParam> | undefined> => {
|
|
320
|
+
const current = baseQuery.data();
|
|
321
|
+
if (!current || current.pages.length === 0) return undefined;
|
|
322
|
+
const rawOpts = resolveOptions();
|
|
323
|
+
const lastPage = current.pages[current.pages.length - 1];
|
|
324
|
+
const lastParam = current.pageParams[current.pageParams.length - 1];
|
|
325
|
+
const nextParam = rawOpts.getNextPageParam(
|
|
326
|
+
lastPage!,
|
|
327
|
+
current.pages,
|
|
328
|
+
lastParam!,
|
|
329
|
+
current.pageParams
|
|
330
|
+
);
|
|
331
|
+
|
|
332
|
+
if (nextParam === undefined || nextParam === null) {
|
|
333
|
+
return current;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
isFetchingNextPage.set(true);
|
|
337
|
+
try {
|
|
338
|
+
const newPage = await (rawOpts.queryFn as any)({
|
|
339
|
+
queryKey: rawOpts.queryKey,
|
|
340
|
+
signal: new AbortController().signal,
|
|
341
|
+
pageParam: nextParam,
|
|
342
|
+
meta: rawOpts.meta
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
const nextData: InfiniteData<TData, TPageParam> = {
|
|
346
|
+
pages: [...current.pages, newPage],
|
|
347
|
+
pageParams: [...current.pageParams, nextParam]
|
|
348
|
+
};
|
|
349
|
+
|
|
350
|
+
queryClient.setQueryData(rawOpts.queryKey, nextData);
|
|
351
|
+
return nextData;
|
|
352
|
+
} finally {
|
|
353
|
+
isFetchingNextPage.set(false);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
const fetchPreviousPage = async (): Promise<InfiniteData<TData, TPageParam> | undefined> => {
|
|
358
|
+
const current = baseQuery.data();
|
|
359
|
+
if (!current || current.pages.length === 0) return undefined;
|
|
360
|
+
const rawOpts = resolveOptions();
|
|
361
|
+
if (!rawOpts.getPreviousPageParam) return current;
|
|
362
|
+
|
|
363
|
+
const firstPage = current.pages[0];
|
|
364
|
+
const firstParam = current.pageParams[0];
|
|
365
|
+
const prevParam = rawOpts.getPreviousPageParam(
|
|
366
|
+
firstPage!,
|
|
367
|
+
current.pages,
|
|
368
|
+
firstParam!,
|
|
369
|
+
current.pageParams
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
if (prevParam === undefined || prevParam === null) {
|
|
373
|
+
return current;
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
isFetchingPreviousPage.set(true);
|
|
377
|
+
try {
|
|
378
|
+
const newPage = await (rawOpts.queryFn as any)({
|
|
379
|
+
queryKey: rawOpts.queryKey,
|
|
380
|
+
signal: new AbortController().signal,
|
|
381
|
+
pageParam: prevParam,
|
|
382
|
+
meta: rawOpts.meta
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
const nextData: InfiniteData<TData, TPageParam> = {
|
|
386
|
+
pages: [newPage, ...current.pages],
|
|
387
|
+
pageParams: [prevParam, ...current.pageParams]
|
|
388
|
+
};
|
|
389
|
+
|
|
390
|
+
queryClient.setQueryData(rawOpts.queryKey, nextData);
|
|
391
|
+
return nextData;
|
|
392
|
+
} finally {
|
|
393
|
+
isFetchingPreviousPage.set(false);
|
|
394
|
+
}
|
|
395
|
+
};
|
|
396
|
+
|
|
397
|
+
const accessor = ((): InfiniteData<TData, TPageParam> | undefined => {
|
|
398
|
+
return baseQuery();
|
|
399
|
+
}) as unknown as InfiniteQueryResult<TData, TError, TPageParam>;
|
|
400
|
+
|
|
401
|
+
Object.defineProperties(accessor, {
|
|
402
|
+
[SIGNAL_BRAND]: { value: true },
|
|
403
|
+
[COMPUTED_BRAND]: { value: true },
|
|
404
|
+
value: { get: () => baseQuery.data() },
|
|
405
|
+
data: { get: () => baseQuery.data },
|
|
406
|
+
error: { get: () => baseQuery.error },
|
|
407
|
+
status: { get: () => baseQuery.status },
|
|
408
|
+
fetchStatus: { get: () => baseQuery.fetchStatus },
|
|
409
|
+
isLoading: { get: () => baseQuery.isLoading },
|
|
410
|
+
isFetching: { get: () => baseQuery.isFetching },
|
|
411
|
+
isSuccess: { get: () => baseQuery.isSuccess },
|
|
412
|
+
isError: { get: () => baseQuery.isError },
|
|
413
|
+
isStale: { get: () => baseQuery.isStale },
|
|
414
|
+
dataUpdatedAt: { get: () => baseQuery.dataUpdatedAt },
|
|
415
|
+
errorUpdatedAt: { get: () => baseQuery.errorUpdatedAt },
|
|
416
|
+
refetch: { value: baseQuery.refetch },
|
|
417
|
+
fetchNextPage: { value: fetchNextPage },
|
|
418
|
+
fetchPreviousPage: { value: fetchPreviousPage },
|
|
419
|
+
hasNextPage: { get: () => hasNextPage },
|
|
420
|
+
hasPreviousPage: { get: () => hasPreviousPage },
|
|
421
|
+
isFetchingNextPage: { get: () => isFetchingNextPage },
|
|
422
|
+
isFetchingPreviousPage: { get: () => isFetchingPreviousPage }
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
return accessor;
|
|
426
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
export type FocusListener = (focused: boolean) => void;
|
|
2
|
+
|
|
3
|
+
export class FocusManager {
|
|
4
|
+
private _focused?: boolean;
|
|
5
|
+
private _listeners = new Set<FocusListener>();
|
|
6
|
+
private _cleanup?: () => void;
|
|
7
|
+
|
|
8
|
+
constructor() {
|
|
9
|
+
this.setupEventListener();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
private setupEventListener() {
|
|
13
|
+
if (typeof window === "undefined" || typeof window.addEventListener === "undefined") {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const listener = () => {
|
|
18
|
+
this.notify(this.isFocused());
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
window.addEventListener("visibilitychange", listener, false);
|
|
22
|
+
window.addEventListener("focus", listener, false);
|
|
23
|
+
|
|
24
|
+
this._cleanup = () => {
|
|
25
|
+
window.removeEventListener("visibilitychange", listener);
|
|
26
|
+
window.removeEventListener("focus", listener);
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
setFocused(focused?: boolean) {
|
|
31
|
+
this._focused = focused;
|
|
32
|
+
this.notify(this.isFocused());
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
isFocused(): boolean {
|
|
36
|
+
if (typeof this._focused === "boolean") {
|
|
37
|
+
return this._focused;
|
|
38
|
+
}
|
|
39
|
+
if (typeof document !== "undefined" && typeof document.visibilityState === "string") {
|
|
40
|
+
return document.visibilityState !== "hidden";
|
|
41
|
+
}
|
|
42
|
+
return true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
subscribe(listener: FocusListener): () => void {
|
|
46
|
+
this._listeners.add(listener);
|
|
47
|
+
return () => {
|
|
48
|
+
this._listeners.delete(listener);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private notify(focused: boolean) {
|
|
53
|
+
for (const listener of this._listeners) {
|
|
54
|
+
try {
|
|
55
|
+
listener(focused);
|
|
56
|
+
} catch (err) {
|
|
57
|
+
console.error("Error in focus listener:", err);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
cleanup() {
|
|
63
|
+
this._cleanup?.();
|
|
64
|
+
this._listeners.clear();
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const focusManager = new FocusManager();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
export { createMutation } from "./create-mutation";
|
|
2
|
+
export {
|
|
3
|
+
createInfiniteQuery,
|
|
4
|
+
createQuery
|
|
5
|
+
} from "./create-query";
|
|
6
|
+
export {
|
|
7
|
+
type FocusListener,
|
|
8
|
+
FocusManager,
|
|
9
|
+
focusManager
|
|
10
|
+
} from "./focus-manager";
|
|
11
|
+
export {
|
|
12
|
+
Mutation,
|
|
13
|
+
MutationCache
|
|
14
|
+
} from "./mutation-cache";
|
|
15
|
+
export {
|
|
16
|
+
type OnlineListener,
|
|
17
|
+
OnlineManager,
|
|
18
|
+
onlineManager
|
|
19
|
+
} from "./online-manager";
|
|
20
|
+
export {
|
|
21
|
+
Query,
|
|
22
|
+
QueryCache,
|
|
23
|
+
type QueryObserver
|
|
24
|
+
} from "./query-cache";
|
|
25
|
+
export {
|
|
26
|
+
QueryClient,
|
|
27
|
+
type QueryClientConfig,
|
|
28
|
+
QueryClientContext,
|
|
29
|
+
QueryClientProvider,
|
|
30
|
+
useQueryClient
|
|
31
|
+
} from "./query-client";
|
|
32
|
+
export type {
|
|
33
|
+
CreateQueryOptions,
|
|
34
|
+
DefaultOptions,
|
|
35
|
+
FetchStatus,
|
|
36
|
+
InfiniteData,
|
|
37
|
+
InfiniteQueryOptions,
|
|
38
|
+
InfiniteQueryResult,
|
|
39
|
+
MutateOptions,
|
|
40
|
+
MutationFunction,
|
|
41
|
+
MutationOptions,
|
|
42
|
+
MutationResult,
|
|
43
|
+
MutationStatus,
|
|
44
|
+
QueryFilters,
|
|
45
|
+
QueryFunction,
|
|
46
|
+
QueryFunctionContext,
|
|
47
|
+
QueryKey,
|
|
48
|
+
QueryOptions,
|
|
49
|
+
QueryResult,
|
|
50
|
+
QueryState,
|
|
51
|
+
QueryStatus,
|
|
52
|
+
RefetchOptions,
|
|
53
|
+
RetryDelayValue,
|
|
54
|
+
RetryValue
|
|
55
|
+
} from "./types";
|
|
56
|
+
export {
|
|
57
|
+
deepEqual,
|
|
58
|
+
hashKey,
|
|
59
|
+
isPlainObject,
|
|
60
|
+
matchQuery,
|
|
61
|
+
partialDeepEqual,
|
|
62
|
+
sleep
|
|
63
|
+
} from "./utils";
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { computed, type ReadonlySignal, signal, type WritableSignal } from "../signals";
|
|
2
|
+
import type { MutateOptions, MutationOptions, MutationStatus } from "./types";
|
|
3
|
+
|
|
4
|
+
export class Mutation<TData = unknown, TError = any, TVariables = void, TContext = unknown> {
|
|
5
|
+
readonly options: MutationOptions<TData, TError, TVariables, TContext>;
|
|
6
|
+
|
|
7
|
+
readonly data: WritableSignal<TData | undefined>;
|
|
8
|
+
readonly error: WritableSignal<TError | null>;
|
|
9
|
+
readonly status: WritableSignal<MutationStatus>;
|
|
10
|
+
readonly submittedAt: WritableSignal<number>;
|
|
11
|
+
readonly variables: WritableSignal<TVariables | undefined>;
|
|
12
|
+
|
|
13
|
+
readonly isIdle: ReadonlySignal<boolean>;
|
|
14
|
+
readonly isPending: ReadonlySignal<boolean>;
|
|
15
|
+
readonly isLoading: ReadonlySignal<boolean>;
|
|
16
|
+
readonly isSuccess: ReadonlySignal<boolean>;
|
|
17
|
+
readonly isError: ReadonlySignal<boolean>;
|
|
18
|
+
|
|
19
|
+
constructor(options: MutationOptions<TData, TError, TVariables, TContext>) {
|
|
20
|
+
this.options = options;
|
|
21
|
+
this.data = signal<TData | undefined>(undefined);
|
|
22
|
+
this.error = signal<TError | null>(null);
|
|
23
|
+
this.status = signal<MutationStatus>("idle");
|
|
24
|
+
this.submittedAt = signal<number>(0);
|
|
25
|
+
this.variables = signal<TVariables | undefined>(undefined);
|
|
26
|
+
|
|
27
|
+
this.isIdle = computed(() => this.status() === "idle");
|
|
28
|
+
this.isPending = computed(() => this.status() === "pending");
|
|
29
|
+
this.isLoading = this.isPending;
|
|
30
|
+
this.isSuccess = computed(() => this.status() === "success");
|
|
31
|
+
this.isError = computed(() => this.status() === "error");
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
async execute(
|
|
35
|
+
variables: TVariables,
|
|
36
|
+
mutateOptions?: MutateOptions<TData, TError, TVariables, TContext>
|
|
37
|
+
): Promise<TData> {
|
|
38
|
+
this.status.set("pending");
|
|
39
|
+
this.error.set(null);
|
|
40
|
+
this.variables.set(variables);
|
|
41
|
+
this.submittedAt.set(Date.now());
|
|
42
|
+
|
|
43
|
+
let context: TContext | undefined;
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
if (this.options.onMutate) {
|
|
47
|
+
const res = await this.options.onMutate(variables);
|
|
48
|
+
if (res !== undefined) {
|
|
49
|
+
context = res as TContext;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const result = await this.options.mutationFn(variables);
|
|
54
|
+
|
|
55
|
+
this.data.set(result);
|
|
56
|
+
this.status.set("success");
|
|
57
|
+
|
|
58
|
+
try {
|
|
59
|
+
await this.options.onSuccess?.(result, variables, context);
|
|
60
|
+
} catch (err) {
|
|
61
|
+
console.error("Error in mutation onSuccess:", err);
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
mutateOptions?.onSuccess?.(result, variables, context);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
console.error("Error in mutateOptions onSuccess:", err);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
try {
|
|
70
|
+
await this.options.onSettled?.(result, null, variables, context);
|
|
71
|
+
} catch (err) {
|
|
72
|
+
console.error("Error in mutation onSettled:", err);
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
mutateOptions?.onSettled?.(result, null, variables, context);
|
|
76
|
+
} catch (err) {
|
|
77
|
+
console.error("Error in mutateOptions onSettled:", err);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
return result;
|
|
81
|
+
} catch (err: any) {
|
|
82
|
+
this.error.set(err);
|
|
83
|
+
this.status.set("error");
|
|
84
|
+
|
|
85
|
+
try {
|
|
86
|
+
await this.options.onError?.(err, variables, context);
|
|
87
|
+
} catch (e) {
|
|
88
|
+
console.error("Error in mutation onError:", e);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
mutateOptions?.onError?.(err, variables, context);
|
|
92
|
+
} catch (e) {
|
|
93
|
+
console.error("Error in mutateOptions onError:", e);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
await this.options.onSettled?.(undefined, err, variables, context);
|
|
98
|
+
} catch (e) {
|
|
99
|
+
console.error("Error in mutation onSettled:", e);
|
|
100
|
+
}
|
|
101
|
+
try {
|
|
102
|
+
mutateOptions?.onSettled?.(undefined, err, variables, context);
|
|
103
|
+
} catch (e) {
|
|
104
|
+
console.error("Error in mutateOptions onSettled:", e);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
throw err;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
reset() {
|
|
112
|
+
this.data.set(undefined);
|
|
113
|
+
this.error.set(null);
|
|
114
|
+
this.status.set("idle");
|
|
115
|
+
this.submittedAt.set(0);
|
|
116
|
+
this.variables.set(undefined);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export class MutationCache {
|
|
121
|
+
mutations = new Set<Mutation<any, any, any, any>>();
|
|
122
|
+
|
|
123
|
+
build<TData, TError, TVariables, TContext>(
|
|
124
|
+
options: MutationOptions<TData, TError, TVariables, TContext>
|
|
125
|
+
): Mutation<TData, TError, TVariables, TContext> {
|
|
126
|
+
const mutation = new Mutation(options);
|
|
127
|
+
this.mutations.add(mutation);
|
|
128
|
+
return mutation;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
remove(mutation: Mutation<any, any, any, any>) {
|
|
132
|
+
this.mutations.delete(mutation);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
clear() {
|
|
136
|
+
this.mutations.clear();
|
|
137
|
+
}
|
|
138
|
+
}
|