@jsenv/navi 0.29.305 → 0.29.306
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 +70 -16
- package/dist/dev/jsenv_navi.js.map +6 -6
- package/dist/dev/jsenv_navi_side_effects.js +2 -0
- package/dist/dev/jsenv_navi_side_effects.js.map +2 -2
- package/dist/jsenv_navi.js +55 -13
- package/dist/jsenv_navi.js.map +6 -6
- package/dist/jsenv_navi_side_effects.js +2 -0
- package/dist/jsenv_navi_side_effects.js.map +2 -2
- package/docs/popup_backdrop.md +28 -5
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -4947,6 +4947,11 @@ const radioControllersByName = new Map();
|
|
|
4947
4947
|
// The controller id is used as key — if the controller has no id, the value is not registered.
|
|
4948
4948
|
const naviJsRegistry = new Map();
|
|
4949
4949
|
|
|
4950
|
+
// Controllers already reported for sharing their id with another one. An id is
|
|
4951
|
+
// stated on every render of its control, so without this the warning below
|
|
4952
|
+
// would repeat for as long as both controls are on screen.
|
|
4953
|
+
const controllersWarned = new WeakSet();
|
|
4954
|
+
|
|
4950
4955
|
const getUIStateControllerById = (id) => controllersById.get(id);
|
|
4951
4956
|
const getRadioSiblings = (radioUIStateController) => {
|
|
4952
4957
|
const siblings = radioControllersByName.get(radioUIStateController.name);
|
|
@@ -4984,10 +4989,15 @@ const onUIStateControllerCreated = (uiStateController) => {
|
|
|
4984
4989
|
if (id) {
|
|
4985
4990
|
{
|
|
4986
4991
|
const existing = controllersById.get(id);
|
|
4987
|
-
if (
|
|
4992
|
+
if (
|
|
4993
|
+
existing &&
|
|
4994
|
+
existing !== uiStateController &&
|
|
4995
|
+
!controllersWarned.has(uiStateController)
|
|
4996
|
+
) {
|
|
4997
|
+
controllersWarned.add(uiStateController);
|
|
4988
4998
|
console.warn(
|
|
4989
4999
|
`[navi] Two controls share the same id "${id}" ("${existing.controlType}" and "${controlType}"). ` +
|
|
4990
|
-
`
|
|
5000
|
+
`The id resolves to whichever of them rendered last, so the other one is unreachable through it (undefined uiState, dead picker buttons). ` +
|
|
4991
5001
|
`Common causes: several controls inside a single <Field> (the Field provides one id via context and every control consumes it — put each control in its own <Field>, or give one an explicit id), ` +
|
|
4992
5002
|
`or the same content mounted twice (e.g. two popups sharing an id prefix while both hold their content).`,
|
|
4993
5003
|
);
|
|
@@ -5020,8 +5030,15 @@ const onUIStateControllerCreated = (uiStateController) => {
|
|
|
5020
5030
|
const onUIStateControllerDestroyed = (uiStateController) => {
|
|
5021
5031
|
const { id, name, controlType } = uiStateController;
|
|
5022
5032
|
if (id) {
|
|
5023
|
-
|
|
5024
|
-
|
|
5033
|
+
// Only the controller the id currently points at may take the entry away:
|
|
5034
|
+
// when two controls share an id, the one leaving would otherwise unregister
|
|
5035
|
+
// the one staying (see the warning in onUIStateControllerCreated), and the
|
|
5036
|
+
// same holds while a control is being replaced by its successor, which
|
|
5037
|
+
// registers during its render, before this cleanup runs.
|
|
5038
|
+
if (controllersById.get(id) === uiStateController) {
|
|
5039
|
+
controllersById.delete(id);
|
|
5040
|
+
naviJsRegistry.delete(id);
|
|
5041
|
+
}
|
|
5025
5042
|
}
|
|
5026
5043
|
const proxyFor = uiStateController.props["navi-control-proxy-for"];
|
|
5027
5044
|
if (proxyFor) {
|
|
@@ -35277,17 +35294,21 @@ const useUIStateController = (
|
|
|
35277
35294
|
if (el) {
|
|
35278
35295
|
el.__uiStateController__ = controller;
|
|
35279
35296
|
}
|
|
35280
|
-
// Re-register so the radio registry stays in sync when props.ref changes
|
|
35281
|
-
// identity (e.g. across a Suspense boundary). The render-phase call in
|
|
35282
|
-
// control_hooks.jsx handles the initial mount; this call handles re-runs.
|
|
35283
|
-
onUIStateControllerCreated(controller);
|
|
35284
35297
|
return () => {
|
|
35285
35298
|
if (el && el.__uiStateController__ === controller) {
|
|
35286
35299
|
delete el.__uiStateController__;
|
|
35287
35300
|
}
|
|
35288
|
-
onUIStateControllerDestroyed(controller);
|
|
35289
35301
|
};
|
|
35290
35302
|
}, [controllerRef]);
|
|
35303
|
+
// The registry entry lives as long as the component does. Registration is
|
|
35304
|
+
// done by the render (see useInteractiveProps); this cleanup is the only
|
|
35305
|
+
// thing that takes the entry away, so it must not follow the ref: a ref
|
|
35306
|
+
// identity change would run it right after the render that registered.
|
|
35307
|
+
useLayoutEffect(() => {
|
|
35308
|
+
return () => {
|
|
35309
|
+
onUIStateControllerDestroyed(controller);
|
|
35310
|
+
};
|
|
35311
|
+
}, []);
|
|
35291
35312
|
|
|
35292
35313
|
const { parentUIStateController: parentController } = scope;
|
|
35293
35314
|
useLayoutEffect(() => {
|
|
@@ -38916,11 +38937,13 @@ const useInteractiveProps = (props, {
|
|
|
38916
38937
|
// an action's own completion side effect — has to read the signal to get an
|
|
38917
38938
|
// answer that is not one frame late (see BUSY_CONSTRAINT).
|
|
38918
38939
|
uiStateController.boundAction = boundAction;
|
|
38940
|
+
// "This id is that controller", stated on every render: a Suspense boundary
|
|
38941
|
+
// parking a subtree runs every hook cleanup below it — the unregistration
|
|
38942
|
+
// included — while the controllers themselves survive, and readers look a
|
|
38943
|
+
// controller up by id while rendering, before any effect can run again.
|
|
38944
|
+
// Placed after controlHostProps is set, which the constraints read.
|
|
38945
|
+
onUIStateControllerCreated(uiStateController);
|
|
38919
38946
|
if (firstRender) {
|
|
38920
|
-
// Deferred from the factory so these run after controlHostProps is set.
|
|
38921
|
-
// Constraints like READONLY_CONSTRAINT and findControlProxyTargetController
|
|
38922
|
-
// read controlHostProps — calling these earlier would throw or produce wrong results.
|
|
38923
|
-
onUIStateControllerCreated(uiStateController);
|
|
38924
38947
|
uiStateController.rules.validation.checkValidity();
|
|
38925
38948
|
}
|
|
38926
38949
|
return [controlRootProps, controlHostProps];
|
|
@@ -59548,6 +59571,15 @@ const css$E = /* css */`
|
|
|
59548
59571
|
to filter). An entrance animation moves the dialog through scale and
|
|
59549
59572
|
transform instead, which compose under it: see popup_css.js. */
|
|
59550
59573
|
|
|
59574
|
+
/* animation="growing" brings its own wall: the popup is the anchor
|
|
59575
|
+
continued, not a surface shown over a page that goes on being read (see
|
|
59576
|
+
navi_css_vars.js for the paint). Before the rules below, so everything
|
|
59577
|
+
said out loud — an outside press that captures, a backdropVariant, the
|
|
59578
|
+
two paint props — still wins over what the animation assumes. */
|
|
59579
|
+
&[data-growing] {
|
|
59580
|
+
--backdrop-background: var(--navi-backdrop-grow-background);
|
|
59581
|
+
--backdrop-filter: var(--navi-backdrop-grow-backdrop-filter);
|
|
59582
|
+
}
|
|
59551
59583
|
&[data-pointer-interaction-outside="capture"] {
|
|
59552
59584
|
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
59553
59585
|
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
@@ -59718,6 +59750,15 @@ const css$E = /* css */`
|
|
|
59718
59750
|
--backdrop-background: var(--navi-backdrop-close-background);
|
|
59719
59751
|
--backdrop-filter: var(--navi-backdrop-close-backdrop-filter);
|
|
59720
59752
|
}
|
|
59753
|
+
/* animation="growing" brings its own wall: the popup is the anchor
|
|
59754
|
+
continued, not a surface shown over a page that goes on being read (see
|
|
59755
|
+
navi_css_vars.js for the paint). Before the rules below, so everything
|
|
59756
|
+
said out loud — an outside press that captures, a backdropVariant, the
|
|
59757
|
+
two paint props — still wins over what the animation assumes. */
|
|
59758
|
+
&[data-growing] {
|
|
59759
|
+
--backdrop-background: var(--navi-backdrop-grow-background);
|
|
59760
|
+
--backdrop-filter: var(--navi-backdrop-grow-backdrop-filter);
|
|
59761
|
+
}
|
|
59721
59762
|
&[data-pointer-interaction-outside="capture"] {
|
|
59722
59763
|
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
59723
59764
|
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
@@ -59935,7 +59976,8 @@ const css$E = /* css */`
|
|
|
59935
59976
|
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
|
|
59936
59977
|
* visible the backdrop is, independently of what it does. `"auto"`: the
|
|
59937
59978
|
* paint `pointerInteractionOutsideEffect` implies (dimmed for
|
|
59938
|
-
* `"close"`/`"cancel"`, blurred glass for `"capture"`)
|
|
59979
|
+
* `"close"`/`"cancel"`, blurred glass for `"capture"`), or the opaque wall
|
|
59980
|
+
* `animation="growing"` asks for. `"discrete"`: a
|
|
59939
59981
|
* barely-there dim. `"invisible"`: fully transparent — a wall that is not
|
|
59940
59982
|
* seen, still catching every press. This only changes how much the dialog
|
|
59941
59983
|
* insists visually, never what an outside click does; whether there is a
|
|
@@ -59968,7 +60010,11 @@ const css$E = /* css */`
|
|
|
59968
60010
|
* over it. It needs an anchor (whatever opened the dialog, or the `anchor`
|
|
59969
60011
|
* prop) and grows into whatever inside the dialog carries `data-grow`, the
|
|
59970
60012
|
* dialog itself when nothing does. `"auto"` never picks it: only the caller
|
|
59971
|
-
* knows the two boxes are one object.
|
|
60013
|
+
* knows the two boxes are one object. It also brings its own backdrop —
|
|
60014
|
+
* opaque and blurred (`--navi-backdrop-grow-*`), the page it came out of
|
|
60015
|
+
* being what the movement leaves rather than a context to keep readable;
|
|
60016
|
+
* `backdropVariant="discrete"` asks for the light wash back. See
|
|
60017
|
+
* `popup_grow.js`.
|
|
59972
60018
|
* @param {"box"|"scene"} [props.grow="box"] - Under `animation="growing"`,
|
|
59973
60019
|
* what the anchor and what it grows into are to each other, which decides
|
|
59974
60020
|
* how their pictures sit in the box moving between them. `"box"`: one
|
|
@@ -60998,6 +61044,7 @@ const useDialogProps = props => {
|
|
|
60998
61044
|
"animationDuration": rest.animationDuration,
|
|
60999
61045
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
61000
61046
|
"data-backdrop-variant": backdropVariant,
|
|
61047
|
+
"data-growing": growing ? "" : undefined,
|
|
61001
61048
|
backdropColor,
|
|
61002
61049
|
backdropFilter
|
|
61003
61050
|
});
|
|
@@ -61033,6 +61080,11 @@ const useDialogProps = props => {
|
|
|
61033
61080
|
// (and harmless for a local dialog, whose real backdrop element gets it
|
|
61034
61081
|
// via backdropProps).
|
|
61035
61082
|
"data-backdrop-variant": backdropVariant,
|
|
61083
|
+
// That this popup is the anchor continued rather than a surface shown
|
|
61084
|
+
// over the page, which is what its backdrop is painted from (see this
|
|
61085
|
+
// file's CSS). It cannot be read off navi-animation: growing arms no CSS
|
|
61086
|
+
// animation of its own, so that attribute is deliberately absent here.
|
|
61087
|
+
"data-growing": growing ? "" : undefined,
|
|
61036
61088
|
// That this dialog has no wall, said in the DOM: the browser generates a
|
|
61037
61089
|
// ::backdrop for the popover a wall-less top-layer dialog is shown as,
|
|
61038
61090
|
// and the CSS above keys off this to leave it unpainted. Also the only
|
|
@@ -73306,7 +73358,9 @@ const PickerFirstResolver = props => {
|
|
|
73306
73358
|
* (the popup itself when nothing does), and back on close. The trigger IS
|
|
73307
73359
|
* the anchor, so nothing has to be named for it — `dialogSizeFromAnchor`
|
|
73308
73360
|
* for a card that must keep its width on the way, left out for a drawing
|
|
73309
|
-
* that opens precisely to get bigger.
|
|
73361
|
+
* that opens precisely to get bigger. It brings an opaque, blurred backdrop
|
|
73362
|
+
* with it (`--navi-backdrop-grow-*`); `backdropVariant="discrete"` asks for
|
|
73363
|
+
* the light wash back.
|
|
73310
73364
|
* @param {"box"|"scene"} [grow="box"] Dialog's own, under `animation="growing"`:
|
|
73311
73365
|
* `"box"` for a card that extends (its top stays, the box uncovers the rest),
|
|
73312
73366
|
* `"scene"` for a thumbnail and the bigger view it is cut from (each picture
|