kiru 0.54.0-preview.1 → 0.54.1

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 (204) hide show
  1. package/dist/components/derive.d.ts +1 -1
  2. package/dist/components/derive.d.ts.map +1 -1
  3. package/dist/components/derive.js +2 -3
  4. package/dist/components/derive.js.map +1 -1
  5. package/dist/components/memo.d.ts +1 -3
  6. package/dist/components/memo.d.ts.map +1 -1
  7. package/dist/components/memo.js +2 -2
  8. package/dist/components/memo.js.map +1 -1
  9. package/dist/context.d.ts.map +1 -1
  10. package/dist/context.js +1 -23
  11. package/dist/context.js.map +1 -1
  12. package/dist/dom.d.ts.map +1 -1
  13. package/dist/dom.js +111 -78
  14. package/dist/dom.js.map +1 -1
  15. package/dist/error.d.ts.map +1 -1
  16. package/dist/error.js +2 -4
  17. package/dist/error.js.map +1 -1
  18. package/dist/form/index.d.ts.map +1 -1
  19. package/dist/form/index.js +6 -10
  20. package/dist/form/index.js.map +1 -1
  21. package/dist/globals.d.ts +1 -1
  22. package/dist/globals.d.ts.map +1 -1
  23. package/dist/globals.js.map +1 -1
  24. package/dist/hmr.d.ts +1 -0
  25. package/dist/hmr.d.ts.map +1 -1
  26. package/dist/hmr.js +11 -3
  27. package/dist/hmr.js.map +1 -1
  28. package/dist/hooks/useEffectEvent.d.ts.map +1 -1
  29. package/dist/hooks/useEffectEvent.js.map +1 -1
  30. package/dist/hooks/usePromise.d.ts +1 -2
  31. package/dist/hooks/usePromise.d.ts.map +1 -1
  32. package/dist/hooks/usePromise.js +62 -31
  33. package/dist/hooks/usePromise.js.map +1 -1
  34. package/dist/hooks/utils.d.ts.map +1 -1
  35. package/dist/hooks/utils.js +10 -10
  36. package/dist/hooks/utils.js.map +1 -1
  37. package/dist/hydration.d.ts +6 -13
  38. package/dist/hydration.d.ts.map +1 -1
  39. package/dist/hydration.js +20 -50
  40. package/dist/hydration.js.map +1 -1
  41. package/dist/index.js +2 -1
  42. package/dist/index.js.map +1 -1
  43. package/dist/reconciler.d.ts.map +1 -1
  44. package/dist/reconciler.js +3 -6
  45. package/dist/reconciler.js.map +1 -1
  46. package/dist/recursiveRender.d.ts.map +1 -1
  47. package/dist/recursiveRender.js +9 -8
  48. package/dist/recursiveRender.js.map +1 -1
  49. package/dist/renderToString.d.ts.map +1 -1
  50. package/dist/renderToString.js.map +1 -1
  51. package/dist/router/client/index.d.ts +2 -4
  52. package/dist/router/client/index.d.ts.map +1 -1
  53. package/dist/router/client/index.js +13 -59
  54. package/dist/router/client/index.js.map +1 -1
  55. package/dist/router/context.d.ts +5 -2
  56. package/dist/router/context.d.ts.map +1 -1
  57. package/dist/router/context.js +1 -5
  58. package/dist/router/context.js.map +1 -1
  59. package/dist/router/fileRouter.d.ts.map +1 -1
  60. package/dist/router/fileRouter.js +2 -4
  61. package/dist/router/fileRouter.js.map +1 -1
  62. package/dist/router/fileRouterController.d.ts +2 -2
  63. package/dist/router/fileRouterController.d.ts.map +1 -1
  64. package/dist/router/fileRouterController.js +135 -214
  65. package/dist/router/fileRouterController.js.map +1 -1
  66. package/dist/router/globals.d.ts +0 -3
  67. package/dist/router/globals.d.ts.map +1 -1
  68. package/dist/router/globals.js +0 -3
  69. package/dist/router/globals.js.map +1 -1
  70. package/dist/router/head.d.ts.map +1 -1
  71. package/dist/router/head.js +7 -5
  72. package/dist/router/head.js.map +1 -1
  73. package/dist/router/index.d.ts +1 -2
  74. package/dist/router/index.d.ts.map +1 -1
  75. package/dist/router/index.js +1 -2
  76. package/dist/router/index.js.map +1 -1
  77. package/dist/router/link.js +3 -3
  78. package/dist/router/link.js.map +1 -1
  79. package/dist/router/{ssg → server}/index.d.ts +4 -4
  80. package/dist/router/server/index.d.ts.map +1 -0
  81. package/dist/router/{ssg → server}/index.js +7 -9
  82. package/dist/router/server/index.js.map +1 -0
  83. package/dist/router/types.d.ts +16 -42
  84. package/dist/router/types.d.ts.map +1 -1
  85. package/dist/router/types.internal.d.ts +0 -4
  86. package/dist/router/types.internal.d.ts.map +1 -1
  87. package/dist/router/utils/index.d.ts +3 -8
  88. package/dist/router/utils/index.d.ts.map +1 -1
  89. package/dist/router/utils/index.js +8 -40
  90. package/dist/router/utils/index.js.map +1 -1
  91. package/dist/scheduler.d.ts +3 -14
  92. package/dist/scheduler.d.ts.map +1 -1
  93. package/dist/scheduler.js +64 -56
  94. package/dist/scheduler.js.map +1 -1
  95. package/dist/signals/base.d.ts +0 -2
  96. package/dist/signals/base.d.ts.map +1 -1
  97. package/dist/signals/base.js +0 -6
  98. package/dist/signals/base.js.map +1 -1
  99. package/dist/signals/computed.d.ts +3 -0
  100. package/dist/signals/computed.d.ts.map +1 -1
  101. package/dist/signals/computed.js +29 -20
  102. package/dist/signals/computed.js.map +1 -1
  103. package/dist/signals/for.d.ts +3 -3
  104. package/dist/signals/for.d.ts.map +1 -1
  105. package/dist/signals/for.js +2 -1
  106. package/dist/signals/for.js.map +1 -1
  107. package/dist/signals/utils.d.ts.map +1 -1
  108. package/dist/signals/utils.js +2 -1
  109. package/dist/signals/utils.js.map +1 -1
  110. package/dist/signals/watch.d.ts.map +1 -1
  111. package/dist/signals/watch.js +18 -22
  112. package/dist/signals/watch.js.map +1 -1
  113. package/dist/ssr/client.d.ts +1 -1
  114. package/dist/ssr/client.d.ts.map +1 -1
  115. package/dist/ssr/client.js +0 -2
  116. package/dist/ssr/client.js.map +1 -1
  117. package/dist/ssr/server.d.ts +3 -9
  118. package/dist/ssr/server.d.ts.map +1 -1
  119. package/dist/ssr/server.js +30 -37
  120. package/dist/ssr/server.js.map +1 -1
  121. package/dist/types.d.ts +0 -7
  122. package/dist/types.d.ts.map +1 -1
  123. package/dist/types.dom.d.ts +3 -3
  124. package/dist/types.dom.d.ts.map +1 -1
  125. package/dist/utils/format.d.ts +1 -2
  126. package/dist/utils/format.d.ts.map +1 -1
  127. package/dist/utils/format.js +1 -4
  128. package/dist/utils/format.js.map +1 -1
  129. package/dist/utils/index.d.ts +1 -1
  130. package/dist/utils/index.d.ts.map +1 -1
  131. package/dist/utils/index.js +1 -1
  132. package/dist/utils/index.js.map +1 -1
  133. package/dist/utils/promise.d.ts +0 -2
  134. package/dist/utils/promise.d.ts.map +1 -1
  135. package/dist/utils/promise.js +1 -45
  136. package/dist/utils/promise.js.map +1 -1
  137. package/dist/utils/runtime.d.ts +3 -2
  138. package/dist/utils/runtime.d.ts.map +1 -1
  139. package/dist/utils/runtime.js +5 -2
  140. package/dist/utils/runtime.js.map +1 -1
  141. package/dist/utils/vdom.d.ts.map +1 -1
  142. package/dist/utils/vdom.js +2 -2
  143. package/dist/utils/vdom.js.map +1 -1
  144. package/package.json +4 -8
  145. package/src/components/derive.ts +3 -5
  146. package/src/components/memo.ts +3 -11
  147. package/src/context.ts +1 -24
  148. package/src/dom.ts +146 -101
  149. package/src/error.ts +2 -4
  150. package/src/form/index.ts +6 -9
  151. package/src/globals.ts +1 -1
  152. package/src/hmr.ts +14 -5
  153. package/src/hooks/useEffectEvent.ts +0 -1
  154. package/src/hooks/usePromise.ts +77 -58
  155. package/src/hooks/utils.ts +12 -12
  156. package/src/hydration.ts +21 -57
  157. package/src/index.ts +1 -1
  158. package/src/reconciler.ts +2 -6
  159. package/src/recursiveRender.ts +10 -9
  160. package/src/renderToString.ts +0 -1
  161. package/src/router/client/index.ts +16 -114
  162. package/src/router/context.ts +6 -7
  163. package/src/router/fileRouter.ts +2 -6
  164. package/src/router/fileRouterController.ts +161 -324
  165. package/src/router/globals.ts +0 -4
  166. package/src/router/head.ts +7 -5
  167. package/src/router/index.ts +1 -12
  168. package/src/router/link.ts +3 -3
  169. package/src/router/{ssg → server}/index.ts +13 -18
  170. package/src/router/types.internal.ts +0 -5
  171. package/src/router/types.ts +16 -53
  172. package/src/router/utils/index.ts +16 -79
  173. package/src/scheduler.ts +85 -89
  174. package/src/signals/base.ts +0 -8
  175. package/src/signals/computed.ts +30 -18
  176. package/src/signals/for.ts +15 -10
  177. package/src/signals/utils.ts +2 -1
  178. package/src/signals/watch.ts +27 -22
  179. package/src/ssr/client.ts +1 -4
  180. package/src/ssr/server.ts +34 -59
  181. package/src/types.dom.ts +4 -5
  182. package/src/types.ts +0 -10
  183. package/src/utils/format.ts +0 -5
  184. package/src/utils/index.ts +1 -1
  185. package/src/utils/promise.ts +1 -70
  186. package/src/utils/runtime.ts +6 -2
  187. package/src/utils/vdom.ts +2 -7
  188. package/dist/router/constants.d.ts +0 -2
  189. package/dist/router/constants.d.ts.map +0 -1
  190. package/dist/router/constants.js +0 -2
  191. package/dist/router/constants.js.map +0 -1
  192. package/dist/router/guard.d.ts +0 -17
  193. package/dist/router/guard.d.ts.map +0 -1
  194. package/dist/router/guard.js +0 -45
  195. package/dist/router/guard.js.map +0 -1
  196. package/dist/router/ssg/index.d.ts.map +0 -1
  197. package/dist/router/ssg/index.js.map +0 -1
  198. package/dist/router/ssr/index.d.ts +0 -20
  199. package/dist/router/ssr/index.d.ts.map +0 -1
  200. package/dist/router/ssr/index.js +0 -163
  201. package/dist/router/ssr/index.js.map +0 -1
  202. package/src/router/constants.ts +0 -1
  203. package/src/router/guard.ts +0 -72
  204. package/src/router/ssr/index.ts +0 -252
