@jsenv/navi 0.29.364 → 0.29.366
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 +209 -48
- package/dist/dev/jsenv_navi.js.map +6 -6
- package/dist/jsenv_navi.js +147 -43
- package/dist/jsenv_navi.js.map +6 -6
- package/docs/AI_INSTRUCTIONS.md +3 -1
- package/docs/popup_lift.md +81 -1
- package/docs/popup_open.md +15 -2
- package/package.json +1 -1
package/dist/dev/jsenv_navi.js
CHANGED
|
@@ -28872,6 +28872,8 @@ const visitedUrlsSignal = browserIntegration.visitedUrlsSignal;
|
|
|
28872
28872
|
browserIntegration.handleActionTask;
|
|
28873
28873
|
|
|
28874
28874
|
const idUsageMap = new Map();
|
|
28875
|
+
// Keys found in the entry with nobody to claim them, already reported.
|
|
28876
|
+
const orphanKeysReported = new Set();
|
|
28875
28877
|
const useNavStateWithWarnings = (id, options) => {
|
|
28876
28878
|
const idRef = useRef(undefined);
|
|
28877
28879
|
if (idRef.current !== id) {
|
|
@@ -28895,6 +28897,15 @@ Consider using unique IDs for each component instance.`,
|
|
|
28895
28897
|
}
|
|
28896
28898
|
|
|
28897
28899
|
useEffect(() => {
|
|
28900
|
+
// Registered here as well as in the render above: preact/compat's
|
|
28901
|
+
// Suspense parks a subtree by running every hook cleanup in it, and the
|
|
28902
|
+
// render resuming it carries the same id.
|
|
28903
|
+
if (!idUsageMap.has(id)) {
|
|
28904
|
+
idUsageMap.set(id, {
|
|
28905
|
+
stackTrace: new Error().stack,
|
|
28906
|
+
});
|
|
28907
|
+
}
|
|
28908
|
+
warnAboutOrphanGeneratedKeys();
|
|
28898
28909
|
return () => {
|
|
28899
28910
|
idUsageMap.delete(id);
|
|
28900
28911
|
};
|
|
@@ -28903,6 +28914,31 @@ Consider using unique IDs for each component instance.`,
|
|
|
28903
28914
|
return useNavStateBasic(id, options);
|
|
28904
28915
|
};
|
|
28905
28916
|
|
|
28917
|
+
// A generated id (preact's useId()) names one mount. State written under one
|
|
28918
|
+
// outlives that mount in the history entry — a page left with a popup open —
|
|
28919
|
+
// and the mount coming back to the entry generates another id: the state is
|
|
28920
|
+
// there, and nothing reads it. Reported when a component mounting on the entry
|
|
28921
|
+
// finds such a key, the moment someone expected the state back.
|
|
28922
|
+
const warnAboutOrphanGeneratedKeys = () => {
|
|
28923
|
+
const state = browserIntegration.getDocumentState();
|
|
28924
|
+
if (!state) {
|
|
28925
|
+
return;
|
|
28926
|
+
}
|
|
28927
|
+
for (const key of Object.keys(state)) {
|
|
28928
|
+
if (
|
|
28929
|
+
!isLikelyPreactGeneratedId(key) ||
|
|
28930
|
+
idUsageMap.has(key) ||
|
|
28931
|
+
orphanKeysReported.has(key)
|
|
28932
|
+
) {
|
|
28933
|
+
continue;
|
|
28934
|
+
}
|
|
28935
|
+
orphanKeysReported.add(key);
|
|
28936
|
+
console.warn(
|
|
28937
|
+
`useNavState: this history entry holds "${key}", written by a component whose id was generated (preact's useId()) and that is not mounted anymore — a Picker without an id, a popup with navState and no id. A generated id names one mount, so nothing will read that state again: a popup open when this screen was left comes back closed. Give the component a stable id if it was meant to be found as it was.`,
|
|
28938
|
+
);
|
|
28939
|
+
}
|
|
28940
|
+
};
|
|
28941
|
+
|
|
28906
28942
|
const NO_OP = () => {};
|
|
28907
28943
|
const NO_ID_GIVEN = [undefined, NO_OP, NO_OP];
|
|
28908
28944
|
// What the computed below answers for a key the document state does not hold:
|
|
@@ -60567,6 +60603,13 @@ const clipOf = (side, distance) => {
|
|
|
60567
60603
|
* (TARGET_WAIT_MS), on the half-strength frame where the anchor is still
|
|
60568
60604
|
* readable, and lifts the moment it is there.
|
|
60569
60605
|
*
|
|
60606
|
+
* A closing may land where no opening took off: a dialog opened the plain way
|
|
60607
|
+
* (`animation={{ open, close: "lifting" }}` in dialog.jsx), closing into a box the close
|
|
60608
|
+
* itself brings — the state `onClose` writes renders the place the lifted node
|
|
60609
|
+
* belongs to. So the box a closing comes back to is read once the change is
|
|
60610
|
+
* made, inside the transition, and when the caller named it (`liftAnchor`) it
|
|
60611
|
+
* is waited for (LANDING_WAIT_MS): the new picture is taken once it is there.
|
|
60612
|
+
*
|
|
60570
60613
|
* One name serves the whole movement, because only one of the two boxes is on
|
|
60571
60614
|
* screen at a time: it names the anchor while the popup is closed, and the
|
|
60572
60615
|
* lifted node while it is open.
|
|
@@ -60609,6 +60652,12 @@ const ARRIVING_ATTRIBUTE = "data-navi-popup-lift-arriving";
|
|
|
60609
60652
|
// stands, without a movement, so a target that never comes cannot keep it
|
|
60610
60653
|
// unpainted.
|
|
60611
60654
|
const TARGET_WAIT_MS = 1000;
|
|
60655
|
+
// How long a closing waits for the box it comes back to, when that box is
|
|
60656
|
+
// brought by the close (see this file's top comment). The page is frozen on
|
|
60657
|
+
// the picture of the open popup meanwhile, so the wait is short: what it
|
|
60658
|
+
// covers is a render, not a fetch. Past it the popup's picture plays out on
|
|
60659
|
+
// its own.
|
|
60660
|
+
const LANDING_WAIT_MS = 300;
|
|
60612
60661
|
// The popup's own animation duration, published on the root because the
|
|
60613
60662
|
// ::view-transition tree hangs off it and inherits from nowhere else.
|
|
60614
60663
|
const DURATION_PROPERTY = "--navi-popup-lift-duration";
|
|
@@ -60649,14 +60698,16 @@ let releaseScrollHold = null;
|
|
|
60649
60698
|
* a view transition morphing the anchor's box into the lifted node's, or back.
|
|
60650
60699
|
*
|
|
60651
60700
|
* `opened` says which way: the box being left is the anchor when the popup is
|
|
60652
|
-
* opening and the lifted node when it is closing. `
|
|
60653
|
-
*
|
|
60701
|
+
* opening and the lifted node when it is closing. `resolveAnchor` is read on
|
|
60702
|
+
* the spot for an opening, and once the change is made for a closing;
|
|
60703
|
+
* `waitForAnchor` has a closing wait for it when it is not there yet. `lift`
|
|
60704
|
+
* is Dialog's own prop of that name.
|
|
60654
60705
|
*/
|
|
60655
60706
|
const liftPopupFromAnchor = (
|
|
60656
60707
|
popupEl,
|
|
60657
|
-
|
|
60708
|
+
resolveAnchor,
|
|
60658
60709
|
applyChange,
|
|
60659
|
-
{ opened, lift },
|
|
60710
|
+
{ opened, lift, waitForAnchor },
|
|
60660
60711
|
) => {
|
|
60661
60712
|
const startViewTransition = ensureDocumentStartViewTransition();
|
|
60662
60713
|
// A movement still wearing the name would make the name two elements wide,
|
|
@@ -60664,7 +60715,7 @@ const liftPopupFromAnchor = (
|
|
|
60664
60715
|
// document.
|
|
60665
60716
|
releaseLiftInProgress?.();
|
|
60666
60717
|
|
|
60667
|
-
const elementLeaving = opened ?
|
|
60718
|
+
const elementLeaving = opened ? resolveAnchor() : resolveLiftTarget(popupEl);
|
|
60668
60719
|
// Read before the first write: the read brings the style up to date, and a
|
|
60669
60720
|
// write before it would make it bring it up to date once more.
|
|
60670
60721
|
const duration = getComputedStyle(popupEl)
|
|
@@ -60688,12 +60739,14 @@ const liftPopupFromAnchor = (
|
|
|
60688
60739
|
|
|
60689
60740
|
let giveBackNameArriving = null;
|
|
60690
60741
|
let stopWaitingForTarget = null;
|
|
60742
|
+
let stopWaitingForAnchor = null;
|
|
60691
60743
|
const release = () => {
|
|
60692
60744
|
if (releaseLiftInProgress !== release) {
|
|
60693
60745
|
return;
|
|
60694
60746
|
}
|
|
60695
60747
|
releaseLiftInProgress = null;
|
|
60696
60748
|
stopWaitingForTarget?.();
|
|
60749
|
+
stopWaitingForAnchor?.();
|
|
60697
60750
|
boxAnimationInProgress?.cancel();
|
|
60698
60751
|
boxAnimationInProgress = null;
|
|
60699
60752
|
releaseScrollHold?.();
|
|
@@ -60719,13 +60772,18 @@ const liftPopupFromAnchor = (
|
|
|
60719
60772
|
const boxLeaving = room ? elementLeaving.getBoundingClientRect() : null;
|
|
60720
60773
|
let boxArriving = null;
|
|
60721
60774
|
let cornersArriving = null;
|
|
60722
|
-
const viewTransition = startViewTransition(() => {
|
|
60775
|
+
const viewTransition = startViewTransition(async () => {
|
|
60723
60776
|
// The name is the arriving box's from here on: worn by both, it is worn
|
|
60724
60777
|
// by neither. Written rather than removed, so a name the element also
|
|
60725
60778
|
// has from a stylesheet cannot resurface for the length of the movement.
|
|
60726
60779
|
elementLeaving.style.setProperty(NAME_PROPERTY, "none");
|
|
60727
60780
|
change();
|
|
60728
|
-
const elementArriving = resolveElementArriving();
|
|
60781
|
+
const elementArriving = await resolveElementArriving();
|
|
60782
|
+
// Replaced while waiting for its landing: the movement replacing it
|
|
60783
|
+
// holds the name now.
|
|
60784
|
+
if (releaseLiftInProgress !== release) {
|
|
60785
|
+
return;
|
|
60786
|
+
}
|
|
60729
60787
|
if (elementArriving) {
|
|
60730
60788
|
giveBackNameArriving = wearLiftName(elementArriving);
|
|
60731
60789
|
cornersArriving = readCorners(elementArriving);
|
|
@@ -60750,12 +60808,33 @@ const liftPopupFromAnchor = (
|
|
|
60750
60808
|
};
|
|
60751
60809
|
|
|
60752
60810
|
if (!opened) {
|
|
60753
|
-
startMovement(applyChange, () =>
|
|
60811
|
+
startMovement(applyChange, () => {
|
|
60812
|
+
const anchorElement = resolveAnchor();
|
|
60813
|
+
if (anchorElement?.isConnected) {
|
|
60814
|
+
return anchorElement;
|
|
60815
|
+
}
|
|
60754
60816
|
// Gone from the document while the popup was open (the row it stood in
|
|
60755
60817
|
// was removed): nothing to arrive at, and the browser plays the popup's
|
|
60756
60818
|
// picture out on its own.
|
|
60757
|
-
|
|
60758
|
-
|
|
60819
|
+
if (!waitForAnchor) {
|
|
60820
|
+
return null;
|
|
60821
|
+
}
|
|
60822
|
+
return new Promise((resolve) => {
|
|
60823
|
+
stopWaitingForAnchor = whenAnchorAppears(resolveAnchor, (element) => {
|
|
60824
|
+
stopWaitingForAnchor = null;
|
|
60825
|
+
// Not when stopped by a movement replacing this one.
|
|
60826
|
+
if (
|
|
60827
|
+
!element &&
|
|
60828
|
+
releaseLiftInProgress === release
|
|
60829
|
+
) {
|
|
60830
|
+
console.warn(
|
|
60831
|
+
`[navi] Dialog's "liftAnchor" named nothing on screen within ${LANDING_WAIT_MS}ms of the close, so the dialog closes without landing. The element it names is where the box comes back to: in the document at the close, or rendered by what the close changes (onClose).`,
|
|
60832
|
+
);
|
|
60833
|
+
}
|
|
60834
|
+
resolve(element);
|
|
60835
|
+
});
|
|
60836
|
+
});
|
|
60837
|
+
});
|
|
60759
60838
|
return;
|
|
60760
60839
|
}
|
|
60761
60840
|
|
|
@@ -60915,6 +60994,40 @@ const whenLiftTargetAppears = (popupEl, callback) => {
|
|
|
60915
60994
|
return stop;
|
|
60916
60995
|
};
|
|
60917
60996
|
|
|
60997
|
+
// Calls `callback` with the anchor once `resolveAnchor` finds it in the
|
|
60998
|
+
// document, or with null past LANDING_WAIT_MS — or when stopped, since the
|
|
60999
|
+
// transition's update is waiting on it. Returns how to stop.
|
|
61000
|
+
const whenAnchorAppears = (resolveAnchor, callback) => {
|
|
61001
|
+
const observer = new MutationObserver(() => {
|
|
61002
|
+
const anchorElement = resolveAnchor();
|
|
61003
|
+
if (anchorElement?.isConnected) {
|
|
61004
|
+
stop(anchorElement);
|
|
61005
|
+
}
|
|
61006
|
+
});
|
|
61007
|
+
observer.observe(document.documentElement, {
|
|
61008
|
+
childList: true,
|
|
61009
|
+
subtree: true,
|
|
61010
|
+
attributes: true,
|
|
61011
|
+
attributeFilter: ["id"],
|
|
61012
|
+
});
|
|
61013
|
+
const timeout = setTimeout(() => {
|
|
61014
|
+
stop(null);
|
|
61015
|
+
}, LANDING_WAIT_MS);
|
|
61016
|
+
let stopped = false;
|
|
61017
|
+
const stop = (anchorElement = null) => {
|
|
61018
|
+
if (stopped) {
|
|
61019
|
+
return;
|
|
61020
|
+
}
|
|
61021
|
+
stopped = true;
|
|
61022
|
+
observer.disconnect();
|
|
61023
|
+
clearTimeout(timeout);
|
|
61024
|
+
callback(anchorElement);
|
|
61025
|
+
};
|
|
61026
|
+
return () => {
|
|
61027
|
+
stop(null);
|
|
61028
|
+
};
|
|
61029
|
+
};
|
|
61030
|
+
|
|
60918
61031
|
const ignore = () => {};
|
|
60919
61032
|
|
|
60920
61033
|
// The room the fixed bars leave, in viewport coordinates; null without bars.
|
|
@@ -61580,6 +61693,18 @@ const css$E = /* css */`
|
|
|
61580
61693
|
opacity: 0;
|
|
61581
61694
|
}
|
|
61582
61695
|
|
|
61696
|
+
/* A closing lift is the dialog leaving as a picture: whatever exit its
|
|
61697
|
+
opening animation arms (animation={{ open, close: "lifting" }}, see
|
|
61698
|
+
popup_css.js) would
|
|
61699
|
+
keep it rendered into the picture of the state it closes into. */
|
|
61700
|
+
:root[data-navi-popup-lift="closing"] {
|
|
61701
|
+
.navi_dialog,
|
|
61702
|
+
.navi_dialog::backdrop,
|
|
61703
|
+
.navi_dialog_backdrop {
|
|
61704
|
+
transition: none;
|
|
61705
|
+
}
|
|
61706
|
+
}
|
|
61707
|
+
|
|
61583
61708
|
/* While a dialog is lifting out of the element that opened it
|
|
61584
61709
|
(popup_lift.js). The page around IS taken as a picture, the browser's own
|
|
61585
61710
|
default, and on purpose: the wall and what the dialog holds around the
|
|
@@ -61822,7 +61947,7 @@ const css$E = /* css */`
|
|
|
61822
61947
|
* scroll while open (its backdrop only covers the scrollport, so scrolling
|
|
61823
61948
|
* there would reveal uncovered content); this prop extends the lock to the
|
|
61824
61949
|
* whole page. Defaults to `true` for a dialog docked by `dockedOnSmallTouchScreen`.
|
|
61825
|
-
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"|"lifting"|`slide-from-${string}
|
|
61950
|
+
* @param {boolean|"auto"|"fading"|"scaling"|"sliding"|"lifting"|`slide-from-${string}`|{open: boolean|"auto"|"fading"|"scaling"|"sliding"|`slide-from-${string}`, close: "lifting"}} [props.animation]
|
|
61826
61951
|
* - `true`/`"auto"` resolves to `"scaling"` for a centered `positionArea`,
|
|
61827
61952
|
* or a concrete `"slide-from-*"` direction otherwise. Any other explicit
|
|
61828
61953
|
* value is used as-is. `"lifting"` is the odd one out: every other kind
|
|
@@ -61841,6 +61966,15 @@ const css$E = /* css */`
|
|
|
61841
61966
|
* being what the movement leaves rather than a context to keep readable;
|
|
61842
61967
|
* `backdropVariant="discrete"` asks for the light wash back. See
|
|
61843
61968
|
* `popup_lift.js`.
|
|
61969
|
+
* - `{ open, close: "lifting" }`: the close alone lifts. The dialog opens
|
|
61970
|
+
* with `open` (any value above but `"lifting"`), and its `data-lift` node
|
|
61971
|
+
* travels into `liftAnchor` on close — for a dialog that did not come out
|
|
61972
|
+
* of what it lands in (a banner opens a full-screen reveal, closing it puts
|
|
61973
|
+
* the crest in its place on the plate that replaces the banner). The box it
|
|
61974
|
+
* lands in may be rendered by the close itself: `liftAnchor` is read once
|
|
61975
|
+
* `onClose` has run, and waited for a moment when it is not there yet.
|
|
61976
|
+
* `"lifting"` is the only `close` that differs from the opening: every
|
|
61977
|
+
* other kind closes by playing its opening backwards.
|
|
61844
61978
|
* @param {"box"|"scene"} [props.lift="box"] - Under `animation="lifting"`,
|
|
61845
61979
|
* what the anchor and what it becomes are to each other, which decides
|
|
61846
61980
|
* how their pictures sit in the box moving between them. `"box"`: one
|
|
@@ -61865,14 +61999,15 @@ const css$E = /* css */`
|
|
|
61865
61999
|
* `document.getElementById` when the dialog opens — see popover.jsx's own
|
|
61866
62000
|
* `anchor` doc for why (mainly `defaultOpen`).
|
|
61867
62001
|
* @param {Element|{current: Element}|string} [props.liftAnchor] - Under
|
|
61868
|
-
* `animation="lifting"
|
|
61869
|
-
* is
|
|
61870
|
-
* shown one at a time) has something else in
|
|
61871
|
-
* and the box would otherwise fly back to the
|
|
61872
|
-
* grammar as `anchor` (element, ref or id),
|
|
61873
|
-
*
|
|
61874
|
-
*
|
|
61875
|
-
* opening. Left out, the box comes back to the anchor
|
|
62002
|
+
* `animation="lifting"` or `animation={{ open, close: "lifting" }}`, where the closing
|
|
62003
|
+
* brings the box back to, when that is not where it came from: a popup one
|
|
62004
|
+
* walks through (a row of cards shown one at a time) has something else in
|
|
62005
|
+
* front by the time it closes, and the box would otherwise fly back to the
|
|
62006
|
+
* card the press opened on. Same grammar as `anchor` (element, ref or id),
|
|
62007
|
+
* resolved once the close is made — after `onClose` — so whatever names the
|
|
62008
|
+
* card currently in front, or the box the close itself renders, is read
|
|
62009
|
+
* then and not at the opening. Left out, the box comes back to the anchor
|
|
62010
|
+
* it came out of.
|
|
61876
62011
|
* @param {boolean} [props.sizeFromAnchor=false] - Whether the dialog takes the
|
|
61877
62012
|
* anchor's width/height as a min-width/min-height floor
|
|
61878
62013
|
* (`--anchor-width`/`--anchor-height`). Off by default: unlike a popover,
|
|
@@ -62360,7 +62495,18 @@ const useDialogProps = props => {
|
|
|
62360
62495
|
flushEdges.left = expandX || x === "left" || x === "inset-left";
|
|
62361
62496
|
flushEdges.right = expandX || x === "right" || x === "inset-right";
|
|
62362
62497
|
}
|
|
62363
|
-
|
|
62498
|
+
|
|
62499
|
+
// `{ open, close }` says each way on its own; a single value says both.
|
|
62500
|
+
const {
|
|
62501
|
+
open: openAnimation,
|
|
62502
|
+
close: closeAnimation = openAnimation
|
|
62503
|
+
} = animation !== null && typeof animation === "object" ? animation : {
|
|
62504
|
+
open: animation
|
|
62505
|
+
};
|
|
62506
|
+
if (closeAnimation !== openAnimation && closeAnimation !== "lifting") {
|
|
62507
|
+
console.warn(`[navi] Dialog animation={{ close: ${JSON.stringify(closeAnimation)} }}: "lifting" is the only close that differs from the opening; every other kind closes by playing the opening backwards.`);
|
|
62508
|
+
}
|
|
62509
|
+
const isAutoAnimation = openAnimation === true || openAnimation === "auto";
|
|
62364
62510
|
// The dialog and the anchor are one box, and what plays between them is the
|
|
62365
62511
|
// browser's own morph (popup_lift.js) — nothing this dialog does to its own
|
|
62366
62512
|
// box. So it arms no CSS transition of its own, which is not merely useless
|
|
@@ -62368,11 +62514,12 @@ const useDialogProps = props => {
|
|
|
62368
62514
|
// with allow-discrete, and a dialog kept rendered for the length of its exit
|
|
62369
62515
|
// is exactly what the picture taken of the state it closes into must not
|
|
62370
62516
|
// show.
|
|
62371
|
-
const lifting =
|
|
62517
|
+
const lifting = openAnimation === "lifting";
|
|
62518
|
+
const liftsOnClose = closeAnimation === "lifting";
|
|
62372
62519
|
// Dialog never has a real anchor to POSITION against (see this file's top
|
|
62373
62520
|
// comment), so this is always the "no anchor" path — the same one Popover's
|
|
62374
62521
|
// own custom renderer falls into when it has no real anchor either.
|
|
62375
|
-
const resolvedAnimationKind = isAutoAnimation ? resolveAutoAnimationKind(undefined, parsedPositionArea) :
|
|
62522
|
+
const resolvedAnimationKind = isAutoAnimation ? resolveAutoAnimationKind(undefined, parsedPositionArea) : openAnimation;
|
|
62376
62523
|
// Not gated on isAutoAnimation — an explicit animation="sliding" needs a
|
|
62377
62524
|
// concrete direction just as much as an auto-resolved one does (same as
|
|
62378
62525
|
// Popover's own "sliding"/"expanding" resolution step in openEffect).
|
|
@@ -62421,13 +62568,11 @@ const useDialogProps = props => {
|
|
|
62421
62568
|
// is in front NOW, which only the caller knows. Resolved at the close for
|
|
62422
62569
|
// that reason: the element it names changes while the popup is open, so
|
|
62423
62570
|
// anything read at the opening would be the walk's starting point again.
|
|
62571
|
+
// Silent when it names nothing: the close may be what renders it, and
|
|
62572
|
+
// popup_lift.js asks again until it is there (and warns past that).
|
|
62424
62573
|
const resolveLiftAnchorElement = () => {
|
|
62425
62574
|
if (typeof liftAnchor === "string") {
|
|
62426
|
-
|
|
62427
|
-
if (!liftAnchorElementById) {
|
|
62428
|
-
console.warn(`Dialog: liftAnchor="${liftAnchor}" did not match any element`);
|
|
62429
|
-
}
|
|
62430
|
-
return liftAnchorElementById;
|
|
62575
|
+
return document.getElementById(liftAnchor);
|
|
62431
62576
|
}
|
|
62432
62577
|
// A ref is unwrapped even when it holds nothing, the same way `anchor` is:
|
|
62433
62578
|
// the ref object itself has no box to come back to.
|
|
@@ -62439,7 +62584,7 @@ const useDialogProps = props => {
|
|
|
62439
62584
|
// provided the change happens between its two pictures, which is what
|
|
62440
62585
|
// handing it to the controller buys (see popup_lift.js and
|
|
62441
62586
|
// open_controller.js's own transitionChange).
|
|
62442
|
-
openController.transitionChange =
|
|
62587
|
+
openController.transitionChange = liftsOnClose ? (applyChange, {
|
|
62443
62588
|
opened,
|
|
62444
62589
|
event
|
|
62445
62590
|
}) => {
|
|
@@ -62447,29 +62592,29 @@ const useDialogProps = props => {
|
|
|
62447
62592
|
// A mount-time opening was never seen closed (see openEffect's own
|
|
62448
62593
|
// `silent`): there is no box it comes from, because nothing was shown
|
|
62449
62594
|
// before it.
|
|
62450
|
-
if (!dialogEl || opened && event.detail.silent) {
|
|
62595
|
+
if (!dialogEl || opened && (!lifting || event.detail.silent)) {
|
|
62451
62596
|
applyChange();
|
|
62452
62597
|
return;
|
|
62453
62598
|
}
|
|
62454
|
-
|
|
62455
|
-
|
|
62456
|
-
|
|
62457
|
-
|
|
62458
|
-
|
|
62459
|
-
|
|
62460
|
-
|
|
62599
|
+
if (!opened) {
|
|
62600
|
+
// Read once the close is made (popup_lift.js): the box it lands in
|
|
62601
|
+
// may be one the close itself renders.
|
|
62602
|
+
liftPopupFromAnchor(dialogEl, liftAnchor ? resolveLiftAnchorElement : () => anchorElementRef.current, applyChange, {
|
|
62603
|
+
opened,
|
|
62604
|
+
lift,
|
|
62605
|
+
waitForAnchor: Boolean(liftAnchor)
|
|
62606
|
+
});
|
|
62607
|
+
return;
|
|
62461
62608
|
}
|
|
62609
|
+
const anchorElement = resolveAnchorElement(event);
|
|
62462
62610
|
if (!anchorElement) {
|
|
62463
|
-
|
|
62611
|
+
{
|
|
62464
62612
|
console.warn(`[navi] Dialog has animation="lifting" and no anchor to lift out of, so it simply appears. The anchor is whatever opened it — a <Button command="--navi-open">, the "source" given to triggerNaviCommand — or the "anchor" prop.`);
|
|
62465
62613
|
}
|
|
62466
|
-
if (!opened && liftAnchor) {
|
|
62467
|
-
console.warn(`[navi] Dialog has animation="lifting" and a "liftAnchor" naming nothing on screen, so it simply closes. The element it names is where the box comes back to, and it has to be in the document at the close.`);
|
|
62468
|
-
}
|
|
62469
62614
|
applyChange();
|
|
62470
62615
|
return;
|
|
62471
62616
|
}
|
|
62472
|
-
liftPopupFromAnchor(dialogEl, anchorElement, applyChange, {
|
|
62617
|
+
liftPopupFromAnchor(dialogEl, () => anchorElement, applyChange, {
|
|
62473
62618
|
opened,
|
|
62474
62619
|
lift
|
|
62475
62620
|
});
|
|
@@ -65284,8 +65429,8 @@ const PickerCustom = props => {
|
|
|
65284
65429
|
// before computing popupId below, so two Pickers without an explicit id never collide.
|
|
65285
65430
|
// Captured before the fallback chain below overwrites props.id — needed to
|
|
65286
65431
|
// know whether the id actually came from the caller (stable) or from
|
|
65287
|
-
// useId()/ControlIdContext (
|
|
65288
|
-
// pickerNavType below.
|
|
65432
|
+
// useId()/ControlIdContext (a generated id names one mount: a reload, or a
|
|
65433
|
+
// return to this page, generates another), see pickerNavType below.
|
|
65289
65434
|
const hasExplicitId = Boolean(props.id);
|
|
65290
65435
|
const idDefault = useId();
|
|
65291
65436
|
const controlId = useContext(ControlIdContext);
|
|
@@ -65362,10 +65507,12 @@ const PickerCustom = props => {
|
|
|
65362
65507
|
// pushes a history entry so the back button closes it. Every other case
|
|
65363
65508
|
// (popover mode, or a dialog whose id was auto-generated via useId()/
|
|
65364
65509
|
// ControlIdContext) replaces the current history state instead — a
|
|
65365
|
-
// generated id
|
|
65366
|
-
//
|
|
65367
|
-
//
|
|
65368
|
-
//
|
|
65510
|
+
// generated id names one mount, so pushing it would either leave an entry
|
|
65511
|
+
// nothing reads or, worse, collide with a different component's own
|
|
65512
|
+
// generated id (see useNavState's own fallback for the same concern,
|
|
65513
|
+
// applied here proactively for the id we control). What a generated id
|
|
65514
|
+
// costs either way: the state is written, and the mount coming back to
|
|
65515
|
+
// the page (or a reload) finds it under a key it does not have.
|
|
65369
65516
|
const pickerNavType = mode === "dialog" && hasExplicitId ? "push" : "replace";
|
|
65370
65517
|
const [expanded, enterExpanded, leaveExpanded] = useNavState(popupId, {
|
|
65371
65518
|
type: pickerNavType,
|
|
@@ -65904,6 +66051,7 @@ const PickerContentInsidePopup = props => {
|
|
|
65904
66051
|
popupWidthFitContent,
|
|
65905
66052
|
animation,
|
|
65906
66053
|
lift,
|
|
66054
|
+
liftAnchor,
|
|
65907
66055
|
animationDuration,
|
|
65908
66056
|
// mode="callout": what the callout says about what it holds, and paints
|
|
65909
66057
|
// in its border and icon — "none" for a plain tooltip (see the callout
|
|
@@ -66000,6 +66148,7 @@ const PickerContentInsidePopup = props => {
|
|
|
66000
66148
|
dockedOnSmallTouchScreen: isPopover ? undefined : dockedOnSmallTouchScreen,
|
|
66001
66149
|
sizeFromAnchor: isPopover ? undefined : dialogSizeFromAnchor,
|
|
66002
66150
|
lift: isPopover ? undefined : lift,
|
|
66151
|
+
liftAnchor: isPopover ? undefined : liftAnchor,
|
|
66003
66152
|
children: jsx(PopupModeContext.Provider, {
|
|
66004
66153
|
value: mode,
|
|
66005
66154
|
children: children
|
|
@@ -75471,8 +75620,9 @@ const PickerFirstResolver = props => {
|
|
|
75471
75620
|
* children?: import("ignore:preact").ComponentChildren,
|
|
75472
75621
|
* mode?: "popover" | "dialog" | "callout",
|
|
75473
75622
|
* openOn?: "press" | "longpress" | "contextmenu" | string | string[],
|
|
75474
|
-
* animation?: boolean | "auto" | "fading" | "scaling" | "sliding" | "lifting" | `slide-from-${string}`,
|
|
75623
|
+
* animation?: boolean | "auto" | "fading" | "scaling" | "sliding" | "lifting" | `slide-from-${string}` | { open: boolean | "auto" | "fading" | "scaling" | "sliding" | `slide-from-${string}`, close: "lifting" },
|
|
75475
75624
|
* lift?: "box" | "scene",
|
|
75625
|
+
* liftAnchor?: Element | { current: Element } | string,
|
|
75476
75626
|
* animationDuration?: string,
|
|
75477
75627
|
* calloutStatus?: "info" | "warning" | "error" | "success" | "none",
|
|
75478
75628
|
* calloutIcon?: boolean,
|
|
@@ -75631,6 +75781,12 @@ const PickerFirstResolver = props => {
|
|
|
75631
75781
|
* content failed to load, its value could not be resolved…). Shown as a
|
|
75632
75782
|
* callout on the trigger, open or closed — the caller has nothing to place.
|
|
75633
75783
|
* Dismissing it discards that error; a new `error` value raises another one.
|
|
75784
|
+
* @param {string} [id] What the popup's open state is kept under in the
|
|
75785
|
+
* history entry: a screen left and come back to finds the picker open, and
|
|
75786
|
+
* in dialog mode the opening is an entry of its own, closed by the back
|
|
75787
|
+
* button before the screen is left. Left out, the key is a generated id,
|
|
75788
|
+
* which names one mount: the state survives neither leaving the screen nor a
|
|
75789
|
+
* reload. A picker whose popup leads somewhere (a link inside it) has one.
|
|
75634
75790
|
* @param {"popover"|"dialog"|"callout"} [mode] Which popup the children open
|
|
75635
75791
|
* in. Left out, a popover on a large screen and a dialog on a narrow one.
|
|
75636
75792
|
* `"callout"` shows them in the picker's own callout — the speech bubble its
|
|
@@ -75843,6 +75999,11 @@ const PickerFirstResolver = props => {
|
|
|
75843
75999
|
* that opens precisely to get bigger. It brings an opaque, blurred backdrop
|
|
75844
76000
|
* with it (`--navi-backdrop-lift-*`); `backdropVariant="discrete"` asks for
|
|
75845
76001
|
* the light wash back.
|
|
76002
|
+
* @param {Element|{current: Element}|string} [liftAnchor] Dialog mode,
|
|
76003
|
+
* Dialog's own: where a lifting close lands when that is not the trigger
|
|
76004
|
+
* (`animation="lifting"`, or `animation={{ open, close: "lifting" }}` for a
|
|
76005
|
+
* popup that opens the plain way and only lands on close),
|
|
76006
|
+
* read once the close is made (after `onClose`).
|
|
75846
76007
|
* @param {"box"|"scene"} [lift="box"] Dialog's own, under `animation="lifting"`:
|
|
75847
76008
|
* `"box"` for a card that extends (its top stays, the box uncovers the rest),
|
|
75848
76009
|
* `"scene"` for a thumbnail that is a band cut from the middle of the bigger
|