@jsenv/navi 0.29.193 → 0.29.195

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.
@@ -227,7 +227,7 @@ outside it.
227
227
  A drag reads the same press a travel does and holds the pointer from it, so the
228
228
  two share a finger exactly as two travelling boxes do: what is picked up says
229
229
  which axes it walks (`data-drag-source`, written from `data-drag-axis` by
230
- `interactions={{ move, reorder, land, toss }}` — see `docs/interactions.md`), and
230
+ `interactions={{ move, reorder, land, toss, leave }}` — see `docs/interactions.md`), and
231
231
  the box above keeps what is left. A list reordered along its own line inside a
232
232
  row of slides swiped sideways: both gestures live, and neither had to be told
233
233
  about the other.
@@ -565,7 +565,7 @@ outside — and will not find out until they watch a page leave under their
565
565
  finger. The component knows, so the component says it.
566
566
 
567
567
  _Currently marked: the wheel viewport, the table resize handles, the cells of a
568
- table whose columns can be dragged._
568
+ table whose columns can be dragged, a surface declaring `pan` or `zoom`._
569
569
 
570
570
  ## The two consumers that travel between screens
571
571
 
@@ -40,9 +40,13 @@ one — `Box`, `List.Item`, `Button`, `Link`, the field components. Its keys are
40
40
  />
41
41
  ```
42
42
 
43
- `action` is untouched by this and keeps its own wiring — a click on a button, a
44
- change on a field. `interactions` is the other half: everything that is not that
45
- natural one.
43
+ `action` is a control's prop and is untouched by this: a control keeps its own
44
+ wiring — a click on a button, a change on a field — and `interactions` is the
45
+ other half, everything that is not that natural one. A plain `Box` has no such
46
+ wiring: it does nothing with `action` (dev warns), and a click on it is declared
47
+ like any other interaction, `interactions={{ click: onSelect }}`. The click the
48
+ browser fires after a drag is already suppressed, so `click` sits next to `move`
49
+ or `grab` without fighting them.
46
50
 
47
51
  ### The three values
48
52
 
@@ -62,8 +66,9 @@ condition: `{ swipe_right: canArchive && archive }`.
62
66
  | `mousedown` `mouseup` `click` `dblclick` `contextmenu` | the browser's own events |
63
67
  | `swipe_left` `swipe_right` `swipe_up` `swipe_down` | a press that travels |
64
68
  | `longpress` | a press held still |
65
- | `move` `reorder` `land` `toss` | the element carried, and what letting go means |
69
+ | `move` `reorder` `land` `toss` `leave` | the element carried, and what letting go means |
66
70
  | `grab` | the instant a drag takes hold of it |
71
+ | `pan` `zoom` | a surface under the hand, or under a wheel |
67
72
  | `"keyboard:<shortcut>"` | keys, e.g. `"keyboard:ctrl+backspace"` |
68
73
 
69
74
  A name nothing knows how to detect produces a dev warning naming the detectors
@@ -156,16 +161,19 @@ comes back once it settles — a failure leaves the row in place so it can be tr
156
161
  again. What a success does to the element is yours (a list that redemands its
157
162
  rows, a row that leaves): navi does not make it disappear.
158
163
 
159
- ## Carrying something: `move`, `reorder`, `land`, `toss`
164
+ ## Carrying something: `move`, `reorder`, `land`, `toss`, `leave`
160
165
 
161
- All four are the same gesture — the element is picked up and carried — and what
166
+ All five are the same gesture — the element is picked up and carried — and what
162
167
  differs is the release. One detector reads them all, because it is one press.
163
168
 
164
- `toss` **combines** with either of the two others: dropped on another item the
165
- element changes places, thrown far and fast it is gotten rid of. `move`,
166
- `reorder` and `land` do **not** combine with each other — an element either goes
167
- where it is put, takes a place in a list, or comes down on a place, and one
168
- release cannot mean two of those (a dev warning says so).
169
+ `toss` and `leave` each **combine** with `reorder` and with `land`: dropped on
170
+ another item the element changes places, thrown far and fast it is gotten rid of,
171
+ let go of away from every place it leaves. `leave` combines with `move` as well.
172
+ `toss` does **not** combine with `move`, and neither do `reorder` and `land` with
173
+ each other — one release cannot mean two of those. Declared together, the
174
+ copy-carrying one wins and `move` is never answered — the element itself never
175
+ travels, and a release that is not the other outcome means nothing at all (a dev
176
+ warning says so).
169
177
 
170
178
  `move` carries the element ITSELF and leaves it where it was put; the others
171
179
  carry a copy and put the original back. That is the same difference said in layout
@@ -187,11 +195,22 @@ be a scroll container at all (`overflow` anything but `visible`), since there is
187
195
  nothing else for "inside" to mean. A `move` whose answer rejects travels back, because a
188
196
  place the application would not accept must not stay on screen as if it had.
189
197
 
190
- **Declaring `toss` frees the area by itself.** What is dragged is otherwise kept
198
+ **Where the position is kept is the answer's.** An element drawn from state —
199
+ `left`/`top` computed from a position the application holds — is redrawn by the
200
+ handler above, and from then on its layout owns the position: navi sees the
201
+ element drawn elsewhere while the answer was given and lets go of its own
202
+ translate, so the thing does not land twice as far as the hand went. A handler
203
+ that draws nothing (a token on a free canvas) leaves the position to the element,
204
+ where it is baked in. Nothing to declare either way — but a handler whose draw
205
+ comes later than its answer has to return the promise of that draw.
206
+
207
+ **A copy that can be thrown frees its own area.** What is dragged is otherwise kept
191
208
  inside its scroll area — right for a reorder, since a row belongs to its list, and
192
209
  fatal for a throw: the copy hits the edge of the list, no distance is ever covered,
193
- so no throw can happen and no sideways movement is even visible. So the two
194
- together let it leave.
210
+ so no throw can happen and no sideways movement is even visible. So `toss` lifts
211
+ that constraint for the copy it carries, and `leave` lifts it for whatever it is
212
+ declared on — a thing that can be let go of outside has to be able to get there.
213
+ Neither is a way to free a plain `move`, which says `data-drag-free`.
195
214
 
196
215
  ```jsx
