@jsenv/navi 0.30.37 → 0.30.39
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 +96 -24
- package/dist/dev/jsenv_navi.js.map +4 -4
- package/dist/jsenv_navi.js +96 -24
- package/dist/jsenv_navi.js.map +4 -4
- package/docs/scroll.md +6 -0
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -41316,7 +41316,17 @@ const watchRowScroll = (
|
|
|
41316
41316
|
};
|
|
41317
41317
|
|
|
41318
41318
|
installImportMetaCssBuild(import.meta);
|
|
41319
|
-
const css$16 = /* css
|
|
41319
|
+
const css$16 = /* css */`@property --navi-route-row-pin {
|
|
41320
|
+
syntax: "*";
|
|
41321
|
+
inherits: false
|
|
41322
|
+
}
|
|
41323
|
+
|
|
41324
|
+
@property --navi-route-row-stand {
|
|
41325
|
+
syntax: "*";
|
|
41326
|
+
inherits: false
|
|
41327
|
+
}
|
|
41328
|
+
|
|
41329
|
+
.navi_route_travel {
|
|
41320
41330
|
flex-direction: column;
|
|
41321
41331
|
display: flex;
|
|
41322
41332
|
position: relative;
|
|
@@ -41372,7 +41382,7 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
41372
41382
|
display: flex;
|
|
41373
41383
|
}
|
|
41374
41384
|
|
|
41375
|
-
& > [data-route-row-pane][inert]:not([data-route-row-held]),
|
|
41385
|
+
& > [data-route-row-pane][inert]:not([data-route-row-held]), &[data-route-row-holding] > [data-route-row-pane]:not([data-route-row-held]) {
|
|
41376
41386
|
top: var(--navi-route-row-pin, 0);
|
|
41377
41387
|
contain: paint;
|
|
41378
41388
|
max-height: 100dvh;
|
|
@@ -41544,11 +41554,25 @@ const RouteTravel = ({
|
|
|
41544
41554
|
// when the row rests. Not what readers are told the page held is
|
|
41545
41555
|
// (route_travel_hold.js): that follows the hand, and goes at its lift.
|
|
41546
41556
|
const heldPaneRef = useRef(null);
|
|
41547
|
-
const releasePaneAtRest =
|
|
41557
|
+
const releasePaneAtRest = row => {
|
|
41548
41558
|
const heldPane = heldPaneRef.current;
|
|
41549
41559
|
if (heldPane) {
|
|
41550
41560
|
heldPaneRef.current = null;
|
|
41551
41561
|
heldPane.removeAttribute("data-route-row-held");
|
|
41562
|
+
row.removeAttribute("data-route-row-holding");
|
|
41563
|
+
}
|
|
41564
|
+
};
|
|
41565
|
+
|
|
41566
|
+
// How far down the reader is looking, on every pane, for those the CSS pins.
|
|
41567
|
+
const pinPanes = row => {
|
|
41568
|
+
const pin = `${pinOf(row)}px`;
|
|
41569
|
+
for (const pane of panesOf(row)) {
|
|
41570
|
+
pane.style.setProperty("--navi-route-row-pin", pin);
|
|
41571
|
+
}
|
|
41572
|
+
};
|
|
41573
|
+
const unpinPanes = row => {
|
|
41574
|
+
for (const pane of panesOf(row)) {
|
|
41575
|
+
pane.style.removeProperty("--navi-route-row-pin");
|
|
41552
41576
|
}
|
|
41553
41577
|
};
|
|
41554
41578
|
|
|
@@ -41575,13 +41599,14 @@ const RouteTravel = ({
|
|
|
41575
41599
|
if (!windowed && paneAtRest) {
|
|
41576
41600
|
heldPaneRef.current = paneAtRest;
|
|
41577
41601
|
paneAtRest.setAttribute("data-route-row-held", "");
|
|
41602
|
+
row.setAttribute("data-route-row-holding", "");
|
|
41578
41603
|
}
|
|
41579
41604
|
if (movement.scrollsDocument) {
|
|
41580
41605
|
// Whatever the browser does with the offset meanwhile (clamping it to a page
|
|
41581
41606
|
// shorter than the trip) is not the reader scrolling, and the address it
|
|
41582
41607
|
// would be written against may already be another page's.
|
|
41583
41608
|
movement.resumeScrollRecording = suspendScrollRecording();
|
|
41584
|
-
|
|
41609
|
+
pinPanes(row);
|
|
41585
41610
|
}
|
|
41586
41611
|
return movement;
|
|
41587
41612
|
};
|
|
@@ -41842,16 +41867,14 @@ const RouteTravel = ({
|
|
|
41842
41867
|
movement.rowTaken = true;
|
|
41843
41868
|
// A travel no hand set off holds nothing: it goes where it goes.
|
|
41844
41869
|
releaseHeldPage();
|
|
41845
|
-
|
|
41846
|
-
row.setAttribute("data-route-row-taken", "");
|
|
41870
|
+
holdRowAt(row, position);
|
|
41847
41871
|
afterFrames(2, () => {
|
|
41848
41872
|
if (movementRef.current !== movement) {
|
|
41849
41873
|
return;
|
|
41850
41874
|
}
|
|
41851
41875
|
// A scroller again, standing where no page does: not snapped meanwhile.
|
|
41852
41876
|
row.setAttribute("data-route-row-travelling", "");
|
|
41853
|
-
|
|
41854
|
-
row.style.removeProperty("--navi-route-row-stand");
|
|
41877
|
+
releaseTakenRow(row);
|
|
41855
41878
|
afterFrames(1, () => {
|
|
41856
41879
|
if (movementRef.current === movement) {
|
|
41857
41880
|
travelRowTo(latestRef.current.currentIndex, movement);
|
|
@@ -41871,10 +41894,10 @@ const RouteTravel = ({
|
|
|
41871
41894
|
movementRef.current = null;
|
|
41872
41895
|
letRowGo(movement);
|
|
41873
41896
|
putRowBack(movement);
|
|
41874
|
-
|
|
41897
|
+
releaseTakenRow(row);
|
|
41875
41898
|
publishRouteRowMove(null);
|
|
41876
41899
|
releaseHeldPage();
|
|
41877
|
-
releasePaneAtRest();
|
|
41900
|
+
releasePaneAtRest(row);
|
|
41878
41901
|
if (liveRef.current) {
|
|
41879
41902
|
liveRef.current.style.top = "";
|
|
41880
41903
|
}
|
|
@@ -41882,7 +41905,7 @@ const RouteTravel = ({
|
|
|
41882
41905
|
picture.remove();
|
|
41883
41906
|
}
|
|
41884
41907
|
if (movement.scrollsDocument) {
|
|
41885
|
-
|
|
41908
|
+
unpinPanes(row);
|
|
41886
41909
|
const {
|
|
41887
41910
|
pages,
|
|
41888
41911
|
currentIndex
|
|
@@ -42187,7 +42210,7 @@ const RouteTravel = ({
|
|
|
42187
42210
|
movementRef.current = null;
|
|
42188
42211
|
publishRouteRowMove(null);
|
|
42189
42212
|
releaseHeldPage();
|
|
42190
|
-
releasePaneAtRest();
|
|
42213
|
+
releasePaneAtRest(row);
|
|
42191
42214
|
};
|
|
42192
42215
|
}, [windowed]);
|
|
42193
42216
|
|
|
@@ -42251,7 +42274,7 @@ const RouteTravel = ({
|
|
|
42251
42274
|
const row = rowRef.current;
|
|
42252
42275
|
const onTouchStart = () => {
|
|
42253
42276
|
if (!movementRef.current && rowFollowsDocument(row)) {
|
|
42254
|
-
|
|
42277
|
+
pinPanes(row);
|
|
42255
42278
|
}
|
|
42256
42279
|
};
|
|
42257
42280
|
row.addEventListener("touchstart", onTouchStart, {
|
|
@@ -42349,6 +42372,22 @@ const copyScrollPositions = (from, to) => {
|
|
|
42349
42372
|
// A tab pressed over a row a hand has left moving holds it still (takeRowFromHand):
|
|
42350
42373
|
// what the row says meanwhile is not a hand moving it.
|
|
42351
42374
|
const isRowTaken = row => row.hasAttribute("data-route-row-taken");
|
|
42375
|
+
|
|
42376
|
+
// What the CSS offsets while the row is taken. A picture left meanwhile is a clone
|
|
42377
|
+
// of the live page, and takes its offset along.
|
|
42378
|
+
const STANDING_IN_ROW = ":scope > [data-route-row-pane], :scope > [data-route-row-live], :scope > [data-route-row-pictures] > *";
|
|
42379
|
+
const holdRowAt = (row, position) => {
|
|
42380
|
+
for (const element of row.querySelectorAll(STANDING_IN_ROW)) {
|
|
42381
|
+
element.style.setProperty("--navi-route-row-stand", `${-position}px`);
|
|
42382
|
+
}
|
|
42383
|
+
row.setAttribute("data-route-row-taken", "");
|
|
42384
|
+
};
|
|
42385
|
+
const releaseTakenRow = row => {
|
|
42386
|
+
row.removeAttribute("data-route-row-taken");
|
|
42387
|
+
for (const element of row.querySelectorAll(STANDING_IN_ROW)) {
|
|
42388
|
+
element.style.removeProperty("--navi-route-row-stand");
|
|
42389
|
+
}
|
|
42390
|
+
};
|
|
42352
42391
|
const afterFrames = (count, callback) => {
|
|
42353
42392
|
if (count === 0) {
|
|
42354
42393
|
callback();
|
|
@@ -82543,9 +82582,15 @@ const PickerNaviMinute = props => {
|
|
|
82543
82582
|
* element crossing the cursor — a dozen per wheel tick. Those hovers are noise:
|
|
82544
82583
|
* the user asked to scroll, not to hover. Anything doing real work on hover (a
|
|
82545
82584
|
* map highlight, a preview, a prefetch) then pays for that noise on the main
|
|
82546
|
-
* thread, exactly while a scroll animation is running. A rule
|
|
82547
|
-
* `[navi-scrolling]
|
|
82548
|
-
*
|
|
82585
|
+
* thread, exactly while a scroll animation is running. A rule like
|
|
82586
|
+
* `[navi-scrolling] .my_row { pointer-events: none }` takes the rows out of
|
|
82587
|
+
* hit-testing and the browser suppresses it all.
|
|
82588
|
+
*
|
|
82589
|
+
* Such a rule must end on a class (or an id, a tag, an attribute) of what it
|
|
82590
|
+
* styles: Chrome then restyles only those elements when the attribute comes and
|
|
82591
|
+
* goes. One ending on `*`, including `.my_row:is([navi-scrolling] *)`, gives it
|
|
82592
|
+
* nothing to narrow to, so it restyles everything under the scroller (the whole
|
|
82593
|
+
* document when the page scrolls) at the start and at the end of every scroll.
|
|
82549
82594
|
*
|
|
82550
82595
|
* One capturing listener on the document sees them all: "scroll" does not
|
|
82551
82596
|
* bubble, but it does propagate in the capture phase.
|
|
@@ -84927,7 +84972,7 @@ const css$w = /* css */`@property --list-group-label-height {
|
|
|
84927
84972
|
}
|
|
84928
84973
|
}
|
|
84929
84974
|
|
|
84930
|
-
&:not([navi-hover-while-scrolling]) > .navi_list_scroll_container > .navi_list:
|
|
84975
|
+
[navi-scrolling] &:not([navi-hover-while-scrolling]) > .navi_list_scroll_container > .navi_list, &[navi-scrolling]:not([navi-hover-while-scrolling]) > .navi_list_scroll_container > .navi_list, &:not([navi-hover-while-scrolling]) > .navi_list_scroll_container[navi-scrolling] > .navi_list {
|
|
84931
84976
|
pointer-events: none;
|
|
84932
84977
|
}
|
|
84933
84978
|
|
|
@@ -86594,7 +86639,7 @@ const useListScrollSync = ({
|
|
|
86594
86639
|
// where it lands.
|
|
86595
86640
|
if (listItems.pagesSignal.peek() === 0) {
|
|
86596
86641
|
if (typeof scrolledWanted.index === "number") {
|
|
86597
|
-
placeItem(findItemElementAt(getListEl(), scrolledWanted.index), scrolledWanted.offset || 0);
|
|
86642
|
+
placeItem(findItemElementAt(getListEl(), scrolledWanted.index), scrolledWanted.offset || 0, scrolledWanted.align);
|
|
86598
86643
|
}
|
|
86599
86644
|
return;
|
|
86600
86645
|
}
|
|
@@ -86658,11 +86703,13 @@ const useListScrollSync = ({
|
|
|
86658
86703
|
const itemRect = itemEl.getBoundingClientRect();
|
|
86659
86704
|
const viewportSize = (horizontal ? viewportRect.width : viewportRect.height) / scale;
|
|
86660
86705
|
const itemSize = (horizontal ? itemRect.width : itemRect.height) / scale;
|
|
86661
|
-
const
|
|
86662
|
-
|
|
86663
|
-
|
|
86664
|
-
|
|
86665
|
-
|
|
86706
|
+
const offsetWanted = resolveHeldOffset({
|
|
86707
|
+
align,
|
|
86708
|
+
offset,
|
|
86709
|
+
scrollInset: getItemScrollInset(scrollerEl, itemEl, horizontal),
|
|
86710
|
+
viewportSize,
|
|
86711
|
+
itemSize
|
|
86712
|
+
});
|
|
86666
86713
|
const offsetNow = (horizontal ? itemRect.left - viewportRect.left : itemRect.top - viewportRect.top) / scale;
|
|
86667
86714
|
const scrollNow = horizontal ? scrollerEl.scrollLeft : scrollerEl.scrollTop;
|
|
86668
86715
|
const delta = offsetNow - offsetWanted;
|
|
@@ -87391,6 +87438,7 @@ const useListScrollSync = ({
|
|
|
87391
87438
|
}
|
|
87392
87439
|
let index = null;
|
|
87393
87440
|
let offset = 0;
|
|
87441
|
+
let align;
|
|
87394
87442
|
if (typeof wanted === "number") {
|
|
87395
87443
|
index = wanted;
|
|
87396
87444
|
} else if (wanted && wanted.id !== undefined) {
|
|
@@ -87399,6 +87447,7 @@ const useListScrollSync = ({
|
|
|
87399
87447
|
index = wanted.index;
|
|
87400
87448
|
}
|
|
87401
87449
|
offset = wanted.offset || 0;
|
|
87450
|
+
align = wanted.align;
|
|
87402
87451
|
}
|
|
87403
87452
|
if (index === null || index < 0 || index >= total) {
|
|
87404
87453
|
return null;
|
|
@@ -87409,7 +87458,15 @@ const useListScrollSync = ({
|
|
|
87409
87458
|
const rect = itemEl.getBoundingClientRect();
|
|
87410
87459
|
itemSize = horizontal ? rect.width : rect.height;
|
|
87411
87460
|
}
|
|
87412
|
-
|
|
87461
|
+
// Not drawn yet, the item weighs nothing and has no inset: centred, it
|
|
87462
|
+
// stands half the screen down, which is where it will be put.
|
|
87463
|
+
const above = resolveHeldOffset({
|
|
87464
|
+
align,
|
|
87465
|
+
offset,
|
|
87466
|
+
scrollInset: getItemScrollInset(scrollerEl, itemEl, horizontal),
|
|
87467
|
+
viewportSize: screenSize,
|
|
87468
|
+
itemSize
|
|
87469
|
+
});
|
|
87413
87470
|
return {
|
|
87414
87471
|
index,
|
|
87415
87472
|
above
|
|
@@ -87964,6 +88021,21 @@ const resolveOpenOffset = (offset, viewportSize, itemSize) => {
|
|
|
87964
88021
|
}
|
|
87965
88022
|
return offset;
|
|
87966
88023
|
};
|
|
88024
|
+
// How far from the start of the view an item held at `{ offset, align }`
|
|
88025
|
+
// stands: read the same way where the list is placed (placeItem) and where the
|
|
88026
|
+
// window is sized around it (readHold), or the window frames a screen the
|
|
88027
|
+
// item is not on. Centred in what the room at the start leaves of the view (a
|
|
88028
|
+
// fixed bar, a sticky header), not in the whole of it.
|
|
88029
|
+
const resolveHeldOffset = ({
|
|
88030
|
+
align,
|
|
88031
|
+
offset,
|
|
88032
|
+
scrollInset,
|
|
88033
|
+
viewportSize,
|
|
88034
|
+
itemSize
|
|
88035
|
+
}) => {
|
|
88036
|
+
const alignedOffset = align === "center" ? scrollInset + (viewportSize - scrollInset - itemSize) / 2 : align === "end" ? viewportSize - itemSize : scrollInset;
|
|
88037
|
+
return resolveOpenOffset(alignedOffset + offset, viewportSize, itemSize);
|
|
88038
|
+
};
|
|
87967
88039
|
|
|
87968
88040
|
// The room an item must be given at the top (or left) of the view: the
|
|
87969
88041
|
// scroller's own scroll-padding — where a fixed bar publishes the space it
|