@jsenv/navi 0.29.217 → 0.29.218

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.
@@ -26152,9 +26152,10 @@ const setupBrowserIntegrationViaHistory = ({
26152
26152
  const {
26153
26153
  reason,
26154
26154
  navigationType, // "load", "reload", "replace", "push", "traverse"
26155
- state,
26156
26155
  redirected,
26156
+ landOn,
26157
26157
  } = options;
26158
+ let { state } = options;
26158
26159
 
26159
26160
  // Where the entry being reached stands in this document's own stack —
26160
26161
  // decided before the state that carries it is built (see
@@ -26182,7 +26183,22 @@ const setupBrowserIntegrationViaHistory = ({
26182
26183
  } else {
26183
26184
  // traverse / reload: state comes from the history entry, no push/replace needed.
26184
26185
  markUrlAsVisited(url);
26185
- if (redirected) {
26186
+ if (landOn) {
26187
+ // The entry the back landed on, written over where it stands with
26188
+ // what must outlive the popped one (see navBack's `landOn`) — before
26189
+ // the routes read anything, so the only address they ever see is the
26190
+ // one being kept.
26191
+ state = resolveEffectiveDocumentState(landOn.state, {
26192
+ navigationType: "replace",
26193
+ currentState: state,
26194
+ sharedState: {
26195
+ jsenv_visited_urls: Array.from(visitedUrlSet),
26196
+ [NAV_DEPTH_STATE_KEY]: getNavDepth(),
26197
+ },
26198
+ });
26199
+ window.history.replaceState(state, null, url);
26200
+ rememberEntryIsOfThisDocument();
26201
+ } else if (redirected) {
26186
26202
  // The entry the browser is on names an address that only sends
26187
26203
  // elsewhere — a cold load on it, or a back into it. Written over where
26188
26204
  // it stands (the entry keeps its place in the stack, hence its state
@@ -26346,6 +26362,17 @@ const setupBrowserIntegrationViaHistory = ({
26346
26362
  window.addEventListener("popstate", (popstateEvent) => {
26347
26363
  const url = window.location.href;
26348
26364
  const state = popstateEvent.state;
26365
+ const landOn = landOnPending;
26366
+ landOnPending = null;
26367
+ if (landOn) {
26368
+ handleRoutingTask(landOn.url, {
26369
+ reason: `"popstate" event for ${url}, landing on ${landOn.url}`,
26370
+ navigationType: "traverse",
26371
+ state,
26372
+ landOn,
26373
+ });
26374
+ return;
26375
+ }
26349
26376
  handleRoutingTask(url, {
26350
26377
  reason: `"popstate" event for ${url}`,
26351
26378
  navigationType: "traverse",
@@ -26387,7 +26414,11 @@ const setupBrowserIntegrationViaHistory = ({
26387
26414
  });
26388
26415
  };
26389
26416
 
26390
- const navBack = ({ fallback } = {}) => {
26417
+ // What the next "popstate" writes over the entry it lands on, when a back
26418
+ // asked for it (see navBack's `landOn`). Read by the popstate listener,
26419
+ // which is the one place the landing is applied.
26420
+ let landOnPending = null;
26421
+ const navBack = ({ fallback, landOn } = {}) => {
26391
26422
  if (canNavBackSignal.peek()) {
26392
26423
  // Resolved once the back has landed: the "popstate" it is answered with
26393
26424
  // reaches the routing listener first (registered at setup, before this
@@ -26398,6 +26429,7 @@ const setupBrowserIntegrationViaHistory = ({
26398
26429
  once: true,
26399
26430
  });
26400
26431
  });
26432
+ landOnPending = landOn || null;
26401
26433
  window.history.back();
26402
26434
  return landedPromise;
26403
26435
  }
@@ -26600,6 +26632,12 @@ const reload = browserIntegration.reload;
26600
26632
  * Where to land when there is nothing of this document behind. It takes the
26601
26633
  * place of the current entry rather than stacking on it. Without it, a
26602
26634
  * navBack() with nowhere to go does nothing.
26635
+ * @param {{ url: string, state?: object }} [options.landOn]
26636
+ * What the entry the back lands on reads once landed: its url, and its state
26637
+ * (`undefined` keeps the state it has). Written over that entry within the
26638
+ * back's own navigation, so the routes never see the entry as it was — the
26639
+ * way a screen closed over a url keeps what was written to the url while it
26640
+ * was open (see useNavState's leave()).
26603
26641
  * @returns {Promise<boolean>|undefined}
26604
26642
  * When there is something to go back to: a promise resolved once the back
26605
26643
  * has landed and been applied (`true` — the document url and state say
@@ -26691,10 +26729,13 @@ const useNavStateBasic = (
26691
26729
  // Both push-mode closes pop the pushed entry. A keep-close that merely
26692
26730
  // rewrote it in place would leave two entries describing the same closed
26693
26731
  // screen — same url, same state — and the next back press would appear to do
26694
- // nothing. So the keep path goes back like the cancel does, then writes what
26695
- // must be kept onto the entry the back lands on. Only with nothing of this
26696
- // document behind (the state was entered on a cold-loaded url, navBack has
26697
- // nowhere to go) does it rewrite in place.
26732
+ // nothing. So the keep path goes back like the cancel does, with what must
26733
+ // be kept written onto the entry the back lands on, in the same navigation:
26734
+ // a route param written while the state was entered is in the url being
26735
+ // kept, and a routing pass reading the entry behind as it was would take
26736
+ // that param for gone. Only with nothing of this document behind (the state
26737
+ // was entered on a cold-loaded url, navBack has nowhere to go) does it
26738
+ // rewrite in place.
26698
26739
  const leave = ({ isBack } = {}) => {
26699
26740
  enteredRef.current = false;
26700
26741
  const currentStateCopy = browserIntegration.getDocumentState() || {};
@@ -26706,13 +26747,9 @@ const useNavStateBasic = (
26706
26747
  browserIntegration.navBack();
26707
26748
  return;
26708
26749
  }
26709
- const urlToKeep = window.location.href;
26710
26750
  delete currentStateCopy[id];
26711
- browserIntegration.navBack().then((landed) => {
26712
- if (!landed) {
26713
- return;
26714
- }
26715
- navTo(urlToKeep, { replace: true, state: currentStateCopy });
26751
+ browserIntegration.navBack({
26752
+ landOn: { url: window.location.href, state: currentStateCopy },
26716
26753
  });
26717
26754
  return;
26718
26755
  }
@@ -45007,16 +45044,7 @@ const writeOpenedInSignal = (signal, opened, event) => {
45007
45044
  return;
45008
45045
  }
45009
45046
  writeInSignal(signal, false, { history: "replace" });
45010
- const urlToKeep = window.location.href;
45011
- navBack().then((landed) => {
45012
- if (!landed) {
45013
- return;
45014
- }
45015
- // Often nothing at all: with no other write made while the popup was
45016
- // open, the entry landed on already reads urlToKeep and navTo skips
45017
- // the navigation entirely.
45018
- navTo(urlToKeep, { replace: true });
45019
- });
45047
+ navBack({ landOn: { url: window.location.href } });
45020
45048
  return;
45021
45049
  }
45022
45050
  writeInSignal(signal, false, { history: "replace" });