@fluixi/core 1.0.0-alpha.94 → 1.0.0-alpha.95

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 (51) hide show
  1. package/LICENSE +1 -1
  2. package/dist/cdn/core.global.js +2 -2
  3. package/dist/src/cdn/{chunk-7XM7Q5VR.mjs → chunk-IFONZJWJ.mjs} +93 -2
  4. package/dist/src/cdn/core.cjs +99 -3
  5. package/dist/src/cdn/core.mjs +3 -3
  6. package/dist/src/cdn/{router-VOY43YNM.mjs → router-TU5CPI54.mjs} +1 -1
  7. package/dist/src/index.cjs +95 -4
  8. package/dist/src/index.mjs +95 -4
  9. package/dist/src/lib/client/{chunk-TSXM2PNY.mjs → chunk-AHNP3IWU.mjs} +1 -1
  10. package/dist/src/lib/client/index.cjs +100 -4
  11. package/dist/src/lib/client/index.mjs +4 -4
  12. package/dist/src/lib/client/{router-BDVPLLYX.mjs → router-5C6FQJQ4.mjs} +95 -4
  13. package/dist/src/lib/core.cjs +94 -3
  14. package/dist/src/lib/core.mjs +94 -3
  15. package/dist/src/lib/i18n/index.cjs +1 -1
  16. package/dist/src/lib/i18n/index.mjs +1 -1
  17. package/dist/src/lib/index.cjs +1 -1
  18. package/dist/src/lib/index.mjs +1 -1
  19. package/dist/src/lib/jsx-runtime/index.cjs +1 -1
  20. package/dist/src/lib/jsx-runtime/index.mjs +1 -1
  21. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -1
  22. package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -1
  23. package/dist/src/lib/plugins/index.cjs +1 -1
  24. package/dist/src/lib/plugins/index.mjs +1 -1
  25. package/dist/src/lib/render/index.cjs +1 -1
  26. package/dist/src/lib/render/index.mjs +1 -1
  27. package/dist/src/lib/render/versions.cjs +1 -1
  28. package/dist/src/lib/render/versions.mjs +1 -1
  29. package/dist/src/lib/router/index.cjs +94 -3
  30. package/dist/src/lib/router/index.d.ts.map +1 -1
  31. package/dist/src/lib/router/index.js +55 -0
  32. package/dist/src/lib/router/index.mjs +94 -3
  33. package/dist/src/lib/router/scroll.cjs +79 -0
  34. package/dist/src/lib/router/scroll.d.ts +19 -0
  35. package/dist/src/lib/router/scroll.d.ts.map +1 -0
  36. package/dist/src/lib/router/scroll.js +68 -0
  37. package/dist/src/lib/router/scroll.mjs +58 -0
  38. package/dist/src/lib/server/index.cjs +1 -1
  39. package/dist/src/lib/server/index.mjs +1 -1
  40. package/dist/src/lib/storage/index.cjs +1 -1
  41. package/dist/src/lib/storage/index.mjs +1 -1
  42. package/dist/src/routes.cjs +1 -1
  43. package/dist/src/routes.mjs +1 -1
  44. package/dist/src/utils.cjs +1 -1
  45. package/dist/src/utils.mjs +1 -1
  46. package/dist/src/version.generated.cjs +1 -1
  47. package/dist/src/version.generated.d.ts +1 -1
  48. package/dist/src/version.generated.js +1 -1
  49. package/dist/src/version.generated.mjs +1 -1
  50. package/dist/tsconfig.lib.tsbuildinfo +1 -1
  51. package/package.json +16 -16
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/i18n/index.ts
4
4
  import { createSignal } from "@fluixi/reactive/signal";
@@ -114,7 +114,7 @@ var import_signal6 = require("@fluixi/reactive/signal");
114
114
  var import_dom = require("@fluixi/dom");
115
115
 
116
116
  // src/version.generated.ts
117
- var VERSION = "1.0.0-alpha.94";
117
+ var VERSION = "1.0.0-alpha.95";
118
118
 
119
119
  // src/lib/render/versions.ts
