@jsenv/navi 0.29.49 → 0.29.50
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 +234 -146
- package/dist/jsenv_navi.js.map +12 -8
- package/dist/jsenv_navi_side_effects.js +36 -16
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/docs/drag_to_travel.md +80 -8
- package/package.json +2 -2
package/docs/drag_to_travel.md
CHANGED
|
@@ -123,14 +123,17 @@ page moved a little, and it looked wrong":
|
|
|
123
123
|
|
|
124
124
|
- **the leftovers of a scroll**, handed up the chain until something moves: a
|
|
125
125
|
list inside the box reaches its end and the page scrolls behind the travel.
|
|
126
|
-
`overscroll-behavior-<axis>: contain !important
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
axis only — the other one is the content's own scrolling,
|
|
133
|
-
not stop scrolling anyway, it stops spilling
|
|
126
|
+
`overscroll-behavior-<axis>: contain !important`, **written once and for all,
|
|
127
|
+
never while the finger is down**: a browser decides what a gesture may do when
|
|
128
|
+
the gesture BEGINS (at the touchstart, at the first wheel event), so a
|
|
129
|
+
property written after that decision arrives too late for the gesture it was
|
|
130
|
+
meant for. That is what "usually it does not move, sometimes it does" is made
|
|
131
|
+
of — and it is why none of this can be done in JS at the moment it is needed.
|
|
132
|
+
On the travelling axis only — the other one is the content's own scrolling,
|
|
133
|
+
and containing does not stop scrolling anyway, it stops spilling. WHERE that
|
|
134
|
+
property is written is a question of its own, and the engines do not answer it
|
|
135
|
+
the same way: see [What is contained, and what still
|
|
136
|
+
leaks](#what-is-contained-and-what-still-leaks);
|
|
134
137
|
- **the elastic bounce** at the end of a page, and the swipe that goes back in
|
|
135
138
|
history with it: `overscroll-behavior: none` on the document while a finger is
|
|
136
139
|
down. Same lateness applies, so this is a last resort behind the rule above
|
|
@@ -144,6 +147,75 @@ Both are written by the gesture itself (`data-drag-travel-gesture` and
|
|
|
144
147
|
time goes on bouncing. `preventDefault()` on each move says the same thing to
|
|
145
148
|
the browser for what those two properties do not cover.
|
|
146
149
|
|
|
150
|
+
### What is contained, and what still leaks
|
|
151
|
+
|
|
152
|
+
Containing is only ever read on a **scroll container** — an element that clips,
|
|
153
|
+
in the browser's sense, whether or not it has anything to scroll. Three places
|
|
154
|
+
could carry it: the travelling box, everything inside it, or the scrollers
|
|
155
|
+
themselves. Which of the three works is an engine question, and the answer
|
|
156
|
+
splits in two:
|
|
157
|
+
|
|
158
|
+
- **Blink** asks every scroll container between the pointer and the page whether
|
|
159
|
+
the gesture may go past it, _even one with nothing to scroll_. Containing the
|
|
160
|
+
travelling box is therefore the whole answer — and saying it to everything
|
|
161
|
+
inside is actively harmful: anything that happens to clip (a line with an
|
|
162
|
+
ellipsis, a rounded card, the invisible checkbox that covers a selectable row)
|
|
163
|
+
becomes a **dead zone under the wheel**, a container that stops the gesture
|
|
164
|
+
and has nothing to move with it. This is the bug that made a list refuse the
|
|
165
|
+
wheel inside a popup and only answer its scrollbar.
|
|
166
|
+
- **Gecko and WebKit** ask only the containers that actually scroll. The
|
|
167
|
+
travelling box is walked past — it travels, it does not scroll — so the
|
|
168
|
+
scroller itself has to be told, and saying it to everything is harmless there.
|
|
169
|
+
|
|
170
|
+
So `drag_to_travel.js` writes it on the box for everyone, and on everything
|
|
171
|
+
inside only outside Blink (`@supports not (-webkit-app-region: none)`, one of
|
|
172
|
+
the few properties that names an engine rather than a user agent string).
|
|
173
|
+
|
|
174
|
+
It also names the scrollers a browser makes on its own — `textarea`,
|
|
175
|
+
`select[multiple]`, `select[size]` — wherever they are inside the box. Nobody
|
|
176
|
+
declared those, so nothing can find them by looking; being native is exactly
|
|
177
|
+
what makes them nameable. `input` is deliberately not among them: it has
|
|
178
|
+
nothing to scroll on the axis anything travels on, and containing it is how a
|
|
179
|
+
row-wide invisible checkbox becomes a hole under the wheel. The cost of naming
|
|
180
|
+
them is that an empty `textarea` is contained too — a browser cannot be asked
|
|
181
|
+
"only if it scrolls" — so on Blink a wheel over one moves nothing rather than
|
|
182
|
+
the list around it.
|
|
183
|
+
|
|
184
|
+
On Blink this leaves the boxes that **do not clip**, since those are never
|
|
185
|
+
asked. Of navi's own: `SlideContainer` clips (`overflow: hidden`) and a
|
|
186
|
+
`SidePanel` is a `Dialog`, which scrolls (`overflow: auto`) — both are asked. A
|
|
187
|
+
`RouteTravel` box does not clip and must not be made to: a scroll container
|
|
188
|
+
there would become the nearest one for every `position: sticky` inside the pages
|
|
189
|
+
it holds. A row marked swipeable by `interactions` does not clip either.
|
|
190
|
+
|
|
191
|
+
Which is why navi contains what it KNOWS scrolls, in `box.jsx`:
|
|
192
|
+
|
|
193
|
+
```css
|
|
194
|
+
[data-drag-travel*="y"] [data-scrollable] {
|
|
195
|
+
overscroll-behavior-y: contain !important;
|
|
196
|
+
}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
`[data-scrollable]` is worn by a `Box` that ASKED for `overflow: auto|scroll`,
|
|
200
|
+
never by one that merely clips — so this cannot make a dead zone the way `*`
|
|
201
|
+
does, and it puts the containment exactly where every engine reads it. A list, a
|
|
202
|
+
dialog body, a scrolling panel inside a travelling page are covered on Blink
|
|
203
|
+
again.
|
|
204
|
+
|
|
205
|
+
What still leaks, and only on Blink, and only under a box that does not clip: a
|
|
206
|
+
scroller **nobody declared and no tag names** — a bare
|
|
207
|
+
`<div style="overflow: auto">`, a widget from elsewhere. Its leftovers reach the
|
|
208
|
+
page, which is the old symptom in a much smaller corner. Two ways out, per case:
|
|
209
|
+
give the scroller a `Box` with an `overflow` (it is then declared), or contain it
|
|
210
|
+
by hand. The general fix belongs to Blink.
|
|
211
|
+
|
|
212
|
+
A note for whoever tests this: **Firefox cannot be measured with a synthetic
|
|
213
|
+
wheel**. Playwright dispatches one outside APZ, where Gecko enforces
|
|
214
|
+
`overscroll-behavior`, so containment never shows up there — inline, from a
|
|
215
|
+
stylesheet, headless or headed alike. The non-Blink branch is therefore left
|
|
216
|
+
exactly as it always was rather than tuned against a measurement that does not
|
|
217
|
+
exist.
|
|
218
|
+
|
|
147
219
|
### A hand reaching for something still moving is reaching for THAT thing
|
|
148
220
|
|
|
149
221
|
A gesture arriving while a travel is playing takes **that travel** over — it does
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/navi",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.50",
|
|
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.16",
|
|
33
33
|
"@jsenv/humanize": "1.7.8",
|
|
34
34
|
"@jsenv/validity": "0.4.2"
|
|
35
35
|
},
|