@jsenv/navi 0.29.108 → 0.29.110

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/docs/actions.md CHANGED
@@ -176,6 +176,13 @@ one that asks something of a control near it is a `command` (a value proposed is
176
176
  [control_value.md](./control_value.md#a-button-that-proposes-a-value-is---navi-update)).
177
177
  Reaching for a plain `onClick` usually means one of those was missed.
178
178
 
179
+ On a link — a `Link`, a `<Button href>` or `<Button route>` — the three fire on
180
+ the press, before the navigation, and the navigation waits for none of them: a
181
+ `command="--navi-close"` closes the sheet the link leaves, an `action` that
182
+ writes a draft synchronously is found by the next page, and a request goes on
183
+ its own while the page changes. Work that decides the destination is not a
184
+ link's: it navigates itself, from a `<Button action>`.
185
+
179
186
  The press that looks like a fourth case is the one that opens something and then
180
187
  does something with what came of it — "save this guest", pressed on a row,
181
188
  replacing the guest once the profile exists. It is not a fourth case and it is
@@ -121,6 +121,15 @@ Reference: `.navi_button_content` in `button_ui.jsx` (a button reads then
121
121
  stops), `.navi_picker_box`, `.navi_input_slot`, `.navi_popover`,
122
122
  `.navi_dialog`.
123
123
 
124
+ **A member drawing the frame itself stops it too**, without being a control. A
125
+ row of settings — a `Field`, a `Label`, a `Box` — that paints a background or a
126
+ border, or that insets what it holds with padding, is what the outer corner
127
+ belongs to; the switch at the right end of that row is not on it. `Box` marks
128
+ itself with `navi-box-frame` for exactly those props and stops the claims for
129
+ everything inside. A wrapper adding neither is only an enrobage — a tooltip, a
130
+ link, a bare `<Box>` — and lets them through to the control that really carries
131
+ the frame.
132
+
124
133
  A control that declares its radius on an inner element instead is invisible to
125
134
  `Group`: it keeps round corners in the middle of the row, and no rule written
126
135
  in `group.jsx` can reach it without naming that private class — which is how a
@@ -94,6 +94,20 @@ Not an error at all, and not to be modelled as one: a value the app or the
94
94
  browser refuses is a **status on the control**, carried by navi's constraint
95
95
  validation. Never throw to reject a value — see `src/control/rules/`.
96
96
 
97
+ An app's own rule joins that set as a constraint — `{ name, check }`, where
98
+ `check(field)` reads `field.uiState` and returns a message or `null`:
99
+
100
+ ```jsx
101
+ <Input constraints={[TEXT_SHAPE_CONSTRAINT]} />; // this control
102
+ registerGlobalConstraint(TEXT_SHAPE_CONSTRAINT); // every control
103
+ ```
104
+
105
+ A constraint is an object, so it carries whatever it needs to decide — there is
106
+ nothing to pass through an attribute. The attributes the shipped constraints
107
+ read (`required`, `data-single-space`, `data-displayable`…) exist because those
108
+ constraints are global and need a per-field switch; a constraint written for
109
+ one call site does not.
110
+
97
111
  ## What a failing action does
98
112
 
99
113
  It writes the error into `errorSignal`, moves to `FAILED`, and stops.
@@ -59,7 +59,16 @@ The available commands: `--navi-open`, `--navi-close`, `--navi-toggle`,
59
59
  `--navi-cancel` (closes, telling the popup the close means "revert"),
60
60
  `--navi-confirm` (says yes, then closes). What "revert" does to what is inside
61
61
  is [its own section](#escape-cancels-the-other-gestures-keep) — it is also what
62
- Escape says.
62
+ Escape says. `--navi-close:all` closes every popup above the button, nearest
63
+ first; a popup that refuses to close keeps the ones above it open too. A link
64
+ that leaves is the usual case — a badge shown over a sheet, both left in one
65
+ press:
66
+
67
+ ```jsx
68
+ <Link href={PLAYER_ROUTE.buildUrl({ playerId })} command="--navi-close:all">
69
+ Profil
70
+ </Link>
71
+ ```
63
72
 
64
73
  ## Something else opens it: `triggerNaviCommand`
65
74
 
@@ -165,9 +165,18 @@ neighbours, a paragraph's lines are unevenly spaced, a truncated label no
165
165
  longer lines up with its siblings.
166
166
 
167
167
  So, first: **an emoji is only expected in free text a user typed** — a message,
168
- a comment, a description. It has no business in a name, a title, an identifier,
169
- a label. Validate those fields so it never gets in, rather than teaching every
170
- row of the app to survive it.
168
+ a comment, a description. It has no business in a title, an identifier, a
169
+ label, and a field holding one of those can refuse it outright rather than
170
+ teaching every row of the app to survive it.
171
+
172
+ A name is the exception worth stating: people are called what they are called,
173
+ and a whitelist on a name field ends up refusing somebody's real name. An app
174
+ taking that side puts `emojiAsIcon` on everything that renders a name, and
175
+ keeps the name field itself to the rules that are about the layout rather than
176
+ the alphabet — `data-displayable`, which refuses only what cannot be drawn:
177
+ marks stacked into zalgo (the one thing `emojiAsIcon` does not rescue, since it
178
+ draws over the row above), a value that shows nothing at all, blank lines in
179
+ series.
171
180
 
172
181
  Where it is expected, `emojiAsIcon`:
173
182
 
@@ -183,6 +192,18 @@ emoji is a 1em box, never a glyph with its own metrics). `Button` and
183
192
  everything around it relies on, a message is free text; `Badge` forwards it,
184
193
  opt-in.
185
194
 
195
+ **It does not go through a component.** Only the strings the `Text` itself
196
+ receives are rewritten, so `<Text emojiAsIcon><UserName /></Text>` does
197
+ nothing at all: the string is inside `UserName`, and that is where
198
+ `renderEmojiAsIcon()` has to be called. Doing it there also spares a `Text`
199
+ that would inject a separator between the name and whatever follows it.
200
+
201
+ There is no way to turn it on for a whole app, on purpose: most of an app's
202
+ text is its own wording, where an emoji cannot appear, and the ones that do
203
+ carry a typed value are known one by one. An app that renders such a value
204
+ everywhere writes its own component around `Text` — the same place it already
205
+ decides how a name is displayed.
206
+
186
207
  What it does not do, and that is accepted: under `maxLines` the `Text` clips at
187
208
  its own box — that is what truncation is — and an emoji drawn a little beyond
188
209
  its 1em box can lose a sliver at the top. The line stays aligned, which is the
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsenv/navi",
3
- "version": "0.29.108",
3
+ "version": "0.29.110",
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.29",
32
+ "@jsenv/dom": "0.17.30",
33
33
  "@jsenv/humanize": "1.7.8",
34
34
  "@jsenv/validity": "0.4.2"
35
35
  },