@jsenv/navi 0.30.33 → 0.30.34
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 +79 -35
- package/dist/dev/jsenv_navi.js.map +2 -2
- package/dist/jsenv_navi.js +79 -35
- package/dist/jsenv_navi.js.map +2 -2
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -41368,7 +41368,7 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
41368
41368
|
display: flex;
|
|
41369
41369
|
}
|
|
41370
41370
|
|
|
41371
|
-
& > [data-route-row-pane][inert] {
|
|
41371
|
+
& > [data-route-row-pane][inert]:not([data-route-row-held]), &:has( > [data-route-row-held]) > [data-route-row-pane]:not([data-route-row-held]) {
|
|
41372
41372
|
top: var(--navi-route-row-pin, 0);
|
|
41373
41373
|
contain: paint;
|
|
41374
41374
|
max-height: 100dvh;
|
|
@@ -41418,6 +41418,12 @@ const ROW_READING = {
|
|
|
41418
41418
|
// How far a scroll position written can read back from what was written: rounded to
|
|
41419
41419
|
// the device's pixels.
|
|
41420
41420
|
const WRITE_ROUNDING = 1;
|
|
41421
|
+
// The most one frame of a travel plays: a frame of a 30fps screen, which is what a
|
|
41422
|
+
// browser saving power gives (an iPhone in Low Power Mode, Chrome's Energy Saver).
|
|
41423
|
+
// A frame later than that is a main thread busy elsewhere (the page arriving builds,
|
|
41424
|
+
// a list fills its budget), and the travel takes longer rather than jump by it. Not a
|
|
41425
|
+
// frame of a 60Hz screen: that would play every travel in slow motion at 30fps.
|
|
41426
|
+
const TRAVEL_FRAME_MAX_MS = 1000 / 30;
|
|
41421
41427
|
|
|
41422
41428
|
/**
|
|
41423
41429
|
* @type {import("preact").FunctionComponent<{
|
|
@@ -41693,18 +41699,22 @@ const RouteTravel = ({
|
|
|
41693
41699
|
// hesitates, then peaks at 1.65 times this one's speed): two rows of tabs in one
|
|
41694
41700
|
// app would not move alike. The scroll position is written at every frame, so the
|
|
41695
41701
|
// row stays a scroller all the way: what follows it (a Nav's bar) reads it as it
|
|
41696
|
-
// reads a hand, and a finger landing finds it where it is.
|
|
41697
|
-
//
|
|
41702
|
+
// reads a hand, and a finger landing finds it where it is. That is played on the
|
|
41703
|
+
// main thread: a transform on the panes would play on the compositor, but it would
|
|
41704
|
+
// capture what the page on screen holds in position: fixed. Hence a clock of its
|
|
41705
|
+
// own, which a busy main thread slows down rather than makes jump.
|
|
41698
41706
|
const playTravel = (pane, movement) => {
|
|
41699
41707
|
const row = rowRef.current;
|
|
41700
41708
|
// Already moving, so there is no ease-in to play: it would stall the row for an
|
|
41701
41709
|
// instant right where the eye is following it.
|
|
41702
41710
|
const replaced = movement.playing;
|
|
41703
41711
|
const inFlight = Boolean(replaced) || Boolean(movement.rowTaken);
|
|
41712
|
+
// Before the row is read: let go of for an instant, it would be snapped to the
|
|
41713
|
+
// nearest page by that read, and the travel would start from there.
|
|
41714
|
+
row.setAttribute("data-route-row-travelling", "");
|
|
41704
41715
|
if (replaced) {
|
|
41705
|
-
|
|
41706
|
-
|
|
41707
|
-
replaced.cancelFrame();
|
|
41716
|
+
replaced.cancel();
|
|
41717
|
+
movement.playing = null;
|
|
41708
41718
|
}
|
|
41709
41719
|
const from = row.scrollLeft;
|
|
41710
41720
|
const {
|
|
@@ -41716,56 +41726,88 @@ const RouteTravel = ({
|
|
|
41716
41726
|
const travelMs = boxes < 1 ? durationMs * boxes : durationMs;
|
|
41717
41727
|
if (!travelMs) {
|
|
41718
41728
|
row.scrollLeft = pane.offsetLeft;
|
|
41729
|
+
letRowGo(movement);
|
|
41719
41730
|
// A write that changes nothing is followed by no scroll event to say the row
|
|
41720
41731
|
// stopped. After the commit that asked, which goes on to say the row moves.
|
|
41721
41732
|
Promise.resolve().then(landRow);
|
|
41722
41733
|
return;
|
|
41723
41734
|
}
|
|
41724
41735
|
const curve = inFlight ? CSS_EASE_OUT : CSS_EASE;
|
|
41725
|
-
let start = null;
|
|
41726
41736
|
let frame = null;
|
|
41737
|
+
// How much of the travel has played, frame by frame. A travel setting off plays
|
|
41738
|
+
// nothing at its first frame, which may have begun while the press was still being
|
|
41739
|
+
// handled: that is no travel. One taking over goes on from the last frame of the
|
|
41740
|
+
// one it replaces, or the row would stand still for a frame where the eye follows it.
|
|
41741
|
+
let played = 0;
|
|
41727
41742
|
const playing = {
|
|
41728
41743
|
// Where this travel put the row, for a scroll event to tell it from a hand.
|
|
41729
41744
|
written: from,
|
|
41730
|
-
|
|
41745
|
+
lastFrame: replaced ? replaced.lastFrame : null,
|
|
41746
|
+
cancel: () => {
|
|
41731
41747
|
cancelAnimationFrame(frame);
|
|
41732
|
-
},
|
|
41733
|
-
stop: () => {
|
|
41734
|
-
playing.cancelFrame();
|
|
41735
|
-
if (movement.playing === playing) {
|
|
41736
|
-
movement.playing = null;
|
|
41737
|
-
row.removeAttribute("data-route-row-travelling");
|
|
41738
|
-
}
|
|
41739
41748
|
}
|
|
41740
41749
|
};
|
|
41741
41750
|
const step = now => {
|
|
41742
|
-
if (
|
|
41743
|
-
|
|
41744
|
-
|
|
41745
|
-
|
|
41751
|
+
if (playing.lastFrame !== null) {
|
|
41752
|
+
const gap = now - playing.lastFrame;
|
|
41753
|
+
if (gap > TRAVEL_FRAME_MAX_MS) {
|
|
41754
|
+
played += TRAVEL_FRAME_MAX_MS;
|
|
41755
|
+
} else if (gap > 0) {
|
|
41756
|
+
played += gap;
|
|
41757
|
+
}
|
|
41746
41758
|
}
|
|
41747
|
-
|
|
41748
|
-
const elapsed =
|
|
41759
|
+
playing.lastFrame = now;
|
|
41760
|
+
const elapsed = played / travelMs;
|
|
41749
41761
|
// Read at every frame: the layout may move under the travel (a scrollbar
|
|
41750
41762
|
// coming in narrows the row), and it goes where the page stands.
|
|
41751
41763
|
const to = pane.offsetLeft;
|
|
41752
41764
|
const arrived = elapsed >= 1;
|
|
41753
41765
|
playing.written = arrived ? to : from + (to - from) * easedProgress(elapsed, curve);
|
|
41754
41766
|
row.scrollLeft = playing.written;
|
|
41767
|
+
// In the frame it is written: the scroll event saying so comes a frame later,
|
|
41768
|
+
// and what follows the row would be drawn a frame behind it.
|
|
41769
|
+
sayRowMoves();
|
|
41755
41770
|
if (!arrived) {
|
|
41756
41771
|
frame = requestAnimationFrame(step);
|
|
41757
41772
|
return;
|
|
41758
41773
|
}
|
|
41759
|
-
|
|
41774
|
+
letRowGo(movement);
|
|
41760
41775
|
// Said here rather than waited for: the last frames of a curve can move the row
|
|
41761
41776
|
// by less than a pixel, and nothing then says it has stopped.
|
|
41762
41777
|
landRow();
|
|
41763
41778
|
};
|
|
41764
41779
|
movement.playing = playing;
|
|
41765
|
-
row.setAttribute("data-route-row-travelling", "");
|
|
41766
41780
|
frame = requestAnimationFrame(step);
|
|
41767
41781
|
};
|
|
41768
41782
|
|
|
41783
|
+
// The row given back to the browser: no travel writes it any more, and it snaps
|
|
41784
|
+
// again. A travel replacing another keeps it (playTravel).
|
|
41785
|
+
const letRowGo = movement => {
|
|
41786
|
+
if (movement.playing) {
|
|
41787
|
+
movement.playing.cancel();
|
|
41788
|
+
movement.playing = null;
|
|
41789
|
+
}
|
|
41790
|
+
rowRef.current.removeAttribute("data-route-row-travelling");
|
|
41791
|
+
};
|
|
41792
|
+
|
|
41793
|
+
// The address runs ahead of a hand to build the page it pulls towards (onScroll):
|
|
41794
|
+
// the pane under the hand stays laid out as the page on screen until the hand lets
|
|
41795
|
+
// go, whatever `inert` says (see the CSS). What reads the page held is told apart
|
|
41796
|
+
// (route_travel_hold.js), and both are let go of together.
|
|
41797
|
+
const heldPaneRef = useRef(null);
|
|
41798
|
+
const holdPaneOnScreen = pane => {
|
|
41799
|
+
heldPaneRef.current = pane;
|
|
41800
|
+
pane.setAttribute("data-route-row-held", "");
|
|
41801
|
+
};
|
|
41802
|
+
const releaseHold = () => {
|
|
41803
|
+
releaseHeldPage();
|
|
41804
|
+
const heldPane = heldPaneRef.current;
|
|
41805
|
+
if (heldPane) {
|
|
41806
|
+
heldPaneRef.current = null;
|
|
41807
|
+
heldPane.removeAttribute("data-route-row-held");
|
|
41808
|
+
}
|
|
41809
|
+
};
|
|
41810
|
+
|
|
41769
41811
|
// Every column back where the map says, and the row on the page of the address, in
|
|
41770
41812
|
// one go: that page stands at the same place on screen either way.
|
|
41771
41813
|
const putRowBack = movement => {
|
|
@@ -41794,7 +41836,7 @@ const RouteTravel = ({
|
|
|
41794
41836
|
const position = row.scrollLeft;
|
|
41795
41837
|
movement.rowTaken = true;
|
|
41796
41838
|
// A travel no hand set off holds nothing: it goes where it goes.
|
|
41797
|
-
|
|
41839
|
+
releaseHold();
|
|
41798
41840
|
row.style.setProperty("--navi-route-row-stand", `${-position}px`);
|
|
41799
41841
|
row.setAttribute("data-route-row-taken", "");
|
|
41800
41842
|
afterFrames(2, () => {
|
|
@@ -41822,14 +41864,11 @@ const RouteTravel = ({
|
|
|
41822
41864
|
return;
|
|
41823
41865
|
}
|
|
41824
41866
|
movementRef.current = null;
|
|
41825
|
-
|
|
41826
|
-
movement.playing.stop();
|
|
41827
|
-
}
|
|
41867
|
+
letRowGo(movement);
|
|
41828
41868
|
putRowBack(movement);
|
|
41829
|
-
row.removeAttribute("data-route-row-travelling");
|
|
41830
41869
|
row.removeAttribute("data-route-row-taken");
|
|
41831
41870
|
publishRouteRowMove(null);
|
|
41832
|
-
|
|
41871
|
+
releaseHold();
|
|
41833
41872
|
if (liveRef.current) {
|
|
41834
41873
|
liveRef.current.style.top = "";
|
|
41835
41874
|
}
|
|
@@ -42003,7 +42042,7 @@ const RouteTravel = ({
|
|
|
42003
42042
|
// Not where the travel put it: a hand has taken the row (a trackpad, a wheel),
|
|
42004
42043
|
// and the travel lets it go, snapping included, as the browser's own scroll does.
|
|
42005
42044
|
if (moving?.playing && Math.abs(row.scrollLeft - moving.playing.written) > WRITE_ROUNDING) {
|
|
42006
|
-
moving
|
|
42045
|
+
letRowGo(moving);
|
|
42007
42046
|
}
|
|
42008
42047
|
const pane = panes[currentIndex];
|
|
42009
42048
|
if (!moving && pane && restsOn(row, pane, ROW_READING)) {
|
|
@@ -42049,8 +42088,12 @@ const RouteTravel = ({
|
|
|
42049
42088
|
return;
|
|
42050
42089
|
}
|
|
42051
42090
|
leavePictureOfLive(movement);
|
|
42052
|
-
} else
|
|
42053
|
-
|
|
42091
|
+
} else {
|
|
42092
|
+
if (paneTowards.hasAttribute("data-built")) {
|
|
42093
|
+
return;
|
|
42094
|
+
}
|
|
42095
|
+
// Before the address moves: the render that makes it inert must find it held.
|
|
42096
|
+
holdPaneOnScreen(pane);
|
|
42054
42097
|
}
|
|
42055
42098
|
holdPage(pages[currentIndex], page);
|
|
42056
42099
|
askFor(page);
|
|
@@ -42082,7 +42125,7 @@ const RouteTravel = ({
|
|
|
42082
42125
|
}
|
|
42083
42126
|
// After the address: a pull coming back to its page must not light the tab the
|
|
42084
42127
|
// address ran ahead to, even for a render.
|
|
42085
|
-
|
|
42128
|
+
releaseHold();
|
|
42086
42129
|
};
|
|
42087
42130
|
const stopWatching = watchRowScroll(row, {
|
|
42088
42131
|
onScroll,
|
|
@@ -42132,12 +42175,13 @@ const RouteTravel = ({
|
|
|
42132
42175
|
});
|
|
42133
42176
|
const movement = movementRef.current;
|
|
42134
42177
|
if (movement) {
|
|
42135
|
-
movement.playing?.
|
|
42178
|
+
movement.playing?.cancel();
|
|
42136
42179
|
movement.resumeScrollRecording?.();
|
|
42137
42180
|
}
|
|
42181
|
+
row.removeAttribute("data-route-row-travelling");
|
|
42138
42182
|
movementRef.current = null;
|
|
42139
42183
|
publishRouteRowMove(null);
|
|
42140
|
-
|
|
42184
|
+
releaseHold();
|
|
42141
42185
|
};
|
|
42142
42186
|
}, [windowed]);
|
|
42143
42187
|
|