@jsenv/navi 0.29.46 → 0.29.48
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 +251 -133
- package/dist/jsenv_navi.js.map +21 -17
- 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/css_architecture.md +52 -0
- package/docs/popup_open.md +83 -13
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -16993,11 +16993,14 @@ const VISUAL_PROPS = {
|
|
|
16993
16993
|
};
|
|
16994
16994
|
const CONTENT_PROPS = {
|
|
16995
16995
|
align: applyOnTwoProps("alignX", "alignY"),
|
|
16996
|
+
/* The value the caller named is always written out, even when it matches
|
|
16997
|
+
CSS's own initial value ("start" for justify-content, "stretch" for
|
|
16998
|
+
align-items). Skipping it as a no-op only holds for a bare element: a
|
|
16999
|
+
component whose stylesheet already centers its content (Picker in its icon
|
|
17000
|
+
variant, for one) would keep centering, and alignX="start" would silently
|
|
17001
|
+
do nothing — the one case where saying it explicitly matters most. */
|
|
16996
17002
|
alignX: (value, { boxFlow }) => {
|
|
16997
17003
|
if (boxFlow === "flex-y" || boxFlow === "inline-flex-y") {
|
|
16998
|
-
if (value === "stretch") {
|
|
16999
|
-
return undefined; // this is the default
|
|
17000
|
-
}
|
|
17001
17004
|
return { alignItems: value };
|
|
17002
17005
|
}
|
|
17003
17006
|
if (
|
|
@@ -17011,18 +17014,12 @@ const CONTENT_PROPS = {
|
|
|
17011
17014
|
boxFlow === "grid" ||
|
|
17012
17015
|
boxFlow === "inline-grid"
|
|
17013
17016
|
) {
|
|
17014
|
-
if (value === "start") {
|
|
17015
|
-
return undefined; // this is the default
|
|
17016
|
-
}
|
|
17017
17017
|
return { justifyContent: value };
|
|
17018
17018
|
}
|
|
17019
17019
|
return { textAlign: value };
|
|
17020
17020
|
},
|
|
17021
17021
|
alignY: (value, { boxFlow }) => {
|
|
17022
17022
|
if (boxFlow === "flex-y" || boxFlow === "inline-flex-y") {
|
|
17023
|
-
if (value === "start") {
|
|
17024
|
-
return undefined;
|
|
17025
|
-
}
|
|
17026
17023
|
return { justifyContent: value };
|
|
17027
17024
|
}
|
|
17028
17025
|
if (
|
|
@@ -17035,9 +17032,6 @@ const CONTENT_PROPS = {
|
|
|
17035
17032
|
boxFlow === "grid" ||
|
|
17036
17033
|
boxFlow === "inline-grid"
|
|
17037
17034
|
) {
|
|
17038
|
-
if (value === "stretch") {
|
|
17039
|
-
return undefined;
|
|
17040
|
-
}
|
|
17041
17035
|
return { alignItems: value };
|
|
17042
17036
|
}
|
|
17043
17037
|
const verticalAlignMap = {
|
|
@@ -22147,7 +22141,10 @@ const useNavState = useNavStateBasic;
|
|
|
22147
22141
|
* @param {Event} event What the user did.
|
|
22148
22142
|
* @param {object} [options]
|
|
22149
22143
|
* @param {boolean} [options.optional] No suitable target is not a warning.
|
|
22150
|
-
* @param {any} [options.value]
|
|
22144
|
+
* @param {any} [options.value] What the command is about, carried to whoever
|
|
22145
|
+
* answers — and, for `--navi-open`/`--navi-toggle`, what the popup is opened
|
|
22146
|
+
* ON: it reaches its `onOpen` before the popup builds anything. Left out, a
|
|
22147
|
+
* source's own value (`<Button value={id}>`) is read instead.
|
|
22151
22148
|
* @param {Element} [options.anchor] Where a popup this opens should be placed,
|
|
22152
22149
|
* when that is not the element asking: a menu opened by a press belongs at the
|
|
22153
22150
|
* point the press happened, and the row that was pressed is not that point.
|
|
@@ -22176,6 +22173,10 @@ const triggerNaviCommand = (
|
|
|
22176
22173
|
// Whatever followed the colon: "--navi-go-to-slide:edit" → "edit".
|
|
22177
22174
|
argument: command.includes(":") ? commandArgument(command) : undefined,
|
|
22178
22175
|
anchor,
|
|
22176
|
+
// What the command is about, said by the caller rather than read off the
|
|
22177
|
+
// source: the attribute form has a `value` to read (`<Button value={id}>`),
|
|
22178
|
+
// a JS decision has none, and both must be able to say the same thing.
|
|
22179
|
+
value,
|
|
22179
22180
|
});
|
|
22180
22181
|
if (!execute) {
|
|
22181
22182
|
if (optional) {
|
|
@@ -22812,28 +22813,42 @@ registerNaviCommand("--navi-nav-to", (source, event, { argument }) => {
|
|
|
22812
22813
|
};
|
|
22813
22814
|
});
|
|
22814
22815
|
|
|
22815
|
-
registerNaviCommand(
|
|
22816
|
-
|
|
22817
|
-
|
|
22818
|
-
|
|
22819
|
-
|
|
22820
|
-
|
|
22821
|
-
|
|
22822
|
-
|
|
22823
|
-
|
|
22824
|
-
|
|
22825
|
-
|
|
22826
|
-
|
|
22827
|
-
|
|
22828
|
-
|
|
22829
|
-
|
|
22830
|
-
|
|
22831
|
-
|
|
22832
|
-
|
|
22833
|
-
|
|
22834
|
-
|
|
22835
|
-
|
|
22836
|
-
|
|
22816
|
+
registerNaviCommand(
|
|
22817
|
+
"--navi-toggle",
|
|
22818
|
+
(source, event, { anchor, value } = {}) => {
|
|
22819
|
+
const target =
|
|
22820
|
+
resolveExplicitTarget(source) || resolveClosestExpandable(source);
|
|
22821
|
+
if (!target) {
|
|
22822
|
+
return undefined;
|
|
22823
|
+
}
|
|
22824
|
+
return {
|
|
22825
|
+
target,
|
|
22826
|
+
implementation: () => {
|
|
22827
|
+
const isExpanded = target.getAttribute("aria-expanded") === "true";
|
|
22828
|
+
const customEventName = isExpanded
|
|
22829
|
+
? "navi_request_close"
|
|
22830
|
+
: "navi_request_open";
|
|
22831
|
+
return dispatchCustomEvent(target, customEventName, {
|
|
22832
|
+
event,
|
|
22833
|
+
source: resolveCommandProxySource(source),
|
|
22834
|
+
anchor,
|
|
22835
|
+
// Same as --navi-open below: the half of the toggle that opens says
|
|
22836
|
+
// what it opens ON, and the half that closes carries it too so the
|
|
22837
|
+
// popup never has to ask which half it just heard.
|
|
22838
|
+
value:
|
|
22839
|
+
value === undefined ? resolveCommandValue(source, event) : value,
|
|
22840
|
+
});
|
|
22841
|
+
},
|
|
22842
|
+
};
|
|
22843
|
+
},
|
|
22844
|
+
);
|
|
22845
|
+
// A popup that edits opens ON something, and the press is the only place that
|
|
22846
|
+
// knows which one. It says it with `value` — "what this is about", as
|
|
22847
|
+
// everywhere else — rather than with an argument, which says what the command
|
|
22848
|
+
// DOES: "open" is already a complete instruction, unlike --navi-go-to-slide.
|
|
22849
|
+
// <Button value={radar.id} command="--navi-open" commandfor="radar-dialog">
|
|
22850
|
+
// The popup is told before it opens — see Dialog/Popover's `onOpen`.
|
|
22851
|
+
registerNaviCommand("--navi-open", (source, event, { anchor, value } = {}) => {
|
|
22837
22852
|
const target =
|
|
22838
22853
|
resolveExplicitTarget(source) || resolveClosestExpandable(source);
|
|
22839
22854
|
if (!target) {
|
|
@@ -22849,6 +22864,7 @@ registerNaviCommand("--navi-open", (source, event, { anchor } = {}) => {
|
|
|
22849
22864
|
event,
|
|
22850
22865
|
source: resolveCommandProxySource(source),
|
|
22851
22866
|
anchor,
|
|
22867
|
+
value: value === undefined ? resolveCommandValue(source, event) : value,
|
|
22852
22868
|
});
|
|
22853
22869
|
},
|
|
22854
22870
|
};
|
|
@@ -27021,37 +27037,45 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
27021
27037
|
--x-button-border-color: var(--callout-color);
|
|
27022
27038
|
}
|
|
27023
27039
|
|
|
27040
|
+
/* A variant states what the caller did NOT: the frameless ones below move
|
|
27041
|
+
the DEFAULTS (--button-*) and never the resolved values (--x-button-*),
|
|
27042
|
+
so a backgroundColor/background/borderColor prop — which lands inline on
|
|
27043
|
+
this same element — still wins. Two things come with that: the
|
|
27044
|
+
transparent default is written as a fallback of --button-background, so
|
|
27045
|
+
the background prop feeds --button-background-color through it; and the
|
|
27046
|
+
per-state defaults are re-pointed at the base one, otherwise the @layer
|
|
27047
|
+
formulas (hover = 5% black over the background, readonly = the same)
|
|
27048
|
+
would repaint a box the variant just took away. */
|
|
27049
|
+
|
|
27024
27050
|
/* discrete: background on hover, and nothing else — no box at rest, and no
|
|
27025
27051
|
shrink when pressed. What is drawn IS the content (a chevron, a number,
|
|
27026
27052
|
a word), and shrinking it under the finger reads as the content itself
|
|
27027
27053
|
flinching rather than as a button being pressed. */
|
|
27028
27054
|
&[data-variant="discrete"] {
|
|
27029
27055
|
--button-border-width: 0;
|
|
27030
|
-
--
|
|
27031
|
-
--
|
|
27056
|
+
--button-border-color: transparent;
|
|
27057
|
+
--button-border-color-hover: var(--button-border-color);
|
|
27058
|
+
--button-border-color-current: var(--button-border-color);
|
|
27059
|
+
--button-border-color-readonly: var(--button-border-color);
|
|
27060
|
+
--button-border-color-disabled: var(--button-border-color);
|
|
27061
|
+
--button-background-color: var(--button-background, transparent);
|
|
27062
|
+
/* The hover wash is mixed INTO the background instead of replacing it:
|
|
27063
|
+
over the transparent default it is exactly the 8% of currentColor it
|
|
27064
|
+
has always been, and over a backgroundColor the caller gave it darkens
|
|
27065
|
+
that color rather than erasing it. */
|
|
27066
|
+
--button-background-color-hover: color-mix(
|
|
27067
|
+
in srgb,
|
|
27068
|
+
currentColor 8%,
|
|
27069
|
+
var(--button-background-color)
|
|
27070
|
+
);
|
|
27071
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27072
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27032
27073
|
|
|
27033
27074
|
&[data-pressed] {
|
|
27034
27075
|
.navi_button_content {
|
|
27035
27076
|
transform: none;
|
|
27036
27077
|
}
|
|
27037
27078
|
}
|
|
27038
|
-
|
|
27039
|
-
&[data-hover] {
|
|
27040
|
-
--x-button-border-color: transparent;
|
|
27041
|
-
--x-button-background-color: color-mix(
|
|
27042
|
-
in srgb,
|
|
27043
|
-
currentColor 8%,
|
|
27044
|
-
transparent
|
|
27045
|
-
);
|
|
27046
|
-
}
|
|
27047
|
-
&[data-readonly] {
|
|
27048
|
-
--x-button-border-color: transparent;
|
|
27049
|
-
--x-button-background-color: transparent;
|
|
27050
|
-
}
|
|
27051
|
-
&[data-disabled] {
|
|
27052
|
-
--x-button-border-color: transparent;
|
|
27053
|
-
--x-button-background-color: transparent;
|
|
27054
|
-
}
|
|
27055
27079
|
}
|
|
27056
27080
|
/* bare: discrete, minus the background on hover. For a control whose own
|
|
27057
27081
|
drawing IS the button (a carousel bullet, a swatch), where a box lighting
|
|
@@ -27060,13 +27084,16 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
27060
27084
|
on focus, commandable. */
|
|
27061
27085
|
&[data-variant="bare"] {
|
|
27062
27086
|
--button-border-width: 0;
|
|
27063
|
-
--
|
|
27064
|
-
--
|
|
27087
|
+
--button-border-color: transparent;
|
|
27088
|
+
--button-border-color-hover: var(--button-border-color);
|
|
27089
|
+
--button-border-color-current: var(--button-border-color);
|
|
27090
|
+
--button-border-color-readonly: var(--button-border-color);
|
|
27091
|
+
--button-border-color-disabled: var(--button-border-color);
|
|
27092
|
+
--button-background-color: var(--button-background, transparent);
|
|
27093
|
+
--button-background-color-hover: var(--button-background-color);
|
|
27094
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27095
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27065
27096
|
|
|
27066
|
-
&[data-hover] {
|
|
27067
|
-
--x-button-background-color: transparent;
|
|
27068
|
-
--x-button-border-color: transparent;
|
|
27069
|
-
}
|
|
27070
27097
|
&[data-pressed] {
|
|
27071
27098
|
.navi_button_content {
|
|
27072
27099
|
transform: none;
|
|
@@ -27075,36 +27102,34 @@ installImportMetaCssBuild(import.meta);const css$W = /* css */`
|
|
|
27075
27102
|
}
|
|
27076
27103
|
/* discrete-border: border on hover */
|
|
27077
27104
|
&[data-variant="discrete-border"] {
|
|
27078
|
-
--
|
|
27105
|
+
--button-background-color: var(--button-background, transparent);
|
|
27106
|
+
--button-background-color-hover: var(--button-background-color);
|
|
27107
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27108
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27109
|
+
/* The border is the whole point of this variant: it is absent at rest
|
|
27110
|
+
and drawn on hover, so only the resting color goes transparent — the
|
|
27111
|
+
hover one keeps the @layer formula, now mixed from whatever
|
|
27112
|
+
borderColor the caller gave. */
|
|
27079
27113
|
--x-button-border-color: transparent;
|
|
27080
27114
|
|
|
27081
27115
|
&[data-hover] {
|
|
27082
27116
|
--x-button-border-color: var(--button-border-color-hover);
|
|
27083
27117
|
}
|
|
27084
|
-
&[data-readonly]
|
|
27085
|
-
--x-button-border-color: transparent;
|
|
27086
|
-
}
|
|
27118
|
+
&[data-readonly],
|
|
27087
27119
|
&[data-disabled] {
|
|
27088
27120
|
--x-button-border-color: transparent;
|
|
27089
27121
|
}
|
|
27090
27122
|
}
|
|
27091
27123
|
/* border variant: no background, border only */
|
|
27092
27124
|
&[data-variant="border"] {
|
|
27093
|
-
--
|
|
27094
|
-
|
|
27095
|
-
|
|
27096
|
-
|
|
27097
|
-
|
|
27098
|
-
|
|
27099
|
-
|
|
27100
|
-
|
|
27101
|
-
}
|
|
27102
|
-
&[data-readonly] {
|
|
27103
|
-
--x-button-background-color: transparent;
|
|
27104
|
-
}
|
|
27105
|
-
&[data-disabled] {
|
|
27106
|
-
--x-button-background-color: transparent;
|
|
27107
|
-
}
|
|
27125
|
+
--button-background-color: var(--button-background, transparent);
|
|
27126
|
+
--button-background-color-hover: color-mix(
|
|
27127
|
+
in srgb,
|
|
27128
|
+
currentColor 8%,
|
|
27129
|
+
var(--button-background-color)
|
|
27130
|
+
);
|
|
27131
|
+
--button-background-color-readonly: var(--button-background-color);
|
|
27132
|
+
--button-background-color-disabled: var(--button-background-color);
|
|
27108
27133
|
}
|
|
27109
27134
|
/* Last word on the shrink, over whatever the variant decided: the variant
|
|
27110
27135
|
guesses from how the button is drawn, and that guess is wrong as soon as
|
|
@@ -27790,7 +27815,8 @@ const getFocusedBeforeTransfer = (e) => {
|
|
|
27790
27815
|
* - `onClose(e)`: actually closing, not preventable — final reactions live here.
|
|
27791
27816
|
*
|
|
27792
27817
|
* The controller exposes matching action methods:
|
|
27793
|
-
* - `open()`: requests opening —
|
|
27818
|
+
* - `open()`: requests opening — calls the caller's `onOpen` (see below), then
|
|
27819
|
+
* `mountContent`/`openEffect`, then `openHandler`.
|
|
27794
27820
|
* - `requestClose()`: requests closing — calls `onRequestClose` then `onClose`,
|
|
27795
27821
|
* stopping after the first if denied. The popup may choose to stay open.
|
|
27796
27822
|
* - `close()`: closes for real — calls only `onClose`, skipping
|
|
@@ -27960,6 +27986,13 @@ const createOpenController = (
|
|
|
27960
27986
|
// content is still waiting for a first open to be built. Called below,
|
|
27961
27987
|
// before openEffect, so the popup measures and positions the real thing.
|
|
27962
27988
|
mountContent: null,
|
|
27989
|
+
// The caller's own `onOpen`, set by Dialog/Popover from their props on
|
|
27990
|
+
// every render (like openEffect). Called BEFORE mountContent, so whatever
|
|
27991
|
+
// it decides — which record this dialog is opening on — is already true by
|
|
27992
|
+
// the time the content is built, positioned and shown. That order is the
|
|
27993
|
+
// whole point: learning it afterwards means the content mounted on the
|
|
27994
|
+
// previous subject first.
|
|
27995
|
+
onOpen: null,
|
|
27963
27996
|
// The counterpart, set only when the popup was told to throw its content
|
|
27964
27997
|
// away on close (`unmountWhenClosed`). Called from performClose above.
|
|
27965
27998
|
unmountContent: null,
|
|
@@ -28016,6 +28049,10 @@ const createOpenController = (
|
|
|
28016
28049
|
}
|
|
28017
28050
|
};
|
|
28018
28051
|
};
|
|
28052
|
+
// Before mountContent, which builds the content, and before openEffect,
|
|
28053
|
+
// which shows it: what the popup opens ON has to be known before either
|
|
28054
|
+
// (see `onOpen` above).
|
|
28055
|
+
controller.onOpen?.(requestOpenEvent);
|
|
28019
28056
|
// After prepareFocusTransfer, which has to record what held the focus
|
|
28020
28057
|
// before anything inside the popup can claim it, and before openEffect,
|
|
28021
28058
|
// which measures the popup to place it.
|
|
@@ -29026,16 +29063,16 @@ const css$V = /* css */`
|
|
|
29026
29063
|
backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
29027
29064
|
}
|
|
29028
29065
|
|
|
29029
|
-
/*
|
|
29066
|
+
/* backdropVariant, keyed off the originating element (a
|
|
29030
29067
|
pseudo-element carries no attributes of its own — same reasoning as
|
|
29031
29068
|
the capture rule just above). After the rules it overrides: same
|
|
29032
29069
|
specificity, so order is what decides. showModal() still makes the
|
|
29033
29070
|
page inert either way — only the paint goes away. */
|
|
29034
|
-
&[data-backdrop-
|
|
29071
|
+
&[data-backdrop-variant="discrete"]::backdrop {
|
|
29035
29072
|
background: var(--navi-backdrop-discrete-background);
|
|
29036
29073
|
backdrop-filter: none;
|
|
29037
29074
|
}
|
|
29038
|
-
&[data-backdrop-
|
|
29075
|
+
&[data-backdrop-variant="invisible"]::backdrop {
|
|
29039
29076
|
background: transparent;
|
|
29040
29077
|
backdrop-filter: none;
|
|
29041
29078
|
}
|
|
@@ -29162,11 +29199,11 @@ const css$V = /* css */`
|
|
|
29162
29199
|
/* Same override as the via-attribute renderer's own ::backdrop rules
|
|
29163
29200
|
above, on the real element this renderer uses instead — see them for
|
|
29164
29201
|
the specificity/ordering reasoning. */
|
|
29165
|
-
&[data-backdrop-
|
|
29202
|
+
&[data-backdrop-variant="discrete"] {
|
|
29166
29203
|
background: var(--navi-backdrop-discrete-background);
|
|
29167
29204
|
backdrop-filter: none;
|
|
29168
29205
|
}
|
|
29169
|
-
&[data-backdrop-
|
|
29206
|
+
&[data-backdrop-variant="invisible"] {
|
|
29170
29207
|
background: transparent;
|
|
29171
29208
|
backdrop-filter: none;
|
|
29172
29209
|
}
|
|
@@ -29245,11 +29282,11 @@ const css$V = /* css */`
|
|
|
29245
29282
|
* both just absorb the click without closing (visually dimmed backdrop vs.
|
|
29246
29283
|
* not) — a dialog is always modal one way or another, so there's always
|
|
29247
29284
|
* at least a click-absorbing backdrop regardless of this prop.
|
|
29248
|
-
* @param {"auto"|"discrete"|"
|
|
29285
|
+
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
|
|
29249
29286
|
* visible the backdrop is, independently of what it does. `"auto"`: the
|
|
29250
29287
|
* paint `pointerInteractionOutsideEffect` implies (dimmed for
|
|
29251
29288
|
* `"close"`/`"cancel"`, blurred glass for `"capture"`). `"discrete"`: a
|
|
29252
|
-
* barely-there dim. `"
|
|
29289
|
+
* barely-there dim. `"invisible"`: fully transparent. The dialog stays modal
|
|
29253
29290
|
* either way — this only changes how much it insists visually, never what
|
|
29254
29291
|
* an outside click does or whether the page behind stays reachable.
|
|
29255
29292
|
* @param {boolean} [props.scrollCapture] - Traps scroll gestures inside the
|
|
@@ -29305,6 +29342,13 @@ const css$V = /* css */`
|
|
|
29305
29342
|
* for the user to see it transition away from. `"interaction"` says the
|
|
29306
29343
|
* opposite — this dialog is mounted *because* the user just asked for it, so
|
|
29307
29344
|
* the mount is the opening and the entrance plays like any other.
|
|
29345
|
+
* @param {(openEvent: CustomEvent) => void} [props.onOpen] - Called when it
|
|
29346
|
+
* opens, BEFORE its content is built, positioned or shown. What it opens ON
|
|
29347
|
+
* is in `openEvent.detail.value` — the value of whatever asked
|
|
29348
|
+
* (`<Button value={radar.id} command="--navi-open" commandfor="…">`), or the
|
|
29349
|
+
* `value` given to `triggerNaviCommand`. That order is the point: a dialog that
|
|
29350
|
+
* is "new" or "edit X" depending on the press must know which one it is
|
|
29351
|
+
* before what it holds is rendered.
|
|
29308
29352
|
* @param {(event: Event) => void} [props.onClose] - Called when the dialog
|
|
29309
29353
|
* actually closes — not preventable (see `open_controller.js`'s own
|
|
29310
29354
|
* `onRequestClose`/`onClose` distinction; `onRequestClose` is where you'd
|
|
@@ -29379,7 +29423,11 @@ const UncontrolledDialog = props => {
|
|
|
29379
29423
|
openController: openController,
|
|
29380
29424
|
onnavi_request_open: e => {
|
|
29381
29425
|
openController.open(e, {
|
|
29382
|
-
anchor: e.detail?.anchor ?? e.detail?.source
|
|
29426
|
+
anchor: e.detail?.anchor ?? e.detail?.source,
|
|
29427
|
+
// What the command was about — a `<Button value={id}>` that opened
|
|
29428
|
+
// this popup ON that id. Handed to `onOpen` before anything is
|
|
29429
|
+
// built (see open_controller.js).
|
|
29430
|
+
value: e.detail?.value
|
|
29383
29431
|
});
|
|
29384
29432
|
},
|
|
29385
29433
|
onnavi_request_close: e => {
|
|
@@ -29503,7 +29551,7 @@ const useDialogProps = props => {
|
|
|
29503
29551
|
// *does* (that's pointerInteractionOutsideEffect above). A dialog is
|
|
29504
29552
|
// always modal, so "none" here never makes the page behind reachable:
|
|
29505
29553
|
// it only stops the dim from being drawn.
|
|
29506
|
-
|
|
29554
|
+
backdropVariant = "auto",
|
|
29507
29555
|
scrollCapture: scrollCaptureProp,
|
|
29508
29556
|
// "auto" (default) → the dialog follows its content. "frozen" → measured
|
|
29509
29557
|
// once, held at that size while open. See this prop's own JSDoc above.
|
|
@@ -29522,11 +29570,20 @@ const useDialogProps = props => {
|
|
|
29522
29570
|
// instead, so it's read here rather than left in `rest`.
|
|
29523
29571
|
autoFocus = "last-resort",
|
|
29524
29572
|
onKeyDown,
|
|
29573
|
+
// Read here (rather than left in `rest`) for two reasons: it must never
|
|
29574
|
+
// reach the DOM as an `onopen` attribute, and the controller — not this
|
|
29575
|
+
// render — is what calls it, at the one moment that makes it useful (see
|
|
29576
|
+
// openController.onOpen below).
|
|
29577
|
+
onOpen,
|
|
29525
29578
|
children: childrenProp,
|
|
29526
29579
|
mountWhenClosed,
|
|
29527
29580
|
unmountWhenClosed,
|
|
29528
29581
|
...rest
|
|
29529
29582
|
} = props;
|
|
29583
|
+
// Assigned on every render, like openEffect below, so it always closes over
|
|
29584
|
+
// the latest prop. Called by openController.open() before the content is
|
|
29585
|
+
// built: what this popup opens ON is known before anything reads it.
|
|
29586
|
+
openController.onOpen = onOpen || null;
|
|
29530
29587
|
const children = usePopupContentMount(openController, props.ref, {
|
|
29531
29588
|
children: childrenProp,
|
|
29532
29589
|
mountWhenClosed,
|
|
@@ -30025,7 +30082,7 @@ const useDialogProps = props => {
|
|
|
30025
30082
|
"styleCSSVars": DIALOG_STYLE_CSS_VARS,
|
|
30026
30083
|
"animationDuration": rest.animationDuration,
|
|
30027
30084
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
30028
|
-
"data-backdrop-
|
|
30085
|
+
"data-backdrop-variant": backdropVariant
|
|
30029
30086
|
});
|
|
30030
30087
|
Object.assign(contentProps, {
|
|
30031
30088
|
tabIndex,
|
|
@@ -30058,7 +30115,7 @@ const useDialogProps = props => {
|
|
|
30058
30115
|
// ::backdrop, same "a pseudo-element can't carry attributes" reasoning
|
|
30059
30116
|
// as the prop just above (and harmless for the custom renderer, whose
|
|
30060
30117
|
// real backdrop element gets it via backdropProps).
|
|
30061
|
-
"data-backdrop-
|
|
30118
|
+
"data-backdrop-variant": backdropVariant,
|
|
30062
30119
|
"styleCSSVars": DIALOG_STYLE_CSS_VARS,
|
|
30063
30120
|
...rest,
|
|
30064
30121
|
...autoFocusProps,
|
|
@@ -30463,16 +30520,16 @@ const css$U = /* css */`
|
|
|
30463
30520
|
backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
30464
30521
|
}
|
|
30465
30522
|
|
|
30466
|
-
/*
|
|
30523
|
+
/* backdropVariant overrides whatever the effect above picked — same
|
|
30467
30524
|
specificity (class + one attribute), so these have to stay *after*
|
|
30468
30525
|
them to win. Only the paint changes: the element is still rendered
|
|
30469
30526
|
and still pointer-events: auto, so an outside click keeps doing
|
|
30470
30527
|
exactly what pointerInteractionOutsideEffect says. */
|
|
30471
|
-
&[data-backdrop-
|
|
30528
|
+
&[data-backdrop-variant="discrete"] {
|
|
30472
30529
|
background: var(--navi-backdrop-discrete-background);
|
|
30473
30530
|
backdrop-filter: none;
|
|
30474
30531
|
}
|
|
30475
|
-
&[data-backdrop-
|
|
30532
|
+
&[data-backdrop-variant="invisible"] {
|
|
30476
30533
|
background: transparent;
|
|
30477
30534
|
backdrop-filter: none;
|
|
30478
30535
|
}
|
|
@@ -30540,11 +30597,11 @@ const css$U = /* css */`
|
|
|
30540
30597
|
* absorbs the click (dims the backdrop) without closing. Note this
|
|
30541
30598
|
* default differs from `Dialog`'s own (`"close"`) — a popover is
|
|
30542
30599
|
* typically a lightweight, non-modal affordance.
|
|
30543
|
-
* @param {"auto"|"discrete"|"
|
|
30600
|
+
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
|
|
30544
30601
|
* visible the backdrop is, independently of what it does. `"auto"`: the
|
|
30545
30602
|
* paint `pointerInteractionOutsideEffect` implies (dimmed for
|
|
30546
30603
|
* `"close"`/`"cancel"`, blurred glass for `"capture"`). `"discrete"`: a
|
|
30547
|
-
* barely-there dim. `"
|
|
30604
|
+
* barely-there dim. `"invisible"`: fully transparent. The backdrop is still
|
|
30548
30605
|
* rendered and still catches outside clicks in every case — this only
|
|
30549
30606
|
* changes how much the popover insists on being the thing you deal with.
|
|
30550
30607
|
* Ignored when `pointerInteractionOutsideEffect="none"` (there is no
|
|
@@ -30607,6 +30664,13 @@ const css$U = /* css */`
|
|
|
30607
30664
|
* for the user to see it transition away from. `"interaction"` says the
|
|
30608
30665
|
* opposite — this popover is mounted *because* the user just asked for it, so
|
|
30609
30666
|
* the mount is the opening and the entrance plays like any other.
|
|
30667
|
+
* @param {(openEvent: CustomEvent) => void} [props.onOpen] - Called when it
|
|
30668
|
+
* opens, BEFORE its content is built, positioned or shown. What it opens ON
|
|
30669
|
+
* is in `openEvent.detail.value` — the value of whatever asked
|
|
30670
|
+
* (`<Button value={radar.id} command="--navi-open" commandfor="…">`), or the
|
|
30671
|
+
* `value` given to `triggerNaviCommand`. That order is the point: a popover that
|
|
30672
|
+
* is "new" or "edit X" depending on the press must know which one it is
|
|
30673
|
+
* before what it holds is rendered.
|
|
30610
30674
|
* @param {(event: Event) => void} [props.onClose] - Called when the popover
|
|
30611
30675
|
* actually closes — not preventable (see `open_controller.js`'s own
|
|
30612
30676
|
* `onRequestClose`/`onClose` distinction; `onRequestClose` is where you'd
|
|
@@ -30679,7 +30743,11 @@ const UncontrolledPopover = props => {
|
|
|
30679
30743
|
openController: openController,
|
|
30680
30744
|
onnavi_request_open: e => {
|
|
30681
30745
|
openController.open(e, {
|
|
30682
|
-
anchor: e.detail?.anchor ?? e.detail?.source
|
|
30746
|
+
anchor: e.detail?.anchor ?? e.detail?.source,
|
|
30747
|
+
// What the command was about — a `<Button value={id}>` that opened
|
|
30748
|
+
// this popup ON that id. Handed to `onOpen` before anything is
|
|
30749
|
+
// built (see open_controller.js).
|
|
30750
|
+
value: e.detail?.value
|
|
30683
30751
|
});
|
|
30684
30752
|
},
|
|
30685
30753
|
onnavi_request_close: e => {
|
|
@@ -30797,7 +30865,7 @@ const usePopoverProps = props => {
|
|
|
30797
30865
|
// *does* (that's pointerInteractionOutsideEffect above). "auto" keeps
|
|
30798
30866
|
// the paint the effect implies; "discrete"/"none" tone it down or
|
|
30799
30867
|
// remove it entirely without giving up the outside click.
|
|
30800
|
-
|
|
30868
|
+
backdropVariant = "auto",
|
|
30801
30869
|
scrollCapture,
|
|
30802
30870
|
focusCapture,
|
|
30803
30871
|
// "auto" (default) → the popover follows its content. "frozen" → measured
|
|
@@ -30817,11 +30885,20 @@ const usePopoverProps = props => {
|
|
|
30817
30885
|
// instead, so it's read here rather than left in `rest`.
|
|
30818
30886
|
autoFocus = "last-resort",
|
|
30819
30887
|
onKeyDown,
|
|
30888
|
+
// Read here (rather than left in `rest`) for two reasons: it must never
|
|
30889
|
+
// reach the DOM as an `onopen` attribute, and the controller — not this
|
|
30890
|
+
// render — is what calls it, at the one moment that makes it useful (see
|
|
30891
|
+
// openController.onOpen below).
|
|
30892
|
+
onOpen,
|
|
30820
30893
|
children: childrenProp,
|
|
30821
30894
|
mountWhenClosed,
|
|
30822
30895
|
unmountWhenClosed,
|
|
30823
30896
|
...rest
|
|
30824
30897
|
} = props;
|
|
30898
|
+
// Assigned on every render, like openEffect below, so it always closes over
|
|
30899
|
+
// the latest prop. Called by openController.open() before the content is
|
|
30900
|
+
// built: what this popup opens ON is known before anything reads it.
|
|
30901
|
+
openController.onOpen = onOpen || null;
|
|
30825
30902
|
const children = usePopupContentMount(openController, props.ref, {
|
|
30826
30903
|
children: childrenProp,
|
|
30827
30904
|
mountWhenClosed,
|
|
@@ -31471,7 +31548,7 @@ const usePopoverProps = props => {
|
|
|
31471
31548
|
"styleCSSVars": POPUP_STYLE_CSS_VARS,
|
|
31472
31549
|
"animationDuration": rest.animationDuration,
|
|
31473
31550
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
31474
|
-
"data-backdrop-
|
|
31551
|
+
"data-backdrop-variant": backdropVariant,
|
|
31475
31552
|
"onMouseDown": mouseDownEvent => {
|
|
31476
31553
|
if (mouseDownEvent.button !== 0) {
|
|
31477
31554
|
return;
|
|
@@ -51824,7 +51901,7 @@ const css$z = /* css */`
|
|
|
51824
51901
|
* is unavoidably *more* intrusive once it switches to dialog mode than
|
|
51825
51902
|
* the exact same usage would be as a popover — worth keeping in mind for
|
|
51826
51903
|
* anything that relies on `Popup` and can end up on a small screen.
|
|
51827
|
-
* @param {"auto"|"discrete"|"
|
|
51904
|
+
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant] - Forwarded
|
|
51828
51905
|
* as-is to whichever component renders (both understand it identically):
|
|
51829
51906
|
* how visible the backdrop is, independently of what an outside click
|
|
51830
51907
|
* does. Unlike `pointerInteractionOutsideEffect` above, this one needs no
|
|
@@ -52552,7 +52629,7 @@ const PickerContentInsidePopup = props => {
|
|
|
52552
52629
|
pointerInteractionOutsideEffect = "close",
|
|
52553
52630
|
// Named/forwarded rather than left in ...rest: rest goes to the picker
|
|
52554
52631
|
// element itself, not the popup, and this belongs to the popup.
|
|
52555
|
-
|
|
52632
|
+
backdropVariant,
|
|
52556
52633
|
dialogExpand,
|
|
52557
52634
|
dialogExpandX,
|
|
52558
52635
|
dialogExpandY,
|
|
@@ -52603,7 +52680,7 @@ const PickerContentInsidePopup = props => {
|
|
|
52603
52680
|
marginWithContainer: marginWithContainer === undefined && isPopover ? popoverSpacing : marginWithContainer,
|
|
52604
52681
|
scrollCapture: scrollCapture,
|
|
52605
52682
|
pointerInteractionOutsideEffect: pointerLock ? "capture" : pointerInteractionOutsideEffect,
|
|
52606
|
-
|
|
52683
|
+
backdropVariant: backdropVariant,
|
|
52607
52684
|
focusCapture: isPopover ? focusCapture : undefined,
|
|
52608
52685
|
expand: isPopover ? undefined : dialogExpand,
|
|
52609
52686
|
expandX: isPopover ? undefined : dialogExpandX,
|
|
@@ -59102,6 +59179,12 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59102
59179
|
transparent
|
|
59103
59180
|
);
|
|
59104
59181
|
--picker-icon-color-disabled: var(--picker-icon-color-readonly);
|
|
59182
|
+
/* Where the slots sit INSIDE the box, visible only once the box is bigger
|
|
59183
|
+
than what it holds (a width/height the caller gave it). Distinct from
|
|
59184
|
+
textAlign, which places the text inside the value slot; this places the
|
|
59185
|
+
slots themselves. */
|
|
59186
|
+
--picker-align-x-default: flex-start;
|
|
59187
|
+
--picker-align-y-default: center;
|
|
59105
59188
|
}
|
|
59106
59189
|
}
|
|
59107
59190
|
|
|
@@ -59138,6 +59221,8 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59138
59221
|
);
|
|
59139
59222
|
--x-picker-color: var(--picker-color);
|
|
59140
59223
|
--x-picker-icon-color: var(--picker-icon-color);
|
|
59224
|
+
--x-picker-align-x: var(--picker-align-x, var(--picker-align-x-default));
|
|
59225
|
+
--x-picker-align-y: var(--picker-align-y, var(--picker-align-y-default));
|
|
59141
59226
|
|
|
59142
59227
|
/* Deliberately NOT positioned: the popup children live in here, and a
|
|
59143
59228
|
layer="local" Popover/Dialog takes its nearest positioned ancestor as
|
|
@@ -59177,7 +59262,8 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59177
59262
|
padding-left: 0;
|
|
59178
59263
|
flex: 1 1 auto;
|
|
59179
59264
|
flex-direction: row;
|
|
59180
|
-
align-items:
|
|
59265
|
+
align-items: var(--x-picker-align-y);
|
|
59266
|
+
justify-content: var(--x-picker-align-x);
|
|
59181
59267
|
background-color: var(--x-picker-background-color);
|
|
59182
59268
|
border-width: var(--picker-border-width);
|
|
59183
59269
|
border-style: solid;
|
|
@@ -59279,7 +59365,7 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59279
59365
|
}
|
|
59280
59366
|
&[navi-single-line] {
|
|
59281
59367
|
.navi_picker_right_slot {
|
|
59282
|
-
align-self:
|
|
59368
|
+
align-self: var(--x-picker-align-y);
|
|
59283
59369
|
}
|
|
59284
59370
|
}
|
|
59285
59371
|
.navi_picker_input {
|
|
@@ -59353,14 +59439,29 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59353
59439
|
--x-picker-border-color: var(--callout-color);
|
|
59354
59440
|
}
|
|
59355
59441
|
|
|
59442
|
+
/* A variant states what the caller did NOT: it moves the DEFAULTS
|
|
59443
|
+
(--picker-*) and never the resolved values (--x-picker-*), so a
|
|
59444
|
+
backgroundColor/borderColor/padding prop — which lands inline on this
|
|
59445
|
+
same element — still wins. The per-state defaults are re-pointed at the
|
|
59446
|
+
base one too, otherwise the @layer formulas (hover = 5% black over the
|
|
59447
|
+
background, disabled = 5% grey) would repaint a box the variant just
|
|
59448
|
+
took away. */
|
|
59356
59449
|
&[data-variant="icon"] {
|
|
59357
|
-
--
|
|
59358
|
-
--
|
|
59359
|
-
|
|
59360
|
-
|
|
59450
|
+
--picker-padding-x-default: 0;
|
|
59451
|
+
--picker-padding-y-default: 0;
|
|
59452
|
+
/* Nothing but the icon is drawn here, so a width/height the caller gave
|
|
59453
|
+
it is a target area, not a text column: the icon belongs in its middle.
|
|
59454
|
+
A default, like everything else a variant moves, so alignX still wins. */
|
|
59455
|
+
--picker-align-x-default: center;
|
|
59361
59456
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59362
|
-
--
|
|
59363
|
-
--
|
|
59457
|
+
--picker-border-color: transparent;
|
|
59458
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59459
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59460
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59461
|
+
--picker-background-color: transparent;
|
|
59462
|
+
--picker-background-color-hover: var(--picker-background-color);
|
|
59463
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59464
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59364
59465
|
--x-picker-icon-color: currentColor;
|
|
59365
59466
|
}
|
|
59366
59467
|
/* discrete: no box at rest, a background on hover — the same word Button
|
|
@@ -59368,31 +59469,35 @@ installImportMetaCssBuild(import.meta);const css$r = /* css */`
|
|
|
59368
59469
|
around it; the chevron in the right slot is what still says it opens. */
|
|
59369
59470
|
&[data-variant="discrete"] {
|
|
59370
59471
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59371
|
-
--
|
|
59372
|
-
--
|
|
59373
|
-
|
|
59374
|
-
|
|
59375
|
-
|
|
59376
|
-
|
|
59377
|
-
|
|
59378
|
-
|
|
59379
|
-
|
|
59380
|
-
|
|
59381
|
-
|
|
59382
|
-
|
|
59383
|
-
|
|
59384
|
-
|
|
59385
|
-
|
|
59386
|
-
|
|
59472
|
+
--picker-border-color: transparent;
|
|
59473
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59474
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59475
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59476
|
+
--picker-background-color: transparent;
|
|
59477
|
+
/* The hover wash is mixed INTO the background instead of replacing it:
|
|
59478
|
+
over the transparent default it is exactly the 8% of currentColor it
|
|
59479
|
+
has always been, and over a backgroundColor the caller gave it darkens
|
|
59480
|
+
that color rather than erasing it. */
|
|
59481
|
+
--picker-background-color-hover: color-mix(
|
|
59482
|
+
in srgb,
|
|
59483
|
+
currentColor 8%,
|
|
59484
|
+
var(--picker-background-color)
|
|
59485
|
+
);
|
|
59486
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59487
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59387
59488
|
}
|
|
59388
59489
|
&[data-variant="headless"] {
|
|
59389
|
-
--
|
|
59390
|
-
--
|
|
59391
|
-
--x-picker-padding-bottom: 0;
|
|
59392
|
-
--x-picker-padding-left: 0;
|
|
59490
|
+
--picker-padding-x-default: 0;
|
|
59491
|
+
--picker-padding-y-default: 0;
|
|
59393
59492
|
--picker-border-width: 0px; /* must carry a unit (px) — used in calc() to offset the custom input overlay */
|
|
59394
|
-
--
|
|
59395
|
-
--
|
|
59493
|
+
--picker-border-color: transparent;
|
|
59494
|
+
--picker-border-color-hover: var(--picker-border-color);
|
|
59495
|
+
--picker-border-color-readonly: var(--picker-border-color);
|
|
59496
|
+
--picker-border-color-disabled: var(--picker-border-color);
|
|
59497
|
+
--picker-background-color: transparent;
|
|
59498
|
+
--picker-background-color-hover: var(--picker-background-color);
|
|
59499
|
+
--picker-background-color-readonly: var(--picker-background-color);
|
|
59500
|
+
--picker-background-color-disabled: var(--picker-background-color);
|
|
59396
59501
|
--x-picker-icon-color: currentColor;
|
|
59397
59502
|
|
|
59398
59503
|
.navi_picker_box {
|
|
@@ -59449,7 +59554,15 @@ const PickerButton = props => {
|
|
|
59449
59554
|
usePickerErrorCallout(uiStateController, error);
|
|
59450
59555
|
return jsxs(Box, {
|
|
59451
59556
|
as: "div",
|
|
59452
|
-
ref: ref
|
|
59557
|
+
ref: ref
|
|
59558
|
+
// The flow this element really has (.navi_picker is display:inline-flex).
|
|
59559
|
+
// Left unsaid, Box reads a <div> as block and resolves alignX into a
|
|
59560
|
+
// text-align — which is a different intention entirely (that one is the
|
|
59561
|
+
// textAlign prop, placing the text INSIDE the value slot).
|
|
59562
|
+
,
|
|
59563
|
+
|
|
59564
|
+
inline: true,
|
|
59565
|
+
flex: "x",
|
|
59453
59566
|
baseClassName: "navi_picker",
|
|
59454
59567
|
pseudoClasses: PICKER_BUTTON_PSEUDO_CLASSES,
|
|
59455
59568
|
"data-variant": variant,
|
|
@@ -59707,6 +59820,11 @@ const PickerStyleCSSVars = {
|
|
|
59707
59820
|
"popupBorderRadius": "--picker-popup-border-radius",
|
|
59708
59821
|
"dialogBorderWidth": "--picker-dialog-border-width",
|
|
59709
59822
|
"slotSpacing": "--picker-slot-spacing",
|
|
59823
|
+
// alignX/alignY resolve to these two on a flex-x box; naming the CSS style
|
|
59824
|
+
// (not the prop) is what styleCSSVars matches, so justifyContent/alignItems
|
|
59825
|
+
// passed directly land in the same variables.
|
|
59826
|
+
"justifyContent": "--picker-align-x",
|
|
59827
|
+
"alignItems": "--picker-align-y",
|
|
59710
59828
|
"padding": "--picker-padding",
|
|
59711
59829
|
"paddingX": "--picker-padding-x",
|
|
59712
59830
|
"paddingY": "--picker-padding-y",
|