@remix-run/router 1.3.1-pre.0 → 1.3.2-pre.0

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/history.ts CHANGED
@@ -85,7 +85,7 @@ export interface Update {
85
85
  /**
86
86
  * The delta between this location and the former location in the history stack
87
87
  */
88
- delta: number;
88
+ delta: number | null;
89
89
  }
90
90
 
91
91
  /**
@@ -612,24 +612,12 @@ function getUrlBasedHistory(
612
612
  }
613
613
 
614
614
  function handlePop() {
615
- let nextAction = Action.Pop;
615
+ action = Action.Pop;
616
616
  let nextIndex = getIndex();
617
-
618
- if (nextIndex != null) {
619
- let delta = nextIndex - index;
620
- action = nextAction;
621
- index = nextIndex;
622
- if (listener) {
623
- listener({ action, location: history.location, delta });
624
- }
625
- } else {
626
- warning(
627
- false,
628
- `You are trying to perform a POP navigation to a location that was not ` +
629
- `created by @remix-run/router. This will fail silently in production. ` +
630
- `You should navigate via the router to avoid this situation (instead of ` +
631
- `using window.history.pushState/window.location.hash).`
632
- );
617
+ let delta = nextIndex == null ? null : nextIndex - index;
618
+ index = nextIndex;
619
+ if (listener) {
620
+ listener({ action, location: history.location, delta });
633
621
  }
634
622
  }
635
623
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@remix-run/router",
3
- "version": "1.3.1-pre.0",
3
+ "version": "1.3.2-pre.0",
4
4
  "description": "Nested/Data-driven/Framework-agnostic Routing",
5
5
  "keywords": [
6
6
  "remix",
package/router.ts CHANGED
@@ -621,6 +621,8 @@ export const IDLE_BLOCKER: BlockerUnblocked = {
621
621
  location: undefined,
622
622
  };
623
623
 
624
+ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
625
+
624
626
  const isBrowser =
625
627
  typeof window !== "undefined" &&
626
628
  typeof window.document !== "undefined" &&
@@ -754,10 +756,6 @@ export function createRouter(init: RouterInit): Router {
754
756
  // cancel active deferreds for eliminated routes.
755
757
  let activeDeferreds = new Map<string, DeferredData>();
756
758
 
757
- // We ony support a single active blocker at the moment since we don't have
758
- // any compelling use cases for multi-blocker yet
759
- let activeBlocker: string | null = null;
760
-
761
759
  // Store blocker functions in a separate Map outside of router state since
762
760
  // we don't need to update UI state if they change
763
761
  let blockerFunctions = new Map<string, BlockerFunction>();
@@ -781,12 +779,23 @@ export function createRouter(init: RouterInit): Router {
781
779
  return;
782
780
  }
783
781
 
782
+ warning(
783
+ blockerFunctions.size === 0 || delta != null,
784
+ "You are trying to use a blocker on a POP navigation to a location " +
785
+ "that was not created by @remix-run/router. This will fail silently in " +
786
+ "production. This can happen if you are navigating outside the router " +
787
+ "via `window.history.pushState`/`window.location.hash` instead of using " +
788
+ "router navigation APIs. This can also happen if you are using " +
789
+ "createHashRouter and the user manually changes the URL."
790
+ );
791
+
784
792
  let blockerKey = shouldBlockNavigation({
785
793
  currentLocation: state.location,
786
794
  nextLocation: location,
787
795
  historyAction,
788
796
  });
789
- if (blockerKey) {
797
+
798
+ if (blockerKey && delta != null) {
790
799
  // Restore the URL to match the current UI, but don't update router state
791
800
  ignoreNextHistoryUpdate = true;
792
801
  init.history.go(delta * -1);
@@ -1904,8 +1913,12 @@ export function createRouter(init: RouterInit): Router {
1904
1913
  "Expected a location on the redirect navigation"
1905
1914
  );
1906
1915
 
1907
- // Check if this an external redirect that goes to a new origin
1908
- if (isBrowser && typeof window?.location !== "undefined") {
1916
+ // Check if this an absolute external redirect that goes to a new origin
1917
+ if (
1918
+ ABSOLUTE_URL_REGEX.test(redirect.location) &&
1919
+ isBrowser &&
1920
+ typeof window?.location !== "undefined"
1921
+ ) {
1909
1922
  let newOrigin = init.history.createURL(redirect.location).origin;
1910
1923
  if (window.location.origin !== newOrigin) {
1911
1924
  if (replace) {
@@ -2112,12 +2125,6 @@ export function createRouter(init: RouterInit): Router {
2112
2125
 
2113
2126
  if (blockerFunctions.get(key) !== fn) {
2114
2127
  blockerFunctions.set(key, fn);
2115
- if (activeBlocker == null) {
2116
- // This is now the active blocker
2117
- activeBlocker = key;
2118
- } else if (key !== activeBlocker) {
2119
- warning(false, "A router only supports one blocker at a time");
2120
- }
2121
2128
  }
2122
2129
 
2123
2130
  return blocker;
@@ -2126,9 +2133,6 @@ export function createRouter(init: RouterInit): Router {
2126
2133
  function deleteBlocker(key: string) {
2127
2134
  state.blockers.delete(key);
2128
2135
  blockerFunctions.delete(key);
2129
- if (activeBlocker === key) {
2130
- activeBlocker = null;
2131
- }
2132
2136
  }
2133
2137
 
2134
2138
  // Utility function to update blockers, ensuring valid state transitions
@@ -2159,18 +2163,19 @@ export function createRouter(init: RouterInit): Router {
2159
2163
  nextLocation: Location;
2160
2164
  historyAction: HistoryAction;
2161
2165
  }): string | undefined {
2162
- if (activeBlocker == null) {
2166
+ if (blockerFunctions.size === 0) {
2163
2167
  return;
2164
2168
  }
2165
2169
 
2166
- // We only allow a single blocker at the moment. This will need to be
2167
- // updated if we enhance to support multiple blockers in the future
2168
- let blockerFunction = blockerFunctions.get(activeBlocker);
2169
- invariant(
2170
- blockerFunction,
2171
- "Could not find a function for the active blocker"
2172
- );
2173
- let blocker = state.blockers.get(activeBlocker);
2170
+ // We ony support a single active blocker at the moment since we don't have
2171
+ // any compelling use cases for multi-blocker yet
2172
+ if (blockerFunctions.size > 1) {
2173
+ warning(false, "A router only supports one blocker at a time");
2174
+ }
2175
+
2176
+ let entries = Array.from(blockerFunctions.entries());
2177
+ let [blockerKey, blockerFunction] = entries[entries.length - 1];
2178
+ let blocker = state.blockers.get(blockerKey);
2174
2179
 
2175
2180
  if (blocker && blocker.state === "proceeding") {
2176
2181
  // If the blocker is currently proceeding, we don't need to re-check
@@ -2181,7 +2186,7 @@ export function createRouter(init: RouterInit): Router {
2181
2186
  // At this point, we know we're unblocked/blocked so we need to check the
2182
2187
  // user-provided blocker function
2183
2188
  if (blockerFunction({ currentLocation, nextLocation, historyAction })) {
2184
- return activeBlocker;
2189
+ return blockerKey;
2185
2190
  }
2186
2191
  }
2187
2192
 
@@ -3082,10 +3087,8 @@ async function callLoaderOrAction(
3082
3087
  "Redirects returned/thrown from loaders/actions must have a Location header"
3083
3088
  );
3084
3089
 
3085
- let isAbsolute = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(location);
3086
-
3087
3090
  // Support relative routing in internal redirects
3088
- if (!isAbsolute) {
3091
+ if (!ABSOLUTE_URL_REGEX.test(location)) {
3089
3092
  let activeMatches = matches.slice(0, matches.indexOf(match) + 1);
3090
3093
  let routePathnames = getPathContributingMatches(activeMatches).map(
3091
3094
  (match) => match.pathnameBase