@kasperrt/smolter 0.2.0 → 0.3.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.
Files changed (264) hide show
  1. package/{src/internal → .generated}/client/index.ts +1 -0
  2. package/.generated/core/environment.ts +43 -0
  3. package/{src/internal → .generated}/core/errors.ts +1 -1
  4. package/{src/internal → .generated}/core/index.ts +1 -0
  5. package/.generated/core/navigation-router.ts +107 -0
  6. package/.generated/core/navigation.ts +147 -0
  7. package/.generated/core/presentation.ts +108 -0
  8. package/.generated/core/resource-types.ts +44 -0
  9. package/.generated/core/resources.ts +444 -0
  10. package/.generated/core/responses.ts +86 -0
  11. package/{src/internal → .generated}/core/router.ts +136 -63
  12. package/{src/internal → .generated}/core/serialize.ts +7 -2
  13. package/.generated/core/store.ts +25 -0
  14. package/.generated/core/submission.ts +116 -0
  15. package/{src/internal → .generated}/core/types.ts +18 -1
  16. package/.generated/core/url.ts +29 -0
  17. package/.generated/core/utils.ts +5 -0
  18. package/.generated/preact/await.tsx +41 -0
  19. package/.generated/preact/client.tsx +93 -0
  20. package/.generated/preact/context.ts +59 -0
  21. package/.generated/preact/document.tsx +198 -0
  22. package/{src/internal → .generated}/preact/fetcher.ts +43 -23
  23. package/.generated/preact/form.ts +58 -0
  24. package/{src/internal → .generated}/preact/hooks.ts +25 -28
  25. package/.generated/preact/index.ts +34 -0
  26. package/.generated/preact/lazy-route.ts +100 -0
  27. package/.generated/preact/navigation-state.ts +9 -0
  28. package/.generated/preact/navigation.tsx +147 -0
  29. package/.generated/preact/root-context.ts +21 -0
  30. package/.generated/preact/root-data.ts +45 -0
  31. package/.generated/preact/route-hooks.tsx +170 -0
  32. package/.generated/preact/route-types.ts +76 -0
  33. package/.generated/preact/router.tsx +107 -0
  34. package/{src/internal → .generated}/preact/routes.ts +17 -9
  35. package/.generated/react/context.ts +59 -0
  36. package/.generated/react/data.ts +25 -0
  37. package/{src/internal → .generated}/react/fetcher.ts +13 -11
  38. package/.generated/react/form.ts +58 -0
  39. package/{src/internal → .generated}/react/hooks.ts +9 -14
  40. package/{src/internal/preact → .generated/react}/index.ts +5 -1
  41. package/{src/internal → .generated}/react/link.ts +13 -21
  42. package/.generated/react/resources/components.tsx +404 -0
  43. package/{src/internal → .generated}/react/routes.ts +17 -9
  44. package/.generated/server/application.tsx +185 -0
  45. package/.generated/server/assets.ts +19 -0
  46. package/.generated/server/handler.ts +69 -0
  47. package/.generated/server/http.ts +55 -0
  48. package/{src/internal → .generated}/server/index.ts +3 -3
  49. package/.generated/server/node.ts +4 -0
  50. package/.generated/server/preact.ts +7 -0
  51. package/.generated/vite/application/browser-boundary.ts +42 -0
  52. package/.generated/vite/application/lazy-files.ts +136 -0
  53. package/.generated/vite/application/vite.ts +144 -0
  54. package/{src/preact-vite.ts → .generated/vite/preact.ts} +9 -3
  55. package/{src/react-vite.ts → .generated/vite/react.ts} +3 -3
  56. package/CHANGELOG.md +54 -0
  57. package/README.md +227 -35
  58. package/dist/client/deserialize.js +10 -0
  59. package/dist/{internal/client → client}/index.d.ts +1 -0
  60. package/dist/client/index.js +46 -0
  61. package/dist/core/environment.d.ts +12 -0
  62. package/dist/core/environment.js +23 -0
  63. package/dist/core/errors.js +7 -0
  64. package/dist/{internal/core → core}/index.d.ts +1 -0
  65. package/dist/core/match.js +33 -0
  66. package/dist/core/navigation-router.d.ts +15 -0
  67. package/dist/core/navigation-router.js +64 -0
  68. package/dist/core/navigation.d.ts +15 -0
  69. package/dist/core/navigation.js +92 -0
  70. package/dist/core/presentation.d.ts +5 -0
  71. package/dist/core/presentation.js +69 -0
  72. package/dist/core/resource-types.d.ts +37 -0
  73. package/dist/core/resources.d.ts +19 -0
  74. package/dist/core/resources.js +345 -0
  75. package/dist/core/responses.d.ts +15 -0
  76. package/dist/core/responses.js +48 -0
  77. package/dist/{internal/core → core}/router.d.ts +1 -1
  78. package/dist/core/router.js +204 -0
  79. package/dist/{internal/core → core}/serialize.d.ts +2 -0
  80. package/dist/core/serialize.js +17 -0
  81. package/dist/core/store.d.ts +6 -0
  82. package/dist/core/store.js +21 -0
  83. package/dist/core/submission.d.ts +30 -0
  84. package/dist/core/submission.js +41 -0
  85. package/dist/{internal/core → core}/types.d.ts +16 -1
  86. package/dist/core/url.d.ts +7 -0
  87. package/dist/core/url.js +12 -0
  88. package/dist/core/utils.d.ts +5 -0
  89. package/dist/core/utils.js +5 -0
  90. package/dist/files/index.js +64 -0
  91. package/dist/preact/await.d.ts +7 -0
  92. package/dist/preact/await.js +19 -0
  93. package/dist/preact/client.d.ts +7 -0
  94. package/dist/preact/client.js +67 -0
  95. package/dist/preact/context.d.ts +18 -0
  96. package/dist/preact/context.js +23 -0
  97. package/dist/preact/document.d.ts +15 -0
  98. package/dist/preact/document.js +155 -0
  99. package/dist/{internal/preact → preact}/fetcher.d.ts +9 -5
  100. package/dist/preact/fetcher.js +45 -0
  101. package/dist/{internal/preact → preact}/form.d.ts +5 -6
  102. package/dist/preact/form.js +21 -0
  103. package/dist/{internal/preact → preact}/hooks.d.ts +7 -6
  104. package/dist/preact/hooks.js +25 -0
  105. package/dist/preact/index.d.ts +18 -0
  106. package/dist/preact/index.js +15 -0
  107. package/dist/preact/lazy-route.d.ts +19 -0
  108. package/dist/preact/lazy-route.js +51 -0
  109. package/dist/preact/navigation-state.d.ts +2 -0
  110. package/dist/preact/navigation-state.js +9 -0
  111. package/dist/preact/navigation.d.ts +28 -0
  112. package/dist/preact/navigation.js +60 -0
  113. package/dist/preact/root-context.d.ts +13 -0
  114. package/dist/preact/root-context.js +9 -0
  115. package/dist/preact/root-data.d.ts +8 -0
  116. package/dist/preact/root-data.js +28 -0
  117. package/dist/preact/route-hooks.d.ts +32 -0
  118. package/dist/preact/route-hooks.js +94 -0
  119. package/dist/preact/route-types.d.ts +54 -0
  120. package/dist/preact/router.d.ts +16 -0
  121. package/dist/preact/router.js +63 -0
  122. package/dist/{internal/preact → preact}/routes.d.ts +1 -1
  123. package/dist/preact/routes.js +12 -0
  124. package/dist/{internal/preact → preact}/runtime.js +1 -1
  125. package/dist/react/context.d.ts +18 -0
  126. package/dist/react/context.js +23 -0
  127. package/dist/react/data.d.ts +5 -0
  128. package/dist/react/data.js +3 -0
  129. package/dist/{internal/react → react}/fetcher.d.ts +2 -2
  130. package/dist/react/fetcher.js +34 -0
  131. package/dist/{internal/react → react}/form.d.ts +5 -6
  132. package/dist/react/form.js +21 -0
  133. package/dist/react/hooks.js +25 -0
  134. package/dist/{internal/react → react}/index.d.ts +1 -1
  135. package/dist/react/index.js +10 -0
  136. package/dist/{internal/react → react}/link.d.ts +2 -2
  137. package/dist/react/link.js +27 -0
  138. package/dist/react/resources/components.d.ts +64 -0
  139. package/dist/react/resources/components.js +239 -0
  140. package/dist/{internal/react → react}/routes.d.ts +1 -1
  141. package/dist/react/routes.js +12 -0
  142. package/dist/react/runtime.js +1 -0
  143. package/dist/server/application.d.ts +4 -0
  144. package/dist/server/application.js +119 -0
  145. package/dist/server/assets.d.ts +5 -0
  146. package/dist/server/assets.js +7 -0
  147. package/dist/server/handler.d.ts +19 -0
  148. package/dist/server/handler.js +22 -0
  149. package/dist/server/http.d.ts +4 -0
  150. package/dist/server/http.js +27 -0
  151. package/dist/server/index.js +76 -0
  152. package/dist/server/node.d.ts +3 -0
  153. package/dist/server/node.js +3 -0
  154. package/dist/server/preact.d.ts +3 -0
  155. package/dist/server/preact.js +4 -0
  156. package/dist/vite/application/browser-boundary.d.ts +3 -0
  157. package/dist/vite/application/browser-boundary.js +35 -0
  158. package/dist/vite/application/lazy-files.d.ts +2 -0
  159. package/dist/vite/application/lazy-files.js +87 -0
  160. package/dist/vite/application/vite.d.ts +9 -0
  161. package/dist/vite/application/vite.js +101 -0
  162. package/dist/vite/index.js +104 -0
  163. package/dist/{preact-vite.d.ts → vite/preact.d.ts} +5 -3
  164. package/dist/vite/preact.js +15 -0
  165. package/dist/{react-vite.d.ts → vite/react.d.ts} +3 -3
  166. package/dist/vite/react.js +14 -0
  167. package/dist/vite/transport.js +35 -0
  168. package/jsr.json +28 -16
  169. package/package.json +116 -36
  170. package/dist/client.d.ts +0 -2
  171. package/dist/client.js +0 -2
  172. package/dist/core.d.ts +0 -2
  173. package/dist/core.js +0 -2
  174. package/dist/files.d.ts +0 -2
  175. package/dist/files.js +0 -2
  176. package/dist/internal/client/deserialize.js +0 -11
  177. package/dist/internal/client/index.js +0 -44
  178. package/dist/internal/core/errors.js +0 -6
  179. package/dist/internal/core/index.js +0 -7
  180. package/dist/internal/core/match.js +0 -27
  181. package/dist/internal/core/router.js +0 -189
  182. package/dist/internal/core/serialize.js +0 -13
  183. package/dist/internal/core/types.js +0 -5
  184. package/dist/internal/core/url.d.ts +0 -2
  185. package/dist/internal/core/url.js +0 -6
  186. package/dist/internal/files/index.js +0 -77
  187. package/dist/internal/preact/context.d.ts +0 -18
  188. package/dist/internal/preact/context.js +0 -20
  189. package/dist/internal/preact/fetcher.js +0 -28
  190. package/dist/internal/preact/form.js +0 -41
  191. package/dist/internal/preact/hooks.js +0 -35
  192. package/dist/internal/preact/index.d.ts +0 -9
  193. package/dist/internal/preact/index.js +0 -7
  194. package/dist/internal/preact/link.d.ts +0 -12
  195. package/dist/internal/preact/link.js +0 -28
  196. package/dist/internal/preact/routes.js +0 -22
  197. package/dist/internal/react/context.d.ts +0 -18
  198. package/dist/internal/react/context.js +0 -20
  199. package/dist/internal/react/fetcher.js +0 -28
  200. package/dist/internal/react/form.js +0 -41
  201. package/dist/internal/react/hooks.js +0 -35
  202. package/dist/internal/react/index.js +0 -7
  203. package/dist/internal/react/link.js +0 -28
  204. package/dist/internal/react/routes.js +0 -22
  205. package/dist/internal/react/runtime.js +0 -2
  206. package/dist/internal/server/index.js +0 -69
  207. package/dist/internal/vite/index.js +0 -132
  208. package/dist/internal/vite/transport.js +0 -42
  209. package/dist/preact-client.d.ts +0 -2
  210. package/dist/preact-client.js +0 -2
  211. package/dist/preact-server.d.ts +0 -2
  212. package/dist/preact-server.js +0 -2
  213. package/dist/preact-vite.js +0 -9
  214. package/dist/preact.d.ts +0 -2
  215. package/dist/preact.js +0 -2
  216. package/dist/react-client.d.ts +0 -2
  217. package/dist/react-client.js +0 -2
  218. package/dist/react-server.d.ts +0 -2
  219. package/dist/react-server.js +0 -2
  220. package/dist/react-vite.js +0 -9
  221. package/dist/react.d.ts +0 -2
  222. package/dist/react.js +0 -2
  223. package/dist/server.d.ts +0 -2
  224. package/dist/server.js +0 -2
  225. package/dist/utils.d.ts +0 -5
  226. package/dist/utils.js +0 -5
  227. package/dist/vite.d.ts +0 -2
  228. package/dist/vite.js +0 -2
  229. package/src/client.ts +0 -2
  230. package/src/core.ts +0 -2
  231. package/src/files.ts +0 -2
  232. package/src/internal/core/url.ts +0 -6
  233. package/src/internal/preact/context.ts +0 -46
  234. package/src/internal/preact/form.ts +0 -79
  235. package/src/internal/preact/link.ts +0 -46
  236. package/src/internal/react/context.ts +0 -46
  237. package/src/internal/react/form.ts +0 -79
  238. package/src/internal/react/index.ts +0 -13
  239. package/src/preact-client.ts +0 -2
  240. package/src/preact-server.ts +0 -2
  241. package/src/preact.ts +0 -2
  242. package/src/react-client.ts +0 -2
  243. package/src/react-server.ts +0 -2
  244. package/src/react.ts +0 -2
  245. package/src/server.ts +0 -2
  246. package/src/utils.ts +0 -5
  247. package/src/vite.ts +0 -2
  248. /package/{src/internal → .generated}/client/deserialize.ts +0 -0
  249. /package/{src/internal → .generated}/core/match.ts +0 -0
  250. /package/{src/internal → .generated}/files/index.ts +0 -0
  251. /package/{src/internal → .generated}/preact/runtime.ts +0 -0
  252. /package/{src/internal → .generated}/react/runtime.ts +0 -0
  253. /package/{src/internal → .generated}/vite/index.ts +0 -0
  254. /package/{src/internal → .generated}/vite/transport.ts +0 -0
  255. /package/dist/{internal/client → client}/deserialize.d.ts +0 -0
  256. /package/dist/{internal/core → core}/errors.d.ts +0 -0
  257. /package/dist/{internal/core → core}/match.d.ts +0 -0
  258. /package/dist/{internal/files → files}/index.d.ts +0 -0
  259. /package/dist/{internal/preact → preact}/runtime.d.ts +0 -0
  260. /package/dist/{internal/react → react}/hooks.d.ts +0 -0
  261. /package/dist/{internal/react → react}/runtime.d.ts +0 -0
  262. /package/dist/{internal/server → server}/index.d.ts +0 -0
  263. /package/dist/{internal/vite → vite}/index.d.ts +0 -0
  264. /package/dist/{internal/vite → vite}/transport.d.ts +0 -0