197
216
  <List.Item
@@ -211,7 +230,7 @@ together let it leave.
211
230
  ```
212
231
 
213
232
  The gesture is `startDragTo`'s, whole: `move` carries the element itself, the
214
- other two carry a copy above the page while the original keeps its place, with a
233
+ others carry a copy above the page while the original keeps its place, with a
215
234
  drop hint, drop targets found by intersection, no-op drops filtered out, and the
216
235
  flight of a thrown copy plus its return when the answer refuses. Only what the
217
236
  declared outcomes need runs — no copy for a move, no hint for something
@@ -244,36 +263,28 @@ name what moves.
244
263
  | `data-drag-delay` `data-drag-slop` `data-drag-threshold` | when the press becomes a grab |
245
264
  | `data-drag-on-contact` | a finger may drag by travelling too |
246
265
  | `data-toss-distance` `data-toss-speed` | how far and how fast counts as a throw |
247
- | `data-toss-by="throw"\|"release-outside"` | how a toss is made here |
248
266
  | `data-drop-container` | where the places are looked for |
249
267
 
250
- ### How a toss is made: `data-toss-by`
251
-
252
- `toss` names the outcome — the thing is gotten rid of — and a hand has two ways of
253
- saying it, each right where the other is wrong:
254
-
255
- - **`throw`** (the default): far **and** fast — that pair is what a flick is, and
256
- it is asked for together because one without the other is moving something while
257
- hesitating. A list's gesture. It is judged before any landing: a row sent across
258
- the screen has not asked to swap places with whatever it flew over.
259
- - **`release-outside`**: let go with no place under it. Dragging a marker off the plan it
260
- sits on and letting go is slow and deliberate — a surface's gesture, and the only
261
- one it wants, because on a plan a fast drag that ends ON it has not asked for the
262
- thing to go.
268
+ ### Let go of away from every place: `leave`
263
269
 
264
- The same `toss` either way, with the same flight off the screen and the same
265
- return if the answer rejects. Both at once is
266
- `data-toss-by="throw release-outside"`.
270
+ A throw is a **gesture**: far and fast, the flick that gets rid of a row, judged
271
+ before any landing. A release outside is a **place**: the hand let go with nothing
272
+ under the thing, judged after a landing was looked for. They share the outcome an
273
+ application usually attaches to them and nothing else — so `toss` is the throw,
274
+ `leave` is the release outside, and neither reads the other's rules. There is no
275
+ speed to a release; a fast drag across a plan that ends ON it has not asked for the
276
+ thing to go, and a row pulled sideways out of its list and let go is a row put
277
+ back, not a row deleted — a list declares `toss`, a surface declares `leave`.
267
278
 
268
279
  ```jsx
