@jsenv/navi 0.29.417 → 0.29.419

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.
Files changed (45) hide show
  1. package/README.md +1 -1
  2. package/dist/dev/jsenv_navi.js +347 -83
  3. package/dist/dev/jsenv_navi.js.map +12 -12
  4. package/dist/jsenv_navi.js +345 -81
  5. package/dist/jsenv_navi.js.map +12 -12
  6. package/docs/AI_INSTRUCTIONS.md +177 -258
  7. package/docs/actions.md +164 -251
  8. package/docs/autofocus.md +66 -83
  9. package/docs/control_object.md +117 -214
  10. package/docs/control_value.md +121 -185
  11. package/docs/create_and_edit.md +159 -254
  12. package/docs/css_architecture.md +196 -260
  13. package/docs/data_states.md +41 -44
  14. package/docs/dialog_shape.md +91 -134
  15. package/docs/drag_interactions.md +291 -454
  16. package/docs/drag_to_travel.md +152 -748
  17. package/docs/dynamic_import.md +119 -136
  18. package/docs/error_handling.md +75 -127
  19. package/docs/field_validation.md +49 -89
  20. package/docs/form_changed.md +61 -78
  21. package/docs/group.md +141 -0
  22. package/docs/i18n.md +31 -76
  23. package/docs/interactions.md +170 -326
  24. package/docs/list_action.md +36 -51
  25. package/docs/list_refresh.md +73 -115
  26. package/docs/mobile_touch.md +56 -62
  27. package/docs/navigation.md +377 -723
  28. package/docs/network_policy.md +61 -75
  29. package/docs/pan_zoom.md +62 -103
  30. package/docs/popup_backdrop.md +128 -168
  31. package/docs/popup_lift.md +179 -268
  32. package/docs/popup_open.md +380 -651
  33. package/docs/resource.md +228 -408
  34. package/docs/route_transitions.md +333 -473
  35. package/docs/safe_area.md +102 -89
  36. package/docs/scroll.md +175 -317
  37. package/docs/state_binding.md +40 -84
  38. package/docs/testid.md +18 -23
  39. package/docs/typography.md +111 -141
  40. package/docs/view_transitions.md +106 -104
  41. package/docs/z_index.md +61 -109
  42. package/package.json +2 -2
  43. package/docs/badge_list.md +0 -83
  44. package/docs/control_group.md +0 -168
  45. package/docs/mobile_layout_pitfalls.md +0 -145
package/docs/autofocus.md CHANGED
@@ -3,8 +3,8 @@
3
3
  A dialog, a popover, a slide arriving: one of them opens and something inside
4
4
  has to hold the keyboard. `autoFocus` is how each element takes part in that
5
5
  decision. Handing the focus over answers a second question at the same time —
6
- whether what receives it shows a focus ring — and navi answers that one too,
7
- at the end of this page.
6
+ whether what receives it shows a focus ring — and navi answers that one too, at
7
+ the end of this page.
8
8
 
