@fluixi/core 1.0.0-alpha.94 → 1.0.0-alpha.96
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.
- package/LICENSE +1 -1
- package/dist/cdn/core.global.js +2 -2
- package/dist/src/cdn/{chunk-7XM7Q5VR.mjs → chunk-RKBFEFZP.mjs} +125 -10
- package/dist/src/cdn/core.cjs +132 -12
- package/dist/src/cdn/core.mjs +4 -4
- package/dist/src/cdn/{router-VOY43YNM.mjs → router-V2THK27H.mjs} +3 -3
- package/dist/src/index.cjs +122 -7
- package/dist/src/index.mjs +122 -7
- package/dist/src/lib/client/{chunk-TSXM2PNY.mjs → chunk-RNRJHQFG.mjs} +1 -1
- package/dist/src/lib/client/index.cjs +133 -13
- package/dist/src/lib/client/index.d.ts.map +1 -1
- package/dist/src/lib/client/index.js +4 -1
- package/dist/src/lib/client/index.mjs +5 -5
- package/dist/src/lib/client/{router-BDVPLLYX.mjs → router-F3Y4BIVJ.mjs} +127 -12
- package/dist/src/lib/core.cjs +121 -6
- package/dist/src/lib/core.mjs +121 -6
- package/dist/src/lib/i18n/index.cjs +1 -1
- package/dist/src/lib/i18n/index.mjs +1 -1
- package/dist/src/lib/index.cjs +1 -1
- package/dist/src/lib/index.mjs +1 -1
- package/dist/src/lib/isomorphic.cjs +1 -1
- package/dist/src/lib/isomorphic.d.ts +5 -0
- package/dist/src/lib/isomorphic.d.ts.map +1 -1
- package/dist/src/lib/isomorphic.js +1 -1
- package/dist/src/lib/isomorphic.mjs +1 -1
- package/dist/src/lib/jsx-runtime/index.cjs +1 -1
- package/dist/src/lib/jsx-runtime/index.mjs +1 -1
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.cjs +1 -1
- package/dist/src/lib/jsx-runtime/jsx-dev-runtime.mjs +1 -1
- package/dist/src/lib/plugins/index.cjs +1 -1
- package/dist/src/lib/plugins/index.mjs +1 -1
- package/dist/src/lib/render/index.cjs +1 -1
- package/dist/src/lib/render/index.mjs +1 -1
- package/dist/src/lib/render/versions.cjs +1 -1
- package/dist/src/lib/render/versions.mjs +1 -1
- package/dist/src/lib/router/data.cjs +4 -4
- package/dist/src/lib/router/data.d.ts.map +1 -1
- package/dist/src/lib/router/data.js +9 -8
- package/dist/src/lib/router/data.mjs +4 -4
- package/dist/src/lib/router/index.cjs +126 -11
- package/dist/src/lib/router/index.d.ts +8 -5
- package/dist/src/lib/router/index.d.ts.map +1 -1
- package/dist/src/lib/router/index.js +94 -7
- package/dist/src/lib/router/index.mjs +126 -11
- package/dist/src/lib/router/scroll.cjs +79 -0
- package/dist/src/lib/router/scroll.d.ts +19 -0
- package/dist/src/lib/router/scroll.d.ts.map +1 -0
- package/dist/src/lib/router/scroll.js +68 -0
- package/dist/src/lib/router/scroll.mjs +58 -0
- package/dist/src/lib/server/index.cjs +1 -1
- package/dist/src/lib/server/index.mjs +1 -1
- package/dist/src/lib/storage/index.cjs +1 -1
- package/dist/src/lib/storage/index.mjs +1 -1
- package/dist/src/routes.cjs +1 -1
- package/dist/src/routes.mjs +1 -1
- package/dist/src/utils.cjs +1 -1
- package/dist/src/utils.mjs +1 -1
- package/dist/src/version.generated.cjs +1 -1
- package/dist/src/version.generated.d.ts +1 -1
- package/dist/src/version.generated.js +1 -1
- package/dist/src/version.generated.mjs +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +16 -16
|
@@ -114,7 +114,10 @@ export async function startClient(App, options = {}) {
|
|
|
114
114
|
// component. Called directly, the root is the one component the runtime never hears
|
|
115
115
|
// about: nothing holds its return value, so no node is made and a graph of the
|
|
116
116
|
// application starts at whatever the root happened to render.
|
|
117
|
-
|
|
117
|
+
// Built inside hydrate, not as its argument: a memo runs when it is made, and made out
|
|
118
|
+
// here the root would render before hydration is on, without the key scope the server
|
|
119
|
+
// opened for it. Every key below would then be one level off and nothing adopted by key.
|
|
120
|
+
domHydrate(() => rootOf(App), container);
|
|
118
121
|
// Handlers are now wired (delegated $$listeners attach during the hydration
|
|
119
122
|
// render): replay any events the user fired before hydration.
|
|
120
123
|
replayEvents();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
/*! @fluixi/core v1.0.0-alpha.
|
|
2
|
-
import "./chunk-
|
|
1
|
+
/*! @fluixi/core v1.0.0-alpha.96 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
|
+
import "./chunk-RNRJHQFG.mjs";
|
|
3
3
|
|
|
4
4
|
// src/lib/client/index.ts
|
|
5
5
|
import {
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { registerCoreVersion } from "@fluixi/dom";
|
|
16
16
|
|
|
17
17
|
// src/version.generated.ts
|
|
18
|
-
var VERSION = "1.0.0-alpha.
|
|
18
|
+
var VERSION = "1.0.0-alpha.96";
|
|
19
19
|
|
|
20
20
|
// src/lib/render/versions.ts
|
|
21
21
|
import { stampVersions, warnOnVersionSkew, versions } from "@fluixi/dom";
|
|
@@ -246,12 +246,12 @@ async function startClient(App, options = {}) {
|
|
|
246
246
|
beginAppHydration();
|
|
247
247
|
try {
|
|
248
248
|
if (options.routes && options.routes.length) {
|
|
249
|
-
const { preloadRoutes } = await import("./router-
|
|
249
|
+
const { preloadRoutes } = await import("./router-F3Y4BIVJ.mjs");
|
|
250
250
|
await preloadRoutes(options.routes, window.location.pathname);
|
|
251
251
|
}
|
|
252
252
|
deserializeHydrationData();
|
|
253
253
|
setHydrating(true);
|
|
254
|
-
domHydrate(rootOf(App), container);
|
|
254
|
+
domHydrate(() => rootOf(App), container);
|
|
255
255
|
replayEvents();
|
|
256
256
|
} finally {
|
|
257
257
|
endAppHydration();
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
/*! @fluixi/core v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/core v1.0.0-alpha.96 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
import {
|
|
3
3
|
lazy
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-RNRJHQFG.mjs";
|
|
5
5
|
|
|
6
6
|
// src/lib/router/index.ts
|
|
7
7
|
import {
|
|
@@ -75,6 +75,64 @@ import {
|
|
|
75
75
|
import { createContext as createContext2, useContext as useContext2 } from "@fluixi/reactive/signal";
|
|
76
76
|
import { get } from "@fluixi/utils/object";
|
|
77
77
|
import { deepEqual } from "@fluixi/utils/compare";
|
|
78
|
+
|
|
79
|
+
// src/lib/router/scroll.ts
|
|
80
|
+
var STORE = "fx:scroll";
|
|
81
|
+
var KEEP = 100;
|
|
82
|
+
function keepScroll(initial) {
|
|
83
|
+
const read2 = () => {
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
|
|
86
|
+
} catch {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
};
|
|
90
|
+
const positions = read2();
|
|
91
|
+
const write = () => {
|
|
92
|
+
const keys = Object.keys(positions);
|
|
93
|
+
for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
|
|
94
|
+
try {
|
|
95
|
+
sessionStorage.setItem(STORE, JSON.stringify(positions));
|
|
96
|
+
} catch {
|
|
97
|
+
}
|
|
98
|
+
};
|
|
99
|
+
let current = initial.key;
|
|
100
|
+
const save = () => {
|
|
101
|
+
if (current === void 0) return;
|
|
102
|
+
delete positions[current];
|
|
103
|
+
positions[current] = window.scrollY;
|
|
104
|
+
write();
|
|
105
|
+
};
|
|
106
|
+
const restoration = history.scrollRestoration;
|
|
107
|
+
history.scrollRestoration = "manual";
|
|
108
|
+
window.addEventListener("pagehide", save);
|
|
109
|
+
const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
|
|
110
|
+
const toHash = (hash) => {
|
|
111
|
+
if (!hash || hash === "#") return false;
|
|
112
|
+
const target = document.getElementById(decodeURIComponent(hash.slice(1)));
|
|
113
|
+
target?.scrollIntoView({ behavior: "instant" });
|
|
114
|
+
return target !== null;
|
|
115
|
+
};
|
|
116
|
+
return {
|
|
117
|
+
leave: save,
|
|
118
|
+
arrive(location, from) {
|
|
119
|
+
current = location.key;
|
|
120
|
+
if (location.action === "pop" || from === void 0) {
|
|
121
|
+
const y = location.key === void 0 ? void 0 : positions[location.key];
|
|
122
|
+
if (y !== void 0) to(y);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (location.action === "replace" && location.pathname === from.pathname) return;
|
|
126
|
+
if (!toHash(location.hash)) to(0);
|
|
127
|
+
},
|
|
128
|
+
dispose() {
|
|
129
|
+
window.removeEventListener("pagehide", save);
|
|
130
|
+
history.scrollRestoration = restoration;
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// src/lib/router/index.ts
|
|
78
136
|
import {
|
|
79
137
|
createRouter as createCoreRouter,
|
|
80
138
|
createBrowserHistory,
|
|
@@ -206,7 +264,8 @@ function getSubmissionsSignal(url) {
|
|
|
206
264
|
}
|
|
207
265
|
function action(fn, name, options = {}) {
|
|
208
266
|
const actionUrl = name || fn.name || "action";
|
|
209
|
-
const submit = async (
|
|
267
|
+
const submit = async (...args) => {
|
|
268
|
+
const input = args.length > 1 ? args : args[0];
|
|
210
269
|
const [, setSubmission] = getSubmissionSignal(actionUrl);
|
|
211
270
|
const [, setSubmissions] = getSubmissionsSignal(actionUrl);
|
|
212
271
|
let entry;
|
|
@@ -221,11 +280,10 @@ function action(fn, name, options = {}) {
|
|
|
221
280
|
};
|
|
222
281
|
const retry = () => {
|
|
223
282
|
drop2();
|
|
224
|
-
return submit(
|
|
283
|
+
return submit(...args);
|
|
225
284
|
};
|
|
226
285
|
entry = {
|
|
227
286
|
input,
|
|
228
|
-
// Approximate type for tracking
|
|
229
287
|
pending: true,
|
|
230
288
|
clear,
|
|
231
289
|
retry
|
|
@@ -233,7 +291,7 @@ function action(fn, name, options = {}) {
|
|
|
233
291
|
setSubmission(entry);
|
|
234
292
|
setSubmissions((list) => [...list, entry]);
|
|
235
293
|
try {
|
|
236
|
-
const result = await fn(
|
|
294
|
+
const result = await fn(...args);
|
|
237
295
|
setSubmission({
|
|
238
296
|
input,
|
|
239
297
|
result,
|
|
@@ -311,14 +369,49 @@ function renderLayer(m, depth, base) {
|
|
|
311
369
|
});
|
|
312
370
|
});
|
|
313
371
|
};
|
|
372
|
+
let readsLocation;
|
|
314
373
|
const [resource, { refetch }] = createResource2(() => {
|
|
315
|
-
const
|
|
374
|
+
const params = untrack(base.params);
|
|
375
|
+
const location = untrack(base.location);
|
|
376
|
+
readsLocation = false;
|
|
377
|
+
const result = loader(
|
|
378
|
+
{
|
|
379
|
+
params: () => params,
|
|
380
|
+
location: () => {
|
|
381
|
+
readsLocation = true;
|
|
382
|
+
return location;
|
|
383
|
+
}
|
|
384
|
+
},
|
|
385
|
+
owner,
|
|
386
|
+
() => cancelled,
|
|
387
|
+
trackDeps
|
|
388
|
+
);
|
|
316
389
|
return router ? router.trackLoad(result) : result;
|
|
317
390
|
});
|
|
318
|
-
onCleanup(
|
|
391
|
+
onCleanup(
|
|
392
|
+
onRevalidate(() => {
|
|
393
|
+
if (untrack(() => base.matched()[depth]?.route) !== m.route) return;
|
|
394
|
+
void refetch();
|
|
395
|
+
})
|
|
396
|
+
);
|
|
397
|
+
let loadedFor = untrack(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
|
|
398
|
+
let searchedFor = untrack(() => base.location().search);
|
|
399
|
+
createEffect(() => {
|
|
400
|
+
const now = base.matched()[depth];
|
|
401
|
+
const search = base.location().search;
|
|
402
|
+
if (now?.route !== m.route) return;
|
|
403
|
+
const params = JSON.stringify(now.params ?? {});
|
|
404
|
+
const paramsMoved = params !== loadedFor;
|
|
405
|
+
const searchMoved = readsLocation !== false && search !== searchedFor;
|
|
406
|
+
loadedFor = params;
|
|
407
|
+
searchedFor = search;
|
|
408
|
+
if (paramsMoved || searchMoved) untrack(() => void refetch());
|
|
409
|
+
});
|
|
319
410
|
data = () => {
|
|
320
411
|
const error = resource.error;
|
|
321
412
|
if (error !== void 0 && error !== null) throw error;
|
|
413
|
+
const r = resource;
|
|
414
|
+
if (r.state === "refreshing") return r.latest;
|
|
322
415
|
return resource();
|
|
323
416
|
};
|
|
324
417
|
Object.defineProperty(data, "loading", { get: () => resource.loading });
|
|
@@ -423,16 +516,19 @@ function buildDefaultNotFound() {
|
|
|
423
516
|
}
|
|
424
517
|
var pendingTransitionMode;
|
|
425
518
|
function Router(props) {
|
|
426
|
-
const
|
|
519
|
+
const history2 = props.history ?? createBrowserHistory();
|
|
427
520
|
const router = createCoreRouter({
|
|
428
521
|
routes: props.routes,
|
|
429
522
|
base: props.base,
|
|
430
|
-
history
|
|
523
|
+
history: history2
|
|
431
524
|
});
|
|
432
525
|
const [state, setState] = createSignal2(router.state());
|
|
433
526
|
const [navigating, setNavigating] = createSignal2(false);
|
|
434
527
|
const [loads, setLoads] = createSignal2(0);
|
|
435
528
|
let navigationId = 0;
|
|
529
|
+
const scroll = history2.window ? keepScroll(router.state().location) : void 0;
|
|
530
|
+
let arriving = scroll ? { id: 0, location: router.state().location, from: void 0 } : null;
|
|
531
|
+
const [arrived, setArrived] = createSignal2(0);
|
|
436
532
|
const takeMode = () => {
|
|
437
533
|
const mode = pendingTransitionMode ?? (props.transition ?? "auto");
|
|
438
534
|
pendingTransitionMode = void 0;
|
|
@@ -442,6 +538,10 @@ function Router(props) {
|
|
|
442
538
|
const id = ++navigationId;
|
|
443
539
|
const mode = takeMode();
|
|
444
540
|
setNavigating(true);
|
|
541
|
+
if (scroll) {
|
|
542
|
+
scroll.leave();
|
|
543
|
+
arriving = { id, location: next.location, from: untrack(state).location };
|
|
544
|
+
}
|
|
445
545
|
const prepared = prepareComponents(
|
|
446
546
|
(next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
|
|
447
547
|
);
|
|
@@ -449,6 +549,7 @@ function Router(props) {
|
|
|
449
549
|
setState(next);
|
|
450
550
|
const flushed = flush();
|
|
451
551
|
if (id === navigationId) setNavigating(false);
|
|
552
|
+
if (scroll) setArrived(id);
|
|
452
553
|
return flushed;
|
|
453
554
|
};
|
|
454
555
|
if (!prepared) {
|
|
@@ -462,6 +563,7 @@ function Router(props) {
|
|
|
462
563
|
});
|
|
463
564
|
onCleanup(() => {
|
|
464
565
|
unsub();
|
|
566
|
+
scroll?.dispose();
|
|
465
567
|
router.destroy();
|
|
466
568
|
navigationId++;
|
|
467
569
|
});
|
|
@@ -484,6 +586,19 @@ function Router(props) {
|
|
|
484
586
|
return result;
|
|
485
587
|
}
|
|
486
588
|
};
|
|
589
|
+
if (scroll) {
|
|
590
|
+
const nextFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
|
|
591
|
+
createEffect(() => {
|
|
592
|
+
const id = arrived();
|
|
593
|
+
if (ctx.isRouting()) return;
|
|
594
|
+
const next = arriving;
|
|
595
|
+
if (!next || next.id !== id || id !== navigationId) return;
|
|
596
|
+
arriving = null;
|
|
597
|
+
nextFrame(() => {
|
|
598
|
+
if (id === navigationId) scroll.arrive(next.location, next.from);
|
|
599
|
+
});
|
|
600
|
+
});
|
|
601
|
+
}
|
|
487
602
|
const root = {
|
|
488
603
|
depth: -1,
|
|
489
604
|
matched,
|
|
@@ -699,7 +814,7 @@ function Link(props) {
|
|
|
699
814
|
return a;
|
|
700
815
|
}
|
|
701
816
|
var A = Link;
|
|
702
|
-
function
|
|
817
|
+
function ActionForm(props) {
|
|
703
818
|
const action2 = props.action;
|
|
704
819
|
const cls = props.className ?? props.class;
|
|
705
820
|
const url = action2.url ?? "";
|
|
@@ -739,7 +854,7 @@ async function preloadRoutes(routes, pathname) {
|
|
|
739
854
|
}
|
|
740
855
|
export {
|
|
741
856
|
A,
|
|
742
|
-
|
|
857
|
+
ActionForm,
|
|
743
858
|
Link,
|
|
744
859
|
Outlet,
|
|
745
860
|
Redirect,
|
package/dist/src/lib/core.cjs
CHANGED
|
@@ -152,7 +152,7 @@ var import_signal6 = require("@fluixi/reactive/signal");
|
|
|
152
152
|
var import_dom = require("@fluixi/dom");
|
|
153
153
|
|
|
154
154
|
// src/version.generated.ts
|
|
155
|
-
var VERSION = "1.0.0-alpha.
|
|
155
|
+
var VERSION = "1.0.0-alpha.96";
|
|
156
156
|
|
|
157
157
|
// src/lib/render/versions.ts
|
|
158
158
|
var import_dom2 = require("@fluixi/dom");
|
|
@@ -762,7 +762,7 @@ function createIsomorphicStore(key, options) {
|
|
|
762
762
|
}
|
|
763
763
|
return initPromise;
|
|
764
764
|
};
|
|
765
|
-
return { value, fields, set, setField, ensureInit, key };
|
|
765
|
+
return { value, fields, set, setField, ensureInit, key, seeded };
|
|
766
766
|
}
|
|
767
767
|
|
|
768
768
|
// src/lib/env/index.ts
|
|
@@ -1177,6 +1177,64 @@ var import_dom15 = require("@fluixi/dom");
|
|
|
1177
1177
|
var import_signal16 = require("@fluixi/reactive/signal");
|
|
1178
1178
|
var import_object = require("@fluixi/utils/object");
|
|
1179
1179
|
var import_compare = require("@fluixi/utils/compare");
|
|
1180
|
+
|
|
1181
|
+
// src/lib/router/scroll.ts
|
|
1182
|
+
var STORE = "fx:scroll";
|
|
1183
|
+
var KEEP = 100;
|
|
1184
|
+
function keepScroll(initial) {
|
|
1185
|
+
const read3 = () => {
|
|
1186
|
+
try {
|
|
1187
|
+
return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
|
|
1188
|
+
} catch {
|
|
1189
|
+
return {};
|
|
1190
|
+
}
|
|
1191
|
+
};
|
|
1192
|
+
const positions = read3();
|
|
1193
|
+
const write = () => {
|
|
1194
|
+
const keys = Object.keys(positions);
|
|
1195
|
+
for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
|
|
1196
|
+
try {
|
|
1197
|
+
sessionStorage.setItem(STORE, JSON.stringify(positions));
|
|
1198
|
+
} catch {
|
|
1199
|
+
}
|
|
1200
|
+
};
|
|
1201
|
+
let current = initial.key;
|
|
1202
|
+
const save = () => {
|
|
1203
|
+
if (current === void 0) return;
|
|
1204
|
+
delete positions[current];
|
|
1205
|
+
positions[current] = window.scrollY;
|
|
1206
|
+
write();
|
|
1207
|
+
};
|
|
1208
|
+
const restoration = history.scrollRestoration;
|
|
1209
|
+
history.scrollRestoration = "manual";
|
|
1210
|
+
window.addEventListener("pagehide", save);
|
|
1211
|
+
const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
|
|
1212
|
+
const toHash = (hash) => {
|
|
1213
|
+
if (!hash || hash === "#") return false;
|
|
1214
|
+
const target = document.getElementById(decodeURIComponent(hash.slice(1)));
|
|
1215
|
+
target?.scrollIntoView({ behavior: "instant" });
|
|
1216
|
+
return target !== null;
|
|
1217
|
+
};
|
|
1218
|
+
return {
|
|
1219
|
+
leave: save,
|
|
1220
|
+
arrive(location, from) {
|
|
1221
|
+
current = location.key;
|
|
1222
|
+
if (location.action === "pop" || from === void 0) {
|
|
1223
|
+
const y = location.key === void 0 ? void 0 : positions[location.key];
|
|
1224
|
+
if (y !== void 0) to(y);
|
|
1225
|
+
return;
|
|
1226
|
+
}
|
|
1227
|
+
if (location.action === "replace" && location.pathname === from.pathname) return;
|
|
1228
|
+
if (!toHash(location.hash)) to(0);
|
|
1229
|
+
},
|
|
1230
|
+
dispose() {
|
|
1231
|
+
window.removeEventListener("pagehide", save);
|
|
1232
|
+
history.scrollRestoration = restoration;
|
|
1233
|
+
}
|
|
1234
|
+
};
|
|
1235
|
+
}
|
|
1236
|
+
|
|
1237
|
+
// src/lib/router/index.ts
|
|
1180
1238
|
var import_router = require("@fluixi/router");
|
|
1181
1239
|
|
|
1182
1240
|
// src/lib/router/data.ts
|
|
@@ -1251,14 +1309,49 @@ function renderLayer(m, depth, base) {
|
|
|
1251
1309
|
});
|
|
1252
1310
|
});
|
|
1253
1311
|
};
|
|
1312
|
+
let readsLocation;
|
|
1254
1313
|
const [resource2, { refetch }] = (0, import_signal15.createResource)(() => {
|
|
1255
|
-
const
|
|
1314
|
+
const params = (0, import_signal15.untrack)(base.params);
|
|
1315
|
+
const location = (0, import_signal15.untrack)(base.location);
|
|
1316
|
+
readsLocation = false;
|
|
1317
|
+
const result = loader(
|
|
1318
|
+
{
|
|
1319
|
+
params: () => params,
|
|
1320
|
+
location: () => {
|
|
1321
|
+
readsLocation = true;
|
|
1322
|
+
return location;
|
|
1323
|
+
}
|
|
1324
|
+
},
|
|
1325
|
+
owner,
|
|
1326
|
+
() => cancelled,
|
|
1327
|
+
trackDeps
|
|
1328
|
+
);
|
|
1256
1329
|
return router ? router.trackLoad(result) : result;
|
|
1257
1330
|
});
|
|
1258
|
-
(0, import_signal15.onCleanup)(
|
|
1331
|
+
(0, import_signal15.onCleanup)(
|
|
1332
|
+
onRevalidate(() => {
|
|
1333
|
+
if ((0, import_signal15.untrack)(() => base.matched()[depth]?.route) !== m.route) return;
|
|
1334
|
+
void refetch();
|
|
1335
|
+
})
|
|
1336
|
+
);
|
|
1337
|
+
let loadedFor = (0, import_signal15.untrack)(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
|
|
1338
|
+
let searchedFor = (0, import_signal15.untrack)(() => base.location().search);
|
|
1339
|
+
(0, import_signal15.createEffect)(() => {
|
|
1340
|
+
const now = base.matched()[depth];
|
|
1341
|
+
const search = base.location().search;
|
|
1342
|
+
if (now?.route !== m.route) return;
|
|
1343
|
+
const params = JSON.stringify(now.params ?? {});
|
|
1344
|
+
const paramsMoved = params !== loadedFor;
|
|
1345
|
+
const searchMoved = readsLocation !== false && search !== searchedFor;
|
|
1346
|
+
loadedFor = params;
|
|
1347
|
+
searchedFor = search;
|
|
1348
|
+
if (paramsMoved || searchMoved) (0, import_signal15.untrack)(() => void refetch());
|
|
1349
|
+
});
|
|
1259
1350
|
data = () => {
|
|
1260
1351
|
const error = resource2.error;
|
|
1261
1352
|
if (error !== void 0 && error !== null) throw error;
|
|
1353
|
+
const r = resource2;
|
|
1354
|
+
if (r.state === "refreshing") return r.latest;
|
|
1262
1355
|
return resource2();
|
|
1263
1356
|
};
|
|
1264
1357
|
Object.defineProperty(data, "loading", { get: () => resource2.loading });
|
|
@@ -1363,16 +1456,19 @@ function buildDefaultNotFound() {
|
|
|
1363
1456
|
}
|
|
1364
1457
|
var pendingTransitionMode;
|
|
1365
1458
|
function Router(props) {
|
|
1366
|
-
const
|
|
1459
|
+
const history2 = props.history ?? (0, import_router.createBrowserHistory)();
|
|
1367
1460
|
const router = (0, import_router.createRouter)({
|
|
1368
1461
|
routes: props.routes,
|
|
1369
1462
|
base: props.base,
|
|
1370
|
-
history
|
|
1463
|
+
history: history2
|
|
1371
1464
|
});
|
|
1372
1465
|
const [state, setState] = (0, import_signal15.createSignal)(router.state());
|
|
1373
1466
|
const [navigating, setNavigating] = (0, import_signal15.createSignal)(false);
|
|
1374
1467
|
const [loads, setLoads] = (0, import_signal15.createSignal)(0);
|
|
1375
1468
|
let navigationId = 0;
|
|
1469
|
+
const scroll = history2.window ? keepScroll(router.state().location) : void 0;
|
|
1470
|
+
let arriving = scroll ? { id: 0, location: router.state().location, from: void 0 } : null;
|
|
1471
|
+
const [arrived, setArrived] = (0, import_signal15.createSignal)(0);
|
|
1376
1472
|
const takeMode = () => {
|
|
1377
1473
|
const mode = pendingTransitionMode ?? (props.transition ?? "auto");
|
|
1378
1474
|
pendingTransitionMode = void 0;
|
|
@@ -1382,6 +1478,10 @@ function Router(props) {
|
|
|
1382
1478
|
const id = ++navigationId;
|
|
1383
1479
|
const mode = takeMode();
|
|
1384
1480
|
setNavigating(true);
|
|
1481
|
+
if (scroll) {
|
|
1482
|
+
scroll.leave();
|
|
1483
|
+
arriving = { id, location: next.location, from: (0, import_signal15.untrack)(state).location };
|
|
1484
|
+
}
|
|
1385
1485
|
const prepared = prepareComponents(
|
|
1386
1486
|
(next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
|
|
1387
1487
|
);
|
|
@@ -1389,6 +1489,7 @@ function Router(props) {
|
|
|
1389
1489
|
setState(next);
|
|
1390
1490
|
const flushed = (0, import_signal15.flush)();
|
|
1391
1491
|
if (id === navigationId) setNavigating(false);
|
|
1492
|
+
if (scroll) setArrived(id);
|
|
1392
1493
|
return flushed;
|
|
1393
1494
|
};
|
|
1394
1495
|
if (!prepared) {
|
|
@@ -1402,6 +1503,7 @@ function Router(props) {
|
|
|
1402
1503
|
});
|
|
1403
1504
|
(0, import_signal15.onCleanup)(() => {
|
|
1404
1505
|
unsub();
|
|
1506
|
+
scroll?.dispose();
|
|
1405
1507
|
router.destroy();
|
|
1406
1508
|
navigationId++;
|
|
1407
1509
|
});
|
|
@@ -1424,6 +1526,19 @@ function Router(props) {
|
|
|
1424
1526
|
return result;
|
|
1425
1527
|
}
|
|
1426
1528
|
};
|
|
1529
|
+
if (scroll) {
|
|
1530
|
+
const nextFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
|
|
1531
|
+
(0, import_signal15.createEffect)(() => {
|
|
1532
|
+
const id = arrived();
|
|
1533
|
+
if (ctx.isRouting()) return;
|
|
1534
|
+
const next = arriving;
|
|
1535
|
+
if (!next || next.id !== id || id !== navigationId) return;
|
|
1536
|
+
arriving = null;
|
|
1537
|
+
nextFrame(() => {
|
|
1538
|
+
if (id === navigationId) scroll.arrive(next.location, next.from);
|
|
1539
|
+
});
|
|
1540
|
+
});
|
|
1541
|
+
}
|
|
1427
1542
|
const root = {
|
|
1428
1543
|
depth: -1,
|
|
1429
1544
|
matched,
|
package/dist/src/lib/core.mjs
CHANGED
|
@@ -38,7 +38,7 @@ import { createRoot as createRoot2 } from "@fluixi/reactive/signal";
|
|
|
38
38
|
import { registerCoreVersion } from "@fluixi/dom";
|
|
39
39
|
|
|
40
40
|
// src/version.generated.ts
|
|
41
|
-
var VERSION = "1.0.0-alpha.
|
|
41
|
+
var VERSION = "1.0.0-alpha.96";
|
|
42
42
|
|
|
43
43
|
// src/lib/render/versions.ts
|
|
44
44
|
import { stampVersions, warnOnVersionSkew, versions } from "@fluixi/dom";
|
|
@@ -690,7 +690,7 @@ function createIsomorphicStore(key, options) {
|
|
|
690
690
|
}
|
|
691
691
|
return initPromise;
|
|
692
692
|
};
|
|
693
|
-
return { value, fields, set, setField, ensureInit, key };
|
|
693
|
+
return { value, fields, set, setField, ensureInit, key, seeded };
|
|
694
694
|
}
|
|
695
695
|
|
|
696
696
|
// src/lib/env/index.ts
|
|
@@ -1126,6 +1126,64 @@ import {
|
|
|
1126
1126
|
import { createContext as createContext5, useContext as useContext5 } from "@fluixi/reactive/signal";
|
|
1127
1127
|
import { get } from "@fluixi/utils/object";
|
|
1128
1128
|
import { deepEqual } from "@fluixi/utils/compare";
|
|
1129
|
+
|
|
1130
|
+
// src/lib/router/scroll.ts
|
|
1131
|
+
var STORE = "fx:scroll";
|
|
1132
|
+
var KEEP = 100;
|
|
1133
|
+
function keepScroll(initial) {
|
|
1134
|
+
const read3 = () => {
|
|
1135
|
+
try {
|
|
1136
|
+
return JSON.parse(sessionStorage.getItem(STORE) ?? "{}");
|
|
1137
|
+
} catch {
|
|
1138
|
+
return {};
|
|
1139
|
+
}
|
|
1140
|
+
};
|
|
1141
|
+
const positions = read3();
|
|
1142
|
+
const write = () => {
|
|
1143
|
+
const keys = Object.keys(positions);
|
|
1144
|
+
for (const key of keys.slice(0, Math.max(0, keys.length - KEEP))) delete positions[key];
|
|
1145
|
+
try {
|
|
1146
|
+
sessionStorage.setItem(STORE, JSON.stringify(positions));
|
|
1147
|
+
} catch {
|
|
1148
|
+
}
|
|
1149
|
+
};
|
|
1150
|
+
let current = initial.key;
|
|
1151
|
+
const save = () => {
|
|
1152
|
+
if (current === void 0) return;
|
|
1153
|
+
delete positions[current];
|
|
1154
|
+
positions[current] = window.scrollY;
|
|
1155
|
+
write();
|
|
1156
|
+
};
|
|
1157
|
+
const restoration = history.scrollRestoration;
|
|
1158
|
+
history.scrollRestoration = "manual";
|
|
1159
|
+
window.addEventListener("pagehide", save);
|
|
1160
|
+
const to = (top) => window.scrollTo({ top, left: 0, behavior: "instant" });
|
|
1161
|
+
const toHash = (hash) => {
|
|
1162
|
+
if (!hash || hash === "#") return false;
|
|
1163
|
+
const target = document.getElementById(decodeURIComponent(hash.slice(1)));
|
|
1164
|
+
target?.scrollIntoView({ behavior: "instant" });
|
|
1165
|
+
return target !== null;
|
|
1166
|
+
};
|
|
1167
|
+
return {
|
|
1168
|
+
leave: save,
|
|
1169
|
+
arrive(location, from) {
|
|
1170
|
+
current = location.key;
|
|
1171
|
+
if (location.action === "pop" || from === void 0) {
|
|
1172
|
+
const y = location.key === void 0 ? void 0 : positions[location.key];
|
|
1173
|
+
if (y !== void 0) to(y);
|
|
1174
|
+
return;
|
|
1175
|
+
}
|
|
1176
|
+
if (location.action === "replace" && location.pathname === from.pathname) return;
|
|
1177
|
+
if (!toHash(location.hash)) to(0);
|
|
1178
|
+
},
|
|
1179
|
+
dispose() {
|
|
1180
|
+
window.removeEventListener("pagehide", save);
|
|
1181
|
+
history.scrollRestoration = restoration;
|
|
1182
|
+
}
|
|
1183
|
+
};
|
|
1184
|
+
}
|
|
1185
|
+
|
|
1186
|
+
// src/lib/router/index.ts
|
|
1129
1187
|
import {
|
|
1130
1188
|
createRouter as createCoreRouter,
|
|
1131
1189
|
createBrowserHistory,
|
|
@@ -1213,14 +1271,49 @@ function renderLayer(m, depth, base) {
|
|
|
1213
1271
|
});
|
|
1214
1272
|
});
|
|
1215
1273
|
};
|
|
1274
|
+
let readsLocation;
|
|
1216
1275
|
const [resource2, { refetch }] = createResource5(() => {
|
|
1217
|
-
const
|
|
1276
|
+
const params = untrack4(base.params);
|
|
1277
|
+
const location = untrack4(base.location);
|
|
1278
|
+
readsLocation = false;
|
|
1279
|
+
const result = loader(
|
|
1280
|
+
{
|
|
1281
|
+
params: () => params,
|
|
1282
|
+
location: () => {
|
|
1283
|
+
readsLocation = true;
|
|
1284
|
+
return location;
|
|
1285
|
+
}
|
|
1286
|
+
},
|
|
1287
|
+
owner,
|
|
1288
|
+
() => cancelled,
|
|
1289
|
+
trackDeps
|
|
1290
|
+
);
|
|
1218
1291
|
return router ? router.trackLoad(result) : result;
|
|
1219
1292
|
});
|
|
1220
|
-
onCleanup4(
|
|
1293
|
+
onCleanup4(
|
|
1294
|
+
onRevalidate(() => {
|
|
1295
|
+
if (untrack4(() => base.matched()[depth]?.route) !== m.route) return;
|
|
1296
|
+
void refetch();
|
|
1297
|
+
})
|
|
1298
|
+
);
|
|
1299
|
+
let loadedFor = untrack4(() => JSON.stringify(base.matched()[depth]?.params ?? {}));
|
|
1300
|
+
let searchedFor = untrack4(() => base.location().search);
|
|
1301
|
+
createEffect4(() => {
|
|
1302
|
+
const now = base.matched()[depth];
|
|
1303
|
+
const search = base.location().search;
|
|
1304
|
+
if (now?.route !== m.route) return;
|
|
1305
|
+
const params = JSON.stringify(now.params ?? {});
|
|
1306
|
+
const paramsMoved = params !== loadedFor;
|
|
1307
|
+
const searchMoved = readsLocation !== false && search !== searchedFor;
|
|
1308
|
+
loadedFor = params;
|
|
1309
|
+
searchedFor = search;
|
|
1310
|
+
if (paramsMoved || searchMoved) untrack4(() => void refetch());
|
|
1311
|
+
});
|
|
1221
1312
|
data = () => {
|
|
1222
1313
|
const error = resource2.error;
|
|
1223
1314
|
if (error !== void 0 && error !== null) throw error;
|
|
1315
|
+
const r = resource2;
|
|
1316
|
+
if (r.state === "refreshing") return r.latest;
|
|
1224
1317
|
return resource2();
|
|
1225
1318
|
};
|
|
1226
1319
|
Object.defineProperty(data, "loading", { get: () => resource2.loading });
|
|
@@ -1325,16 +1418,19 @@ function buildDefaultNotFound() {
|
|
|
1325
1418
|
}
|
|
1326
1419
|
var pendingTransitionMode;
|
|
1327
1420
|
function Router(props) {
|
|
1328
|
-
const
|
|
1421
|
+
const history2 = props.history ?? createBrowserHistory();
|
|
1329
1422
|
const router = createCoreRouter({
|
|
1330
1423
|
routes: props.routes,
|
|
1331
1424
|
base: props.base,
|
|
1332
|
-
history
|
|
1425
|
+
history: history2
|
|
1333
1426
|
});
|
|
1334
1427
|
const [state, setState] = createSignal8(router.state());
|
|
1335
1428
|
const [navigating, setNavigating] = createSignal8(false);
|
|
1336
1429
|
const [loads, setLoads] = createSignal8(0);
|
|
1337
1430
|
let navigationId = 0;
|
|
1431
|
+
const scroll = history2.window ? keepScroll(router.state().location) : void 0;
|
|
1432
|
+
let arriving = scroll ? { id: 0, location: router.state().location, from: void 0 } : null;
|
|
1433
|
+
const [arrived, setArrived] = createSignal8(0);
|
|
1338
1434
|
const takeMode = () => {
|
|
1339
1435
|
const mode = pendingTransitionMode ?? (props.transition ?? "auto");
|
|
1340
1436
|
pendingTransitionMode = void 0;
|
|
@@ -1344,6 +1440,10 @@ function Router(props) {
|
|
|
1344
1440
|
const id = ++navigationId;
|
|
1345
1441
|
const mode = takeMode();
|
|
1346
1442
|
setNavigating(true);
|
|
1443
|
+
if (scroll) {
|
|
1444
|
+
scroll.leave();
|
|
1445
|
+
arriving = { id, location: next.location, from: untrack4(state).location };
|
|
1446
|
+
}
|
|
1347
1447
|
const prepared = prepareComponents(
|
|
1348
1448
|
(next.match?.matched ?? []).map((m) => m.component).filter(Boolean)
|
|
1349
1449
|
);
|
|
@@ -1351,6 +1451,7 @@ function Router(props) {
|
|
|
1351
1451
|
setState(next);
|
|
1352
1452
|
const flushed = flush();
|
|
1353
1453
|
if (id === navigationId) setNavigating(false);
|
|
1454
|
+
if (scroll) setArrived(id);
|
|
1354
1455
|
return flushed;
|
|
1355
1456
|
};
|
|
1356
1457
|
if (!prepared) {
|
|
@@ -1364,6 +1465,7 @@ function Router(props) {
|
|
|
1364
1465
|
});
|
|
1365
1466
|
onCleanup4(() => {
|
|
1366
1467
|
unsub();
|
|
1468
|
+
scroll?.dispose();
|
|
1367
1469
|
router.destroy();
|
|
1368
1470
|
navigationId++;
|
|
1369
1471
|
});
|
|
@@ -1386,6 +1488,19 @@ function Router(props) {
|
|
|
1386
1488
|
return result;
|
|
1387
1489
|
}
|
|
1388
1490
|
};
|
|
1491
|
+
if (scroll) {
|
|
1492
|
+
const nextFrame = typeof requestAnimationFrame === "function" ? requestAnimationFrame : (fn) => setTimeout(fn, 0);
|
|
1493
|
+
createEffect4(() => {
|
|
1494
|
+
const id = arrived();
|
|
1495
|
+
if (ctx.isRouting()) return;
|
|
1496
|
+
const next = arriving;
|
|
1497
|
+
if (!next || next.id !== id || id !== navigationId) return;
|
|
1498
|
+
arriving = null;
|
|
1499
|
+
nextFrame(() => {
|
|
1500
|
+
if (id === navigationId) scroll.arrive(next.location, next.from);
|
|
1501
|
+
});
|
|
1502
|
+
});
|
|
1503
|
+
}
|
|
1389
1504
|
const root = {
|
|
1390
1505
|
depth: -1,
|
|
1391
1506
|
matched,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/*! @fluixi/core v1.0.0-alpha.
|
|
1
|
+
/*! @fluixi/core v1.0.0-alpha.96 | (c) 2026 Ibrahima Touré and Fluixi contributors | MIT */
|
|
2
2
|
"use strict";
|
|
3
3
|
var __defProp = Object.defineProperty;
|
|
4
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|