@jsenv/navi 0.29.64 → 0.29.66
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/jsenv_navi.js +829 -97
- package/dist/jsenv_navi.js.map +17 -16
- package/docs/AI_INSTRUCTIONS.md +6 -0
- package/docs/navigation.md +6 -0
- package/docs/route_transitions.md +129 -0
- package/package.json +2 -2
package/docs/AI_INSTRUCTIONS.md
CHANGED
|
@@ -159,6 +159,12 @@ consistency across the app, not from any single call site.
|
|
|
159
159
|
it.
|
|
160
160
|
- `docs/MOBILE_LAYOUT_PITFALLS.md` — mobile-specific layout gotchas (viewport
|
|
161
161
|
units, virtual keyboard, safe areas).
|
|
162
|
+
- `docs/route_transitions.md` — how pages move against each other on
|
|
163
|
+
navigation (`defineRouteTransition`): a transition states a relation the
|
|
164
|
+
user reads as a map, which movement fits which relation, when a global
|
|
165
|
+
default is right, marking the page area between fixed bars, and why a pair
|
|
166
|
+
of routes is animated by `RouteTravel` or by a route transition but never
|
|
167
|
+
both. Read it before animating any navigation.
|
|
162
168
|
- `docs/navigation.md` — how to build navigation: declaring routes
|
|
163
169
|
(`route()` / `setupRoutes()`), when a section is a route of its own rather
|
|
164
170
|
than a param, search params bound to signals, rendering with `<Route>`,
|
package/docs/navigation.md
CHANGED
|
@@ -288,6 +288,12 @@ Demo: [../src/nav/demos/route_travel/route_travel.html](../src/nav/demos/route_t
|
|
|
288
288
|
and [../src/nav/demos/tabs/tabs.html](../src/nav/demos/tabs/tabs.html). The full
|
|
289
289
|
spec of the gesture is [drag_to_travel.md](./drag_to_travel.md).
|
|
290
290
|
|
|
291
|
+
`RouteTravel` is for pages that form a ROW the finger can push. Pages related
|
|
292
|
+
pair by pair without being a row — a game opened from several places, a
|
|
293
|
+
settings page rising over whatever showed it — are animated with
|
|
294
|
+
`defineRouteTransition` instead, and a given pair must be animated by one of
|
|
295
|
+
the two, never both: see [route_transitions.md](./route_transitions.md).
|
|
296
|
+
|
|
291
297
|
## Creating something, then editing it
|
|
292
298
|
|
|
293
299
|
The create screen, the page of what was created, the edit screen — three routes,
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
# Route transitions
|
|
2
|
+
|
|
3
|
+
How pages of an app move against each other when the user navigates —
|
|
4
|
+
`defineRouteTransition`, `defineRouteDefaultTransition`, and the thinking that
|
|
5
|
+
decides which movement (if any) a navigation deserves. The API grammar itself
|
|
6
|
+
(accepted forms, shipped type names) lives in the JSDoc of
|
|
7
|
+
`defineRouteTransition`; this file holds what a signature cannot say.
|
|
8
|
+
|
|
9
|
+
Demos:
|
|
10
|
+
[../src/nav/demos/route_transition/route_transition.html](../src/nav/demos/route_transition/route_transition.html),
|
|
11
|
+
[../src/nav/demos/route_transition/route_transition_default.html](../src/nav/demos/route_transition/route_transition_default.html)
|
|
12
|
+
|
|
13
|
+
## What a transition is for
|
|
14
|
+
|
|
15
|
+
A transition is not decoration: it states a **relation** between two pages, and
|
|
16
|
+
the user reads it as a map. A page sliding in from the right says "this place is
|
|
17
|
+
deeper, the way back is to the left" — which is why the back arrow then feels
|
|
18
|
+
inevitable rather than learned. A movement that states a relation the app does
|
|
19
|
+
not actually have (a slide between two sibling tabs) teaches a false map, and a
|
|
20
|
+
false map is worse than no animation at all.
|
|
21
|
+
|
|
22
|
+
So the unit of declaration is the pair, not the app:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
defineRouteTransition(MY_GAMES_PAGE, GAME_PAGE, "slide-x");
|
|
26
|
+
defineRouteTransition(RADAR_PAGE, GAME_PAGE, "slide-x");
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
and two pages never written in the same relation play **nothing** between each
|
|
30
|
+
other. That silence is a statement too: "Mes parties" and "Radars" are two tabs
|
|
31
|
+
of a bottom bar, side by side, neither before the other — a cut is the honest
|
|
32
|
+
rendering of that fact. Resist the urge to fill every navigation with movement;
|
|
33
|
+
declare the relations that exist and let the rest cut.
|
|
34
|
+
|
|
35
|
+
## Choosing a movement
|
|
36
|
+
|
|
37
|
+
- **`slide-x`** — going INTO something: a list item opened, a card followed, a
|
|
38
|
+
notification tapped. The page is deeper on the same plane; leaving it slides
|
|
39
|
+
back out. The most common relation in an app, and the one every phone has
|
|
40
|
+
taught.
|
|
41
|
+
- **`slide-y`** — the same relation on a vertical arrangement, when the layout
|
|
42
|
+
genuinely reads as a column.
|
|
43
|
+
- **`cover-x` / `cover-y`** — a page that INTERRUPTS rather than continues:
|
|
44
|
+
settings, a composer, anything modal-like that one returns from to find the
|
|
45
|
+
page beneath unchanged. The covered page holding still is the point — it
|
|
46
|
+
promises "you are not leaving, this is on top".
|
|
47
|
+
- **`zoom`** — a detail brought closer: a photo, a card expanded into a page.
|
|
48
|
+
- **`cross-fade`** — a soft change with no spatial claim. Use it where a cut
|
|
49
|
+
feels harsh but no direction would be true.
|
|
50
|
+
- **`none`** — silence, written down. Needed only to override: one way of a
|
|
51
|
+
pair, or the default.
|
|
52
|
+
|
|
53
|
+
Two recommendations that matter more than the individual choices:
|
|
54
|
+
|
|
55
|
+
- **One movement per KIND of relation, app-wide.** If opening a game slides
|
|
56
|
+
from the right, opening a profile should too — the user learns one grammar,
|
|
57
|
+
not one rule per page.
|
|
58
|
+
- **Keep reciprocity.** The way back being the same movement reversed is what
|
|
59
|
+
makes the map hold together; it is the default, and breaking it (a relation
|
|
60
|
+
written for the exact way travelled wins over being the reverse of another)
|
|
61
|
+
should answer a real asymmetry in the app, not a styling whim.
|
|
62
|
+
|
|
63
|
+
## A default transition — when
|
|
64
|
+
|
|
65
|
+
`defineRouteDefaultTransition("cross-fade")` plays on every navigation no
|
|
66
|
+
relation was written for. Two situations, two answers:
|
|
67
|
+
|
|
68
|
+
- **App-shaped UI** (bars, tabs, pages one goes into): don't. The silence
|
|
69
|
+
between sibling tabs is part of the grammar, and a default erases it. Declare
|
|
70
|
+
the relations by hand.
|
|
71
|
+
- **Content-shaped site** (documents, articles, browsing): a global cross-fade
|
|
72
|
+
can be right — every navigation is a soft change of subject and no pair
|
|
73
|
+
deserves a direction. This is the case the export exists for.
|
|
74
|
+
|
|
75
|
+
A default has no direction (nothing says which of two arbitrary pages is
|
|
76
|
+
"before" the other), so only directionless movements make sense there. Written
|
|
77
|
+
relations, and `"none"`, always win over it.
|
|
78
|
+
|
|
79
|
+
## Pages between fixed bars: mark the area
|
|
80
|
+
|
|
81
|
+
By default the movement plays on the document itself — right when pages are the
|
|
82
|
+
whole viewport. With fixed bars it is not: the root snapshot spans the viewport
|
|
83
|
+
and the bars' regions are blank in it, so a vertical movement drags a blank
|
|
84
|
+
band across the screen. Mark the region the pages live in instead:
|
|
85
|
+
|
|
86
|
+
```html
|
|
87
|
+
<div class="app" data-navi-route-transition-area>…routes…</div>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
One attribute, on an element the layout already has. The movement then plays on
|
|
91
|
+
that region's own pictures, clipped at its bounds, and the bars never move —
|
|
92
|
+
without being named one by one. An app with fixed bars should consider this
|
|
93
|
+
attribute part of declaring transitions at all, not an option.
|
|
94
|
+
|
|
95
|
+
## Custom movements
|
|
96
|
+
|
|
97
|
+
A type navi does not ship belongs to the application: the name is written on
|
|
98
|
+
the root for the length of the transition
|
|
99
|
+
(`data-navi-route-transition-type="<type>"`, next to
|
|
100
|
+
`data-navi-route-transition="forward"|"back"`), and the app's CSS defines the
|
|
101
|
+
movement against the view transition pseudo-elements — of the document, or of
|
|
102
|
+
the marked area. See the JSDoc of `defineRouteTransition` for the selector
|
|
103
|
+
shape, and the `spin` type in the demo for a working one.
|
|
104
|
+
|
|
105
|
+
## Route transitions and `RouteTravel` — one pair, one system
|
|
106
|
+
|
|
107
|
+
`RouteTravel` and `defineRouteTransition` answer different questions:
|
|
108
|
+
|
|
109
|
+
- **`RouteTravel`** is a ROW: a total order of tabs, plus the drag gesture that
|
|
110
|
+
walks it. Use it when the pages are genuinely a row the finger should push.
|
|
111
|
+
- **`defineRouteTransition`** declares individual relations, with no gesture
|
|
112
|
+
and no order beyond each pair.
|
|
113
|
+
|
|
114
|
+
A given pair of routes must be animated by one of the two, never both: a
|
|
115
|
+
travel's pictures can be under a finger, and a transition starting on top would
|
|
116
|
+
skip them mid-slide — and a page one can drag has promised a translation, which
|
|
117
|
+
a cross-fade would break. The runtime enforces the priority (a travel in flight
|
|
118
|
+
wins; the route transition is skipped with a console warning); the warning is
|
|
119
|
+
the sign of a misconfiguration to fix, not a mechanism to rely on.
|
|
120
|
+
|
|
121
|
+
## The rest, briefly
|
|
122
|
+
|
|
123
|
+
- Pace: `--navi-route-transition-duration` (CSS, default 300ms) for everyone;
|
|
124
|
+
a per-relation `{ type, duration }` for one relation.
|
|
125
|
+
- The URL leads: transitions play on navigations somebody else started (a
|
|
126
|
+
`<Link>`, the back button, `history.back()`). Nothing here navigates.
|
|
127
|
+
- A browser without view transitions (Firefox) navigates with a cut. The app
|
|
128
|
+
must remain fully usable that way — which it is, if the transitions state
|
|
129
|
+
relations rather than carry information.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/navi",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.66",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Library of components including navigation to create frontend applications",
|
|
6
6
|
"repository": {
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"prepublishOnly": "npm run build"
|
|
30
30
|
},
|
|
31
31
|
"dependencies": {
|
|
32
|
-
"@jsenv/dom": "0.17.
|
|
32
|
+
"@jsenv/dom": "0.17.22",
|
|
33
33
|
"@jsenv/humanize": "1.7.8",
|
|
34
34
|
"@jsenv/validity": "0.4.2"
|
|
35
35
|
},
|