9
9
  - [What we want](#what-we-want)
10
10
  - [The ladder](#the-ladder)
@@ -21,8 +21,8 @@ at the end of this page.
21
21
  ## What we want
22
22
 
23
23
  The focus is where the user is. So an opening has to answer one question — what
24
- did the user come here to do? — and the answer is rarely "type": a picker opens
25
- on its search box, but a popup that explains something opens on the explanation.
24
+ did the user come here to do? — and the answer is rarely "type": a popup that
25
+ explains something opens on the explanation.
26
26
 
27
27
  On a phone the difference is not a nuance. Focusing a field raises the virtual
28
28
  keyboard, the keyboard takes a third of the height, and the popup scrolls the
@@ -40,12 +40,14 @@ Whoever hands out the focus — a popup opening, a slide arriving — tries thes
40
40
  in order, and stops at the first that leads somewhere focusable:
41
41
 
42
42
  1. the element that held the focus when this container was last closed;
43
- 2. the first `autoFocus` — "put it here". The container's own comes last here,
44
- so a field naming itself wins over the surface around it;
43
+ 2. the first `autoFocus` — "put it here", the container's own tried last;
45
44
  3. the first focusable element — what one came to do;
46
- 4. the deepest `autoFocus="last-resort"`, the container itself included;
47
- 5. nothing: the focus stays where it was, and [when the opening places
48
- nothing](#when-the-opening-places-nothing) says what follows.
45
+ 4. one `autoFocus="last-resort"`: the first found that holds no other, the
46
+ container's own only when nothing inside says it;
47
+ 5. what held the focus before the opening (the trigger, for a press): the focus
48
+ stays outside, and
49
+ [when the opening places nothing](#when-the-opening-places-nothing) says what
50
+ follows.
49
51
 
50
52
  Step 1 is why reopening a popup comes back to where the user was, rather than to
51
53
  what the content asks for on a fresh open.
@@ -77,7 +79,7 @@ the opposite: "anything in here before me".
77
79
  2 of the ladder, and the container's own mark is tried last there. The two can
78
80
  be stated together without a conflict to resolve — the surface says where the
79
81
  focus goes by default, a field that really is what the user came for says so
80
- itself.
82
+ itself, on a touch device too.
81
83
 
82
84
  ```jsx
83
85
  <Dialog autoFocus>
@@ -90,38 +92,32 @@ itself.
90
92
 
91
93
  Where the keyboard is a virtual one — anything answering `pointer: coarse` — an
92
94
  arrival drops step 3 of the ladder entirely: the focus goes where something
93
- ASKED for it, and otherwise to the surface itself.
94
-
95
- Every arrival, not just a popup opening. A slide travelling in (so a
96
- `RouteTravel` screen too) hands out the focus the same way and loses the same
97
- thing by landing on the first focusable — more of it, even, a screen having more
98
- above the fold than a popup. Its surface is the `SlideContainer` box, which is
99
- what takes the keyboard when the slide holds nothing that can, so the arrows
100
- keep working from there.
95
+ ASKED for it, and otherwise to the surface itself. Step 4 still runs, though: a
96
+ `last-resort` inside is picked before a surface that is only `last-resort`
97
+ itself, the default — a chevron marked so takes the focus, and a field marked
98
+ so raises the keyboard.
99
+
100
+ Every arrival, not just a popup opening. A slide travelling into a
101
+ `SlideContainer` hands out the focus the same way and would lose the same thing
102
+ by landing on the first focusable — more of it, even, a screen having more above
103
+ the fold than a popup. Its surface is the `SlideContainer` box, which takes the
104
+ keyboard when the slide holds nothing that can, so the arrows keep working from
105
+ there.
101
106
 
102
107
  The condition is the device, not the shape of what arrives and not the gesture
103
- that brought it. A virtual keyboard is a fact about the screen: it costs a third
104
- of the height whatever raised it, and an arrival with no pointer in it at all —
105
- a popup opened by the page loading, a travel asked for by code — is exactly the
106
- one that must not be answered "no keyboard here". Docking only makes the cost
107
- more visible (a bottom sheet is short, so there is less room to lose before the
108
- title goes), it is not what creates it.
109
-
110
- Withdrawing only the FIELDS would not be enough either. The first focusable is
111
- wherever the content happens to put it — and in a popup that explains before it
112
- asks, what comes first is the explanation, so the first focusable is far down:
113
- the terms checkbox, the submit button. Landing there scrolls the popup to it and
114
- the title is above the top edge again, keyboard or no keyboard. The cause
115
- changes, the user sees the same thing.
116
-
117
- Nothing to pass, and nothing to remember per call site.
108
+ that brought it. A virtual keyboard costs a third of the height whatever raised
109
+ it, and an arrival with no pointer in it at all — a popup opened by the page
110
+ loading, a travel asked for by code — is exactly the one that must not be
111
+ answered "no keyboard here". Withdrawing only the fields would not do either: in
112
+ a popup that explains before it asks, the first focusable is far down (the terms
113
+ checkbox, the submit button), and landing there scrolls the title away, keyboard
114
+ or no keyboard.
118
115
 
119
116
  ### Opting a field back in
120
117
 
121
- Some popups — and some screens — really are opened to type in: one comment box,
122
- one rename field.
123
- There, the field says so itself, and that beats the device — step 2 of the
124
- ladder comes before step 3 was ever skipped.
118
+ Some popups — and some screens — really are opened to type in: one comment
119
+ box, one rename field. There, the field says so itself, and that beats the
120
+ device — step 2 of the ladder comes before step 3 was ever skipped.
125
121
 
126
122
  ```jsx
127
123
  <Dialog>
@@ -130,18 +126,15 @@ ladder comes before step 3 was ever skipped.
130
126
  </Dialog>
131
127
  ```
132
128
 
133
- Worth saying out loud before writing it: a popup holding one field is not
134
- necessarily a popup opened to fill it — it is often opened to READ what the
135
- field holds, and raising the keyboard over it then costs the reading for nothing.
136
- The default answers that case; `autoFocus` on the field answers the other, and
137
- saying which is which is the caller's to make because nothing about the markup
138
- can tell them apart.
129
+ A popup holding one field is not necessarily a popup opened to fill it — it is
130
+ often opened to READ what the field holds, and raising the keyboard over it then
131
+ costs the reading for nothing. Nothing about the markup tells the two apart, so
132
+ saying which is the caller's.
139
133
 
140
134
  ## What a field says about itself
141
135
 
142
- - `autoFocus` — "I am what the user came for". A picker's search box, the field
143
- of a popup opened to type in it. It holds on a touch device too: it is how a
144
- field opts back into a keyboard the surface would otherwise keep down.
136
+ - `autoFocus` — "I am what the user came for": the field of a popup opened to
137
+ type in it.
145
138
  - `autoFocus="restore"` — "never on a fresh open, but bring me back". A field
146
139
  the user was typing in when a popup over it closed: reopening returns to it,
147
140
  opening for the first time does not raise a keyboard on it.
@@ -153,10 +146,8 @@ can tell them apart.
153
146
  ## When the opening places nothing
154
147
 
155
148
  A popup can open on content that holds nothing focusable yet — content still
156
- being built, a screen not yet interactive. The ladder then comes back empty and
157
- the opening places no focus at all.
158
-
159
- That debt is settled two ways, whichever comes first:
149
+ being built, a screen not yet interactive. The ladder then places nothing inside
150
+ it, and that debt is settled two ways, whichever comes first:
160
151
 
161
152
  - what arrives a moment later takes it — an `autoFocus` in content built during
162
153
  the opening is honored, rather than deferring to a transfer that never
@@ -165,9 +156,8 @@ That debt is settled two ways, whichever comes first:
165
156
  before the browser paints and long before the user can do anything. A surface
166
157
  that says `autoFocus` about itself is placed by that second try.
167
158
 
168
- Without this, the same popup would land the focus in a different place — or
169
- nowhere — depending on whether it was opened by a click or by the page loading,
170
- which is the same popup behaving differently for no reason the user can see.
159
+ So the same popup places the focus the same way whether a click or the page
160
+ loading opened it.
171
161
 
172
162
  ## The ring is decided too
173
163
 
@@ -180,25 +170,25 @@ answers instead, and the answer is the **modality of what asked**:
180
170
  arrow key: a ring;
181
171
  - a finger or a mouse asked: no ring, whatever the code did in between;
182
172
  - the element receiving it is **editable** — a text input, a textarea, a
183
- contenteditable: a ring anyway. Someone about to type has to see where.
173
+ contenteditable: a ring anyway. Someone about to type has to see where, so
174
+ opening a search field with a mouse click still rings.
184
175
 
185
- That last one is why opening a search field with a mouse click still rings: the
186
- field is where you are about to type, not somewhere you merely landed.
187
-
188
- Nothing to pass, and nothing to opt into: it is how every navi component moves
189
- the focus.
176
+ The ladder answers it this way, and so does `moveFocusTo`
177
+ ([below](#moving-the-focus-yourself)).
190
178
 
191
179
  ### In your CSS
192
180
 
193
- `:focus-visible` and `[data-focus-visible]` — the standard selectors, nothing
194
- navi-specific. navi implements them with a wider meaning than the browser's: an
195
- element also counts as focused while a **proxy** holds the focus (a read-only
196
- range delegating to a sibling) or while an element **controlling** it does (a
197
- combobox input with `aria-controls` on its listbox — the listbox reads as
198
- focused while the input is). Style the standard name and you get that for free.
181
+ Navi's "focused" is wider than the browser's: an element counts as focused while
182
+ an element **controlling** it holds the focus (a listbox, while the combobox
183
+ input with `aria-controls` on it does), and a **proxy** — the visible stand-in
184
+ for a hidden real control — while its real control does. That meaning lives in
185
+ `[data-focus-visible]`, the attribute navi writes on an element tracking the
186
+ pseudo-class: navi's own controls, and a `Box` of yours once its `style` holds a
187
+ `":focus-visible"` key. A native `:focus-visible` rule only gets the browser's
188
+ behaviour.
199
189
 
200
190
  ```css
201
- .my_row:focus-visible {
191
+ .my_row[data-focus-visible] {
202
192
  outline: 2px solid var(--navi-focus-outline-color);
203
193
  }
204
194
  ```
@@ -217,18 +207,21 @@ when something else took the focus meanwhile — the page arriving, focusing a
217
207
  field of its own — that one keeps it.
218
208
 
219
209
  So `{editing && <Dialog open>…</Dialog>}` unmounted from a button inside it
220
- lands the focus back on the button that opened it, and a dialog left along
221
- with the page around it lands it nowhere (`<body>`), exactly as if the page
222
- had simply been removed.
210
+ lands the focus back on the button that opened it, and a dialog left along with
211
+ the page around it lands it nowhere (`<body>`), exactly as if the page had
212
+ simply been removed.
223
213
 
224
214
  ## Moving the focus yourself
225
215
 
226
216
  Prefer saying where the focus belongs over moving it: `autoFocus` on the field
227
217
  or the surface (the ladder above), and navi places it at the right moment, with
228
- the right ring, without scrolling anything.
218
+ the right ring, without scrolling it into view.
229
219
 
230
220
  When you really do have to move it — a control of your own handing over to
231
- another — use `moveFocusTo` rather than `element.focus()`:
221
+ another — use `moveFocusTo` rather than `element.focus()`. A bare `.focus()`
222
+ answers "who" and leaves "is this visible" to the browser, which reads the last
223
+ thing that touched the DOM — your own call. `moveFocusTo` applies both decisions
224
+ above, no scroll-into-view and the ring of the modality:
232
225
 
233
226
  ```js
234
227
  import { moveFocusTo } from "@jsenv/navi";
@@ -236,15 +229,5 @@ import { moveFocusTo } from "@jsenv/navi";
236
229
  moveFocusTo(searchInputElement);
237
230
  ```
238
231
 
239
- That is the whole call. It applies the two decisions above for you: no
240
- scroll-into-view, and a ring only where the user is on the keyboard (an
241
- editable target ringing anyway). A bare `element.focus()` answers "who" and
242
- leaves "is this visible" to the browser, and the browser reads the last thing
243
- that touched the DOM — which was your own call.
244
-
245
- Pass `focusVisible` when you know better than the last interaction does, and
246
- `preventScroll: false` when the element really has to be brought into view:
247
-
248
- ```js
249
- moveFocusTo(element, { focusVisible: true });
250
- ```
232
+ `focusVisible` is for when you know better than the last interaction does, and
233
+ `preventScroll: false` for an element that really has to be brought into view.