@jsenv/navi 0.29.418 → 0.29.420

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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/dev/jsenv_navi.js +584 -196
  3. package/dist/dev/jsenv_navi.js.map +35 -35
  4. package/dist/jsenv_navi.js +563 -187
  5. package/dist/jsenv_navi.js.map +35 -35
  6. package/docs/AI_INSTRUCTIONS.md +177 -261
  7. package/docs/actions.md +164 -251
  8. package/docs/autofocus.md +66 -83
  9. package/docs/control_object.md +117 -214
  10. package/docs/control_value.md +121 -185
  11. package/docs/create_and_edit.md +169 -254
  12. package/docs/css_architecture.md +196 -260
  13. package/docs/data_states.md +39 -43
  14. package/docs/dialog_shape.md +91 -134
  15. package/docs/drag_interactions.md +115 -174
  16. package/docs/drag_to_travel.md +10 -9
  17. package/docs/dynamic_import.md +119 -136
  18. package/docs/error_handling.md +75 -127
  19. package/docs/field_validation.md +49 -89
  20. package/docs/form_changed.md +66 -81
  21. package/docs/group.md +141 -0
  22. package/docs/i18n.md +31 -76
  23. package/docs/interactions.md +6 -4
  24. package/docs/list_action.md +36 -51
  25. package/docs/list_refresh.md +73 -115
  26. package/docs/mobile_touch.md +56 -62
  27. package/docs/navigation.md +377 -723
  28. package/docs/network_policy.md +61 -75
  29. package/docs/pan_zoom.md +62 -103
  30. package/docs/popup_backdrop.md +128 -168
  31. package/docs/popup_lift.md +179 -268
  32. package/docs/popup_open.md +380 -651
  33. package/docs/resource.md +228 -408
  34. package/docs/route_transitions.md +333 -482
  35. package/docs/safe_area.md +102 -89
  36. package/docs/scroll.md +175 -335
  37. package/docs/state_binding.md +2 -1
  38. package/docs/testid.md +18 -23
  39. package/docs/typography.md +111 -141
  40. package/docs/view_transitions.md +106 -104
  41. package/docs/z_index.md +61 -109
  42. package/package.json +2 -2
  43. package/docs/badge_list.md +0 -83
  44. package/docs/control_group.md +0 -168
  45. package/docs/mobile_layout_pitfalls.md +0 -145
@@ -70,24 +70,24 @@ do not ask**: what they return is not waited on, and preventing their event
70
70
  calls nothing off.
71
71
 
72
72
  **Where the position is kept is the answer's.** Until the release navi carries