120
120
  var import_dom2 = require("@fluixi/dom");
@@ -44,7 +44,7 @@ import { createRoot as createRoot2 } from "@fluixi/reactive/signal";
44
44
  import { registerCoreVersion } from "@fluixi/dom";
45
45
 
46
46
  // src/version.generated.ts
47
- var VERSION = "1.0.0-alpha.94";
47
+ var VERSION = "1.0.0-alpha.95";
48
48
 
49
49
  // src/lib/render/versions.ts
50
50
  import { stampVersions, warnOnVersionSkew, versions } from "@fluixi/dom";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/jsx-runtime/index.ts
4
4
  export * from "@fluixi/jsx/jsx-runtime";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/jsx-runtime/jsx-dev-runtime.ts
4
4
  export * from "@fluixi/jsx/jsx-dev-runtime";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __create = Object.create;
4
4
  var __defProp = Object.defineProperty;
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/plugins/vite.ts
4
4
  import { fluixi, createVitePlugin } from "@fluixi/vite-plugin";
@@ -63,7 +63,7 @@ var import_signal6 = require("@fluixi/reactive/signal");
63
63
  var import_dom = require("@fluixi/dom");
64
64
 
65
65
  // src/version.generated.ts
66
- var VERSION = "1.0.0-alpha.94";
66
+ var VERSION = "1.0.0-alpha.95";
67
67
 
68
68
  // src/lib/render/versions.ts
69
69
  var import_dom2 = require("@fluixi/dom");
@@ -6,7 +6,7 @@ import { createRoot as createRoot2 } from "@fluixi/reactive/signal";
6
6
  import { registerCoreVersion } from "@fluixi/dom";
7
7
 
8
8
  // src/version.generated.ts
9
- var VERSION = "1.0.0-alpha.94";
9
+ var VERSION = "1.0.0-alpha.95";
10
10
 
11
11
  // src/lib/render/versions.ts
12
12
  import { stampVersions, warnOnVersionSkew, versions } from "@fluixi/dom";
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(versions_exports);
28
28
  var import_dom = require("@fluixi/dom");
29
29
 
30
30
  // src/version.generated.ts
31
- var VERSION = "1.0.0-alpha.94";
31
+ var VERSION = "1.0.0-alpha.95";
32
32
 
33
33
  // src/lib/render/versions.ts
34
34
  var import_dom2 = require("@fluixi/dom");
@@ -2,7 +2,7 @@
2
2
  import { registerCoreVersion } from "@fluixi/dom";
3
3
 
4
4
  // src/version.generated.ts
5
- var VERSION = "1.0.0-alpha.94";
5
+ var VERSION = "1.0.0-alpha.95";
6
6
 
7
7
  // src/lib/render/versions.ts
8
8
  import { stampVersions, warnOnVersionSkew, versions } from "@fluixi/dom";
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
  "use strict";
3
3
  var __defProp = Object.defineProperty;
4
4
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
@@ -113,6 +113,64 @@ var import_dom3 = require("@fluixi/dom");
113
113
  var import_signal6 = require("@fluixi/reactive/signal");
114
114
  var import_object = require("@fluixi/utils/object");
115
115
  var import_compare = require("@fluixi/utils/compare");
