@jsenv/navi 0.29.299 → 0.29.301
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/dev/jsenv_navi.js +264 -24
- package/dist/dev/jsenv_navi.js.map +9 -9
- package/dist/jsenv_navi.js +188 -19
- package/dist/jsenv_navi.js.map +9 -9
- package/docs/AI_INSTRUCTIONS.md +2 -1
- package/docs/interactions.md +6 -0
- package/docs/popup_open.md +102 -2
- package/package.json +1 -1
package/docs/AI_INSTRUCTIONS.md
CHANGED
|
@@ -157,7 +157,8 @@ to start when unsure which export solves a problem.
|
|
|
157
157
|
|
|
158
158
|
- `popup_open.md` — a popup owns its open state; `command` + `commandfor`;
|
|
159
159
|
`triggerNaviCommand` as the last resort, with the event forwarded and never
|
|
160
|
-
invented; opening ON something; a press that opens and acts is a `Picker
|
|
160
|
+
invented; opening ON something; a press that opens and acts is a `Picker`,
|
|
161
|
+
and its trigger wears the wait and the error (a card that lifts, `openOn`);
|
|
161
162
|
Escape cancels; the close cross; a popup that loads data. Read before passing
|
|
162
163
|
`open`, calling `triggerNaviCommand`, or writing a close button.
|
|
163
164
|
- `popup_backdrop.md` — three independent questions: a wall or not
|
package/docs/interactions.md
CHANGED
|
@@ -98,6 +98,12 @@ which the carrying interactions answer with).
|
|
|
98
98
|
| `pan` `zoom` | a surface under the hand, or under a wheel |
|
|
99
99
|
| `"keyboard:<shortcut>"` | keys, e.g. `"keyboard:ctrl+backspace"` |
|
|
100
100
|
|
|
101
|
+
Two holds on one press — a `longpress` declared on something inside an
|
|
102
|
+
element that declares one too — are answered by the nearer one, the way a
|
|
103
|
+
click is the innermost target's: the inner hold fires, the outer wait is given
|
|
104
|
+
up. Delays being equal; an outer hold made shorter than the inner one fires
|
|
105
|
+
first.
|
|
106
|
+
|
|
101
107
|
A name nothing knows how to detect produces a dev warning naming the detectors
|
|
102
108
|
that exist. The carrying family and the two surface streams each have a file of
|
|
103
109
|
their own — [drag_interactions.md](./drag_interactions.md) and
|
package/docs/popup_open.md
CHANGED
|
@@ -403,6 +403,102 @@ dialog hides: a popup written once, far from every press that opens it, has to
|
|
|
403
403
|
be told what it is about and has to answer somebody — and neither question
|
|
404
404
|
exists once the popup is written where it is used.
|
|
405
405
|
|
|
406
|
+
### The trigger wears the wait
|
|
407
|
+
|
|
408
|
+
The picker's `action` runs on the trigger, not in the popup: it is dispatched
|
|
409
|
+
on the close that keeps, and the popup goes while it runs. So what is still on
|
|
410
|
+
screen answers for the write — `aria-busy` and the loading outline on the
|
|
411
|
+
trigger while the request is out, the error callout on it if the server
|
|
412
|
+
refuses, and the value rolled back to the last accepted one — on by default
|
|
413
|
+
for a picker, and what one wants: nobody is left mid-edit behind a closed
|
|
414
|
+
popup, and the card goes on saying what the server knows. A
|
|
415
|
+
card that IS the trigger (`variant="bare"`, the card as `ui`) therefore waits
|
|
416
|
+
as a card and is refused as a card, wherever in the tree the sheet was written.
|
|
417
|
+
|
|
418
|
+
```jsx
|
|
419
|
+
<Picker
|
|
420
|
+
variant="bare"
|
|
421
|
+
type="object"
|
|
422
|
+
mode="dialog"
|
|
423
|
+
ui={<MatchCard match={match} />}
|
|
424
|
+
value={match}
|
|
425
|
+
action={(next) => MATCH.PATCH({ id: match.id, ...next })}
|
|
426
|
+
>
|
|
427
|
+
<ControlGroup>
|
|
428
|
+
<MatchCard match={match} editable />
|
|
429
|
+
<Button command="--navi-cancel">Cancel</Button>
|
|
430
|
+
<Button command="--navi-send">Save</Button>
|
|
431
|
+
</ControlGroup>
|
|
432
|
+
</Picker>
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
The card shows the answer the moment the sheet leaves when its `ui` is drawn
|
|
436
|
+
from what the picker holds rather than from what the caller knows — the same
|
|
437
|
+
state navi's own default `ui` reads, rolled back by `resetOnError`, so nothing
|
|
438
|
+
about the pending value is the caller's to keep or to put back. Two ways to
|
|
439
|
+
read it: `ui={MatchCard}` hands the component `value`, `loading` and
|
|
440
|
+
`interactive` as props; `ui={<MatchCard match={match} />}` keeps the caller's
|
|
441
|
+
own props and reads the same three with `usePickerState()` inside. The
|
|
442
|
+
`loading` is the wait: navi's loading outline is a two-pixel run around the
|
|
443
|
+
box, which a card-sized trigger draws its own waiting state for.
|
|
444
|
+
|
|
445
|
+
What the picker measures as "changed since open" is what its mirrored group
|
|
446
|
+
holds. A piece of the answer living outside the controls — a seating
|
|
447
|
+
rearranged by drag, kept in component state — has to be held by a control in
|
|
448
|
+
the group too (a named control bound to that state), or a close over it reads
|
|
449
|
+
as nothing changed and nothing runs.
|
|
450
|
+
|
|
451
|
+
Two props finish the construct. `openOn="longpress"` (or
|
|
452
|
+
`["longpress", "contextmenu"]`) makes the hold what opens it, so a tap on the
|
|
453
|
+
card stays a tap — what a card in a list needs: the drawing gets its pointer
|
|
454
|
+
back, a link in it navigates, a button in it presses, a picker in it opens on
|
|
455
|
+
its own click, with nothing to declare. Two pickers on one card is the score
|
|
456
|
+
sheet inside the edit card (`12_picker_card_demo.html`): the inner one names
|
|
457
|
+
the card as its `anchor` so it lifts the whole card, and says `standalone` so
|
|
458
|
+
its value stays its own. One card, one wait: each picker wears the other's
|
|
459
|
+
run through `loading` (from its `onActionStart`/`onActionEnd`), so while
|
|
460
|
+
either write is out the hold and the click are both refused, with the busy
|
|
461
|
+
reason where the finger is — the click only once the score picker says
|
|
462
|
+
`openWhileReadOnly={false}`: a busy picker otherwise still opens, to be read,
|
|
463
|
+
and a sheet of fields to fill in is not that. A hold declared inside the card answers before the
|
|
464
|
+
card's own: the nearer hold takes the press. `animation="growing"` with
|
|
465
|
+
`dialogSizeFromAnchor` (as wide as the card, floor and ceiling),
|
|
466
|
+
`popupBackgroundColor="transparent"` and `popupBoxShadow="none"` lifts the
|
|
467
|
+
card out of its place and puts it back (`data-grow` on the card inside the
|
|
468
|
+
sheet; see Dialog's own `animation`). `12_picker_card_demo.html` shows all of
|
|
469
|
+
it, against a backend that answers when told to.
|
|
470
|
+
|
|
471
|
+
This is not `optimistic`. `optimistic` on a control is "draw no wait at all";
|
|
472
|
+
here the wait is drawn, on the trigger, and the popup was never what held it.
|
|
473
|
+
An optimistic picker is for a write not worth showing — the card then reads
|
|
474
|
+
the store and says nothing until the answer lands.
|
|
475
|
+
|
|
476
|
+
The same shape with nothing to write is a **door**: a drawing that grows to be
|
|
477
|
+
looked at — a weather scene, a plan — and comes back. `picksNothing`, no
|
|
478
|
+
`action`, no `dialogSizeFromAnchor` (it opens precisely to get bigger):
|
|
479
|
+
|
|
480
|
+
```jsx
|
|
481
|
+
<Picker
|
|
482
|
+
picksNothing
|
|
483
|
+
variant="bare"
|
|
484
|
+
mode="dialog"
|
|
485
|
+
ui={scene}
|
|
486
|
+
aria-label="Zoom"
|
|
487
|
+
animation="growing"
|
|
488
|
+
popupBackgroundColor="transparent"
|
|
489
|
+
popupBoxShadow="none"
|
|
490
|
+
>
|
|
491
|
+
<Box data-grow>{scene}</Box>
|
|
492
|
+
</Picker>
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
A `Button` opening a `Dialog` with an `anchor` does the same and is not wrong;
|
|
496
|
+
what the picker removes is the id plumbing (the trigger is the anchor, the
|
|
497
|
+
popup is its own), and what it keeps is the day the drawing becomes editable —
|
|
498
|
+
it is already the thing that wears the wait. The button + shared dialog stays
|
|
499
|
+
the answer for [the two cases where a popup must be
|
|
500
|
+
shared](#when-a-shared-popup-is-still-the-right-answer).
|
|
501
|
+
|
|
406
502
|
### A trigger that is only an icon
|
|
407
503
|
|
|
408
504
|
`variant="icon"` draws no value, and therefore no slot beside one either: the
|
|
@@ -536,8 +632,12 @@ to be hand-written to work around it: `command` next to `action` is that
|
|
|
536
632
|
workaround, done at the one moment where the action has settled and the button
|
|
537
633
|
is no longer busy.
|
|
538
634
|
|
|
539
|
-
|
|
540
|
-
|
|
635
|
+
When what opened the popup is still on screen and should answer for the write
|
|
636
|
+
— its wait, its refusal — the popup was a picker's all along: see [the trigger
|
|
637
|
+
wears the wait](#the-trigger-wears-the-wait). What follows is for the other
|
|
638
|
+
case, a popup nobody stands in for. To close on the press — the answer taken as
|
|
639
|
+
soon as it is given, the save running on its own behind a closed popup — say so
|
|
640
|
+
on the control:
|
|
541
641
|
|
|
542
642
|
```jsx
|
|
543
643
|
<Form command="--navi-close" action={saveScore} optimistic resetOnError>
|