@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/dev/jsenv_navi.js
CHANGED
|
@@ -42632,7 +42632,17 @@ const watchRowScroll = (
|
|
|
42632
42632
|
};
|
|
42633
42633
|
|
|
42634
42634
|
installImportMetaCssBuild(import.meta);
|
|
42635
|
-
const css$16 = /* css
|
|
42635
|
+
const css$16 = /* css */`@property --navi-route-row-pin {
|
|
42636
|
+
syntax: "*";
|
|
42637
|
+
inherits: false
|
|
42638
|
+
}
|
|
42639
|
+
|
|
42640
|
+
@property --navi-route-row-stand {
|
|
42641
|
+
syntax: "*";
|
|
42642
|
+
inherits: false
|
|
42643
|
+
}
|
|
42644
|
+
|
|
42645
|
+
.navi_route_travel {
|
|
42636
42646
|
flex-direction: column;
|
|
42637
42647
|
display: flex;
|
|
42638
42648
|
position: relative;
|
|
@@ -42688,7 +42698,7 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
42688
42698
|
display: flex;
|
|
42689
42699
|
}
|
|
42690
42700
|
|
|
42691
|
-
& > [data-route-row-pane][inert]:not([data-route-row-held]),
|
|
42701
|
+
& > [data-route-row-pane][inert]:not([data-route-row-held]), &[data-route-row-holding] > [data-route-row-pane]:not([data-route-row-held]) {
|
|
42692
42702
|
top: var(--navi-route-row-pin, 0);
|
|
42693
42703
|
contain: paint;
|
|
42694
42704
|
max-height: 100dvh;
|
|
@@ -42860,11 +42870,25 @@ const RouteTravel = ({
|
|
|
42860
42870
|
// when the row rests. Not what readers are told the page held is
|
|
42861
42871
|
// (route_travel_hold.js): that follows the hand, and goes at its lift.
|
|
42862
42872
|
const heldPaneRef = useRef(null);
|
|
42863
|
-
const releasePaneAtRest =
|
|
42873
|
+
const releasePaneAtRest = row => {
|
|
42864
42874
|
const heldPane = heldPaneRef.current;
|
|
42865
42875
|
if (heldPane) {
|
|
42866
42876
|
heldPaneRef.current = null;
|
|
42867
42877
|
heldPane.removeAttribute("data-route-row-held");
|
|
42878
|
+
row.removeAttribute("data-route-row-holding");
|
|
42879
|
+
}
|
|
42880
|
+
};
|
|
42881
|
+
|
|
42882
|
+
// How far down the reader is looking, on every pane, for those the CSS pins.
|
|
42883
|
+
const pinPanes = row => {
|
|
42884
|
+
const pin = `${pinOf(row)}px`;
|
|
42885
|
+
for (const pane of panesOf(row)) {
|
|
42886
|
+
pane.style.setProperty("--navi-route-row-pin", pin);
|
|
42887
|
+
}
|
|
42888
|
+
};
|
|
42889
|
+
const unpinPanes = row => {
|
|
42890
|
+
for (const pane of panesOf(row)) {
|
|
42891
|
+
pane.style.removeProperty("--navi-route-row-pin");
|
|
42868
42892
|
}
|
|
42869
42893
|
};
|
|
42870
42894
|
|
|
@@ -42891,13 +42915,14 @@ const RouteTravel = ({
|
|
|
42891
42915
|
if (!windowed && paneAtRest) {
|
|
42892
42916
|
heldPaneRef.current = paneAtRest;
|
|
42893
42917
|
paneAtRest.setAttribute("data-route-row-held", "");
|
|
42918
|
+
row.setAttribute("data-route-row-holding", "");
|
|
42894
42919
|
}
|
|
42895
42920
|
if (movement.scrollsDocument) {
|
|
42896
42921
|
// Whatever the browser does with the offset meanwhile (clamping it to a page
|
|
42897
42922
|
// shorter than the trip) is not the reader scrolling, and the address it
|
|
42898
42923
|
// would be written against may already be another page's.
|
|
42899
42924
|
movement.resumeScrollRecording = suspendScrollRecording();
|
|
42900
|
-
|
|
42925
|
+
pinPanes(row);
|
|
42901
42926
|
}
|
|
42902
42927
|
return movement;
|
|
42903
42928
|
};
|
|
@@ -43158,16 +43183,14 @@ const RouteTravel = ({
|
|
|
43158
43183
|
movement.rowTaken = true;
|
|
43159
43184
|
// A travel no hand set off holds nothing: it goes where it goes.
|
|
43160
43185
|
releaseHeldPage();
|
|
43161
|
-
|
|
43162
|
-
row.setAttribute("data-route-row-taken", "");
|
|
43186
|
+
holdRowAt(row, position);
|
|
43163
43187
|
afterFrames(2, () => {
|
|
43164
43188
|
if (movementRef.current !== movement) {
|
|
43165
43189
|
return;
|
|
43166
43190
|
}
|
|
43167
43191
|
// A scroller again, standing where no page does: not snapped meanwhile.
|
|
43168
43192
|
row.setAttribute("data-route-row-travelling", "");
|
|
43169
|
-
|
|
43170
|
-
row.style.removeProperty("--navi-route-row-stand");
|
|
43193
|
+
releaseTakenRow(row);
|
|
43171
43194
|
afterFrames(1, () => {
|
|
43172
43195
|
if (movementRef.current === movement) {
|
|
43173
43196
|
travelRowTo(latestRef.current.currentIndex, movement);
|
|
@@ -43187,10 +43210,10 @@ const RouteTravel = ({
|
|
|
43187
43210
|
movementRef.current = null;
|
|
43188
43211
|
letRowGo(movement);
|
|
43189
43212
|
putRowBack(movement);
|
|
43190
|
-
|
|
43213
|
+
releaseTakenRow(row);
|
|
43191
43214
|
publishRouteRowMove(null);
|
|
43192
43215
|
releaseHeldPage();
|
|
43193
|
-
releasePaneAtRest();
|
|
43216
|
+
releasePaneAtRest(row);
|
|
43194
43217
|
if (liveRef.current) {
|
|
43195
43218
|
liveRef.current.style.top = "";
|
|
43196
43219
|
}
|
|
@@ -43198,7 +43221,7 @@ const RouteTravel = ({
|
|
|
43198
43221
|
picture.remove();
|
|
43199
43222
|
}
|
|
43200
43223
|
if (movement.scrollsDocument) {
|
|
43201
|
-
|
|
43224
|
+
unpinPanes(row);
|
|
43202
43225
|
const {
|
|
43203
43226
|
pages,
|
|
43204
43227
|
currentIndex
|
|
@@ -43503,7 +43526,7 @@ const RouteTravel = ({
|
|
|
43503
43526
|
movementRef.current = null;
|
|
43504
43527
|
publishRouteRowMove(null);
|
|
43505
43528
|
releaseHeldPage();
|
|
43506
|
-
releasePaneAtRest();
|
|
43529
|
+
releasePaneAtRest(row);
|
|
43507
43530
|
};
|
|
43508
43531
|
}, [windowed]);
|
|
43509
43532
|
|
|
@@ -43567,7 +43590,7 @@ const RouteTravel = ({
|
|
|
43567
43590
|
const row = rowRef.current;
|
|
43568
43591
|
const onTouchStart = () => {
|
|
43569
43592
|
if (!movementRef.current && rowFollowsDocument(row)) {
|
|
43570
|
-
|
|
43593
|
+
pinPanes(row);
|
|
43571
43594
|
}
|
|
43572
43595
|
};
|
|
43573
43596
|
row.addEventListener("touchstart", onTouchStart, {
|
|
@@ -43665,6 +43688,22 @@ const copyScrollPositions = (from, to) => {
|
|
|
43665
43688
|
// A tab pressed over a row a hand has left moving holds it still (takeRowFromHand):
|
|
43666
43689
|
// what the row says meanwhile is not a hand moving it.
|
|
43667
43690
|
const isRowTaken = row => row.hasAttribute("data-route-row-taken");
|
|
43691
|
+
|
|
43692
|
+
// What the CSS offsets while the row is taken. A picture left meanwhile is a clone
|
|
43693
|
+
// of the live page, and takes its offset along.
|
|
43694
|
+
const STANDING_IN_ROW = ":scope > [data-route-row-pane], :scope > [data-route-row-live], :scope > [data-route-row-pictures] > *";
|
|
43695
|
+
const holdRowAt = (row, position) => {
|
|
43696
|
+
for (const element of row.querySelectorAll(STANDING_IN_ROW)) {
|
|
43697
|
+
element.style.setProperty("--navi-route-row-stand", `${-position}px`);
|
|
43698
|
+
}
|
|
43699
|
+
row.setAttribute("data-route-row-taken", "");
|
|
43700
|
+
};
|
|
43701
|
+
const releaseTakenRow = row => {
|
|
43702
|
+
row.removeAttribute("data-route-row-taken");
|
|
43703
|
+
for (const element of row.querySelectorAll(STANDING_IN_ROW)) {
|
|
43704
|
+
element.style.removeProperty("--navi-route-row-stand");
|
|
43705
|
+
}
|
|
43706
|
+
};
|
|
43668
43707
|
const afterFrames = (count, callback) => {
|
|
43669
43708
|
if (count === 0) {
|
|
43670
43709
|
callback();
|
|
@@ -84371,9 +84410,15 @@ const PickerNaviMinute = props => {
|
|
|
84371
84410
|
* element crossing the cursor — a dozen per wheel tick. Those hovers are noise:
|
|
84372
84411
|
* the user asked to scroll, not to hover. Anything doing real work on hover (a
|
|
84373
84412
|
* map highlight, a preview, a prefetch) then pays for that noise on the main
|
|
84374
|
-
* thread, exactly while a scroll animation is running. A rule
|
|
84375
|
-
* `[navi-scrolling]
|
|
84376
|
-
*
|
|
84413
|
+
* thread, exactly while a scroll animation is running. A rule like
|
|
84414
|
+
* `[navi-scrolling] .my_row { pointer-events: none }` takes the rows out of
|
|
84415
|
+
* hit-testing and the browser suppresses it all.
|
|
84416
|
+
*
|
|
84417
|
+
* Such a rule must end on a class (or an id, a tag, an attribute) of what it
|
|
84418
|
+
* styles: Chrome then restyles only those elements when the attribute comes and
|
|
84419
|
+
* goes. One ending on `*`, including `.my_row:is([navi-scrolling] *)`, gives it
|
|
84420
|
+
* nothing to narrow to, so it restyles everything under the scroller (the whole
|
|
84421
|
+
* document when the page scrolls) at the start and at the end of every scroll.
|
|
84377
84422
|
*
|
|
84378
84423
|
* One capturing listener on the document sees them all: "scroll" does not
|
|
84379
84424
|
* bubble, but it does propagate in the capture phase.
|
|
@@ -86758,7 +86803,7 @@ const css$w = /* css */`@property --list-group-label-height {
|
|
|
86758
86803
|
}
|
|
86759
86804
|
}
|
|
86760
86805
|
|
|
86761
|
-
&:not([navi-hover-while-scrolling]) > .navi_list_scroll_container > .navi_list:
|
|
86806
|
+
[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 {
|
|
86762
86807
|
pointer-events: none;
|
|
86763
86808
|
}
|
|
86764
86809
|
|
|
@@ -88477,7 +88522,7 @@ const useListScrollSync = ({
|
|
|
88477
88522
|
// where it lands.
|
|
88478
88523
|
if (listItems.pagesSignal.peek() === 0) {
|
|
88479
88524
|
if (typeof scrolledWanted.index === "number") {
|
|
88480
|
-
placeItem(findItemElementAt(getListEl(), scrolledWanted.index), scrolledWanted.offset || 0);
|
|
88525
|
+
placeItem(findItemElementAt(getListEl(), scrolledWanted.index), scrolledWanted.offset || 0, scrolledWanted.align);
|
|
88481
88526
|
}
|
|
88482
88527
|
return;
|
|
88483
88528
|
}
|
|
@@ -88541,11 +88586,13 @@ const useListScrollSync = ({
|
|
|
88541
88586
|
const itemRect = itemEl.getBoundingClientRect();
|
|
88542
88587
|
const viewportSize = (horizontal ? viewportRect.width : viewportRect.height) / scale;
|
|
88543
88588
|
const itemSize = (horizontal ? itemRect.width : itemRect.height) / scale;
|
|
88544
|
-
const
|
|
88545
|
-
|
|
88546
|
-
|
|
88547
|
-
|
|
88548
|
-
|
|
88589
|
+
const offsetWanted = resolveHeldOffset({
|
|
88590
|
+
align,
|
|
88591
|
+
offset,
|
|
88592
|
+
scrollInset: getItemScrollInset(scrollerEl, itemEl, horizontal),
|
|
88593
|
+
viewportSize,
|
|
88594
|
+
itemSize
|
|
88595
|
+
});
|
|
88549
88596
|
const offsetNow = (horizontal ? itemRect.left - viewportRect.left : itemRect.top - viewportRect.top) / scale;
|
|
88550
88597
|
const scrollNow = horizontal ? scrollerEl.scrollLeft : scrollerEl.scrollTop;
|
|
88551
88598
|
const delta = offsetNow - offsetWanted;
|
|
@@ -89284,6 +89331,7 @@ const useListScrollSync = ({
|
|
|
89284
89331
|
}
|
|
89285
89332
|
let index = null;
|
|
89286
89333
|
let offset = 0;
|
|
89334
|
+
let align;
|
|
89287
89335
|
if (typeof wanted === "number") {
|
|
89288
89336
|
index = wanted;
|
|
89289
89337
|
} else if (wanted && wanted.id !== undefined) {
|
|
@@ -89292,6 +89340,7 @@ const useListScrollSync = ({
|
|
|
89292
89340
|
index = wanted.index;
|
|
89293
89341
|
}
|
|
89294
89342
|
offset = wanted.offset || 0;
|
|
89343
|
+
align = wanted.align;
|
|
89295
89344
|
}
|
|
89296
89345
|
if (index === null || index < 0 || index >= total) {
|
|
89297
89346
|
return null;
|
|
@@ -89302,7 +89351,15 @@ const useListScrollSync = ({
|
|
|
89302
89351
|
const rect = itemEl.getBoundingClientRect();
|
|
89303
89352
|
itemSize = horizontal ? rect.width : rect.height;
|
|
89304
89353
|
}
|
|
89305
|
-
|
|
89354
|
+
// Not drawn yet, the item weighs nothing and has no inset: centred, it
|
|
89355
|
+
// stands half the screen down, which is where it will be put.
|
|
89356
|
+
const above = resolveHeldOffset({
|
|
89357
|
+
align,
|
|
89358
|
+
offset,
|
|
89359
|
+
scrollInset: getItemScrollInset(scrollerEl, itemEl, horizontal),
|
|
89360
|
+
viewportSize: screenSize,
|
|
89361
|
+
itemSize
|
|
89362
|
+
});
|
|
89306
89363
|
return {
|
|
89307
89364
|
index,
|
|
89308
89365
|
above
|
|
@@ -89974,6 +90031,21 @@ const resolveOpenOffset = (offset, viewportSize, itemSize) => {
|
|
|
89974
90031
|
}
|
|
89975
90032
|
return offset;
|
|
89976
90033
|
};
|
|
90034
|
+
// How far from the start of the view an item held at `{ offset, align }`
|
|
90035
|
+
// stands: read the same way where the list is placed (placeItem) and where the
|
|
90036
|
+
// window is sized around it (readHold), or the window frames a screen the
|
|
90037
|
+
// item is not on. Centred in what the room at the start leaves of the view (a
|
|
90038
|
+
// fixed bar, a sticky header), not in the whole of it.
|
|
90039
|
+
const resolveHeldOffset = ({
|
|
90040
|
+
align,
|
|
90041
|
+
offset,
|
|
90042
|
+
scrollInset,
|
|
90043
|
+
viewportSize,
|
|
90044
|
+
itemSize
|
|
90045
|
+
}) => {
|
|
90046
|
+
const alignedOffset = align === "center" ? scrollInset + (viewportSize - scrollInset - itemSize) / 2 : align === "end" ? viewportSize - itemSize : scrollInset;
|
|
90047
|
+
return resolveOpenOffset(alignedOffset + offset, viewportSize, itemSize);
|
|
90048
|
+
};
|
|
89977
90049
|
|
|
89978
90050
|
// The room an item must be given at the top (or left) of the view: the
|
|
89979
90051
|
// scroller's own scroll-padding — where a fixed bar publishes the space it
|