@@ -0,0 +1,94 @@
1
+ import { submissionBody, submissionSearch } from "../core/submission.js";
2
+ import { useContext, useMemo } from "./runtime.js";
3
+ import { useRouter, useSnapshot } from "./context.js";
4
+ import { pendingLocation } from "../core/presentation.js";
5
+ import { useNavigationSnapshot } from "./navigation-state.js";
6
+ import { OutletContext, useApplication } from "./root-context.js";
7
+ import { useCallback } from "preact/hooks";
8
+ //#region .generated/preact/route-hooks.tsx
9
+ function useRootData() {
10
+ return useApplication().root;
11
+ }
12
+ /** Read root data or the active route's data by its manifest identifier. */
13
+ function useRouteLoaderData(id) {
14
+ const app = useApplication();
15
+ const snapshot = useSnapshot();
16
+ if (id === "root") return app.root;
17
+ const route = app.routes.find((item) => item.id === id);
18
+ if (!route || route.path !== snapshot.path) return void 0;
19
+ return snapshot.data;
20
+ }
21
+ function useRouteError() {
22
+ return useSnapshot("error");
23
+ }
24
+ function useNavigation() {
25
+ const router = useRouter();
26
+ const snapshot = useSnapshot();
27
+ const location = pendingLocation(router);
28
+ return useMemo(() => ({
29
+ state: snapshot.state,
30
+ location
31
+ }), [snapshot.state, location?.href]);
32
+ }
33
+ function useMatches() {
34
+ const { routes } = useApplication();
35
+ const snapshot = useSnapshot();
36
+ return [{
37
+ id: routes.find((item) => item.path === snapshot.path)?.id ?? "",
38
+ data: snapshot.data,
39
+ params: snapshot.params
40
+ }];
41
+ }
42
+ function useOutletContext() {
43
+ return useContext(OutletContext);
44
+ }
45
+ function useSubmit() {
46
+ const router = useRouter();
47
+ return useCallback((value, options = {}) => {
48
+ const body = submissionBody(value, options.encType);
49
+ const method = options.method?.toUpperCase();
50
+ const target = options.action ?? router.getSnapshot().url;
51
+ if (method === "GET") {
52
+ const url = new URL(target, router.getSnapshot().url);
53
+ url.search = submissionSearch(body);
54
+ return router.navigate(url.href, options);
55
+ }
56
+ return router.submit(target, body, { method });
57
+ }, [router]);
58
+ }
59
+ function useURLLocation() {
60
+ const href = useSnapshot("url");
61
+ const snapshot = useNavigationSnapshot(useRouter());
62
+ return useMemo(() => Object.assign(new URL(href), {
63
+ state: snapshot.state,
64
+ key: snapshot.key
65
+ }), [
66
+ href,
67
+ snapshot.state,
68
+ snapshot.key
69
+ ]);
70
+ }
71
+ function useNavigate() {
72
+ const router = useRouter();
73
+ return useCallback((to, options) => {
74
+ if (typeof to === "number") {
75
+ window.history.go(to);
76
+ return;
77
+ }
78
+ const current = new URL(router.getSnapshot().url);
79
+ const target = typeof to === "string" ? to : `${to.pathname ?? current.pathname}${to.search ?? current.search}${to.hash ?? current.hash}`;
80
+ router.navigate(target, options);
81
+ }, [router]);
82
+ }
83
+ function useSearchParams() {
84
+ const location = useURLLocation();
85
+ const navigate = useNavigate();
86
+ return [useMemo(() => new URLSearchParams(location.search), [location.search]), useCallback((value, options) => {
87
+ navigate(`${location.pathname}?${new URLSearchParams(value)}`, options);
88
+ }, [location.pathname, navigate])];
89
+ }
90
+ function useNavigationType() {
91
+ return useNavigationSnapshot(useRouter()).type;
92
+ }
93
+ //#endregion
94
+ export { useMatches, useNavigate, useNavigation, useNavigationType, useOutletContext, useRootData, useRouteError, useRouteLoaderData, useSearchParams, useSnapshot, useSubmit, useURLLocation };
@@ -0,0 +1,54 @@
1
+ import type { DataArgs, RevalidationArgs, Route, Snapshot } from "../core/index.ts";
2
+ import type { DataResponse } from "../core/responses.ts";
3
+ import type { ComponentType, ReactNode } from "preact/compat";
4
+ export interface LoaderFunctionArgs extends DataArgs {
5
+ context?: unknown;
6
+ }
7
+ export type ActionFunctionArgs = LoaderFunctionArgs;
8
+ export interface ClientLoaderFunctionArgs extends LoaderFunctionArgs {
9
+ serverLoader: <T = unknown>() => Promise<T>;
10
+ }
11
+ export interface ClientActionFunctionArgs extends LoaderFunctionArgs {
12
+ serverAction: <T = unknown>() => Promise<T>;
13
+ }
14
+ export type ShouldRevalidateFunctionArgs = RevalidationArgs;
15
+ type UnwrapData<T> = T extends DataResponse<infer V> ? V : T;
16
+ export type RouteData<T> = T extends (...args: never[]) => infer R ? UnwrapData<Exclude<Awaited<R>, Response | Error>> : T;
17
+ export type MetaDescriptor = Record<string, unknown>;
18
+ export interface MetaArgs<T> {
19
+ data: RouteData<T> | undefined;
20
+ loaderData: RouteData<T> | undefined;
21
+ error?: unknown;
22
+ params: Record<string, string>;
23
+ location: URL;
24
+ }
25
+ export type MetaFunction<T = unknown> = (args: MetaArgs<T>) => MetaDescriptor[];
26
+ export type LinksFunction = () => Record<string, string>[];
27
+ export interface AppRoute extends Route {
28
+ resolveComponent?: () => ComponentType | undefined;
29
+ preload?: () => Promise<void>;
30
+ id?: string;
31
+ routePath?: string;
32
+ meta?: MetaFunction;
33
+ }
34
+ export interface RootModule {
35
+ /** Route identity used by targeted revalidation. Defaults to root. */
36
+ id?: string;
37
+ /** Optional registered route URL used to revalidate root data after mutations. */
38
+ loaderPath?: string;
39
+ ErrorBoundary?: ComponentType;
40
+ default: ComponentType;
41
+ Layout: ComponentType<{
42
+ children: ReactNode;
43
+ }>;
44
+ loader?: (args: LoaderFunctionArgs) => unknown;
45
+ links?: LinksFunction;
46
+ meta?: MetaFunction;
47
+ shouldRevalidate?: (args: RevalidationArgs) => boolean;
48
+ }
49
+ export interface Hydration {
50
+ root: unknown;
51
+ snapshot: Snapshot;
52
+ }
53
+ export type HandleDataRequestFunction = (response: Response, args: LoaderFunctionArgs) => Response | Promise<Response>;
54
+ export {};
@@ -0,0 +1,16 @@
1
+ /** @jsxImportSource preact */
2
+ import type { ReactNode } from "preact/compat";
3
+ import { type ApplicationContext } from "./root-context.ts";
4
+ import { createRootStore } from "./root-data.ts";
5
+ import type { AppRoute } from "./route-types.ts";
6
+ export interface OutletProps {
7
+ context?: unknown;
8
+ children?: ReactNode;
9
+ }
10
+ export declare function Outlet({ context, children, }: OutletProps): import("preact").JSX.Element;
11
+ export interface ApplicationProps extends ApplicationContext {
12
+ document?: boolean;
13
+ rootStore?: ReturnType<typeof createRootStore>;
14
+ }
15
+ export declare function RouterApplication(props: ApplicationProps): import("preact").JSX.Element;
16
+ export declare function prepareRoutes(routes: AppRoute[]): AppRoute[];
@@ -0,0 +1,63 @@
1
+ import { normalizeResult } from "../core/responses.js";
2
+ import { useContext, useMemo, useSyncExternalStore } from "./runtime.js";
3
+ import { RouterProvider } from "./context.js";
4
+ import { createStore } from "../core/store.js";
5
+ import { Application, OutletContext } from "./root-context.js";
6
+ import { Routes } from "./routes.js";
7
+ import { jsx } from "preact/jsx-runtime";
8
+ //#region .generated/preact/router.tsx
9
+ function Outlet({ context, children }) {
10
+ const current = useContext(OutletContext);
11
+ return /* @__PURE__ */ jsx(OutletContext, {
12
+ value: context ?? current,
13
+ children: children ?? /* @__PURE__ */ jsx(Routes, { fallback: /* @__PURE__ */ jsx("p", {
14
+ role: "status",
15
+ children: "Loading…"
16
+ }) })
17
+ });
18
+ }
19
+ function RouterApplication(props) {
20
+ const rootStore = useMemo(() => props.rootStore ?? createStore(props.root), [props.rootStore, props.root]);
21
+ const root = useSyncExternalStore(rootStore.subscribe, rootStore.getSnapshot);
22
+ const snapshot = useSyncExternalStore(props.router.subscribe, props.router.getSnapshot);
23
+ const route = props.routes.find((item) => item.path === snapshot.path);
24
+ const Root = snapshot.error && !route?.ErrorBoundary ? props.rootModule?.ErrorBoundary ?? Outlet : props.rootModule?.default ?? Outlet;
25
+ const Layout = props.rootModule?.Layout;
26
+ const children = /* @__PURE__ */ jsx(Root, {});
27
+ return /* @__PURE__ */ jsx(RouterProvider, {
28
+ router: props.router,
29
+ children: /* @__PURE__ */ jsx(Application, {
30
+ value: {
31
+ ...props,
32
+ root
33
+ },
34
+ children: props.document ? Layout && /* @__PURE__ */ jsx(Layout, { children }) : children
35
+ })
36
+ });
37
+ }
38
+ function prepareRoutes(routes) {
39
+ return routes.map((route) => {
40
+ const wrapped = {
41
+ ...route,
42
+ path: route.routePath ?? route.path,
43
+ shouldRevalidate: (args) => {
44
+ const { currentUrl, nextUrl } = args;
45
+ if (args.reason === "navigation" && currentUrl.pathname === nextUrl.pathname && currentUrl.search === nextUrl.search && currentUrl.hash !== nextUrl.hash) return false;
46
+ return route.shouldRevalidate?.(args) ?? args.defaultShouldRevalidate;
47
+ }
48
+ };
49
+ for (const key of [
50
+ "loader",
51
+ "action",
52
+ "clientLoader",
53
+ "clientAction"
54
+ ]) {
55
+ const handler = route[key];
56
+ if (!handler) continue;
57
+ wrapped[key] = (args) => Promise.resolve().then(() => handler(args)).then(normalizeResult, normalizeResult);
58
+ }
59
+ return wrapped;
60
+ });
61
+ }
62
+ //#endregion
63
+ export { Outlet, RouterApplication, prepareRoutes };
@@ -3,7 +3,7 @@
3
3
  * @module
