vorma 0.0.0-pre.0 → 0.83.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 (225) hide show
  1. package/LICENSE +28 -0
  2. package/README.md +48 -0
  3. package/internal/framework/_typescript/client/index.ts +64 -0
  4. package/internal/framework/_typescript/client/src/asset_manager.ts +67 -0
  5. package/internal/framework/_typescript/client/src/client.ts +1201 -0
  6. package/internal/framework/_typescript/client/src/client_loaders.ts +249 -0
  7. package/internal/framework/_typescript/client/src/component_loader.ts +105 -0
  8. package/internal/framework/_typescript/client/src/error_boundary.ts +7 -0
  9. package/internal/framework/_typescript/client/src/events.ts +54 -0
  10. package/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.ts +125 -0
  11. package/internal/framework/_typescript/client/src/hard_reload.ts +1 -0
  12. package/internal/framework/_typescript/client/src/head_elements/head_elements.ts +193 -0
  13. package/internal/framework/_typescript/client/src/history/history.ts +118 -0
  14. package/internal/framework/_typescript/client/src/history/npm_history_types.ts +83 -0
  15. package/internal/framework/_typescript/client/src/hmr/hmr.ts +71 -0
  16. package/internal/framework/_typescript/client/src/init_client.ts +134 -0
  17. package/internal/framework/_typescript/client/src/links.ts +218 -0
  18. package/internal/framework/_typescript/client/src/redirects/redirects.ts +203 -0
  19. package/internal/framework/_typescript/client/src/rendering.ts +135 -0
  20. package/internal/framework/_typescript/client/src/resolve_public_href.ts +15 -0
  21. package/internal/framework/_typescript/client/src/scroll_state_manager.ts +100 -0
  22. package/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.ts +22 -0
  23. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.ts +131 -0
  24. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.ts +56 -0
  25. package/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.ts +58 -0
  26. package/internal/framework/_typescript/client/src/utils/errors.ts +10 -0
  27. package/internal/framework/_typescript/client/src/utils/logging.ts +7 -0
  28. package/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.ts +290 -0
  29. package/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.ts +128 -0
  30. package/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.ts +32 -0
  31. package/internal/framework/_typescript/client/tsconfig.json +3 -0
  32. package/internal/framework/_typescript/create/main.ts +378 -0
  33. package/internal/framework/_typescript/create/package.json +33 -0
  34. package/internal/framework/_typescript/create/pnpm-lock.yaml +70 -0
  35. package/internal/framework/_typescript/create/tsconfig.json +3 -0
  36. package/internal/framework/_typescript/preact/index.tsx +10 -0
  37. package/internal/framework/_typescript/preact/src/helpers.ts +113 -0
  38. package/internal/framework/_typescript/preact/src/link.tsx +107 -0
  39. package/internal/framework/_typescript/preact/src/preact.tsx +191 -0
  40. package/internal/framework/_typescript/preact/tsconfig.json +7 -0
  41. package/internal/framework/_typescript/react/index.tsx +10 -0
  42. package/internal/framework/_typescript/react/src/helpers.ts +118 -0
  43. package/internal/framework/_typescript/react/src/link.tsx +115 -0
  44. package/internal/framework/_typescript/react/src/react.tsx +299 -0
  45. package/internal/framework/_typescript/react/tsconfig.json +6 -0
  46. package/internal/framework/_typescript/solid/index.tsx +10 -0
  47. package/internal/framework/_typescript/solid/src/helpers.ts +114 -0
  48. package/internal/framework/_typescript/solid/src/link.tsx +104 -0
  49. package/internal/framework/_typescript/solid/src/solid.tsx +204 -0
  50. package/internal/framework/_typescript/solid/tsconfig.json +7 -0
  51. package/internal/framework/_typescript/vite/tsconfig.json +3 -0
  52. package/internal/framework/_typescript/vite/vite.ts +93 -0
  53. package/internal/site/frontend/assets/vorma-banner.webp +0 -0
  54. package/kit/_typescript/converters/converters.ts +152 -0
  55. package/kit/_typescript/cookies/cookies.ts +18 -0
  56. package/kit/_typescript/csrf/csrf.ts +10 -0
  57. package/kit/_typescript/debounce/debounce.ts +17 -0
  58. package/kit/_typescript/fmt/fmt.ts +3 -0
  59. package/kit/_typescript/json/deep_equals.ts +54 -0
  60. package/kit/_typescript/json/json.ts +3 -0
  61. package/kit/_typescript/json/search_param_serializer.ts +49 -0
  62. package/kit/_typescript/json/stringify_stable.ts +43 -0
  63. package/kit/_typescript/listeners/listeners.ts +16 -0
  64. package/kit/_typescript/matcher/find_best_match.ts +205 -0
  65. package/kit/_typescript/matcher/find_nested_matches.ts +357 -0
  66. package/kit/_typescript/matcher/parse_segments.ts +30 -0
  67. package/kit/_typescript/matcher/register.ts +271 -0
  68. package/kit/_typescript/theme/theme.ts +177 -0
  69. package/kit/_typescript/tsconfig.json +3 -0
  70. package/kit/_typescript/url/url.ts +132 -0
  71. package/npm_dist/internal/framework/_typescript/client/index.d.ts +17 -0
  72. package/npm_dist/internal/framework/_typescript/client/index.d.ts.map +1 -0
  73. package/npm_dist/internal/framework/_typescript/client/index.js +2489 -0
  74. package/npm_dist/internal/framework/_typescript/client/index.js.map +7 -0
  75. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts +6 -0
  76. package/npm_dist/internal/framework/_typescript/client/src/asset_manager.d.ts.map +1 -0
  77. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts +119 -0
  78. package/npm_dist/internal/framework/_typescript/client/src/client.d.ts.map +1 -0
  79. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts +18 -0
  80. package/npm_dist/internal/framework/_typescript/client/src/client_loaders.d.ts.map +1 -0
  81. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts +10 -0
  82. package/npm_dist/internal/framework/_typescript/client/src/component_loader.d.ts.map +1 -0
  83. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts +3 -0
  84. package/npm_dist/internal/framework/_typescript/client/src/error_boundary.d.ts.map +1 -0
  85. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts +26 -0
  86. package/npm_dist/internal/framework/_typescript/client/src/events.d.ts.map +1 -0
  87. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts +12 -0
  88. package/npm_dist/internal/framework/_typescript/client/src/global_loading_indicator/global_loading_indicator.d.ts.map +1 -0
  89. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts +2 -0
  90. package/npm_dist/internal/framework/_typescript/client/src/hard_reload.d.ts.map +1 -0
  91. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts +7 -0
  92. package/npm_dist/internal/framework/_typescript/client/src/head_elements/head_elements.d.ts.map +1 -0
  93. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts +14 -0
  94. package/npm_dist/internal/framework/_typescript/client/src/history/history.d.ts.map +1 -0
  95. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts +84 -0
  96. package/npm_dist/internal/framework/_typescript/client/src/history/npm_history_types.d.ts.map +1 -0
  97. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts +3 -0
  98. package/npm_dist/internal/framework/_typescript/client/src/hmr/hmr.d.ts.map +1 -0
  99. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts +9 -0
  100. package/npm_dist/internal/framework/_typescript/client/src/init_client.d.ts.map +1 -0
  101. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts +33 -0
  102. package/npm_dist/internal/framework/_typescript/client/src/links.d.ts.map +1 -0
  103. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts +26 -0
  104. package/npm_dist/internal/framework/_typescript/client/src/redirects/redirects.d.ts.map +1 -0
  105. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts +18 -0
  106. package/npm_dist/internal/framework/_typescript/client/src/rendering.d.ts.map +1 -0
  107. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts +2 -0
  108. package/npm_dist/internal/framework/_typescript/client/src/resolve_public_href.d.ts.map +1 -0
  109. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts +22 -0
  110. package/npm_dist/internal/framework/_typescript/client/src/scroll_state_manager.d.ts.map +1 -0
  111. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts +12 -0
  112. package/npm_dist/internal/framework/_typescript/client/src/static_route_defs/route_def_helpers.d.ts.map +1 -0
  113. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts +28 -0
  114. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/link_components.d.ts.map +1 -0
  115. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts +18 -0
  116. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/route_components.d.ts.map +1 -0
  117. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts +11 -0
  118. package/npm_dist/internal/framework/_typescript/client/src/ui_lib_impl_helpers/typed_navigate.d.ts.map +1 -0
  119. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts +3 -0
  120. package/npm_dist/internal/framework/_typescript/client/src/utils/errors.d.ts.map +1 -0
  121. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts +3 -0
  122. package/npm_dist/internal/framework/_typescript/client/src/utils/logging.d.ts.map +1 -0
  123. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts +119 -0
  124. package/npm_dist/internal/framework/_typescript/client/src/vorma_app_helpers/vorma_app_helpers.d.ts.map +1 -0
  125. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts +88 -0
  126. package/npm_dist/internal/framework/_typescript/client/src/vorma_ctx/vorma_ctx.d.ts.map +1 -0
  127. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts +10 -0
  128. package/npm_dist/internal/framework/_typescript/client/src/window_focus_revalidation/window_focus_revalidation.d.ts.map +1 -0
  129. package/npm_dist/internal/framework/_typescript/create/main.d.ts +3 -0
  130. package/npm_dist/internal/framework/_typescript/create/main.d.ts.map +1 -0
  131. package/npm_dist/internal/framework/_typescript/preact/index.d.ts +4 -0
  132. package/npm_dist/internal/framework/_typescript/preact/index.d.ts.map +1 -0
  133. package/npm_dist/internal/framework/_typescript/preact/index.js +283 -0
  134. package/npm_dist/internal/framework/_typescript/preact/index.js.map +7 -0
  135. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts +21 -0
  136. package/npm_dist/internal/framework/_typescript/preact/src/helpers.d.ts.map +1 -0
  137. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts +11 -0
  138. package/npm_dist/internal/framework/_typescript/preact/src/link.d.ts.map +1 -0
  139. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts +21 -0
  140. package/npm_dist/internal/framework/_typescript/preact/src/preact.d.ts.map +1 -0
  141. package/npm_dist/internal/framework/_typescript/react/index.d.ts +4 -0
  142. package/npm_dist/internal/framework/_typescript/react/index.d.ts.map +1 -0
  143. package/npm_dist/internal/framework/_typescript/react/index.js +370 -0
  144. package/npm_dist/internal/framework/_typescript/react/index.js.map +7 -0
  145. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts +21 -0
  146. package/npm_dist/internal/framework/_typescript/react/src/helpers.d.ts.map +1 -0
  147. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts +11 -0
  148. package/npm_dist/internal/framework/_typescript/react/src/link.d.ts.map +1 -0
  149. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts +20 -0
  150. package/npm_dist/internal/framework/_typescript/react/src/react.d.ts.map +1 -0
  151. package/npm_dist/internal/framework/_typescript/solid/index.d.ts +4 -0
  152. package/npm_dist/internal/framework/_typescript/solid/index.d.ts.map +1 -0
  153. package/npm_dist/internal/framework/_typescript/solid/index.js +314 -0
  154. package/npm_dist/internal/framework/_typescript/solid/index.js.map +7 -0
  155. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts +22 -0
  156. package/npm_dist/internal/framework/_typescript/solid/src/helpers.d.ts.map +1 -0
  157. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts +11 -0
  158. package/npm_dist/internal/framework/_typescript/solid/src/link.d.ts.map +1 -0
  159. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts +22 -0
  160. package/npm_dist/internal/framework/_typescript/solid/src/solid.d.ts.map +1 -0
  161. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts +11 -0
  162. package/npm_dist/internal/framework/_typescript/vite/vite.d.ts.map +1 -0
  163. package/npm_dist/internal/framework/_typescript/vite/vite.js +82 -0
  164. package/npm_dist/internal/framework/_typescript/vite/vite.js.map +7 -0
  165. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js +202 -0
  166. package/npm_dist/kit/_typescript/chunk-YBAPNBS2.js.map +7 -0
  167. package/npm_dist/kit/_typescript/converters/converters.d.ts +26 -0
  168. package/npm_dist/kit/_typescript/converters/converters.d.ts.map +1 -0
  169. package/npm_dist/kit/_typescript/converters/converters.js +99 -0
  170. package/npm_dist/kit/_typescript/converters/converters.js.map +7 -0
  171. package/npm_dist/kit/_typescript/cookies/cookies.d.ts +13 -0
  172. package/npm_dist/kit/_typescript/cookies/cookies.d.ts.map +1 -0
  173. package/npm_dist/kit/_typescript/cookies/cookies.js +13 -0
  174. package/npm_dist/kit/_typescript/cookies/cookies.js.map +7 -0
  175. package/npm_dist/kit/_typescript/csrf/csrf.d.ts +5 -0
  176. package/npm_dist/kit/_typescript/csrf/csrf.d.ts.map +1 -0
  177. package/npm_dist/kit/_typescript/csrf/csrf.js +11 -0
  178. package/npm_dist/kit/_typescript/csrf/csrf.js.map +7 -0
  179. package/npm_dist/kit/_typescript/debounce/debounce.d.ts +4 -0
  180. package/npm_dist/kit/_typescript/debounce/debounce.d.ts.map +1 -0
  181. package/npm_dist/kit/_typescript/debounce/debounce.js +16 -0
  182. package/npm_dist/kit/_typescript/debounce/debounce.js.map +7 -0
  183. package/npm_dist/kit/_typescript/fmt/fmt.d.ts +2 -0
  184. package/npm_dist/kit/_typescript/fmt/fmt.d.ts.map +1 -0
  185. package/npm_dist/kit/_typescript/fmt/fmt.js +8 -0
  186. package/npm_dist/kit/_typescript/fmt/fmt.js.map +7 -0
  187. package/npm_dist/kit/_typescript/json/deep_equals.d.ts +7 -0
  188. package/npm_dist/kit/_typescript/json/deep_equals.d.ts.map +1 -0
  189. package/npm_dist/kit/_typescript/json/json.d.ts +4 -0
  190. package/npm_dist/kit/_typescript/json/json.d.ts.map +1 -0
  191. package/npm_dist/kit/_typescript/json/json.js +110 -0
  192. package/npm_dist/kit/_typescript/json/json.js.map +7 -0
  193. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts +2 -0
  194. package/npm_dist/kit/_typescript/json/search_param_serializer.d.ts.map +1 -0
  195. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts +7 -0
  196. package/npm_dist/kit/_typescript/json/stringify_stable.d.ts.map +1 -0
  197. package/npm_dist/kit/_typescript/listeners/listeners.d.ts +2 -0
  198. package/npm_dist/kit/_typescript/listeners/listeners.d.ts.map +1 -0
  199. package/npm_dist/kit/_typescript/listeners/listeners.js +20 -0
  200. package/npm_dist/kit/_typescript/listeners/listeners.js.map +7 -0
  201. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts +10 -0
  202. package/npm_dist/kit/_typescript/matcher/find_best_match.d.ts.map +1 -0
  203. package/npm_dist/kit/_typescript/matcher/find_best_match.js +146 -0
  204. package/npm_dist/kit/_typescript/matcher/find_best_match.js.map +7 -0
  205. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts +14 -0
  206. package/npm_dist/kit/_typescript/matcher/find_nested_matches.d.ts.map +1 -0
  207. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js +248 -0
  208. package/npm_dist/kit/_typescript/matcher/find_nested_matches.js.map +7 -0
  209. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts +2 -0
  210. package/npm_dist/kit/_typescript/matcher/parse_segments.d.ts.map +1 -0
  211. package/npm_dist/kit/_typescript/matcher/register.d.ts +54 -0
  212. package/npm_dist/kit/_typescript/matcher/register.d.ts.map +1 -0
  213. package/npm_dist/kit/_typescript/matcher/register.js +21 -0
  214. package/npm_dist/kit/_typescript/matcher/register.js.map +7 -0
  215. package/npm_dist/kit/_typescript/theme/theme.d.ts +24 -0
  216. package/npm_dist/kit/_typescript/theme/theme.d.ts.map +1 -0
  217. package/npm_dist/kit/_typescript/theme/theme.js +133 -0
  218. package/npm_dist/kit/_typescript/theme/theme.js.map +7 -0
  219. package/npm_dist/kit/_typescript/url/url.d.ts +30 -0
  220. package/npm_dist/kit/_typescript/url/url.d.ts.map +1 -0
  221. package/npm_dist/kit/_typescript/url/url.js +100 -0
  222. package/npm_dist/kit/_typescript/url/url.js.map +7 -0
  223. package/package.json +135 -3
  224. package/tsconfig.base.json +17 -0
  225. package/index.js +0 -1
