@jsenv/navi 0.30.6 → 0.30.7

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.
@@ -41679,17 +41679,19 @@ const STOPPED_SILENCE = 150;
41679
41679
  const isOnRow = (page) =>
41680
41680
  page.offsetWidth > 0 && !page.hasAttribute("data-off-row");
41681
41681
 
41682
- const restsOn = (scroller, page) =>
41682
+ // `sideways`: see readRowStretch.
41683
+ const restsOn = (scroller, page, { sideways } = {}) =>
41683
41684
  Math.abs(page.offsetLeft - scroller.scrollLeft) <= AT_REST_DISTANCE &&
41684
- Math.abs(page.offsetTop - scroller.scrollTop) <= AT_REST_DISTANCE;
41685
+ (sideways ||
41686
+ Math.abs(page.offsetTop - scroller.scrollTop) <= AT_REST_DISTANCE);
41685
41687
 
41686
41688
  /**
41687
41689
  * @returns {Element|undefined} the page the row rests on, nothing while it stands
41688
41690
  * between two: a hand can pause midway, and an engine may call that the end of
41689
41691
  * a scroll.
41690
41692
  */
41691
- const pageAtRest = (scroller, pages) =>
41692
- pages.find((page) => isOnRow(page) && restsOn(scroller, page));
41693
+ const pageAtRest = (scroller, pages, options) =>
41694
+ pages.find((page) => isOnRow(page) && restsOn(scroller, page, options));
41693
41695
 
41694
41696
  /**
41695
41697
  * Where the row stands between two neighbouring pages, on the side it has moved
@@ -41697,14 +41699,18 @@ const pageAtRest = (scroller, pages) =>
41697
41699
  * since is walked over. A map moves along one axis at a time, the one it has
41698
41700
  * moved furthest on.
41699
41701
  *
41702
+ * @param {object} [options]
41703
+ * @param {boolean} [options.sideways] - a row with one line, whatever `offsetTop` its
41704
+ * pages read: a page pinned with `top` is still on it.
41700
41705
  * @returns {{base: Element, toward: Element|undefined, fraction: number, forward: boolean}}
41701
41706
  * the last page the row has passed (`page` itself until then), the one after,
41702
41707
  * and how far between the two from 0 to 1. Nothing `toward` past the last.
41703
41708
  */