269
280
  <div data-drop-container>
270
- <Plan id="plan" data-droppable data-toss-by="release-outside">
281
+ <Plan id="plan" data-droppable>
271
282
  {markers.map((marker) => (
272
283
  <Marker
273
284
  id={marker.id}
274
285
  interactions={{
275
286
  land: (event) => moveTo(marker.id, event.detail),
276
- toss: () => remove(marker.id),
287
+ leave: () => remove(marker.id),
277
288
  }}
278
289
  />
279
290
  ))}
@@ -281,11 +292,36 @@ return if the answer rejects. Both at once is
281
292
  </div>
282
293
  ```
283
294
 
284
- `release-outside` is never the default because the same release means the
285
- opposite on a list: a row pulled sideways out of it and let go is a row put back, not a row
286
- deleted. And it needs places to be outside OF — declared next to `toss` alone,
287
- with nothing that can receive the thing, every release is outside and a dev
288
- warning says so.
295
+ `leave` combines with every other outcome. Beside `land` or `reorder`, "outside" is
296
+ away from every place. Beside `move` — the element itself travels, and nothing is a
297
+ place — it is outside the surface the element stands in: the nearest
298
+ `data-droppable` ancestor, or, without one, what can be seen of the scroll
299
+ container (a dev warning says which). Either way it is judged on the element's
300
+ box no longer overlapping it, not on the pointer, which is still well inside the
301
+ frame when a small marker has just left it.
302
+
303
+ ```jsx
304
+ <Plan data-droppable>
305
+ <Marker
306
+ interactions={{
307
+ move: (event) => remember(event.detail.x, event.detail.y),
308
+ leave: () => remove(marker.id),
309
+ }}
310
+ />
311
+ </Plan>
312
+ ```
313
+
314
+ Its detail is `toss`'s — `{ id, x, y }`, the distance travelled being what an exit
315
+ is animated with. Picked up and put straight back down stays a cancel: it has to
316
+ have gone somewhere to be away from anything.
317
+
318
+ What the thing does while the answer is asked follows what was carried. A copy
319
+ fades where it was let go of; the element itself stays where the hand put it. A
320
+ resolve takes the copy away and lets go of the element's position — the
321
+ application has removed the thing, or drawn it where it goes back to (the address
322
+ point returns to where the geocoder put it) — and a reject brings either back, as
323
+ a refused `move` does. A surface that clips its overflow clips the element on its
324
+ way out; the copy a `land` carries lives in the top layer and does not.
289
325
 
290
326
  ### A finger that does not have to wait: `data-drag-on-contact`
291
327
 
@@ -355,7 +391,8 @@ carried does not stand among the places — a palette BESIDE the surface it fill
355
391
  marker drawn INSIDE the surface it can be put back on — say what holds both with
356
392
  `data-drop-container`. It holds the places rather than being one, so it goes on an
357
393
  ancestor of them: a surface that is itself the place is never found from inside
358
- itself.
394
+ itself. Missed, nothing lands and nothing says why — so the first press on a
395
+ `land` with no place in reach warns, and names the surface it is standing on.
359
396
 
360
397
  ```jsx
361
398
  <div data-drop-container>