73
- the element with a translate of its own, and `move` is told once, at the end. An
74
- element drawn from state — `left`/`top` computed from a position the application
75
- holds — is redrawn by the handler, and from then on its layout owns the
76
- position: navi sees it drawn elsewhere and lets go of its translate (both kept,
77
- it would land twice as far as the hand went). A handler that draws nothing (a
78
- token on a free canvas) leaves the position to the element, baked in. A handler
79
- whose draw comes later than its answer returns the promise of that draw. A thing
80
- that has to change something WHILE it is dragged, or must never be translated,
81
- declares [`moving`](#while-it-is-being-moved-moving).
73
+ the element with a translate of its own. An element drawn from state
74
+ (`left`/`top` computed from a position the application holds) is redrawn by the
75
+ `move` handler, and its layout owns the position from then on: navi sees it drawn
76
+ elsewhere and drops its translate, or it would land twice as far as the hand
77
+ went. A handler that draws nothing (a token on a free canvas) leaves the position
78
+ baked into the element; one whose draw comes later than its answer returns the
79
+ promise of that draw. Something that changes WHILE it is dragged, or must never
80
+ be translated, is [`moving`](#while-it-is-being-moved-moving).
82
81
 
83
82
  **Where it may go.** A `move` stays inside what one can SEE of its scroll
84
83
  container — the nearest ancestor whose `overflow` is `auto` or `scroll`, the
85
84
  viewport when there is none — so a board that only cuts its content (`hidden`,
86
- `clip`) does not hold it; a copy stays inside its scroll area, right for a row
87
- that belongs to its list. `data-drag-free` on the element or a container lets it
88
- out, and a `toss`, a `leave` or a `data-drop-container` free the copy on their
89
- own: a throw kept inside its list covers no distance, and a place outside can
90
- only be reached from outside.
85
+ `clip`) does not hold it; a copy stays inside its scroll area, as a row belongs
86
+ to its list. `data-drag-free` on the element or a container lets it out, and
87
+ three things do on their own, each needing to get somewhere: a `toss` for the
88
+ copy it throws (kept inside its list, it covers no distance), a `leave` for
89
+ whatever it is declared on, and a `data-drop-container` (a place outside is only
90
+ reached from outside).
91
91
 
92
92
  ```jsx
93
93
  <List.Item
@@ -108,15 +108,15 @@ only be reached from outside.
108
108
 
109
109
  Every element declaring `reorder` marks itself, so the set of items IS the set of
110
110
  elements that declared it — no selector to pass, and an item that must not move
111
- simply does not declare it. An element declaring only `toss` marks nothing: it is
112
- not a place anything lands. `toId` is null for a drop at the end.
113
-
114
- `syncCloneWithDropTarget` must be called synchronously inside the transition
115
- callback, next to the state change, so the copy is captured where it lands rather
116
- than where it was let go of; returning the transition is what makes a landing
117
- continuous. Starting that transition is the application's call, not navi's: a
118
- `view-transition-name` must be unique per document, so only the application can
119
- name what moves.
111
+ simply does not declare it; one declaring only `toss` is not a place anything
112
+ lands. `toId` is null for a drop at the end. `syncCloneWithDropTarget` must be
113
+ called synchronously inside the transition callback, next to the state change,
114
+ so the copy is captured where it lands rather than where it was let go of;
115
+ returning the transition is what makes the landing continuous. Starting that
116
+ transition is the application's call, not navi's: a `view-transition-name` must
117
+ be unique per document (see
118
+ [view_transitions.md](./view_transitions.md#a-name-is-unique-per-document)), so
119
+ only the application can name what moves.
120
120
 
121
121
  A throw is asked about before a landing: a hand that sent something across the
122
122
  screen has not asked for it to swap places with whatever it flew over.
@@ -155,29 +155,25 @@ all along, and needs to be the one drawing.
155
155
  Declaring it says both at once: the element is told where the hand has taken it
156
156
  on every frame, and **navi moves nothing** — no translate, nothing to hand back
157
157
  at the release. The numbers are counted from the grab, not steps since the last
158
- frame (which is what `pan` gives, a surface having no grab to count from): a
159
- caller adding up steps drifts, and has nothing to re-read after a frame it
160
- missed.
161
-
162
- Told, not asked — a draw that has to be awaited before the next frame is a draw
163
- one frame late — yet a gesture of its own: `moving` alone is a complete
164
- declaration, keeping everything the drag knows (the axes, the threshold, the
165
- hold a finger owes, `data-drag-free`, `grab`/`release`, `leave`, `"refuse"` to
166
- lock it). Write `move` beside it only when the release settles something the
167
- frames did not. And nothing travels back: a `move` or a `leave` beside it that
168
- is refused has no home to send the element to, so the state the frames wrote is
169
- the caller's to put back.
158
+ frame (what `pan` gives, a surface having no grab to count from): a caller adding
159
+ up steps drifts, and has nothing to re-read after a frame it missed.
160
+
161
+ Told, not asked — a draw awaited before the next frame is a draw one frame late —
162
+ yet a complete declaration on its own, keeping everything the drag knows: the
163
+ axes, the threshold, the hold a finger owes, `data-drag-free`,
164
+ `grab`/`release`, `leave`, `"refuse"` to lock it. Write `move` beside it only
165
+ when the release settles something the frames did not. Nothing travels back: a
166
+ refused `move` or `leave` beside it has no home to send the element to, so what
167
+ the frames wrote is the caller's to put back.
170
168
 
171
169
  ### Let go of away from every place: `leave`
172
170
 
173
- A throw is a **gesture**: far and fast, judged before any landing. A release
174
- outside is a **place**: the hand let go with nothing under the thing, judged
175
- after a landing was looked for. They share the outcome an application usually
176
- attaches to them and nothing else, so neither reads the other's rules — there is
177
- no speed to a release, and a fast drag across a plan that ends ON it has not
178
- asked for the thing to go. A row pulled sideways out of its list and let go is a
179
- row put back, not a row deleted: a list declares `toss`, a surface declares
180
- `leave`.
171
+ A throw is a **gesture** — far and fast, judged before any landing. A release
172
+ outside is a **place** — nothing under the thing, judged after a landing was
173
+ looked for. Neither reads the other's rules: there is no speed to a release, a
174
+ fast drag that ends ON a plan has not asked for the thing to go, and a row pulled
175
+ sideways out of its list and let go is a row put back, not a row deleted — a list
176
+ declares `toss`, a surface declares `leave`.
181
177
 
182
178
  ```jsx
183
179
  <div data-drop-container>
@@ -245,25 +241,10 @@ construction, so the answer is an insertion and putting a row back where it
245
241
  already was is a no-op. A place of a board is a place of its own, which may
246
242
  already be taken — so nothing is inserted, nothing is a no-op, and the answer is
247
243
  simply "this one came down on that one". What that means is yours: take the
248
- place, swap the two, refuse.
249
-
250
- ```jsx
251
- <Box
252
- id={playerId}
253
- interactions={{
254
- land: (event) => {
255
- const { fromId, toId, syncCloneWithDropTarget } = event.detail;
256
- return document.startViewTransition(() => {
257
- syncCloneWithDropTarget();
258
- setLineup((previous) => swapPlaces(previous, fromId, toId));
259
- }).finished;
260
- },
261
- }}
262
- />
263
- ```
264
-
265
- `toId` always names an element and is **never null**: a copy over nothing is a
266
- release that meant nothing, and the interaction does not happen at all.
244
+ place, swap the two, refuse. It is answered in the shape of a `reorder` (the
245
+ transition returned, `syncCloneWithDropTarget` inside it), and `toId` always names
246
+ an element — **never null**: a copy over nothing is a release that meant nothing,
247
+ and the interaction does not happen at all.
267
248
 
268
249
  **Which elements are places: those marked `data-droppable`, and only those.**
269
250
  Declaring `land` says an element can be CARRIED, which on a board is a different
@@ -325,54 +306,32 @@ itself — so the copy stays where the hand put it, over the thing appearing the
325
306
 
326
307
  #### Naming what travels
327
308
 
328
- **The copy is already named, and it is the copy that does the visible travel**:
329
- `syncCloneWithDropTarget` moves it onto the destination inside the callback,
330
- whether the application names anything or not. Each copy has a name of its own,
331
- two being on screen at once while a `toss` is answered; what they share is the
332
- class `navi-drag-clone`, so a stylesheet reaches the landing with
333
- `::view-transition-group(.navi-drag-clone)` (read from Chrome 125 on; before
334
- that only a rule written against the class goes unread).
335
-
336
- What is left to name is the OTHER piece, the one that was standing there and
337
- goes the other way. **A name rides the element that MOVES, and that element has
338
- to be visible at both ends of the transition.** Never the source: it stays
339
- hidden (`navi-drag-clone-source`) until the promise `land` returned settles, and
340
- a hidden element is still captured, so a name on it is a group fading in from
341
- nothing, or out into nothing, over the copy doing the real travel. Where the
342
- places are fixed and the pieces drawn into them, key each piece by WHO it is
343
- (`key={playerId}`), so the same node walks from one place to the other instead
344
- of two boxes changing content.
345
-
346
- The name is written twice, and neither write is redundant: by hand on the DOM,
347
- because the old state is captured the moment `startViewTransition` is called;
348
- and from state, because the render inside the callback would put the plain name
349
- straight back. Clear that state when `finished` resolves — a name left behind is
350
- claimed twice by the next transition, and that one is dropped for it.
351
-
352
- ```jsx
353
- land: (event) => {
354
- const { fromId, toId, syncCloneWithDropTarget } = event.detail;
355
- const displacedId = playerAt(toId);
356
- const roles = { [fromId]: OVER, [displacedId]: UNDER };
357
- for (const id of Object.keys(roles)) {
358
- document.getElementById(id).style.viewTransitionName = roles[id];
359
- }
360
- const transition = document.startViewTransition(() => {
361
- syncCloneWithDropTarget(document.getElementById(displacedId));
362
- setSwapRoles(roles); // the render inside the callback keeps the names
363
- setLineup((previous) => swapPlaces(previous, fromId, toId));
364
- });
365
- transition.finished.then(() => setSwapRoles(null));
366
- return transition.finished;
367
- };
368
- ```
369
-
370
- The roles are names because a `::view-transition` pseudo is selected by name and
371
- by nothing else — which is how one piece is told to pass over the other, and the
372
- travel given a length worth a card crossing a board. Address both
373
- `::view-transition-group(…)` and `::view-transition-image-pair(…)`: the morph
374
- lives in one, anything a style adds rides in the other. The whole board is in
375
- `38_interactions_demo.html`.
309
+ **The copy is already named, and it does the visible travel**:
310
+ `syncCloneWithDropTarget` moves it onto the destination inside the callback. Each
311
+ copy has a name of its own, two being on screen at once while a `toss` is
312
+ answered, and all share the class `navi-drag-clone`, so
313
+ `::view-transition-group(.navi-drag-clone)` styles the landing (read from Chrome
314
+ 125 on; before that only a rule written against the class goes unread).
315
+
316
+ What is left to name is the OTHER piece, the one standing there that goes the
317
+ other way. **A name rides the element that MOVES, and that element has to be
318
+ visible at both ends of the transition.** Never the source: it is
319
+ `visibility: hidden` until the promise `land` returned settles, which still gets
320
+ it captured, as an empty image — a name on it is a group fading in from nothing,
321
+ or out into nothing, over the copy doing the real travel. Where the places are
322
+ fixed and the pieces drawn into them, key each piece by WHO it is, so the same
323
+ node walks from one place to the other.
324
+
325
+ The name is written twice, and neither write is redundant: by hand on the DOM
326
+ before `startViewTransition` is called, because the old state is captured right
327
+ then, and from state, because the render inside the callback would put the plain
328
+ name straight back. Clear that state when `finished` resolves — a name left
329
+ behind is claimed twice by the next transition, and that one is dropped for it.
330
+ The names are roles (the piece passing over, the one passing under) because a
331
+ `::view-transition` pseudo is selected by name and by nothing else; address both
332
+ its group and its image pair — the morph lives in one, anything a style adds
333
+ rides in the other. The padel board in `38_interactions_demo.html` does all of
334
+ it.
376
335
 
377
336
  The drop hint follows what a place is: a line drawn in the gap for `reorder`, the
378
337
  place itself lit up for `land`. Both are drawn among the places — the parent, or
@@ -389,26 +348,15 @@ the board or the surface and reach them by inheritance:
389
348
  ### Saying the grab is acquired: `grab`
390
349
 
391
350
  The outcomes answer the **release**. Between the press and the release there is
392
- one instant that counts for the hand: the one where the object stops being
393
- pressed and starts being held — the same one whichever way the drag was entered,
394
- a finger held still or a mouse travelled a few pixels. `grab` is that instant.
395
-
396
- ```jsx
397
- <Box
398
- interactions={{
399
- toss: (event) => remove(event.detail.id),
400
- grab: () => navigator.vibrate?.(10),
401
- }}
402
- />
403
- ```
404
-
405
- It matters most where it is least visible. On a screen the held object is under
406
- the thumb that hides it, so the only feedback available is the one that is felt;
407
- without it the hand waits, doubts the press was heard, and lets go too early —
408
- the whole gesture fails, not its decoration. (With a mouse the object has visibly
409
- moved by then.) If the moment is for **paint**, no listener is needed: navi puts
410
- `data-grabbed` on the element for as long as the gesture holds it. `grab` is for
411
- what a stylesheet cannot do — a vibration, a state kept elsewhere, a counter.
351
+ one instant that counts for the hand — the object stops being pressed and starts
352
+ being held, whichever way the drag was entered — and `grab` is that instant:
353
+ `grab: () => navigator.vibrate?.(10)` beside the outcome. On a screen the held
354
+ object is under the thumb that hides it, so the only feedback available is the
355
+ one that is felt; without it the hand doubts the press was heard and lets go too
356
+ early — the whole gesture fails, not its decoration. For **paint** no listener
357
+ is needed: navi puts `data-grabbed` on the element for as long as the gesture
358
+ holds it. `grab` is for what a stylesheet cannot do — a vibration, a state kept
359
+ elsewhere, a counter.
412
360
 
413
361
  It is not an interaction on its own: declared without an outcome or `moving`
414
362
  there is no gesture for it to begin, and a dev warning says so — unless the
@@ -463,13 +411,13 @@ and says nothing reads as a broken screen, so the hand insists.
463
411
  ```
464
412
 
465
413
  So the interaction stays declared and says `"refuse"` in place of what it does.
466
- The threshold is the same one — a mouse travelling, a finger holding still, a
467
- mouse's few pixels inside a `data-drag-on-contact` — and at the instant the grab
468
- would have been acquired there is none: nothing translates, no copy is made, no
469
- release is answered. `refuse` is told at that instant, where feedback is
470
- expected; it has no `gestureInfo`, there being no gesture, and `pointerType`
471
- says which hand asked — a vibration for a finger, nothing extra for a mouse whose
472
- cursor has already said it. One outcome refusing refuses the whole carry.
414
+ The threshold is the same — a mouse travelling, a finger holding still, a mouse's
415
+ few pixels inside a `data-drag-on-contact` — and at the instant the grab would
416
+ have been acquired there is none: nothing translates, no copy is made, no release
417
+ is answered. `refuse` is told then, where feedback is expected, with no
418
+ `gestureInfo` (there was no gesture) and the `pointerType` that says which hand
419
+ asked — a vibration for a finger, nothing extra for a mouse whose cursor has
420
+ already said it. One outcome refusing refuses the whole carry.
473
421
 
474
422
  **It walks no axis, so it takes none.** Whatever reads what a drag source walks
475
423
  to know what is left for itself — a box that travels, a surface that pans — steps
@@ -477,16 +425,15 @@ over an element that is refusing: a swipe starting on a locked row is the row of
477
425
  slides' swipe, a drag starting on a pinned court pans the plan. A thing that
478
426
  cannot be taken hold of is exactly the one a hand rests on without thinking, and
479
427
  a surface with a dead zone the size of an object in the middle of it is wrong
480
- every time. For the axes, `move: "refuse"` is `move: false`. For the press it is
481
- not:
428
+ every time. For the axes, `move: "refuse"` is `move: false`; for the press it is
429
+ not.
482
430
 
483
431
  **The press itself stays the element's**, settled there like any gesture settles
484
432
  one: the pointer is taken, so a `longpress` declared beside the drag does not
485
- answer afterwards, and the click the release leaves behind is swallowed. What is
486
- locked behaves like what is not, up to the moment it says no. The exception is a
487
- box declaring `pan`/`zoom`, the one thing that takes a press whole and in every
488
- direction: there the surface keeps it, and the refusal is told without taking
489
- anything — no pointer, no click, nothing prevented.
433
+ answer afterwards, and the click the release leaves behind is swallowed. The
434
+ exception is a box declaring `pan`/`zoom`, the one thing that takes a press whole
435
+ and in every direction: there the surface keeps it, and the refusal is told
436
+ without taking anything — no pointer, no click, nothing prevented.
490
437
 
491
438
  ### A press made elsewhere: `--navi-grab`
492
439
 
@@ -525,14 +472,13 @@ item plus whatever being carried changes.
525
472
 
526
473
  **Which is also the trap, for anything positioned on a board.** The copy is a
527
474
  deep clone put in a carrier box, so a geometry written in the style attribute
528
- comes with it. navi takes back where it stands (`position`, `inset`, `margin` and
529
- `translate` are reset on the copy) but not its size —
530
- `width: calc(50% - 2 * var(--gap))` then means half of the carrier, and the piece
531
- is carried at the wrong size. Put what a piece LOOKS like in a class, leave only
532
- which place it is inline (two custom properties will do), and let it fill its
533
- carrier — said of what is inside the wrapper rather than of `[navi-drag-clone]`,
534
- because the copy loses that mark as it lands (that is how it drops its lift for
535
- the transition) and has to keep its size all the way down:
475
+ comes with it. navi resets where it stands (`position`, `inset`, `margin`,
476
+ `translate`) but not its size: `width: calc(50% - 2 * var(--gap))` then means
477
+ half of the carrier, and the piece is carried at the wrong size. Put what a piece
478
+ LOOKS like in a class, leave only which place it is inline (two custom properties
479
+ will do), and let it fill its carrier — said of what is inside the wrapper, not
480
+ of `[navi-drag-clone]`, which the copy loses as it lands (that is how it drops
481
+ its lift for the transition) while it has to keep its size all the way down:
536
482
 
537
483
  ```css
538
484
  [navi-drag-clone-wrapper] .piece {
@@ -549,10 +495,10 @@ Read off the dragged element, so a whole list or a single item can answer:
549
495
  | `--drag-clone-scale` | how much bigger it gets once picked up; `1` to keep its size |
550
496
 
551
497
  **What stays behind is the source, not a hole.** The original keeps its place in
552
- the layout, only `visibility: hidden`, until the answer settles — so it says
553
- where the thing left from for as long as the question is open. A mark left where
554
- the thing was — an imprint, a dashed outline — is drawn ON that element, and its
555
- parts say `visibility: visible` to come back from the hidden source:
498
+ the layout, only `visibility: hidden`, until the answer settles — it says where
499
+ the thing left from for as long as the question is open. A mark left there (an
500
+ imprint, a dashed outline) is drawn ON that element, and its parts say
501
+ `visibility: visible` to come back from the hidden source:
556
502
 
557
503
  ```css
558
504
  .paper[navi-drag-clone-source]::after {
@@ -663,24 +609,19 @@ const onPointerDown = (pointerDownEvent) => {
663
609
 
664
610
  An element that ends up somewhere is NOT this: that one is `move` — or `land`
665
611
  when what it ends up on is a surface — and doing it by hand gives up the
666
- constraint, the commit and the way back when the answer refuses. What the
667
- machinery brings is the reason not to write it again:
668
-
669
- - **When the press becomes a drag** is `dragAfterIntent`: a `data-drag-handle`
670
- on contact, a mouse by distance, a finger by TIME, because travel is exactly
671
- what a scroll looks like — one timer for every pointer makes the mouse wait for
672
- something it never had to prove.
673
- - **A touch has to be refusable before it is refused**: `markDragSource` goes
674
- down at mount, on the source itself, so what surrounds it keeps scrolling (the
675
- two conditions are in
676
- [mobile_touch.md](./mobile_touch.md#the-browser-decides-about-8px-in-and-does-not-wait)).
677
- A blanket `touch-action: none` on the container buys the same drag by taking
678
- the pan away, and the pan then has to be written by hand too.
679
- - **A capture that goes was not necessarily given back.** `lostpointercapture`
680
- reads the same whether the gesture handed the pointer over or the browser
681
- dropped it mid-drag, which it does more often than the specification suggests.
682
- The loop tells the two apart, and `gestureInfo.cancelled` is where it comes
683
- out: a release nobody asked for must commit nothing.
612
+ constraint, the commit and the way back when the answer refuses.
613
+
614
+ **A touch has to be refusable before it is refused**, so `markDragSource` goes
615
+ down at mount, on the source itself, and what surrounds it keeps scrolling (the
616
+ two conditions are in
617
+ [mobile_touch.md](./mobile_touch.md#the-browser-decides-about-8px-in-and-does-not-wait)).
618
+ A blanket `touch-action: none` on the container buys the same drag by taking the
619
+ pan away, and the pan then has to be written by hand too. **A capture that goes
620
+ was not necessarily given back**: `lostpointercapture` reads the same whether the
621
+ gesture handed the pointer over or the browser dropped it mid-drag, which it does
622
+ more often than the specification suggests. The loop tells the two apart, and
623
+ `gestureInfo.cancelled` is where it comes out — a release nobody asked for must
624
+ commit nothing.
684
625
 
685
626
  A gesture driven this way is outside the registry, so it says so itself to
686
627
  whatever travels above it: `data-no-drag-travel` (see
@@ -84,7 +84,8 @@ are read at the press, before the box moves:
84
84
  so with `data-press-only`, and a travel starts there like anywhere else.
85
85
  2. **A scroller in between with room left that way.** It keeps the gesture until
86
86
  it has no room left, and only then hands the travel over — so a row that
87
- scrolls sideways inside a page still scrolls sideways.
87
+ scrolls sideways inside a page still scrolls sideways. A row swiped with
88
+ `interactions` is the exception: its swipe does not ask.
88
89
  3. **Another travelling box in between** — see
89
90
  [Boxes inside boxes](#boxes-inside-boxes).
90
91
  4. **Something in between that is picked up and carried** — see
@@ -192,14 +193,14 @@ A popup pushed back towards its edge and a swiped row are travels too, the
192
193
  simple kind: one box, one direction, no neighbour to bring in. The two below
193
194
  carry screens.
194
195
 
195
- | | `SlideContainer` | `RouteTravel` |
196
- | ----------------------- | ----------------------------------- | ---------------------------------- |
197
- | what the screens are | `<Slide>`s in one box, all mounted | routes — one mounted, ever |
198
- | what says which is here | a `signal`, `current` / a command | the URL |
199
- | what the finger moves | a translated track | the pictures of a view transition |
200
- | letting go too early | the track comes back | the transition is played backwards |
201
- | what says the order | the layout map | the `<Route>` children, in order |
202
- | what one wheel push is | `move(±1)`, as an arrow key | one travel, as a tab pressed |
196
+ | | `SlideContainer` | `RouteTravel` |
197
+ | ----------------------- | ---------------------------------- | ---------------------------------- |
198
+ | what the screens are | `<Slide>`s in one box, all mounted | routes — one mounted, ever |
199
+ | what says which is here | a `signal`, `current` / a command | the URL |
200
+ | what the finger moves | a translated track | the pictures of a view transition |
201
+ | letting go too early | the track comes back | the transition is played backwards |
202
+ | what says the order | the layout map | the `<Route>` children, in order |
203
+ | what one wheel push is | `move(±1)`, as an arrow key | one travel, as a tab pressed |
203
204
 
204
205
  Both expose how far the travel has come, and the way to read it differs because
205
206
  what draws an indicator differs. `SlideContainer` writes