@jsenv/navi 0.29.60 → 0.29.62
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 +87 -16
- package/dist/jsenv_navi.js.map +6 -5
- package/docs/AI_INSTRUCTIONS.md +8 -0
- package/docs/actions.md +32 -0
- package/docs/drag_to_travel.md +68 -9
- package/docs/interactions.md +8 -0
- package/package.json +2 -2
package/docs/AI_INSTRUCTIONS.md
CHANGED
|
@@ -143,6 +143,14 @@ consistency across the app, not from any single call site.
|
|
|
143
143
|
Read it before reading the pointer by hand — who owns a press between nested
|
|
144
144
|
boxes, and what a touch may do, are decided before the first pixel moves and
|
|
145
145
|
cannot be got right from outside navi.
|
|
146
|
+
- `docs/drag_to_travel.md` — a pointer pushing a whole screen aside
|
|
147
|
+
(`SlideContainer`, `RouteTravel`) and a popup pushed back towards its edge:
|
|
148
|
+
what the gesture is, and above all who owns a press several boxes want — a
|
|
149
|
+
scroller with room left, a nested travelling box, something being carried, a
|
|
150
|
+
surface in the top layer, and the grip a docked popup narrows itself to. Read
|
|
151
|
+
it before putting anything that reads the pointer inside a box that travels,
|
|
152
|
+
and before wondering why a page moved under a gesture meant for what was in
|
|
153
|
+
it.
|
|
146
154
|
- `docs/MOBILE_LAYOUT_PITFALLS.md` — mobile-specific layout gotchas (viewport
|
|
147
155
|
units, virtual keyboard, safe areas).
|
|
148
156
|
- `docs/navigation.md` — how to build navigation: declaring routes
|
package/docs/actions.md
CHANGED
|
@@ -158,6 +158,38 @@ To merely REMEMBER the value rather than send it, neither is the answer: bind a
|
|
|
158
158
|
signal and drop the callback entirely — see
|
|
159
159
|
[control_value.md](./control_value.md).
|
|
160
160
|
|
|
161
|
+
## `uiAction` mirrors the state, it does not report a gesture
|
|
162
|
+
|
|
163
|
+
`uiAction` fires whenever the control's state changes, whoever changed it. The
|
|
164
|
+
user typing is one cause among several: a `value` prop coming back down after a
|
|
165
|
+
render, a popup control propagating its choice up to the picker holding it, a
|
|
166
|
+
group cascading a value into its children — all of them reach `uiAction` too, so
|
|
167
|
+
that a signal or a local variable listening to it never drifts out of sync.
|
|
168
|
+
Reading it as "the user did something" is the natural mistake.
|
|
169
|
+
|
|
170
|
+
The second argument says which one it was. Every event navi dispatches carries
|
|
171
|
+
the event that caused it, and `findEvent(event, type)` walks that chain back:
|
|
172
|
+
|
|
173
|
+
```jsx
|
|
174
|
+
<Picker
|
|
175
|
+
clearable
|
|
176
|
+
uiAction={(value, event) => {
|
|
177
|
+
if (findEvent(event, "navi_clear_ui_state")) {
|
|
178
|
+
// the clear cross was pressed — for this row that means "back to the
|
|
179
|
+
// profile level", not "empty"
|
|
180
|
+
draft.level = profile.level;
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
draft.level = value;
|
|
184
|
+
}}
|
|
185
|
+
/>
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Useful types to match on: `navi_clear_ui_state` (the clear cross, or a
|
|
189
|
+
`--navi-clear` command), `navi_reset_ui_state`, and the browser events at the
|
|
190
|
+
root of the chain (`click`, `keydown`, `input`) — a change no user gesture
|
|
191
|
+
caused has none of them.
|
|
192
|
+
|
|
161
193
|
## Reruns
|
|
162
194
|
|
|
163
195
|
Actions do not stay stale on their own: a resource's `POST` reruns the
|
package/docs/drag_to_travel.md
CHANGED
|
@@ -84,19 +84,27 @@ scrolling while a screen slides. Same word, other gesture.
|
|
|
84
84
|
|
|
85
85
|
## Who owns a gesture
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
Five things can claim a pointer that landed on a travelling box, and all five
|
|
88
88
|
are read before the box moves:
|
|
89
89
|
|
|
90
|
-
1. **What says so itself.** A field, a `contenteditable`,
|
|
91
|
-
`data-no-drag-travel`.
|
|
90
|
+
1. **What says so itself.** A field, a `contenteditable`, a dedicated drag
|
|
91
|
+
handle (`data-drag-handle`), or anything carrying `data-no-drag-travel`.
|
|
92
92
|
2. **A scroller in between with room left that way.** It keeps the gesture until
|
|
93
93
|
it has no room left, and only then hands the travel over — so a row that
|
|
94
94
|
scrolls sideways inside a page still scrolls sideways.
|
|
95
95
|
3. **Another travelling box in between.** The innermost one takes the axes it
|
|
96
96
|
walks, and leaves the ones it does not to whoever is above it.
|
|
97
|
-
4. **
|
|
97
|
+
4. **Something in between that is picked up and carried.** A row taken out of a
|
|
98
|
+
list, a card carried across a board: it takes the axes it is dragged on and
|
|
99
|
+
leaves the others — see [Something being carried inside a
|
|
100
|
+
box](#something-being-carried-inside-a-box).
|
|
101
|
+
5. **A surface in the top layer in between.** Nothing above it gets the gesture
|
|
98
102
|
at all — see [A surface in the top layer](#a-surface-in-the-top-layer).
|
|
99
103
|
|
|
104
|
+
And one thing narrows it from the other end: a popup that names a **grip** reads
|
|
105
|
+
the press only there — see [A popup pushed back the way it
|
|
106
|
+
came](#a-popup-pushed-back-the-way-it-came).
|
|
107
|
+
|
|
100
108
|
### Boxes inside boxes
|
|
101
109
|
|
|
102
110
|
A row of slides inside a page that walks between pages, a carousel inside a
|
|
@@ -117,6 +125,39 @@ last slide does not hand the gesture over mid-drag: it leans on its wall, the wa
|
|
|
117
125
|
it does when it is alone. Travelling the box around it means starting the gesture
|
|
118
126
|
outside it.
|
|
119
127
|
|
|
128
|
+
### Something being carried inside a box
|
|
129
|
+
|
|
130
|
+
A drag reads the same press a travel does and holds the pointer from it, so the
|
|
131
|
+
two share a finger exactly as two travelling boxes do: what is picked up says
|
|
132
|
+
which axes it walks (`data-drag-source`, written from `data-drag-axis` by
|
|
133
|
+
`interactions={{ move, reorder, land, toss }}` — see `docs/interactions.md`), and
|
|
134
|
+
the box above keeps what is left. A list reordered along its own line inside a
|
|
135
|
+
row of slides swiped sideways: both gestures live, and neither had to be told
|
|
136
|
+
about the other.
|
|
137
|
+
|
|
138
|
+
When the two want the same axes — a piece carried both ways inside a sheet
|
|
139
|
+
pushed down to close it — nothing is left and the press is the piece's, whole.
|
|
140
|
+
That is the right way round: the box above is a surface, and the thing in it is
|
|
141
|
+
what the hand came for.
|
|
142
|
+
|
|
143
|
+
The exception is a **dedicated handle** (`data-drag-handle`), which has no axis:
|
|
144
|
+
it is a place whose only purpose is to be taken hold of, from the first pixel,
|
|
145
|
+
so it takes the press outright.
|
|
146
|
+
|
|
147
|
+
### A popup pushed back the way it came
|
|
148
|
+
|
|
149
|
+
A `Dialog` docked to the bottom edge (`dockedOnSmallTouchScreen`) and a
|
|
150
|
+
`SidePanel` close by being pushed back the way they came in — a third consumer
|
|
151
|
+
of this same travel, `swipe_to_close.js`. A popup that names a **grip** reads the
|
|
152
|
+
press only there: for a `Dialog` that is its header, plus anything carrying
|
|
153
|
+
`data-swipe-grip`. Everything else it holds is content the finger came to operate
|
|
154
|
+
— a board a piece is dragged across, a map, a list — and a press there never
|
|
155
|
+
reaches the travel at all, whatever it is made of.
|
|
156
|
+
|
|
157
|
+
So a sheet with no header and nothing marked is not pushed down; it closes by
|
|
158
|
+
its own controls, the backdrop and Escape. A `SidePanel` names no grip and is
|
|
159
|
+
pushed from its whole surface, which suits a panel made of nothing else.
|
|
160
|
+
|
|
120
161
|
### A surface in the top layer
|
|
121
162
|
|
|
122
163
|
A popover, a modal `<dialog>`, an element gone fullscreen: it is written inside
|
|
@@ -298,6 +339,12 @@ Two things a travel in hand must never lose:
|
|
|
298
339
|
- **the hold belongs to a travel, not to the page.** Only the travel that took
|
|
299
340
|
it may give it back — and it must give it back even when it ends after
|
|
300
341
|
something else has replaced it, or the hold survives its owner;
|
|
342
|
+
- **a capture that goes while the pointer is still down was taken, not given.**
|
|
343
|
+
The ends a gesture has are the pointer going up and the pointer being
|
|
344
|
+
cancelled; a `lostpointercapture` before either means someone else asked for
|
|
345
|
+
the pointer (or the element it was held on left the document). What was being
|
|
346
|
+
carried goes back rather than landing wherever the hand happened to be, and a
|
|
347
|
+
travel comes home rather than committing;
|
|
301
348
|
- **a gesture must hear its own end wherever it is delivered.** A pointer can be
|
|
302
349
|
cancelled somewhere the box is not on the path (the document root, during a
|
|
303
350
|
transition): missed, the gesture never ends, and whatever it was holding stays
|
|
@@ -370,10 +417,17 @@ hold:
|
|
|
370
417
|
touch keeps being dispatched at the node it started on, and a travel may
|
|
371
418
|
replace the DOM under the finger (a page that travels navigates), after which
|
|
372
419
|
that node no longer passes through the box on its way up;
|
|
373
|
-
- the pointer is captured
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
420
|
+
- the pointer is captured on the BOX rather than on what the finger landed on,
|
|
421
|
+
for the same reason: what the caller does may take that target away, and a
|
|
422
|
+
capture whose element leaves the document is a capture the browser drops;
|
|
423
|
+
- and it is captured only once the travel has been ACCEPTED — not when the press
|
|
424
|
+
crossed its threshold. There is one capture per pointer for the whole document,
|
|
425
|
+
so taking it is taking it from whoever had it, who is then told the very thing
|
|
426
|
+
it is told when its own gesture ends. A travel that gives itself up one event
|
|
427
|
+
later (an axis this box does not walk, an `onStart` that refuses) would have
|
|
428
|
+
killed a gesture already carrying something. Until the capture is claimed the
|
|
429
|
+
moves are read from the window, filtered by pointer id, so nothing is missed
|
|
430
|
+
for not owning the pointer.
|
|
377
431
|
|
|
378
432
|
And the refusal has to be _listened for_ from the grab, even though it only
|
|
379
433
|
refuses later: whether a touchmove can be refused at all is decided when the
|
|
@@ -398,7 +452,12 @@ finger. The component knows, so the component says it.
|
|
|
398
452
|
_Currently marked: the wheel viewport, the table resize handles, the cells of a
|
|
399
453
|
table whose columns can be dragged._
|
|
400
454
|
|
|
401
|
-
## The two consumers
|
|
455
|
+
## The two consumers that travel between screens
|
|
456
|
+
|
|
457
|
+
A popup being pushed back towards its edge is a travel too, and it is the simple
|
|
458
|
+
one: one box, one direction, no neighbour to bring in (see [A popup pushed back
|
|
459
|
+
the way it came](#a-popup-pushed-back-the-way-it-came)). The two below carry
|
|
460
|
+
screens, and everything the rest of this file weighs is about them.
|
|
402
461
|
|
|
403
462
|
| | `SlideContainer` | `RouteTravel` |
|
|
404
463
|
| ----------------------- | ---------------------------------- | ---------------------------------- |
|
package/docs/interactions.md
CHANGED
|
@@ -623,6 +623,14 @@ container above it does not take the gesture:
|
|
|
623
623
|
|
|
624
624
|
## Things worth knowing before guessing
|
|
625
625
|
|
|
626
|
+
- **A drag says its axes to whoever else answers the press.** `data-drag-axis`
|
|
627
|
+
is written into the DOM as `data-drag-source`, and a box above that travels
|
|
628
|
+
under the same finger reads it before answering: a list reordered vertically
|
|
629
|
+
inside a row of slides swiped sideways leaves the sideways gesture alone, and a
|
|
630
|
+
piece carried both ways inside a bottom sheet takes the press whole. Nothing to
|
|
631
|
+
wire — see `docs/drag_to_travel.md`. A `Dialog` docked to the bottom edge goes
|
|
632
|
+
further and reads the press only on its header (plus anything carrying
|
|
633
|
+
`data-swipe-grip`), so its body is free whatever is in it.
|
|
626
634
|
- **A hold does not take the context menu.** Declaring `longpress` says what a
|
|
627
635
|
held finger does; a right click comes from the other button and keeps opening
|
|
628
636
|
the browser's menu. Declare `contextmenu` beside it to make the right click do
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsenv/navi",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.62",
|
|
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.20",
|
|
33
33
|
"@jsenv/humanize": "1.7.8",
|
|
34
34
|
"@jsenv/validity": "0.4.2"
|
|
35
35
|
},
|