@jsenv/navi 0.29.30 → 0.29.32
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 +184 -47
- package/dist/jsenv_navi.js.map +10 -10
- package/docs/control_group.md +51 -11
- package/docs/interactions.md +45 -8
- package/package.json +1 -1
package/docs/control_group.md
CHANGED
|
@@ -46,12 +46,15 @@ Live examples: `src/control/demos/15_group_demo.html`.
|
|
|
46
46
|
- **Corners**: the first member loses the radius on the side that joins, the
|
|
47
47
|
last one loses it on the other side, and any member in between loses all
|
|
48
48
|
four. A single member keeps its own radius — a group of one looks like the
|
|
49
|
-
control alone.
|
|
50
|
-
- **Overlap order**: the member under the pointer, and the member
|
|
51
|
-
focus,
|
|
52
|
-
Without it the border color
|
|
53
|
-
|
|
54
|
-
|
|
49
|
+
control alone. The ask is made twice, in two forms — see below.
|
|
50
|
+
- **Overlap order**: the member under the pointer, and the member showing a
|
|
51
|
+
focus ring, paint above their neighbours (`position: relative` plus
|
|
52
|
+
`--navi-z-index-control-hovered` / `-focused`). Without it the border color
|
|
53
|
+
change and the focus ring of the active member would be sliced by whichever
|
|
54
|
+
neighbour is painted after it. The focused member is matched whether it wears
|
|
55
|
+
`data-focus-visible` itself or merely contains it — a control that wraps a
|
|
56
|
+
real input (`Picker`, `Spin`) draws the ring on its own frame while the
|
|
57
|
+
keyboard is held inside. There is deliberately no `isolation: isolate` — see
|
|
55
58
|
[z_index.md](./z_index.md).
|
|
56
59
|
|
|
57
60
|
Nothing else: a group does not restyle its members, does not impose a size,
|
|
@@ -59,14 +62,21 @@ and takes any `Box` prop for its own layout.
|
|
|
59
62
|
|
|
60
63
|
## Writing a control that belongs in a group
|
|
61
64
|
|
|
62
|
-
A group
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
A group never writes a selector that reaches inside a member — a member's
|
|
66
|
+
subtree holds more than the member (a `Picker` renders its popup inside
|
|
67
|
+
itself, not in a portal; a control carries buttons of its own, like the clear
|
|
68
|
+
cross in a slot), and a rule matching "some descendant" finds all of them. It
|
|
69
|
+
asks for a square corner in two forms instead, and a control answers with
|
|
70
|
+
whichever fits.
|
|
71
|
+
|
|
72
|
+
**The property, on the member itself.** A control declares the radius of its
|
|
73
|
+
frame on its own root, and whatever inner element paints that frame takes
|
|
74
|
+
`border-radius: inherit`. The group sets the property on the root; the frame
|
|
75
|
+
follows.
|
|
66
76
|
|
|
67
77
|
```css
|
|
68
78
|
.navi_thing {
|
|
69
|
-
/*
|
|
79
|
+
/* Declared here even though the box below is what draws it */
|
|
70
80
|
border-radius: var(--thing-border-radius);
|
|
71
81
|
|
|
72
82
|
.navi_thing_box {
|
|
@@ -76,6 +86,36 @@ paints the frame takes `border-radius: inherit`:
|
|
|
76
86
|
}
|
|
77
87
|
```
|
|
78
88
|
|
|
89
|
+
**The custom property, which travels.** A member is not always the control
|
|
90
|
+
that carries the frame: a button can arrive wrapped in a tooltip or a link, at
|
|
91
|
+
any depth. So the group also sets `--x-corner-top-left-radius` and its three
|
|
92
|
+
siblings on the member, and a control that can arrive wrapped reads them as an
|
|
93
|
+
override of its own radius. The `--x-` prefix says what they are: navi's
|
|
94
|
+
internal wiring between a group and its members, not a surface an app writes
|
|
95
|
+
to (an app changes a radius with the `borderRadius` prop, which lands in the
|
|
96
|
+
fallback below and is what the corner keeps everywhere the group has no claim):
|
|
97
|
+
|
|
98
|
+
```css
|
|
99
|
+
.navi_thing {
|
|
100
|
+
border-top-left-radius: var(
|
|
101
|
+
--x-corner-top-left-radius,
|
|
102
|
+
var(--thing-border-radius)
|
|
103
|
+
);
|
|
104
|
+
/* …and the three others */
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
**Whoever answers the ask also stops it.** Custom properties inherit all the
|
|
109
|
+
way down, so the control that consumed a corner sets the four back to
|
|
110
|
+
`initial` on the first element inside it — otherwise a button in a slot, or the
|
|
111
|
+
Save button of a form in an open popup, reads a corner meant for the row that
|
|
112
|
+
opened it. `Popover` and `Dialog` stop it too, at their own root: nothing a
|
|
113
|
+
popup holds is at a seam.
|
|
114
|
+
|
|
115
|
+
Reference: `.navi_button_content` in `button_ui.jsx` (a button reads then
|
|
116
|
+
stops), `.navi_picker_right_slot`, `.navi_input_slot`, `.navi_popover`,
|
|
117
|
+
`.navi_dialog`.
|
|
118
|
+
|
|
79
119
|
A control that declares its radius on an inner element instead is invisible to
|
|
80
120
|
`Group`: it keeps round corners in the middle of the row, and no rule written
|
|
81
121
|
in `group.jsx` can reach it without naming that private class — which is how a
|
package/docs/interactions.md
CHANGED
|
@@ -63,6 +63,7 @@ condition: `{ swipe_right: canArchive && archive }`.
|
|
|
63
63
|
| `swipe_left` `swipe_right` `swipe_up` `swipe_down` | a press that travels |
|
|
64
64
|
| `longpress` | a press held still |
|
|
65
65
|
| `move` `reorder` `toss` | the element carried, and what letting go means |
|
|
66
|
+
| `grab` | the instant a drag takes hold of it |
|
|
66
67
|
| `"keyboard:<shortcut>"` | keys, e.g. `"keyboard:ctrl+backspace"` |
|
|
67
68
|
|
|
68
69
|
A name nothing knows how to detect produces a dev warning naming the detectors
|
|
@@ -109,17 +110,18 @@ in dev.
|
|
|
109
110
|
navi makes the element follow the finger — there is nothing to decide about
|
|
110
111
|
that — and says where the gesture is up to:
|
|
111
112
|
|
|
112
|
-
| Written on the element | Meaning
|
|
113
|
-
| ---------------------------------------- |
|
|
114
|
-
| `--swipe-pulled` | how far it has come, signed, in px
|
|
115
|
-
| `--swipe-progress` | the same as a fraction, signed
|
|
116
|
-
| `[data-swiping="left\|right\|up\|down"]` | which way, while a finger holds it
|
|
117
|
-
| `[data-swipe-past-threshold]` | letting go now would go through with it
|
|
113
|
+
| Written on the element | Meaning |
|
|
114
|
+
| ---------------------------------------- | --------------------------------------- |
|
|
115
|
+
| `--swipe-pulled` | how far it has come, signed, in px |
|
|
116
|
+
| `--swipe-progress` | the same as a fraction, signed |
|
|
117
|
+
| `[data-swiping="left\|right\|up\|down"]` | which way, while a finger holds it |
|
|
118
|
+
| `[data-swipe-past-threshold]` | letting go now would go through with it |
|
|
118
119
|
|
|
119
120
|
WHAT is revealed behind is yours: navi does not know what putting a row away
|
|
120
121
|
looks like. A trail is usually a child of the swiped element sized off
|
|
121
|
-
`--swipe-pulled
|
|
122
|
-
|
|
122
|
+
`--swipe-pulled`. Both values inherit, so a child reads them; a sibling cannot,
|
|
123
|
+
which is why the trail goes inside — and it travels with the row, since what
|
|
124
|
+
navi translates is the element that declares the gesture.
|
|
123
125
|
|
|
124
126
|
```css
|
|
125
127
|
.trail {
|
|
@@ -227,6 +229,39 @@ name what moves.
|
|
|
227
229
|
| `data-drag-delay` `data-drag-slop` `data-drag-threshold` | when the press becomes a grab |
|
|
228
230
|
| `data-toss-distance` `data-toss-speed` | how far and how fast counts as a throw |
|
|
229
231
|
|
|
232
|
+
### Saying the grab is acquired: `grab`
|
|
233
|
+
|
|
234
|
+
The three above answer the **release**. Between the press and the release there is
|
|
235
|
+
one instant that counts for the hand: the one where the object stops being pressed
|
|
236
|
+
and starts being held. `grab` is that instant — the same one whichever way the drag
|
|
237
|
+
was entered, a finger held still or a mouse travelled a few pixels.
|
|
238
|
+
|
|
239
|
+
```jsx
|
|
240
|
+
<Box
|
|
241
|
+
interactions={{
|
|
242
|
+
toss: (event) => remove(event.detail.id),
|
|
243
|
+
grab: () => navigator.vibrate?.(10),
|
|
244
|
+
}}
|
|
245
|
+
/>
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
It matters most where it is least visible. On a screen the held object is under the
|
|
249
|
+
thumb that hides it, so the only feedback available is the one that is felt; without
|
|
250
|
+
it the hand waits, doubts the press was heard, and lets go too early — the whole
|
|
251
|
+
gesture fails, not its decoration. With a mouse the grab is acquired after a few
|
|
252
|
+
pixels and the object has visibly moved, so the answer is already there.
|
|
253
|
+
|
|
254
|
+
Nothing here is about vibration: a sound, a class, a measure are the same moment.
|
|
255
|
+
|
|
256
|
+
`grab` **reports, it does not ask**: what it returns is not waited on, and
|
|
257
|
+
preventing its event does not call the gesture off. And it is not an interaction on
|
|
258
|
+
its own — declared without `move`, `reorder` or `toss` there is no gesture for it to
|
|
259
|
+
be the beginning of, and a dev warning says so. Its detail carries `pointerType` and
|
|
260
|
+
the `gestureInfo`.
|
|
261
|
+
|
|
262
|
+
A `longpress` needs none of this: it already happens at the moment the hold is
|
|
263
|
+
acquired, not at the release.
|
|
264
|
+
|
|
230
265
|
### Dressing the clone
|
|
231
266
|
|
|
232
267
|
What the pointer carries is a copy, and a copy of a transparent element is
|
|
@@ -399,6 +434,8 @@ container above it does not take the gesture:
|
|
|
399
434
|
the registry.
|
|
400
435
|
- `src/control/interaction/interaction_press.js` — swipes and holds, and what a
|
|
401
436
|
swipe writes on the element.
|
|
437
|
+
- `src/control/interaction/interaction_drag.js` — `move`, `reorder`, `toss` and
|
|
438
|
+
the `grab` moment.
|
|
402
439
|
- `src/control/interaction/interaction_keyboard.js`,
|
|
403
440
|
`interaction_native.js` — the other two detectors.
|
|
404
441
|
- `src/control/demos/38_interactions_demo.html` — every case above, plus a
|