@@ -26510,9 +26510,10 @@ const setupBrowserIntegrationViaHistory = ({
2651026510 const {
2651126511 reason,
2651226512 navigationType, // "load", "reload", "replace", "push", "traverse"
26513- state,
2651426513 redirected,
26514+ landOn,
2651526515 } = options;
26516+ let { state } = options;
2651626517
2651726518 // Where the entry being reached stands in this document's own stack —
2651826519 // decided before the state that carries it is built (see
@@ -26540,7 +26541,22 @@ const setupBrowserIntegrationViaHistory = ({
2654026541 } else {
2654126542 // traverse / reload: state comes from the history entry, no push/replace needed.
2654226543 markUrlAsVisited(url);
26543- if (redirected) {
26544+ if (landOn) {
26545+ // The entry the back landed on, written over where it stands with
26546+ // what must outlive the popped one (see navBack's `landOn`) — before
26547+ // the routes read anything, so the only address they ever see is the
26548+ // one being kept.
26549+ state = resolveEffectiveDocumentState(landOn.state, {
26550+ navigationType: "replace",
26551+ currentState: state,
26552+ sharedState: {
26553+ jsenv_visited_urls: Array.from(visitedUrlSet),
26554+ [NAV_DEPTH_STATE_KEY]: getNavDepth(),
26555+ },
26556+ });
26557+ window.history.replaceState(state, null, url);
26558+ rememberEntryIsOfThisDocument();
26559+ } else if (redirected) {
2654426560 // The entry the browser is on names an address that only sends
2654526561 // elsewhere — a cold load on it, or a back into it. Written over where
2654626562 // it stands (the entry keeps its place in the stack, hence its state
@@ -26704,6 +26720,17 @@ const setupBrowserIntegrationViaHistory = ({
2670426720 window.addEventListener("popstate", (popstateEvent) => {
2670526721 const url = window.location.href;
2670626722 const state = popstateEvent.state;
26723+ const landOn = landOnPending;
26724+ landOnPending = null;
26725+ if (landOn) {
26726+ handleRoutingTask(landOn.url, {
26727+ reason: `"popstate" event for ${url}, landing on ${landOn.url}`,
26728+ navigationType: "traverse",
26729+ state,
26730+ landOn,
26731+ });
26732+ return;
26733+ }
2670726734 handleRoutingTask(url, {
2670826735 reason: `"popstate" event for ${url}`,
2670926736 navigationType: "traverse",
@@ -26745,7 +26772,11 @@ const setupBrowserIntegrationViaHistory = ({
2674526772 });
2674626773 };
2674726774
26748- const navBack = ({ fallback } = {}) => {
26775+ // What the next "popstate" writes over the entry it lands on, when a back
26776+ // asked for it (see navBack's `landOn`). Read by the popstate listener,
26777+ // which is the one place the landing is applied.
26778+ let landOnPending = null;
26779+ const navBack = ({ fallback, landOn } = {}) => {
2674926780 if (canNavBackSignal.peek()) {
2675026781 // Resolved once the back has landed: the "popstate" it is answered with
2675126782 // reaches the routing listener first (registered at setup, before this
@@ -26756,6 +26787,7 @@ const setupBrowserIntegrationViaHistory = ({
2675626787 once: true,
2675726788 });
2675826789 });
26790+ landOnPending = landOn || null;
2675926791 window.history.back();
2676026792 return landedPromise;
2676126793 }
@@ -26958,6 +26990,12 @@ const reload = browserIntegration.reload;
2695826990 * Where to land when there is nothing of this document behind. It takes the
2695926991 * place of the current entry rather than stacking on it. Without it, a
2696026992 * navBack() with nowhere to go does nothing.
26993+ * @param {{ url: string, state?: object }} [options.landOn]
26994+ * What the entry the back lands on reads once landed: its url, and its state
26995+ * (`undefined` keeps the state it has). Written over that entry within the
26996+ * back's own navigation, so the routes never see the entry as it was — the
26997+ * way a screen closed over a url keeps what was written to the url while it
26998+ * was open (see useNavState's leave()).
2696126999 * @returns {Promise<boolean>|undefined}
2696227000 * When there is something to go back to: a promise resolved once the back
2696327001 * has landed and been applied (`true` — the document url and state say
@@ -27086,10 +27124,13 @@ const useNavStateBasic = (
2708627124 // Both push-mode closes pop the pushed entry. A keep-close that merely
2708727125 // rewrote it in place would leave two entries describing the same closed
2708827126 // screen — same url, same state — and the next back press would appear to do
27089- // nothing. So the keep path goes back like the cancel does, then writes what
27090- // must be kept onto the entry the back lands on. Only with nothing of this
27091- // document behind (the state was entered on a cold-loaded url, navBack has
27092- // nowhere to go) does it rewrite in place.
27127+ // nothing. So the keep path goes back like the cancel does, with what must
27128+ // be kept written onto the entry the back lands on, in the same navigation:
27129+ // a route param written while the state was entered is in the url being
27130+ // kept, and a routing pass reading the entry behind as it was would take
27131+ // that param for gone. Only with nothing of this document behind (the state
27132+ // was entered on a cold-loaded url, navBack has nowhere to go) does it
27133+ // rewrite in place.
2709327134 const leave = ({ isBack } = {}) => {
2709427135 enteredRef.current = false;
2709527136 const currentStateCopy = browserIntegration.getDocumentState() || {};
@@ -27101,13 +27142,9 @@ const useNavStateBasic = (
2710127142 browserIntegration.navBack();
2710227143 return;
2710327144 }
27104- const urlToKeep = window.location.href;
2710527145 delete currentStateCopy[id];
27106- browserIntegration.navBack().then((landed) => {
27107- if (!landed) {
27108- return;
27109- }
27110- navTo(urlToKeep, { replace: true, state: currentStateCopy });
27146+ browserIntegration.navBack({
27147+ landOn: { url: window.location.href, state: currentStateCopy },
2711127148 });
2711227149 return;
2711327150 }
@@ -45579,16 +45616,7 @@ const writeOpenedInSignal = (signal, opened, event) => {
4557945616 return;
4558045617 }
4558145618 writeInSignal(signal, false, { history: "replace" });
45582- const urlToKeep = window.location.href;
45583- navBack().then((landed) => {
45584- if (!landed) {
45585- return;
45586- }
45587- // Often nothing at all: with no other write made while the popup was
45588- // open, the entry landed on already reads urlToKeep and navTo skips
45589- // the navigation entirely.
45590- navTo(urlToKeep, { replace: true });
45591- });
45619+ navBack({ landOn: { url: window.location.href } });
4559245620 return;
4559345621 }
4559445622 writeInSignal(signal, false, { history: "replace" });
0 commit comments