41704
- const readRowStretch = (scroller, pages, page) => {
41709
+ const readRowStretch = (scroller, pages, page, { sideways } = {}) => {
41705
41710
  const alongX =
41711
+ sideways ||
41706
41712
  Math.abs(scroller.scrollLeft - page.offsetLeft) >=
41707
- Math.abs(scroller.scrollTop - page.offsetTop);
41713
+ Math.abs(scroller.scrollTop - page.offsetTop);
41708
41714
  const position = alongX ? "offsetLeft" : "offsetTop";
41709
41715
  const cross = alongX ? "offsetTop" : "offsetLeft";
41710
41716
  const scrolled = alongX ? scroller.scrollLeft : scroller.scrollTop;
@@ -41712,7 +41718,8 @@ const readRowStretch = (scroller, pages, page) => {
41712
41718
  const step = forward ? 1 : -1;
41713
41719
  const line = pages
41714
41720
  .filter(
41715
- (candidate) => isOnRow(candidate) && candidate[cross] === page[cross],
41721
+ (candidate) =>
41722
+ isOnRow(candidate) && (sideways || candidate[cross] === page[cross]),
41716
41723
  )
41717
41724
  .sort((pageA, pageB) => pageA[position] - pageB[position]);
41718
41725
  let index = line.indexOf(page);
@@ -41919,6 +41926,11 @@ const css$16 = /* css */`.navi_route_travel {
41919
41926
  // there yet: past what a hand that only shook covers, so that a shake costs
41920
41927
  // neither a navigation nor the requests of a page.
41921
41928
  const SET_OFF_PULL = 16;
41929
+ // A row of routes is one line, whatever `offsetTop` its pinned panes read (see the pin
41930
+ // above): they are on it all the same.
41931
+ const ROW_READING = {
41932
+ sideways: true
41933
+ };
41922
41934
 
41923
41935
  /**
41924
41936
  * @type {import("preact").FunctionComponent<{
@@ -42092,10 +42104,7 @@ const RouteTravel = ({
42092
42104
  const paneCurrent = panesOf(row)[currentIndex];
42093
42105
  if (paneCurrent) {
42094
42106
  movement.travelling = true;
42095
- row.scrollTo({
42096
- left: paneCurrent.offsetLeft,
42097
- behavior: "smooth"
42098
- });
42107
+ travelRowTo(currentIndex, movement);
42099
42108
  }
42100
42109
  });
42101
42110
  };
@@ -42112,7 +42121,7 @@ const RouteTravel = ({
42112
42121
  base,
42113
42122
  toward,
42114
42123
  fraction
42115
- } = readRowStretch(row, panes, panes[0]);
42124
+ } = readRowFrame(row, panes);
42116
42125
  publishRouteRowMove({
42117
42126
  basePath: pathOf(pages[panes.indexOf(base)]),
42118
42127
  towardPath: toward ? pathOf(pages[panes.indexOf(toward)]) : null,
@@ -42120,6 +42129,81 @@ const RouteTravel = ({
42120
42129
  });
42121
42130
  };
42122
42131
 
42132
+ // A travel no hand set off is one box long however far the page is, as in a
42133
+ // SlideContainer: the browser's smooth scroll would fly past every page in between.
42134
+ // So the page asked for takes the column next to what is in the frame, on the side
42135
+ // it already stands, which moves nothing on screen, and endMovement puts the columns
42136
+ // back. Columns rather than offsets: every page stays a place to snap to, and none
42137
+ // has to be hidden.
42138
+ const travelRowTo = (index, movement) => {
42139
+ const row = rowRef.current;
42140
+ const panes = panesOf(row);
42141
+ const pane = panes[index];
42142
+ if (!pane) {
42143
+ return;
42144
+ }
42145
+ const {
42146
+ base,
42147
+ toward,
42148
+ fraction
42149
+ } = readRowFrame(row, panes);
42150
+ const inFrame = toward && fraction > 0 ? [base, toward] : [base];
42151
+ if (!inFrame.includes(pane)) {
42152
+ // In a window, what the window put in a column moves with its pane.
42153
+ const standingIn = paneIndex => {
42154
+ const standing = [panes[paneIndex]];
42155
+ if (windowed) {
42156
+ const picture = movement.pictures.get(paneIndex);
42157
+ if (picture) {
42158
+ standing.push(picture);
42159
+ }
42160
+ if (paneIndex === latestRef.current.liveIndex) {
42161
+ standing.push(liveRef.current);
42162
+ }
42163
+ }
42164
+ return standing;
42165
+ };
42166
+ const columns = [...panes].sort((a, b) => a.offsetLeft - b.offsetLeft);
42167
+ const first = columns.indexOf(inFrame[0]);
42168
+ const last = columns.indexOf(inFrame[inFrame.length - 1]);
42169
+ const from = columns.indexOf(pane);
42170
+ columns.splice(from, 1);
42171
+ columns.splice(from < first ? first - 1 : last + 1, 0, pane);
42172
+ movement.placed ||= new Map();
42173
+ columns.forEach((eachPane, column) => {
42174
+ for (const element of standingIn(panes.indexOf(eachPane))) {
42175
+ if (!movement.placed.has(element)) {
42176
+ movement.placed.set(element, element.style.gridColumn);
42177
+ }
42178
+ element.style.gridColumn = String(column + 1);
42179
+ }
42180
+ });
42181
+ }
42182
+ row.scrollTo({
42183
+ left: pane.offsetLeft,
42184
+ behavior: "smooth"
42185
+ });
42186
+ };
42187
+
42188
+ // Every column back where the map says, and the row on the page of the address, in
42189
+ // one go: that page stands at the same place on screen either way.
42190
+ const putRowBack = movement => {
42191
+ const row = rowRef.current;
42192
+ if (movement.placed) {
42193
+ for (const [element, column] of movement.placed) {
42194
+ element.style.gridColumn = column;
42195
+ }
42196
+ movement.placed = null;
42197
+ }
42198
+ const pane = panesOf(row)[latestRef.current.currentIndex];
42199
+ if (pane && !restsOn(row, pane, ROW_READING)) {
42200
+ row.scrollTo({
42201
+ left: pane.offsetLeft,
42202
+ behavior: "instant"
42203
+ });
42204
+ }
42205
+ };
42206
+
42123
42207
  // A tab pressed over a row a hand has left moving, which the browser plays on and
42124
42208
  // overwrites a travel with once that travel is over: the snap is ended first. Given
42125
42209
  // back, the row stands where it stood. A frame later, because until then WebKit still
@@ -42140,12 +42224,8 @@ const RouteTravel = ({
42140
42224
  row.setAttribute("data-route-row-taken", "");
42141
42225
  row.style.removeProperty("--navi-route-row-stand");
42142
42226
  afterFrames(1, () => {
42143
- const pane = panesOf(row)[latestRef.current.currentIndex];
42144
- if (movementRef.current === movement && pane) {
42145
- row.scrollTo({
42146
- left: pane.offsetLeft,
42147
- behavior: "smooth"
42148
- });
42227
+ if (movementRef.current === movement) {
42228
+ travelRowTo(latestRef.current.currentIndex, movement);
42149
42229
  }
42150
42230
  });
42151
42231
  });
@@ -42160,6 +42240,7 @@ const RouteTravel = ({
42160
42240
  return;
42161
42241
  }
42162
42242
  movementRef.current = null;
42243
+ putRowBack(movement);
42163
42244
  row.removeAttribute("data-moving");
42164
42245
  row.removeAttribute("data-route-row-taken");
42165
42246
  publishRouteRowMove(null);
@@ -42199,7 +42280,7 @@ const RouteTravel = ({
42199
42280
  const pane = panesOf(row)[currentIndex];
42200
42281
  const answered = answeredPageRef.current;
42201
42282
  if (samePage(answered, page)) {
42202
- if (pane && !movementRef.current && !restsOn(row, pane)) {
42283
+ if (pane && !movementRef.current && !restsOn(row, pane, ROW_READING)) {
42203
42284
  row.scrollTo({
42204
42285
  left: pane.offsetLeft,
42205
42286
  behavior: "instant"
@@ -42215,13 +42296,13 @@ const RouteTravel = ({
42215
42296
  if (asked && samePage(asked, page)) {
42216
42297
  askedPageRef.current = null;
42217
42298
  // The hand landed before the address did.
42218
- if (movementRef.current?.landed && restsOn(row, pane)) {
42299
+ if (movementRef.current?.landed && restsOn(row, pane, ROW_READING)) {
42219
42300
  Promise.resolve().then(endMovement);
42220
42301
  }
42221
42302
  return;
42222
42303
  }
42223
- if (!answered || restsOn(row, pane)) {
42224
- if (!restsOn(row, pane)) {
42304
+ if (!answered || restsOn(row, pane, ROW_READING)) {
42305
+ if (!restsOn(row, pane, ROW_READING)) {
42225
42306
  row.scrollTo({
42226
42307
  left: pane.offsetLeft,
42227
42308
  behavior: "instant"
@@ -42233,19 +42314,17 @@ const RouteTravel = ({
42233
42314
  const movement = beginMovement({
42234
42315
  travelling: true
42235
42316
  });
42236
- // In this very commit: the tab pressed already wears its bar, and the first
42237
- // scroll event is a frame away.
42238
- sayRowMoves();
42239
42317
  if (movementBefore?.byHand && !movementBefore.rowTaken) {
42318
+ sayRowMoves();
42240
42319
  takeRowFromHand(movement);
42241
42320
  return;
42242
42321
  }
42243
42322
  if (row.getAttribute("data-route-row-taken") !== "clip") {
42244
- row.scrollTo({
42245
- left: pane.offsetLeft,
42246
- behavior: "smooth"
42247
- });
42323
+ travelRowTo(currentIndex, movement);
42248
42324
  }
42325
+ // In this very commit: the tab pressed already wears its bar, and the first
42326
+ // scroll event is a frame away.
42327
+ sayRowMoves();
42249
42328
  });
42250
42329
 
42251
42330
  // Somebody else is about to move the address to another page of a window: its
@@ -42292,7 +42371,7 @@ const RouteTravel = ({
42292
42371
  }
42293
42372
  const moving = movementRef.current;
42294
42373
  const pane = panes[currentIndex];
42295
- if (!moving && pane && restsOn(row, pane)) {
42374
+ if (!moving && pane && restsOn(row, pane, ROW_READING)) {
42296
42375
  // Written by this box, at rest: nobody is moving anything.
42297
42376
  return;
42298
42377
  }
@@ -42311,7 +42390,7 @@ const RouteTravel = ({
42311
42390
  base,
42312
42391
  toward,
42313
42392
  fraction
42314
- } = readRowStretch(row, panes, panes[0]);
42393
+ } = readRowFrame(row, panes);
42315
42394
  followPageOnScreen(pages[panes.indexOf(fraction >= 0.5 && toward ? toward : base)], askedPageRef.current || pages[currentIndex]);
42316
42395
  }
42317
42396
  const pulled = row.scrollLeft - pane.offsetLeft;
@@ -42351,7 +42430,7 @@ const RouteTravel = ({
42351
42430
  const {
42352
42431
  base,
42353
42432
  toward
42354
- } = readRowStretch(row, panes, panes[0]);
42433
+ } = readRowFrame(row, panes);
42355
42434
  const index = panes.indexOf(forward && toward ? toward : base);
42356
42435
  const page = pages[index];
42357
42436
  if (!page) {
@@ -42370,8 +42449,18 @@ const RouteTravel = ({
42370
42449
  return;
42371
42450
  }
42372
42451
  const panes = panesOf(row);
42373
- const pane = pageAtRest(row, panes);
42452
+ const pane = pageAtRest(row, panes, ROW_READING);
42374
42453
  if (!pane) {
42454
+ // A travel stopped short of its page: the layout moved under it (a scrollbar
42455
+ // coming in narrows the row), and where it was sent is not where the page
42456
+ // stands. Sent again: the row then rests, or does not move and is not heard.
42457
+ const target = panes[latestRef.current.currentIndex];
42458
+ if (movement.travelling && !isClipped() && target) {
42459
+ row.scrollTo({
42460
+ left: target.offsetLeft,
42461
+ behavior: "smooth"
42462
+ });
42463
+ }
42375
42464
  return;
42376
42465
  }
42377
42466
  movement.landed = true;
@@ -42395,8 +42484,15 @@ const RouteTravel = ({
42395
42484
  onLand,
42396
42485
  onLeftToSnap
42397
42486
  });
42398
- // A hand back on a row taken from one: it is the hand's again, snapping included.
42399
- const onHandBack = () => {
42487
+ // A finger on a travel still playing: the row is the finger's from here, and it
42488
+ // stands where the travel was going, as in a SlideContainer. A wheel only gives the
42489
+ // row its snapping back: a page scrolled vertically over it is no hand on it.
42490
+ const onTouchOnTravel = () => {
42491
+ if (movementRef.current?.travelling && !isClipped()) {
42492
+ endMovement();
42493
+ }
42494
+ };
42495
+ const onWheelOnTravel = () => {
42400
42496
  if (row.getAttribute("data-route-row-taken") === "") {
42401
42497
  row.removeAttribute("data-route-row-taken");
42402
42498
  }
@@ -42421,10 +42517,10 @@ const RouteTravel = ({
42421
42517
  movement.travelling = true;
42422
42518
  takeRowFromHand(movement);
42423
42519
  };
42424
- row.addEventListener("touchstart", onHandBack, {
42520
+ row.addEventListener("touchstart", onTouchOnTravel, {
42425
42521
  passive: true
42426
42522
  });
42427
- row.addEventListener("wheel", onHandBack, {
42523
+ row.addEventListener("wheel", onWheelOnTravel, {
42428
42524
  passive: true
42429
42525
  });
42430
42526
  document.addEventListener("click", onPress, {
@@ -42432,8 +42528,8 @@ const RouteTravel = ({
42432
42528
  });
42433
42529
  return () => {
42434
42530
  stopWatching();
42435
- row.removeEventListener("touchstart", onHandBack);
42436
- row.removeEventListener("wheel", onHandBack);
42531
+ row.removeEventListener("touchstart", onTouchOnTravel);
42532
+ row.removeEventListener("wheel", onWheelOnTravel);
42437
42533
  document.removeEventListener("click", onPress, {
42438
42534
  capture: true
42439
42535
  });
@@ -42452,7 +42548,7 @@ const RouteTravel = ({
42452
42548
  return;
42453
42549
  }
42454
42550
  const pane = panesOf(rowRef.current)[currentIndex];
42455
- if (pane && restsOn(rowRef.current, pane)) {
42551
+ if (pane && restsOn(rowRef.current, pane, ROW_READING)) {
42456
42552
  Promise.resolve().then(endMovement);
42457
42553
  }
42458
42554
  }, [currentIndex]);
@@ -42560,10 +42656,6 @@ const copyScrollPositions = (from, to) => {
42560
42656
  }
42561
42657
  }
42562
42658
  };
42563
-
42564
- // A page of the row: a route, and the params that say which of its tabs when
42565
- // several of them share it. Written as a bare route by a caller whose tabs are
42566
- // routes of their own — which is the same page with nothing to tell apart.
42567
42659
  const afterFrames = (count, callback) => {
42568
42660
  if (count === 0) {
42569
42661
  callback();
@@ -42573,6 +42665,13 @@ const afterFrames = (count, callback) => {
42573
42665
  afterFrames(count - 1, callback);
42574
42666
  });
42575
42667
  };
42668
+
42669
+ // The two pages the row stands between.
42670
+ const readRowFrame = (row, panes) => readRowStretch(row, panes, panes[0], ROW_READING);
42671
+
42672
+ // A page of the row: a route, and the params that say which of its tabs when
42673
+ // several of them share it. Written as a bare route by a caller whose tabs are
42674
+ // routes of their own — which is the same page with nothing to tell apart.
42576
42675
  const normalizePage = page => page.isRoute ? {
42577
42676
  route: page,
42578
42677
  params: undefined
@@ -78781,7 +78880,10 @@ const KEYBOARD_RAISING_CONTROL_SELECTOR = `
78781
78880
  [contenteditable]:not([contenteditable="false"])
78782
78881
  `;
78783
78882
  const warnBottomSheetHoldingKeyboardControl = dialogEl => {
78784
- const controlEl = dialogEl.querySelector(KEYBOARD_RAISING_CONTROL_SELECTOR);
78883
+ // A popup opens inside its opener's subtree, so the sheet's subtree also
78884
+ // holds the fields of popups opened from it. Those are typed into in that
78885
+ // popup, and a nested Dialog docked to the bottom runs this check itself.
78886
+ const controlEl = Array.from(dialogEl.querySelectorAll(KEYBOARD_RAISING_CONTROL_SELECTOR)).find(el => el.closest(`[navi-control="dialog"], [navi-control="popover"]`) === dialogEl);
78785
78887
  if (!controlEl) {
78786
78888
  return;
78787
78889
  }