Skip to content

Commit 92c924f

Browse files
committed
work
1 parent 87e6136 commit 92c924f

21 files changed

Lines changed: 999 additions & 448 deletions

packages/frontend/navi/dist/dev/jsenv_navi.js

Lines changed: 225 additions & 89 deletions
Large diffs are not rendered by default.

packages/frontend/navi/dist/dev/jsenv_navi.js.map

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/frontend/navi/dist/jsenv_navi.js

Lines changed: 215 additions & 87 deletions
Large diffs are not rendered by default.

packages/frontend/navi/dist/jsenv_navi.js.map

Lines changed: 10 additions & 10 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/frontend/navi/docs/AI_INSTRUCTIONS.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -189,8 +189,10 @@ consistency across the app, not from any single call site.
189189
a popup, before writing a close button by hand, and before an
190190
`onOpen`/`onClose` writing a signal.
191191
- `docs/popup_backdrop.md` — what a popup lays between itself and the page
192-
behind: the two independent questions it answers (what an outside press does,
193-
how far what is behind withdraws), where the outside begins for a popup
192+
behind: the three independent questions it answers (whether there is a wall
193+
at all — `backdrop={false}` lets one press both dismiss the popup and reach
194+
what it landed on, which `backdropVariant="invisible"` does NOT do — what an
195+
outside press does, how far what is behind withdraws), where the outside begins for a popup
194196
painting no surface of its own (`data-navi-popup-outside`), the
195197
`backdropColor`/`backdropFilter` props
196198
for one popup and the `--navi-backdrop-*` colour+filter token pairs for the

packages/frontend/navi/docs/popup_backdrop.md

Lines changed: 53 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@ What a `Dialog`, a `Popover` — and everything built on them: `Popup`,
44
`SidePanel`, a `Picker`'s popup — lays between itself and the page it opened
55
over.
66

7-
It answers two questions, and they are independent:
7+
It answers three questions, and they are independent:
88

9+
0. **Is there anything between the popup and the page at all?** That is
10+
`backdrop`.
911
1. **What does a press outside do?** Close, cancel, be absorbed, pass through.
1012
That is `pointerInteractionOutsideEffect`.
1113
2. **How far does what is behind withdraw?** Dimmed, blurred, barely marked,
@@ -15,7 +17,54 @@ It answers two questions, and they are independent:
1517
Keeping them apart is the whole point of this page. A popup that must close on
1618
an outside click — because that click is the way out of the screen — may also
1719
need the page behind to stop competing for the eye. How much it withdraws says
18-
nothing about what the click does.
20+
nothing about what the click does, and neither says whether the page behind is
21+
still reachable.
22+
23+
## Is there a backdrop at all
24+
25+
A backdrop is a wall: a full-screen element in front of the page, which wins
26+
hit-testing. That is how it absorbs a press — not by handling the event and
27+
stopping it, but by being what the pointer hits. Nothing behind it hears
28+
anything.
29+
30+
So a popup that closes on an outside press spends that press: the first press
31+
dismisses, and a second one is needed to do the thing the user was already
32+
pointing at. That is right when the page has withdrawn — the dim says the page
33+
is off, and a press on it means "come back", nothing more.
34+
35+
It is wrong when nothing withdrew. A bubble opened over a map, a plan, a canvas
36+
— a page that looks exactly as pressable as it did a second ago — makes the
37+
next press a natural continuation of the gesture, not a dismissal. Taking it to
38+
close the bubble spends it on something the user never asked for, and on a page
39+
that gave no sign it would.
40+
41+
`backdrop={false}` is how that popup says there is no wall:
42+
43+
```jsx
44+
<Popover pointerInteractionOutsideEffect="close" backdrop={false}>
45+
```
46+
47+
The popup then hears an outside press from the document itself, and takes
48+
nothing from it: no `preventDefault`, no `stopPropagation`. It closes, and the
49+
same press is answered by whatever it landed on — one gesture, one press.
50+
51+
**It is not `backdropVariant="invisible"`.** A wall that is not painted is
52+
still a wall, and it still eats the press; the two props answer different
53+
questions. `"invisible"` is for a popup that must absorb — a menu whose
54+
dismissing click must not also press what is under it — without dimming the
55+
page for it. `backdrop={false}` is for a popup that must not absorb at all.
56+
57+
**Only a non-modal popup can honour it.** `Popover` always can, either layer. A
58+
`Dialog` can only in `layer="local"`: the default `layer="top"` is shown with
59+
`showModal()`, which makes everything behind genuinely inert before any of
60+
navi's code runs — there is no press left to let through, and asking for one
61+
warns. `Popup` follows from that: it forwards `backdrop` to its popover and
62+
drops it for a top-layer dialog, so the same usage that gives one press on a
63+
desktop costs two once the small-screen resolution picks dialog mode.
64+
65+
`pointerInteractionOutsideEffect="capture"` and `backdrop={false}` contradict
66+
each other — absorbing is what a wall does — and navi warns rather than
67+
silently behaving like `"none"`.
1968

2069
## Where the outside begins
2170

@@ -115,7 +164,8 @@ closes on an outside click blurs too.
115164

116165
`backdropVariant` is the shorthand for the other direction: `"discrete"` for a
117166
barely-there dim, `"invisible"` for no paint at all. It never changes what the
118-
outside click does — the backdrop is still there and still catches it.
167+
outside click does — the wall is still there and still catches it. Whether
168+
there is a wall to paint is `backdrop`, above.
119169

