@jsenv/navi 0.30.33 → 0.30.35
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 +80 -34
- package/dist/dev/jsenv_navi.js.map +2 -2
- package/dist/jsenv_navi.js +80 -34
- package/dist/jsenv_navi.js.map +2 -2
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -42668,7 +42668,7 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
42668
42668
|
display: flex;
|
|
42669
42669
|
}
|
|
42670
42670
|
|
|
42671
|
-
& > [data-route-row-pane][inert] {
|
|
42671
|
+
& > [data-route-row-pane][inert]:not([data-route-row-held]), &:has( > [data-route-row-held]) > [data-route-row-pane]:not([data-route-row-held]) {
|
|
42672
42672
|
top: var(--navi-route-row-pin, 0);
|
|
42673
42673
|
contain: paint;
|
|
42674
42674
|
max-height: 100dvh;
|
|
@@ -42718,6 +42718,12 @@ const ROW_READING = {
|
|
|
42718
42718
|
// How far a scroll position written can read back from what was written: rounded to
|
|
42719
42719
|
// the device's pixels.
|
|
42720
42720
|
const WRITE_ROUNDING = 1;
|
|
42721
|
+
// The most one frame of a travel plays: a frame of a 30fps screen, which is what a
|
|
42722
|
+
// browser saving power gives (an iPhone in Low Power Mode, Chrome's Energy Saver).
|
|
42723
|
+
// A frame later than that is a main thread busy elsewhere (the page arriving builds,
|
|
42724
|
+
// a list fills its budget), and the travel takes longer rather than jump by it. Not a
|
|
42725
|
+
// frame of a 60Hz screen: that would play every travel in slow motion at 30fps.
|
|
42726
|
+
const TRAVEL_FRAME_MAX_MS = 1000 / 30;
|
|
42721
42727
|
|
|
42722
42728
|
/**
|
|
42723
42729
|
* @type {import("preact").FunctionComponent<{
|
|
@@ -42830,9 +42836,23 @@ const RouteTravel = ({
|
|
|
42830
42836
|
params
|
|
42831
42837
|
}) => new URL(route.buildUrl(params), window.location.href).pathname;
|
|
42832
42838
|
|
|
42839
|
+
// The pane laid out as the page on screen for the length of a movement, let go of
|
|
42840
|
+
// when the row rests. Not what readers are told the page held is
|
|
42841
|
+
// (route_travel_hold.js): that follows the hand, and goes at its lift.
|
|
42842
|
+
const heldPaneRef = useRef(null);
|
|
42843
|
+
const releasePaneAtRest = () => {
|
|
42844
|
+
const heldPane = heldPaneRef.current;
|
|
42845
|
+
if (heldPane) {
|
|
42846
|
+
heldPaneRef.current = null;
|
|
42847
|
+
heldPane.removeAttribute("data-route-row-held");
|
|
42848
|
+
}
|
|
42849
|
+
};
|
|
42850
|
+
|
|
42833
42851
|
// One movement, whoever set it off, from the first thing that moves to the row
|
|
42834
|
-
// at rest. Null when nothing moves.
|
|
42835
|
-
|
|
42852
|
+
// at rest. Null when nothing moves. `paneAtRest` is the pane the row rests on as it
|
|
42853
|
+
// begins: laid out as the page on screen until the row rests again, wherever the
|
|
42854
|
+
// address goes meanwhile (see the CSS).
|
|
42855
|
+
const beginMovement = (fields, paneAtRest) => {
|
|
42836
42856
|
const row = rowRef.current;
|
|
42837
42857
|
if (movementRef.current) {
|
|
42838
42858
|
Object.assign(movementRef.current, fields);
|
|
@@ -42847,6 +42867,11 @@ const RouteTravel = ({
|
|
|
42847
42867
|
...fields
|
|
42848
42868
|
};
|
|
42849
42869
|
movementRef.current = movement;
|
|
42870
|
+
// In a window the page is a picture, contained with what it holds.
|
|
42871
|
+
if (!windowed && paneAtRest) {
|
|
42872
|
+
heldPaneRef.current = paneAtRest;
|
|
42873
|
+
paneAtRest.setAttribute("data-route-row-held", "");
|
|
42874
|
+
}
|
|
42850
42875
|
if (movement.scrollsDocument) {
|
|
42851
42876
|
// Whatever the browser does with the offset meanwhile (clamping it to a page
|
|
42852
42877
|
// shorter than the trip) is not the reader scrolling, and the address it
|
|
@@ -42993,18 +43018,22 @@ const RouteTravel = ({
|
|
|
42993
43018
|
// hesitates, then peaks at 1.65 times this one's speed): two rows of tabs in one
|
|
42994
43019
|
// app would not move alike. The scroll position is written at every frame, so the
|
|
42995
43020
|
// row stays a scroller all the way: what follows it (a Nav's bar) reads it as it
|
|
42996
|
-
// reads a hand, and a finger landing finds it where it is.
|
|
42997
|
-
//
|
|
43021
|
+
// reads a hand, and a finger landing finds it where it is. That is played on the
|
|
43022
|
+
// main thread: a transform on the panes would play on the compositor, but it would
|
|
43023
|
+
// capture what the page on screen holds in position: fixed. Hence a clock of its
|
|
43024
|
+
// own, which a busy main thread slows down rather than makes jump.
|
|
42998
43025
|
const playTravel = (pane, movement) => {
|
|
42999
43026
|
const row = rowRef.current;
|
|
43000
43027
|
// Already moving, so there is no ease-in to play: it would stall the row for an
|
|
43001
43028
|
// instant right where the eye is following it.
|
|
43002
43029
|
const replaced = movement.playing;
|
|
43003
43030
|
const inFlight = Boolean(replaced) || Boolean(movement.rowTaken);
|
|
43031
|
+
// Before the row is read: let go of for an instant, it would be snapped to the
|
|
43032
|
+
// nearest page by that read, and the travel would start from there.
|
|
43033
|
+
row.setAttribute("data-route-row-travelling", "");
|
|
43004
43034
|
if (replaced) {
|
|
43005
|
-
|
|
43006
|
-
|
|
43007
|
-
replaced.cancelFrame();
|
|
43035
|
+
replaced.cancel();
|
|
43036
|
+
movement.playing = null;
|
|
43008
43037
|
}
|
|
43009
43038
|
const from = row.scrollLeft;
|
|
43010
43039
|
const {
|
|
@@ -43016,56 +43045,70 @@ const RouteTravel = ({
|
|
|
43016
43045
|
const travelMs = boxes < 1 ? durationMs * boxes : durationMs;
|
|
43017
43046
|
if (!travelMs) {
|
|
43018
43047
|
row.scrollLeft = pane.offsetLeft;
|
|
43048
|
+
letRowGo(movement);
|
|
43019
43049
|
// A write that changes nothing is followed by no scroll event to say the row
|
|
43020
43050
|
// stopped. After the commit that asked, which goes on to say the row moves.
|
|
43021
43051
|
Promise.resolve().then(landRow);
|
|
43022
43052
|
return;
|
|
43023
43053
|
}
|
|
43024
43054
|
const curve = inFlight ? CSS_EASE_OUT : CSS_EASE;
|
|
43025
|
-
let start = null;
|
|
43026
43055
|
let frame = null;
|
|
43056
|
+
// How much of the travel has played, frame by frame. A travel setting off plays
|
|
43057
|
+
// nothing at its first frame, which may have begun while the press was still being
|
|
43058
|
+
// handled: that is no travel. One taking over goes on from the last frame of the
|
|
43059
|
+
// one it replaces, or the row would stand still for a frame where the eye follows it.
|
|
43060
|
+
let played = 0;
|
|
43027
43061
|
const playing = {
|
|
43028
43062
|
// Where this travel put the row, for a scroll event to tell it from a hand.
|
|
43029
43063
|
written: from,
|
|
43030
|
-
|
|
43064
|
+
lastFrame: replaced ? replaced.lastFrame : null,
|
|
43065
|
+
cancel: () => {
|
|
43031
43066
|
cancelAnimationFrame(frame);
|
|
43032
|
-
},
|
|
43033
|
-
stop: () => {
|
|
43034
|
-
playing.cancelFrame();
|
|
43035
|
-
if (movement.playing === playing) {
|
|
43036
|
-
movement.playing = null;
|
|
43037
|
-
row.removeAttribute("data-route-row-travelling");
|
|
43038
|
-
}
|
|
43039
43067
|
}
|
|
43040
43068
|
};
|
|
43041
43069
|
const step = now => {
|
|
43042
|
-
if (
|
|
43043
|
-
|
|
43044
|
-
|
|
43045
|
-
|
|
43070
|
+
if (playing.lastFrame !== null) {
|
|
43071
|
+
const gap = now - playing.lastFrame;
|
|
43072
|
+
if (gap > TRAVEL_FRAME_MAX_MS) {
|
|
43073
|
+
played += TRAVEL_FRAME_MAX_MS;
|
|
43074
|
+
} else if (gap > 0) {
|
|
43075
|
+
played += gap;
|
|
43076
|
+
}
|
|
43046
43077
|
}
|
|
43047
|
-
|
|
43048
|
-
const elapsed =
|
|
43078
|
+
playing.lastFrame = now;
|
|
43079
|
+
const elapsed = played / travelMs;
|
|
43049
43080
|
// Read at every frame: the layout may move under the travel (a scrollbar
|
|
43050
43081
|
// coming in narrows the row), and it goes where the page stands.
|
|
43051
43082
|
const to = pane.offsetLeft;
|
|
43052
43083
|
const arrived = elapsed >= 1;
|
|
43053
43084
|
playing.written = arrived ? to : from + (to - from) * easedProgress(elapsed, curve);
|
|
43054
43085
|
row.scrollLeft = playing.written;
|
|
43086
|
+
// In the frame it is written: the scroll event saying so comes a frame later,
|
|
43087
|
+
// and what follows the row would be drawn a frame behind it.
|
|
43088
|
+
sayRowMoves();
|
|
43055
43089
|
if (!arrived) {
|
|
43056
43090
|
frame = requestAnimationFrame(step);
|
|
43057
43091
|
return;
|
|
43058
43092
|
}
|
|
43059
|
-
|
|
43093
|
+
letRowGo(movement);
|
|
43060
43094
|
// Said here rather than waited for: the last frames of a curve can move the row
|
|
43061
43095
|
// by less than a pixel, and nothing then says it has stopped.
|
|
43062
43096
|
landRow();
|
|
43063
43097
|
};
|
|
43064
43098
|
movement.playing = playing;
|
|
43065
|
-
row.setAttribute("data-route-row-travelling", "");
|
|
43066
43099
|
frame = requestAnimationFrame(step);
|
|
43067
43100
|
};
|
|
43068
43101
|
|
|
43102
|
+
// The row given back to the browser: no travel writes it any more, and it snaps
|
|
43103
|
+
// again. A travel replacing another keeps it (playTravel).
|
|
43104
|
+
const letRowGo = movement => {
|
|
43105
|
+
if (movement.playing) {
|
|
43106
|
+
movement.playing.cancel();
|
|
43107
|
+
movement.playing = null;
|
|
43108
|
+
}
|
|
43109
|
+
rowRef.current.removeAttribute("data-route-row-travelling");
|
|
43110
|
+
};
|
|
43111
|
+
|
|
43069
43112
|
// Every column back where the map says, and the row on the page of the address, in
|
|
43070
43113
|
// one go: that page stands at the same place on screen either way.
|
|
43071
43114
|
const putRowBack = movement => {
|
|
@@ -43122,14 +43165,12 @@ const RouteTravel = ({
|
|
|
43122
43165
|
return;
|
|
43123
43166
|
}
|
|
43124
43167
|
movementRef.current = null;
|
|
43125
|
-
|
|
43126
|
-
movement.playing.stop();
|
|
43127
|
-
}
|
|
43168
|
+
letRowGo(movement);
|
|
43128
43169
|
putRowBack(movement);
|
|
43129
|
-
row.removeAttribute("data-route-row-travelling");
|
|
43130
43170
|
row.removeAttribute("data-route-row-taken");
|
|
43131
43171
|
publishRouteRowMove(null);
|
|
43132
43172
|
releaseHeldPage();
|
|
43173
|
+
releasePaneAtRest();
|
|
43133
43174
|
if (liveRef.current) {
|
|
43134
43175
|
liveRef.current.style.top = "";
|
|
43135
43176
|
}
|
|
@@ -43242,9 +43283,11 @@ const RouteTravel = ({
|
|
|
43242
43283
|
return;
|
|
43243
43284
|
}
|
|
43244
43285
|
const movementBefore = movementRef.current;
|
|
43286
|
+
// The row still rests on the page answered before. Held in the commit that made
|
|
43287
|
+
// its pane inert, so no frame paints it contained.
|
|
43245
43288
|
const movement = beginMovement({
|
|
43246
43289
|
travelling: true
|
|
43247
|
-
});
|
|
43290
|
+
}, panesOf(row)[pages.findIndex(each => samePage(each, answered))]);
|
|
43248
43291
|
if (movementBefore?.byHand && !movementBefore.rowTaken) {
|
|
43249
43292
|
sayRowMoves();
|
|
43250
43293
|
takeRowFromHand(movement);
|
|
@@ -43303,7 +43346,7 @@ const RouteTravel = ({
|
|
|
43303
43346
|
// Not where the travel put it: a hand has taken the row (a trackpad, a wheel),
|
|
43304
43347
|
// and the travel lets it go, snapping included, as the browser's own scroll does.
|
|
43305
43348
|
if (moving?.playing && Math.abs(row.scrollLeft - moving.playing.written) > WRITE_ROUNDING) {
|
|
43306
|
-
moving
|
|
43349
|
+
letRowGo(moving);
|
|
43307
43350
|
}
|
|
43308
43351
|
const pane = panes[currentIndex];
|
|
43309
43352
|
if (!moving && pane && restsOn(row, pane, ROW_READING)) {
|
|
@@ -43312,7 +43355,7 @@ const RouteTravel = ({
|
|
|
43312
43355
|
}
|
|
43313
43356
|
const movement = moving || beginMovement({
|
|
43314
43357
|
byHand: true
|
|
43315
|
-
});
|
|
43358
|
+
}, pane);
|
|
43316
43359
|
sayRowMoves();
|
|
43317
43360
|
if (movement.travelling || !travelByDrag || !pane) {
|
|
43318
43361
|
return;
|
|
@@ -43381,7 +43424,8 @@ const RouteTravel = ({
|
|
|
43381
43424
|
askForPageOfRow(index, movement);
|
|
43382
43425
|
}
|
|
43383
43426
|
// After the address: a pull coming back to its page must not light the tab the
|
|
43384
|
-
// address ran ahead to, even for a render.
|
|
43427
|
+
// address ran ahead to, even for a render. Only what readers are told: the
|
|
43428
|
+
// panes keep their layout until the row rests.
|
|
43385
43429
|
releaseHeldPage();
|
|
43386
43430
|
};
|
|
43387
43431
|
const stopWatching = watchRowScroll(row, {
|
|
@@ -43432,12 +43476,14 @@ const RouteTravel = ({
|
|
|
43432
43476
|
});
|
|
43433
43477
|
const movement = movementRef.current;
|
|
43434
43478
|
if (movement) {
|
|
43435
|
-
movement.playing?.
|
|
43479
|
+
movement.playing?.cancel();
|
|
43436
43480
|
movement.resumeScrollRecording?.();
|
|
43437
43481
|
}
|
|
43482
|
+
row.removeAttribute("data-route-row-travelling");
|
|
43438
43483
|
movementRef.current = null;
|
|
43439
43484
|
publishRouteRowMove(null);
|
|
43440
43485
|
releaseHeldPage();
|
|
43486
|
+
releasePaneAtRest();
|
|
43441
43487
|
};
|
|
43442
43488
|
}, [windowed]);
|
|
43443
43489
|
|