4
4
  */
5
5
  import type { RouteModule } from "../core/index.ts";
6
- import type { ComponentType, ReactNode } from "./runtime.ts";
6
+ import { type ComponentType, type ReactNode } from "./runtime.ts";
7
7
  /** Renderable route module with optional loading and error components. */
8
8
  export interface ViewModule extends RouteModule {
9
9
  default?: ComponentType;
@@ -0,0 +1,12 @@
1
+ import { createElement, useMemo } from "./runtime.js";
2
+ import { useRouter, useSnapshot } from "./context.js";
3
+ //#region .generated/preact/routes.ts
4
+ /** Renders the first matching registered module. */
5
+ function Routes({ fallback }) {
6
+ const router = useRouter();
7
+ const state = useSnapshot();
8
+ const component = router.routes.find((route) => route.path === state.path)?.[state.error ? "ErrorBoundary" : state.state === "loading" && !state.loaded ? "HydrateFallback" : "default"];
9
+ return useMemo(() => component && createElement(component, { error: state.error }), [component, state.error]) ?? state.error?.message ?? fallback;
10
+ }
11
+ //#endregion
12
+ export { Routes };
@@ -1 +1 @@
1
- export { createContext, createElement, useContext, useEffect, useMemo, useSyncExternalStore, } from "preact/compat";
1
+ export { createContext, createElement, useContext, useEffect, useMemo, useSyncExternalStore } from "preact/compat";
@@ -0,0 +1,18 @@
1
+ /**
2
+ * React components and typed data hooks. Import from @kasperrt/smolter/react.
3
+ * @module
4
+ */
5
+ import type { NavigationRouter, Snapshot } from "../core/index.ts";
6
+ import { type ReactNode } from "./runtime.ts";
7
+ /** Router instance and children rendered within its context. */
8
+ export interface RouterProviderProps {
9
+ router: NavigationRouter;
10
+ children?: ReactNode;
11
+ }
12
+ /** Provide a router to descendant hooks and connect its browser lifecycle. */
13
+ export declare function RouterProvider({ router, children, }: RouterProviderProps): ReactNode;
14
+ /** Hooks require a RouterProvider. */
15
+ export declare function useRouter<T extends NavigationRouter = NavigationRouter>(): T;
16
+ export declare function useSnapshot(): Snapshot;
17
+ export declare function useSnapshot<K extends keyof Snapshot>(key: K): Snapshot[K];
18
+ export declare function useSnapshot<K extends keyof Snapshot>(key: K, path: string | undefined): Snapshot[K] | undefined;
@@ -0,0 +1,23 @@
1
+ import { createContext, createElement, useContext, useEffect, useSyncExternalStore } from "./runtime.js";
2
+ //#region .generated/react/context.ts
3
+ var RouterContext = createContext(void 0);
4
+ /** Provide a router to descendant hooks and connect its browser lifecycle. */
5
+ function RouterProvider({ router, children }) {
6
+ useEffect(router.start, [router]);
7
+ return createElement(RouterContext.Provider, { value: router }, children);
8
+ }
9
+ /** Hooks require a RouterProvider. */
10
+ function useRouter() {
11
+ return useContext(RouterContext);
12
+ }
13
+ function useSnapshot(key, path) {
14
+ const router = useRouter();
15
+ const getSnapshot = () => {
16
+ const snapshot = router.getSnapshot();
17
+ if (path !== void 0 && path !== snapshot.path) return void 0;
18
+ return key ? snapshot[key] : snapshot;
19
+ };
20
+ return useSyncExternalStore(router.subscribe, getSnapshot, getSnapshot);
21
+ }
22
+ //#endregion
23
+ export { RouterProvider, useRouter, useSnapshot };
@@ -0,0 +1,5 @@
1
+ /** Resource subscriptions independent of URL navigation. @module */
2
+ export type { ActionFunctionArgs as ResourceActionArgs, DataResult as ResourceResult, LoaderFunctionArgs as ResourceLoaderArgs, ShouldRevalidateFunctionArgs as ResourceRevalidationArgs, } from "../core/resource-types.ts";
3
+ export { createResourceRouter, ResourceRouter, } from "../core/resources.ts";
4
+ export type { ResourceRouteModule } from "./resources/components.tsx";
5
+ export { Form as ResourceForm, Route as Resource, RouterProvider as ResourceProvider, useActionData as useResourceActionData, useFetcher as useResourceFetcher, useLoaderData as useResourceData, useNavigation as useResourceNavigation, useRevalidator as useResourceRevalidator, useRouteLoaderData, useRouter as useResourceRouter, useSubmit as useResourceSubmit, } from "./resources/components.tsx";
@@ -0,0 +1,3 @@
1
+ import { ResourceRouter, createResourceRouter } from "../core/resources.js";
2
+ import { Form, Route, RouterProvider, useActionData, useFetcher, useLoaderData, useNavigation, useRevalidator, useRouteLoaderData, useRouter, useSubmit } from "./resources/components.js";
3
+ export { Route as Resource, Form as ResourceForm, RouterProvider as ResourceProvider, ResourceRouter, createResourceRouter, useActionData as useResourceActionData, useLoaderData as useResourceData, useFetcher as useResourceFetcher, useNavigation as useResourceNavigation, useRevalidator as useResourceRevalidator, useRouter as useResourceRouter, useSubmit as useResourceSubmit, useRouteLoaderData };
@@ -2,9 +2,9 @@
2
2
  * React components and typed data hooks. Import from @kasperrt/smolter/react.
3
3
  * @module
4
4
  */
5
- import type { AnyDataFunction, DataFunction, DataOf, FetcherSnapshot, Result, Route as RouteDefinition, RouteModule, SubmitOptions } from "../core/index.ts";
5
+ import { type AnyDataFunction, type DataFunction, type DataOf, type FetcherSnapshot, type Result, type Route as RouteDefinition, type RouteModule, type SubmitOptions } from "../core/index.ts";
6
6
  import { type FormProps } from "./form.ts";
7
- import type { ComponentType } from "./runtime.ts";
7
+ import { type ComponentType } from "./runtime.ts";
8
8
  /** Action method and optional explicit route URL for a fetcher submission. */
9
9
  export interface FetcherSubmitOptions extends SubmitOptions {
10
10
  action?: string;
@@ -0,0 +1,34 @@
1
+ import { createElement, useEffect, useMemo, useSyncExternalStore } from "./runtime.js";
2
+ import { useRouter } from "./context.js";
3
+ import { Form } from "./form.js";
4
+ //#region .generated/react/fetcher.ts
5
+ /** Create a fetcher for independent route reads and mutations; its data stays local. */
6
+ function useFetcher(route) {
7
+ const router = useRouter();
8
+ const path = route?.path;
9
+ const fetcher = useMemo(() => {
10
+ const store = router.createFetcher();
11
+ const target = () => {
12
+ const snapshot = router.getSnapshot();
13
+ return path === void 0 || path === snapshot.path ? snapshot.url : path;
14
+ };
15
+ return {
16
+ ...store,
17
+ Form: (props) => createElement(Form, {
18
+ action: target(),
19
+ ...props,
20
+ fetcher: store
21
+ }),
22
+ load: (url) => store.load(url ?? target()),
23
+ submit: (body, options) => store.submit(options?.action ?? target(), body, options)
24
+ };
25
+ }, [router, path]);
26
+ useEffect(() => fetcher.dispose, [fetcher]);
27
+ const state = useSyncExternalStore(fetcher.subscribe, fetcher.getSnapshot, fetcher.getSnapshot);
28
+ return {
29
+ ...fetcher,
30
+ ...state
31
+ };
32
+ }
33
+ //#endregion
34
+ export { useFetcher };
@@ -2,16 +2,15 @@
2
2
  * React components and typed data hooks. Import from @kasperrt/smolter/react.
3
3
  * @module
4
4
  */
5
- import type { Fetcher } from "../core/index.ts";
6
- import type { FormHTMLAttributes, ReactNode } from "./runtime.ts";
5
+ import { type Fetcher } from "../core/index.ts";
6
+ import { type RouteFormOptions } from "../core/submission.ts";
7
+ import { type FormHTMLAttributes, type ReactNode } from "./runtime.ts";
7
8
  /** Form attributes with GET loader requests or POST, PUT, PATCH, and DELETE actions. */
8
- export interface FormProps extends Omit<FormHTMLAttributes<HTMLFormElement>, "action" | "method"> {
9
- action?: string;
10
- method?: "get" | "post" | "put" | "patch" | "delete";
9
+ export interface FormProps extends Omit<FormHTMLAttributes<HTMLFormElement>, "action" | "method">, RouteFormOptions {
11
10
  }
12
11
  interface InternalFormProps extends FormProps {
13
12
  fetcher?: Fetcher;
14
13
  }
15
14
  /** Submit form data to a registered route without a document reload. */
16
- export declare function Form({ action, method, fetcher, onSubmit, ...props }: InternalFormProps): ReactNode;
15
+ export declare function Form(options: InternalFormProps): ReactNode;
17
16
  export {};
@@ -0,0 +1,21 @@
1
+ import { createElement } from "./runtime.js";
2
+ import { useRouter } from "./context.js";
3
+ import { submitForm } from "../core/submission.js";
4
+ //#region .generated/react/form.ts
5
+ /** Submit form data to a registered route without a document reload. */
6
+ function Form(options) {
7
+ const { action, method, fetcher, onSubmit, reloadDocument, preventScrollReset, replace, ...props } = options;
8
+ const router = useRouter();
9
+ const submit = (event) => {
10
+ onSubmit?.(event);
11
+ submitForm(router, event, event.nativeEvent.submitter, options, fetcher);
12
+ };
13
+ return createElement("form", {
14
+ ...props,
15
+ action,
16
+ method: method === "get" ? "get" : "post",
17
+ onSubmit: submit
18
+ });
19
+ }
20
+ //#endregion
21
+ export { Form };
@@ -0,0 +1,25 @@
1
+ import { useRouter, useSnapshot } from "./context.js";
2
+ //#region .generated/react/hooks.ts
3
+ /** Pass a route for inference, or use useLoaderData<typeof loader>() in its module. */
4
+ function useLoaderData(route) {
5
+ return useSnapshot("data", route?.path);
6
+ }
7
+ /** Read the last page action result, optionally inferring its type from a route. */
8
+ function useActionData(route) {
9
+ return useSnapshot("actionData", route?.path);
10
+ }
11
+ /** Read path parameters for the active route. */
12
+ function useParams() {
13
+ return useSnapshot("params");
14
+ }
15
+ /** Read the current path, search, and hash together with the navigate function. */
16
+ function useLocation() {
17
+ const router = useRouter();
18
+ return [useSnapshot("url").replace(/^\w+:\/\/[^/]+/, ""), router.navigate];
19
+ }
20
+ /** Get the function that revalidates the current loader subject to shouldRevalidate. */
21
+ function useRevalidator() {
22
+ return useRouter().revalidate;
23
+ }
24
+ //#endregion
25
+ export { useActionData, useLoaderData, useLocation, useParams, useRevalidator };
@@ -1,6 +1,6 @@
1
1
  /** Framework components and typed data hooks. @module */
2
2
  export type * from "../core/index.ts";
3
- export { createRouter, defineRoute } from "../core/index.ts";
3
+ export { createDataRouter, createRouter, defineRoute, } from "../core/index.ts";
4
4
  export { RouterProvider, type RouterProviderProps, useRouter, } from "./context.ts";
5
5
  export * from "./fetcher.ts";
6
6
  export * from "./form.ts";
@@ -0,0 +1,10 @@
1
+ import { defineRoute } from "../core/match.js";
2
+ import { createRouter } from "../core/navigation-router.js";
3
+ import { createDataRouter } from "../core/router.js";
4
+ import { RouterProvider, useRouter } from "./context.js";
5
+ import { Form } from "./form.js";
6
+ import { useFetcher } from "./fetcher.js";
7
+ import { useActionData, useLoaderData, useLocation, useParams, useRevalidator } from "./hooks.js";
8
+ import { Link } from "./link.js";
9
+ import { Routes } from "./routes.js";
10
+ export { Form, Link, RouterProvider, Routes, createDataRouter, createRouter, defineRoute, useActionData, useFetcher, useLoaderData, useLocation, useParams, useRevalidator, useRouter };
@@ -2,11 +2,11 @@
2
2
  * React components and typed data hooks. Import from @kasperrt/smolter/react.
3
3
  * @module
4
4
  */
5
- import type { AnchorHTMLAttributes, ReactNode } from "./runtime.ts";
5
+ import { type AnchorHTMLAttributes, type ReactNode } from "./runtime.ts";
6
6
  /** Anchor attributes with internal navigation and optional history replacement. */
7
7
  export interface LinkProps extends AnchorHTMLAttributes<HTMLAnchorElement> {
8
8
  href: string;
9
9
  replace?: boolean;
10
10
  }
11
11
  /** Render an anchor that handles internal navigation and preserves native modified clicks. */
12
- export declare function Link({ href, replace, onClick, ...props }: LinkProps): ReactNode;
12
+ export declare function Link(options: LinkProps): ReactNode;
@@ -0,0 +1,27 @@
1
+ import { internalURL, navigationClick } from "../core/url.js";
2
+ import { createElement } from "./runtime.js";
3
+ import { useRouter } from "./context.js";
4
+ //#region .generated/react/link.ts
5
+ /**
6
+ * React components and typed data hooks. Import from @kasperrt/smolter/react.
7
+ * @module
8
+ */
9
+ /** Render an anchor that handles internal navigation and preserves native modified clicks. */
10
+ function Link(options) {
11
+ const { href, replace, onClick, ...props } = options;
12
+ const router = useRouter();
13
+ const click = (event) => {
14
+ onClick?.(event);
15
+ if (!navigationClick(event, event.currentTarget)) return;
16
+ if (!internalURL(router.getSnapshot().url, href)) return;
17
+ event.preventDefault();
18
+ router.navigate(href, options);
19
+ };
20
+ return createElement("a", {
21
+ ...props,
22
+ href,
23
+ onClick: click
24
+ });
25
+ }
26
+ //#endregion
27
+ export { Link };
@@ -0,0 +1,64 @@
1
+ /** @jsxImportSource react */
2
+ import type { DataResult, NavigationState, Params, ResourceModule, RouteState } from "../../core/resource-types.ts";
3
+ import type { ResourceRouter } from "../../core/resources.ts";
4
+ import { type ComponentType, type PropsWithChildren } from "react";
5
+ export interface ResourceRouteModule extends ResourceModule {
6
+ default?: ComponentType;
7
+ ErrorBoundary?: ComponentType<{
8
+ retry: () => void;
9
+ }>;
10
+ HydrateFallback?: ComponentType;
11
+ }
12
+ interface RouterProviderProps extends PropsWithChildren {
13
+ initialMatches?: readonly {
14
+ params?: Params;
15
+ routeId: string;
16
+ }[];
17
+ router: ResourceRouter;
18
+ }
19
+ export declare function RouterProvider({ children, initialMatches, router, }: RouterProviderProps): import("react").JSX.Element;
20
+ interface RouteProps extends PropsWithChildren {
21
+ params?: Params;
22
+ persistent?: boolean;
23
+ routeId: string;
24
+ }
25
+ export declare function Route({ children, params, persistent, routeId, }: RouteProps): import("react").JSX.Element;
26
+ export declare function useLoaderData<Data>(): Data | null;
27
+ export declare function useRouteLoaderData<Data>(routeId: string, params?: Params): Data | null;
28
+ export declare function useActionData<Data>(): Data | null;
29
+ export declare function useNavigation(): {
30
+ state: NavigationState;
31
+ };
32
+ export declare function useRevalidator(): {
33
+ revalidate: () => Promise<DataResult<unknown>>;
34
+ state: string;
35
+ };
36
+ interface FetcherOptions {
37
+ params?: Params;
38
+ routeId?: string;
39
+ }
40
+ interface FetcherTarget {
41
+ params?: Params;
42
+ routeId?: string;
43
+ }
44
+ interface FormProps extends PropsWithChildren {
45
+ action?: string;
46
+ input?: unknown;
47
+ params?: Params;
48
+ }
49
+ export declare function Form({ action, children, input, params, }: FormProps): import("react").JSX.Element;
50
+ export declare function useSubmit(): (input?: unknown) => Promise<DataResult<unknown>>;
51
+ export declare function useFetcher<Data = unknown>(options?: FetcherOptions): readonly [
52
+ {
53
+ data: Data | null;
54
+ error: string;
55
+ state: NavigationState;
56
+ },
57
+ {
58
+ Form: ({ children, input, }: Pick<FormProps, "children" | "input">) => import("react").JSX.Element;
59
+ load: (target?: FetcherTarget) => Promise<DataResult<Data>>;
60
+ submit: (input: unknown, target?: FetcherTarget) => Promise<DataResult<Data>>;
61
+ }
62
+ ];
63
+ export declare function useRouter(): ResourceRouter;
64
+ export type { NavigationState, RouteState };