@jsenv/navi 0.29.462 → 0.29.463
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/dist/dev/jsenv_navi.js +88 -51
- package/dist/dev/jsenv_navi.js.map +3 -3
- package/dist/jsenv_navi.js +88 -51
- package/dist/jsenv_navi.js.map +3 -3
- package/docs/navigation.md +20 -19
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -11862,6 +11862,26 @@ const activeRouteActionsSignal = computed(() => {
|
|
|
11862
11862
|
return active;
|
|
11863
11863
|
});
|
|
11864
11864
|
|
|
11865
|
+
/**
|
|
11866
|
+
* Whether a route action of the page on screen asks nothing yet: its route
|
|
11867
|
+
* matches and its params (or `when`) say no. Gated on app state not there yet,
|
|
11868
|
+
* or never meant to ask on this page — nothing tells one from the other before
|
|
11869
|
+
* it asks. Read by the scroll restoration, which stays ready for it.
|
|
11870
|
+
*
|
|
11871
|
+
* @type {import("@preact/signals").ReadonlySignal<boolean>}
|
|
11872
|
+
*/
|
|
11873
|
+
const routeActionYetToAskSignal = computed(() => {
|
|
11874
|
+
for (const {
|
|
11875
|
+
routeMatchingSignal,
|
|
11876
|
+
askingSignal,
|
|
11877
|
+
} of routeActionEntriesSignal.value) {
|
|
11878
|
+
if (routeMatchingSignal.value && !askingSignal.value) {
|
|
11879
|
+
return true;
|
|
11880
|
+
}
|
|
11881
|
+
}
|
|
11882
|
+
return false;
|
|
11883
|
+
});
|
|
11884
|
+
|
|
11865
11885
|
let activeRouteReadsPrevious = new Set();
|
|
11866
11886
|
/**
|
|
11867
11887
|
* `activeRouteActionsSignal` without the page's code: what to rerun to read
|
|
@@ -11975,6 +11995,7 @@ const routeAction = (
|
|
|
11975
11995
|
...routeActionEntriesSignal.peek(),
|
|
11976
11996
|
{
|
|
11977
11997
|
routeAction: actionBoundToRoute,
|
|
11998
|
+
routeMatchingSignal,
|
|
11978
11999
|
askingSignal: computed(() => Boolean(readParamsAsked())),
|
|
11979
12000
|
},
|
|
11980
12001
|
];
|
|
@@ -12131,11 +12152,11 @@ const haveSameMembers = (setA, setB) => {
|
|
|
12131
12152
|
* moment it is put back, and a position beyond what has arrived is clamped.
|
|
12132
12153
|
* What navi knows a first render left out, it waits for: a `<Box
|
|
12133
12154
|
* mount="after-paint">` is built before the offset that shows it is written
|
|
12134
|
-
* (see mount_after_paint.jsx), and a reload waits for the route
|
|
12135
|
-
*
|
|
12136
|
-
* that starts asking
|
|
12137
|
-
*
|
|
12138
|
-
*
|
|
12155
|
+
* (see mount_after_paint.jsx), and a reload or a return waits for the route
|
|
12156
|
+
* actions the page has nothing to draw for — its code among them — including
|
|
12157
|
+
* one that starts asking after the position is written (see
|
|
12158
|
+
* putBackOnceAnswered). Anything else only the page knows, and it says so
|
|
12159
|
+
* (useHoldScrollRestoration). A wait can be long, so the reader reaching for
|
|
12139
12160
|
* the page during it cancels the position: moved afterwards, they would lose
|
|
12140
12161
|
* whatever they had started on.
|
|
12141
12162
|
*
|
|
@@ -12250,17 +12271,16 @@ const suspendScrollRecording = () => {
|
|
|
12250
12271
|
};
|
|
12251
12272
|
};
|
|
12252
12273
|
|
|
12253
|
-
// The position a reload or a return is about to put back, until it is written
|
|
12254
|
-
//
|
|
12255
|
-
//
|
|
12256
|
-
//
|
|
12257
|
-
//
|
|
12258
|
-
// are is theirs (see
|
|
12274
|
+
// The position a reload or a return is about to put back, until it is written
|
|
12275
|
+
// into a page that will ask nothing more (see stayForLateAsks). Where the
|
|
12276
|
+
// document lands is the last arrival's to say: an arrival decided meanwhile — a
|
|
12277
|
+
// page that sends the reader elsewhere as it mounts — replaces it (see
|
|
12278
|
+
// startAtTop), and must not be scrolled to where the return was going. So does
|
|
12279
|
+
// the reader reaching for the page: where they are is theirs (see
|
|
12280
|
+
// installScrollRestoration).
|
|
12259
12281
|
let pendingRestoration = null;
|
|
12260
|
-
|
|
12261
|
-
|
|
12262
|
-
const startRestoration = (position, { untilReached = false } = {}) => {
|
|
12263
|
-
const restoration = { position, due: false, untilReached };
|
|
12282
|
+
const startRestoration = (position) => {
|
|
12283
|
+
const restoration = { position, due: false };
|
|
12264
12284
|
pendingRestoration = restoration;
|
|
12265
12285
|
return restoration;
|
|
12266
12286
|
};
|
|
@@ -12275,16 +12295,13 @@ const putBack = (restoration) => {
|
|
|
12275
12295
|
// The page is not whole yet: the last release puts it back.
|
|
12276
12296
|
return;
|
|
12277
12297
|
}
|
|
12278
|
-
pendingRestoration = null;
|
|
12279
12298
|
if (documentHoldCount) {
|
|
12299
|
+
pendingRestoration = null;
|
|
12280
12300
|
return;
|
|
12281
12301
|
}
|
|
12282
12302
|
scrollTo(restoration.position);
|
|
12283
|
-
|
|
12284
|
-
|
|
12285
|
-
pendingRestoration = restoration;
|
|
12286
|
-
putBackOnLateAnswer(restoration);
|
|
12287
|
-
}
|
|
12303
|
+
restoration.due = false;
|
|
12304
|
+
stayForLateAsks(restoration);
|
|
12288
12305
|
};
|
|
12289
12306
|
|
|
12290
12307
|
// A list scrolling the document that opens on a row puts the document where
|
|
@@ -12342,9 +12359,10 @@ const holdScrollRestoration = () => {
|
|
|
12342
12359
|
* `held` turns false — unless the reader has reached for the page in the
|
|
12343
12360
|
* meantime (a finger, a click, a wheel, a key), or gone elsewhere.
|
|
12344
12361
|
*
|
|
12345
|
-
*
|
|
12346
|
-
*
|
|
12347
|
-
* cannot see: a read the page starts itself, content whose height
|
|
12362
|
+
* The page's route actions are waited for without this — its code, a read
|
|
12363
|
+
* with no answer yet, one gated on app state that asks later. This is for
|
|
12364
|
+
* what navi cannot see: a read the page starts itself, content whose height
|
|
12365
|
+
* arrives late.
|
|
12348
12366
|
*
|
|
12349
12367
|
* ```jsx
|
|
12350
12368
|
* const [games] = useAsyncData(GAMES, { loading: true, run: true });
|
|
@@ -12429,19 +12447,22 @@ const installScrollRestoration = ({ readAddress }) => {
|
|
|
12429
12447
|
// page the position was taken on, and the position stays for the reload that
|
|
12430
12448
|
// brings the page back.
|
|
12431
12449
|
const restoreScrollPositionOnLoad = (position) => {
|
|
12432
|
-
const restoration = startRestoration(position
|
|
12450
|
+
const restoration = startRestoration(position);
|
|
12433
12451
|
const stopListening = observeRouteRender(() => {
|
|
12434
12452
|
stopListening();
|
|
12435
12453
|
putBackOnceAnswered(restoration);
|
|
12436
12454
|
});
|
|
12437
12455
|
};
|
|
12438
12456
|
|
|
12439
|
-
// Reads the actions to wait for at once: from the commit of
|
|
12457
|
+
// Reads the actions to wait for at once: called from the commit of a render,
|
|
12440
12458
|
// the ones it had nothing to draw for are those still running then. An answer
|
|
12441
12459
|
// can start another read (params made of that answer), so the actions asking
|
|
12442
12460
|
// are read again before the position is written.
|
|
12461
|
+
//
|
|
12462
|
+
// The same for a reload and a return: a return to a page this document has
|
|
12463
|
+
// never drawn, or whose read was reset since, finds no answer either.
|
|
12443
12464
|
const putBackOnceAnswered = (restoration) => {
|
|
12444
|
-
const unanswered =
|
|
12465
|
+
const unanswered = readUnansweredRouteActions();
|
|
12445
12466
|
if (unanswered.length === 0) {
|
|
12446
12467
|
queueMicrotask(() => {
|
|
12447
12468
|
putBack(restoration);
|
|
@@ -12469,10 +12490,10 @@ const putBackOnceAnswered = (restoration) => {
|
|
|
12469
12490
|
|
|
12470
12491
|
const readUnansweredRouteActions = () => {
|
|
12471
12492
|
const unanswered = [];
|
|
12472
|
-
for (const routeAction of activeRouteActionsSignal.
|
|
12493
|
+
for (const routeAction of activeRouteActionsSignal.peek()) {
|
|
12473
12494
|
if (
|
|
12474
|
-
routeAction.runningStateSignal.
|
|
12475
|
-
routeAction.dataSignal.
|
|
12495
|
+
routeAction.runningStateSignal.peek() === RUNNING &&
|
|
12496
|
+
routeAction.dataSignal.peek() === undefined
|
|
12476
12497
|
) {
|
|
12477
12498
|
unanswered.push(routeAction);
|
|
12478
12499
|
}
|
|
@@ -12480,33 +12501,48 @@ const readUnansweredRouteActions = () => {
|
|
|
12480
12501
|
return unanswered;
|
|
12481
12502
|
};
|
|
12482
12503
|
|
|
12483
|
-
// A page can start asking after
|
|
12484
|
-
// state
|
|
12485
|
-
//
|
|
12486
|
-
//
|
|
12487
|
-
//
|
|
12488
|
-
//
|
|
12489
|
-
//
|
|
12490
|
-
//
|
|
12491
|
-
const
|
|
12504
|
+
// A page can start asking after the position is written: an action gated on
|
|
12505
|
+
// app state not there yet (`when`, or params reading an app-wide read), and
|
|
12506
|
+
// nothing tells "not yet" from "never" before it asks (see
|
|
12507
|
+
// routeActionYetToAskSignal). So a written position stays pending while a
|
|
12508
|
+
// route action of the page has not asked: the next one that starts without an
|
|
12509
|
+
// answer is waited for like the first ones, and the position put back once it
|
|
12510
|
+
// is drawn. Not told when the restoration is dropped (pendingRestoration is no
|
|
12511
|
+
// signal): it notices at its next run.
|
|
12512
|
+
const stayForLateAsks = (restoration) => {
|
|
12492
12513
|
effect(function () {
|
|
12514
|
+
let running = false;
|
|
12515
|
+
let starting = false;
|
|
12516
|
+
for (const routeAction of activeRouteActionsSignal.value) {
|
|
12517
|
+
if (routeAction.dataSignal.value !== undefined) {
|
|
12518
|
+
continue;
|
|
12519
|
+
}
|
|
12520
|
+
const runningState = routeAction.runningStateSignal.value;
|
|
12521
|
+
if (runningState === RUNNING) {
|
|
12522
|
+
running = true;
|
|
12523
|
+
} else if (runningState === IDLE) {
|
|
12524
|
+
// Asking, and run by an effect of the same batch that has not run yet.
|
|
12525
|
+
starting = true;
|
|
12526
|
+
}
|
|
12527
|
+
}
|
|
12528
|
+
const yetToAsk = routeActionYetToAskSignal.value;
|
|
12493
12529
|
if (pendingRestoration !== restoration) {
|
|
12494
12530
|
this.dispose();
|
|
12495
12531
|
return;
|
|
12496
12532
|
}
|
|
12497
|
-
if (
|
|
12533
|
+
if (running) {
|
|
12534
|
+
this.dispose();
|
|
12535
|
+
putBackOnceAnswered(restoration);
|
|
12536
|
+
return;
|
|
12537
|
+
}
|
|
12538
|
+
if (starting || yetToAsk) {
|
|
12498
12539
|
return;
|
|
12499
12540
|
}
|
|
12500
12541
|
this.dispose();
|
|
12501
|
-
|
|
12542
|
+
pendingRestoration = null;
|
|
12502
12543
|
});
|
|
12503
12544
|
};
|
|
12504
12545
|
|
|
12505
|
-
// A pixel of slack: the offset kept is the fractional one the browser reports.
|
|
12506
|
-
const fellShortOf = (position) => {
|
|
12507
|
-
return position.y - window.scrollY > 1;
|
|
12508
|
-
};
|
|
12509
|
-
|
|
12510
12546
|
// Calls back once none of the actions is running, saying whether all of them
|
|
12511
12547
|
// completed.
|
|
12512
12548
|
const whenSettled = (actions, callback) => {
|
|
@@ -12555,10 +12591,11 @@ const restoreScrollPosition = (url) => {
|
|
|
12555
12591
|
};
|
|
12556
12592
|
|
|
12557
12593
|
// A traversal back to `url`. The offset is written once the page returned to is
|
|
12558
|
-
// rendered: written sooner, the document
|
|
12559
|
-
//
|
|
12560
|
-
//
|
|
12561
|
-
//
|
|
12594
|
+
// rendered and answered (see putBackOnceAnswered): written sooner, the document
|
|
12595
|
+
// still holds the page being left, or a stand-in for the one arriving, and
|
|
12596
|
+
// clamps it to that height. It is read at once all the same — a page left
|
|
12597
|
+
// taller than the one arriving is clamped by the render itself, and that clamp
|
|
12598
|
+
// is a scroll recorded under the url already returned to.
|
|
12562
12599
|
const restoreScrollPositionOnReturn = (url) => {
|
|
12563
12600
|
pendingRestoration = null;
|
|
12564
12601
|
const href = new URL(url, window.location.href).href;
|
|
@@ -12569,7 +12606,7 @@ const restoreScrollPositionOnReturn = (url) => {
|
|
|
12569
12606
|
}
|
|
12570
12607
|
const restoration = startRestoration(position);
|
|
12571
12608
|
whenPageRendered(() => {
|
|
12572
|
-
|
|
12609
|
+
putBackOnceAnswered(restoration);
|
|
12573
12610
|
});
|
|
12574
12611
|
};
|
|
12575
12612
|
|