@jsenv/navi 0.29.418 → 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.
- package/README.md +1 -1
- package/dist/dev/jsenv_navi.js +192 -43
- package/dist/dev/jsenv_navi.js.map +10 -10
- package/dist/jsenv_navi.js +190 -41
- package/dist/jsenv_navi.js.map +10 -10
- package/docs/AI_INSTRUCTIONS.md +177 -261
- package/docs/actions.md +164 -251
- package/docs/autofocus.md +66 -83
- package/docs/control_object.md +117 -214
- package/docs/control_value.md +121 -185
- package/docs/create_and_edit.md +159 -254
- package/docs/css_architecture.md +196 -260
- package/docs/data_states.md +41 -44
- package/docs/dialog_shape.md +91 -134
- package/docs/drag_interactions.md +115 -174
- package/docs/drag_to_travel.md +10 -9
- package/docs/dynamic_import.md +119 -136
- package/docs/error_handling.md +75 -127
- package/docs/field_validation.md +49 -89
- package/docs/form_changed.md +61 -78
- package/docs/group.md +141 -0
- package/docs/i18n.md +31 -76
- package/docs/interactions.md +6 -4
- package/docs/list_action.md +36 -51
- package/docs/list_refresh.md +73 -115
- package/docs/mobile_touch.md +56 -62
- package/docs/navigation.md +377 -723
- package/docs/network_policy.md +61 -75
- package/docs/pan_zoom.md +62 -103
- package/docs/popup_backdrop.md +128 -168
- package/docs/popup_lift.md +179 -268
- package/docs/popup_open.md +380 -651
- package/docs/resource.md +228 -408
- package/docs/route_transitions.md +333 -482
- package/docs/safe_area.md +102 -89
- package/docs/scroll.md +175 -335
- package/docs/state_binding.md +2 -1
- package/docs/testid.md +18 -23
- package/docs/typography.md +111 -141
- package/docs/view_transitions.md +106 -104
- package/docs/z_index.md +61 -109
- package/package.json +2 -2
- package/docs/badge_list.md +0 -83
- package/docs/control_group.md +0 -168
- package/docs/mobile_layout_pitfalls.md +0 -145
package/docs/AI_INSTRUCTIONS.md
CHANGED
|
@@ -1,315 +1,231 @@
|
|
|
1
1
|
# @jsenv/navi — context for AI assistants
|
|
2
2
|
|
|
3
|
-
This file gives context for using `@jsenv/navi` as intended,
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
This file gives context for using `@jsenv/navi` as intended, whether you read
|
|
4
|
+
the source or the built `dist/jsenv_navi.js` (e.g. inside
|
|
5
|
+
`node_modules/@jsenv/navi/`).
|
|
6
6
|
|
|
7
|
-
`dist/jsenv_navi.js` is
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
(the bundler only keeps a comment that sits directly above a declaration it
|
|
12
|
-
retains as-is).
|
|
7
|
+
`dist/jsenv_navi.js` is navi's actual source, bundled — not an opaque blob. The
|
|
8
|
+
JSDoc on functions and exports is kept and carries real information; what
|
|
9
|
+
bundling loses is only file-level comments and comments attached to an
|
|
10
|
+
import/re-export statement.
|
|
13
11
|
|
|
14
12
|
## Where the answer to "how do I use X" is
|
|
15
13
|
|
|
16
|
-
There is deliberately **no per-export reference page
|
|
17
|
-
|
|
18
|
-
|
|
14
|
+
There is deliberately **no per-export reference page**, and there never will
|
|
15
|
+
be: a page per component drifts from the code the day after it is written. Each
|
|
16
|
+
source of knowledge has one job:
|
|
19
17
|
|
|
20
18
|
- **These `docs/*.md` files** — decisions, concepts and invariants: what a
|
|
21
|
-
mechanism is for, what it costs, what not to hand-write beside it
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
- **JSDoc on an export** (`@type`, `@param`) — a
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
interplay between two props, everything a component composes are not repeated
|
|
19
|
+
mechanism is for, what it costs, what not to hand-write beside it — what a
|
|
20
|
+
signature cannot say. Read the relevant one BEFORE writing code in its area;
|
|
21
|
+
they are listed below.
|
|
22
|
+
- **JSDoc on an export** (`@type`, `@param`) — what a prop means and accepts. A
|
|
23
|
+
hint at the call site, not exhaustive: the props that flow through to `Box`,
|
|
24
|
+
the interplay between two props, what a component composes are not repeated
|
|
28
25
|
there.
|
|
29
|
-
- **The built code, `dist/jsenv_navi.js`** — the exhaustive truth about the API
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
So the loop, when the JSDoc did not answer: read the built export, then find a
|
|
44
|
-
demo using it. Write the answer down in one of these `docs/*.md` files only if
|
|
45
|
-
what you learned is a decision or an invariant — never as a reference page for
|
|
46
|
-
one component.
|
|
26
|
+
- **The built code, `dist/jsenv_navi.js`** — the exhaustive truth about the API,
|
|
27
|
+
JSDoc included, always under `node_modules/@jsenv/navi/`. When a signature, a
|
|
28
|
+
default or an accepted value is what you need, read it there rather than
|
|
29
|
+
guessing.
|
|
30
|
+
- **Sources, demos and tests** — how an export is really used:
|
|
31
|
+
`src/**/demos/*_demo.html` exercise one component per page, prop by prop. They
|
|
32
|
+
are not published to npm, so they live only in the repo
|
|
33
|
+
(https://github.com/jsenv/core/tree/main/packages/frontend/navi); a project
|
|
34
|
+
that wants an AI to work with navi seriously keeps a local clone beside it.
|
|
35
|
+
|
|
36
|
+
So when the JSDoc did not answer: read the built export, then find a demo using
|
|
37
|
+
it. Write what you learned into a `docs/*.md` only if it is a decision or an
|
|
38
|
+
invariant — never as a reference page for one component.
|
|
47
39
|
|
|
48
40
|
## Library, but also a framework
|
|
49
41
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
When building something Navi already has a primitive for, prefer that
|
|
58
|
-
primitive over a custom one, even if the custom one would be quicker to
|
|
59
|
-
write for this one case — the value of using Navi as a framework comes from
|
|
60
|
-
consistency across the app, not from any single call site.
|
|
42
|
+
Every export is usable on its own — just `stateSignal`, just `Table`. But navi
|
|
43
|
+
also provides the primitives most apps otherwise reinvent inconsistently:
|
|
44
|
+
routing, the async data lifecycle, CSS layering and tokens, focus and keyboard
|
|
45
|
+
handling, and more. When navi has a primitive for what you are building, prefer
|
|
46
|
+
it over a custom one, even when the custom one would be quicker to write for this
|
|
47
|
+
one case: the value of navi as a framework is the consistency across the app,
|
|
48
|
+
not any single call site.
|
|
61
49
|
|
|
62
50
|
## The docs, and when to read each
|
|
63
51
|
|
|
64
|
-
One line per file: what it decides, and the moment to open it.
|
|
65
|
-
holds the reasoning; nothing here substitutes for it.
|
|
52
|
+
One line per file: what it decides, and the moment to open it.
|
|
66
53
|
|
|
67
|
-
`README.md` (package root) names what navi provides, area by area — the place
|
|
68
|
-
|
|
54
|
+
`README.md` (package root) names what navi provides, area by area — the place to
|
|
55
|
+
start when unsure which export solves a problem.
|
|
69
56
|
|
|
70
57
|
### Routing and movement
|
|
71
58
|
|
|
72
|
-
- `navigation.md` — the position of the user belongs in the URL by default
|
|
73
|
-
and
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
before
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
`finished` fulfills, the top layer painted only through the root's picture,
|
|
92
|
-
the two frames that show the live document, what makes the start of a
|
|
93
|
-
transition restyle the whole document (an unscoped `::highlight()`, a value
|
|
94
|
-
changed on `:root`), and a hidden popup photographed on one side only. Read
|
|
95
|
-
before calling `document.startViewTransition`, and before putting a value on
|
|
96
|
-
`:root` for a movement.
|
|
97
|
-
- `drag_to_travel.md` — a pointer or a wheel pushing a whole screen aside, and
|
|
98
|
-
who owns a press several boxes want. Read before putting anything that reads the pointer
|
|
59
|
+
- `navigation.md` — the position of the user belongs in the URL by default:
|
|
60
|
+
routes and which branch renders, search params, redirections, the back arrow
|
|
61
|
+
(`navBack`), where a navigation lands (a `#id` for an element), a
|
|
62
|
+
`SlideContainer` read from the URL, what a layer drawn over the screen may say
|
|
63
|
+
in its address. Before any routing code.
|
|
64
|
+
- `route_transitions.md` — a transition states a relation between two pages;
|
|
65
|
+
`RouteTravel` or a transition, never both on one pair; fixed bars and
|
|
66
|
+
`RouteTransitionArea`; the page being left stays mounted, hidden, until the
|
|
67
|
+
movement is over; a test waits for the page, never for its address; what a
|
|
68
|
+
transition costs. Before animating a navigation, and before believing a
|
|
69
|
+
symptom that only appears once a pair is animated.
|
|
70
|
+
- `view_transitions.md` — what the browser does to any view transition: unique
|
|
71
|
+
names (and none inside a page that moves), the fallback fade, a callback in
|
|
72
|
+
which no frame ticks, `ready` and `finished`, the top layer, what restyles the
|
|
73
|
+
whole document, what cannot be pointed at while one plays. Before
|
|
74
|
+
`document.startViewTransition`, and before putting a value on `:root` for a
|
|
75
|
+
movement.
|
|
76
|
+
- `drag_to_travel.md` — a pointer or a wheel pushing a screen aside, and who owns
|
|
77
|
+
a press several boxes want. Before putting anything that reads the pointer
|
|
99
78
|
inside a box that travels.
|
|
100
79
|
|
|
101
80
|
### Data
|
|
102
81
|
|
|
103
|
-
- `actions.md` —
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
`
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
is told whether it is loading. Read before drawing a skeleton on `!data` or
|
|
117
|
-
hiding content because `error` is set.
|
|
118
|
-
- `list_refresh.md` — what a write sends back and what stays on screen
|
|
119
|
-
meanwhile; `rerunOn` and its defaults; a paginated list re-reading its window;
|
|
120
|
-
on the way back, the source decides the re-read and never the navigation.
|
|
121
|
-
Read before adding verbs to `rerunOn` or remounting a list to refresh it.
|
|
82
|
+
- `actions.md` — calling versus binding, a failing run rejects, reading is not
|
|
83
|
+
running (`{ run: true }` is the fallback), `action` versus `uiAction`, an
|
|
84
|
+
action and a command on one press. Before running an action from a component.
|
|
85
|
+
- `resource.md` — `resource()` and its relations (never an `op` discriminator),
|
|
86
|
+
`GET_RANGE`, a search as the same `GET_MANY`, `withParams()` scopes and
|
|
87
|
+
`dependencies`, `persist`, a function versus the verb's instance. Before
|
|
88
|
+
writing a resource, and before caching a response yourself.
|
|
89
|
+
- `data_states.md` — `data`, `loading` and `error` are three questions;
|
|
90
|
+
`loading: true` never suspends; a skeleton is told whether it is loading.
|
|
91
|
+
Before drawing a skeleton on `!data` or hiding content because `error` is set.
|
|
92
|
+
- `list_refresh.md` — what a write sends back and what stays on screen meanwhile;
|
|
93
|
+
`rerunOn` and its defaults; coming back to a list. Before adding verbs to
|
|
94
|
+
`rerunOn` or remounting a list to refresh it.
|
|
122
95
|
- `list_action.md` — where the `action` lives decides who waits; a row whose
|
|
123
|
-
button works is `readOnly`, not `loading`; `parallelGuard`.
|
|
96
|
+
button works is `readOnly`, not `loading`; `parallelGuard`. Before
|
|
124
97
|
`<List readOnly={pending}>` or a second spinner beside a control's own.
|
|
125
|
-
- `error_handling.md` —
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
- `network_policy.md` — `setNetworkPolicy`:
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
state, `useAsyncData(() => import(…))` only as the fallback;
|
|
136
|
-
links prerun on intent what asks nothing of the address; a transition
|
|
137
|
-
photographs the pending screen; a chunk's `import.meta.css`; a chunk that
|
|
138
|
-
does not come is never a bug and never comes twice in one document — offer
|
|
139
|
-
`reload()`; why not preact's `lazy`. Read before an `import()` in a component
|
|
140
|
-
or a page, and before `prefetch={false}`.
|
|
98
|
+
- `error_handling.md` — a refusal versus a bug, where each is shown, displaying
|
|
99
|
+
is claiming, the rules of a boundary. Before displaying an error by hand or
|
|
100
|
+
writing a boundary.
|
|
101
|
+
- `network_policy.md` — `setNetworkPolicy`: writes held before the press, reads
|
|
102
|
+
answered from the store or let through. Before caching responses in the app, or
|
|
103
|
+
guarding writes in its own request layer.
|
|
104
|
+
- `dynamic_import.md` — code arrives like data: a page's import is a route
|
|
105
|
+
action, a component's is started by what asks; links prefetch on intent; a
|
|
106
|
+
chunk that does not come needs a fresh document; no `lazy()`. Before an
|
|
107
|
+
`import()` in a component or a page.
|
|
141
108
|
|
|
142
109
|
### Controls and forms
|
|
143
110
|
|
|
144
|
-
- `state_binding.md` —
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
`
|
|
153
|
-
|
|
154
|
-
- `
|
|
155
|
-
|
|
156
|
-
settings sheet. Read before putting anything in a picker popup.
|
|
157
|
-
- `control_group.md` — `<Group>`: several controls reading as one framed
|
|
158
|
-
object. Read before negative margins or `border-radius: 0` by hand.
|
|
111
|
+
- `state_binding.md` — state navi shows is bound (`signal`), not copied back by a
|
|
112
|
+
callback; the three shapes (`signal`, `action`, `command` + `commandFor`).
|
|
113
|
+
Before any handler whose body only assigns state.
|
|
114
|
+
- `control_value.md` — who holds a control's value; `--navi-update` for a button
|
|
115
|
+
proposing one; a `defaultValue` follows the record it was read from; empty
|
|
116
|
+
keeps the shape of the question. Before wiring a value with `value` +
|
|
117
|
+
`uiAction`.
|
|
118
|
+
- `control_object.md` — one value made of several controls: `ControlGroup` versus
|
|
119
|
+
`Form`, naming, `<Picker type="object">`, a settings sheet. Before putting
|
|
120
|
+
anything in a picker popup.
|
|
121
|
+
- `group.md` — `<Group>`: several controls reading as one framed object. Before
|
|
122
|
+
negative margins or `border-radius: 0` by hand.
|
|
159
123
|
- `form_changed.md` — a form sends nothing when nothing changed; what "changed"
|
|
160
|
-
is measured against; `pristineKey`; `standalone`; what follows a send
|
|
161
|
-
`command
|
|
162
|
-
|
|
163
|
-
has no business joining.
|
|
124
|
+
is measured against; `pristineKey`; `standalone`; what follows a send
|
|
125
|
+
(`command`, `--navi-void`). Before `canSendWhileUnchanged`, and before a control
|
|
126
|
+
inside a group whose value it has no business joining.
|
|
164
127
|
- `field_validation.md` — what only a browser can answer versus "is this value
|
|
165
|
-
acceptable" (validity's); constraints as props; `singleSpace="autoFix"
|
|
166
|
-
|
|
167
|
-
before writing a constraint: if the sentence would make sense in a server's
|
|
168
|
-
response, the rule belongs in validity.
|
|
128
|
+
acceptable" (@jsenv/validity's); constraints as props; `singleSpace="autoFix"`;
|
|
129
|
+
guards. Before writing a constraint.
|
|
169
130
|
- `create_and_edit.md` — the create/edit loop assembled from `route`,
|
|
170
|
-
`resource`, `Form` and `RouteTravel`.
|
|
171
|
-
screen.
|
|
172
|
-
- `badge_list.md` — how a `BadgeList` counts its badges, `maxLines` inside a
|
|
173
|
-
`Picker`, why it needs a `fallback` there.
|
|
131
|
+
`resource`, `Form` and `RouteTravel`. Before writing a create or edit screen.
|
|
174
132
|
|
|
175
133
|
### Popups
|
|
176
134
|
|
|
177
|
-
- `popup_open.md` — a popup owns its open state; `command` + `commandFor
|
|
178
|
-
`triggerNaviCommand` as the last resort
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
- `
|
|
187
|
-
|
|
188
|
-
`data-navi-popup-outside`, and `data-navi-popup-inside` for a box of the
|
|
189
|
-
page whose press is not a dismissal. Read before writing CSS for a backdrop.
|
|
190
|
-
- `popup_lift.md` — `animation="lifting"`: the pressed card brought to the
|
|
191
|
-
front. `data-lift` names what is lifted and is rendered at once; the
|
|
192
|
-
trigger's box is the card's box; `lift="box"` for a card, `"scene"` for a
|
|
193
|
-
drawing framed the same way; one popup for a whole row, walked from the front
|
|
194
|
-
through a `SlideContainer`, `liftAnchor` naming where the closing comes back
|
|
195
|
-
to; `animation={{ open, close: "lifting" }}` for a popup that did not come out of what it
|
|
196
|
-
lands in, the landing rendered by `onClose`; what an opening costs and where
|
|
197
|
-
the time goes;
|
|
198
|
-
the wall arriving from nothing, over the movement. Read before
|
|
199
|
-
giving a `Dialog` or a `Picker` `animation="lifting"`, or before measuring
|
|
200
|
-
why one opens slowly.
|
|
135
|
+
- `popup_open.md` — a popup owns its open state; `command` + `commandFor`,
|
|
136
|
+
`triggerNaviCommand` as the last resort; opening ON something; a press that
|
|
137
|
+
opens and acts is a `Picker`; Escape cancels; the close cross;
|
|
138
|
+
`signal`/`navState`/`open`; a popup that loads data; `mount`; a closed
|
|
139
|
+
`Dialog` costs one element until asked (a row may hold the dialogs of its
|
|
140
|
+
own actions). Before passing `open`, calling `triggerNaviCommand`, or
|
|
141
|
+
writing a close button.
|
|
142
|
+
- `popup_backdrop.md` — three independent questions: a wall or not, what an
|
|
143
|
+
outside press does, how far the page withdraws. Before CSS for a backdrop.
|
|
144
|
+
- `popup_lift.md` — `animation="lifting"`: the pressed card brought to the front.
|
|
145
|
+
Before giving a `Dialog` or a `Picker` `animation="lifting"`.
|
|
201
146
|
- `dialog_shape.md` — bounds rather than a width, the container ceiling, the
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
deriving `smallTouchScreenSignal` in an app or writing CSS to make a dialog
|
|
205
|
-
fit.
|
|
147
|
+
docked sheet. Before deriving `smallTouchScreenSignal` in an app or writing CSS
|
|
148
|
+
to make a dialog fit.
|
|
206
149
|
- `autofocus.md` — the ladder that hands out the keyboard, `autoFocus` on a
|
|
207
|
-
surface versus
|
|
208
|
-
`
|
|
150
|
+
surface versus a field, the ring, `moveFocusTo`. Before calling
|
|
151
|
+
`element.focus()` anywhere.
|
|
209
152
|
|
|
210
153
|
### Gestures
|
|
211
154
|
|
|
212
155
|
- `interactions.md` — a gesture is named, not read by hand: the `interactions`
|
|
213
|
-
prop, swipes, holds
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
registering a detector. Read before a `pointerdown` listener of your own, and
|
|
217
|
-
before stopping propagation to keep a popup shut.
|
|
156
|
+
prop, swipes, holds, counted taps, the gate, `selfInteractions`, registering a
|
|
157
|
+
detector. Before a `pointerdown` listener of your own, and before stopping
|
|
158
|
+
propagation to keep a popup shut.
|
|
218
159
|
- `drag_interactions.md` — an element carried: `move`, `reorder`, `land`,
|
|
219
|
-
`toss`, `leave`, `moving`, the `grab`/`release`/`refuse` moments,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
intent before that), `touch-action` restarts at every scroller, when the
|
|
227
|
-
click survives, the tap Chrome drops after a touch drag, the capture every
|
|
228
|
-
finger lands with (which `hasPointerCapture` misses on a field), and how to
|
|
229
|
-
reproduce all of it without a device (Chrome's mobile touch emulator, Safari
|
|
230
|
-
in the iOS simulator). Read before reading a finger yourself, and before concluding a
|
|
231
|
-
gesture works because it works with a mouse.
|
|
160
|
+
`toss`, `leave`, `moving`, the `grab`/`release`/`refuse` moments,
|
|
161
|
+
`--navi-grab`, dressing the clone. Before moving anything with the pointer.
|
|
162
|
+
- `pan_zoom.md` — a surface under the hand: `pan`, `zoom`, and what a touch or a
|
|
163
|
+
wheel over it may do to the page around it.
|
|
164
|
+
- `mobile_touch.md` — what Chrome and Safari do with a finger, measured, and how
|
|
165
|
+
to reproduce it without a device. Before reading a finger yourself, and before
|
|
166
|
+
concluding a gesture works because it works with a mouse.
|
|
232
167
|
|
|
233
168
|
### Layout, CSS and text
|
|
234
169
|
|
|
235
|
-
- `css_architecture.md` — navi wins by default, defaults
|
|
236
|
-
|
|
237
|
-
opener;
|
|
238
|
-
`import.meta.css` and what a `${}` costs;
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
`
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
window (`renderBudget`, its `{ initial, after }` form for a list whose first
|
|
251
|
-
picture is taken — opening in a click, coming back in a route transition —
|
|
252
|
-
counted from the row it opens on; the whole `onScrolledChange` position,
|
|
253
|
-
`visibleCount` included, handed back to open on it; `virtualItemSize`,
|
|
254
|
-
`findText` for Cmd/Ctrl + F beyond the window).
|
|
255
|
-
Read before writing CSS to make something scroll, and before rendering a
|
|
256
|
-
collection as `<List.Item>` children.
|
|
257
|
-
- `mobile_layout_pitfalls.md` — a horizontal overflow inflates the layout
|
|
258
|
-
viewport on Chrome Android and miscenters every dialog; `overflow-x: clip`.
|
|
170
|
+
- `css_architecture.md` — navi wins by default, defaults in `@layer navi`, props
|
|
171
|
+
first; `--navi-*` versus `--component-*`; what a popup inherits from its
|
|
172
|
+
opener; structural selectors (`:last-child`…) and navi's out-of-flow children;
|
|
173
|
+
`import.meta.css` and what a `${}` costs; browser support. Before overriding a
|
|
174
|
+
component style or writing `import.meta.css`.
|
|
175
|
+
- `safe_area.md` — the app's rectangle and the band left free inside it, an app
|
|
176
|
+
narrower than the window (`--navi-app-max-width`), `data-navi-safe-area`, the
|
|
177
|
+
viewport under a virtual keyboard, a document wider than the screen. Before
|
|
178
|
+
hand-writing an offset to clear a `FixedBar`.
|
|
179
|
+
- `scroll.md` — where scrolling happens: `header`/`body`/`footer`, a `List`'s
|
|
180
|
+
`scroller`, where a list opens (a position handed back whole, `visibleCount`
|
|
181
|
+
included), a popup that scrolls, many rows (`<List.Items>`, the render window
|
|
182
|
+
and its first picture, `findText`), hover while scrolling. Before writing CSS
|
|
183
|
+
to make something scroll, and before rendering a collection as `<List.Item>`
|
|
184
|
+
children.
|
|
259
185
|
- `z_index.md` — DOM order first; a `z-index` without `isolation: isolate`
|
|
260
|
-
competes with the page; navi's bands.
|
|
261
|
-
- `typography.md` — text is a component; `maxLines` is the one truncation
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
`attachLastChild`; one line height for everything (`--navi-line-height`,
|
|
265
|
-
1.25). Read before an overflowing label, and before touching a
|
|
266
|
-
`line-height`.
|
|
186
|
+
competes with the page; navi's bands. Before writing a `z-index`.
|
|
187
|
+
- `typography.md` — text is a component; `maxLines` is the one truncation; one
|
|
188
|
+
line height for everything; `BadgeList`. Before an overflowing label, and
|
|
189
|
+
before touching a `line-height`.
|
|
267
190
|
- `i18n.md` — `interpolateText`/`<Interpolate>` for one sentence, `createI18n`
|
|
268
|
-
for the app's texts, `naviI18n` for navi's own.
|
|
269
|
-
|
|
270
|
-
- `testid.md` — role and accessible name first; `data-testid` lands
|
|
271
|
-
|
|
272
|
-
target. Read before a selector in a test.
|
|
191
|
+
for the app's texts, `naviI18n` for navi's own. Before writing a user-visible
|
|
192
|
+
sentence.
|
|
193
|
+
- `testid.md` — role and accessible name first; where `data-testid` lands; what
|
|
194
|
+
not to target. Before a selector in a test.
|
|
273
195
|
|
|
274
196
|
## Key concepts to know before guessing an API
|
|
275
197
|
|
|
276
|
-
- **Routing is signal-based**: URL state
|
|
277
|
-
|
|
278
|
-
|
|
198
|
+
- **Routing is signal-based**: URL state, search params included, two-way syncs
|
|
199
|
+
with signals. Don't build parallel state for what a route or query signal
|
|
200
|
+
already tracks.
|
|
279
201
|
- **A link lands on an element by its fragment**: give the element an `id` and
|
|
280
|
-
link to `#id
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
`
|
|
285
|
-
not run it: a `routeAction`, a control's `action`, or
|
|
286
|
-
`useAsyncData(action, { run: true })` starts it.
|
|
202
|
+
link to `#id` — never a search param plus `scrollIntoView` in an effect.
|
|
203
|
+
- **Actions** model async operations with a lifecycle (idle, running, completed,
|
|
204
|
+
failed, aborted). Components read an action's state with `useAsyncData`, not
|
|
205
|
+
hand-tracked loading/error booleans. Reading does not run it: a `routeAction`,
|
|
206
|
+
a control's `action`, or `useAsyncData(action, { run: true })` starts it.
|
|
287
207
|
- **REST state is modelled with `resource()`**, and parent/child relations with
|
|
288
|
-
`.one` / `.many` / `.scopedOne` / `.scopedMany
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
- **`Box`** is the element every component is drawn with: `flex` (side by
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
inside Navi apps.
|
|
208
|
+
`.one` / `.many` / `.scopedOne` / `.scopedMany` — never a backend sub-resource
|
|
209
|
+
(`/games/:id/candidates`) encoded as an `op`/`type` discriminator inside one
|
|
210
|
+
verb's callback. Searching a collection is that collection's `GET_MANY` with
|
|
211
|
+
one more param.
|
|
212
|
+
- **`Box`** is the element every component is drawn with: `flex` (side by side),
|
|
213
|
+
`flex="y"` (stacked), `grid`, `inline`, `alignX`/`alignY`, `spacing` for the gap
|
|
214
|
+
(there is no `gap` prop), sizes from the `"xxs"`…`"xxl"` scale. Prefer it over
|
|
215
|
+
raw CSS for layout.
|
|
297
216
|
- **A control holds its own value.** `Input` (checkbox and radio are
|
|
298
|
-
`<Input type="checkbox">`/`<Input type="radio"
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
`onChange` + manual state (see `control_value.md`).
|
|
217
|
+
`<Input type="checkbox">`/`<Input type="radio">`; there is no `Checkbox`),
|
|
218
|
+
`Select`, `Picker` and the others work with nothing wired: inside a `Form`, the
|
|
219
|
+
form reads them when it sends. When the app needs the value, bind it with
|
|
220
|
+
`signal`. `action` reacts to a change that can fail or take time; it is not how
|
|
221
|
+
a control is wired. Never `onChange` + manual state.
|
|
304
222
|
- **A gesture is named, not read by hand**: `interactions={{ swipe_right: … }}`
|
|
305
|
-
on any `Box
|
|
306
|
-
- **Texts**: a user-visible sentence containing a value is
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
texts never go into `naviI18n`.
|
|
223
|
+
on any `Box`, so on any component — never a `pointerdown` listener of your own.
|
|
224
|
+
- **Texts**: a user-visible sentence containing a value is one template with
|
|
225
|
+
`[placeholder]`s (`interpolateText` / `<Interpolate>`), not JSX fragments or
|
|
226
|
+
concatenations. Beyond a handful of texts, the app declares them in its own
|
|
227
|
+
`createI18n()` instance, the English text as the key; navi's `naviI18n` uses
|
|
228
|
+
opaque keys, and application texts never go into it.
|
|
312
229
|
- **View transitions**: navi components animate their own changes and never
|
|
313
|
-
decide for the whole document. What an app starting its own transition has
|
|
314
|
-
|
|
315
|
-
ticks — is `view_transitions.md`.
|
|
230
|
+
decide for the whole document. What an app starting its own transition has to
|
|
231
|
+
know is `view_transitions.md`.
|