@jsenv/navi 0.29.47 → 0.29.49
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 +176 -66
- package/dist/jsenv_navi.js.map +20 -16
- package/dist/jsenv_navi_side_effects.js +1 -1
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/docs/create_and_edit.md +38 -0
- package/docs/popup_open.md +109 -13
- package/package.json +1 -1
package/docs/popup_open.md
CHANGED
|
@@ -7,6 +7,7 @@ What opens a `Dialog` or a `Popover`, and who owns the fact that it is open.
|
|
|
7
7
|
- [Something else opens it: `triggerNaviCommand`](#something-else-opens-it-triggernavicommand)
|
|
8
8
|
- [Which element receives the command](#which-element-receives-the-command)
|
|
9
9
|
- [The anchor](#the-anchor)
|
|
10
|
+
- [Opening it ON something](#opening-it-on-something)
|
|
10
11
|
- [Reacting to open and close](#reacting-to-open-and-close)
|
|
11
12
|
- [Escape cancels, the other gestures keep](#escape-cancels-the-other-gestures-keep)
|
|
12
13
|
- [When `open` is the right answer, and what it costs](#when-open-is-the-right-answer-and-what-it-costs)
|
|
@@ -124,24 +125,93 @@ The `anchor` prop always wins over whatever the command carried.
|
|
|
124
125
|
event's anchor entirely, for a popover that must never be anchored to whatever
|
|
125
126
|
opened it.
|
|
126
127
|
|
|
127
|
-
##
|
|
128
|
+
## Opening it ON something
|
|
128
129
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
130
|
+
A popup that edits is never only open or closed: it is open **on** something. A
|
|
131
|
+
dialog that is "new radar" from the top of a list and "edit this radar" from a
|
|
132
|
+
row is one dialog with two modes, and the press is the only thing that knows
|
|
133
|
+
which one — so the press says it, with its own value:
|
|
134
|
+
|
|
135
|
+
```jsx
|
|
136
|
+
<Button command="--navi-open" commandfor="radar-dialog">Nouveau radar</Button>
|
|
137
|
+
<Button value={radar.id} command="--navi-open" commandfor="radar-dialog" />
|
|
138
|
+
|
|
139
|
+
<Dialog
|
|
140
|
+
id="radar-dialog"
|
|
141
|
+
unmountWhenClosed
|
|
142
|
+
onOpen={(e) => {
|
|
143
|
+
editedRadarIdSignal.value = e.detail.value; // undefined = création
|
|
144
|
+
}}
|
|
145
|
+
>
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
That subject travels as the command's **value**, not as an argument after a
|
|
149
|
+
colon (`--navi-open:radar-42`). The two places say different things and the
|
|
150
|
+
distinction holds across every command: an argument says WHAT the command does —
|
|
151
|
+
`--navi-go-to-slide:edit` needs one, "go" without a destination is not an
|
|
152
|
+
instruction — and `value` says what it is about. "Open" is already a complete
|
|
153
|
+
instruction; the radar is what it is about. A button therefore says it the way it
|
|
154
|
+
says it everywhere else, with `value`, and nothing has to be parsed.
|
|
155
|
+
|
|
156
|
+
A JS decision says the same thing through the same door:
|
|
133
157
|
|
|
134
158
|
```js
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
159
|
+
triggerNaviCommand(dialogRef.current, "--navi-open", event, {
|
|
160
|
+
value: radar.id,
|
|
161
|
+
});
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
`--navi-toggle` carries it too, on the half that opens.
|
|
165
|
+
|
|
166
|
+
### `onOpen` runs before the popup has built anything
|
|
167
|
+
|
|
168
|
+
The order is the whole point, and it is a guarantee, not a coincidence:
|
|
169
|
+
|
|
170
|
+
```
|
|
171
|
+
onOpen(openEvent) ← the subject is decided here
|
|
172
|
+
children mounted ← unmountWhenClosed rebuilds them from scratch, on that subject
|
|
173
|
+
positioned, shown
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
So a dialog whose content is seeded once — an uncontrolled field on a
|
|
177
|
+
`defaultValue`, a form keyed on what it edits — reads the right thing on its very
|
|
178
|
+
first render. Learning it afterwards would mean mounting on the previous subject
|
|
179
|
+
and correcting it, which is a flicker at best and stale fields at worst.
|
|
180
|
+
|
|
181
|
+
The two other places one could listen are not that moment, and it is worth
|
|
182
|
+
knowing why:
|
|
183
|
+
|
|
184
|
+
| where | when it runs | chained to the caller |
|
|
185
|
+
| ----------------------------- | ------------------------------ | --------------------- |
|
|
186
|
+
| `onOpen` | before the content is built | yes — this prop |
|
|
187
|
+
| `onnavi_command` on the popup | after the command has been run | yes |
|
|
188
|
+
| `navi_request_open` listener | before the popup's own handler | on the element only |
|
|
189
|
+
|
|
190
|
+
`onnavi_command` receives the whole command string and its value, but it runs
|
|
191
|
+
**after** the opening: whatever it writes lands on a popup that is already open.
|
|
192
|
+
That works only as long as nothing has read the state yet — which
|
|
193
|
+
`unmountWhenClosed` makes a real race rather than a theoretical one.
|
|
194
|
+
|
|
195
|
+
A `navi_request_open` listener added on the element is the request itself, ahead
|
|
196
|
+
of the popup acting on it — but it is ordered against the popup's own handler by
|
|
197
|
+
registration, and it has to be attached in an effect on a ref. `onOpen` is that
|
|
198
|
+
moment, said as a prop.
|
|
199
|
+
|
|
200
|
+
## Reacting to open and close
|
|
201
|
+
|
|
202
|
+
`onOpen` is called on every open, before the popup builds anything (see
|
|
203
|
+
[above](#opening-it-on-something)); `onClose` is called on every real close, and
|
|
204
|
+
carries `detail.isCancel` when the close meant "revert".
|
|
205
|
+
|
|
206
|
+
```jsx
|
|
207
|
+
<Dialog onOpen={(e) => {}} onClose={(e) => {}}>
|
|
143
208
|
```
|
|
144
209
|
|
|
210
|
+
Neither can veto: `onClose` is the close happening, not a request to close.
|
|
211
|
+
Refusing a close is `onRequestClose`, which belongs to whoever owns an
|
|
212
|
+
`openController` (see `open_controller.js`) — an uncontrolled popup already
|
|
213
|
+
refuses the one close that matters, the one over a control mid-action.
|
|
214
|
+
|
|
145
215
|
### Closing when a button also runs an action
|
|
146
216
|
|
|
147
217
|
Closing from inside the `action` does not close. While the action runs, the
|
|
@@ -232,6 +302,32 @@ value the app passes it. Escape on that first pass goes back to empty, not to
|
|
|
232
302
|
what was on screen when the popup opened. From the second open onwards it puts
|
|
233
303
|
back what was really there.
|
|
234
304
|
|
|
305
|
+
### A picker that holds nothing and shows nothing
|
|
306
|
+
|
|
307
|
+
The gestures that KEEP (a click outside, a close cross) let a picker send what
|
|
308
|
+
it is showing: a picker sitting on a `defaultValue` holds nothing, so closing on
|
|
309
|
+
it untouched IS the answer ("yes, 1h30"), and the action runs.
|
|
310
|
+
|
|
311
|
+
A picker used as a **menu of gestures** — no `value`, no `defaultValue`, no
|
|
312
|
+
signal, each row a command — shows nothing, so there is nothing to confirm.
|
|
313
|
+
Closing it without choosing runs no action; only an explicit choice sends.
|
|
314
|
+
|
|
315
|
+
```jsx
|
|
316
|
+
// Clicking outside closes this and sends nothing.
|
|
317
|
+
<Picker id="pause" mode="popover" variant="icon" action={pauseAction}>
|
|
318
|
+
<List selectable command="--navi-send">
|
|
319
|
+
<List.Item selectable id="24h" value="24h">
|
|
320
|
+
…
|
|
321
|
+
</List.Item>
|
|
322
|
+
</List>
|
|
323
|
+
</Picker>
|
|
324
|
+
```
|
|
325
|
+
|
|
326
|
+
Note this is about a picker holding NOTHING. Passing `value={undefined}` is not
|
|
327
|
+
that: a `value` prop is held whatever is in it, and navi puts it back after each
|
|
328
|
+
click — the rows then appear to do nothing. Drop the prop instead of passing it
|
|
329
|
+
empty.
|
|
330
|
+
|
|
235
331
|
### `escapeEffect="close"`, and why it is a last resort
|
|
236
332
|
|
|
237
333
|
`escapeEffect="close"` makes Escape say what a click outside says. It exists,
|