@@ -2,16 +2,14 @@ import { Signal } from "../signals/base.js";
2
2
  import { watch } from "../signals/watch.js";
3
3
  import { __DEV__ } from "../env.js";
4
4
  import { flushSync, nextIdle } from "../scheduler.js";
5
- import { toArray } from "../utils/format.js";
6
5
  import { FileRouterDataLoadError } from "./errors.js";
7
- import { fileRouterInstance, fileRouterRoute, requestContext, routerCache, } from "./globals.js";
8
- import { formatViteImportMap, matchModules, matchRoute, match404Route, normalizePrefixPath, parseQuery, wrapWithLayouts, runAfterEachGuards, runBeforeEachGuards, runBeforeEnterHooks, runBeforeLeaveHooks, } from "./utils/index.js";
6
+ import { fileRouterInstance, fileRouterRoute, routerCache } from "./globals.js";
7
+ import { formatViteImportMap, matchLayouts, matchRoute, match404Route, normalizePrefixPath, parseQuery, wrapWithLayouts, } from "./utils/index.js";
9
8
  import { RouterCache } from "./cache.js";
10
9
  import { scrollStack } from "./scrollStack.js";
11
- let transitionId = 0;
12
- let currentTransition = null;
13
10
  export class FileRouterController {
14
11
  constructor() {
12
+ this.baseUrl = "/";
15
13
  routerCache.current ?? (routerCache.current = new RouterCache());
16
14
  this.abortController = new AbortController();
17
15
  this.currentPage = new Signal(null);
@@ -21,7 +19,6 @@ export class FileRouterController {
21
19
  this.historyIndex = 0;
22
20
  this.layouts = {};
23
21
  this.pages = {};
24
- this.guards = {};
25
22
  this.state = {
26
23
  pathname: window.location.pathname,
27
24
  hash: window.location.hash,
@@ -29,27 +26,7 @@ export class FileRouterController {
29
26
  query: {},
30
27
  signal: this.abortController.signal,
31
28
  };
32
- const __this = this;
33
- this.contextValue = {
34
- invalidate: async (...paths) => {
35
- if (this.invalidate(...paths)) {
36
- return this.loadRoute();
37
- }
38
- },
39
- get state() {
40
- return { ...__this.state };
41
- },
42
- navigate: this.navigate.bind(this),
43
- prefetchRouteModules: this.prefetchRouteModules.bind(this),
44
- reload: async (options) => {
45
- if (options?.invalidate ?? true) {
46
- this.invalidate(this.state.pathname);
47
- }
48
- return this.loadRoute({ transition: options?.transition });
49
- },
50
- setQuery: this.setQuery.bind(this),
51
- setHash: this.setHash.bind(this),
52
- };
29
+ this.contextValue = this.createContextValue();
53
30
  if (__DEV__) {
54
31
  this.filePathToPageRoute = new Map();
55
32
  this.pageRouteToConfig = new Map();
@@ -66,10 +43,11 @@ export class FileRouterController {
66
43
  const loader = config.loader;
67
44
  if (curPage?.route === existing.route && loader) {
68
45
  const p = this.currentPageProps.value;
69
- const transition = (!loader.static && loader.transition) ?? this.enableTransitions;
46
+ const transition = (loader.mode !== "static" && loader.transition) ??
47
+ this.enableTransitions;
70
48
  // Check cache first if caching is enabled
71
49
  let cachedData = null;
72
- if (!loader.static && loader.cache) {
50
+ if (loader.mode !== "static" && loader.cache) {
73
51
  const cacheKey = {
74
52
  path: this.state.pathname,
75
53
  params: this.state.params,
@@ -85,7 +63,9 @@ export class FileRouterController {
85
63
  error: null,
86
64
  loading: false,
87
65
  };
88
- handleStateTransition(transition, transitionId, () => (this.currentPageProps.value = props));
66
+ handleStateTransition(this.state.signal, transition, () => {
67
+ this.currentPageProps.value = props;
68
+ });
89
69
  }
90
70
  else {
91
71
  // No cached data - show loading state and load data
@@ -95,8 +75,10 @@ export class FileRouterController {
95
75
  data: null,
96
76
  error: null,
97
77
  };
98
- handleStateTransition(transition, transitionId, () => (this.currentPageProps.value = props));
99
- this.loadRouteData(config, this.state, transition);
78
+ handleStateTransition(this.state.signal, transition, () => {
79
+ this.currentPageProps.value = props;
80
+ });
81
+ this.loadRouteData(config, props, this.state, transition);
100
82
  }
101
83
  }
102
84
  this.pageRouteToConfig?.set(existing.route, config);
@@ -121,25 +103,15 @@ export class FileRouterController {
121
103
  }
122
104
  }
123
105
  init(config) {
124
- const { pages, layouts, guards, dir = "/pages", baseUrl = "/", transition, preloaded, } = config;
106
+ const { pages, layouts, dir = "/pages", baseUrl = "/", transition, preloaded, } = config;
125
107
  this.enableTransitions = !!transition;
126
108
  const [normalizedDir, normalizedBaseUrl] = [
127
109
  normalizePrefixPath(dir),
128
110
  normalizePrefixPath(baseUrl),
129
111
  ];
130
- if (!preloaded) {
131
- this.pages = formatViteImportMap(pages, normalizedDir, normalizedBaseUrl);
132
- this.layouts = formatViteImportMap(layouts, normalizedDir, normalizedBaseUrl);
133
- this.guards = !guards
134
- ? {}
135
- : formatViteImportMap(guards, normalizedDir, normalizedBaseUrl);
136
- if (__DEV__) {
137
- validateRoutes(this.pages);
138
- }
139
- this.loadRoute();
140
- }
141
- else {
142
- const { pages, layouts, guards, page, pageProps, pagePropsPromise, pageLayouts, route, params, query, cacheData, } = preloaded;
112
+ this.baseUrl = normalizedBaseUrl.slice(0, -1);
113
+ if (preloaded) {
114
+ const { pages, layouts, page, pageProps, pageLayouts, route, params, query, cacheData, } = preloaded;
143
115
  this.state = {
144
116
  params,
145
117
  query,
@@ -156,42 +128,45 @@ export class FileRouterController {
156
128
  this.currentLayouts.value = pageLayouts.map((l) => l.default);
157
129
  this.pages = pages;
158
130
  this.layouts = layouts;
159
- this.guards = (guards ??
160
- {});
161
131
  if (__DEV__) {
162
- validateRoutes(this.pages);
163
132
  if (page.config) {
164
133
  this.dev_onPageConfigDefined(route, page.config);
165
134
  }
166
135
  }
167
- const loader = page.config?.loader;
168
- const transition = (!loader?.static && loader?.transition) ?? this.enableTransitions;
169
- if (loader && pagePropsPromise) {
170
- const prevState = this.state;
171
- pagePropsPromise.then(({ data, error }) => {
172
- if (this.state !== prevState)
173
- return;
174
- handleStateTransition(transition, transitionId, () => (this.currentPageProps.value = { loading: false, data, error }));
175
- });
136
+ if (__DEV__) {
137
+ validateRoutes(this.pages);
176
138
  }
177
- else if (loader &&
178
- ((!loader.static && pageProps.loading === true) || __DEV__)) {
139
+ const loader = page.config?.loader;
140
+ if (loader &&
141
+ ((loader.mode !== "static" && pageProps.loading === true) || __DEV__)) {
179
142
  if (cacheData === null) {
180
- this.loadRouteData(page.config, this.state);
143
+ this.loadRouteData(page.config, pageProps, this.state);
181
144
  }
182
145
  else {
183
146
  nextIdle(() => {
184
- handleStateTransition(transition, transitionId, () => {
185
- this.currentPageProps.value = {
186
- data: cacheData.value,
187
- error: null,
188
- loading: false,
189
- };
147
+ const props = {
148
+ ...pageProps,
149
+ data: cacheData.value,
150
+ error: null,
151
+ loading: false,
152
+ };
153
+ // @ts-ignore
154
+ const transition = loader.transition ?? this.enableTransitions;
155
+ handleStateTransition(this.state.signal, transition, () => {
156
+ this.currentPageProps.value = props;
190
157
  });
191
158
  });
192
159
  }
193
160
  }
194
161
  }
162
+ else {
163
+ this.pages = formatViteImportMap(pages, normalizedDir, normalizedBaseUrl);
164
+ this.layouts = formatViteImportMap(layouts, normalizedDir, normalizedBaseUrl);
165
+ if (__DEV__) {
166
+ validateRoutes(this.pages);
167
+ }
168
+ this.loadRoute();
169
+ }
195
170
  window.history.scrollRestoration = "manual";
196
171
  const historyState = window.history.state;
197
172
  if (typeof historyState !== "object" ||
@@ -219,59 +194,20 @@ export class FileRouterController {
219
194
  scrollStack.replace(this.historyIndex, window.scrollX, window.scrollY);
220
195
  window.history.scrollRestoration = "auto";
221
196
  });
222
- let ignorePopState = false;
223
197
  window.addEventListener("popstate", (e) => {
224
198
  e.preventDefault();
225
- if (!ignorePopState &&
226
- this.onBeforeLeave(window.location.pathname) === false) {
227
- ignorePopState = true;
228
- if (e.state !== null) {
229
- if (e.state.index > this.historyIndex) {
230
- window.history.go(-1);
231
- }
232
- else if (e.state.index < this.historyIndex) {
233
- window.history.go(1);
234
- }
235
- }
236
- return;
237
- }
238
- if (ignorePopState) {
239
- ignorePopState = false;
240
- return;
241
- }
242
199
  scrollStack.replace(this.historyIndex, window.scrollX, window.scrollY);
243
- // prep 'on painted' callback for scroll-to-offset action
244
- // this will fire once the page has rendered but before (loader?) kicks off.
245
- let onPaint;
246
- if (e.state != null) {
247
- onPaint = () => {
200
+ this.loadRoute().then(() => {
201
+ if (e.state != null) {
248
202
  this.historyIndex = e.state.index;
249
203
  const offset = scrollStack.getItem(e.state.index);
250
204
  if (offset !== undefined) {
251
205
  window.scrollTo(...offset);
252
206
  }
253
- };
254
- }
255
- this.loadRoute({ onPaint });
207
+ }
208
+ });
256
209
  });
257
210
  }
258
- onBeforeLeave(to) {
259
- const currentPage = this.currentPage.peek();
260
- if (!currentPage) {
261
- return true;
262
- }
263
- let config = currentPage.config ?? {};
264
- if (__DEV__) {
265
- if (this.pageRouteToConfig?.has(currentPage.route)) {
266
- config = this.pageRouteToConfig.get(currentPage.route);
267
- }
268
- }
269
- const onBeforeLeave = config.hooks?.onBeforeLeave;
270
- if (onBeforeLeave) {
271
- return runBeforeLeaveHooks(toArray(onBeforeLeave), { ...requestContext.current }, to, this.state.pathname);
272
- }
273
- return true;
274
- }
275
211
  getChildren() {
276
212
  const page = this.currentPage.value;
277
213
  if (!page)
@@ -288,8 +224,7 @@ export class FileRouterController {
288
224
  fileRouterRoute.current = null;
289
225
  fileRouterInstance.current = null;
290
226
  }
291
- async loadRoute(options) {
292
- const { transition: enableTransition = this.enableTransitions, isStatic404 = false, path = window.location.pathname, onPaint, } = options ?? {};
227
+ async loadRoute(path = window.location.pathname, props = {}, enableTransition = this.enableTransitions, isStatic404 = false) {
293
228
  this.abortController?.abort();
294
229
  const signal = (this.abortController = new AbortController()).signal;
295
230
  try {
@@ -308,22 +243,9 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
308
243
  routeMatch = _404Match;
309
244
  }
310
245
  const { route, pageEntry, params, routeSegments } = routeMatch;
311
- // Apply beforeEach guards before loading route
312
- const guardEntries = matchModules(this.guards, routeSegments);
313
- const guardModules = await Promise.all(guardEntries.map((entry) => entry.load()));
314
- const fromPath = this.state.pathname;
315
- const redirectPath = await runBeforeEachGuards(guardModules, { ...requestContext.current }, path, fromPath);
316
- // If redirect was requested, navigate to that path instead
317
- if (redirectPath !== null) {
318
- this.state.pathname = path;
319
- return this.navigate(redirectPath, {
320
- replace: true,
321
- transition: enableTransition,
322
- });
323
- }
324
246
  fileRouterRoute.current = route;
325
247
  const pagePromise = pageEntry.load();
326
- const layoutPromises = matchModules(this.layouts, routeSegments).map((layoutEntry) => layoutEntry.load());
248
+ const layoutPromises = matchLayouts(this.layouts, routeSegments).map((layoutEntry) => layoutEntry.load());
327
249
  const [page, ...layouts] = await Promise.all([
328
250
  pagePromise,
329
251
  ...layoutPromises,
@@ -348,67 +270,56 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
348
270
  config = this.pageRouteToConfig.get(route);
349
271
  }
350
272
  }
351
- const { loader, hooks } = config;
352
- if (hooks?.onBeforeEnter) {
353
- const redirectPath = await runBeforeEnterHooks(toArray(hooks.onBeforeEnter), requestContext, path, fromPath);
354
- if (redirectPath !== null) {
355
- this.state.pathname = path;
356
- return this.navigate(redirectPath, {
357
- replace: true,
358
- transition: enableTransition,
359
- });
360
- }
361
- }
362
- let props = {};
363
- if (!!loader) {
364
- props = {
365
- data: null,
366
- error: null,
367
- loading: true,
368
- };
369
- }
370
- if (loader?.static && !__DEV__) {
371
- const staticProps = page.__KIRU_STATIC_PROPS__?.[path];
372
- if (!staticProps) {
373
- // 404
374
- return this.loadRoute({
375
- path,
376
- transition: enableTransition,
377
- isStatic404: true,
378
- });
273
+ const { loader } = config;
274
+ if (loader) {
275
+ if (loader.mode !== "static" || __DEV__) {
276
+ // Check cache first if caching is enabled
277
+ let cachedData = null;
278
+ if (loader.mode !== "static" && loader.cache) {
279
+ const cacheKey = {
280
+ path: routerState.pathname,
281
+ params: routerState.params,
282
+ query: routerState.query,
283
+ };
284
+ cachedData = routerCache.current.get(cacheKey, loader.cache);
285
+ }
286
+ if (cachedData !== null) {
287
+ // Use cached data immediately - no loading state needed
288
+ props = {
289
+ ...props,
290
+ data: cachedData.value,
291
+ error: null,
292
+ loading: false,
293
+ };
294
+ }
295
+ else {
296
+ // No cached data - show loading state and load data
297
+ props = {
298
+ ...props,
299
+ loading: true,
300
+ data: null,
301
+ error: null,
302
+ };
303
+ this.loadRouteData(config, props, routerState, enableTransition);
304
+ }
379
305
  }
380
- const { data, error } = staticProps;
381
- props = error
382
- ? {
383
- data: null,
384
- error: new FileRouterDataLoadError(error),
385
- loading: false,
306
+ else {
307
+ const staticProps = page.__KIRU_STATIC_PROPS__?.[path];
308
+ if (!staticProps) {
309
+ return this.loadRoute(path, props, enableTransition, true);
386
310
  }
387
- : {
388
- data: data,
389
- error: null,
390
- loading: false,
391
- };
392
- }
393
- else if (!loader?.static && loader?.cache) {
394
- const cacheKey = {
395
- path: routerState.pathname,
396
- params: routerState.params,
397
- query: routerState.query,
398
- };
399
- const cachedData = routerCache.current.get(cacheKey, loader.cache);
400
- if (cachedData !== null) {
311
+ const { data, error } = staticProps;
401
312
  props = {
402
- data: cachedData.value,
403
- error: null,
313
+ ...props,
314
+ data: data,
315
+ error: error ? new FileRouterDataLoadError(error) : null,
404
316
  loading: false,
405
317
  };
406
318
  }
407
319
  }
408
- // loader transition must use the same id as page transition in order to prevent skipping it.
409
- let tId = transitionId++;
410
- return await handleStateTransition(enableTransition, tId, () => {
320
+ return handleStateTransition(signal, enableTransition, () => {
411
321
  this.state = routerState;
322
+ this.contextValue = this.createContextValue();
412
323
  this.currentPage.value = {
413
324
  component: page.default,
414
325
  config,
@@ -418,15 +329,6 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
418
329
  this.currentLayouts.value = layouts
419
330
  .filter((m) => typeof m.default === "function")
420
331
  .map((m) => m.default);
421
- nextIdle(() => {
422
- runAfterEachGuards(guardModules, { ...requestContext.current }, path, fromPath);
423
- if (props.loading) {
424
- this.loadRouteData(config, routerState, enableTransition, tId).then(() => signal.aborted || onPaint?.());
425
- }
426
- else {
427
- onPaint?.();
428
- }
429
- });
430
332
  });
431
333
  }
432
334
  catch (error) {
@@ -434,14 +336,14 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
434
336
  this.currentPage.value = null;
435
337
  }
436
338
  }
437
- async loadRouteData(config, routerState, enableTransition = this.enableTransitions, id = transitionId) {
339
+ async loadRouteData(config, props, routerState, enableTransition = this.enableTransitions) {
438
340
  const { loader } = config;
439
341
  // Load data from loader (cache check is now done earlier in loadRoute)
440
- return loader
441
- .load({ ...routerState, context: { ...requestContext.current } })
342
+ loader
343
+ .load(routerState)
442
344
  .then((data) => {
443
345
  // Cache the data if caching is enabled
444
- if (!loader.static && loader.cache) {
346
+ if (loader.mode !== "static" && loader.cache) {
445
347
  const cacheKey = {
446
348
  path: routerState.pathname,
447
349
  params: routerState.params,
@@ -462,8 +364,13 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
462
364
  .then((state) => {
463
365
  if (routerState.signal.aborted)
464
366
  return;
465
- const transition = (!loader.static && loader.transition) ?? enableTransition;
466
- return handleStateTransition(transition, id, () => (this.currentPageProps.value = state));
367
+ const transition = (loader.mode !== "static" && loader.transition) ?? enableTransition;
368
+ handleStateTransition(routerState.signal, transition, () => {
369
+ this.currentPageProps.value = {
370
+ ...props,
371
+ ...state,
372
+ };
373
+ });
467
374
  });
468
375
  }
469
376
  invalidate(...paths) {
@@ -478,13 +385,11 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
478
385
  const url = new URL(path, "http://localhost");
479
386
  const { hash: nextHash, pathname: nextPath } = url;
480
387
  const { hash: prevHash, pathname: prevPath } = this.state;
481
- if ((nextHash === prevHash && nextPath === prevPath) ||
482
- this.onBeforeLeave(prevPath) === false) {
388
+ if (nextHash === prevHash && nextPath === prevPath) {
483
389
  return;
484
390
  }
485
391
  this.updateHistoryState(path, options);
486
- const transition = options?.transition ?? this.enableTransitions;
487
- this.loadRoute({ transition }).then(() => {
392
+ this.loadRoute(void 0, void 0, options?.transition ?? this.enableTransitions).then(() => {
488
393
  if (nextHash !== prevHash) {
489
394
  window.dispatchEvent(new HashChangeEvent("hashchange"));
490
395
  }
@@ -507,7 +412,7 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
507
412
  const { pageEntry, route } = routeMatch;
508
413
  fileRouterRoute.current = route;
509
414
  const pagePromise = pageEntry.load();
510
- const layoutPromises = matchModules(this.layouts, route.split("/")).map((layoutEntry) => layoutEntry.load());
415
+ const layoutPromises = matchLayouts(this.layouts, route.split("/")).map((layoutEntry) => layoutEntry.load());
511
416
  await Promise.all([pagePromise, ...layoutPromises]);
512
417
  fileRouterRoute.current = null;
513
418
  }
@@ -542,10 +447,10 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
542
447
  window.history.replaceState({ ...window.history.state, index: this.historyIndex }, "", path);
543
448
  }
544
449
  else {
545
- const current = scrollStack.get();
546
450
  // if we've gone back and are now going forward, we need to
547
451
  // truncate the scroll stack so it doesn't just permanently grow.
548
452
  // this should keep it at the same length as the history stack.
453
+ const current = scrollStack.get();
549
454
  if (this.historyIndex < window.history.length - 1) {
550
455
  current.length = this.historyIndex;
551
456
  }
@@ -553,6 +458,32 @@ See https://kirujs.dev/docs/api/file-router#404 for more information.`);
553
458
  window.history.pushState({ ...window.history.state, index: ++this.historyIndex }, "", path);
554
459
  }
555
460
  }
461
+ createContextValue() {
462
+ const __this = this;
463
+ return {
464
+ get baseUrl() {
465
+ return __this.baseUrl;
466
+ },
467
+ invalidate: async (...paths) => {
468
+ if (this.invalidate(...paths)) {
469
+ return this.loadRoute(void 0, void 0, true);
470
+ }
471
+ },
472
+ get state() {
473
+ return { ...__this.state };
474
+ },
475
+ navigate: this.navigate.bind(this),
476
+ prefetchRouteModules: this.prefetchRouteModules.bind(this),
477
+ reload: async (options) => {
478
+ if (options?.invalidate ?? true) {
479
+ this.invalidate(this.state.pathname);
480
+ }
481
+ return this.loadRoute(void 0, void 0, options?.transition);
482
+ },
483
+ setQuery: this.setQuery.bind(this),
484
+ setHash: this.setHash.bind(this),
485
+ };
486
+ }
556
487
  }
557
488
  function buildQueryString(query) {
558
489
  const params = new URLSearchParams();
@@ -568,29 +499,19 @@ function buildQueryString(query) {
568
499
  }
569
500
  return params.toString();
570
501
  }
571
- async function handleStateTransition(enableTransition, id, callback) {
572
- if (currentTransition) {
573
- const { id: currentId, transition } = currentTransition;
574
- // for cross-page navigations, we skip any existing transitions.
575
- // otherwise (eg. loaders), we wait for the existing transition to finish
576
- if (id !== currentId) {
577
- transition.skipTransition();
578
- }
579
- await transition.finished;
580
- }
502
+ async function handleStateTransition(signal, enableTransition, callback) {
581
503
  if (!enableTransition || typeof document.startViewTransition !== "function") {
582
504
  return new Promise((resolve) => {
583
505
  callback();
584
506
  nextIdle(resolve);
585
507
  });
586
508
  }
587
- const transition = document.startViewTransition(() => {
509
+ const vt = document.startViewTransition(() => {
588
510
  callback();
589
511
  flushSync();
590
512
  });
591
- currentTransition = { id, transition };
592
- await transition.finished;
593
- currentTransition = null;
513
+ signal.addEventListener("abort", () => vt.skipTransition());
514
+ await vt.ready;
594
515
  }
595
516
  function validateRoutes(pageMap) {
596
517
  const routeConflicts = [];