@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.
Files changed (70) hide show
  1. package/.generated/core/environment.ts +1 -0
  2. package/.generated/core/navigation.ts +1 -0
  3. package/.generated/core/resource-types.ts +4 -0
  4. package/.generated/core/resources.ts +2 -0
  5. package/.generated/core/responses.ts +12 -0
  6. package/.generated/core/utils.ts +5 -2
  7. package/.generated/preact/await.tsx +1 -0
  8. package/.generated/preact/client.tsx +7 -1
  9. package/.generated/preact/document.tsx +10 -0
  10. package/.generated/preact/index.ts +6 -2
  11. package/.generated/preact/lazy-route.ts +7 -0
  12. package/.generated/preact/navigation.tsx +6 -0
  13. package/.generated/preact/route-hooks.tsx +12 -2
  14. package/.generated/preact/route-types.ts +14 -0
  15. package/.generated/preact/router.tsx +3 -0
  16. package/.generated/react/data.ts +5 -1
  17. package/.generated/react/index.ts +11 -1
  18. package/.generated/react/outlet.ts +48 -0
  19. package/.generated/react/resources/components.tsx +12 -0
  20. package/.generated/server/application.tsx +3 -0
  21. package/.generated/server/assets.ts +7 -0
  22. package/.generated/server/handler.ts +3 -0
  23. package/.generated/server/http.ts +2 -0
  24. package/.generated/server/node.ts +5 -2
  25. package/.generated/server/preact.ts +5 -2
  26. package/CHANGELOG.md +10 -0
  27. package/README.md +16 -16
  28. package/dist/core/environment.d.ts +1 -0
  29. package/dist/core/navigation.d.ts +1 -0
  30. package/dist/core/resource-types.d.ts +4 -0
  31. package/dist/core/resources.d.ts +2 -0
  32. package/dist/core/resources.js +2 -0
  33. package/dist/core/responses.d.ts +12 -0
  34. package/dist/core/responses.js +5 -0
  35. package/dist/core/utils.d.ts +5 -2
  36. package/dist/core/utils.js +1 -2
  37. package/dist/preact/await.d.ts +1 -0
  38. package/dist/preact/await.js +1 -0
  39. package/dist/preact/client.d.ts +7 -1
  40. package/dist/preact/client.js +6 -1
  41. package/dist/preact/document.d.ts +10 -0
  42. package/dist/preact/document.js +9 -0
  43. package/dist/preact/index.d.ts +6 -2
  44. package/dist/preact/lazy-route.d.ts +2 -0
  45. package/dist/preact/lazy-route.js +6 -0
  46. package/dist/preact/navigation.d.ts +6 -0
  47. package/dist/preact/navigation.js +2 -0
  48. package/dist/preact/route-hooks.d.ts +10 -0
  49. package/dist/preact/route-hooks.js +12 -2
  50. package/dist/preact/route-types.d.ts +14 -0
  51. package/dist/preact/router.d.ts +3 -0
  52. package/dist/preact/router.js +2 -0
  53. package/dist/react/data.d.ts +5 -1
  54. package/dist/react/index.d.ts +6 -1
  55. package/dist/react/index.js +2 -1
  56. package/dist/react/outlet.d.ts +16 -0
  57. package/dist/react/outlet.js +26 -0
  58. package/dist/react/resources/components.d.ts +12 -0
  59. package/dist/react/resources/components.js +11 -0
  60. package/dist/server/application.d.ts +3 -0
  61. package/dist/server/application.js +2 -0
  62. package/dist/server/assets.d.ts +2 -0
  63. package/dist/server/assets.js +6 -0
  64. package/dist/server/handler.d.ts +3 -0
  65. package/dist/server/http.d.ts +2 -0
  66. package/dist/server/http.js +2 -0
  67. package/dist/server/node.d.ts +5 -1
  68. package/dist/server/preact.d.ts +5 -1
  69. package/jsr.json +1 -1
  70. package/package.json +6 -5
@@ -1,3 +1,4 @@
1
+ /** Application base URLs, navigation handoff and document-transition settings shared by browser integrations. */
1
2
  export interface ApplicationEnvironment {
2
3
  resolveURL?: (url: URL) => URL;
3
4
  isDocumentHandoff?: (from: URL, to: URL) => boolean;
@@ -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
 
@@ -1,5 +1,8 @@
1
- /** Framework-independent, browser-safe utilities. @module */
2
- export * from "./errors.ts";
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
- /** Browser mounting and hydration for Preact applications. @module */
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
- /** Framework components and typed data hooks. @module */
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 { routes } = useApplication();
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 {
@@ -1,4 +1,8 @@
1
- /** Resource subscriptions independent of URL navigation. @module */
1
+ /**
2
+ * Independent React resource data, forms and subscriptions.
3
+ *
4
+ * @module
5
+ */
2
6
  export type {
3
7
  ActionFunctionArgs as ResourceActionArgs,
4
8
  DataResult as ResourceResult,
@@ -1,4 +1,8 @@
1
- /** Framework components and typed data hooks. @module */
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[],