@kasperrt/smolter 0.4.3 → 0.4.4
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/.generated/client/hash-history.ts +27 -0
- package/.generated/client/hydration.ts +98 -0
- package/.generated/client/root-data.ts +52 -0
- package/.generated/core/prepare-routes.ts +50 -0
- package/.generated/core/presentation.ts +1 -1
- package/.generated/preact/client.tsx +1 -26
- package/.generated/preact/deferred-hydration.ts +1 -98
- package/.generated/preact/index.ts +6 -1
- package/.generated/preact/navigation.tsx +13 -5
- package/.generated/preact/root-data.ts +1 -45
- package/.generated/preact/router.tsx +2 -48
- package/.generated/react/client.tsx +130 -0
- package/.generated/react/document.tsx +235 -0
- package/.generated/react/fetcher.ts +29 -7
- package/.generated/react/hooks.ts +20 -18
- package/.generated/react/index.ts +17 -1
- package/.generated/react/lazy-route.ts +116 -0
- package/.generated/react/link.ts +1 -38
- package/.generated/react/navigation-state.ts +13 -0
- package/.generated/react/navigation.ts +145 -0
- package/.generated/react/root-context.ts +22 -0
- package/.generated/react/route-hooks.ts +159 -0
- package/.generated/react/route-types.ts +91 -0
- package/.generated/react/router.ts +50 -0
- package/.generated/react/runtime.ts +1 -0
- package/.generated/server/application.tsx +18 -253
- package/.generated/server/dispatch.ts +87 -0
- package/.generated/server/index.ts +2 -0
- package/.generated/server/react.ts +34 -0
- package/.generated/server/render-application.ts +203 -0
- package/.generated/vite/application/lazy-files.ts +2 -1
- package/.generated/vite/application/vite.ts +12 -4
- package/.generated/vite/react.ts +11 -0
- package/CHANGELOG.md +10 -0
- package/README.md +41 -41
- package/dist/client/hash-history.d.ts +2 -0
- package/dist/client/hash-history.js +26 -0
- package/dist/client/hydration.d.ts +10 -0
- package/dist/{preact/deferred-hydration.js → client/hydration.js} +1 -1
- package/dist/client/root-data.d.ts +14 -0
- package/dist/{preact → client}/root-data.js +1 -1
- package/dist/core/prepare-routes.d.ts +7 -0
- package/dist/core/prepare-routes.js +28 -0
- package/dist/core/presentation.js +1 -1
- package/dist/preact/client.js +5 -26
- package/dist/preact/deferred-hydration.d.ts +1 -10
- package/dist/preact/document.js +2 -2
- package/dist/preact/index.d.ts +1 -1
- package/dist/preact/index.js +1 -1
- package/dist/preact/navigation-state.js +1 -1
- package/dist/preact/navigation.js +7 -5
- package/dist/preact/root-data.d.ts +1 -8
- package/dist/preact/route-hooks.js +1 -1
- package/dist/preact/router.d.ts +2 -2
- package/dist/preact/router.js +2 -26
- package/dist/react/client.d.ts +20 -0
- package/dist/react/client.js +86 -0
- package/dist/react/document.d.ts +25 -0
- package/dist/react/document.js +169 -0
- package/dist/react/fetcher.d.ts +8 -4
- package/dist/react/fetcher.js +12 -1
- package/dist/react/form.js +1 -1
- package/dist/react/hooks.d.ts +7 -6
- package/dist/react/index.d.ts +7 -1
- package/dist/react/index.js +6 -2
- package/dist/react/lazy-route.d.ts +22 -0
- package/dist/react/lazy-route.js +57 -0
- package/dist/react/link.d.ts +1 -12
- package/dist/react/navigation-state.d.ts +2 -0
- package/dist/react/navigation-state.js +9 -0
- package/dist/react/navigation.d.ts +33 -0
- package/dist/react/navigation.js +64 -0
- package/dist/react/root-context.d.ts +14 -0
- package/dist/react/root-context.js +10 -0
- package/dist/react/route-hooks.d.ts +34 -0
- package/dist/react/route-hooks.js +89 -0
- package/dist/react/route-types.d.ts +69 -0
- package/dist/react/router.d.ts +10 -0
- package/dist/react/router.js +22 -0
- package/dist/react/runtime.d.ts +1 -1
- package/dist/react/runtime.js +1 -1
- package/dist/server/application.d.ts +4 -8
- package/dist/server/application.js +9 -156
- package/dist/server/dispatch.d.ts +5 -0
- package/dist/server/dispatch.js +50 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2 -1
- package/dist/server/preact.js +2 -1
- package/dist/server/react.d.ts +10 -0
- package/dist/server/react.js +22 -0
- package/dist/server/render-application.d.ts +31 -0
- package/dist/server/render-application.js +118 -0
- package/dist/vite/application/lazy-files.d.ts +1 -1
- package/dist/vite/application/lazy-files.js +2 -2
- package/dist/vite/application/vite.d.ts +2 -1
- package/dist/vite/application/vite.js +12 -5
- package/dist/vite/react.d.ts +4 -0
- package/dist/vite/react.js +9 -1
- package/jsr.json +10 -6
- package/package.json +18 -10
- package/.generated/core/resource-types.ts +0 -48
- package/.generated/core/resources.ts +0 -446
- package/.generated/react/data.ts +0 -29
- package/.generated/react/resources/components.tsx +0 -416
- package/dist/core/resource-types.d.ts +0 -41
- package/dist/core/resources.d.ts +0 -21
- package/dist/core/resources.js +0 -347
- package/dist/react/data.d.ts +0 -9
- package/dist/react/data.js +0 -3
- package/dist/react/link.js +0 -27
- package/dist/react/resources/components.d.ts +0 -76
- package/dist/react/resources/components.js +0 -250
package/.generated/react/data.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Independent React resource data, forms and subscriptions.
|
|
3
|
-
*
|
|
4
|
-
* @module
|
|
5
|
-
*/
|
|
6
|
-
export type {
|
|
7
|
-
ActionFunctionArgs as ResourceActionArgs,
|
|
8
|
-
DataResult as ResourceResult,
|
|
9
|
-
LoaderFunctionArgs as ResourceLoaderArgs,
|
|
10
|
-
ShouldRevalidateFunctionArgs as ResourceRevalidationArgs,
|
|
11
|
-
} from "../core/resource-types.ts";
|
|
12
|
-
export {
|
|
13
|
-
createResourceRouter,
|
|
14
|
-
ResourceRouter,
|
|
15
|
-
} from "../core/resources.ts";
|
|
16
|
-
export type { ResourceRouteModule } from "./resources/components.tsx";
|
|
17
|
-
export {
|
|
18
|
-
Form as ResourceForm,
|
|
19
|
-
Route as Resource,
|
|
20
|
-
RouterProvider as ResourceProvider,
|
|
21
|
-
useActionData as useResourceActionData,
|
|
22
|
-
useFetcher as useResourceFetcher,
|
|
23
|
-
useLoaderData as useResourceData,
|
|
24
|
-
useNavigation as useResourceNavigation,
|
|
25
|
-
useRevalidator as useResourceRevalidator,
|
|
26
|
-
useRouteLoaderData,
|
|
27
|
-
useRouter as useResourceRouter,
|
|
28
|
-
useSubmit as useResourceSubmit,
|
|
29
|
-
} from "./resources/components.tsx";
|
|
@@ -1,416 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource react */
|
|
2
|
-
import type {
|
|
3
|
-
DataResult,
|
|
4
|
-
NavigationState,
|
|
5
|
-
Params,
|
|
6
|
-
ResourceModule,
|
|
7
|
-
RouteState,
|
|
8
|
-
} from "../../core/resource-types.ts";
|
|
9
|
-
import type { ResourceRouter } from "../../core/resources.ts";
|
|
10
|
-
|
|
11
|
-
import {
|
|
12
|
-
Component,
|
|
13
|
-
type ComponentType,
|
|
14
|
-
createContext,
|
|
15
|
-
type PropsWithChildren,
|
|
16
|
-
type ReactNode,
|
|
17
|
-
useCallback,
|
|
18
|
-
useContext,
|
|
19
|
-
useEffect,
|
|
20
|
-
useMemo,
|
|
21
|
-
useRef,
|
|
22
|
-
useState,
|
|
23
|
-
useSyncExternalStore,
|
|
24
|
-
} from "react";
|
|
25
|
-
|
|
26
|
-
/** Resource handlers with optional React content, pending UI and retry boundary. */
|
|
27
|
-
export interface ResourceRouteModule extends ResourceModule {
|
|
28
|
-
default?: ComponentType;
|
|
29
|
-
ErrorBoundary?: ComponentType<{ retry: () => void }>;
|
|
30
|
-
HydrateFallback?: ComponentType;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const RouterContext = createContext<ResourceRouter | null>(null);
|
|
34
|
-
const RouteContext = createContext<{ params: Params; routeId: string } | null>(
|
|
35
|
-
null,
|
|
36
|
-
);
|
|
37
|
-
const FormContext = createContext<
|
|
38
|
-
((input?: unknown) => Promise<DataResult<unknown>>) | null
|
|
39
|
-
>(null);
|
|
40
|
-
|
|
41
|
-
interface RouterProviderProps extends PropsWithChildren {
|
|
42
|
-
initialMatches?: readonly { params?: Params; routeId: string }[];
|
|
43
|
-
router: ResourceRouter;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/** Provide a resource router and load initial matches; dispose it when unmounted. */
|
|
47
|
-
export function RouterProvider({
|
|
48
|
-
children,
|
|
49
|
-
initialMatches = EMPTY_MATCHES,
|
|
50
|
-
router,
|
|
51
|
-
}: RouterProviderProps): import("react").JSX.Element {
|
|
52
|
-
useEffect(() => {
|
|
53
|
-
for (const match of initialMatches) {
|
|
54
|
-
void router.load(match.routeId, match.params ?? {});
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
return () => router.dispose();
|
|
58
|
-
}, [initialMatches, router]);
|
|
59
|
-
|
|
60
|
-
return (
|
|
61
|
-
<RouterContext.Provider value={router}>{children}</RouterContext.Provider>
|
|
62
|
-
);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
interface RouteProps extends PropsWithChildren {
|
|
66
|
-
params?: Params;
|
|
67
|
-
persistent?: boolean;
|
|
68
|
-
routeId: string;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
/** Provide a resource route and render its content, loading state or retry boundary. */
|
|
72
|
-
export function Route({
|
|
73
|
-
children,
|
|
74
|
-
params = {},
|
|
75
|
-
persistent = false,
|
|
76
|
-
routeId,
|
|
77
|
-
}: RouteProps): import("react").JSX.Element {
|
|
78
|
-
const router = useRouter();
|
|
79
|
-
const stableParams = useStableParams(params);
|
|
80
|
-
const state = useRouteState(routeId, stableParams, true);
|
|
81
|
-
const route = router.getRoute(routeId) as ResourceRouteModule | null;
|
|
82
|
-
const retry = useCallback(
|
|
83
|
-
() => void router.retry(routeId, stableParams),
|
|
84
|
-
[routeId, router, stableParams],
|
|
85
|
-
);
|
|
86
|
-
const contextValue = useMemo(
|
|
87
|
-
() => ({ params: stableParams, routeId }),
|
|
88
|
-
[routeId, stableParams],
|
|
89
|
-
);
|
|
90
|
-
useEffect(() => {
|
|
91
|
-
if (persistent) router.persist(routeId, stableParams);
|
|
92
|
-
}, [persistent, routeId, router, stableParams]);
|
|
93
|
-
let content: ReactNode = children;
|
|
94
|
-
|
|
95
|
-
if (children === undefined && route?.default) {
|
|
96
|
-
const RouteComponent = route.default;
|
|
97
|
-
content = <RouteComponent />;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
if (state.unexpectedError && route?.ErrorBoundary) {
|
|
101
|
-
const ErrorBoundary = route.ErrorBoundary;
|
|
102
|
-
content = <ErrorBoundary retry={retry} />;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
if (
|
|
106
|
-
!state.unexpectedError &&
|
|
107
|
-
!state.loaderInitialized &&
|
|
108
|
-
route?.HydrateFallback
|
|
109
|
-
) {
|
|
110
|
-
const HydrateFallback = route.HydrateFallback;
|
|
111
|
-
content = <HydrateFallback />;
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
return (
|
|
115
|
-
<RouteContext.Provider value={contextValue}>
|
|
116
|
-
<RenderErrorBoundary
|
|
117
|
-
onRetry={retry}
|
|
118
|
-
resetKey={`${routeId}:${JSON.stringify(stableParams)}`}
|
|
119
|
-
{...(route?.ErrorBoundary ? { fallback: route.ErrorBoundary } : {})}
|
|
120
|
-
>
|
|
121
|
-
{content}
|
|
122
|
-
</RenderErrorBoundary>
|
|
123
|
-
</RouteContext.Provider>
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
/** Read the current resource route loader result. */
|
|
128
|
-
export function useLoaderData<Data>(): Data | null {
|
|
129
|
-
const route = useCurrentRoute();
|
|
130
|
-
|
|
131
|
-
return useRouteLoaderData<Data>(route.routeId, route.params);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/** Read loader data for a registered resource route. */
|
|
135
|
-
export function useRouteLoaderData<Data>(
|
|
136
|
-
routeId: string,
|
|
137
|
-
params: Params = {},
|
|
138
|
-
): Data | null {
|
|
139
|
-
const state = useRouteState(routeId, useStableParams(params), true);
|
|
140
|
-
|
|
141
|
-
return state.loaderData as Data | null;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/** Read the current resource route action result. */
|
|
145
|
-
export function useActionData<Data>(): Data | null {
|
|
146
|
-
const route = useCurrentRoute();
|
|
147
|
-
const state = useRouteState(route.routeId, route.params, false);
|
|
148
|
-
|
|
149
|
-
return state.actionData as Data | null;
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
/** Read the current page navigation or submission state. */
|
|
153
|
-
export function useNavigation(): { state: NavigationState } {
|
|
154
|
-
const route = useCurrentRoute();
|
|
155
|
-
const state = useRouteState(route.routeId, route.params, false);
|
|
156
|
-
|
|
157
|
-
return { state: state.navigationState };
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/** Return the resource route revalidation function. */
|
|
161
|
-
export function useRevalidator(): {
|
|
162
|
-
revalidate: () => Promise<DataResult<unknown>>;
|
|
163
|
-
state: string;
|
|
164
|
-
} {
|
|
165
|
-
const route = useCurrentRoute();
|
|
166
|
-
const router = useRouter();
|
|
167
|
-
const state = useRouteState(route.routeId, route.params, false);
|
|
168
|
-
|
|
169
|
-
return useMemo(
|
|
170
|
-
() => ({
|
|
171
|
-
revalidate: () => router.load(route.routeId, route.params, true),
|
|
172
|
-
state: state.navigationState === "loading" ? "loading" : "idle",
|
|
173
|
-
}),
|
|
174
|
-
[route, router, state.navigationState],
|
|
175
|
-
);
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
interface FetcherOptions {
|
|
179
|
-
params?: Params;
|
|
180
|
-
routeId?: string;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
interface FetcherTarget {
|
|
184
|
-
params?: Params;
|
|
185
|
-
routeId?: string;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
interface FormProps extends PropsWithChildren {
|
|
189
|
-
action?: string;
|
|
190
|
-
input?: unknown;
|
|
191
|
-
params?: Params;
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
/** Submit a resource action from a form without document navigation. */
|
|
195
|
-
export function Form({
|
|
196
|
-
action,
|
|
197
|
-
children,
|
|
198
|
-
input,
|
|
199
|
-
params,
|
|
200
|
-
}: FormProps): import("react").JSX.Element {
|
|
201
|
-
const currentRoute = useContext(RouteContext);
|
|
202
|
-
const router = useRouter();
|
|
203
|
-
const routeId = action ?? currentRoute?.routeId ?? "";
|
|
204
|
-
const routeParams = useStableParams(params ?? currentRoute?.params ?? {});
|
|
205
|
-
const submit = useCallback(
|
|
206
|
-
(override?: unknown) =>
|
|
207
|
-
router.submit(
|
|
208
|
-
routeId,
|
|
209
|
-
override === undefined ? input : override,
|
|
210
|
-
routeParams,
|
|
211
|
-
),
|
|
212
|
-
[input, routeId, routeParams, router],
|
|
213
|
-
);
|
|
214
|
-
|
|
215
|
-
if (!routeId) throw new Error("Form requires an action or a parent Route.");
|
|
216
|
-
|
|
217
|
-
return <FormContext.Provider value={submit}>{children}</FormContext.Provider>;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
/** Return a function that submits form data through the current router. */
|
|
221
|
-
export function useSubmit(): (input?: unknown) => Promise<DataResult<unknown>> {
|
|
222
|
-
const submit = useContext(FormContext);
|
|
223
|
-
|
|
224
|
-
if (!submit) throw new Error("useSubmit must be used inside Form.");
|
|
225
|
-
|
|
226
|
-
return submit;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
/** Read or mutate a resource independently of the rendered route. */
|
|
230
|
-
export function useFetcher<Data = unknown>(
|
|
231
|
-
options: FetcherOptions = {},
|
|
232
|
-
): readonly [
|
|
233
|
-
{ data: Data | null; error: string; state: NavigationState },
|
|
234
|
-
{
|
|
235
|
-
Form: ({
|
|
236
|
-
children,
|
|
237
|
-
input,
|
|
238
|
-
}: Pick<FormProps, "children" | "input">) => import("react").JSX.Element;
|
|
239
|
-
load: (target?: FetcherTarget) => Promise<DataResult<Data>>;
|
|
240
|
-
submit: (
|
|
241
|
-
input: unknown,
|
|
242
|
-
target?: FetcherTarget,
|
|
243
|
-
) => Promise<DataResult<Data>>;
|
|
244
|
-
},
|
|
245
|
-
] {
|
|
246
|
-
const currentRoute = useContext(RouteContext);
|
|
247
|
-
const router = useRouter();
|
|
248
|
-
const routeId = options.routeId ?? currentRoute?.routeId ?? "";
|
|
249
|
-
const params = useStableParams(options.params ?? currentRoute?.params ?? {});
|
|
250
|
-
const [data, setData] = useState<Data | null>(null);
|
|
251
|
-
const [error, setError] = useState("");
|
|
252
|
-
const [state, setState] = useState<NavigationState>("idle");
|
|
253
|
-
const controller = useRef<AbortController | null>(null);
|
|
254
|
-
useEffect(
|
|
255
|
-
() => () => {
|
|
256
|
-
controller.current?.abort();
|
|
257
|
-
},
|
|
258
|
-
[],
|
|
259
|
-
);
|
|
260
|
-
const run = useCallback(
|
|
261
|
-
async (mutating: boolean, input: unknown, target: FetcherTarget) => {
|
|
262
|
-
controller.current?.abort();
|
|
263
|
-
|
|
264
|
-
const nextController = new AbortController();
|
|
265
|
-
const { signal } = nextController;
|
|
266
|
-
const targetId = target.routeId ?? routeId;
|
|
267
|
-
const targetParams = target.params ?? params;
|
|
268
|
-
|
|
269
|
-
controller.current = nextController;
|
|
270
|
-
setError("");
|
|
271
|
-
setState(mutating ? "submitting" : "loading");
|
|
272
|
-
|
|
273
|
-
const result = await (mutating
|
|
274
|
-
? router.fetchAction<Data>(targetId, input, targetParams, signal)
|
|
275
|
-
: router.fetchLoader<Data>(targetId, targetParams, signal));
|
|
276
|
-
|
|
277
|
-
if (signal.aborted) return result;
|
|
278
|
-
|
|
279
|
-
controller.current = null;
|
|
280
|
-
setData(result.data);
|
|
281
|
-
setError(result.error);
|
|
282
|
-
setState("idle");
|
|
283
|
-
|
|
284
|
-
if (result.unexpected && currentRoute) {
|
|
285
|
-
router.reportUnexpected(currentRoute.routeId, currentRoute.params);
|
|
286
|
-
}
|
|
287
|
-
|
|
288
|
-
return result;
|
|
289
|
-
},
|
|
290
|
-
[currentRoute, params, routeId, router],
|
|
291
|
-
);
|
|
292
|
-
const submit = useCallback(
|
|
293
|
-
(input: unknown, target: FetcherTarget = {}) => run(true, input, target),
|
|
294
|
-
[run],
|
|
295
|
-
);
|
|
296
|
-
const load = useCallback(
|
|
297
|
-
(target: FetcherTarget = {}) => run(false, undefined, target),
|
|
298
|
-
[run],
|
|
299
|
-
);
|
|
300
|
-
const BoundForm = useCallback(
|
|
301
|
-
({ children, input }: Pick<FormProps, "children" | "input">) => (
|
|
302
|
-
<FormContext.Provider
|
|
303
|
-
value={(override) => submit(override === undefined ? input : override)}
|
|
304
|
-
>
|
|
305
|
-
{children}
|
|
306
|
-
</FormContext.Provider>
|
|
307
|
-
),
|
|
308
|
-
[submit],
|
|
309
|
-
);
|
|
310
|
-
|
|
311
|
-
if (!routeId)
|
|
312
|
-
throw new Error("useFetcher requires a routeId or a parent Route.");
|
|
313
|
-
|
|
314
|
-
const fetcherState = useMemo(
|
|
315
|
-
() => ({ data, error, state }),
|
|
316
|
-
[data, error, state],
|
|
317
|
-
);
|
|
318
|
-
const fetcherOperations = useMemo(
|
|
319
|
-
() => ({ Form: BoundForm, load, submit }),
|
|
320
|
-
[BoundForm, load, submit],
|
|
321
|
-
);
|
|
322
|
-
|
|
323
|
-
return [fetcherState, fetcherOperations] as const;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/** Read the resource router supplied by its provider. */
|
|
327
|
-
export function useRouter(): ResourceRouter {
|
|
328
|
-
const router = useContext(RouterContext);
|
|
329
|
-
|
|
330
|
-
if (!router) throw new Error("RouterProvider is missing.");
|
|
331
|
-
|
|
332
|
-
return router;
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
function useCurrentRoute() {
|
|
336
|
-
const route = useContext(RouteContext);
|
|
337
|
-
|
|
338
|
-
if (!route) throw new Error("This hook requires a parent Route.");
|
|
339
|
-
|
|
340
|
-
return route;
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
function useRouteState(routeId: string, params: Params, loadOnMount: boolean) {
|
|
344
|
-
const router = useRouter();
|
|
345
|
-
const subscribe = useCallback(
|
|
346
|
-
(listener: () => void) => router.subscribe(routeId, params, listener),
|
|
347
|
-
[params, routeId, router],
|
|
348
|
-
);
|
|
349
|
-
const getSnapshot = useCallback(
|
|
350
|
-
() => router.getSnapshot(routeId, params),
|
|
351
|
-
[params, routeId, router],
|
|
352
|
-
);
|
|
353
|
-
const state = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);
|
|
354
|
-
useEffect(() => {
|
|
355
|
-
if (loadOnMount) void router.load(routeId, params);
|
|
356
|
-
}, [loadOnMount, params, routeId, router]);
|
|
357
|
-
|
|
358
|
-
return state;
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
function useStableParams(params: Params) {
|
|
362
|
-
const key = JSON.stringify(
|
|
363
|
-
Object.entries(params).sort(([left], [right]) => left.localeCompare(right)),
|
|
364
|
-
);
|
|
365
|
-
const ref = useRef({ key, value: params });
|
|
366
|
-
|
|
367
|
-
if (ref.current.key !== key) ref.current = { key, value: params };
|
|
368
|
-
|
|
369
|
-
return ref.current.value;
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
interface RenderErrorBoundaryProps extends PropsWithChildren {
|
|
373
|
-
fallback?: ComponentType<{ retry: () => void }>;
|
|
374
|
-
onRetry: () => void;
|
|
375
|
-
resetKey: string;
|
|
376
|
-
}
|
|
377
|
-
|
|
378
|
-
class RenderErrorBoundary extends Component<
|
|
379
|
-
RenderErrorBoundaryProps,
|
|
380
|
-
{ error: Error | null }
|
|
381
|
-
> {
|
|
382
|
-
override state = { error: null };
|
|
383
|
-
|
|
384
|
-
static getDerivedStateFromError(error: Error) {
|
|
385
|
-
return { error };
|
|
386
|
-
}
|
|
387
|
-
|
|
388
|
-
override componentDidUpdate(previousProps: RenderErrorBoundaryProps) {
|
|
389
|
-
if (this.state.error && previousProps.resetKey !== this.props.resetKey) {
|
|
390
|
-
this.setState({ error: null });
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
override render() {
|
|
395
|
-
if (this.state.error && this.props.fallback) {
|
|
396
|
-
const ErrorBoundary = this.props.fallback;
|
|
397
|
-
|
|
398
|
-
return (
|
|
399
|
-
<ErrorBoundary
|
|
400
|
-
retry={() => {
|
|
401
|
-
this.setState({ error: null });
|
|
402
|
-
this.props.onRetry();
|
|
403
|
-
}}
|
|
404
|
-
/>
|
|
405
|
-
);
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
if (this.state.error) throw this.state.error;
|
|
409
|
-
|
|
410
|
-
return this.props.children;
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
export type { NavigationState, RouteState };
|
|
415
|
-
|
|
416
|
-
const EMPTY_MATCHES: readonly { params?: Params; routeId: string }[] = [];
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export type Params = Readonly<Record<string, string>>;
|
|
2
|
-
/** Resource parameters and cancellation signal supplied to a loader. */
|
|
3
|
-
export interface LoaderFunctionArgs {
|
|
4
|
-
params: Params;
|
|
5
|
-
signal: AbortSignal;
|
|
6
|
-
}
|
|
7
|
-
/** Submitted input, resource parameters and cancellation signal supplied to an action. */
|
|
8
|
-
export interface ActionFunctionArgs<Input = unknown> {
|
|
9
|
-
input: Input;
|
|
10
|
-
params: Params;
|
|
11
|
-
signal: AbortSignal;
|
|
12
|
-
}
|
|
13
|
-
/** Successful resource data or a normalized resource failure. */
|
|
14
|
-
export interface DataResult<Data> {
|
|
15
|
-
data: Data | null;
|
|
16
|
-
error: string;
|
|
17
|
-
unexpected?: true;
|
|
18
|
-
}
|
|
19
|
-
export interface ResourceModule {
|
|
20
|
-
action?: (args: ActionFunctionArgs) => Promise<DataResult<unknown>>;
|
|
21
|
-
loader?: (args: LoaderFunctionArgs) => Promise<DataResult<unknown>>;
|
|
22
|
-
shouldRevalidate?: (args: ShouldRevalidateFunctionArgs) => boolean;
|
|
23
|
-
}
|
|
24
|
-
/** Navigation or mutation context used to decide whether loader data should refresh. */
|
|
25
|
-
export interface ShouldRevalidateFunctionArgs {
|
|
26
|
-
actionResult: DataResult<unknown>;
|
|
27
|
-
defaultShouldRevalidate: boolean;
|
|
28
|
-
params: Params;
|
|
29
|
-
}
|
|
30
|
-
export type NavigationState = "idle" | "loading" | "submitting";
|
|
31
|
-
export interface RouteState {
|
|
32
|
-
actionData: unknown;
|
|
33
|
-
actionError: string;
|
|
34
|
-
actionState: "idle" | "submitting";
|
|
35
|
-
loaderData: unknown;
|
|
36
|
-
loaderError: string;
|
|
37
|
-
loaderInitialized: boolean;
|
|
38
|
-
loaderState: "idle" | "loading";
|
|
39
|
-
navigationState: NavigationState;
|
|
40
|
-
unexpectedError: boolean;
|
|
41
|
-
}
|
package/dist/core/resources.d.ts
DELETED
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import type { DataResult, Params, ResourceModule, RouteState } from "./resource-types.ts";
|
|
2
|
-
/** Manage keyed resource reads, submissions, subscriptions and cancellation independently of navigation. */
|
|
3
|
-
export declare class ResourceRouter {
|
|
4
|
-
#private;
|
|
5
|
-
constructor(routes: ReadonlyMap<string, ResourceModule>);
|
|
6
|
-
dispose(): void;
|
|
7
|
-
getRoute(routeId: string): ResourceModule | null;
|
|
8
|
-
getSnapshot(routeId: string, params: Params): RouteState;
|
|
9
|
-
hydrateRoute<Data>(routeId: string, data: Data, params?: Params): void;
|
|
10
|
-
persist(routeId: string, params?: Params): void;
|
|
11
|
-
disposeRoute(routeId: string, params?: Params): void;
|
|
12
|
-
load<Data>(routeId: string, params?: Params, force?: boolean): Promise<DataResult<Data>>;
|
|
13
|
-
subscribe(routeId: string, params: Params, listener: () => void): () => void;
|
|
14
|
-
submit<Data>(routeId: string, input: unknown, params?: Params): Promise<DataResult<Data>>;
|
|
15
|
-
fetchLoader<Data>(routeId: string, params: Params, signal: AbortSignal): Promise<DataResult<Data>>;
|
|
16
|
-
fetchAction<Data>(routeId: string, input: unknown, params: Params, signal: AbortSignal): Promise<DataResult<Data>>;
|
|
17
|
-
retry(routeId: string, params: Params): Promise<DataResult<unknown>>;
|
|
18
|
-
reportUnexpected(routeId: string, params: Params): void;
|
|
19
|
-
}
|
|
20
|
-
/** Create an independent resource-data router from registered modules; this does not manage URL history. */
|
|
21
|
-
export declare function createResourceRouter(routes: ReadonlyMap<string, ResourceModule>): ResourceRouter;
|