@jsenv/navi 0.30.36 → 0.30.38
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 +69 -21
- package/dist/dev/jsenv_navi.js.map +5 -5
- package/dist/jsenv_navi.js +69 -21
- package/dist/jsenv_navi.js.map +5 -5
- package/docs/resource.md +4 -0
- package/docs/scroll.md +6 -0
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -29381,8 +29381,9 @@ const debug$2 = (...args) => {
|
|
|
29381
29381
|
* policy as that verb, and is a write of its own for a dependent:
|
|
29382
29382
|
* `{ resource: ORDER, on: ["cancel"] }`. Its `rerunOn` says which reads of
|
|
29383
29383
|
* this resource it reruns (`{ GET_RANGE: true }`); a read it leaves out
|
|
29384
|
-
* follows `rerunOn` for its verb. A
|
|
29385
|
-
* already exposes (`withParams`, `store`…),
|
|
29384
|
+
* follows `rerunOn` for its verb. A verb's name in any case (`post`,
|
|
29385
|
+
* `get_many`…), or one the resource already exposes (`withParams`, `store`…),
|
|
29386
|
+
* throws. A `.scopedOne()` or
|
|
29386
29387
|
* `.scopedMany()` takes `writes` too, `.scopedMany()` with the plural verbs.
|
|
29387
29388
|
* @param {{ GET?: { ms?: number, max?: number }, GET_MANY?: { ms?: number, max?: number } }} [restCallbacks.keep] -
|
|
29388
29389
|
* how long an answer of a read is trusted, coming back to the same params
|
|
@@ -30938,12 +30939,15 @@ ${name}.many("${propertyName}") source location: ${declarationSite}`,
|
|
|
30938
30939
|
|
|
30939
30940
|
// expose one action per write named in `writes`
|
|
30940
30941
|
if (writes) {
|
|
30942
|
+
const membersExposed = Object.keys(stateFacade).filter(
|
|
30943
|
+
(key) => !VERB_KEYS.includes(key),
|
|
30944
|
+
);
|
|
30941
30945
|
for (const [writeName, write] of Object.entries(writes)) {
|
|
30942
30946
|
assertWriteCanBeNamed(
|
|
30943
30947
|
name,
|
|
30944
30948
|
writeName,
|
|
30945
30949
|
write,
|
|
30946
|
-
|
|
30950
|
+
membersExposed,
|
|
30947
30951
|
namedWriteVerbs,
|
|
30948
30952
|
);
|
|
30949
30953
|
const { verb: writeVerb, callback, rerunOn: writeRerunOn } = write;
|
|
@@ -31256,7 +31260,7 @@ const assertWriteCanBeNamed = (
|
|
|
31256
31260
|
name,
|
|
31257
31261
|
writeName,
|
|
31258
31262
|
write,
|
|
31259
|
-
|
|
31263
|
+
membersExposed,
|
|
31260
31264
|
namedWriteVerbs,
|
|
31261
31265
|
) => {
|
|
31262
31266
|
const where = `resource(${name}) writes.${writeName}`;
|
|
@@ -31265,9 +31269,9 @@ const assertWriteCanBeNamed = (
|
|
|
31265
31269
|
`${where}: "${writeName}" is a verb's name — a write named in "writes" takes a name of its own (cancel, archive…)`,
|
|
31266
31270
|
);
|
|
31267
31271
|
}
|
|
31268
|
-
if (
|
|
31272
|
+
if (membersExposed.includes(writeName)) {
|
|
31269
31273
|
throw new Error(
|
|
31270
|
-
`${where}: the resource already exposes "${writeName}" —
|
|
31274
|
+
`${where}: the resource already exposes "${writeName}" — a write takes a name none of its members has: ${membersExposed.join(", ")}`,
|
|
31271
31275
|
);
|
|
31272
31276
|
}
|
|
31273
31277
|
if (!write || typeof write !== "object") {
|
|
@@ -41312,7 +41316,12 @@ const watchRowScroll = (
|
|
|
41312
41316
|
};
|
|
41313
41317
|
|
|
41314
41318
|
installImportMetaCssBuild(import.meta);
|
|
41315
|
-
const css$16 = /* css
|
|
41319
|
+
const css$16 = /* css */`@property --navi-route-row-pin {
|
|
41320
|
+
syntax: "*";
|
|
41321
|
+
inherits: false
|
|
41322
|
+
}
|
|
41323
|
+
|
|
41324
|
+
.navi_route_travel {
|
|
41316
41325
|
flex-direction: column;
|
|
41317
41326
|
display: flex;
|
|
41318
41327
|
position: relative;
|
|
@@ -41368,7 +41377,7 @@ const css$16 = /* css */`.navi_route_travel {
|
|
|
41368
41377
|
display: flex;
|
|
41369
41378
|
}
|
|
41370
41379
|
|
|
41371
|
-
& > [data-route-row-pane][inert]:not([data-route-row-held]),
|
|
41380
|
+
& > [data-route-row-pane][inert]:not([data-route-row-held]), &[data-route-row-holding] > [data-route-row-pane]:not([data-route-row-held]) {
|
|
41372
41381
|
top: var(--navi-route-row-pin, 0);
|
|
41373
41382
|
contain: paint;
|
|
41374
41383
|
max-height: 100dvh;
|
|
@@ -41540,11 +41549,25 @@ const RouteTravel = ({
|
|
|
41540
41549
|
// when the row rests. Not what readers are told the page held is
|
|
41541
41550
|
// (route_travel_hold.js): that follows the hand, and goes at its lift.
|
|
41542
41551
|
const heldPaneRef = useRef(null);
|
|
41543
|
-
const releasePaneAtRest =
|
|
41552
|
+
const releasePaneAtRest = row => {
|
|
41544
41553
|
const heldPane = heldPaneRef.current;
|
|
41545
41554
|
if (heldPane) {
|
|
41546
41555
|
heldPaneRef.current = null;
|
|
41547
41556
|
heldPane.removeAttribute("data-route-row-held");
|
|
41557
|
+
row.removeAttribute("data-route-row-holding");
|
|
41558
|
+
}
|
|
41559
|
+
};
|
|
41560
|
+
|
|
41561
|
+
// How far down the reader is looking, on every pane, for those the CSS pins.
|
|
41562
|
+
const pinPanes = row => {
|
|
41563
|
+
const pin = `${pinOf(row)}px`;
|
|
41564
|
+
for (const pane of panesOf(row)) {
|
|
41565
|
+
pane.style.setProperty("--navi-route-row-pin", pin);
|
|
41566
|
+
}
|
|
41567
|
+
};
|
|
41568
|
+
const unpinPanes = row => {
|
|
41569
|
+
for (const pane of panesOf(row)) {
|
|
41570
|
+
pane.style.removeProperty("--navi-route-row-pin");
|
|
41548
41571
|
}
|
|
41549
41572
|
};
|
|
41550
41573
|
|
|
@@ -41571,13 +41594,14 @@ const RouteTravel = ({
|
|
|
41571
41594
|
if (!windowed && paneAtRest) {
|
|
41572
41595
|
heldPaneRef.current = paneAtRest;
|
|
41573
41596
|
paneAtRest.setAttribute("data-route-row-held", "");
|
|
41597
|
+
row.setAttribute("data-route-row-holding", "");
|
|
41574
41598
|
}
|
|
41575
41599
|
if (movement.scrollsDocument) {
|
|
41576
41600
|
// Whatever the browser does with the offset meanwhile (clamping it to a page
|
|
41577
41601
|
// shorter than the trip) is not the reader scrolling, and the address it
|
|
41578
41602
|
// would be written against may already be another page's.
|
|
41579
41603
|
movement.resumeScrollRecording = suspendScrollRecording();
|
|
41580
|
-
|
|
41604
|
+
pinPanes(row);
|
|
41581
41605
|
}
|
|
41582
41606
|
return movement;
|
|
41583
41607
|
};
|
|
@@ -41870,7 +41894,7 @@ const RouteTravel = ({
|
|
|
41870
41894
|
row.removeAttribute("data-route-row-taken");
|
|
41871
41895
|
publishRouteRowMove(null);
|
|
41872
41896
|
releaseHeldPage();
|
|
41873
|
-
releasePaneAtRest();
|
|
41897
|
+
releasePaneAtRest(row);
|
|
41874
41898
|
if (liveRef.current) {
|
|
41875
41899
|
liveRef.current.style.top = "";
|
|
41876
41900
|
}
|
|
@@ -41878,7 +41902,7 @@ const RouteTravel = ({
|
|
|
41878
41902
|
picture.remove();
|
|
41879
41903
|
}
|
|
41880
41904
|
if (movement.scrollsDocument) {
|
|
41881
|
-
|
|
41905
|
+
unpinPanes(row);
|
|
41882
41906
|
const {
|
|
41883
41907
|
pages,
|
|
41884
41908
|
currentIndex
|
|
@@ -42183,7 +42207,7 @@ const RouteTravel = ({
|
|
|
42183
42207
|
movementRef.current = null;
|
|
42184
42208
|
publishRouteRowMove(null);
|
|
42185
42209
|
releaseHeldPage();
|
|
42186
|
-
releasePaneAtRest();
|
|
42210
|
+
releasePaneAtRest(row);
|
|
42187
42211
|
};
|
|
42188
42212
|
}, [windowed]);
|
|
42189
42213
|
|
|
@@ -42247,7 +42271,7 @@ const RouteTravel = ({
|
|
|
42247
42271
|
const row = rowRef.current;
|
|
42248
42272
|
const onTouchStart = () => {
|
|
42249
42273
|
if (!movementRef.current && rowFollowsDocument(row)) {
|
|
42250
|
-
|
|
42274
|
+
pinPanes(row);
|
|
42251
42275
|
}
|
|
42252
42276
|
};
|
|
42253
42277
|
row.addEventListener("touchstart", onTouchStart, {
|
|
@@ -82539,9 +82563,15 @@ const PickerNaviMinute = props => {
|
|
|
82539
82563
|
* element crossing the cursor — a dozen per wheel tick. Those hovers are noise:
|
|
82540
82564
|
* the user asked to scroll, not to hover. Anything doing real work on hover (a
|
|
82541
82565
|
* map highlight, a preview, a prefetch) then pays for that noise on the main
|
|
82542
|
-
* thread, exactly while a scroll animation is running. A rule
|
|
82543
|
-
* `[navi-scrolling]
|
|
82544
|
-
*
|
|
82566
|
+
* thread, exactly while a scroll animation is running. A rule like
|
|
82567
|
+
* `[navi-scrolling] .my_row { pointer-events: none }` takes the rows out of
|
|
82568
|
+
* hit-testing and the browser suppresses it all.
|
|
82569
|
+
*
|
|
82570
|
+
* Such a rule must end on a class (or an id, a tag, an attribute) of what it
|
|
82571
|
+
* styles: Chrome then restyles only those elements when the attribute comes and
|
|
82572
|
+
* goes. One ending on `*`, including `.my_row:is([navi-scrolling] *)`, gives it
|
|
82573
|
+
* nothing to narrow to, so it restyles everything under the scroller (the whole
|
|
82574
|
+
* document when the page scrolls) at the start and at the end of every scroll.
|
|
82545
82575
|
*
|
|
82546
82576
|
* One capturing listener on the document sees them all: "scroll" does not
|
|
82547
82577
|
* bubble, but it does propagate in the capture phase.
|
|
@@ -84923,7 +84953,7 @@ const css$w = /* css */`@property --list-group-label-height {
|
|
|
84923
84953
|
}
|
|
84924
84954
|
}
|
|
84925
84955
|
|
|
84926
|
-
&:not([navi-hover-while-scrolling]) > .navi_list_scroll_container > .navi_list:
|
|
84956
|
+
[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 {
|
|
84927
84957
|
pointer-events: none;
|
|
84928
84958
|
}
|
|
84929
84959
|
|
|
@@ -90744,8 +90774,19 @@ const useItemStore = ({
|
|
|
90744
90774
|
// was asked for, and the window keeps growing meanwhile: dropping what the
|
|
90745
90775
|
// page did not cover empties items on screen.
|
|
90746
90776
|
const staleRanksRef = useRef(null);
|
|
90777
|
+
// A run standing for no item has no rank to mark: its count is what is from
|
|
90778
|
+
// before, and no window frames anything that would ask for it again.
|
|
90779
|
+
const countStaleRef = useRef(false);
|
|
90780
|
+
const markHeldStale = () => {
|
|
90781
|
+
staleRanksRef.current = new Set(pages.byIndex.keys());
|
|
90782
|
+
countStaleRef.current = pages.count === 0;
|
|
90783
|
+
};
|
|
90747
90784
|
if (staleRanksRef.current === null) {
|
|
90748
|
-
|
|
90785
|
+
if (restored) {
|
|
90786
|
+
markHeldStale();
|
|
90787
|
+
} else {
|
|
90788
|
+
staleRanksRef.current = new Set();
|
|
90789
|
+
}
|
|
90749
90790
|
}
|
|
90750
90791
|
const takeInPage = ({
|
|
90751
90792
|
pageItems,
|
|
@@ -90784,6 +90825,7 @@ const useItemStore = ({
|
|
|
90784
90825
|
i++;
|
|
90785
90826
|
}
|
|
90786
90827
|
pages.count = pageCount;
|
|
90828
|
+
countStaleRef.current = false;
|
|
90787
90829
|
// Which rank holds which id, kept by the source so a list drawing
|
|
90788
90830
|
// this collection again finds it drawn (see readComposition above).
|
|
90789
90831
|
if (itemsAction.writeComposition) {
|
|
@@ -90819,7 +90861,7 @@ const useItemStore = ({
|
|
|
90819
90861
|
const invalidationRef = useRef(invalidation);
|
|
90820
90862
|
if (invalidationRef.current !== invalidation) {
|
|
90821
90863
|
invalidationRef.current = invalidation;
|
|
90822
|
-
|
|
90864
|
+
markHeldStale();
|
|
90823
90865
|
}
|
|
90824
90866
|
// The one request in flight, with the means to call it off: a page asked for
|
|
90825
90867
|
// a window the list has left is work the server and the browser are doing for
|
|
@@ -91017,7 +91059,8 @@ const useItemStore = ({
|
|
|
91017
91059
|
rank++;
|
|
91018
91060
|
}
|
|
91019
91061
|
}
|
|
91020
|
-
const
|
|
91062
|
+
const countStale = countStaleRef.current;
|
|
91063
|
+
const revalidating = staleFrom !== -1 || countStale;
|
|
91021
91064
|
// The list is held on an item nothing on screen leads to: the items it holds
|
|
91022
91065
|
// do not contain it, so no window it could draw will ever bring it. Only
|
|
91023
91066
|
// asking for it by name does.
|
|
@@ -91033,6 +91076,10 @@ const useItemStore = ({
|
|
|
91033
91076
|
const from = typeof wanted.index === "number" ? rankOfIndex(wanted.index) - Math.floor(budget / 2) : 0;
|
|
91034
91077
|
start = from < 0 ? 0 : from;
|
|
91035
91078
|
end = start + budget - 1;
|
|
91079
|
+
} else if (countStale) {
|
|
91080
|
+
// Nothing drawn to anchor on: the first page, like the very first ask.
|
|
91081
|
+
start = 0;
|
|
91082
|
+
end = budget - 1;
|
|
91036
91083
|
} else if (revalidating) {
|
|
91037
91084
|
// The items from before that the window draws, and the missing ones
|
|
91038
91085
|
// with them: one ask.
|
|
@@ -91234,6 +91281,7 @@ const useItemStore = ({
|
|
|
91234
91281
|
staleRanksRef.current.delete(rank);
|
|
91235
91282
|
rank++;
|
|
91236
91283
|
}
|
|
91284
|
+
countStaleRef.current = false;
|
|
91237
91285
|
setRefreshing(false);
|
|
91238
91286
|
return;
|
|
91239
91287
|
}
|