@jsenv/navi 0.29.304 → 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 +217 -34
- package/dist/dev/jsenv_navi.js.map +9 -9
- 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 +194 -30
- package/dist/jsenv_navi.js.map +9 -9
- 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(() => {
|
|
@@ -38366,6 +38387,15 @@ const useInteractiveProps = (props, {
|
|
|
38366
38387
|
const debugAction = useDebugAction();
|
|
38367
38388
|
const debugInteraction = useDebugInteraction();
|
|
38368
38389
|
const debugFocus = useDebugFocus();
|
|
38390
|
+
|
|
38391
|
+
// The very instance a run of this control is using, held in a SIGNAL because
|
|
38392
|
+
// the busy state below follows it: it is captured at navi_action_start and
|
|
38393
|
+
// released when the run settles (see onnavi_action_start).
|
|
38394
|
+
const runningActionSignalRef = useRef(null);
|
|
38395
|
+
if (runningActionSignalRef.current === null) {
|
|
38396
|
+
runningActionSignalRef.current = signal(null);
|
|
38397
|
+
}
|
|
38398
|
+
uiStateController.runningActionSignal = runningActionSignalRef.current;
|
|
38369
38399
|
{
|
|
38370
38400
|
const {
|
|
38371
38401
|
autoFocus,
|
|
@@ -38404,7 +38434,15 @@ const useInteractiveProps = (props, {
|
|
|
38404
38434
|
const isActionRequesterComputed = useMemo(() => parentActionRequesterSignal ? computed(() => parentActionRequesterSignal.value === ref.current) : null, [parentActionRequesterSignal]);
|
|
38405
38435
|
const parallelGuard = useContext(ParallelGuardContext);
|
|
38406
38436
|
const parentAction = useContext(ActionContext);
|
|
38407
|
-
|
|
38437
|
+
// The instance the run in flight is using when there is one, and only
|
|
38438
|
+
// then boundAction: boundAction can be a proxy following the UI state
|
|
38439
|
+
// signal, and that state moves while a run is out — a popup content
|
|
38440
|
+
// unmounting takes the group's value with it. The proxy would resolve to
|
|
38441
|
+
// the instance for the new value, which is idle, and the control would
|
|
38442
|
+
// stop waiting on a run that is still going. What it waits on is the run
|
|
38443
|
+
// it started, from navi_action_start to its settlement.
|
|
38444
|
+
const runningAction = uiStateController.runningActionSignal.value;
|
|
38445
|
+
const actionStatus = useActionStatus(runningAction || boundAction);
|
|
38408
38446
|
const networkPolicyReason = useNetworkPolicyReason();
|
|
38409
38447
|
const {
|
|
38410
38448
|
disabled,
|
|
@@ -38765,7 +38803,7 @@ const useInteractiveProps = (props, {
|
|
|
38765
38803
|
// state has already moved to the new value by now — the proxy would
|
|
38766
38804
|
// resolve to the instance for that new value, which is not the one
|
|
38767
38805
|
// running.
|
|
38768
|
-
uiStateController.
|
|
38806
|
+
uiStateController.runningActionSignal.peek()?.abort(`superseded by a newer request on this control`);
|
|
38769
38807
|
return;
|
|
38770
38808
|
}
|
|
38771
38809
|
debugAction(e, `executing action ${e.detail.action.callSource}`);
|
|
@@ -38787,14 +38825,14 @@ const useInteractiveProps = (props, {
|
|
|
38787
38825
|
// this run (see the optimistic queue above), the state — and the
|
|
38788
38826
|
// proxy's resolution — will have moved on.
|
|
38789
38827
|
const runAction = e.detail.action;
|
|
38790
|
-
uiStateController.
|
|
38828
|
+
uiStateController.runningActionSignal.value = runAction.getCurrentAction?.() ?? runAction;
|
|
38791
38829
|
// Fires when the run's underlying work has settled — even for an
|
|
38792
38830
|
// aborted run, whose promise is awaited to completion (see
|
|
38793
38831
|
// performRun in actions.js) — which is exactly what "the server is
|
|
38794
38832
|
// done with it" means, and therefore when the queued request may go.
|
|
38795
38833
|
e.detail.addSideEffect(outcome => {
|
|
38796
38834
|
uiStateController.actionInFlight = false;
|
|
38797
|
-
uiStateController.
|
|
38835
|
+
uiStateController.runningActionSignal.value = null;
|
|
38798
38836
|
uiStateController.parallelGuard?.release(uiStateController);
|
|
38799
38837
|
const queuedEvent = uiStateController.queuedActionAllowedEvent;
|
|
38800
38838
|
if (!queuedEvent) {
|
|
@@ -38899,11 +38937,13 @@ const useInteractiveProps = (props, {
|
|
|
38899
38937
|
// an action's own completion side effect — has to read the signal to get an
|
|
38900
38938
|
// answer that is not one frame late (see BUSY_CONSTRAINT).
|
|
38901
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);
|
|
38902
38946
|
if (firstRender) {
|
|
38903
|
-
// Deferred from the factory so these run after controlHostProps is set.
|
|
38904
|
-
// Constraints like READONLY_CONSTRAINT and findControlProxyTargetController
|
|
38905
|
-
// read controlHostProps — calling these earlier would throw or produce wrong results.
|
|
38906
|
-
onUIStateControllerCreated(uiStateController);
|
|
38907
38947
|
uiStateController.rules.validation.checkValidity();
|
|
38908
38948
|
}
|
|
38909
38949
|
return [controlRootProps, controlHostProps];
|
|
@@ -59115,14 +59155,22 @@ const clipOf = (side, distance) => {
|
|
|
59115
59155
|
// before the next one takes it (see releaseGrowInProgress).
|
|
59116
59156
|
const NAME = "navi-popup-grow";
|
|
59117
59157
|
const NAME_PROPERTY = "view-transition-name";
|
|
59118
|
-
// Worn by the root for the length of the movement
|
|
59119
|
-
//
|
|
59158
|
+
// Worn by the root for the length of the movement, saying which way it goes
|
|
59159
|
+
// ("opening" | "closing") — what the CSS keys the page's own opt-out and the
|
|
59160
|
+
// clip near the anchor's end on, and the movement's only trace in the document.
|
|
59120
59161
|
const ROOT_ATTRIBUTE = "data-navi-popup-grow";
|
|
59162
|
+
// What the two boxes are to each other (Dialog's `grow`: "box" | "scene"),
|
|
59163
|
+
// worn by the root too — it decides how each picture sits in the moving box.
|
|
59164
|
+
const KIND_ATTRIBUTE = "data-navi-popup-grow-kind";
|
|
59121
59165
|
// Inside the popup, the one node that IS the anchor once it has grown.
|
|
59122
59166
|
const TARGET_SELECTOR = "[data-grow]";
|
|
59123
59167
|
// The popup's own animation duration, published on the root because the
|
|
59124
59168
|
// ::view-transition tree hangs off it and inherits from nowhere else.
|
|
59125
59169
|
const DURATION_PROPERTY = "--navi-popup-grow-duration";
|
|
59170
|
+
// The corners of the box being left, published the same way: the pictures are
|
|
59171
|
+
// clipped to the moving box (dialog.jsx), and a card with rounded corners must
|
|
59172
|
+
// not travel with square ones.
|
|
59173
|
+
const BORDER_RADIUS_PROPERTY = "--navi-popup-grow-border-radius";
|
|
59126
59174
|
|
|
59127
59175
|
let releaseGrowInProgress = null;
|
|
59128
59176
|
|
|
@@ -59133,13 +59181,13 @@ let releaseGrowInProgress = null;
|
|
|
59133
59181
|
* `opened` says which way: the box being left is the anchor when the popup is
|
|
59134
59182
|
* opening and the popup when it is closing, and the arriving one is only known
|
|
59135
59183
|
* once the change has been made (the content a popup grows into is built by
|
|
59136
|
-
* that very change).
|
|
59184
|
+
* that very change). `grow` is Dialog's own prop of that name.
|
|
59137
59185
|
*/
|
|
59138
59186
|
const growPopupFromAnchor = (
|
|
59139
59187
|
popupEl,
|
|
59140
59188
|
anchorElement,
|
|
59141
59189
|
applyChange,
|
|
59142
|
-
{ opened },
|
|
59190
|
+
{ opened, grow },
|
|
59143
59191
|
) => {
|
|
59144
59192
|
const startViewTransition = ensureDocumentStartViewTransition();
|
|
59145
59193
|
// A movement still wearing the name would make the name two elements wide,
|
|
@@ -59150,7 +59198,8 @@ const growPopupFromAnchor = (
|
|
|
59150
59198
|
const elementLeaving = opened ? anchorElement : resolveGrowTarget(popupEl);
|
|
59151
59199
|
const giveBackNameLeaving = wearGrowName(elementLeaving);
|
|
59152
59200
|
const root = document.documentElement;
|
|
59153
|
-
root.setAttribute(ROOT_ATTRIBUTE, "");
|
|
59201
|
+
root.setAttribute(ROOT_ATTRIBUTE, opened ? "opening" : "closing");
|
|
59202
|
+
root.setAttribute(KIND_ATTRIBUTE, grow);
|
|
59154
59203
|
const duration = getComputedStyle(popupEl)
|
|
59155
59204
|
.getPropertyValue("--popup-animation-duration")
|
|
59156
59205
|
.trim();
|
|
@@ -59160,6 +59209,10 @@ const growPopupFromAnchor = (
|
|
|
59160
59209
|
// browser's own pace.
|
|
59161
59210
|
root.style.setProperty(DURATION_PROPERTY, duration);
|
|
59162
59211
|
}
|
|
59212
|
+
const borderRadius = getComputedStyle(elementLeaving).borderRadius;
|
|
59213
|
+
if (borderRadius) {
|
|
59214
|
+
root.style.setProperty(BORDER_RADIUS_PROPERTY, borderRadius);
|
|
59215
|
+
}
|
|
59163
59216
|
|
|
59164
59217
|
let giveBackNameArriving = null;
|
|
59165
59218
|
const release = () => {
|
|
@@ -59170,7 +59223,9 @@ const growPopupFromAnchor = (
|
|
|
59170
59223
|
giveBackNameLeaving();
|
|
59171
59224
|
giveBackNameArriving?.();
|
|
59172
59225
|
root.removeAttribute(ROOT_ATTRIBUTE);
|
|
59226
|
+
root.removeAttribute(KIND_ATTRIBUTE);
|
|
59173
59227
|
root.style.removeProperty(DURATION_PROPERTY);
|
|
59228
|
+
root.style.removeProperty(BORDER_RADIUS_PROPERTY);
|
|
59174
59229
|
};
|
|
59175
59230
|
releaseGrowInProgress = release;
|
|
59176
59231
|
|
|
@@ -59516,6 +59571,15 @@ const css$E = /* css */`
|
|
|
59516
59571
|
to filter). An entrance animation moves the dialog through scale and
|
|
59517
59572
|
transform instead, which compose under it: see popup_css.js. */
|
|
59518
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
|
+
}
|
|
59519
59583
|
&[data-pointer-interaction-outside="capture"] {
|
|
59520
59584
|
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
59521
59585
|
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
@@ -59686,6 +59750,15 @@ const css$E = /* css */`
|
|
|
59686
59750
|
--backdrop-background: var(--navi-backdrop-close-background);
|
|
59687
59751
|
--backdrop-filter: var(--navi-backdrop-close-backdrop-filter);
|
|
59688
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
|
+
}
|
|
59689
59762
|
&[data-pointer-interaction-outside="capture"] {
|
|
59690
59763
|
--backdrop-background: var(--navi-backdrop-capture-background);
|
|
59691
59764
|
--backdrop-filter: var(--navi-backdrop-capture-backdrop-filter);
|
|
@@ -59734,6 +59807,73 @@ const css$E = /* css */`
|
|
|
59734
59807
|
&::view-transition-new(navi-popup-grow) {
|
|
59735
59808
|
animation-duration: var(--navi-popup-grow-duration, 0.25s);
|
|
59736
59809
|
}
|
|
59810
|
+
|
|
59811
|
+
/* Each picture is drawn as wide as the box and as tall as it is, so a box
|
|
59812
|
+
that grows in height alone (a card keeping its width) would show the
|
|
59813
|
+
whole taller picture from the first frame, and the movement would read
|
|
59814
|
+
as a fade. Clipped to the box, the picture is uncovered as the box
|
|
59815
|
+
grows and covered back as it shrinks — behind the corners the box
|
|
59816
|
+
has in the page, published by popup_grow.js. */
|
|
59817
|
+
&::view-transition-image-pair(navi-popup-grow) {
|
|
59818
|
+
border-radius: var(--navi-popup-grow-border-radius, 0);
|
|
59819
|
+
overflow: clip;
|
|
59820
|
+
}
|
|
59821
|
+
|
|
59822
|
+
/* One scene through two frames (Dialog's grow="scene"): each picture
|
|
59823
|
+
covers the box, cropped around its centre, so what both frames show
|
|
59824
|
+
lands on itself. */
|
|
59825
|
+
&[data-navi-popup-grow-kind="scene"] {
|
|
59826
|
+
&::view-transition-old(navi-popup-grow),
|
|
59827
|
+
&::view-transition-new(navi-popup-grow) {
|
|
59828
|
+
height: 100%;
|
|
59829
|
+
object-fit: cover;
|
|
59830
|
+
}
|
|
59831
|
+
}
|
|
59832
|
+
|
|
59833
|
+
/* The anchor lives in the page, under the fixed bars; the popup lives in
|
|
59834
|
+
the top layer, over them. The pictures are painted above everything,
|
|
59835
|
+
bars included, so near the anchor's end of the movement the whole tree
|
|
59836
|
+
is clipped to the room between the bars — a thumbnail half under the
|
|
59837
|
+
top bar leaves from under it and comes back under it — and freed near
|
|
59838
|
+
the popup's end, where a tall dialog may stand over them. Clipped for
|
|
59839
|
+
the 65% of the time nearest the anchor: with the group's own ease that
|
|
59840
|
+
leaves the last 35% of the time to cover more than half of the trip,
|
|
59841
|
+
so the picture is out of the bars before the clip closes on it. */
|
|
59842
|
+
&::view-transition {
|
|
59843
|
+
animation: navi-popup-grow-clip var(--navi-popup-grow-duration, 0.25s)
|
|
59844
|
+
ease both;
|
|
59845
|
+
}
|
|
59846
|
+
&[data-navi-popup-grow="closing"]::view-transition {
|
|
59847
|
+
animation-direction: reverse;
|
|
59848
|
+
}
|
|
59849
|
+
}
|
|
59850
|
+
/* The bars sit at the app's own inset (fixed_bar.jsx), so the room they
|
|
59851
|
+
take starts there; both tokens are 0px where nothing takes any. */
|
|
59852
|
+
@keyframes navi-popup-grow-clip {
|
|
59853
|
+
0%,
|
|
59854
|
+
65% {
|
|
59855
|
+
clip-path: inset(
|
|
59856
|
+
calc(
|
|
59857
|
+
var(--navi-app-inset-top, 0px) +
|
|
59858
|
+
var(--navi-fixed-bar-space-top, 0px)
|
|
59859
|
+
)
|
|
59860
|
+
calc(
|
|
59861
|
+
var(--navi-app-inset-right, 0px) +
|
|
59862
|
+
var(--navi-fixed-bar-space-right, 0px)
|
|
59863
|
+
)
|
|
59864
|
+
calc(
|
|
59865
|
+
var(--navi-app-inset-bottom, 0px) +
|
|
59866
|
+
var(--navi-fixed-bar-space-bottom, 0px)
|
|
59867
|
+
)
|
|
59868
|
+
calc(
|
|
59869
|
+
var(--navi-app-inset-left, 0px) +
|
|
59870
|
+
var(--navi-fixed-bar-space-left, 0px)
|
|
59871
|
+
)
|
|
59872
|
+
);
|
|
59873
|
+
}
|
|
59874
|
+
100% {
|
|
59875
|
+
clip-path: inset(0);
|
|
59876
|
+
}
|
|
59737
59877
|
}
|
|
59738
59878
|
|
|
59739
59879
|
${surfaceTextCss}
|
|
@@ -59836,7 +59976,8 @@ const css$E = /* css */`
|
|
|
59836
59976
|
* @param {"auto"|"discrete"|"invisible"} [props.backdropVariant="auto"] - How
|
|
59837
59977
|
* visible the backdrop is, independently of what it does. `"auto"`: the
|
|
59838
59978
|
* paint `pointerInteractionOutsideEffect` implies (dimmed for
|
|
59839
|
-
* `"close"`/`"cancel"`, blurred glass for `"capture"`)
|
|
59979
|
+
* `"close"`/`"cancel"`, blurred glass for `"capture"`), or the opaque wall
|
|
59980
|
+
* `animation="growing"` asks for. `"discrete"`: a
|
|
59840
59981
|
* barely-there dim. `"invisible"`: fully transparent — a wall that is not
|
|
59841
59982
|
* seen, still catching every press. This only changes how much the dialog
|
|
59842
59983
|
* insists visually, never what an outside click does; whether there is a
|
|
@@ -59869,7 +60010,20 @@ const css$E = /* css */`
|
|
|
59869
60010
|
* over it. It needs an anchor (whatever opened the dialog, or the `anchor`
|
|
59870
60011
|
* prop) and grows into whatever inside the dialog carries `data-grow`, the
|
|
59871
60012
|
* dialog itself when nothing does. `"auto"` never picks it: only the caller
|
|
59872
|
-
* 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`.
|
|
60018
|
+
* @param {"box"|"scene"} [props.grow="box"] - Under `animation="growing"`,
|
|
60019
|
+
* what the anchor and what it grows into are to each other, which decides
|
|
60020
|
+
* how their pictures sit in the box moving between them. `"box"`: one
|
|
60021
|
+
* object at two sizes — a card gaining fields. Each picture is drawn at the
|
|
60022
|
+
* box's width from its top edge, and a box growing in height uncovers more
|
|
60023
|
+
* of it: the header stays where it is, the rest extends. `"scene"`: one
|
|
60024
|
+
* scene through two frames — a thumbnail and the map it is cut from. Each
|
|
60025
|
+
* picture covers the box, cropped around its centre and never distorted, so
|
|
60026
|
+
* what both frames show lands on itself.
|
|
59873
60027
|
* @param {string} [props.animationDuration] - Maps to
|
|
59874
60028
|
* `--popup-animation-duration`.
|
|
59875
60029
|
* @param {Element|{current: Element}|string} [props.anchor] - Never used for
|
|
@@ -60212,6 +60366,7 @@ const useDialogProps = props => {
|
|
|
60212
60366
|
// once, held at that size while open. See this prop's own JSDoc above.
|
|
60213
60367
|
sizing = "auto",
|
|
60214
60368
|
animation,
|
|
60369
|
+
grow = "box",
|
|
60215
60370
|
// Inert unless sizeFromAnchor below (see this file's top comment) —
|
|
60216
60371
|
// Dialog's own positioning is never relative to it.
|
|
60217
60372
|
anchor,
|
|
@@ -60438,7 +60593,8 @@ const useDialogProps = props => {
|
|
|
60438
60593
|
return;
|
|
60439
60594
|
}
|
|
60440
60595
|
growPopupFromAnchor(dialogEl, anchorElement, applyChange, {
|
|
60441
|
-
opened
|
|
60596
|
+
opened,
|
|
60597
|
+
grow
|
|
60442
60598
|
});
|
|
60443
60599
|
} : null;
|
|
60444
60600
|
|
|
@@ -60888,6 +61044,7 @@ const useDialogProps = props => {
|
|
|
60888
61044
|
"animationDuration": rest.animationDuration,
|
|
60889
61045
|
"data-pointer-interaction-outside": pointerInteractionOutsideEffect,
|
|
60890
61046
|
"data-backdrop-variant": backdropVariant,
|
|
61047
|
+
"data-growing": growing ? "" : undefined,
|
|
60891
61048
|
backdropColor,
|
|
60892
61049
|
backdropFilter
|
|
60893
61050
|
});
|
|
@@ -60923,6 +61080,11 @@ const useDialogProps = props => {
|
|
|
60923
61080
|
// (and harmless for a local dialog, whose real backdrop element gets it
|
|
60924
61081
|
// via backdropProps).
|
|
60925
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,
|
|
60926
61088
|
// That this dialog has no wall, said in the DOM: the browser generates a
|
|
60927
61089
|
// ::backdrop for the popover a wall-less top-layer dialog is shown as,
|
|
60928
61090
|
// and the CSS above keys off this to leave it unpainted. Also the only
|
|
@@ -62777,6 +62939,7 @@ const css$C = /* css */`@layer navi {
|
|
|
62777
62939
|
* popup meant to dock on a phone must not declare itself compact — see
|
|
62778
62940
|
* `maxWidth` below.
|
|
62779
62941
|
* @param {boolean} [props.sizeFromAnchor] - **Dialog-only**, same guard.
|
|
62942
|
+
* @param {"box"|"scene"} [props.grow] - **Dialog-only**, same guard.
|
|
62780
62943
|
* @param {string} [props.positionArea] - Forwarded as-is — `Dialog` and
|
|
62781
62944
|
* `Popover` have different own defaults (`"center"` vs. `"bottom"`),
|
|
62782
62945
|
* deliberately not homogenized here (each reads best for its own typical
|
|
@@ -62883,6 +63046,7 @@ const Popup = props => {
|
|
|
62883
63046
|
// in the dialog branch, so they never reach the popover element.
|
|
62884
63047
|
dockedOnSmallTouchScreen,
|
|
62885
63048
|
sizeFromAnchor,
|
|
63049
|
+
grow,
|
|
62886
63050
|
...rest
|
|
62887
63051
|
} = props;
|
|
62888
63052
|
const [mode] = useResolvedPopupMode(modeProp, maxWidth, {
|
|
@@ -62901,6 +63065,7 @@ const Popup = props => {
|
|
|
62901
63065
|
...rest,
|
|
62902
63066
|
dockedOnSmallTouchScreen: dockedOnSmallTouchScreen,
|
|
62903
63067
|
sizeFromAnchor: sizeFromAnchor,
|
|
63068
|
+
grow: grow,
|
|
62904
63069
|
maxWidth: maxWidth,
|
|
62905
63070
|
pointerInteractionOutsideEffect: pointerInteractionOutsideEffect,
|
|
62906
63071
|
backdrop: backdrop,
|
|
@@ -63360,19 +63525,26 @@ const PickerCustom = props => {
|
|
|
63360
63525
|
commitUIStateAsAnswer(controller, closeEvent);
|
|
63361
63526
|
}
|
|
63362
63527
|
}
|
|
63363
|
-
leaveExpanded({
|
|
63364
|
-
isBack: closeEvent.detail.isCancel
|
|
63365
|
-
});
|
|
63366
|
-
// Reset so the next opening re-evaluates screen size
|
|
63367
|
-
resetMode();
|
|
63368
63528
|
const confirmEvent = confirmEventRef.current;
|
|
63369
63529
|
confirmEventRef.current = null;
|
|
63370
63530
|
if (confirmEvent && !closeEvent.detail.isCancel) {
|
|
63371
63531
|
onConfirm?.(confirmEvent);
|
|
63372
63532
|
}
|
|
63373
|
-
//
|
|
63374
|
-
// picker's value as it ends up
|
|
63533
|
+
// After the value bookkeeping above — whoever listens reads the
|
|
63534
|
+
// picker's value as it ends up, committed or restored on a cancel —
|
|
63535
|
+
// and before leaveExpanded below, which is where the caller's
|
|
63536
|
+
// reaction runs for a Dialog too. A close that keeps goes back onto
|
|
63537
|
+
// the entry the popup was opened from while KEEPING the url as it
|
|
63538
|
+
// stands at that moment (see useNavState's leave()), so what onClose
|
|
63539
|
+
// spells into the address — a route param naming what was being
|
|
63540
|
+
// edited, cleared now that nothing is — has to be written before,
|
|
63541
|
+
// or the landing puts it back.
|
|
63375
63542
|
onClose?.(closeEvent);
|
|
63543
|
+
leaveExpanded({
|
|
63544
|
+
isBack: closeEvent.detail.isCancel
|
|
63545
|
+
});
|
|
63546
|
+
// Reset so the next opening re-evaluates screen size
|
|
63547
|
+
resetMode();
|
|
63376
63548
|
}
|
|
63377
63549
|
};
|
|
63378
63550
|
});
|
|
@@ -63766,6 +63938,7 @@ const PickerContentInsidePopup = props => {
|
|
|
63766
63938
|
// its own width once lifted. Dialog's own `sizeFromAnchor`.
|
|
63767
63939
|
dialogSizeFromAnchor,
|
|
63768
63940
|
animation,
|
|
63941
|
+
grow,
|
|
63769
63942
|
animationDuration,
|
|
63770
63943
|
// mode="callout": what the callout says about what it holds, and paints
|
|
63771
63944
|
// in its border and icon — "none" for a plain tooltip (see the callout
|
|
@@ -63844,6 +64017,7 @@ const PickerContentInsidePopup = props => {
|
|
|
63844
64017
|
expandY: isPopover ? undefined : dialogExpandY,
|
|
63845
64018
|
dockedOnSmallTouchScreen: isPopover ? undefined : dockedOnSmallTouchScreen,
|
|
63846
64019
|
sizeFromAnchor: isPopover ? undefined : dialogSizeFromAnchor,
|
|
64020
|
+
grow: isPopover ? undefined : grow,
|
|
63847
64021
|
children: jsx(PopupModeContext.Provider, {
|
|
63848
64022
|
value: mode,
|
|
63849
64023
|
children: children
|
|
@@ -72845,6 +73019,7 @@ const PickerFirstResolver = props => {
|
|
|
72845
73019
|
* mode?: "popover" | "dialog" | "callout",
|
|
72846
73020
|
* openOn?: "press" | "longpress" | "contextmenu" | string | string[],
|
|
72847
73021
|
* animation?: boolean | "auto" | "fading" | "scaling" | "sliding" | "growing" | `slide-from-${string}`,
|
|
73022
|
+
* grow?: "box" | "scene",
|
|
72848
73023
|
* animationDuration?: string,
|
|
72849
73024
|
* calloutStatus?: "info" | "warning" | "error" | "success" | "none",
|
|
72850
73025
|
* calloutIcon?: boolean,
|
|
@@ -73135,7 +73310,9 @@ const PickerFirstResolver = props => {
|
|
|
73135
73310
|
* the user validated: that is `action`. `closeEvent.detail.isCancel` tells a
|
|
73136
73311
|
* cancel (Escape, the back gesture) from a close that keeps. Fires after the
|
|
73137
73312
|
* picker's value has settled — committed, or restored on a cancel — so the
|
|
73138
|
-
* value read in here is the one the picker ends up holding
|
|
73313
|
+
* value read in here is the one the picker ends up holding, and before the
|
|
73314
|
+
* popup leaves the history entry it pushed, so a route param cleared in here
|
|
73315
|
+
* is part of the url a close that keeps carries back.
|
|
73139
73316
|
* @param {number|string} [rightSlotIconSize="inherit"] How big what sits in the
|
|
73140
73317
|
* right slot is drawn — the chevron, a `rightSlotIcon`, or the clear button's
|
|
73141
73318
|
* cross. "inherit" takes the picker's own font size.
|
|
@@ -73181,7 +73358,13 @@ const PickerFirstResolver = props => {
|
|
|
73181
73358
|
* (the popup itself when nothing does), and back on close. The trigger IS
|
|
73182
73359
|
* the anchor, so nothing has to be named for it — `dialogSizeFromAnchor`
|
|
73183
73360
|
* for a card that must keep its width on the way, left out for a drawing
|
|
73184
|
-
* 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.
|
|
73364
|
+
* @param {"box"|"scene"} [grow="box"] Dialog's own, under `animation="growing"`:
|
|
73365
|
+
* `"box"` for a card that extends (its top stays, the box uncovers the rest),
|
|
73366
|
+
* `"scene"` for a thumbnail and the bigger view it is cut from (each picture
|
|
73367
|
+
* covers the box, cropped around its centre).
|
|
73185
73368
|
* @param {string} [animationDuration] The popup's own (`--popup-animation-duration`).
|
|
73186
73369
|
* @param {boolean} [dialogSizeFromAnchor] Dialog mode: the dialog is as wide
|
|
73187
73370
|
* as the trigger — its box as a floor (Dialog's own `sizeFromAnchor`) and
|