@@ -512,7 +549,7 @@ thing it copies, and dressed by where that thing stands.
512
549
 
513
550
  ### Saying the grab is acquired: `grab`
514
551
 
515
- The three above answer the **release**. Between the press and the release there is
552
+ The interactions above answer the **release**. Between the press and the release there is
516
553
  one instant that counts for the hand: the one where the object stops being pressed
517
554
  and starts being held. `grab` is that instant — the same one whichever way the drag
518
555
  was entered, a finger held still or a mouse travelled a few pixels.
@@ -536,8 +573,8 @@ Nothing here is about vibration: a sound, a class, a measure are the same moment
536
573
 
537
574
  `grab` **reports, it does not ask**: what it returns is not waited on, and
538
575
  preventing its event does not call the gesture off. And it is not an interaction on
539
- its own — declared without `move`, `reorder` or `toss` there is no gesture for it to
540
- be the beginning of, and a dev warning says so. Its detail carries `pointerType` and
576
+ its own — declared without one of the five above there is no gesture for it to be
577
+ the beginning of, and a dev warning says so. Its detail carries `pointerType` and
541
578
  the `gestureInfo`.
542
579
 
543
580
  A `longpress` needs none of this: it already happens at the moment the hold is
@@ -620,7 +657,8 @@ back to it.
620
657
  `data-drag-axis` says which axes the drag walks, and its default is not the same
621
658
  for every outcome: `reorder` alone walks the list (`y`, or `x` for a list that runs
622
659
  sideways), while a `move` goes wherever it is put, a `land` wherever the board has
623
- places and a `toss` wherever it was thrown (`xy`). `data-drag-delay`,
660
+ places, a `toss` wherever it was thrown and a `leave` out by whichever edge (`xy`).
661
+ `data-drag-delay`,
624
662
  `data-drag-slop`, `data-drag-threshold` tune when the press becomes a grab.
625
663
 
626
664
  ### An affordance inside somebody else's box: `selfInteractions`
@@ -873,19 +911,63 @@ container above it does not take the gesture:
873
911
  `docs/drag_to_travel.md`). navi's own swipes do the equivalent with
874
912
  `data-travel-by-drag`.
875
913
 
914
+ ## A surface under the hand: `pan`, `zoom`
915
+
916
+ A plan drawn over an aerial photo, a map, a floor: one box the hand drags to look
917
+ elsewhere on, pinches or rolls a wheel over to look closer at, with things carried
918
+ across it that must not drag the surface along.
919
+
920
+ ```jsx
921
+ <Box
922
+ interactions={{
923
+ pan: (event) => moveCenterBy(event.detail), // { x, y } since the last one
924
+ zoom: (event) => zoomBy(event.detail), // { factor, x, y }
925
+ }}
926
+ >
927
+ {markers.map((marker) => (
928
+ <Marker interactions={{ move: (event) => place(marker, event.detail) }} />
929
+ ))}
930
+ </Box>
931
+ ```
932
+
933
+ Both are a **stream**, reported on every frame: `pan` says how far the hand has
934
+ moved since the previous `pan`, in px; `zoom` by what factor (above 1 is in) and
935
+ around which point of the surface, measured inside its border — the point between
936
+ the fingers, or under the wheel. Two fingers are one gesture, the point between
937
+ them panning and the distance between them zooming, and a finger lifting
938
+ re-anchors on what is left. What a pixel of pan means in your coordinates, and
939
+ whether the zoom is continuous or stepped, is yours: the numbers are the numbers.
940
+
941
+ What navi holds is what has to be settled **before** the press: `touch-action` on
942
+ the surface, said from a stylesheet because a browser decides what a touch may do
943
+ when it lands; the pan stepping back for what is carried across the surface (a
944
+ `move`, a handle, a field, a popover — the same list a travelling box steps back
945
+ for); the pinch not beginning as a pan under its first finger; the wheel and the
946
+ pinch writing one `zoom`; the capture, the pointer the browser drops, the click
947
+ the release leaves behind. A pointer pans only once it has travelled a few px
948
+ (`data-drag-threshold`), so a tap stays a tap and a `longpress` declared beside
949
+ `pan` still gets its hold.
950
+
951
+ Declared alone, `zoom` takes two fingers and the wheel and leaves one pointer to
952
+ whatever else reads it; `pan` alone leaves the wheel to the page.
953
+
876
954
  ## A gesture whose product is a value