@@ -0,0 +1,107 @@
1
+ import { h, type JSX } from "preact";
2
+ import { memo } from "preact/compat";
3
+ import type {
4
+ ExtractApp,
5
+ PermissivePatternBasedProps,
6
+ VormaAppBase,
7
+ VormaLoaderPattern,
8
+ } from "vorma/client";
9
+ import {
10
+ __makeFinalLinkProps,
11
+ __resolvePath,
12
+ type VormaAppConfig,
13
+ type VormaLinkPropsBase,
14
+ } from "vorma/client";
15
+
16
+ export const VormaLink = memo(function VormaLink(
17
+ props: JSX.HTMLAttributes<HTMLAnchorElement> &
18
+ VormaLinkPropsBase<
19
+ (
20
+ e: JSX.TargetedMouseEvent<HTMLAnchorElement>,
21
+ ) => void | Promise<void>
22
+ >,
23
+ ) {
24
+ const finalLinkProps = __makeFinalLinkProps(props);
25
+ // oxlint-disable-next-line no-unused-vars
26
+ const { prefetch, scrollToTop, replace, state, ...rest } = props;
27
+
28
+ return h(
29
+ "a",
30
+ {
31
+ "data-external": finalLinkProps.dataExternal,
32
+ ...(rest as any),
33
+ onPointerEnter: finalLinkProps.onPointerEnter,
34
+ onFocus: finalLinkProps.onFocus,
35
+ onPointerLeave: finalLinkProps.onPointerLeave,
36
+ onBlur: finalLinkProps.onBlur,
37
+ onTouchCancel: finalLinkProps.onTouchCancel,
38
+ onClick: finalLinkProps.onClick,
39
+ },
40
+ props.children,
41
+ );
42
+ });
43
+
44
+ type TypedVormaLinkProps<
45
+ App extends VormaAppBase,
46
+ Pattern extends VormaLoaderPattern<App> = VormaLoaderPattern<App>,
47
+ > = Omit<JSX.HTMLAttributes<HTMLAnchorElement>, "href" | "pattern"> &
48
+ VormaLinkPropsBase<
49
+ (e: JSX.TargetedMouseEvent<HTMLAnchorElement>) => void | Promise<void>
50
+ > &
51
+ PermissivePatternBasedProps<App, Pattern> & {
52
+ search?: string;
53
+ hash?: string;
54
+ };
55
+
56
+ export function makeTypedLink<C extends VormaAppConfig>(
57
+ vormaAppConfig: C,
58
+ defaultProps?: Partial<
59
+ Omit<
60
+ TypedVormaLinkProps<ExtractApp<C>>,
61
+ "pattern" | "params" | "splatValues"
62
+ >
63
+ >,
64
+ ) {
65
+ type App = ExtractApp<C>;
66
+
67
+ const TypedLink = memo(function TypedLink<
68
+ Pattern extends VormaLoaderPattern<App>,
69
+ >(props: TypedVormaLinkProps<App, Pattern>) {
70
+ const {
71
+ pattern,
72
+ params,
73
+ splatValues,
74
+ search,
75
+ hash,
76
+ state,
77
+ ...linkProps
78
+ } = props as any;
79
+
80
+ const href = __resolvePath({
81
+ vormaAppConfig,
82
+ type: "loader",
83
+ props: {
84
+ pattern,
85
+ ...(params && { params }),
86
+ ...(splatValues && { splatValues }),
87
+ },
88
+ });
89
+
90
+ const url = new URL(href, window.location.origin);
91
+ if (search !== undefined) url.search = search;
92
+ if (hash !== undefined) url.hash = hash;
93
+
94
+ const finalProps = {
95
+ ...defaultProps,
96
+ ...linkProps,
97
+ href: url.href,
98
+ state,
99
+ };
100
+
101
+ return h(VormaLink, finalProps);
102
+ });
103
+
104
+ (TypedLink as any).displayName =
105
+ `TypedLink(${Object.keys(defaultProps || {}).join(", ")})`;
106
+ return TypedLink;
107
+ }
@@ -0,0 +1,191 @@
1
+ import { batch, computed, effect, signal } from "@preact/signals";
2
+ import { h } from "preact";
3
+ import { useEffect, useLayoutEffect, useMemo, useRef } from "preact/hooks";
4
+ import {
5
+ __applyScrollState,
6
+ addLocationListener,
7
+ addRouteChangeListener,
8
+ __vormaClientGlobal as ctx,
9
+ getLocation,
10
+ getRouterData,
11
+ type RouteChangeEvent,
12
+ } from "vorma/client";
13
+
14
+ /////////////////////////////////////////////////////////////////////
15
+ /////// CORE SETUP
16
+ /////////////////////////////////////////////////////////////////////
17
+
18
+ const latestEvent = signal<RouteChangeEvent | null>(null);
19
+ const loadersData = signal(ctx.get("loadersData"));
20
+ const clientLoadersData = signal(ctx.get("clientLoadersData"));
21
+ const routerData = signal(getRouterData());
22
+ const outermostErrorIdx = signal(ctx.get("outermostErrorIdx"));
23
+ const outermostError = signal(ctx.get("outermostError"));
24
+ const activeComponents = signal(ctx.get("activeComponents"));
25
+ const activeErrorBoundary = signal(ctx.get("activeErrorBoundary"));
26
+ const importURLs = signal(ctx.get("importURLs"));
27
+ const exportKeys = signal(ctx.get("exportKeys"));
28
+
29
+ export { clientLoadersData, loadersData, routerData };
30
+
31
+ let isInited = false;
32
+
33
+ function initUIListeners() {
34
+ if (isInited) return;
35
+ isInited = true;
36
+
37
+ addRouteChangeListener((e) => {
38
+ batch(() => {
39
+ latestEvent.value = e;
40
+ loadersData.value = ctx.get("loadersData");
41
+ clientLoadersData.value = ctx.get("clientLoadersData");
42
+ routerData.value = getRouterData();
43
+ outermostErrorIdx.value = ctx.get("outermostErrorIdx");
44
+ outermostError.value = ctx.get("outermostError");
45
+ activeComponents.value = ctx.get("activeComponents");
46
+ activeErrorBoundary.value = ctx.get("activeErrorBoundary");
47
+ importURLs.value = ctx.get("importURLs");
48
+ exportKeys.value = ctx.get("exportKeys");
49
+ });
50
+ });
51
+
52
+ addLocationListener(() => {
53
+ location.value = getLocation();
54
+ });
55
+ }
56
+
57
+ export const location = signal(getLocation());
58
+
59
+ /////////////////////////////////////////////////////////////////////
60
+ /////// COMPONENT
61
+ /////////////////////////////////////////////////////////////////////
62
+
63
+ export function VormaRootOutlet(props: { idx?: number }): h.JSX.Element {
64
+ const idx = props.idx ?? 0;
65
+
66
+ const initialRenderRef = useRef(true);
67
+
68
+ if (idx === 0 && initialRenderRef.current) {
69
+ initUIListeners();
70
+
71
+ initialRenderRef.current = false;
72
+ batch(() => {
73
+ loadersData.value = ctx.get("loadersData");
74
+ clientLoadersData.value = ctx.get("clientLoadersData");
75
+ routerData.value = getRouterData();
76
+ outermostError.value = ctx.get("outermostError");
77
+ outermostErrorIdx.value = ctx.get("outermostErrorIdx");
78
+ activeComponents.value = ctx.get("activeComponents");
79
+ activeErrorBoundary.value = ctx.get("activeErrorBoundary");
80
+ importURLs.value = ctx.get("importURLs");
81
+ exportKeys.value = ctx.get("exportKeys");
82
+ });
83
+ }
84
+
85
+ const currentImportURL = signal(importURLs.value[idx]);
86
+ const currentExportKey = signal(exportKeys.value[idx]);
87
+ const nextImportURL = signal(importURLs.value[idx + 1]);
88
+ const nextExportKey = signal(exportKeys.value[idx + 1]);
89
+
90
+ useEffect(() => {
91
+ const dispose = effect(() => {
92
+ if (!currentImportURL.value || !latestEvent.value) {
93
+ return;
94
+ }
95
+
96
+ batch(() => {
97
+ const newCurrentImportURL = importURLs.value[idx];
98
+ const newCurrentExportKey = exportKeys.value[idx];
99
+
100
+ if (currentImportURL.value !== newCurrentImportURL) {
101
+ currentImportURL.value = newCurrentImportURL;
102
+ }
103
+ if (currentExportKey.value !== newCurrentExportKey) {
104
+ currentExportKey.value = newCurrentExportKey;
105
+ }
106
+
107
+ // these are also needed for Outlets to render correctly
108
+ const newNextImportURL = importURLs.value[idx + 1];
109
+ const newNextExportKey = exportKeys.value[idx + 1];
110
+
111
+ if (nextImportURL.value !== newNextImportURL) {
112
+ nextImportURL.value = newNextImportURL;
113
+ }
114
+ if (nextExportKey.value !== newNextExportKey) {
115
+ nextExportKey.value = newNextExportKey;
116
+ }
117
+ });
118
+ });
119
+
120
+ return dispose;
121
+ }, [idx]);
122
+
123
+ useLayoutEffect(() => {
124
+ const dispose = effect(() => {
125
+ const event = latestEvent.value;
126
+ if (!event || idx !== 0) {
127
+ return;
128
+ }
129
+ window.requestAnimationFrame(() => {
130
+ __applyScrollState(event.detail.__scrollState);
131
+ });
132
+ });
133
+
134
+ return dispose;
135
+ }, [idx]);
136
+
137
+ const isErrorIdx = computed(() => idx === outermostErrorIdx.value);
138
+
139
+ const CurrentComp = computed(() => {
140
+ if (isErrorIdx.value) {
141
+ return null;
142
+ }
143
+ currentImportURL.value;
144
+ currentExportKey.value;
145
+ return activeComponents.value?.[idx];
146
+ });
147
+
148
+ const Outlet = useMemo(
149
+ () => (localProps: Record<string, any> | undefined) => {
150
+ return h(VormaRootOutlet, {
151
+ ...localProps,
152
+ ...props,
153
+ idx: idx + 1,
154
+ });
155
+ },
156
+ [nextImportURL.value, nextExportKey.value],
157
+ );
158
+
159
+ const shouldFallbackOutlet = computed(() => {
160
+ if (isErrorIdx.value) {
161
+ return false;
162
+ }
163
+ if (CurrentComp.value) {
164
+ return false;
165
+ }
166
+ return idx + 1 < loadersData.value.length;
167
+ });
168
+
169
+ const ErrorComp = computed(() => {
170
+ if (!isErrorIdx.value) {
171
+ return null;
172
+ }
173
+ return activeErrorBoundary.value;
174
+ });
175
+
176
+ if (isErrorIdx.value) {
177
+ if (ErrorComp.value) {
178
+ return h(ErrorComp.value, { error: outermostError.value });
179
+ }
180
+ return h("div", {}, `Error: ${outermostError.value || "unknown"}`);
181
+ }
182
+
183
+ if (!CurrentComp.value) {
184
+ if (shouldFallbackOutlet.value) {
185
+ return h(Outlet, {});
186
+ }
187
+ return h("div", {});
188
+ }
189
+
190
+ return h(CurrentComp.value, { idx, Outlet });
191
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "extends": "../../../../tsconfig.base.json",
3
+ "compilerOptions": {
4
+ "jsx": "react-jsx",
5
+ "jsxImportSource": "preact"
6
+ }
7
+ }
@@ -0,0 +1,10 @@
1
+ export {
2
+ makeTypedAddClientLoader,
3
+ makeTypedUseLoaderData,
4
+ makeTypedUsePatternLoaderData,
5
+ makeTypedUseRouterData,
6
+ type VormaRoute,
7
+ type VormaRouteProps,
8
+ } from "./src/helpers.ts";
9
+ export { VormaLink, makeTypedLink } from "./src/link.tsx";
10
+ export { VormaRootOutlet, useLocation } from "./src/react.tsx";
@@ -0,0 +1,118 @@
1
+ /// <reference types="vite/client" />
2
+
3
+ import { useMemo, type JSX } from "react";
4
+ import {
5
+ __registerClientLoaderPattern,
6
+ __runClientLoadersAfterHMRUpdate,
7
+ __vormaClientGlobal,
8
+ type ClientLoaderAwaitedServerData,
9
+ type ParamsForPattern,
10
+ type UseRouterDataFunction,
11
+ type VormaAppBase,
12
+ type VormaLoaderOutput,
13
+ type VormaLoaderPattern,
14
+ type VormaRouteGeneric,
15
+ type VormaRoutePropsGeneric,
16
+ } from "vorma/client";
17
+ import {
18
+ useClientLoadersData,
19
+ useLoadersData,
20
+ useRouterData,
21
+ } from "./react.tsx";
22
+
23
+ export type VormaRouteProps<
24
+ App extends VormaAppBase = any,
25
+ Pattern extends VormaLoaderPattern<App> = string,
26
+ > = VormaRoutePropsGeneric<JSX.Element, App, Pattern>;
27
+
28
+ export type VormaRoute<
29
+ App extends VormaAppBase = any,
30
+ Pattern extends VormaLoaderPattern<App> = string,
31
+ > = VormaRouteGeneric<JSX.Element, App, Pattern>;
32
+
33
+ export function makeTypedUseRouterData<App extends VormaAppBase>() {
34
+ return useRouterData as UseRouterDataFunction<App, false>;
35
+ }
36
+
37
+ export function makeTypedUseLoaderData<App extends VormaAppBase>() {
38
+ return function useLoaderData<Pattern extends VormaLoaderPattern<App>>(
39
+ props: VormaRouteProps<App, Pattern>,
40
+ ): VormaLoaderOutput<App, Pattern> {
41
+ const loadersData = useLoadersData();
42
+ return loadersData[props.idx];
43
+ };
44
+ }
45
+
46
+ export function makeTypedUsePatternLoaderData<App extends VormaAppBase>() {
47
+ return function usePatternLoaderData<
48
+ Pattern extends VormaLoaderPattern<App>,
49
+ >(pattern: Pattern): VormaLoaderOutput<App, Pattern> | undefined {
50
+ const routerData = useRouterData();
51
+ const loadersData = useLoadersData();
52
+ const idx = useMemo(() => {
53
+ return routerData.matchedPatterns.findIndex((p) => p === pattern);
54
+ }, [routerData.matchedPatterns, pattern]);
55
+
56
+ if (idx === -1) {
57
+ return undefined;
58
+ }
59
+ return loadersData[idx];
60
+ };
61
+ }
62
+
63
+ export function makeTypedAddClientLoader<App extends VormaAppBase>() {
64
+ const m = __vormaClientGlobal.get("patternToWaitFnMap");
65
+ return function addClientLoader<
66
+ Pattern extends VormaLoaderPattern<App>,
67
+ LoaderData extends VormaLoaderOutput<App, Pattern>,
68
+ T = any,
69
+ >(props: {
70
+ pattern: Pattern;
71
+ clientLoader: (props: {
72
+ params: Record<ParamsForPattern<App, Pattern>, string>;
73
+ splatValues: string[];
74
+ serverDataPromise: Promise<
75
+ ClientLoaderAwaitedServerData<App["rootData"], LoaderData>
76
+ >;
77
+ signal: AbortSignal;
78
+ }) => Promise<T>;
79
+ reRunOnModuleChange?: ImportMeta;
80
+ }) {
81
+ const p = props.pattern;
82
+ const fn = props.clientLoader;
83
+
84
+ __registerClientLoaderPattern(p as string).catch((error) => {
85
+ console.error("Failed to register client loader pattern:", error);
86
+ });
87
+ (m as any)[p] = fn;
88
+
89
+ if (import.meta.env.DEV && props.reRunOnModuleChange) {
90
+ __runClientLoadersAfterHMRUpdate(props.reRunOnModuleChange, p);
91
+ }
92
+
93
+ type Res = Awaited<ReturnType<typeof fn>>;
94
+
95
+ const useClientLoaderData = (
96
+ props?: VormaRouteProps<App, Pattern>,
97
+ ): Res | undefined => {
98
+ const clientLoadersData = useClientLoadersData();
99
+ const routerData = useRouterData();
100
+
101
+ const idx = useMemo(() => {
102
+ if (props) {
103
+ return props.idx;
104
+ }
105
+ const matched = routerData.matchedPatterns;
106
+ return matched.findIndex((pattern) => pattern === p);
107
+ }, [props, routerData.matchedPatterns]);
108
+
109
+ if (idx === -1) return undefined;
110
+ return clientLoadersData[idx];
111
+ };
112
+
113
+ return useClientLoaderData as {
114
+ (props: VormaRouteProps<App, Pattern>): Res;
115
+ (): Res | undefined;
116
+ };
117
+ };
118
+ }
@@ -0,0 +1,115 @@
1
+ import { memo, type ComponentProps, type JSX } from "react";
2
+ import type {
3
+ ExtractApp,
4
+ PermissivePatternBasedProps,
5
+ VormaAppBase,
6
+ VormaLoaderPattern,
7
+ } from "vorma/client";
8
+ import {
9
+ __makeFinalLinkProps,
10
+ __resolvePath,
11
+ type VormaAppConfig,
12
+ type VormaLinkPropsBase,
13
+ } from "vorma/client";
14
+
15
+ export const VormaLink = memo(function VormaLink(
16
+ props: ComponentProps<"a"> &
17
+ VormaLinkPropsBase<
18
+ (
19
+ e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
20
+ ) => void | Promise<void>
21
+ >,
22
+ ) {
23
+ const finalLinkProps = __makeFinalLinkProps(props);
24
+ // oxlint-disable-next-line no-unused-vars
25
+ const { prefetch, scrollToTop, replace, state, ...rest } = props;
26
+
27
+ return (
28
+ <a
29
+ data-external={finalLinkProps.dataExternal}
30
+ {...(rest as any)}
31
+ onPointerEnter={finalLinkProps.onPointerEnter}
32
+ onFocus={finalLinkProps.onFocus}
33
+ onPointerLeave={finalLinkProps.onPointerLeave}
34
+ onBlur={finalLinkProps.onBlur}
35
+ onTouchCancel={finalLinkProps.onTouchCancel}
36
+ onClick={finalLinkProps.onClick}
37
+ >
38
+ {props.children}
39
+ </a>
40
+ );
41
+ });
42
+
43
+ type TypedVormaLinkProps<
44
+ App extends VormaAppBase,
45
+ Pattern extends VormaLoaderPattern<App> = VormaLoaderPattern<App>,
46
+ > = Omit<ComponentProps<"a">, "href" | "pattern"> &
47
+ VormaLinkPropsBase<
48
+ (
49
+ e: React.MouseEvent<HTMLAnchorElement, MouseEvent>,
50
+ ) => void | Promise<void>
51
+ > &
52
+ PermissivePatternBasedProps<App, Pattern> & {
53
+ search?: string;
54
+ hash?: string;
55
+ };
56
+
57
+ export function makeTypedLink<C extends VormaAppConfig>(
58
+ vormaAppConfig: C,
59
+ defaultProps?: Partial<
60
+ Omit<
61
+ TypedVormaLinkProps<ExtractApp<C>>,
62
+ "pattern" | "params" | "splatValues"
63
+ >
64
+ >,
65
+ ) {
66
+ type App = ExtractApp<C>;
67
+
68
+ const TypedLink = <Pattern extends VormaLoaderPattern<App>>(
69
+ props: TypedVormaLinkProps<App, Pattern>,
70
+ ) => {
71
+ const {
72
+ pattern,
73
+ params,
74
+ splatValues,
75
+ search,
76
+ hash,
77
+ state,
78
+ ...linkProps
79
+ } = props as any;
80
+
81
+ const href = __resolvePath({
82
+ vormaAppConfig,
83
+ type: "loader",
84
+ props: {
85
+ pattern,
86
+ ...(params && { params }),
87
+ ...(splatValues && { splatValues }),
88
+ },
89
+ });
90
+
91
+ const url = new URL(href, window.location.origin);
92
+ if (search !== undefined) url.search = search;
93
+ if (hash !== undefined) url.hash = hash;
94
+
95
+ const finalProps = {
96
+ ...defaultProps,
97
+ ...linkProps,
98
+ href: url.href,
99
+ state,
100
+ };
101
+
102
+ return <VormaLink {...finalProps} />;
103
+ };
104
+
105
+ const MemoizedTypedLink = memo(TypedLink) as <
106
+ Pattern extends VormaLoaderPattern<App>,
107
+ >(
108
+ props: TypedVormaLinkProps<App, Pattern>,
109
+ ) => JSX.Element;
110
+
111
+ (MemoizedTypedLink as any).displayName =
112
+ `TypedLink(${Object.keys(defaultProps || {}).join(", ")})`;
113
+
114
+ return MemoizedTypedLink;
115
+ }