@jsenv/navi 0.29.402 → 0.29.404

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.
@@ -40,11 +40,10 @@ and are referenced from here rather than restated.
40
40
  — how that axis is read, why the reading is biased, and why a finger's number
41
41
  is a deadline rather than a feel, has [a section of its own
42
42
  below](#the-axis-is-read-once-and-read-with-a-bias). **Except on something
43
- already moving**: there the hand said what it wanted by reaching for it, so
44
- the gesture answers from its first pixel and owes it every one of them —
45
- asking it to cross a threshold is asking twice, and over those pixels the
46
- thing it is holding answers to nobody. A diagonal would ask for two travels at
47
- once and only one screen can arrive.
43
+ already moving**: its axis is already decided, and a diagonal would ask for
44
+ two travels at once when only one screen can arrive. What the hand wants
45
+ there — the next screen, or that one — is read from its first steps, [see
46
+ below](#a-hand-reaching-for-something-still-moving-is-reaching-for-that-thing).
48
47
  - **Of the way covered when the gesture forms, only the threshold is withheld**
49
48
  — never the whole first report. Movement reports are coalesced to frames, so
50
49
  the faster the gesture the bigger its first report is: charged whole, a flick
@@ -435,25 +434,57 @@ not ask for a new one, and it is not refused. Refusing it is what makes a page
435
434
  rock: a gesture given back to the browser is answered by the browser, over a
436
435
  travel that is already moving.
437
436
 
438
- **Touching it stops it, at the press** — in both consumers — and not at the first
439
- pixels that decide an axis. A hand landing on something that is moving expects it to obey at once;
440
- waiting for a threshold lets the pages travel on under a finger already resting
441
- on them, which is the one moment a gesture must not ask for proof. A press that
442
- turns out to be nothing lets go again and the travel carries on from where it
443
- was caught, over what is left of it.
444
-
445
- Position alone does not say it is working: caught late, the picture is already
446
- where the finger is and nothing looks wrong. What gives it away is SPEED — a
447
- travel that keeps its pace under a resting finger, then is pinned to a hand
448
- moving at another one. Measure the position frame by frame across the press: it
449
- must stop on the frame the finger lands, not on the one where the axis is
450
- decided.
437
+ But a hand landing on a travel is two different hands, and the likelier one is
438
+ not reaching for it at all: **it is the next swipe**, thrown while the last one
439
+ is still playing. Stopping the travel at the press answers the rarer hand —
440
+ the one catching — and makes the likelier one feel a stall: the screen stops
441
+ dead under a swipe that starts from rest, then crawls at the finger's speed
442
+ before it goes anywhere. So what the hand is doing is listened to first
443
+ (`inFlight`), with the touch refused from the first pixel meanwhile (the
444
+ browser's deadline does not wait for us — see
445
+ [mobile_touch.md](./mobile_touch.md)):
446
+
447
+ - **a step the travel's way** (the start threshold) is the next swipe: one
448
+ screen further (`onPushOn`), and the travel goes on there from where it is —
449
+ as a second arrow press sends it — never having stopped. The hand holds
450
+ nothing; it pushed;
451
+ - **a step against it, or a hand saying nothing** for `DRAG_CATCH_HOLD_MS`
452
+ (100ms) is a catch: the travel stops where it stands at that moment, and the
453
+ hand holds it from there;
454
+ - **let go before either** — a tap — and the travel was never touched.
455
+
456
+ The price is paid by the rarer hand: a catch lands up to 100ms after the finger,
457
+ so the screen goes on that much under it. A slow hand stepping the travel's way
458
+ before stopping reads as the next swipe too. Both are the right side to be
459
+ wrong on.
460
+
461
+ Both consumers answer the next swipe without stopping anything, each in its own
462
+ way:
463
+
464
+ - a `SlideContainer` sets off a new travel from where the track is, to the slide
465
+ after — the one a second arrow press asks for — over the distance left, so it
466
+ speeds up;
467
+ - a `RouteTravel` keeps the transition it is playing and points the router one
468
+ page further — what a tab pressed while it plays does (see [Asking for a page
469
+ while one is on its
470
+ way](#asking-for-a-page-while-one-is-on-its-way)) — so the pace does not
471
+ change and the page arriving is simply the next one. What the transition
472
+ carries besides the pages cannot follow that, see [One gesture that bar
473
+ cannot follow](#one-gesture-that-bar-cannot-follow).
474
+
475
+ Position alone does not say either is working. What gives it away is SPEED:
476
+ measure the position frame by frame across the press (for a `RouteTravel`, the
477
+ `currentTime` and `playState` of the transition's animations). A next swipe
478
+ must not change the pace at all until the travel takes the new target, and
479
+ then only keep it or speed up; a catch must stop on the frame the hold is
480
+ decided, not later.
451
481
 
452
482
  Taking over means the pictures stop where they are and answer the finger again,
453
483
  from where they stand (`slack`) rather than from zero. Only one box is in hand,
454
484
  and walking out of either of its ends is a travel of its own — see below.
455
485
 
456
- What letting go of it again means is read from the hand, three ways:
486
+ What letting go of a travel caught this way means is read from the hand, three
487
+ ways:
457
488
 
458
489
  - **merely touched** — a press that moved less than a gesture's worth: nobody
459
490
  asked the travel to stop, it was asked to wait, and it carries on to where it
@@ -461,9 +492,10 @@ What letting go of it again means is read from the hand, three ways:
461
492
  - **thrown back** — against the way it was going, fast: everything goes back;
462
493
  - **thrown on** — the way it was already going, fast, having moved by more than
463
494
  a tremor: that is a second push, and it asks for the screen AFTER the one
464
- arriving (`thrownOn`). Read as a verdict on the box in hand, it only confirms
465
- what was already arriving — the travel stops at the press and goes on to the
466
- same place, and the hand feels its second swipe swallowed. So the gesture
495
+ arriving (`thrownOn`) — the same answer as a step the travel's way, for a
496
+ hand that caught it first. Read as a verdict on the box in hand, it only
497
+ confirms what was already arriving, and the hand feels its second swipe
498
+ swallowed. So the gesture
467
499
  asks for the next box at the release (`onEdge` with `thrown`), with the
468
500
  picture still short of the end of the one in hand, and nothing on screen
469
501
  moves for it: the travel goes on from where the hand left it, to one screen
@@ -497,10 +529,11 @@ The two ends cost differently, and it is worth knowing which one is being felt:
497
529
  That cost is a `RouteTravel` one: a `SlideContainer` has every slide mounted,
498
530
  so handing over is only re-staging — the slide reached becomes the one dragged,
499
531
  the one left stays beside it, the slide past it is put on the other side, and
500
- nothing on screen moves. Which is also why only a `SlideContainer` answers a
501
- throw (`thrown`, above): a `RouteTravel` would have to jump its pictures the
502
- rest of the way before handing over, a page seen leaping, so it declines and
503
- the page caught simply arrives.
532
+ nothing on screen moves. A throw (`thrown`, above) is answered differently for
533
+ the same reason: a `SlideContainer` hands over by re-staging, while a
534
+ `RouteTravel` would have to jump its pictures the rest of the way before
535
+ handing over, a page seen leaping — so it aims the travel in hand one page
536
+ further instead, hands nothing over, and lets it go: it arrives there.
504
537
 
505
538
  What the browser will not turn around with it is everything ELSE the
506
539
  transition carries — see [One gesture that bar cannot
@@ -752,7 +785,11 @@ stood, and where it was going to stand. That second place is now one nobody is
752
785
  going to, and the thing itself has already moved on in the live page — so the
753
786
  picture and the thing are in two places at once, and one sees two bars.
754
787
 
755
- So on that one gesture the pictures of everything that is not the pages are
788
+ The same holds whenever a travel is aimed further the same way while it plays
789
+ — a tab pressed two pages along, the next swipe landing on a page still
790
+ arriving: the bar was photographed going to a tab nobody is going to anymore.
791
+
792
+ So on those gestures the pictures of everything that is not the pages are
756
793
  dropped, and those things are left where they are, live: the bar jumps to the
757
794
  tab one is heading for instead of sliding to a tab one is not. A slide would be
758
795
  nicer, and it is not available — the browser measured both of its ends before
package/docs/safe_area.md CHANGED
@@ -145,7 +145,8 @@ brings its target to.
145
145
 
146
146
  Which element scrolls is the app's business, so navi never picks one. `:root`
147
147
  gets the `scroll-padding` unconditionally, since the document is the scrollport
148
- in the common case.
148
+ in the common case — and, while nothing is marked, the keyboard's room at its
149
+ end (see below).
149
150
 
150
151
  Beware of making that container scrollable by accident — see
151
152
  [mobile_layout_pitfalls.md](./mobile_layout_pitfalls.md).
@@ -208,6 +209,15 @@ visual viewport instead, and `--navi-keyboard-inset-bottom` stays 0. Either way
208
209
  `--navi-app-height` and the popup ceilings answer the part of the screen left
209
210
  visible.
210
211
 
212
+ An overlaying keyboard is one the browser no longer scrolls the focused field
213
+ out from under, so navi does: when the keyboard rises or resizes, and when focus
214
+ moves to another field with the keyboard up, the focused field is scrolled to
215
+ the nearest position clear of it. That scroll relies on both paddings — the
216
+ `scroll-padding-bottom` counts the keyboard, and the room to scroll into comes
217
+ from the marked element's `padding-bottom`, or, on a page that marked nothing,
218
+ from a block navi adds at the end of the document for as long as the keyboard
219
+ is up.
220
+
211
221
  `position: fixed` — so every `FixedBar` — is laid out against the **layout**
212
222
  viewport. Where the visual viewport is what shrinks, a bottom bar therefore
213
223
  stays at the bottom of a window the keyboard is covering: it ends up _behind_
package/docs/scroll.md CHANGED
@@ -207,7 +207,8 @@ what keeps a `scrollIntoView()` on a row from landing under the sticky header.
207
207
 
208
208
  - **`loading` / `loadingFallback` / `loadingSkeletonCount` / `renderSkeleton`**
209
209
  — "I have nothing at all to show yet". Placeholder rows (or a `"loader"`
210
- spinner) stand in for the whole list.
210
+ spinner) stand in for the whole list; the rows are held to the render
211
+ window like the ones they stand for.
211
212
  - **`<List.Items count>`** — "I know how many rows are coming". The rows not
212
213
  held yet are drawn as skeletons _in their own place_, virtualized like the
213
214
  rest, and asked for as they enter the render window.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.29.402",
3
+ "version": "0.29.404",
4
4
  "type": "module",
5
5
  "description": "Library of components including navigation to create frontend applications",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "preact": "^11.0.0-rc.2"
35
35
  },
36
36
  "dependencies": {
37
- "@jsenv/dom": "0.17.76",
37
+ "@jsenv/dom": "0.17.77",
38
38
  "@jsenv/humanize": "1.8.6",
39
39
  "@jsenv/validity": "0.4.5"
40
40
  },