@jsenv/navi 0.29.416 → 0.29.418

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.
@@ -6,8 +6,6 @@ An element picked up and carried, and what letting go means. It is one gesture
6
6
  the gate they go through and how a control learns which of them asked are in
7
7
  [interactions.md](./interactions.md); who owns a press when the carried thing
8
8
  stands in a box that travels is in [drag_to_travel.md](./drag_to_travel.md).
9
- Whatever the moment, `event.detail.event` is the `pointerdown` the carry began
10
- with — for the release as well, unlike a swipe's.
11
9
 
12
10
  - [Carrying something: `move`, `reorder`, `land`, `toss`, `leave`](#carrying-something-move-reorder-land-toss-leave)
13
11
  - [While it is being moved: `moving`](#while-it-is-being-moved-moving)
@@ -17,6 +15,7 @@ with — for the release as well, unlike a swipe's.
17
15
  - [Saying the grab is acquired: `grab`](#saying-the-grab-is-acquired-grab)
18
16
  - [Saying the hold is let go: `release`](#saying-the-hold-is-let-go-release)
19
17
  - [The hand pulls and nothing follows: `refuse`](#the-hand-pulls-and-nothing-follows-refuse)
18
+ - [A press made elsewhere: `--navi-grab`](#a-press-made-elsewhere---navi-grab)
20
19
  - [Dressing the clone](#dressing-the-clone)
21
20
  - [What says a thing can be picked up](#what-says-a-thing-can-be-picked-up)
22
21
  - [The text inside: `user-select: none`](#the-text-inside-user-select-none)
@@ -25,23 +24,19 @@ with — for the release as well, unlike a swipe's.
25
24
 
26
25
  ## Carrying something: `move`, `reorder`, `land`, `toss`, `leave`
27
26
 
28
- All five are the same gesture — the element is picked up and carried — and what
29
- differs is the release. One detector reads them all, because it is one press.
27
+ `move` carries the element ITSELF and leaves it where it was put; `reorder`,
28
+ `land` and `toss` carry a copy and put the original back; `leave` carries the
29
+ element beside `move` or `moving`, a copy otherwise. Something moved has a new
30
+ place of its own; something reordered had its place taken by the list.
30
31
 
31
32
  `toss` and `leave` each **combine** with `reorder` and with `land`: dropped on
32
33
  another item the element changes places, thrown far and fast it is gotten rid of,
33
34
  let go of away from every place it leaves. `leave` combines with `move` as well.
34
- `move` does **not** combine with any of the three that carry a copy (`reorder`,
35
- `land`, `toss`), and neither do `reorder` and `land` with each other — one
36
- release cannot mean two of those. Declared together, the copy-carrying one wins
37
- and `move` is never answered — the element itself never travels, and a release
38
- that is not the other outcome means nothing at all; of `reorder` and `land`,
39
- `land` wins. A dev warning says so in each case.
40
-
41
- `move` carries the element ITSELF and leaves it where it was put; the others
42
- carry a copy and put the original back. That is the same difference said in layout
43
- terms: something moved has a new place of its own, something reordered had its
44
- place taken by the list.
35
+ `move` does **not** combine with the three that carry a copy, and neither do
36
+ `reorder` and `land` with each other — one release cannot mean two of those.
37
+ Declared together, the copy-carrying one wins and the element itself never
38
+ travels; of `reorder` and `land`, `land` wins. `moving` goes with `move` and
39
+ `leave`, never with a copy. A dev warning says so in each case.
45
40
 
46
41
  ```jsx
47
42
  <Box
@@ -52,34 +47,47 @@ place taken by the list.
52
47
  />
53
48
  ```
54
49
 
55
- `data-drag-free` on the element or a container lets it leave; by default a `move`
56
- stays inside what one can SEE of its scroll container — the nearest ancestor whose
57
- `overflow` is `auto` or `scroll`, the page's viewport when there is none — so a
58
- board that only cuts its content (`hidden`, `clip`) does not hold what moves on
59
- it. A `move` whose answer rejects travels back, because a
60
- place the application would not accept must not stay on screen as if it had.
61
-
62
- **Where the position is kept is the answer's.** An element drawn from state —
63
- `left`/`top` computed from a position the application holds — is redrawn by the
64
- handler above, and from then on its layout owns the position: navi sees the
65
- element drawn elsewhere while the answer was given and lets go of its own
66
- translate, so the thing does not land twice as far as the hand went. A handler
67
- that draws nothing (a token on a free canvas) leaves the position to the element,
68
- where it is baked in. Nothing to declare either way — but a handler whose draw
69
- comes later than its answer has to return the promise of that draw.
70
-
71
- That is one answer, at the release, with the whole of the gesture in it: `move` is
72
- not told while the hand moves, and until the release navi carries the element with
73
- a translate of its own. A thing that has to change something WHILE it is dragged —
74
- or that must never be translated at all — declares `moving` instead (below).
75
-
76
- **A copy that can be thrown frees its own area.** What is dragged is otherwise kept
77
- inside its scroll area — right for a reorder, since a row belongs to its list, and
78
- fatal for a throw: the copy hits the edge of the list, no distance is ever covered,
79
- so no throw can happen and no sideways movement is even visible. So `toss` lifts
80
- that constraint for the copy it carries, and `leave` lifts it for whatever it is
81
- declared on — a thing that can be let go of outside has to be able to get there.
82
- Neither is a way to free a plain `move`, which says `data-drag-free`.
50
+ What each one is told, in `event.detail` beside `event` — the `pointerdown` the
51
+ carry began with, for the release as well (unlike a swipe's), except for
52
+ [a press handed over](#a-press-made-elsewhere---navi-grab):
53
+
54
+ | interaction | `event.detail` |
55
+ | ---------------- | ---------------------------------------------------------------- |
56
+ | `move`, `moving` | `{ x, y }`, how far from the grab: once, or on every frame |
57
+ | `reorder` | `{ fromId, toId, syncCloneWithDropTarget }` |
58
+ | `land` | `{ fromId, toId, x, y, width, height, syncCloneWithDropTarget }` |
59
+ | `toss` | `{ id, velocity, x, y }` |
60
+ | `leave` | `{ id, x, y }` |
61
+ | `grab` | `{ pointerType, gestureInfo }` |
62
+ | `release` | `{ id, x, y, outcome }` |
63
+ | `refuse` | `{ pointerType }` |
64
+
65
+ Items and places are named by their `id`. **What an outcome returns is waited
66
+ on**: the gesture holds what it carries until that promise settles, and a
67
+ rejection sends it home — a place the application would not accept must not stay
68
+ on screen as if it had. `moving`, `grab`, `release` and `refuse` **report, they
69
+ do not ask**: what they return is not waited on, and preventing their event
70
+ calls nothing off.
71
+
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).
82
+
83
+ **Where it may go.** A `move` stays inside what one can SEE of its scroll
84
+ container — the nearest ancestor whose `overflow` is `auto` or `scroll`, the
85
+ 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.
83
91
 
84
92
  ```jsx
85
93
  <List.Item
@@ -98,42 +106,34 @@ Neither is a way to free a plain `move`, which says `data-drag-free`.
98
106
  />
99
107
  ```
100
108
 
101
- The gesture is `startDragTo`'s, whole: `move` carries the element itself, the
102
- others carry a copy above the page while the original keeps its place, with a
103
- drop hint, drop targets found by intersection, no-op drops filtered out, and the
104
- flight of a thrown copy plus its return when the answer refuses. Only what the
105
- declared outcomes need runs — no copy for a move, no hint for something
106
- that can only be thrown away.
107
-
108
109
  Every element declaring `reorder` marks itself, so the set of items IS the set of
109
110
  elements that declared it — no selector to pass, and an item that must not move
110
111
  simply does not declare it. An element declaring only `toss` marks nothing: it is
111
- not a place anything lands. Items are named by their `id`.
112
-
113
- `toId` is null for a drop at the end. `syncCloneWithDropTarget` must be called
114
- synchronously inside the transition callback, next to the state change, so the copy
115
- is captured where it lands rather than where it was let go of.
112
+ not a place anything lands. `toId` is null for a drop at the end.
116
113
 
117
- **The promise matters in both cases**: the gesture holds its copy until the answer
118
- settles. Returning the transition is what makes a landing continuous; a `toss` that
119
- rejects brings the copy back, because the thing still exists and the screen has to
120
- say so.
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.
121
120
 
122
121
  A throw is asked about before a landing: a hand that sent something across the
123
122
  screen has not asked for it to swap places with whatever it flew over.
124
123
 
125
- Starting a document transition is the application's call, not navi's: a
126
- `view-transition-name` must be unique per document, so only the application can
127
- name what moves.
128
-
129
124
  | Attribute | Meaning |
130
125
  | -------------------------------------------------------- | -------------------------------------- |
131
126
  | `data-drag-axis="x"\|"y"\|"xy"` | which axes the drag walks |
132
127
  | `data-drag-delay` `data-drag-slop` `data-drag-threshold` | when the press becomes a grab |
133
128
  | `data-drag-on-contact` | a finger may drag by travelling too |
129
+ | `data-drag-free` | it may leave its scroll area |
134
130
  | `data-toss-distance` `data-toss-speed` | how far and how fast counts as a throw |
135
131
  | `data-drop-container` | where the places are looked for |
136
132
 
133
+ `data-drag-axis` is `y` for a `reorder` with no `land`, `toss` or `leave` beside
134
+ it — it walks the list; a list that runs sideways says `x` — and `xy` for
135
+ everything else, which goes wherever the hand takes it.
136
+
137
137
  ### While it is being moved: `moving`
138
138
 
139
139
  `move` says where the element ended up, once. That is the answer for something
@@ -152,42 +152,32 @@ all along, and needs to be the one drawing.
152
152
  />
153
153
  ```
154
154
 
155
- Declaring it says both things at once: the element is told where the hand has
156
- taken it on every frame, and **navi moves nothing** — no translate while the
157
- gesture runs, nothing to hand back at the release, no reading the element
158
- afterwards to find out who owns its position. The caller draws, from the numbers
159
- it is given.
160
-
161
- Its detail is `{ x, y }`: where it is now, counted from the grab — the very
162
- numbers `move` ends with, said all along instead of once. Not steps since the last
163
- frame, which is what `pan` gives (a surface has no grab to count from): a caller
164
- adding up steps drifts, and has nothing to re-read after a frame it missed.
165
-
166
- Told, not asked, like `grab` and `release` — a draw that has to be awaited before
167
- the next frame is a draw one frame late. Where it differs from those two is that
168
- it is a gesture of its own: `moving` alone is a complete declaration, and it keeps
169
- everything the drag knows — the axes, the threshold, the hold a finger owes,
170
- `data-drag-free`, `grab`/`release`, `leave`, and `"refuse"` to lock it. Write
171
- `move` beside it only when the release settles something the frames did not.
172
-
173
- Nothing travels back, either: a `move` or a `leave` beside it whose answer rejects
174
- normally sends the element home, and there is no home to send it to when navi
175
- never moved it. The state the frames wrote is the caller's to put back.
176
-
177
- It carries the element itself, so it goes with `move` and `leave` and not with the
178
- three that carry a copy — for those, the original never goes anywhere, and there
179
- is nothing being moved to tell about (a dev warning says so).
155
+ Declaring it says both at once: the element is told where the hand has taken it
156
+ on every frame, and **navi moves nothing** — no translate, nothing to hand back
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.
180
170
 
181
171
  ### Let go of away from every place: `leave`
182
172
 
183
- A throw is a **gesture**: far and fast, the flick that gets rid of a row, judged
184
- before any landing. A release outside is a **place**: the hand let go with nothing
185
- under the thing, judged after a landing was looked for. They share the outcome an
186
- application usually attaches to them and nothing else — so `toss` is the throw,
187
- `leave` is the release outside, and neither reads the other's rules. There is no
188
- speed to a release; a fast drag across a plan that ends ON it has not asked for the
189
- thing to go, and a row pulled sideways out of its list and let go is a row put
190
- back, not a row deleted — a list declares `toss`, a surface declares `leave`.
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`.
191
181
 
192
182
  ```jsx
193
183
  <div data-drop-container>
@@ -205,37 +195,21 @@ back, not a row deleted — a list declares `toss`, a surface declares `leave`.
205
195
  </div>
206
196
  ```
207
197
 
208
- `leave` combines with every other outcome. Beside `land` or `reorder`, "outside" is
209
- away from every place. Where nothing is a place — beside `move`, which carries the
210
- element itself, beside `toss`, or alone — it is outside the surface the element
211
- stands in: the nearest
198
+ `leave` combines with every other outcome. Beside `land` or `reorder`, "outside"
199
+ is away from every place. Where nothing is a place — beside `move`, beside
200
+ `toss`, or alone — it is outside the surface the element stands in: the nearest
212
201
  `data-droppable` ancestor, or, without one, what can be seen of the scroll
213
202
  container (a dev warning says which). Either way it is judged on the element's
214
203
  box no longer overlapping it, not on the pointer, which is still well inside the
215
- frame when a small marker has just left it.
216
-
217
- ```jsx
218
- <Plan data-droppable>
219
- <Marker
220
- interactions={{
221
- move: (event) => remember(event.detail.x, event.detail.y),
222
- leave: () => remove(marker.id),
223
- }}
224
- />
225
- </Plan>
226
- ```
227
-
228
- Its detail is `toss`'s without the speed — `{ id, x, y }`, the distance travelled
229
- being what an exit is animated with. Picked up and put straight back down stays a cancel: it has to
230
- have gone somewhere to be away from anything.
204
+ frame when a small marker has just left it. Picked up and put straight back down
205
+ stays a cancel: it has to have gone somewhere to be away from anything. Its
206
+ `x`/`y` are what an exit is animated with.
231
207
 
232
- What the thing does while the answer is asked follows what was carried. A copy
233
- fades where it was let go of; the element itself stays where the hand put it. A
234
- resolve takes the copy away and lets go of the element's position — the
235
- application has removed the thing, or drawn it where it goes back to (the address
236
- point returns to where the geocoder put it) — and a reject brings either back, as
237
- a refused `move` does. A surface that clips its overflow clips the element on its
238
- way out; the copy a `land` carries lives in the top layer and does not.
208
+ While the answer is asked, a copy fades where it was let go of and the element
209
+ itself stays where the hand put it; a resolve takes the copy away and lets go of
210
+ the element's position (the application removed the thing, or drew it where it
211
+ goes back to). A surface that clips its overflow clips the element on its way
212
+ out; the copy lives in the top layer and does not.
239
213
 
240
214
  ### A finger that does not have to wait: `data-drag-on-contact`
241
215
 
@@ -296,17 +270,15 @@ Declaring `land` says an element can be CARRIED, which on a board is a different
296
270
  thing from being somewhere one can be put — a zone receives without ever being
297
271
  carried, a piece is carried without ever receiving, and both at once is a third
298
272
  case (dropped on a piece, the two swap, so it says `data-droppable` as well). A
299
- list has no such distinction, every row being both, which is why `reorder` needs
300
- no marker in the markup.
273
+ list has no such distinction, which is why `reorder` needs no marker.
301
274
 
302
275
  Places are looked for among the carried element's **siblings**, which is what a
303
- board is: pieces drawn beside the places, positioned over them. When what is
304
- carried does not stand among the places — a palette BESIDE the surface it fills, a
305
- marker drawn INSIDE the surface it can be put back on — say what holds both with
306
- `data-drop-container`. It holds the places rather than being one, so it goes on an
307
- ancestor of them: a surface that is itself the place is never found from inside
308
- itself. Missed, nothing lands and nothing says why — so the first press on a
309
- `land` with no place in reach warns, and names the surface it is standing on.
276
+ board is. When what is carried does not stand among the places — a palette
277
+ BESIDE the surface it fills, a marker drawn INSIDE the surface it can be put back
278
+ on — say what holds both with `data-drop-container`, on an ancestor of the
279
+ places: a surface that is itself the place is never found from inside itself.
280
+ Missed, nothing lands, so the first press on a `land` with no place in reach
281
+ warns, and names the surface it is standing on.
310
282
 
311
283
  ```jsx
312
284
  <div data-drop-container>
@@ -319,36 +291,20 @@ itself. Missed, nothing lands and nothing says why — so the first press on a
319
291
  </div>
320
292
  ```
321
293
 
322
- It also frees the copy's travel: the places being elsewhere by construction, a
323
- copy kept inside its own scroll area could never reach them.
324
-
325
294
  **When the place is bigger than what stands on it** — a zone holding a smaller
326
295
  card, a square holding a piece — the copy must not take the place's box, or it
327
- resizes on landing and resizes back when the real element appears.
328
- `syncCloneWithDropTarget` takes an element for that: the copy comes down on THAT
329
- box instead of the target's. Pass whatever occupies the destination — the piece
330
- already standing there, the empty slot waiting.
331
-
332
- ```jsx
333
- land: (event) => {
334
- const { fromId, toId, syncCloneWithDropTarget } = event.detail;
335
- const landingElement = pieceAt(toId) || slotOf(toId);
336
- return document.startViewTransition(() => {
337
- syncCloneWithDropTarget(landingElement);
338
- …
339
- }).finished;
340
- };
341
- ```
296
+ resizes on landing and resizes back when the real element appears. Pass
297
+ `syncCloneWithDropTarget` whatever occupies the destination — the piece already
298
+ standing there, the empty slot waiting — and the copy comes down on THAT box:
299
+ `syncCloneWithDropTarget(pieceAt(toId) || slotOf(toId))`.
342
300
 
343
301
  #### A place that is a surface
344
302
 
345
- A board's place is an element one can point at. A **surface** — a plan drawn over
346
- an aerial photo, a map, a floor — is one box where every point is a place, and
347
- "which element did it come down on" says nothing there. So the detail says
348
- **where**: `x`, `y`, `width`, `height`, the box the copy came down in, measured
349
- inside the place with its border and its scroll taken out. `toId` still names the
350
- surface it came down on, and nothing changes about the rest — the copy travels,
351
- the original stays where it was.
303
+ A **surface** — a plan drawn over an aerial photo, a map, a floor — is one box
304
+ where every point is a place, and "which element did it come down on" says
305
+ nothing there. So the detail says **where**: `x`, `y`, `width`, `height`, the box
306
+ the copy came down in, measured inside the place with its border and its scroll
307
+ taken out. `toId` names the surface.
352
308
 
353
309
  ```jsx
354
310
  <Shape
@@ -363,62 +319,35 @@ the original stays where it was.
363
319
 
364
320
  The size comes along because the anchor is yours: a chip dragged out of a palette
365
321
  is not the shape it becomes, so the middle of what the hand carried is usually the
366
- point that was aimed at.
367
-
368
- `syncCloneWithDropTarget` is the one thing to leave alone here — called with
369
- nothing it takes the whole surface's box, and there is rarely an element to pass
370
- it either, the thing being created by the answer itself. Not calling it leaves the
371
- copy where the hand put it, over the thing appearing there.
322
+ point that was aimed at. Leave `syncCloneWithDropTarget` alone here — called with
323
+ nothing it takes the whole surface's box, and the thing is created by the answer
324
+ itself — so the copy stays where the hand put it, over the thing appearing there.
372
325
 
373
326
  #### Naming what travels
374
327
 
375
- **The copy is already named, and it is the copy that does the visible travel.**
376
- `syncCloneWithDropTarget` moves it onto the destination inside the callback — so
377
- the piece the hand let go of slides to its place whether the application names
378
- anything or not. What is left to name is the OTHER one: the piece that was
379
- standing there and has to go the other way.
380
-
381
- The name is the copy's own, because two copies can be on screen at once — one
382
- still flying away while its `toss` is answered, another landing — and a name
383
- claimed twice aborts the transition. What every copy shares is the class
384
- `navi-drag-clone`, which is how a stylesheet reaches the landing:
385
- `::view-transition-group(.navi-drag-clone)`. A view-transition class is read
386
- from Chrome 125 on; before that the landing still plays, and only a rule written
387
- against the class goes unread. The wrapper carrying the copy paints nothing and
388
- takes neither.
389
-
390
- **And the original is hidden for the whole landing**, not only for the drag: it
391
- wears `navi-drag-clone-source` (`visibility: hidden`) until the promise returned
392
- by `land` settles, because the copy stands for it until then. An element that
393
- paints nothing is still captured — the group gets an empty image — so a name put
394
- on the source is a group fading in from nothing, or out into nothing, over the
395
- copy that is doing the real travel. That is what a swap looks like when it fades
396
- instead of sliding.
397
-
398
- Both follow from one rule: **a name rides the element that MOVES, and that
399
- element has to be visible at both ends of the transition.** Where the places are
400
- fixed and the pieces are drawn into them, nothing moves — two boxes change
401
- content, and hand-writing a name on each so that it "follows the player" names a
402
- journey whose start or end is the hidden source. Key the piece by WHO it is and
403
- let it be re-parented:
404
-
405
- ```jsx
406
- {places.map((place) => {
407
- const playerId = lineupAt(place.id);
408
- // Keyed by the player: the same DOM node walks from one place to the other,
409
- // so the browser has something to morph — and the displaced one was visible
410
- // before and is visible after.
411
- return <Piece key={playerId} id={playerId} style={boxOf(place)} … />;
412
- })}
413
- ```
414
-
415
- **The name is written twice, and neither write is redundant.** The old state is
416
- captured the moment `startViewTransition` is called, before any render, so the
417
- name must be on the DOM by then — written by hand, on the element. The render
418
- happening inside the callback would then put the plain name straight back, so
419
- the same name must also come from state. Clear that state when `finished`
420
- resolves: a name left behind is claimed twice by the next transition, and that
421
- one is dropped for it.
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.
422
351
 
423
352
  ```jsx
424
353
  land: (event) => {
@@ -438,29 +367,17 @@ land: (event) => {
438
367
  };
439
368
  ```
440
369
 
441
- The roles are names because a `::view-transition` pseudo can be selected by name
442
- and by nothing else — which is also how one of the two is told to pass over the
443
- other, and how the travel is given a length worth a card crossing a board rather
444
- than a menu opening. Both the group and the image pair are addressed: the morph
445
- lives in one, anything a style adds rides in the other.
446
-
447
- ```css
448
- ::view-transition-group(swap_over) {
449
- z-index: 20;
450
- }
451
- ::view-transition-group(swap_over),
452
- ::view-transition-image-pair(swap_over) {
453
- animation-duration: 420ms;
454
- animation-timing-function: ease-in-out;
455
- }
456
- ```
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`.
457
376
 
458
- The hint follows what a place is: a line drawn in the gap for `reorder`, the
459
- place itself lit up for `land`. Both are drawn among the places — the carried
460
- element's parent, or the `data-drop-container` when there is one — so the
461
- variables dressing them are read from the list, the board or the surface and reach
462
- them by plain inheritance. The copy goes the other way: it is drawn beside the
463
- thing it copies, and dressed by where that thing stands.
377
+ The drop hint follows what a place is: a line drawn in the gap for `reorder`, the
378
+ place itself lit up for `land`. Both are drawn among the places — the parent, or
379
+ the `data-drop-container` — so the variables dressing them are set on the list,
380
+ the board or the surface and reach them by inheritance:
464
381
 
465
382
  | Variable | Dresses |
466
383
  | ------------------------------------------------------------------------------------------ | ----------------------- |
@@ -471,10 +388,10 @@ thing it copies, and dressed by where that thing stands.
471
388
 
472
389
  ### Saying the grab is acquired: `grab`
473
390
 
474
- The interactions above answer the **release**. Between the press and the release there is
475
- one instant that counts for the hand: the one where the object stops being pressed
476
- and starts being held. `grab` is that instant — the same one whichever way the drag
477
- was entered, a finger held still or a mouse travelled a few pixels.
391
+ 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.
478
395
 
479
396
  ```jsx
480
397
  <Box
@@ -485,36 +402,26 @@ was entered, a finger held still or a mouse travelled a few pixels.
485
402
  />
486
403
  ```
487
404
 
488
- It matters most where it is least visible. On a screen the held object is under the
489
- thumb that hides it, so the only feedback available is the one that is felt; without
490
- it the hand waits, doubts the press was heard, and lets go too early — the whole
491
- gesture fails, not its decoration. With a mouse the grab is acquired after a few
492
- pixels and the object has visibly moved, so the answer is already there.
493
-
494
- Nothing here is about vibration: a sound, a class, a measure are the same moment.
495
-
496
- If what the moment is for is **paint**, no listener is needed at all: navi puts
497
- `data-grabbed` on the element for as long as the gesture holds it, and a
498
- stylesheet draws from that. `grab` is for what a stylesheet cannot do — the
499
- vibration above, a state kept elsewhere, a counter.
500
-
501
- `grab` **reports, it does not ask**: what it returns is not waited on, and
502
- preventing its event does not call the gesture off. And it is not an interaction on
503
- its own — declared without one of the five above (or `moving`) there is no
504
- gesture for it to be the beginning of, and a dev warning says so, unless the
505
- element declares `pan` or `zoom`, whose moments they then are
506
- ([pan_zoom.md](./pan_zoom.md)). Its detail carries `pointerType` and the
507
- `gestureInfo`.
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.
508
412
 
509
- A `longpress` needs none of this: it already happens at the moment the hold is
510
- acquired, not at the release.
413
+ It is not an interaction on its own: declared without an outcome or `moving`
414
+ there is no gesture for it to begin, and a dev warning says so — unless the
415
+ element declares `pan` or `zoom`, whose moment it then is
416
+ ([pan_zoom.md](./pan_zoom.md)). A `longpress` needs none of this: it already
417
+ happens at the moment the hold is acquired.
511
418
 
512
419
  ### Saying the hold is let go: `release`
513
420
 
514
- The mirror of `grab`, and the only interaction of the family always told. Each of
515
- the five above answers ONE meaning, so a release that means none of them — let go
516
- of over nothing, taken away by the system — reaches nobody, and whatever `grab` set
517
- up stays set up with nothing to take it down.
421
+ The mirror of `grab`, and the only interaction of the family always told. Each
422
+ outcome answers ONE meaning, so a release that means none of them — let go of
423
+ over nothing, taken away by the system — reaches nobody, and whatever `grab` set
424
+ up (a counter of what is in the hand) stays set up with nothing to take it down.
518
425
 
519
426
  ```jsx
520
427
  <Chip
@@ -526,28 +433,20 @@ up stays set up with nothing to take it down.
526
433
  />
527
434
  ```
528
435
 
529
- A bank of chips one drags onto a plan is the case: the counter must count what is
530
- in the hand from the moment the copy takes off — « Terrain 4/21 » before it lands —
531
- and something has to say when the hand is empty again, whether the copy landed,
532
- flew off or came home.
533
-
534
- Its detail is `{ id, x, y, outcome }`. `outcome` is which of the five is about to
535
- answer — `"move"`, `"reorder"`, `"land"`, `"toss"`, `"leave"` — or `null` when the
536
- release means none of them. It is told **before** that answer runs, so what the grab
537
- put up comes down at the moment the hand lets go, while still knowing whether
538
- something is on its way.
539
-
540
- Like `grab`, it **reports, it does not ask**, and it is not an interaction on its
541
- own: a moment of a drag needs a drag to happen in, and a dev warning says so.
436
+ `outcome` is which one is about to answer — `"move"`, `"reorder"`, `"land"`,
437
+ `"toss"`, `"leave"` — or `null` when the release means none of them. It is told
438
+ **before** that answer runs, so what the grab put up comes down the moment the
439
+ hand lets go, while still knowing whether something is on its way. Like `grab`,
440
+ it needs a drag to happen in, and a dev warning says so.
542
441
 
543
442
  ### The hand pulls and nothing follows: `refuse`
544
443
 
545
444
  Something that can be carried is not always free to be: a court whose place on the
546
445
  plan is settled, a marker pinned by whoever owns it. Taking the interaction away —
547
- `move: false` — makes the element **deaf** rather than locked. The press is then
548
- nobody's, so whatever it stands on answers it (the surface pans under an object the
549
- hand was aiming at), and the pull is told nothing at all — and a thing that does not
550
- move and says nothing reads as a screen that is broken, so the hand insists.
446
+ `move: false` — makes the element **deaf** rather than locked: the press is
447
+ nobody's, so whatever it stands on answers it (the surface pans under an object
448
+ the hand was aiming at), and the pull is told nothing — a thing that does not move
449
+ and says nothing reads as a broken screen, so the hand insists.
551
450
 
552
451
  ```jsx
553
452
  <Court
@@ -563,44 +462,50 @@ move and says nothing reads as a screen that is broken, so the hand insists.
563
462
  />
564
463
  ```
565
464
 
566
- So the interaction stays declared and says `"refuse"` in place of what it does. The
567
- threshold is the same one (a mouse travelling, a finger holding still, the first
568
- pixel inside a `data-drag-on-contact`), and at the instant the grab would have been
569
- acquired there is none: nothing translates, no copy is made, no release is
570
- answered. `refuse` is that instant, and the one where feedback is expected.
571
-
572
- **It walks no axis, so it takes none.** Everything that reads what a drag source
573
- walks to know what is left for itself — a box that travels, a surface that pans —
574
- steps over an element that is refusing: a swipe starting on a locked row is the
575
- row of slides' swipe, a drag starting on a pinned court pans the plan. A thing
576
- that cannot be taken hold of is exactly the one a hand rests on without thinking,
577
- and a surface with a dead zone the size of an object in the middle of it is wrong
578
- every time. So `move: "refuse"` really is `move: false` plus a word to the hand.
579
-
580
- **The press itself stays the element's**, and is settled there like any other
581
- gesture settles one: the pointer is taken, so a `longpress` declared beside the
582
- drag does not answer a hundred milliseconds later, and the click the release
583
- leaves behind is swallowed. What is locked behaves like what is not, up to the
584
- moment it says no. The exception is a box declaring `pan`/`zoom`, the one thing
585
- that takes a press whole and in every direction: there the surface keeps it, and
586
- the refusal is told without taking anything — no pointer, no click, nothing
587
- prevented.
588
-
589
- One outcome refusing refuses the whole gesture — the five answer one carry, and
590
- something that must not be carried has none of them. Like `grab` and `release`,
591
- `refuse` **reports, it does not ask**, and it is not an interaction on its own.
592
- Its detail is `{ pointerType }` beside the press (`event`), and no `gestureInfo`
593
- because there was no gesture, and what feedback wants to know is which hand asked
594
- — a vibration for a finger, nothing extra for a mouse whose cursor has already
595
- said it.
465
+ 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.
473
+
474
+ **It walks no axis, so it takes none.** Whatever reads what a drag source walks
475
+ to know what is left for itself — a box that travels, a surface that pans — steps
476
+ over an element that is refusing: a swipe starting on a locked row is the row of
477
+ slides' swipe, a drag starting on a pinned court pans the plan. A thing that
478
+ cannot be taken hold of is exactly the one a hand rests on without thinking, and
479
+ 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:
482
+
483
+ **The press itself stays the element's**, settled there like any gesture settles
484
+ 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.
490
+
491
+ ### A press made elsewhere: `--navi-grab`
492
+
493
+ A hold opens a popup, and something in it is what the hand meant to take:
494
+ `triggerNaviCommand(element, "--navi-grab", openEvent)` hands the press still
495
+ down to that element (or the drag source around it), so the finger carries it
496
+ without lifting and pressing again. It brings **a copy only**, to the finger,
497
+ once the popup has settled: `move` and `moving` carry nothing there (a dev
498
+ warning says so), and let go of before it has travelled — the hold only meant to
499
+ open the popup — the copy goes back and nothing is answered. Its interactions
500
+ are chained to that request rather than to a press on the element, so
501
+ `event.detail.event` is the request: reach the `pointerdown` with
502
+ `findEvent(event, "pointerdown")`.
596
503
 
597
504
  ### Dressing the clone
598
505
 
599
- What the pointer carries is a copy, and a copy of a transparent element is
600
- invisible — an element has no background unless something gave it one, and a row
601
- usually gets its own from the list around it, which the copy has left. So the
602
- clone's look is the page's to declare, through the attributes the gesture puts on
603
- it:
506
+ A copy of a transparent element is invisible — a row usually gets its background
507
+ from the list around it, which the copy has left. So the clone's look is the
508
+ page's to declare, through the attributes the gesture puts on it:
604
509
 
605
510
  | Attribute | On |
606
511
  | ------------------------- | ---------------------------------------------------- |
@@ -615,17 +520,19 @@ it:
615
520
  }
616
521
  ```
617
522
 
618
- Reusing the item's own class is the point: the copy is that item, so it is styled
619
- as that item plus whatever being carried changes.
523
+ Reusing the item's own class is the point: the copy is that item, styled as that
524
+ item plus whatever being carried changes.
620
525
 
621
526
  **Which is also the trap, for anything positioned on a board.** The copy is a
622
- deep clone of the element put in a carrier box, so a geometry written in the style
623
- attribute comes with it. navi takes back where it stands (`position`, `inset`,
624
- `margin` and `translate` are reset on the copy) but not its size —
625
- `width: calc(50% - 2 * var(--gap))` then means half of the carrier instead of
626
- half of the board, and the piece is carried at the wrong size. Put what a piece
627
- LOOKS like in a class and leave only which place it is inline (two custom
628
- properties will do), then let it fill its carrier:
527
+ 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:
629
536
 
630
537
  ```css
631
538
  [navi-drag-clone-wrapper] .piece {
@@ -634,24 +541,18 @@ properties will do), then let it fill its carrier:
634
541
  }
635
542
  ```
636
543
 
637
- Said of what is inside the wrapper rather than of `[navi-drag-clone]` itself,
638
- because the copy loses that mark as it lands — that is how it drops its lift for
639
- the transition — and it has to keep its size all the way down. The copy is a real element in the
640
- page, in the top layer, and everything about its look is reachable from CSS —
641
- including these, read off the dragged element so a whole list or a single item can
642
- answer:
544
+ Read off the dragged element, so a whole list or a single item can answer:
643
545
 
644
546
  | Variable | What it changes |
645
547
  | --------------------- | ------------------------------------------------------------- |
646
548
  | `--drag-clone-shadow` | what being lifted casts; `none` for something that flies flat |
647
549
  | `--drag-clone-scale` | how much bigger it gets once picked up; `1` to keep its size |
648
550
 
649
- **What stays behind is the source, not a hole.** The original is never taken out of
650
- the page — it keeps its place in the layout and wears `navi-drag-clone-source`,
651
- which only makes it `visibility: hidden`. So a mark left where the thing was — an
652
- imprint, a dashed outline, the shape a note was pinned on — is drawn ON that
653
- element and not next to it, and its parts have to say `visibility: visible` to come
654
- back from the hidden source:
551
+ **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:
655
556
 
656
557
  ```css
657
558
  .paper[navi-drag-clone-source]::after {
@@ -664,17 +565,6 @@ back from the hidden source:
664
565
  }
665
566
  ```
666
567
 
667
- It stays until the answer settles, which is what makes it say where the thing left
668
- from for as long as the question is open — and if the answer refuses, the copy comes
669
- back to it.
670
-
671
- `data-drag-axis` says which axes the drag walks, and its default is not the same
672
- for every outcome: `reorder` alone walks the list (`y`; a list that runs sideways
673
- says `data-drag-axis="x"`), while a `move` goes wherever it is put, a `land` wherever the board has
674
- places, a `toss` wherever it was thrown and a `leave` out by whichever edge (`xy`).
675
- `data-drag-delay`,
676
- `data-drag-slop`, `data-drag-threshold` tune when the press becomes a grab.
677
-
678
568
  ### What says a thing can be picked up
679
569
 
680
570
  Almost nothing, on purpose. A **handle** (`data-drag-handle`) exists only to drag,
@@ -686,8 +576,8 @@ text inside cannot be selected either — a finger is another matter, see below)
686
576
 
687
577
  So on a board where a piece is also clickable, the cursor is already spoken for and
688
578
  the affordance has to be said in the piece itself — a grip mark in a corner, a
689
- shadow appearing under the pointer, a handle. It is worth deciding, not defaulting:
690
- a board one may drag on is worth nothing if nobody tries.
579
+ shadow appearing under the pointer, a handle. Decide it rather than default it: a
580
+ board one may drag on is worth nothing if nobody tries.
691
581
 
692
582
  ### The text inside: `user-select: none`
693
583
 
@@ -711,9 +601,9 @@ a stylesheet, and it has to be true before the press:
711
601
 
712
602
  **Most of the time that is what you want.** What can be picked up carries a
713
603
  label rather than a text to read — a token, a row, a card one moves — and the
714
- press is there for the drag: nobody selects the word inside a thing they are
715
- carrying. Keep the selection where the text IS the point (a note one copies from)
716
- and give that one a `data-drag-handle`: the grip drags, the text stays text.
604
+ press is there for the drag. Keep the selection where the text IS the point (a
605
+ note one copies from) and give that one a `data-drag-handle`: the grip drags, the
606
+ text stays text.
717
607
 
718
608
  navi says it on its own in one place only, inside `[data-drag-on-contact]`, where
719
609
  there is no wait left to answer the finger with.
@@ -721,42 +611,49 @@ there is no wait left to answer the finger with.
721
611
  ## A gesture whose product is a value
722
612
 
723
613
  `move`, `reorder`, `land`, `toss` and `leave` answer the same question — where did
724
- the element end up — because all five carry it. A rotation does not: what comes out
725
- of it is an angle, and the handle that produced it stays exactly where it is. Same
726
- for a scale, or a sun dragged around a plan to set the hour.
614
+ the element end up. A rotation does not: what comes out of it is an angle, and
615
+ the handle that produced it stays exactly where it is. Same for a scale, or a sun
616
+ dragged around a plan to set the hour.
727
617
 
728
- What navi names is never the value: it does not know that these pixels are an
618
+ What navi names is never the value — it does not know that these pixels are an
729
619
  angle, that the angle snaps to the neighbouring court, or where the result is
730
- kept. What it names is the **arbitration** — a press that could have been a tap, a
731
- scroll, a page travelling, the surface underneath — and once that is settled it
732
- hands the numbers over. `moving` is that for something carried (the deltas from the
733
- grab, every frame, nothing translated), `pan` and `zoom` for a surface under the
734
- hand ([pan_zoom.md](./pan_zoom.md)). A value gesture written on either of those two shapes is `interactions`
735
- work, and the machinery below is not needed for it.
736
-
737
- What is left to it is a gesture whose SHAPE is none of navi's: it does not begin on
738
- an element that could be carried, or on a surface — it begins wherever the
739
- application says, on its own rules. Then navi hands over the machinery instead and
740
- leaves the paint alone:
620
+ kept — but the **arbitration**: a press that could have been a tap, a scroll, a
621
+ page travelling, the surface underneath. Once that is settled it hands the
622
+ numbers over. **A value computed from how far a handle was taken is `moving`**:
623
+ the deltas from the grab, every frame, nothing translated, and `move` beside it
624
+ when the release commits something. A value read off a surface is `pan` and
625
+ `zoom` ([pan_zoom.md](./pan_zoom.md)). Both are `interactions` work.
626
+
627
+ What is left is a gesture whose SHAPE is none of navi's: it does not begin on an
628
+ element that could be carried, or on a surface — it begins wherever the
629
+ application says, on its own rules. Then navi hands over the machinery and leaves
630
+ the paint alone; the options are in the JSDoc of `dragAfterIntent`,
631
+ `markDragSource` and `createDragGestureController`:
741
632
 
742
633
  ```js
743
- import { createDragGestureController, dragAfterIntent } from "@jsenv/navi";
634
+ import {
635
+ createDragGestureController,
636
+ dragAfterIntent,
637
+ markDragSource,
638
+ } from "@jsenv/navi";
639
+
640
+ // At mount, not in the pointerdown.
641
+ const unmarkDragSource = markDragSource(element, "xy");
744
642
 
745
643
  const onPointerDown = (pointerDownEvent) => {
746
- // Read now: the callback below runs once the intent shows, after dispatch,
747
- // when `currentTarget` is null.
748
- const element = pointerDownEvent.currentTarget;
644
+ // `element`, not `pointerDownEvent.currentTarget`: the callback runs once the
645
+ // intent shows, after dispatch, when `currentTarget` is null.
749
646
  dragAfterIntent(pointerDownEvent, () => {
750
647
  const controller = createDragGestureController({
751
648
  onDrag: (gestureInfo) => {
752
649
  const { xDelta, yDelta } = gestureInfo.layout;
753
- angleSignal.value = snapToNeighbours(angleFromDelta(xDelta, yDelta));
650
+ valueSignal.value = valueFrom(xDelta, yDelta);
754
651
  },
755
652
  onRelease: (gestureInfo) => {
756
653
  if (gestureInfo.cancelled) {
757
654
  return;
758
655
  }
759
- COURT.PUT.run({ angle: angleSignal.peek() });
656
+ commit(valueSignal.peek());
760
657
  },
761
658
  });
762
659
  return controller.grabViaPointer(pointerDownEvent, { element });
@@ -764,40 +661,39 @@ const onPointerDown = (pointerDownEvent) => {
764
661
  };
765
662
  ```
766
663
 
767
- An element that ends up somewhere is NOT this: that one is `move` — or `land` when
768
- what it ends up on is a surface and a copy is what travels — and doing it by hand
769
- gives up the constraint, the commit and the way back when the answer refuses.
770
-
771
- Three things come with the machinery, and they are the reason not to write it again:
772
-
773
- - **When the press becomes a drag** is `dragAfterIntent`, and the answer is not one
774
- policy but three: a `data-drag-handle` exists only to drag, so it takes the
775
- gesture on contact; a mouse resolves it by distance; a finger resolves it by
776
- TIME, because travel is exactly what a scroll looks like. One timer for every
777
- pointer makes the mouse wait for something it never had to prove.
778
- - **A touch has to be refusable before it is refused.** `touch-action` must be
779
- non-`auto` when the finger LANDS: after that the touch is on the compositor's
780
- fast path, every `preventDefault` is an intervention, and on Android the scroll
781
- runs away with the object. `markDragSource(element, axes)` says it from a
782
- stylesheet, on the source itself — which is how what surrounds it keeps
783
- scrolling. A blanket `touch-action: none` on the container buys the same drag by
784
- taking the pan away, and the pan then has to be written by hand too.
664
+ An element that ends up somewhere is NOT this: that one is `move` — or `land`
665
+ 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.
785
679
  - **A capture that goes was not necessarily given back.** `lostpointercapture`
786
- reads the same whether the gesture handed the pointer over or the browser dropped
787
- it mid-drag, which it does more often than the specification suggests. The loop
788
- tells the two apart, and `gestureInfo.cancelled` is where it comes out: a release
789
- nobody asked for must commit nothing.
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.
790
684
 
791
- A gesture driven this way is outside the registry, so it says so itself to whatever
792
- travels above it: `data-no-drag-travel` (see `docs/drag_to_travel.md`).
685
+ A gesture driven this way is outside the registry, so it says so itself to
686
+ whatever travels above it: `data-no-drag-travel` (see
687
+ [drag_to_travel.md](./drag_to_travel.md#a-navi-component-that-reads-the-pointer-marks-itself)).
793
688
 
794
689
  ## Reference
795
690
 
796
- - `src/control/interaction/interaction_drag.js` — `move`, `reorder`, `land`,
797
- `toss`, `leave` and the `grab`/`release`/`refuse` moments.
798
- - `@jsenv/dom` — `src/interaction/drag/drag_gesture.js` (the loop, its options
799
- and what `gestureInfo` holds) and `src/interaction/drag/drag_after_intent.js`
800
- (when a press becomes a drag, and what a source says in the stylesheet).
691
+ - `src/control/interaction/interaction_drag.js` — the outcomes, `moving`, the
692
+ `grab`/`release`/`refuse` moments and `--navi-grab`.
693
+ - `@jsenv/dom` — `src/interaction/drag/drag_to.js` (`startDragTo`,
694
+ `refuseDragTo`), `drag_gesture.js` (the loop and what `gestureInfo` holds),
695
+ `drag_after_intent.js` (when a press becomes a drag, and what a source says in
696
+ the stylesheet).
801
697
  - `src/control/demos/38_interactions_demo.html` — a board whose places are
802
698
  zones and the same board whose places are the pieces.
803
699
  - `src/control/demos/integration/5_plan_editor_demo.html` — a place that is a