120170
`"invisible"` is the one kind with no filter token: it paints nothing, and a
121171
filter would still be seen.

packages/frontend/navi/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@jsenv/navi",
3-
"version": "0.29.204",
3+
"version": "0.29.205",
44
"type": "module",
55
"description": "Library of components including navigation to create frontend applications",
66
"repository": {

packages/frontend/navi/src/control/input/split_button.jsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ const css = /* css */ `
9191
* dialogExpandY?: boolean,
9292
* dockedOnSmallTouchScreen?: boolean,
9393
* marginWithContainer?: number | string,
94+
* backdrop?: boolean,
9495
* backdropVariant?: "auto" | "discrete" | "invisible",
9596
* backdropColor?: string,
9697
* backdropFilter?: string,
@@ -139,8 +140,8 @@ const css = /* css */ `
139140
* `dockedOnSmallTouchScreen`, `dialogExpand*`, `dialogMinWidth`/`Height`,
140141
* `dialogMaxWidth`/`Height`,
141142
* `marginWithContainer`, `popoverMode`, `popoverSpacing`, `popupLayer`,
142-
* `popupTestId`, `popupWidthFitContent`, `popoverMaxHeight`, `backdropVariant`,
143-
* `backdropColor`, `backdropFilter`,
143+
* `popupTestId`, `popupWidthFitContent`, `popoverMaxHeight`, `backdrop`,
144+
* `backdropVariant`, `backdropColor`, `backdropFilter`,
144145
* `pointerInteractionOutsideEffect`, `escapeEffect`, `closeOnFocusOut`,
145146
* `scrollCapture`, `focusCapture`, `popupBackgroundColor`,
146147
* `popupBorderRadius`, `animation`. See picker.jsx for what each one says.
@@ -395,6 +396,7 @@ const POPUP_PROP_SET = new Set([
395396
"dialogExpandY",
396397
"dockedOnSmallTouchScreen",
397398
"marginWithContainer",
399+
"backdrop",
398400
"backdropVariant",
399401
"backdropColor",
400402
"backdropFilter",

packages/frontend/navi/src/control/picker/picker.jsx

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1586,6 +1586,7 @@ const PickerFirstResolver = (props) => {
15861586
* anchor?: import("preact").RefObject<HTMLElement> | HTMLElement,
15871587
* escapeEffect?: "cancel" | "close",
15881588
* pointerInteractionOutsideEffect?: "close" | "cancel" | "capture",
1589+
* backdrop?: boolean,
15891590
* backdropVariant?: "auto" | "discrete" | "invisible",
15901591
* backdropColor?: string,
15911592
* backdropFilter?: string,
@@ -1839,11 +1840,18 @@ const PickerFirstResolver = (props) => {
18391840
* put back the value at open ("cancel"), or nothing at all ("capture"). The
18401841
* default is what gives a popup with no confirm button its way out that
18411842
* keeps — see the same section.
1843+
* @param {boolean} [backdrop=true] Whether anything is laid between the popup
1844+
* and the page at all. `false` lets a press outside both close the popup and
1845+
* reach whatever it landed on, in one gesture — for a picker opened over a
1846+
* page that stays as pressable as it looks (a plan, a map, a canvas), where a
1847+
* wall would spend the first press on dismissing. Only the popover mode can
1848+
* honour it: a dialog is modal and the page behind it is inert.
18421849
* @param {"auto"|"discrete"|"invisible"} [backdropVariant="auto"] How visible the
18431850
* popup's backdrop is, independently of what a click outside does: `"auto"`
18441851
* is the paint `pointerInteractionOutsideEffect` implies, `"discrete"` a
1845-
* barely-there dim, `"invisible"` fully transparent. For a picker that closes on
1846-
* an outside click without wanting to dim the page for it.
1852+
* barely-there dim, `"invisible"` fully transparent — a wall that is not seen
1853+
* is still a wall, which is what `backdrop` above answers. For a picker that
1854+
* closes on an outside click without wanting to dim the page for it.
18471855
* @param {string} [backdropColor] The wash the popup paints over what is
18481856
* behind, for this picker alone. See Dialog's own doc.
18491857
* @param {string} [backdropFilter] What that wash does to the picture

packages/frontend/navi/src/control/picker/picker_custom.jsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,8 @@ const PickerContentInsidePopup = (props) => {
916916
// clicking outside revert instead, or "capture" to keep it open.
917917
pointerInteractionOutsideEffect = "close",
918918
// Named/forwarded rather than left in ...rest: rest goes to the picker
919-
// element itself, not the popup, and this belongs to the popup.
919+
// element itself, not the popup, and these belong to the popup.
920+
backdrop,
920921
backdropVariant,
921922
backdropColor,
922923
backdropFilter,
@@ -1011,6 +1012,7 @@ const PickerContentInsidePopup = (props) => {
10111012
pointerInteractionOutsideEffect={
10121013
pointerLock ? "capture" : pointerInteractionOutsideEffect
10131014
}
1015+
backdrop={backdrop}
10141016
backdropVariant={backdropVariant}
10151017
backdropColor={backdropColor}
10161018
backdropFilter={backdropFilter}

0 commit comments

Comments
 (0)