116
+
117
+ // src/lib/router/scroll.ts
118
+ var STORE = "fx:scroll";
119
+ var KEEP = 100;
120
+ function keepScroll(initial) {
121
+ const read2 = () => {
122
+ try {
123
+ return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
124
+ } catch {
125
+ return {};
126
+ }
127
+ };
128
+ const positions = read2();
129
+ const write = () => {
130
+ const keys = Object.keys(positions);
131
+ for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
132
+ try {
133
+ sessionStorage.setItem(STORE, JSON.stringify(positions));
134
+ } catch {
135
+ }
136
+ };
137
+ let current = initial.key;
138
+ const save = () => {
139
+ if (current === void 0) return;
140
+ delete positions[current];
141
+ positions[current] = window.scrollY;
142
+ write();
143
+ };
144
+ const restoration = history.scrollRestoration;
145
+ history.scrollRestoration = "manual";
146
+ window.addEventListener("pagehide", save);
147
+ const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
148
+ const toHash = (hash) => {
149
+ if (!hash || hash === "#") return false;
150
+ const target = document.getElementById(decodeURIComponent(hash.slice(1)));
151
+ target?.scrollIntoView({ behavior: "instant" });
152
+ return target !== null;
153
+ };
154
+ return {
155
+ leave: save,
156
+ arrive(location, from) {
157
+ current = location.key;
158
+ if (location.action === "pop" || from === void 0) {
159
+ const y = location.key === void 0 ? void 0 : positions[location.key];
160
+ if (y !== void 0) to(y);
161
+ return;
162
+ }
163
+ if (location.action === "replace" && location.pathname === from.pathname) return;
164
+ if (!toHash(location.hash)) to(0);
165
+ },
166
+ dispose() {
167
+ window.removeEventListener("pagehide", save);
168
+ history.scrollRestoration = restoration;
169
+ }
170
+ };
171
+ }
172
+
173
+ // src/lib/router/index.ts
116
174
  var import_router = require("@fluixi/router");
117
175
 
118
176
  // src/lib/router/data.ts
@@ -383,9 +441,20 @@ function renderLayer(m, depth, base) {
383
441
  return router ? router.trackLoad(result) : result;
384
442
  });
385
443
  (0, import_signal5.onCleanup)(onRevalidate(() => void refetch()));
