@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.
@@ -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 name a verb takes, or one the resource
29385
- * already exposes (`withParams`, `store`…), throws. A `.scopedOne()` or
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
- stateFacade,
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
- stateFacade,
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 (Object.hasOwn(stateFacade, writeName)) {
31272
+ if (membersExposed.includes(writeName)) {
31269
31273
  throw new Error(
31270
- `${where}: the resource already exposes "${writeName}" — pick another name`,
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 */`.navi_route_travel {
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]), &:has( > [data-route-row-held]) > [data-route-row-pane]: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
- row.style.setProperty("--navi-route-row-pin", `${pinOf(row)}px`);
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
- row.style.removeProperty("--navi-route-row-pin");
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
- row.style.setProperty("--navi-route-row-pin", `${pinOf(row)}px`);
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 matching
82543
- * `[navi-scrolling] *` takes the rows out of hit-testing and the browser
82544
- * suppresses it all, at no cost per element.
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:is([navi-scrolling] *) {
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
- staleRanksRef.current = restored ? new Set(pages.byIndex.keys()) : new Set();
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
- staleRanksRef.current = new Set(pages.byIndex.keys());
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 revalidating = staleFrom !== -1;
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
  }