@kasperrt/smolter 0.4.2 → 0.4.3
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/core/environment.ts +1 -0
- package/.generated/core/navigation.ts +1 -0
- package/.generated/core/resource-types.ts +4 -0
- package/.generated/core/resources.ts +2 -0
- package/.generated/core/responses.ts +12 -0
- package/.generated/core/utils.ts +5 -2
- package/.generated/preact/await.tsx +1 -0
- package/.generated/preact/client.tsx +7 -1
- package/.generated/preact/document.tsx +10 -0
- package/.generated/preact/index.ts +6 -2
- package/.generated/preact/lazy-route.ts +7 -0
- package/.generated/preact/navigation.tsx +6 -0
- package/.generated/preact/route-hooks.tsx +12 -2
- package/.generated/preact/route-types.ts +14 -0
- package/.generated/preact/router.tsx +3 -0
- package/.generated/react/data.ts +5 -1
- package/.generated/react/index.ts +11 -1
- package/.generated/react/outlet.ts +48 -0
- package/.generated/react/resources/components.tsx +12 -0
- package/.generated/server/application.tsx +3 -0
- package/.generated/server/assets.ts +7 -0
- package/.generated/server/handler.ts +3 -0
- package/.generated/server/http.ts +2 -0
- package/.generated/server/node.ts +5 -2
- package/.generated/server/preact.ts +5 -2
- package/CHANGELOG.md +10 -0
- package/README.md +16 -16
- package/dist/core/environment.d.ts +1 -0
- package/dist/core/navigation.d.ts +1 -0
- package/dist/core/resource-types.d.ts +4 -0
- package/dist/core/resources.d.ts +2 -0
- package/dist/core/resources.js +2 -0
- package/dist/core/responses.d.ts +12 -0
- package/dist/core/responses.js +5 -0
- package/dist/core/utils.d.ts +5 -2
- package/dist/core/utils.js +1 -2
- package/dist/preact/await.d.ts +1 -0
- package/dist/preact/await.js +1 -0
- package/dist/preact/client.d.ts +7 -1
- package/dist/preact/client.js +6 -1
- package/dist/preact/document.d.ts +10 -0
- package/dist/preact/document.js +9 -0
- package/dist/preact/index.d.ts +6 -2
- package/dist/preact/lazy-route.d.ts +2 -0
- package/dist/preact/lazy-route.js +6 -0
- package/dist/preact/navigation.d.ts +6 -0
- package/dist/preact/navigation.js +2 -0
- package/dist/preact/route-hooks.d.ts +10 -0
- package/dist/preact/route-hooks.js +12 -2
- package/dist/preact/route-types.d.ts +14 -0
- package/dist/preact/router.d.ts +3 -0
- package/dist/preact/router.js +2 -0
- package/dist/react/data.d.ts +5 -1
- package/dist/react/index.d.ts +6 -1
- package/dist/react/index.js +2 -1
- package/dist/react/outlet.d.ts +16 -0
- package/dist/react/outlet.js +26 -0
- package/dist/react/resources/components.d.ts +12 -0
- package/dist/react/resources/components.js +11 -0
- package/dist/server/application.d.ts +3 -0
- package/dist/server/application.js +2 -0
- package/dist/server/assets.d.ts +2 -0
- package/dist/server/assets.js +6 -0
- package/dist/server/handler.d.ts +3 -0
- package/dist/server/http.d.ts +2 -0
- package/dist/server/http.js +2 -0
- package/dist/server/node.d.ts +5 -1
- package/dist/server/preact.d.ts +5 -1
- package/jsr.json +1 -1
- package/package.json +6 -5
|
@@ -7,6 +7,7 @@ import { createStore } from "./store.ts";
|
|
|
7
7
|
import type { NavigateOptions, Router } from "./types.ts";
|
|
8
8
|
import { navigationClick } from "./url.ts";
|
|
9
9
|
|
|
10
|
+
/** Browser history operation: POP, PUSH or REPLACE. */
|
|
10
11
|
export type NavigationType = "POP" | "PUSH" | "REPLACE";
|
|
11
12
|
|
|
12
13
|
export interface NavigationSnapshot {
|
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
export type Params = Readonly<Record<string, string>>;
|
|
2
2
|
|
|
3
|
+
/** Resource parameters and cancellation signal supplied to a loader. */
|
|
3
4
|
export interface LoaderFunctionArgs {
|
|
4
5
|
params: Params;
|
|
5
6
|
signal: AbortSignal;
|
|
6
7
|
}
|
|
7
8
|
|
|
9
|
+
/** Submitted input, resource parameters and cancellation signal supplied to an action. */
|
|
8
10
|
export interface ActionFunctionArgs<Input = unknown> {
|
|
9
11
|
input: Input;
|
|
10
12
|
params: Params;
|
|
11
13
|
signal: AbortSignal;
|
|
12
14
|
}
|
|
13
15
|
|
|
16
|
+
/** Successful resource data or a normalized resource failure. */
|
|
14
17
|
export interface DataResult<Data> {
|
|
15
18
|
data: Data | null;
|
|
16
19
|
error: string;
|
|
@@ -23,6 +26,7 @@ export interface ResourceModule {
|
|
|
23
26
|
shouldRevalidate?: (args: ShouldRevalidateFunctionArgs) => boolean;
|
|
24
27
|
}
|
|
25
28
|
|
|
29
|
+
/** Navigation or mutation context used to decide whether loader data should refresh. */
|
|
26
30
|
export interface ShouldRevalidateFunctionArgs {
|
|
27
31
|
actionResult: DataResult<unknown>;
|
|
28
32
|
defaultShouldRevalidate: boolean;
|
|
@@ -18,6 +18,7 @@ const IDLE_ROUTE_STATE: RouteState = {
|
|
|
18
18
|
unexpectedError: false,
|
|
19
19
|
};
|
|
20
20
|
|
|
21
|
+
/** Manage keyed resource reads, submissions, subscriptions and cancellation independently of navigation. */
|
|
21
22
|
export class ResourceRouter {
|
|
22
23
|
readonly #cleanupTimers = new Map<string, ReturnType<typeof setTimeout>>();
|
|
23
24
|
readonly #controllers = new Map<string, AbortController>();
|
|
@@ -427,6 +428,7 @@ export class ResourceRouter {
|
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
430
|
|
|
431
|
+
/** Create an independent resource-data router from registered modules; this does not manage URL history. */
|
|
430
432
|
export function createResourceRouter(
|
|
431
433
|
routes: ReadonlyMap<string, ResourceModule>,
|
|
432
434
|
): ResourceRouter {
|
|
@@ -1,19 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP response helpers and loader result normalization.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
6
|
+
/** Normalized route failure with an HTTP status, status text and optional response data. */
|
|
1
7
|
export interface RouteError extends Error {
|
|
2
8
|
status: number;
|
|
3
9
|
statusText: string;
|
|
4
10
|
data?: unknown;
|
|
5
11
|
}
|
|
6
12
|
|
|
13
|
+
/** Loader value paired with HTTP response metadata. */
|
|
7
14
|
export interface DataResponse<T> {
|
|
8
15
|
value: T;
|
|
9
16
|
init: ResponseInit;
|
|
10
17
|
__routeData: true;
|
|
11
18
|
}
|
|
12
19
|
|
|
20
|
+
/** Wrap loader data with HTTP status and headers without creating a Response body. */
|
|
13
21
|
export function data<T>(value: T, init: ResponseInit = {}): DataResponse<T> {
|
|
14
22
|
return { value, init, __routeData: true };
|
|
15
23
|
}
|
|
16
24
|
|
|
25
|
+
/** Create an empty redirect Response with a Location header; defaults to HTTP 302. */
|
|
17
26
|
export function redirect(
|
|
18
27
|
location: string,
|
|
19
28
|
init: number | ResponseInit = 302,
|
|
@@ -29,10 +38,12 @@ export function redirect(
|
|
|
29
38
|
});
|
|
30
39
|
}
|
|
31
40
|
|
|
41
|
+
/** Identify normalized Error objects carrying an HTTP status. */
|
|
32
42
|
export function isRouteErrorResponse(value: unknown): value is RouteError {
|
|
33
43
|
return value instanceof Error && "status" in value;
|
|
34
44
|
}
|
|
35
45
|
|
|
46
|
+
/** Normalize transport responses and wrapped data, optionally resolving nested deferred values. */
|
|
36
47
|
export async function normalizeResult(
|
|
37
48
|
value: unknown,
|
|
38
49
|
resolveDeferred = true,
|
|
@@ -68,6 +79,7 @@ export async function normalizeResult(
|
|
|
68
79
|
}
|
|
69
80
|
|
|
70
81
|
// Smolter transfers JSON snapshots. Resolve deferred fields before serialization.
|
|
82
|
+
/** Recursively resolve promises in arrays and plain objects before JSON serialization. */
|
|
71
83
|
export async function resolveData(value: unknown): Promise<unknown> {
|
|
72
84
|
const resolved = await value;
|
|
73
85
|
|
package/.generated/core/utils.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
/**
|
|
2
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Routing patterns, query strings and serialized data utilities.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
3
6
|
export * from "./match.ts";
|
|
4
7
|
export * from "./serialize.ts";
|
|
5
8
|
export * from "./url.ts";
|
|
@@ -17,6 +17,7 @@ type Resolution = { value: unknown } | { error: unknown };
|
|
|
17
17
|
// Cache only the error-as-data adapter. Preact owns pending and resolved state.
|
|
18
18
|
const resolutions = new WeakMap<Promise<unknown>, Promise<Resolution>>();
|
|
19
19
|
|
|
20
|
+
/** Render a value or promise. An explicit fallback owns pending content during early hydration; errorElement handles rejection. */
|
|
20
21
|
export function Await<T>(props: AwaitProps<T>): ComponentChildren {
|
|
21
22
|
const app = useContext(Application);
|
|
22
23
|
if (!(props.resolve instanceof Promise))
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Preact document hydration, browser history and deployment recovery.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
2
6
|
/** @jsxImportSource preact */
|
|
3
7
|
|
|
4
8
|
import {
|
|
@@ -19,6 +23,7 @@ import { prepareRoutes, RouterApplication } from "./router.tsx";
|
|
|
19
23
|
export * from "../client/index.ts";
|
|
20
24
|
export { configureApplication } from "../core/environment.ts";
|
|
21
25
|
|
|
26
|
+
/** Browser hydration settings for hash history, deployment recovery and deferred-data timeout. */
|
|
22
27
|
export interface MountApplicationOptions {
|
|
23
28
|
hash?: boolean;
|
|
24
29
|
deployment?: DeploymentOptions | null;
|
|
@@ -26,6 +31,7 @@ export interface MountApplicationOptions {
|
|
|
26
31
|
deferredTimeout?: number;
|
|
27
32
|
}
|
|
28
33
|
|
|
34
|
+
/** Create the browser application router and hydrate the document, installing recovery before initial lazy loading. */
|
|
29
35
|
export async function mountApplication(
|
|
30
36
|
routes: AppRoute[],
|
|
31
37
|
rootModule?: RootModule,
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Preact document metadata, resource links and hydration scripts.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
/** @jsxImportSource preact */
|
|
2
7
|
|
|
3
8
|
import { applicationEnvironment } from "../core/environment.ts";
|
|
@@ -34,6 +39,7 @@ function renderMeta(item: MetaDescriptor, index: number) {
|
|
|
34
39
|
});
|
|
35
40
|
}
|
|
36
41
|
|
|
42
|
+
/** Render root or active-route metadata in the document head. */
|
|
37
43
|
export function Meta(): import("preact").JSX.Element {
|
|
38
44
|
const { routes, rootModule } = useApplication();
|
|
39
45
|
const snapshot = useSnapshot();
|
|
@@ -55,6 +61,7 @@ export function Meta(): import("preact").JSX.Element {
|
|
|
55
61
|
return <Fragment>{values.map(renderMeta)}</Fragment>;
|
|
56
62
|
}
|
|
57
63
|
|
|
64
|
+
/** Render stylesheet and other link descriptors from the application root. */
|
|
58
65
|
export function Links(): import("preact").JSX.Element {
|
|
59
66
|
const { rootModule } = useApplication();
|
|
60
67
|
|
|
@@ -67,10 +74,12 @@ export function Links(): import("preact").JSX.Element {
|
|
|
67
74
|
);
|
|
68
75
|
}
|
|
69
76
|
|
|
77
|
+
/** Nonce and browser entry options for the document hydration scripts. */
|
|
70
78
|
export interface ScriptProps {
|
|
71
79
|
nonce?: string;
|
|
72
80
|
}
|
|
73
81
|
|
|
82
|
+
/** Render the hydration snapshot and browser entry script with an optional CSP nonce. */
|
|
74
83
|
export function Scripts({ nonce }: ScriptProps): import("preact").JSX.Element {
|
|
75
84
|
const { root, rootError, router, entry, streaming, initialData } =
|
|
76
85
|
useApplication();
|
|
@@ -119,6 +128,7 @@ export function Scripts({ nonce }: ScriptProps): import("preact").JSX.Element {
|
|
|
119
128
|
);
|
|
120
129
|
}
|
|
121
130
|
|
|
131
|
+
/** Reset scroll after navigation unless the navigation requests preservation. */
|
|
122
132
|
export function ScrollRestoration(_props: ScriptProps): null {
|
|
123
133
|
const { router } = useApplication();
|
|
124
134
|
const { url, state } = useSnapshot();
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* Preact routing components, typed data hooks and application integration.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
2
6
|
export type * from "../core/index.ts";
|
|
3
7
|
export {
|
|
4
8
|
createDataRouter,
|
|
@@ -30,5 +34,5 @@ export {
|
|
|
30
34
|
useSubmit,
|
|
31
35
|
} from "./route-hooks.tsx";
|
|
32
36
|
export * from "./route-types.ts";
|
|
33
|
-
export { Outlet, RouterApplication } from "./router.tsx";
|
|
37
|
+
export { Outlet, type OutletProps, RouterApplication } from "./router.tsx";
|
|
34
38
|
export * from "./routes.ts";
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* On-demand Preact route modules with shared intent prefetching.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
1
6
|
import { serverRoute } from "../client/index.ts";
|
|
2
7
|
import type { DataArgs, RouteModule, Router } from "../core/index.ts";
|
|
3
8
|
import { type ComponentType, createElement } from "preact";
|
|
@@ -6,6 +11,7 @@ import type { AppRoute } from "./route-types.ts";
|
|
|
6
11
|
import type { ErrorProps } from "./routes.ts";
|
|
7
12
|
import { useSyncExternalStore } from "./runtime.ts";
|
|
8
13
|
|
|
14
|
+
/** Lazy route path, server transport endpoint and available handler capabilities. */
|
|
9
15
|
export interface LazyRouteOptions {
|
|
10
16
|
path: string;
|
|
11
17
|
dataEndpoint?: string;
|
|
@@ -36,6 +42,7 @@ function LazyView() {
|
|
|
36
42
|
return Component && createElement(Component, {});
|
|
37
43
|
}
|
|
38
44
|
|
|
45
|
+
/** Create a route that imports its module on demand and shares the import with intent prefetching. */
|
|
39
46
|
export function lazyRoute(
|
|
40
47
|
options: LazyRouteOptions,
|
|
41
48
|
importer: () => Promise<LoadedRoute>,
|
|
@@ -15,11 +15,13 @@ export type { NavigateOptions } from "../core/index.ts";
|
|
|
15
15
|
|
|
16
16
|
export type { NavigationType } from "../core/navigation.ts";
|
|
17
17
|
|
|
18
|
+
/** Navigate to a URL or move through browser history using a numeric offset. */
|
|
18
19
|
export type NavigateFunction = (
|
|
19
20
|
to: string | number | Partial<Pick<URL, "pathname" | "search" | "hash">>,
|
|
20
21
|
options?: NavigateOptions,
|
|
21
22
|
) => void;
|
|
22
23
|
|
|
24
|
+
/** Anchor properties and router navigation options, including document reload and prefetch controls. */
|
|
23
25
|
export interface LinkProps extends Omit<ComponentProps<"a">, "href" | "role"> {
|
|
24
26
|
to?: string;
|
|
25
27
|
href?: string;
|
|
@@ -47,11 +49,13 @@ export interface LinkProps extends Omit<ComponentProps<"a">, "href" | "role"> {
|
|
|
47
49
|
reloadDocument?: boolean;
|
|
48
50
|
}
|
|
49
51
|
|
|
52
|
+
/** Active and pending flags supplied to NavLink render callbacks. */
|
|
50
53
|
export interface NavLinkRenderProps {
|
|
51
54
|
isActive: boolean;
|
|
52
55
|
isPending: boolean;
|
|
53
56
|
}
|
|
54
57
|
|
|
58
|
+
/** Link options with matching rules and state-aware class or children callbacks. */
|
|
55
59
|
export interface NavLinkProps
|
|
56
60
|
extends Omit<LinkProps, "className" | "children"> {
|
|
57
61
|
end?: boolean;
|
|
@@ -59,6 +63,7 @@ export interface NavLinkProps
|
|
|
59
63
|
children?: ReactNode | ((state: NavLinkRenderProps) => ReactNode);
|
|
60
64
|
}
|
|
61
65
|
|
|
66
|
+
/** Render an anchor with same-origin router navigation and optional intent prefetching. */
|
|
62
67
|
export function Link(options: LinkProps): ReactNode {
|
|
63
68
|
const {
|
|
64
69
|
href: hrefProp,
|
|
@@ -115,6 +120,7 @@ export function Link(options: LinkProps): ReactNode {
|
|
|
115
120
|
});
|
|
116
121
|
}
|
|
117
122
|
|
|
123
|
+
/** Render a Link with active-route state and aria-current for the matching destination. */
|
|
118
124
|
export function NavLink({
|
|
119
125
|
href,
|
|
120
126
|
to = href ?? "/",
|
|
@@ -15,6 +15,7 @@ import { OutletContext, useApplication } from "./root-context.ts";
|
|
|
15
15
|
import type { RouteData } from "./route-types.ts";
|
|
16
16
|
import { useContext, useMemo } from "./runtime.ts";
|
|
17
17
|
|
|
18
|
+
/** Read root loader data from the application context. */
|
|
18
19
|
export function useRootData<T = unknown>(): RouteData<T> {
|
|
19
20
|
return useApplication().root as RouteData<T>;
|
|
20
21
|
}
|
|
@@ -37,10 +38,12 @@ export function useRouteLoaderData<T = unknown>(
|
|
|
37
38
|
|
|
38
39
|
export { useSnapshot };
|
|
39
40
|
|
|
41
|
+
/** Read the current route error for an error boundary. */
|
|
40
42
|
export function useRouteError(): Error | undefined {
|
|
41
43
|
return useSnapshot("error");
|
|
42
44
|
}
|
|
43
45
|
|
|
46
|
+
/** Read the current page navigation or submission state. */
|
|
44
47
|
export function useNavigation(): {
|
|
45
48
|
state: "idle" | "loading" | "submitting";
|
|
46
49
|
location: URL | undefined;
|
|
@@ -58,24 +61,27 @@ export function useNavigation(): {
|
|
|
58
61
|
);
|
|
59
62
|
}
|
|
60
63
|
|
|
64
|
+
/** Read the active flat route match and loader data; this is not a nested layout match chain. */
|
|
61
65
|
export function useMatches(): {
|
|
62
66
|
id: string;
|
|
63
67
|
data: unknown;
|
|
64
68
|
params: import("../core/index.ts").Params;
|
|
65
69
|
}[] {
|
|
66
|
-
const
|
|
70
|
+
const router = useRouter();
|
|
67
71
|
const snapshot = useSnapshot();
|
|
68
|
-
const route = routes.find((item) => item.path === snapshot.path);
|
|
72
|
+
const route = router.routes.find((item) => item.path === snapshot.path);
|
|
69
73
|
|
|
70
74
|
return [
|
|
71
75
|
{ id: route?.id ?? "", data: snapshot.data, params: snapshot.params },
|
|
72
76
|
];
|
|
73
77
|
}
|
|
74
78
|
|
|
79
|
+
/** Read context supplied by the nearest Outlet. */
|
|
75
80
|
export function useOutletContext<T>(): T {
|
|
76
81
|
return useContext(OutletContext) as T;
|
|
77
82
|
}
|
|
78
83
|
|
|
84
|
+
/** Return a function that submits form data through the current router. */
|
|
79
85
|
export function useSubmit(): (
|
|
80
86
|
value: Submission,
|
|
81
87
|
options?: SubmissionOptions,
|
|
@@ -103,6 +109,7 @@ export function useSubmit(): (
|
|
|
103
109
|
);
|
|
104
110
|
}
|
|
105
111
|
|
|
112
|
+
/** Read the current router location as a URL. */
|
|
106
113
|
export function useURLLocation(): URL & { state: unknown; key: string } {
|
|
107
114
|
const href = useSnapshot("url");
|
|
108
115
|
const snapshot = useNavigationSnapshot(useRouter<Router>());
|
|
@@ -117,6 +124,7 @@ export function useURLLocation(): URL & { state: unknown; key: string } {
|
|
|
117
124
|
);
|
|
118
125
|
}
|
|
119
126
|
|
|
127
|
+
/** Return the application navigation function, including history offsets and relative destinations. */
|
|
120
128
|
export function useNavigate(): NavigateFunction {
|
|
121
129
|
const router = useRouter<Router>();
|
|
122
130
|
|
|
@@ -139,6 +147,7 @@ export function useNavigate(): NavigateFunction {
|
|
|
139
147
|
);
|
|
140
148
|
}
|
|
141
149
|
|
|
150
|
+
/** Read URL search parameters and update them through router navigation. */
|
|
142
151
|
export function useSearchParams(): [
|
|
143
152
|
URLSearchParams,
|
|
144
153
|
(
|
|
@@ -165,6 +174,7 @@ export function useSearchParams(): [
|
|
|
165
174
|
return [params, set];
|
|
166
175
|
}
|
|
167
176
|
|
|
177
|
+
/** Read the last browser history operation. */
|
|
168
178
|
export function useNavigationType(): NavigationType {
|
|
169
179
|
return useNavigationSnapshot(useRouter<Router>()).type;
|
|
170
180
|
}
|
|
@@ -7,30 +7,38 @@ import type {
|
|
|
7
7
|
import type { DataResponse } from "../core/responses.ts";
|
|
8
8
|
import type { ComponentType, ReactNode } from "preact/compat";
|
|
9
9
|
|
|
10
|
+
/** Request, route parameters and cancellation signal supplied to a loader. */
|
|
10
11
|
export interface LoaderFunctionArgs extends DataArgs {
|
|
11
12
|
context?: unknown;
|
|
12
13
|
}
|
|
13
14
|
|
|
15
|
+
/** Request, route parameters and cancellation signal supplied to an action. */
|
|
14
16
|
export type ActionFunctionArgs = LoaderFunctionArgs;
|
|
15
17
|
|
|
18
|
+
/** Loader arguments with a serverLoader callback for the server transport. */
|
|
16
19
|
export interface ClientLoaderFunctionArgs extends LoaderFunctionArgs {
|
|
17
20
|
serverLoader: <T = unknown>() => Promise<T>;
|
|
18
21
|
}
|
|
19
22
|
|
|
23
|
+
/** Action arguments with a serverAction callback for the server transport. */
|
|
20
24
|
export interface ClientActionFunctionArgs extends LoaderFunctionArgs {
|
|
21
25
|
serverAction: <T = unknown>() => Promise<T>;
|
|
22
26
|
}
|
|
23
27
|
|
|
28
|
+
/** Navigation or mutation context used to decide whether loader data should refresh. */
|
|
24
29
|
export type ShouldRevalidateFunctionArgs = RevalidationArgs;
|
|
25
30
|
|
|
26
31
|
type UnwrapData<T> = T extends DataResponse<infer V> ? V : T;
|
|
27
32
|
|
|
33
|
+
/** Infer successful loader data, unwrapping promises and data responses. */
|
|
28
34
|
export type RouteData<T> = T extends (...args: never[]) => infer R
|
|
29
35
|
? UnwrapData<Exclude<Awaited<R>, Response | Error>>
|
|
30
36
|
: T;
|
|
31
37
|
|
|
38
|
+
/** A document metadata descriptor, such as a title, meta tag or structured-data record. */
|
|
32
39
|
export type MetaDescriptor = Record<string, unknown>;
|
|
33
40
|
|
|
41
|
+
/** Loader data, error, parameters and location supplied to a route metadata function. */
|
|
34
42
|
export interface MetaArgs<T> {
|
|
35
43
|
data: RouteData<T> | undefined;
|
|
36
44
|
loaderData: RouteData<T> | undefined;
|
|
@@ -39,10 +47,13 @@ export interface MetaArgs<T> {
|
|
|
39
47
|
location: URL;
|
|
40
48
|
}
|
|
41
49
|
|
|
50
|
+
/** Derive document metadata descriptors from the current route data and location. */
|
|
42
51
|
export type MetaFunction<T = unknown> = (args: MetaArgs<T>) => MetaDescriptor[];
|
|
43
52
|
|
|
53
|
+
/** Return link descriptors rendered in the document head. */
|
|
44
54
|
export type LinksFunction = () => Record<string, string>[];
|
|
45
55
|
|
|
56
|
+
/** Data route with optional lazy component, preload and document metadata integration. */
|
|
46
57
|
export interface AppRoute extends Route {
|
|
47
58
|
resolveComponent?: () => ComponentType | undefined;
|
|
48
59
|
preload?: () => Promise<void>;
|
|
@@ -51,6 +62,7 @@ export interface AppRoute extends Route {
|
|
|
51
62
|
meta?: MetaFunction;
|
|
52
63
|
}
|
|
53
64
|
|
|
65
|
+
/** Root document components, loader, metadata and revalidation policy for a Preact application. */
|
|
54
66
|
export interface RootModule {
|
|
55
67
|
/** Route identity used by targeted revalidation. Defaults to root. */
|
|
56
68
|
id?: string;
|
|
@@ -65,12 +77,14 @@ export interface RootModule {
|
|
|
65
77
|
shouldRevalidate?: (args: RevalidationArgs) => boolean;
|
|
66
78
|
}
|
|
67
79
|
|
|
80
|
+
/** Serialized root data and route snapshot used to hydrate without repeating initial loaders. */
|
|
68
81
|
export interface Hydration {
|
|
69
82
|
rootError?: boolean;
|
|
70
83
|
root: unknown;
|
|
71
84
|
snapshot: Snapshot;
|
|
72
85
|
}
|
|
73
86
|
|
|
87
|
+
/** Transform a data transport response using the current request context. */
|
|
74
88
|
export type HandleDataRequestFunction = (
|
|
75
89
|
response: Response,
|
|
76
90
|
args: LoaderFunctionArgs,
|
|
@@ -14,11 +14,13 @@ import type { AppRoute } from "./route-types.ts";
|
|
|
14
14
|
import { Routes } from "./routes.ts";
|
|
15
15
|
import { useContext, useMemo, useSyncExternalStore } from "./runtime.ts";
|
|
16
16
|
|
|
17
|
+
/** Optional children and context shared with descendants through useOutletContext. */
|
|
17
18
|
export interface OutletProps {
|
|
18
19
|
context?: unknown;
|
|
19
20
|
children?: ReactNode;
|
|
20
21
|
}
|
|
21
22
|
|
|
23
|
+
/** Render supplied children or the active route, and provide outlet context to descendants. */
|
|
22
24
|
export function Outlet({
|
|
23
25
|
context,
|
|
24
26
|
children,
|
|
@@ -37,6 +39,7 @@ export interface ApplicationProps extends ApplicationContext {
|
|
|
37
39
|
rootStore?: ReturnType<typeof createRootStore>;
|
|
38
40
|
}
|
|
39
41
|
|
|
42
|
+
/** Render a Preact root document and active route with shared root data and application context. */
|
|
40
43
|
export function RouterApplication(
|
|
41
44
|
props: ApplicationProps,
|
|
42
45
|
): import("preact").JSX.Element {
|
package/.generated/react/data.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
/**
|
|
1
|
+
/**
|
|
2
|
+
* React routing components, typed data hooks and forms.
|
|
3
|
+
*
|
|
4
|
+
* @module
|
|
5
|
+
*/
|
|
2
6
|
export type * from "../core/index.ts";
|
|
3
7
|
export {
|
|
4
8
|
createDataRouter,
|
|
@@ -14,4 +18,10 @@ export * from "./fetcher.ts";
|
|
|
14
18
|
export * from "./form.ts";
|
|
15
19
|
export * from "./hooks.ts";
|
|
16
20
|
export * from "./link.ts";
|
|
21
|
+
export {
|
|
22
|
+
Outlet,
|
|
23
|
+
type OutletProps,
|
|
24
|
+
useMatches,
|
|
25
|
+
useOutletContext,
|
|
26
|
+
} from "./outlet.ts";
|
|
17
27
|
export * from "./routes.ts";
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { useRouter, useSnapshot } from "./context.ts";
|
|
2
|
+
import { Routes } from "./routes.ts";
|
|
3
|
+
import {
|
|
4
|
+
createContext,
|
|
5
|
+
createElement,
|
|
6
|
+
type ReactNode,
|
|
7
|
+
useContext,
|
|
8
|
+
} from "./runtime.ts";
|
|
9
|
+
|
|
10
|
+
const OutletContext = createContext<unknown>(undefined);
|
|
11
|
+
|
|
12
|
+
/** Optional children and context shared with descendants through useOutletContext. */
|
|
13
|
+
export interface OutletProps {
|
|
14
|
+
context?: unknown;
|
|
15
|
+
children?: ReactNode;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/** Render the active route under a layout's shared context. */
|
|
19
|
+
export function Outlet({ context, children }: OutletProps): ReactNode {
|
|
20
|
+
const inherited = useContext(OutletContext);
|
|
21
|
+
return createElement(
|
|
22
|
+
OutletContext.Provider,
|
|
23
|
+
{ value: context ?? inherited },
|
|
24
|
+
children ??
|
|
25
|
+
createElement(Routes, {
|
|
26
|
+
fallback: createElement("p", { role: "status" }, "Loading…"),
|
|
27
|
+
}),
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Read the nearest Outlet's context. */
|
|
32
|
+
export function useOutletContext<T>(): T {
|
|
33
|
+
return useContext(OutletContext) as T;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/** Read the active flat route match; this is not a nested layout match chain. */
|
|
37
|
+
export function useMatches(): {
|
|
38
|
+
id: string;
|
|
39
|
+
data: unknown;
|
|
40
|
+
params: import("../core/index.ts").Params;
|
|
41
|
+
}[] {
|
|
42
|
+
const router = useRouter();
|
|
43
|
+
const snapshot = useSnapshot();
|
|
44
|
+
const route = router.routes.find((item) => item.path === snapshot.path);
|
|
45
|
+
return [
|
|
46
|
+
{ id: route?.id ?? "", data: snapshot.data, params: snapshot.params },
|
|
47
|
+
];
|
|
48
|
+
}
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
useSyncExternalStore,
|
|
24
24
|
} from "react";
|
|
25
25
|
|
|
26
|
+
/** Resource handlers with optional React content, pending UI and retry boundary. */
|
|
26
27
|
export interface ResourceRouteModule extends ResourceModule {
|
|
27
28
|
default?: ComponentType;
|
|
28
29
|
ErrorBoundary?: ComponentType<{ retry: () => void }>;
|
|
@@ -42,6 +43,7 @@ interface RouterProviderProps extends PropsWithChildren {
|
|
|
42
43
|
router: ResourceRouter;
|
|
43
44
|
}
|
|
44
45
|
|
|
46
|
+
/** Provide a resource router and load initial matches; dispose it when unmounted. */
|
|
45
47
|
export function RouterProvider({
|
|
46
48
|
children,
|
|
47
49
|
initialMatches = EMPTY_MATCHES,
|
|
@@ -66,6 +68,7 @@ interface RouteProps extends PropsWithChildren {
|
|
|
66
68
|
routeId: string;
|
|
67
69
|
}
|
|
68
70
|
|
|
71
|
+
/** Provide a resource route and render its content, loading state or retry boundary. */
|
|
69
72
|
export function Route({
|
|
70
73
|
children,
|
|
71
74
|
params = {},
|
|
@@ -121,12 +124,14 @@ export function Route({
|
|
|
121
124
|
);
|
|
122
125
|
}
|
|
123
126
|
|
|
127
|
+
/** Read the current resource route loader result. */
|
|
124
128
|
export function useLoaderData<Data>(): Data | null {
|
|
125
129
|
const route = useCurrentRoute();
|
|
126
130
|
|
|
127
131
|
return useRouteLoaderData<Data>(route.routeId, route.params);
|
|
128
132
|
}
|
|
129
133
|
|
|
134
|
+
/** Read loader data for a registered resource route. */
|
|
130
135
|
export function useRouteLoaderData<Data>(
|
|
131
136
|
routeId: string,
|
|
132
137
|
params: Params = {},
|
|
@@ -136,6 +141,7 @@ export function useRouteLoaderData<Data>(
|
|
|
136
141
|
return state.loaderData as Data | null;
|
|
137
142
|
}
|
|
138
143
|
|
|
144
|
+
/** Read the current resource route action result. */
|
|
139
145
|
export function useActionData<Data>(): Data | null {
|
|
140
146
|
const route = useCurrentRoute();
|
|
141
147
|
const state = useRouteState(route.routeId, route.params, false);
|
|
@@ -143,6 +149,7 @@ export function useActionData<Data>(): Data | null {
|
|
|
143
149
|
return state.actionData as Data | null;
|
|
144
150
|
}
|
|
145
151
|
|
|
152
|
+
/** Read the current page navigation or submission state. */
|
|
146
153
|
export function useNavigation(): { state: NavigationState } {
|
|
147
154
|
const route = useCurrentRoute();
|
|
148
155
|
const state = useRouteState(route.routeId, route.params, false);
|
|
@@ -150,6 +157,7 @@ export function useNavigation(): { state: NavigationState } {
|
|
|
150
157
|
return { state: state.navigationState };
|
|
151
158
|
}
|
|
152
159
|
|
|
160
|
+
/** Return the resource route revalidation function. */
|
|
153
161
|
export function useRevalidator(): {
|
|
154
162
|
revalidate: () => Promise<DataResult<unknown>>;
|
|
155
163
|
state: string;
|
|
@@ -183,6 +191,7 @@ interface FormProps extends PropsWithChildren {
|
|
|
183
191
|
params?: Params;
|
|
184
192
|
}
|
|
185
193
|
|
|
194
|
+
/** Submit a resource action from a form without document navigation. */
|
|
186
195
|
export function Form({
|
|
187
196
|
action,
|
|
188
197
|
children,
|
|
@@ -208,6 +217,7 @@ export function Form({
|
|
|
208
217
|
return <FormContext.Provider value={submit}>{children}</FormContext.Provider>;
|
|
209
218
|
}
|
|
210
219
|
|
|
220
|
+
/** Return a function that submits form data through the current router. */
|
|
211
221
|
export function useSubmit(): (input?: unknown) => Promise<DataResult<unknown>> {
|
|
212
222
|
const submit = useContext(FormContext);
|
|
213
223
|
|
|
@@ -216,6 +226,7 @@ export function useSubmit(): (input?: unknown) => Promise<DataResult<unknown>> {
|
|
|
216
226
|
return submit;
|
|
217
227
|
}
|
|
218
228
|
|
|
229
|
+
/** Read or mutate a resource independently of the rendered route. */
|
|
219
230
|
export function useFetcher<Data = unknown>(
|
|
220
231
|
options: FetcherOptions = {},
|
|
221
232
|
): readonly [
|
|
@@ -312,6 +323,7 @@ export function useFetcher<Data = unknown>(
|
|
|
312
323
|
return [fetcherState, fetcherOperations] as const;
|
|
313
324
|
}
|
|
314
325
|
|
|
326
|
+
/** Read the resource router supplied by its provider. */
|
|
315
327
|
export function useRouter(): ResourceRouter {
|
|
316
328
|
const router = useContext(RouterContext);
|
|
317
329
|
|
|
@@ -17,11 +17,13 @@ import { privateResponse } from "./private-response.ts";
|
|
|
17
17
|
import { progressiveDocument } from "./progressive-document.ts";
|
|
18
18
|
import { resolveHydration, streamDocument } from "./stream-document.ts";
|
|
19
19
|
|
|
20
|
+
/** SSR settings for CSP nonce and early deferred-data hydration. */
|
|
20
21
|
export interface RenderApplicationOptions {
|
|
21
22
|
nonce?: string;
|
|
22
23
|
earlyHydration?: boolean;
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
/** Render a Preact application response with root and route data, streaming deferred content when enabled. */
|
|
25
27
|
export async function renderApplication(
|
|
26
28
|
request: Request,
|
|
27
29
|
routes: AppRoute[],
|
|
@@ -260,6 +262,7 @@ async function dispatch(
|
|
|
260
262
|
return Response.json((await normalizeResult(value)) ?? null);
|
|
261
263
|
}
|
|
262
264
|
|
|
265
|
+
/** Dispatch a normalized application URL to its route loader or action and return an HTTP response. */
|
|
263
266
|
export async function dispatchRoute(
|
|
264
267
|
request: Request,
|
|
265
268
|
routes: AppRoute[],
|