@jsenv/navi 0.29.365 → 0.29.367
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 +270 -18
- package/dist/dev/jsenv_navi.js.map +5 -5
- package/dist/jsenv_navi.js +228 -18
- package/dist/jsenv_navi.js.map +5 -5
- package/docs/popup_lift.md +9 -0
- package/docs/popup_open.md +15 -2
- package/docs/route_transitions.md +61 -15
- package/package.json +1 -1
package/dist/jsenv_navi.js
CHANGED
|
@@ -29721,6 +29721,9 @@ const TRANSITION_TARGET_ATTRIBUTE = "data-navi-route-transition-target";
|
|
|
29721
29721
|
// link being pressed (see <Link routeTransition>), or handed to navTo(). It answers
|
|
29722
29722
|
// for that navigation and for no other — the next one is back to the relations.
|
|
29723
29723
|
const TRANSITION_REQUEST_ATTRIBUTE = "data-navi-route-transition-request";
|
|
29724
|
+
// What a history entry remembers of the crossing that created it, in the
|
|
29725
|
+
// entry's own state: `{ from, type, direction, duration }` (see recordCrossing).
|
|
29726
|
+
const CROSSING_STATE_KEY = "jsenv_route_transition";
|
|
29724
29727
|
const AREA_NAME = "navi-route-transition";
|
|
29725
29728
|
// The pictures carrying the movement, among everything else it takes along —
|
|
29726
29729
|
// the pages', or the document's own when the pages ARE the document (see
|
|
@@ -30269,6 +30272,106 @@ const normalizeRequest = transition => {
|
|
|
30269
30272
|
};
|
|
30270
30273
|
};
|
|
30271
30274
|
|
|
30275
|
+
/**
|
|
30276
|
+
* What a TRAVERSAL asks for: the crossing it retraces.
|
|
30277
|
+
*
|
|
30278
|
+
* The entry a push creates remembers the crossing that created it (see
|
|
30279
|
+
* recordCrossing). A back onto the page that crossing came from undoes it —
|
|
30280
|
+
* the same movement, the other way — and a forward onto an entry whose
|
|
30281
|
+
* crossing came from the page being left plays it again as it was. Both
|
|
30282
|
+
* entries are read because each side is the only one that knows its case: the
|
|
30283
|
+
* entry being LEFT says how it was reached (a back), the entry being REACHED
|
|
30284
|
+
* says how it was reached (a forward).
|
|
30285
|
+
*
|
|
30286
|
+
* Both can be true at once — A, B, A again: leaving the second A for B is the
|
|
30287
|
+
* way back of A → B and the way in of B → A. The entries' depths in the stack
|
|
30288
|
+
* tell them apart; without a depth on both, a back is assumed, the traversal
|
|
30289
|
+
* by far the most often made.
|
|
30290
|
+
*
|
|
30291
|
+
* Answers in the shape of readNavigationRequest, with every field said, so
|
|
30292
|
+
* that the relations have nothing left to answer for — and marked as a replay,
|
|
30293
|
+
* because one relation still outranks it: the one written for the exact way
|
|
30294
|
+
* travelled (see the watcher's onMove).
|
|
30295
|
+
*/
|
|
30296
|
+
const readTraversalReplay = ({
|
|
30297
|
+
url,
|
|
30298
|
+
state
|
|
30299
|
+
}, {
|
|
30300
|
+
fromUrl,
|
|
30301
|
+
fromState
|
|
30302
|
+
}) => {
|
|
30303
|
+
const to = absoluteUrl(url);
|
|
30304
|
+
const from = absoluteUrl(fromUrl);
|
|
30305
|
+
if (!to || !from) {
|
|
30306
|
+
return null;
|
|
30307
|
+
}
|
|
30308
|
+
const crossingIn = crossingRecordedOn(state);
|
|
30309
|
+
const crossingOut = crossingRecordedOn(fromState);
|
|
30310
|
+
const isForward = crossingIn !== null && crossingIn.from === from;
|
|
30311
|
+
const isBack = crossingOut !== null && crossingOut.from === to;
|
|
30312
|
+
if (isForward && isBack) {
|
|
30313
|
+
const depthIn = navDepthOf(state);
|
|
30314
|
+
const depthOut = navDepthOf(fromState);
|
|
30315
|
+
if (depthIn !== undefined && depthOut !== undefined && depthIn > depthOut) {
|
|
30316
|
+
return replayOf(crossingIn);
|
|
30317
|
+
}
|
|
30318
|
+
return replayOf(reverseCrossing(crossingOut));
|
|
30319
|
+
}
|
|
30320
|
+
if (isForward) {
|
|
30321
|
+
return replayOf(crossingIn);
|
|
30322
|
+
}
|
|
30323
|
+
if (isBack) {
|
|
30324
|
+
return replayOf(reverseCrossing(crossingOut));
|
|
30325
|
+
}
|
|
30326
|
+
return null;
|
|
30327
|
+
};
|
|
30328
|
+
const crossingRecordedOn = state => {
|
|
30329
|
+
if (!state) {
|
|
30330
|
+
return null;
|
|
30331
|
+
}
|
|
30332
|
+
const crossing = state[CROSSING_STATE_KEY];
|
|
30333
|
+
if (!crossing || typeof crossing.from !== "string") {
|
|
30334
|
+
return null;
|
|
30335
|
+
}
|
|
30336
|
+
return crossing;
|
|
30337
|
+
};
|
|
30338
|
+
const navDepthOf = state => {
|
|
30339
|
+
if (state && typeof state[NAV_DEPTH_STATE_KEY] === "number") {
|
|
30340
|
+
return state[NAV_DEPTH_STATE_KEY];
|
|
30341
|
+
}
|
|
30342
|
+
return undefined;
|
|
30343
|
+
};
|
|
30344
|
+
const reverseCrossing = crossing => {
|
|
30345
|
+
return {
|
|
30346
|
+
...crossing,
|
|
30347
|
+
direction: reverseDirection(crossing.direction)
|
|
30348
|
+
};
|
|
30349
|
+
};
|
|
30350
|
+
|
|
30351
|
+
// A direction that is neither ("" — a default has none) stays what it is.
|
|
30352
|
+
const reverseDirection = direction => {
|
|
30353
|
+
if (direction === "forward") {
|
|
30354
|
+
return "back";
|
|
30355
|
+
}
|
|
30356
|
+
if (direction === "back") {
|
|
30357
|
+
return "forward";
|
|
30358
|
+
}
|
|
30359
|
+
return direction;
|
|
30360
|
+
};
|
|
30361
|
+
const replayOf = ({
|
|
30362
|
+
type,
|
|
30363
|
+
direction,
|
|
30364
|
+
duration
|
|
30365
|
+
}) => {
|
|
30366
|
+
return {
|
|
30367
|
+
type,
|
|
30368
|
+
typeSaid: true,
|
|
30369
|
+
duration,
|
|
30370
|
+
direction,
|
|
30371
|
+
replay: true
|
|
30372
|
+
};
|
|
30373
|
+
};
|
|
30374
|
+
|
|
30272
30375
|
// The request first, field by field, then what was defined for this pair (or
|
|
30273
30376
|
// for everything). Written as one function because both ends of the file
|
|
30274
30377
|
// resolve the same way: the one that knows the pair, and the one that only
|
|
@@ -30344,7 +30447,14 @@ const rebuildWatcher = () => {
|
|
|
30344
30447
|
const fromPage = fromIndex === -1 ? null : pages[fromIndex];
|
|
30345
30448
|
const toPage = index === -1 ? null : pages[index];
|
|
30346
30449
|
const found = findRelation(fromPage, toPage);
|
|
30347
|
-
|
|
30450
|
+
// A traversal retraces its crossing over everything deduced here — the
|
|
30451
|
+
// reverse of a pair, a page from anywhere — and not over a relation
|
|
30452
|
+
// written for this exact way: that line is the author's one tool for
|
|
30453
|
+
// breaking reciprocity, and the back button is the way back it has to
|
|
30454
|
+
// reach. A request made by a link or a navTo() is never dropped: it is
|
|
30455
|
+
// about this one crossing, and a written relation is about every one.
|
|
30456
|
+
const request = navigationRequest && navigationRequest.replay && found && found.written ? null : navigationRequest;
|
|
30457
|
+
if (!found && !request) {
|
|
30348
30458
|
// No relation says anything about these two and this navigation asked
|
|
30349
30459
|
// for nothing: they are side by side, and silence is the fact — not a
|
|
30350
30460
|
// missing case.
|
|
@@ -30353,12 +30463,15 @@ const rebuildWatcher = () => {
|
|
|
30353
30463
|
const {
|
|
30354
30464
|
type,
|
|
30355
30465
|
duration
|
|
30356
|
-
} = resolveTransition(
|
|
30466
|
+
} = resolveTransition(request, found ? found.relation : null);
|
|
30357
30467
|
if (type === "none") {
|
|
30358
30468
|
// Silence said out loud: this way of the pair was written to play
|
|
30359
30469
|
// nothing — or this one navigation asked for nothing — where the reverse
|
|
30360
30470
|
// of the other way, or the default, would have played.
|
|
30361
30471
|
navigationAnimated = true;
|
|
30472
|
+
navigationDecision = {
|
|
30473
|
+
type: "none"
|
|
30474
|
+
};
|
|
30362
30475
|
return;
|
|
30363
30476
|
}
|
|
30364
30477
|
beginTransition({
|
|
@@ -30366,10 +30479,11 @@ const rebuildWatcher = () => {
|
|
|
30366
30479
|
url: navigationUrl,
|
|
30367
30480
|
fromUrl: navigationFromUrl,
|
|
30368
30481
|
// Which way it plays: what the navigation itself said first — the link
|
|
30369
|
-
// being pressed is where the way the app is being walked is known
|
|
30370
|
-
//
|
|
30371
|
-
// between two pages no
|
|
30372
|
-
|
|
30482
|
+
// being pressed is where the way the app is being walked is known, and
|
|
30483
|
+
// a traversal says the way it retraces — then the relation, and forward
|
|
30484
|
+
// for a navigation that asked for a movement between two pages no
|
|
30485
|
+
// relation orders.
|
|
30486
|
+
direction: request && request.direction !== undefined ? request.direction : found && found.direction || "forward",
|
|
30373
30487
|
type,
|
|
30374
30488
|
duration
|
|
30375
30489
|
});
|
|
@@ -30398,6 +30512,13 @@ let navigationUrl = null;
|
|
|
30398
30512
|
// the address has already moved and location would answer with the destination.
|
|
30399
30513
|
let navigationFromUrl = null;
|
|
30400
30514
|
let navigationAnimated = false;
|
|
30515
|
+
// "push", "replace", "traverse", … — a push is the one navigation that creates
|
|
30516
|
+
// the entry a crossing is recorded on.
|
|
30517
|
+
let navigationType = null;
|
|
30518
|
+
// What was decided for the navigation now landing — a movement, or "none" —
|
|
30519
|
+
// which is what its entry remembers (see recordCrossing). Null while nothing
|
|
30520
|
+
// has been decided, and for a navigation nothing was said about.
|
|
30521
|
+
let navigationDecision = null;
|
|
30401
30522
|
|
|
30402
30523
|
// The two ends of every navigation, watched from here on. The picture of the
|
|
30403
30524
|
// page being left has to be honest, so rendering is held from before the
|
|
@@ -30407,9 +30528,18 @@ let navigationAnimated = false;
|
|
|
30407
30528
|
// one moment the DEFAULT can decide: every relation has had its say by then.
|
|
30408
30529
|
observeBeforeRouting(details => {
|
|
30409
30530
|
navigationAnimated = false;
|
|
30410
|
-
|
|
30531
|
+
navigationDecision = null;
|
|
30532
|
+
navigationType = details.navigationType;
|
|
30411
30533
|
navigationUrl = details.url;
|
|
30412
30534
|
navigationFromUrl = documentUrlSignal.peek();
|
|
30535
|
+
// A traversal has no element and no call to ask anything: what it asks is
|
|
30536
|
+
// the crossing it retraces — reversed for a back, as it was for a forward.
|
|
30537
|
+
// Read before the document state moves, so the state peeked is the entry
|
|
30538
|
+
// being left.
|
|
30539
|
+
navigationRequest = navigationType === "traverse" ? readTraversalReplay(details, {
|
|
30540
|
+
fromUrl: navigationFromUrl,
|
|
30541
|
+
fromState: documentStateSignal.peek()
|
|
30542
|
+
}) : readNavigationRequest(details);
|
|
30413
30543
|
if (relations.length === 0 && !defaultTransition && !navigationRequest) {
|
|
30414
30544
|
return;
|
|
30415
30545
|
}
|
|
@@ -30426,17 +30556,23 @@ observeAfterRouting(() => {
|
|
|
30426
30556
|
const request = navigationRequest;
|
|
30427
30557
|
const url = navigationUrl;
|
|
30428
30558
|
const fromUrl = navigationFromUrl;
|
|
30559
|
+
const type = navigationType;
|
|
30429
30560
|
// Read here and dropped here: a request answers for the navigation it was
|
|
30430
30561
|
// made on, and the next one is back to the relations.
|
|
30431
30562
|
navigationRequest = null;
|
|
30432
30563
|
navigationUrl = null;
|
|
30433
30564
|
navigationFromUrl = null;
|
|
30565
|
+
navigationType = null;
|
|
30434
30566
|
if (!navigationAnimated && (request || defaultTransition)) {
|
|
30435
30567
|
const {
|
|
30436
30568
|
type,
|
|
30437
30569
|
duration
|
|
30438
30570
|
} = resolveTransition(request, defaultTransition);
|
|
30439
|
-
if (type
|
|
30571
|
+
if (type === "none") {
|
|
30572
|
+
navigationDecision = {
|
|
30573
|
+
type: "none"
|
|
30574
|
+
};
|
|
30575
|
+
} else {
|
|
30440
30576
|
beginTransition({
|
|
30441
30577
|
page: null,
|
|
30442
30578
|
url,
|
|
@@ -30448,15 +30584,70 @@ observeAfterRouting(() => {
|
|
|
30448
30584
|
// press that names the movement means forward unless it says
|
|
30449
30585
|
// otherwise — and a movement of navi's is written on the direction,
|
|
30450
30586
|
// so left empty it would play nothing at all.
|
|
30451
|
-
direction: request && request.direction
|
|
30587
|
+
direction: request && request.direction !== undefined ? request.direction : request && request.typeSaid ? "forward" : "",
|
|
30452
30588
|
type,
|
|
30453
30589
|
duration
|
|
30454
30590
|
});
|
|
30455
30591
|
}
|
|
30456
30592
|
}
|
|
30593
|
+
if (type === "push") {
|
|
30594
|
+
recordCrossing({
|
|
30595
|
+
url,
|
|
30596
|
+
fromUrl,
|
|
30597
|
+
decision: navigationDecision
|
|
30598
|
+
});
|
|
30599
|
+
}
|
|
30600
|
+
navigationDecision = null;
|
|
30457
30601
|
releaseRoutingRenderingHold();
|
|
30458
30602
|
});
|
|
30459
30603
|
|
|
30604
|
+
// The entry a push created remembers what was decided on the way in, so that
|
|
30605
|
+
// the traversals leaving it or landing on it retrace it (see
|
|
30606
|
+
// readTraversalReplay). Written once the navigation has landed — the decision
|
|
30607
|
+
// needs the pages to be current, which is after the entry was created — as a
|
|
30608
|
+
// state-only replace: it announces nothing and routes nothing. Nothing is
|
|
30609
|
+
// written when nothing was decided: the silence between two unrelated pages is
|
|
30610
|
+
// not a crossing to remember. A replace keeps its entry's state, so an entry
|
|
30611
|
+
// reached by one keeps the crossing that led to where it stands.
|
|
30612
|
+
const recordCrossing = ({
|
|
30613
|
+
url,
|
|
30614
|
+
fromUrl,
|
|
30615
|
+
decision
|
|
30616
|
+
}) => {
|
|
30617
|
+
if (!decision) {
|
|
30618
|
+
return;
|
|
30619
|
+
}
|
|
30620
|
+
const to = absoluteUrl(url);
|
|
30621
|
+
const from = absoluteUrl(fromUrl);
|
|
30622
|
+
if (!to || !from) {
|
|
30623
|
+
return;
|
|
30624
|
+
}
|
|
30625
|
+
if (documentUrlSignal.peek() !== to) {
|
|
30626
|
+
// Superseded before it landed: the entry now current is another one's.
|
|
30627
|
+
return;
|
|
30628
|
+
}
|
|
30629
|
+
const crossing = {
|
|
30630
|
+
from
|
|
30631
|
+
};
|
|
30632
|
+
if (decision.type !== undefined) {
|
|
30633
|
+
crossing.type = decision.type;
|
|
30634
|
+
}
|
|
30635
|
+
if (decision.direction !== undefined) {
|
|
30636
|
+
crossing.direction = decision.direction;
|
|
30637
|
+
}
|
|
30638
|
+
if (decision.duration !== undefined) {
|
|
30639
|
+
crossing.duration = decision.duration;
|
|
30640
|
+
}
|
|
30641
|
+
const state = documentStateSignal.peek();
|
|
30642
|
+
navTo(to, {
|
|
30643
|
+
replace: true,
|
|
30644
|
+
state: {
|
|
30645
|
+
...(state || {}),
|
|
30646
|
+
[CROSSING_STATE_KEY]: crossing
|
|
30647
|
+
}
|
|
30648
|
+
});
|
|
30649
|
+
};
|
|
30650
|
+
|
|
30460
30651
|
// The exact way travelled first, over the whole registry, then the reverses,
|
|
30461
30652
|
// and last the pages written from anywhere.
|
|
30462
30653
|
//
|
|
@@ -30469,6 +30660,11 @@ observeAfterRouting(() => {
|
|
|
30469
30660
|
// same destination still owns its crossing — the map, where it was drawn, is
|
|
30470
30661
|
// more precise than "from wherever". Arriving is read before leaving: between
|
|
30471
30662
|
// two such pages, the one being opened says what plays.
|
|
30663
|
+
//
|
|
30664
|
+
// Only the first answer is `written`: a sentence the author wrote about this
|
|
30665
|
+
// exact way. Every other answer is deduced from a sentence about something
|
|
30666
|
+
// else, and a traversal retracing its own crossing knows better than a
|
|
30667
|
+
// deduction (see readTraversalReplay).
|
|
30472
30668
|
const findRelation = (fromPage, toPage) => {
|
|
30473
30669
|
for (const relation of relations) {
|
|
30474
30670
|
if (!relation.from) {
|
|
@@ -30477,7 +30673,8 @@ const findRelation = (fromPage, toPage) => {
|
|
|
30477
30673
|
if (samePage$1(relation.from, fromPage) && samePage$1(relation.to, toPage)) {
|
|
30478
30674
|
return {
|
|
30479
30675
|
direction: "forward",
|
|
30480
|
-
relation
|
|
30676
|
+
relation,
|
|
30677
|
+
written: true
|
|
30481
30678
|
};
|
|
30482
30679
|
}
|
|
30483
30680
|
}
|
|
@@ -30539,12 +30736,19 @@ const beginTransition = ({
|
|
|
30539
30736
|
console.warn("A RouteTravel is animating this navigation; the route transition defined between these routes is skipped. Animate a pair of routes with RouteTravel or defineRouteTransition, not both.");
|
|
30540
30737
|
return;
|
|
30541
30738
|
}
|
|
30739
|
+
navigationDecision = {
|
|
30740
|
+
type,
|
|
30741
|
+
direction,
|
|
30742
|
+
duration
|
|
30743
|
+
};
|
|
30542
30744
|
// The two ends of the crossing, kept for the length of the movement: they are
|
|
30543
30745
|
// what lets the navigation after this one be recognised as its way back (see
|
|
30544
|
-
// turnRunningTransitionRound)
|
|
30746
|
+
// turnRunningTransitionRound) — and what it decided, which that way back
|
|
30747
|
+
// then undoes.
|
|
30545
30748
|
const transition = {
|
|
30546
30749
|
fromUrl: absoluteUrl(fromUrl),
|
|
30547
30750
|
url: absoluteUrl(url),
|
|
30751
|
+
decision: navigationDecision,
|
|
30548
30752
|
walkHome: null,
|
|
30549
30753
|
releaseReverting: null
|
|
30550
30754
|
};
|
|
@@ -30720,6 +30924,7 @@ const turnRunningTransitionRound = (fromUrl, url) => {
|
|
|
30720
30924
|
}
|
|
30721
30925
|
const animations = viewTransitionAnimations();
|
|
30722
30926
|
if (isWayInAgain) {
|
|
30927
|
+
navigationDecision = running.decision;
|
|
30723
30928
|
// The token is dropped first: the walk it stands for is the one that must
|
|
30724
30929
|
// not arrive anywhere anymore, and its promise is still pending.
|
|
30725
30930
|
running.walkHome = null;
|
|
@@ -30737,6 +30942,9 @@ const turnRunningTransitionRound = (fromUrl, url) => {
|
|
|
30737
30942
|
// played, and nothing was on screen to teleport.
|
|
30738
30943
|
return false;
|
|
30739
30944
|
}
|
|
30945
|
+
// What this navigation plays, for the entry it may create: the movement on
|
|
30946
|
+
// screen, the other way.
|
|
30947
|
+
navigationDecision = reverseCrossing(running.decision);
|
|
30740
30948
|
// Which walk home this is, so the one that arrives is the one still wanted: a
|
|
30741
30949
|
// walk turned round mid-way leaves a promise nobody cancelled, and it settles
|
|
30742
30950
|
// when the pictures reach the far end.
|
|
@@ -30939,7 +31147,7 @@ const warnAboutBothWaysWritten = ({
|
|
|
30939
31147
|
// wrote them in, and the order it will find them in to fix them.
|
|
30940
31148
|
const written = `${describePage(reverse.from)} → ${describePage(reverse.to)}`;
|
|
30941
31149
|
const added = `${describePage(from)} → ${describePage(to)}`;
|
|
30942
|
-
warnOnce(`both-ways-written:${written}|${added}`, `${written} and ${added} are both written with the same movement, so BOTH crossings play forward and this pair can never say "back" — the back button included. A relation written for the exact way travelled wins over being the reverse of another (see findRelation), which is what makes reciprocity the default: write the way back only to give it a DIFFERENT movement, or "none" to silence it. A single crossing that walks the map backwards says so on itself instead: <Link routeTransition={{ direction: "forward" }}>, or navTo(url, { routeTransition: { direction: "forward" } }).`);
|
|
31150
|
+
warnOnce(`both-ways-written:${written}|${added}`, `${written} and ${added} are both written with the same movement, so BOTH crossings play forward and this pair can never say "back" — the back button included. A relation written for the exact way travelled wins over being the reverse of another, and over the crossing a history traversal retraces (see findRelation), which is what makes reciprocity the default: write the way back only to give it a DIFFERENT movement, or "none" to silence it. A single crossing that walks the map backwards says so on itself instead: <Link routeTransition={{ direction: "forward" }}>, or navTo(url, { routeTransition: { direction: "forward" } }).`);
|
|
30943
31151
|
};
|
|
30944
31152
|
const warnPagesBothCurrent = (pageKept, pageIgnored) => {
|
|
30945
31153
|
const kept = describePage(pageKept);
|
|
@@ -64090,8 +64298,8 @@ const PickerCustom = props => {
|
|
|
64090
64298
|
// before computing popupId below, so two Pickers without an explicit id never collide.
|
|
64091
64299
|
// Captured before the fallback chain below overwrites props.id — needed to
|
|
64092
64300
|
// know whether the id actually came from the caller (stable) or from
|
|
64093
|
-
// useId()/ControlIdContext (
|
|
64094
|
-
// pickerNavType below.
|
|
64301
|
+
// useId()/ControlIdContext (a generated id names one mount: a reload, or a
|
|
64302
|
+
// return to this page, generates another), see pickerNavType below.
|
|
64095
64303
|
const hasExplicitId = Boolean(props.id);
|
|
64096
64304
|
const idDefault = useId();
|
|
64097
64305
|
const controlId = useContext(ControlIdContext);
|
|
@@ -64167,10 +64375,12 @@ const PickerCustom = props => {
|
|
|
64167
64375
|
// pushes a history entry so the back button closes it. Every other case
|
|
64168
64376
|
// (popover mode, or a dialog whose id was auto-generated via useId()/
|
|
64169
64377
|
// ControlIdContext) replaces the current history state instead — a
|
|
64170
|
-
// generated id
|
|
64171
|
-
//
|
|
64172
|
-
//
|
|
64173
|
-
//
|
|
64378
|
+
// generated id names one mount, so pushing it would either leave an entry
|
|
64379
|
+
// nothing reads or, worse, collide with a different component's own
|
|
64380
|
+
// generated id (see useNavState's own fallback for the same concern,
|
|
64381
|
+
// applied here proactively for the id we control). What a generated id
|
|
64382
|
+
// costs either way: the state is written, and the mount coming back to
|
|
64383
|
+
// the page (or a reload) finds it under a key it does not have.
|
|
64174
64384
|
const pickerNavType = mode === "dialog" && hasExplicitId ? "push" : "replace";
|
|
64175
64385
|
const [expanded, enterExpanded, leaveExpanded] = useNavState(popupId, {
|
|
64176
64386
|
type: pickerNavType,
|