444
+ let loadedFor = (0, import_signal5.untrack)(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
445
+ (0, import_signal5.createEffect)(() => {
446
+ const now = base.matched()[depth];
447
+ if (now?.route !== m.route) return;
448
+ const params = JSON.stringify(now.params ?? {});
449
+ if (params === loadedFor) return;
450
+ loadedFor = params;
451
+ (0, import_signal5.untrack)(() => void refetch());
452
+ });
386
453
  data = () => {
387
454
  const error = resource.error;
388
455
  if (error !== void 0 && error !== null) throw error;
456
+ const r = resource;
457
+ if (r.state === "refreshing") return r.latest;
389
458
  return resource();
390
459
  };
391
460
  Object.defineProperty(data, "loading", { get: () => resource.loading });
@@ -490,16 +559,19 @@ function buildDefaultNotFound() {
490
559
  }
491
560
  var pendingTransitionMode;
492
561
  function Router(props) {
493
- const history = props.history ?? (0, import_router.createBrowserHistory)();
562
+ const history2 = props.history ?? (0, import_router.createBrowserHistory)();
494
563
  const router = (0, import_router.createRouter)({
495
564
  routes: props.routes,
496
565
  base: props.base,
497
- history
566
+ history: history2
498
567
  });
499
568
  const [state, setState] = (0, import_signal5.createSignal)(router.state());
500
569
  const [navigating, setNavigating] = (0, import_signal5.createSignal)(false);
501
570
  const [loads, setLoads] = (0, import_signal5.createSignal)(0);
502
571
  let navigationId = 0;
572
+ const scroll = history2.window ? keepScroll(router.state().location) : void 0;
573
+ let arriving = scroll ? { id: 0, location: router.state().location, from: void 0 } : null;
574
+ const [arrived, setArrived] = (0, import_signal5.createSignal)(0);
503
575
  const takeMode = () => {
504
576
  const mode = pendingTransitionMode ?? (props.transition ?? "auto");
505
577
  pendingTransitionMode = void 0;
@@ -509,6 +581,10 @@ function Router(props) {
509
581
  const id = ++navigationId;
510
582
  const mode = takeMode();
511
583
  setNavigating(true);
584
+ if (scroll) {
585
+ scroll.leave();
586
+ arriving = { id, location: next.location, from: (0, import_signal5.untrack)(state).location };
587
+ }
512
588
  const prepared = prepareComponents(
513
589
  (next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
514
590
  );
@@ -516,6 +592,7 @@ function Router(props) {
516
592
  setState(next);
517
593
  const flushed = (0, import_signal5.flush)();
518
594
  if (id === navigationId) setNavigating(false);
595
+ if (scroll) setArrived(id);
519
596
  return flushed;
520
597
  };
521
598
  if (!prepared) {
@@ -529,6 +606,7 @@ function Router(props) {
529
606
  });
530
607
  (0, import_signal5.onCleanup)(() => {
531
608
  unsub();
609
+ scroll?.dispose();
532
610
  router.destroy();
533
611
  navigationId++;
534
612
  });
@@ -551,6 +629,19 @@ function Router(props) {
551
629
  return result;
552
630
  }
553
631
  };
632
+ if (scroll) {
633
+ const nextFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
634
+ (0, import_signal5.createEffect)(() => {
635
+ const id = arrived();
636
+ if (ctx.isRouting()) return;
637
+ const next = arriving;
638
+ if (!next || next.id !== id || id !== navigationId) return;
639
+ arriving = null;
640
+ nextFrame(() => {
641
+ if (id === navigationId) scroll.arrive(next.location, next.from);
642
+ });
643
+ });
644
+ }
554
645
  const root = {
555
646
  depth: -1,
556
647
  matched,
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/index.ts"],"names":[],"mappings":"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"}
@@ -19,6 +19,7 @@ import { insert, createComponent, createNativeElement, setAttribute, } from '@fl
19
19
  import { createContext, useContext } from '@fluixi/reactive/signal';
20
20
  import { get } from '@fluixi/utils/object';
21
21
  import { deepEqual } from '@fluixi/utils/compare';
22
+ import { keepScroll } from './scroll.js';
22
23
  import { createRouter as createCoreRouter, createBrowserHistory, matchRoutes, matchPath, } from '@fluixi/router';
23
24
  const RouterContext = createContext(undefined, 'router');
24
25
  const OutletContext = createContext(undefined, 'outlet');
@@ -61,6 +62,21 @@ function renderLayer(m, depth, base) {
61
62
  });
62
63
  // A revalidated cache entry: load again. The page stays on screen with its current data.
63
64
  onCleanup(onRevalidate(() => void refetch()));
65
+ // A navigation that changes only this layer's params keeps the layer, so nothing else
66
+ // would load its data for them. Compared by value: `matched` is rebuilt on every navigation.
67
+ let loadedFor = untrack(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
68
+ createEffect(() => {
69
+ const now = base.matched()[depth];
70
+ // Another route at this depth: this page is on its way out, kept only until the next
71
+ // one has its data, and the new params are not for it.
72
+ if (now?.route !== m.route)
73
+ return;
74
+ const params = JSON.stringify(now.params ?? {});
75
+ if (params === loadedFor)
76
+ return;
77
+ loadedFor = params;
78
+ untrack(() => void refetch());
79
+ });
64
80
  // A failed load throws where the page reads it, so the nearest ErrorBoundary shows it.
65
81
  // A resource reads as undefined once it has failed, which left the page empty and gave
66
82
  // nothing a chance to catch the error.
@@ -68,6 +84,12 @@ function renderLayer(m, depth, base) {
68
84
  const error = resource.error;
69
85
  if (error !== undefined && error !== null)
70
86
  throw error;
87
+ // Loading again (new params, a revalidation): the page keeps its current data. Reading
88
+ // the resource itself would suspend, and a Suspense boundary above would take the page
89
+ // out of the document until the data arrives, losing what the reader had in it.
90
+ const r = resource;
91
+ if (r.state === 'refreshing')
92
+ return r.latest;
71
93
  return resource();
72
94
  };
73
95
  Object.defineProperty(data, 'loading', { get: () => resource.loading });
@@ -250,6 +272,11 @@ export function Router(props) {
250
272
  * the page would show B.
251
273
  */
252
274
  let navigationId = 0;
275
+ // The window's scroll, for a browser history: where each navigation lands once its page is
276
+ // shown. `arrived` is the navigation whose page was last committed.
277
+ const scroll = history.window ? keepScroll(router.state().location) : undefined;
278
+ let arriving = scroll ? { id: 0, location: router.state().location, from: undefined } : null;
279
+ const [arrived, setArrived] = createSignal(0);
253
280
  /**
254
281
  * How to present the next commit, set by `useNavigate` immediately before it calls
255
282
  * into the core router.
@@ -268,6 +295,10 @@ export function Router(props) {
268
295
  const id = ++navigationId;
269
296
  const mode = takeMode();
270
297
  setNavigating(true);
298
+ if (scroll) {
299
+ scroll.leave();
300
+ arriving = { id, location: next.location, from: untrack(state).location };
301
+ }
271
302
  // Load the modules the next route needs before anything is torn down, so a lazy
272
303
  // route renders straight through instead of suspending into a fallback with the
273
304
  // old page already gone.
@@ -280,6 +311,8 @@ export function Router(props) {
280
311
  const flushed = flush();
281
312
  if (id === navigationId)
282
313
  setNavigating(false);
314
+ if (scroll)
315
+ setArrived(id);
283
316
  return flushed;
284
317
  };
285
318
  if (!prepared) {
@@ -296,6 +329,7 @@ export function Router(props) {
296
329
  });
297
330
  onCleanup(() => {
298
331
  unsub();
332
+ scroll?.dispose();
299
333
  router.destroy();
300
334
  // Anything still preparing is now stale, so nothing can commit into a torn-down
301
335
  // router.
@@ -319,6 +353,27 @@ export function Router(props) {
319
353
  return result;
320
354
  },
321
355
  };
356
+ // Scroll once the page is on screen: after its modules and its data, which is when the
357
+ // router stops routing, and a frame later, before that frame is painted. The page's own
358
+ // effects fill it in after the router's (an article set through innerHTML), and a scroll
359
+ // into a page not yet filled is cut short to its height. A newer navigation takes over
360
+ // from one still loading.
361
+ if (scroll) {
362
+ const nextFrame = typeof requestAnimationFrame === 'function' ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
363
+ createEffect(() => {
364
+ const id = arrived();
365
+ if (ctx.isRouting())
366
+ return;
367
+ const next = arriving;
368
+ if (!next || next.id !== id || id !== navigationId)
369
+ return;
370
+ arriving = null;
371
+ nextFrame(() => {
372
+ if (id === navigationId)
373
+ scroll.arrive(next.location, next.from);
374
+ });
375
+ });
376
+ }
322
377
  // Render depth 0 (a virtual parent at depth -1 so the root reuses the same path).
323
378
  const root = {
324
379
  depth: -1,
@@ -1,4 +1,4 @@
1
- /*! @fluixi/core v1.0.0-alpha.94 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
1
+ /*! @fluixi/core v1.0.0-alpha.95 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
2
2
 
3
3
  // src/lib/router/index.ts
4
4
  import {
@@ -72,6 +72,64 @@ import {
72
72
  import { createContext as createContext2, useContext as useContext2 } from "@fluixi/reactive/signal";
73
73
  import { get } from "@fluixi/utils/object";
74
74
  import { deepEqual } from "@fluixi/utils/compare";
75
+
76
+ // src/lib/router/scroll.ts
77
+ var STORE = "fx:scroll";
78
+ var KEEP = 100;
79
+ function keepScroll(initial) {
80
+ const read2 = () => {
81
+ try {
82
+ return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
83
+ } catch {
84
+ return {};
85
+ }
86
+ };
87
+ const positions = read2();
88
+ const write = () => {
89
+ const keys = Object.keys(positions);
90
+ for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
91
+ try {
92
+ sessionStorage.setItem(STORE, JSON.stringify(positions));
93
+ } catch {
94
+ }
95
+ };
96
+ let current = initial.key;
97
+ const save = () => {
98
+ if (current === void 0) return;
99
+ delete positions[current];
100
+ positions[current] = window.scrollY;
101
+ write();
102
+ };
103
+ const restoration = history.scrollRestoration;
104
+ history.scrollRestoration = "manual";
105
+ window.addEventListener("pagehide", save);
106
+ const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
107
+ const toHash = (hash) => {
108
+ if (!hash || hash === "#") return false;
109
+ const target = document.getElementById(decodeURIComponent(hash.slice(1)));
110
+ target?.scrollIntoView({ behavior: "instant" });
111
+ return target !== null;
112
+ };
113
+ return {
114
+ leave: save,
115
+ arrive(location, from) {
116
+ current = location.key;
117
+ if (location.action === "pop" || from === void 0) {
118
+ const y = location.key === void 0 ? void 0 : positions[location.key];
119
+ if (y !== void 0) to(y);
120
+ return;
121
+ }
122
+ if (location.action === "replace" && location.pathname === from.pathname) return;
123
+ if (!toHash(location.hash)) to(0);
124
+ },
125
+ dispose() {
126
+ window.removeEventListener("pagehide", save);
127
+ history.scrollRestoration = restoration;
128
+ }
129
+ };
130
+ }
131
+
132
+ // src/lib/router/index.ts
75
133
  import {
76
134
  createRouter as createCoreRouter,
77
135
  createBrowserHistory,
@@ -363,9 +421,20 @@ function renderLayer(m, depth, base) {
363
421
  return router ? router.trackLoad(result) : result;
364
422
  });
365
423
  onCleanup(onRevalidate(() => void refetch()));
424
+ let loadedFor = untrack2(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
425
+ createEffect(() => {
426
+ const now = base.matched()[depth];
427
+ if (now?.route !== m.route) return;
428
+ const params = JSON.stringify(now.params ?? {});
429
+ if (params === loadedFor) return;
430
+ loadedFor = params;
431
+ untrack2(() => void refetch());
432
+ });
366
433
  data = () => {
367
434
  const error = resource.error;
368
435
  if (error !== void 0 && error !== null) throw error;
436
+ const r = resource;
437
+ if (r.state === "refreshing") return r.latest;
369
438
  return resource();
370
439
  };
371
440
  Object.defineProperty(data, "loading", { get: () => resource.loading });
@@ -470,16 +539,19 @@ function buildDefaultNotFound() {
470
539
  }
471
540
  var pendingTransitionMode;
472
541
  function Router(props) {
473
- const history = props.history ?? createBrowserHistory();
542
+ const history2 = props.history ?? createBrowserHistory();
474
543
  const router = createCoreRouter({
475
544
  routes: props.routes,
476
545
  base: props.base,
477
- history
546
+ history: history2
478
547
  });
479
548
  const [state, setState] = createSignal2(router.state());
480
549
  const [navigating, setNavigating] = createSignal2(false);
481
550
  const [loads, setLoads] = createSignal2(0);
482
551
  let navigationId = 0;
552
+ const scroll = history2.window ? keepScroll(router.state().location) : void 0;
553
+ let arriving = scroll ? { id: 0, location: router.state().location, from: void 0 } : null;
554
+ const [arrived, setArrived] = createSignal2(0);
483
555
  const takeMode = () => {
484
556
  const mode = pendingTransitionMode ?? (props.transition ?? "auto");
485
557
  pendingTransitionMode = void 0;
@@ -489,6 +561,10 @@ function Router(props) {
489
561
  const id = ++navigationId;
490
562
  const mode = takeMode();
491
563
  setNavigating(true);
564
+ if (scroll) {
565
+ scroll.leave();
566
+ arriving = { id, location: next.location, from: untrack2(state).location };
567
+ }
492
568
  const prepared = prepareComponents(
493
569
  (next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
494
570
  );
@@ -496,6 +572,7 @@ function Router(props) {
496
572
  setState(next);
497
573
  const flushed = flush();
498
574
  if (id === navigationId) setNavigating(false);
575
+ if (scroll) setArrived(id);
499
576
  return flushed;
500
577
  };
501
578
  if (!prepared) {
@@ -509,6 +586,7 @@ function Router(props) {
509
586
  });
510
587
  onCleanup(() => {
511
588
  unsub();
589
+ scroll?.dispose();
512
590
  router.destroy();
513
591
  navigationId++;
514
592
  });
@@ -531,6 +609,19 @@ function Router(props) {
531
609
  return result;
532
610
  }
533
611
  };
612
+ if (scroll) {
613
+ const nextFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
614
+ createEffect(() => {
615
+ const id = arrived();
616
+ if (ctx.isRouting()) return;
617
+ const next = arriving;
618
+ if (!next || next.id !== id || id !== navigationId) return;
619
+ arriving = null;
620
+ nextFrame(() => {
621
+ if (id === navigationId) scroll.arrive(next.location, next.from);
622
+ });
623
+ });
624
+ }
534
625
  const root = {
535
626
  depth: -1,
536
627
  matched,
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/lib/router/scroll.ts
21
+ var scroll_exports = {};
22
+ __export(scroll_exports, {
23
+ keepScroll: () => keepScroll
24
+ });
25
+ module.exports = __toCommonJS(scroll_exports);
26
+ var STORE = "fx:scroll";
27
+ var KEEP = 100;
28
+ function keepScroll(initial) {
29
+ const read = () => {
30
+ try {
31
+ return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
32
+ } catch {
33
+ return {};
34
+ }
35
+ };
36
+ const positions = read();
37
+ const write = () => {
38
+ const keys = Object.keys(positions);
39
+ for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
40
+ try {
41
+ sessionStorage.setItem(STORE, JSON.stringify(positions));
42
+ } catch {
43
+ }
44
+ };
45
+ let current = initial.key;
46
+ const save = () => {
47
+ if (current === void 0) return;
48
+ delete positions[current];
49
+ positions[current] = window.scrollY;
50
+ write();
51
+ };
52
+ const restoration = history.scrollRestoration;
53
+ history.scrollRestoration = "manual";
54
+ window.addEventListener("pagehide", save);
55
+ const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
56
+ const toHash = (hash) => {
57
+ if (!hash || hash === "#") return false;
58
+ const target = document.getElementById(decodeURIComponent(hash.slice(1)));
59
+ target?.scrollIntoView({ behavior: "instant" });
60
+ return target !== null;
61
+ };
62
+ return {
63
+ leave: save,
64
+ arrive(location, from) {
65
+ current = location.key;
66
+ if (location.action === "pop" || from === void 0) {
67
+ const y = location.key === void 0 ? void 0 : positions[location.key];
68
+ if (y !== void 0) to(y);
69
+ return;
70
+ }
71
+ if (location.action === "replace" && location.pathname === from.pathname) return;
72
+ if (!toHash(location.hash)) to(0);
73
+ },
74
+ dispose() {
75
+ window.removeEventListener("pagehide", save);
76
+ history.scrollRestoration = restoration;
77
+ }
78
+ };
79
+ }
@@ -0,0 +1,19 @@
1
+ /**
2
+ * The window's scroll across client navigations, as a full page load would leave it: a new
3
+ * page starts at the top, or at its `#hash`; back and forward return to where the reader
4
+ * was; a reload stays where it was.
5
+ *
6
+ * The router keeps the current page on screen until the next one has loaded its data, so
7
+ * the browser's own restoration, applied when the URL changes, would scroll the page being
8
+ * left. The router turns it off and scrolls once the next page is shown.
9
+ */
10
+ import type { RouterLocation } from '@fluixi/router';
11
+ export interface ScrollKeeper {
12
+ /** A navigation started: remember where the entry being left was scrolled to. */
13
+ leave(): void;
14
+ /** The page for `location` is on screen. */
15
+ arrive(location: RouterLocation, from: RouterLocation | undefined): void;
16
+ dispose(): void;
17
+ }
18
+ export declare function keepScroll(initial: RouterLocation): ScrollKeeper;
19
+ //# sourceMappingURL=scroll.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scroll.d.ts","sourceRoot":"","sources":["../../../../src/lib/router/scroll.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAMrD,MAAM,WAAW,YAAY;IAC3B,iFAAiF;IACjF,KAAK,IAAI,IAAI,CAAC;IACd,4CAA4C;IAC5C,MAAM,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,GAAG,SAAS,GAAG,IAAI,CAAC;IACzE,OAAO,IAAI,IAAI,CAAC;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,cAAc,GAAG,YAAY,CA4DhE"}