877
955
 
878
- `move`, `reorder`, `land` and `toss` answer the same question — where did the
879
- element end up — because all four carry it. A rotation does not: what comes out of
956
+ `move`, `reorder`, `land`, `toss` and `leave` answer the same question — where did
957
+ the element end up — because all five carry it. A rotation does not: what comes out of
880
958
  it is an angle, and the handle that produced it stays exactly where it is. Same for
881
- a scale, a zoom, a plan panned under the finger.
959
+ a scale, or a sun dragged around a plan to set the hour.
882
960
 
883
961
  navi names none of those, and it is not an oversight: an interaction names an
884
962
  **outcome** — something that happened once, that can be told, refused, awaited.
885
963
  There is no outcome here, only a number read while the hand is still moving, and
886
964
  what to do with it (snap it to the neighbouring court, draw it, keep it in a
887
- signal) is knowledge navi does not have. So it hands over the machinery instead
888
- and leaves the paint alone:
965
+ signal) is knowledge navi does not have. `pan` and `zoom` above are the one
966
+ exception, and not for the number: a surface has an arbitration to settle before
967
+ the press — what it yields to, what a touch on it may do — and arbitration is
968
+ what `interactions` is for. A handle has none; it is the whole surface of its own
969
+ gesture. So for those navi hands over the machinery instead and leaves the paint
970
+ alone:
889
971
 
890
972
  ```js
891
973
  import { createDragGestureController, dragAfterIntent } from "@jsenv/navi";
@@ -988,7 +1070,9 @@ travels above it: `data-no-drag-travel` (see `docs/drag_to_travel.md`).
988
1070
  - `src/control/interaction/interaction_press.js` — swipes and holds, and what a
989
1071
  swipe writes on the element.
990
1072
  - `src/control/interaction/interaction_drag.js` — `move`, `reorder`, `land`,
991
- `toss` and the `grab` moment.
1073
+ `toss`, `leave` and the `grab` moment.
1074
+ - `src/control/interaction/interaction_surface.js` — `pan` and `zoom`, on
1075
+ `installPanZoom` from `@jsenv/dom`.
992
1076
  - `src/control/interaction/interaction_keyboard.js`,
993
1077
  `interaction_native.js` — the other two detectors.
994
1078
  - `@jsenv/dom` — `src/interaction/drag/drag_gesture.js` (the loop, its options and
@@ -996,7 +1080,8 @@ travels above it: `data-no-drag-travel` (see `docs/drag_to_travel.md`).
996
1080
  press becomes a drag, and what a source says in the stylesheet).
997
1081
  - `src/control/demos/38_interactions_demo.html` — every case above, plus a
998
1082
  mailbox, a board whose places are zones and the same board whose places are the
999
- pieces, and a custom gesture registered from the page.
1083
+ pieces, a surface panned and zoomed, and a custom gesture registered from the
1084
+ page.
1000
1085
  - `src/control/demos/integration/5_plan_editor_demo.html` — a place that is a
1001
1086
  surface: shapes dragged out of a bank onto a plan, moved on it, and dragged off
1002
- it to go.
1087
+ it to go; and an address point that travels itself (`move` + `leave`).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.29.193",
3
+ "version": "0.29.195",
4
4
  "type": "module",
5
5
  "description": "Library of components including navigation to create frontend applications",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "preact": "^11.0.0-beta.2"
35
35
  },
36
36
  "dependencies": {
37
- "@jsenv/dom": "0.17.47",
37
+ "@jsenv/dom": "0.17.48",
38
38
  "@jsenv/humanize": "1.8.1",
39
39
  "@jsenv/validity": "0.4.3"
40
40
  },