@remix-run/router 1.6.3 → 1.7.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/CHANGELOG.md +53 -0
- package/dist/history.d.ts +6 -6
- package/dist/router.cjs.js +378 -234
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +69 -41
- package/dist/router.js +365 -229
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +378 -234
- package/dist/router.umd.js.map +1 -1
- package/dist/router.umd.min.js +2 -2
- package/dist/router.umd.min.js.map +1 -1
- package/dist/utils.d.ts +54 -28
- package/package.json +1 -1
- package/router.ts +501 -277
- package/utils.ts +44 -20
package/dist/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.
|
|
2
|
+
* @remix-run/router v1.7.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -708,26 +708,21 @@ function generatePath(originalPath, params) {
|
|
|
708
708
|
}
|
|
709
709
|
// ensure `/` is added at the beginning if the path is absolute
|
|
710
710
|
const prefix = path.startsWith("/") ? "/" : "";
|
|
711
|
+
const stringify = p => p == null ? "" : typeof p === "string" ? p : String(p);
|
|
711
712
|
const segments = path.split(/\/+/).map((segment, index, array) => {
|
|
712
713
|
const isLastSegment = index === array.length - 1;
|
|
713
714
|
// only apply the splat if it's the last segment
|
|
714
715
|
if (isLastSegment && segment === "*") {
|
|
715
716
|
const star = "*";
|
|
716
|
-
const starParam = params[star];
|
|
717
717
|
// Apply the splat
|
|
718
|
-
return
|
|
718
|
+
return stringify(params[star]);
|
|
719
719
|
}
|
|
720
720
|
const keyMatch = segment.match(/^:(\w+)(\??)$/);
|
|
721
721
|
if (keyMatch) {
|
|
722
722
|
const [, key, optional] = keyMatch;
|
|
723
723
|
let param = params[key];
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
if (param == null) {
|
|
728
|
-
invariant(false, "Missing \":" + key + "\" param");
|
|
729
|
-
}
|
|
730
|
-
return param;
|
|
724
|
+
invariant(optional === "?" || param != null, "Missing \":" + key + "\" param");
|
|
725
|
+
return stringify(param);
|
|
731
726
|
}
|
|
732
727
|
// Remove any optional markers from optional static segments
|
|
733
728
|
return segment.replace(/\?$/g, "");
|
|
@@ -1202,7 +1197,9 @@ const IDLE_NAVIGATION = {
|
|
|
1202
1197
|
formMethod: undefined,
|
|
1203
1198
|
formAction: undefined,
|
|
1204
1199
|
formEncType: undefined,
|
|
1205
|
-
formData: undefined
|
|
1200
|
+
formData: undefined,
|
|
1201
|
+
json: undefined,
|
|
1202
|
+
text: undefined
|
|
1206
1203
|
};
|
|
1207
1204
|
const IDLE_FETCHER = {
|
|
1208
1205
|
state: "idle",
|
|
@@ -1210,7 +1207,9 @@ const IDLE_FETCHER = {
|
|
|
1210
1207
|
formMethod: undefined,
|
|
1211
1208
|
formAction: undefined,
|
|
1212
1209
|
formEncType: undefined,
|
|
1213
|
-
formData: undefined
|
|
1210
|
+
formData: undefined,
|
|
1211
|
+
json: undefined,
|
|
1212
|
+
text: undefined
|
|
1214
1213
|
};
|
|
1215
1214
|
const IDLE_BLOCKER = {
|
|
1216
1215
|
state: "unblocked",
|
|
@@ -1404,9 +1403,10 @@ function createRouter(init) {
|
|
|
1404
1403
|
init.history.go(delta);
|
|
1405
1404
|
},
|
|
1406
1405
|
reset() {
|
|
1407
|
-
|
|
1406
|
+
let blockers = new Map(state.blockers);
|
|
1407
|
+
blockers.set(blockerKey, IDLE_BLOCKER);
|
|
1408
1408
|
updateState({
|
|
1409
|
-
blockers
|
|
1409
|
+
blockers
|
|
1410
1410
|
});
|
|
1411
1411
|
}
|
|
1412
1412
|
});
|
|
@@ -1476,9 +1476,8 @@ function createRouter(init) {
|
|
|
1476
1476
|
let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
|
|
1477
1477
|
// On a successful navigation we can assume we got through all blockers
|
|
1478
1478
|
// so we can start fresh
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
}
|
|
1479
|
+
let blockers = new Map();
|
|
1480
|
+
blockerFunctions.clear();
|
|
1482
1481
|
// Always respect the user flag. Otherwise don't reset on mutation
|
|
1483
1482
|
// submission navigations unless they redirect
|
|
1484
1483
|
let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
|
|
@@ -1486,6 +1485,11 @@ function createRouter(init) {
|
|
|
1486
1485
|
dataRoutes = inFlightDataRoutes;
|
|
1487
1486
|
inFlightDataRoutes = undefined;
|
|
1488
1487
|
}
|
|
1488
|
+
if (isUninterruptedRevalidation) ; else if (pendingAction === Action.Pop) ; else if (pendingAction === Action.Push) {
|
|
1489
|
+
init.history.push(location, location.state);
|
|
1490
|
+
} else if (pendingAction === Action.Replace) {
|
|
1491
|
+
init.history.replace(location, location.state);
|
|
1492
|
+
}
|
|
1489
1493
|
updateState(_extends({}, newState, {
|
|
1490
1494
|
actionData,
|
|
1491
1495
|
loaderData,
|
|
@@ -1496,13 +1500,8 @@ function createRouter(init) {
|
|
|
1496
1500
|
revalidation: "idle",
|
|
1497
1501
|
restoreScrollPosition: getSavedScrollPosition(location, newState.matches || state.matches),
|
|
1498
1502
|
preventScrollReset,
|
|
1499
|
-
blockers
|
|
1503
|
+
blockers
|
|
1500
1504
|
}));
|
|
1501
|
-
if (isUninterruptedRevalidation) ; else if (pendingAction === Action.Pop) ; else if (pendingAction === Action.Push) {
|
|
1502
|
-
init.history.push(location, location.state);
|
|
1503
|
-
} else if (pendingAction === Action.Replace) {
|
|
1504
|
-
init.history.replace(location, location.state);
|
|
1505
|
-
}
|
|
1506
1505
|
// Reset stateful navigation vars
|
|
1507
1506
|
pendingAction = Action.Pop;
|
|
1508
1507
|
pendingPreventScrollReset = false;
|
|
@@ -1565,9 +1564,10 @@ function createRouter(init) {
|
|
|
1565
1564
|
navigate(to, opts);
|
|
1566
1565
|
},
|
|
1567
1566
|
reset() {
|
|
1568
|
-
|
|
1567
|
+
let blockers = new Map(state.blockers);
|
|
1568
|
+
blockers.set(blockerKey, IDLE_BLOCKER);
|
|
1569
1569
|
updateState({
|
|
1570
|
-
blockers
|
|
1570
|
+
blockers
|
|
1571
1571
|
});
|
|
1572
1572
|
}
|
|
1573
1573
|
});
|
|
@@ -1684,11 +1684,7 @@ function createRouter(init) {
|
|
|
1684
1684
|
}
|
|
1685
1685
|
pendingActionData = actionOutput.pendingActionData;
|
|
1686
1686
|
pendingError = actionOutput.pendingActionError;
|
|
1687
|
-
|
|
1688
|
-
state: "loading",
|
|
1689
|
-
location
|
|
1690
|
-
}, opts.submission);
|
|
1691
|
-
loadingNavigation = navigation;
|
|
1687
|
+
loadingNavigation = getLoadingNavigation(location, opts.submission);
|
|
1692
1688
|
// Create a GET request for the loaders
|
|
1693
1689
|
request = new Request(request.url, {
|
|
1694
1690
|
signal: request.signal
|
|
@@ -1719,12 +1715,12 @@ function createRouter(init) {
|
|
|
1719
1715
|
// Call the action matched by the leaf route for this navigation and handle
|
|
1720
1716
|
// redirects/errors
|
|
1721
1717
|
async function handleAction(request, location, submission, matches, opts) {
|
|
1718
|
+
if (opts === void 0) {
|
|
1719
|
+
opts = {};
|
|
1720
|
+
}
|
|
1722
1721
|
interruptActiveLoads();
|
|
1723
1722
|
// Put us in a submitting state
|
|
1724
|
-
let navigation =
|
|
1725
|
-
state: "submitting",
|
|
1726
|
-
location
|
|
1727
|
-
}, submission);
|
|
1723
|
+
let navigation = getSubmittingNavigation(location, submission);
|
|
1728
1724
|
updateState({
|
|
1729
1725
|
navigation
|
|
1730
1726
|
});
|
|
@@ -1800,28 +1796,12 @@ function createRouter(init) {
|
|
|
1800
1796
|
// errors, etc.
|
|
1801
1797
|
async function handleLoaders(request, location, matches, overrideNavigation, submission, fetcherSubmission, replace, pendingActionData, pendingError) {
|
|
1802
1798
|
// Figure out the right navigation we want to use for data loading
|
|
1803
|
-
let loadingNavigation = overrideNavigation;
|
|
1804
|
-
if (!loadingNavigation) {
|
|
1805
|
-
let navigation = _extends({
|
|
1806
|
-
state: "loading",
|
|
1807
|
-
location,
|
|
1808
|
-
formMethod: undefined,
|
|
1809
|
-
formAction: undefined,
|
|
1810
|
-
formEncType: undefined,
|
|
1811
|
-
formData: undefined
|
|
1812
|
-
}, submission);
|
|
1813
|
-
loadingNavigation = navigation;
|
|
1814
|
-
}
|
|
1799
|
+
let loadingNavigation = overrideNavigation || getLoadingNavigation(location, submission);
|
|
1815
1800
|
// If this was a redirect from an action we don't have a "submission" but
|
|
1816
1801
|
// we have it on the loading navigation so use that if available
|
|
1817
|
-
let activeSubmission = submission || fetcherSubmission
|
|
1818
|
-
formMethod: loadingNavigation.formMethod,
|
|
1819
|
-
formAction: loadingNavigation.formAction,
|
|
1820
|
-
formData: loadingNavigation.formData,
|
|
1821
|
-
formEncType: loadingNavigation.formEncType
|
|
1822
|
-
} : undefined;
|
|
1802
|
+
let activeSubmission = submission || fetcherSubmission || getSubmissionFromNavigation(loadingNavigation);
|
|
1823
1803
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
1824
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError);
|
|
1804
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, activeSubmission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError);
|
|
1825
1805
|
// Cancel pending deferreds for no-longer-matched routes or routes we're
|
|
1826
1806
|
// about to reload. Note that if this is an action reload we would have
|
|
1827
1807
|
// already cancelled all pending deferreds so this would be a no-op
|
|
@@ -1850,15 +1830,7 @@ function createRouter(init) {
|
|
|
1850
1830
|
if (!isUninterruptedRevalidation) {
|
|
1851
1831
|
revalidatingFetchers.forEach(rf => {
|
|
1852
1832
|
let fetcher = state.fetchers.get(rf.key);
|
|
1853
|
-
let revalidatingFetcher =
|
|
1854
|
-
state: "loading",
|
|
1855
|
-
data: fetcher && fetcher.data,
|
|
1856
|
-
formMethod: undefined,
|
|
1857
|
-
formAction: undefined,
|
|
1858
|
-
formEncType: undefined,
|
|
1859
|
-
formData: undefined,
|
|
1860
|
-
" _hasFetcherDoneAnything ": true
|
|
1861
|
-
};
|
|
1833
|
+
let revalidatingFetcher = getLoadingFetcher(undefined, fetcher ? fetcher.data : undefined);
|
|
1862
1834
|
state.fetchers.set(rf.key, revalidatingFetcher);
|
|
1863
1835
|
});
|
|
1864
1836
|
let actionData = pendingActionData || state.actionData;
|
|
@@ -1874,6 +1846,9 @@ function createRouter(init) {
|
|
|
1874
1846
|
}
|
|
1875
1847
|
pendingNavigationLoadId = ++incrementingLoadId;
|
|
1876
1848
|
revalidatingFetchers.forEach(rf => {
|
|
1849
|
+
if (fetchControllers.has(rf.key)) {
|
|
1850
|
+
abortFetcher(rf.key);
|
|
1851
|
+
}
|
|
1877
1852
|
if (rf.controller) {
|
|
1878
1853
|
// Fetchers use an independent AbortController so that aborting a fetcher
|
|
1879
1854
|
// (via deleteFetcher) does not abort the triggering navigation that
|
|
@@ -1959,8 +1934,13 @@ function createRouter(init) {
|
|
|
1959
1934
|
}
|
|
1960
1935
|
let {
|
|
1961
1936
|
path,
|
|
1962
|
-
submission
|
|
1937
|
+
submission,
|
|
1938
|
+
error
|
|
1963
1939
|
} = normalizeNavigateOptions(future.v7_normalizeFormMethod, true, normalizedPath, opts);
|
|
1940
|
+
if (error) {
|
|
1941
|
+
setFetcherError(key, routeId, error);
|
|
1942
|
+
return;
|
|
1943
|
+
}
|
|
1964
1944
|
let match = getTargetMatch(matches, path);
|
|
1965
1945
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1966
1946
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
@@ -1991,12 +1971,7 @@ function createRouter(init) {
|
|
|
1991
1971
|
}
|
|
1992
1972
|
// Put this fetcher into it's submitting state
|
|
1993
1973
|
let existingFetcher = state.fetchers.get(key);
|
|
1994
|
-
let fetcher =
|
|
1995
|
-
state: "submitting"
|
|
1996
|
-
}, submission, {
|
|
1997
|
-
data: existingFetcher && existingFetcher.data,
|
|
1998
|
-
" _hasFetcherDoneAnything ": true
|
|
1999
|
-
});
|
|
1974
|
+
let fetcher = getSubmittingFetcher(submission, existingFetcher);
|
|
2000
1975
|
state.fetchers.set(key, fetcher);
|
|
2001
1976
|
updateState({
|
|
2002
1977
|
fetchers: new Map(state.fetchers)
|
|
@@ -2017,12 +1992,7 @@ function createRouter(init) {
|
|
|
2017
1992
|
if (isRedirectResult(actionResult)) {
|
|
2018
1993
|
fetchControllers.delete(key);
|
|
2019
1994
|
fetchRedirectIds.add(key);
|
|
2020
|
-
let loadingFetcher =
|
|
2021
|
-
state: "loading"
|
|
2022
|
-
}, submission, {
|
|
2023
|
-
data: undefined,
|
|
2024
|
-
" _hasFetcherDoneAnything ": true
|
|
2025
|
-
});
|
|
1995
|
+
let loadingFetcher = getLoadingFetcher(submission);
|
|
2026
1996
|
state.fetchers.set(key, loadingFetcher);
|
|
2027
1997
|
updateState({
|
|
2028
1998
|
fetchers: new Map(state.fetchers)
|
|
@@ -2051,14 +2021,9 @@ function createRouter(init) {
|
|
|
2051
2021
|
invariant(matches, "Didn't find any matches after fetcher action");
|
|
2052
2022
|
let loadId = ++incrementingLoadId;
|
|
2053
2023
|
fetchReloadIds.set(key, loadId);
|
|
2054
|
-
let loadFetcher =
|
|
2055
|
-
state: "loading",
|
|
2056
|
-
data: actionResult.data
|
|
2057
|
-
}, submission, {
|
|
2058
|
-
" _hasFetcherDoneAnything ": true
|
|
2059
|
-
});
|
|
2024
|
+
let loadFetcher = getLoadingFetcher(submission, actionResult.data);
|
|
2060
2025
|
state.fetchers.set(key, loadFetcher);
|
|
2061
|
-
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, {
|
|
2026
|
+
let [matchesToLoad, revalidatingFetchers] = getMatchesToLoad(init.history, state, matches, submission, nextLocation, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, {
|
|
2062
2027
|
[match.route.id]: actionResult.data
|
|
2063
2028
|
}, undefined // No need to send through errors since we short circuit above
|
|
2064
2029
|
);
|
|
@@ -2068,16 +2033,11 @@ function createRouter(init) {
|
|
|
2068
2033
|
revalidatingFetchers.filter(rf => rf.key !== key).forEach(rf => {
|
|
2069
2034
|
let staleKey = rf.key;
|
|
2070
2035
|
let existingFetcher = state.fetchers.get(staleKey);
|
|
2071
|
-
let revalidatingFetcher =
|
|
2072
|
-
state: "loading",
|
|
2073
|
-
data: existingFetcher && existingFetcher.data,
|
|
2074
|
-
formMethod: undefined,
|
|
2075
|
-
formAction: undefined,
|
|
2076
|
-
formEncType: undefined,
|
|
2077
|
-
formData: undefined,
|
|
2078
|
-
" _hasFetcherDoneAnything ": true
|
|
2079
|
-
};
|
|
2036
|
+
let revalidatingFetcher = getLoadingFetcher(undefined, existingFetcher ? existingFetcher.data : undefined);
|
|
2080
2037
|
state.fetchers.set(staleKey, revalidatingFetcher);
|
|
2038
|
+
if (fetchControllers.has(staleKey)) {
|
|
2039
|
+
abortFetcher(staleKey);
|
|
2040
|
+
}
|
|
2081
2041
|
if (rf.controller) {
|
|
2082
2042
|
fetchControllers.set(staleKey, rf.controller);
|
|
2083
2043
|
}
|
|
@@ -2111,15 +2071,7 @@ function createRouter(init) {
|
|
|
2111
2071
|
// Since we let revalidations complete even if the submitting fetcher was
|
|
2112
2072
|
// deleted, only put it back to idle if it hasn't been deleted
|
|
2113
2073
|
if (state.fetchers.has(key)) {
|
|
2114
|
-
let doneFetcher =
|
|
2115
|
-
state: "idle",
|
|
2116
|
-
data: actionResult.data,
|
|
2117
|
-
formMethod: undefined,
|
|
2118
|
-
formAction: undefined,
|
|
2119
|
-
formEncType: undefined,
|
|
2120
|
-
formData: undefined,
|
|
2121
|
-
" _hasFetcherDoneAnything ": true
|
|
2122
|
-
};
|
|
2074
|
+
let doneFetcher = getDoneFetcher(actionResult.data);
|
|
2123
2075
|
state.fetchers.set(key, doneFetcher);
|
|
2124
2076
|
}
|
|
2125
2077
|
let didAbortFetchLoads = abortStaleFetchLoads(loadId);
|
|
@@ -2152,16 +2104,7 @@ function createRouter(init) {
|
|
|
2152
2104
|
async function handleFetcherLoader(key, routeId, path, match, matches, submission) {
|
|
2153
2105
|
let existingFetcher = state.fetchers.get(key);
|
|
2154
2106
|
// Put this fetcher into it's loading state
|
|
2155
|
-
let loadingFetcher =
|
|
2156
|
-
state: "loading",
|
|
2157
|
-
formMethod: undefined,
|
|
2158
|
-
formAction: undefined,
|
|
2159
|
-
formEncType: undefined,
|
|
2160
|
-
formData: undefined
|
|
2161
|
-
}, submission, {
|
|
2162
|
-
data: existingFetcher && existingFetcher.data,
|
|
2163
|
-
" _hasFetcherDoneAnything ": true
|
|
2164
|
-
});
|
|
2107
|
+
let loadingFetcher = getLoadingFetcher(submission, existingFetcher ? existingFetcher.data : undefined);
|
|
2165
2108
|
state.fetchers.set(key, loadingFetcher);
|
|
2166
2109
|
updateState({
|
|
2167
2110
|
fetchers: new Map(state.fetchers)
|
|
@@ -2209,15 +2152,7 @@ function createRouter(init) {
|
|
|
2209
2152
|
}
|
|
2210
2153
|
invariant(!isDeferredResult(result), "Unhandled fetcher deferred data");
|
|
2211
2154
|
// Put the fetcher back into an idle state
|
|
2212
|
-
let doneFetcher =
|
|
2213
|
-
state: "idle",
|
|
2214
|
-
data: result.data,
|
|
2215
|
-
formMethod: undefined,
|
|
2216
|
-
formAction: undefined,
|
|
2217
|
-
formEncType: undefined,
|
|
2218
|
-
formData: undefined,
|
|
2219
|
-
" _hasFetcherDoneAnything ": true
|
|
2220
|
-
};
|
|
2155
|
+
let doneFetcher = getDoneFetcher(result.data);
|
|
2221
2156
|
state.fetchers.set(key, doneFetcher);
|
|
2222
2157
|
updateState({
|
|
2223
2158
|
fetchers: new Map(state.fetchers)
|
|
@@ -2277,26 +2212,13 @@ function createRouter(init) {
|
|
|
2277
2212
|
let redirectHistoryAction = replace === true ? Action.Replace : Action.Push;
|
|
2278
2213
|
// Use the incoming submission if provided, fallback on the active one in
|
|
2279
2214
|
// state.navigation
|
|
2280
|
-
let
|
|
2281
|
-
formMethod,
|
|
2282
|
-
formAction,
|
|
2283
|
-
formEncType,
|
|
2284
|
-
formData
|
|
2285
|
-
} = state.navigation;
|
|
2286
|
-
if (!submission && formMethod && formAction && formData && formEncType) {
|
|
2287
|
-
submission = {
|
|
2288
|
-
formMethod,
|
|
2289
|
-
formAction,
|
|
2290
|
-
formEncType,
|
|
2291
|
-
formData
|
|
2292
|
-
};
|
|
2293
|
-
}
|
|
2215
|
+
let activeSubmission = submission || getSubmissionFromNavigation(state.navigation);
|
|
2294
2216
|
// If this was a 307/308 submission we want to preserve the HTTP method and
|
|
2295
2217
|
// re-submit the GET/POST/PUT/PATCH/DELETE as a submission navigation to the
|
|
2296
2218
|
// redirected location
|
|
2297
|
-
if (redirectPreserveMethodStatusCodes.has(redirect.status) &&
|
|
2219
|
+
if (redirectPreserveMethodStatusCodes.has(redirect.status) && activeSubmission && isMutationMethod(activeSubmission.formMethod)) {
|
|
2298
2220
|
await startNavigation(redirectHistoryAction, redirectLocation, {
|
|
2299
|
-
submission: _extends({},
|
|
2221
|
+
submission: _extends({}, activeSubmission, {
|
|
2300
2222
|
formAction: redirect.location
|
|
2301
2223
|
}),
|
|
2302
2224
|
// Preserve this flag across redirects
|
|
@@ -2306,30 +2228,16 @@ function createRouter(init) {
|
|
|
2306
2228
|
// For a fetch action redirect, we kick off a new loading navigation
|
|
2307
2229
|
// without the fetcher submission, but we send it along for shouldRevalidate
|
|
2308
2230
|
await startNavigation(redirectHistoryAction, redirectLocation, {
|
|
2309
|
-
overrideNavigation:
|
|
2310
|
-
|
|
2311
|
-
location: redirectLocation,
|
|
2312
|
-
formMethod: undefined,
|
|
2313
|
-
formAction: undefined,
|
|
2314
|
-
formEncType: undefined,
|
|
2315
|
-
formData: undefined
|
|
2316
|
-
},
|
|
2317
|
-
fetcherSubmission: submission,
|
|
2231
|
+
overrideNavigation: getLoadingNavigation(redirectLocation),
|
|
2232
|
+
fetcherSubmission: activeSubmission,
|
|
2318
2233
|
// Preserve this flag across redirects
|
|
2319
2234
|
preventScrollReset: pendingPreventScrollReset
|
|
2320
2235
|
});
|
|
2321
2236
|
} else {
|
|
2322
|
-
//
|
|
2323
|
-
|
|
2237
|
+
// If we have a submission, we will preserve it through the redirect navigation
|
|
2238
|
+
let overrideNavigation = getLoadingNavigation(redirectLocation, activeSubmission);
|
|
2324
2239
|
await startNavigation(redirectHistoryAction, redirectLocation, {
|
|
2325
|
-
overrideNavigation
|
|
2326
|
-
state: "loading",
|
|
2327
|
-
location: redirectLocation,
|
|
2328
|
-
formMethod: submission ? submission.formMethod : undefined,
|
|
2329
|
-
formAction: submission ? submission.formAction : undefined,
|
|
2330
|
-
formEncType: submission ? submission.formEncType : undefined,
|
|
2331
|
-
formData: submission ? submission.formData : undefined
|
|
2332
|
-
},
|
|
2240
|
+
overrideNavigation,
|
|
2333
2241
|
// Preserve this flag across redirects
|
|
2334
2242
|
preventScrollReset: pendingPreventScrollReset
|
|
2335
2243
|
});
|
|
@@ -2407,15 +2315,7 @@ function createRouter(init) {
|
|
|
2407
2315
|
function markFetchersDone(keys) {
|
|
2408
2316
|
for (let key of keys) {
|
|
2409
2317
|
let fetcher = getFetcher(key);
|
|
2410
|
-
let doneFetcher =
|
|
2411
|
-
state: "idle",
|
|
2412
|
-
data: fetcher.data,
|
|
2413
|
-
formMethod: undefined,
|
|
2414
|
-
formAction: undefined,
|
|
2415
|
-
formEncType: undefined,
|
|
2416
|
-
formData: undefined,
|
|
2417
|
-
" _hasFetcherDoneAnything ": true
|
|
2418
|
-
};
|
|
2318
|
+
let doneFetcher = getDoneFetcher(fetcher.data);
|
|
2419
2319
|
state.fetchers.set(key, doneFetcher);
|
|
2420
2320
|
}
|
|
2421
2321
|
}
|
|
@@ -2467,9 +2367,10 @@ function createRouter(init) {
|
|
|
2467
2367
|
// Poor mans state machine :)
|
|
2468
2368
|
// https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM
|
|
2469
2369
|
invariant(blocker.state === "unblocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "blocked" || blocker.state === "blocked" && newBlocker.state === "proceeding" || blocker.state === "blocked" && newBlocker.state === "unblocked" || blocker.state === "proceeding" && newBlocker.state === "unblocked", "Invalid blocker state transition: " + blocker.state + " -> " + newBlocker.state);
|
|
2470
|
-
state.blockers
|
|
2370
|
+
let blockers = new Map(state.blockers);
|
|
2371
|
+
blockers.set(key, newBlocker);
|
|
2471
2372
|
updateState({
|
|
2472
|
-
blockers
|
|
2373
|
+
blockers
|
|
2473
2374
|
});
|
|
2474
2375
|
}
|
|
2475
2376
|
function shouldBlockNavigation(_ref2) {
|
|
@@ -2523,7 +2424,7 @@ function createRouter(init) {
|
|
|
2523
2424
|
function enableScrollRestoration(positions, getPosition, getKey) {
|
|
2524
2425
|
savedScrollPositions = positions;
|
|
2525
2426
|
getScrollPosition = getPosition;
|
|
2526
|
-
getScrollRestorationKey = getKey ||
|
|
2427
|
+
getScrollRestorationKey = getKey || null;
|
|
2527
2428
|
// Perform initial hydration scroll restoration, since we miss the boat on
|
|
2528
2429
|
// the initial updateState() because we've not yet rendered <ScrollRestoration/>
|
|
2529
2430
|
// and therefore have no savedScrollPositions available
|
|
@@ -2542,17 +2443,22 @@ function createRouter(init) {
|
|
|
2542
2443
|
getScrollRestorationKey = null;
|
|
2543
2444
|
};
|
|
2544
2445
|
}
|
|
2446
|
+
function getScrollKey(location, matches) {
|
|
2447
|
+
if (getScrollRestorationKey) {
|
|
2448
|
+
let key = getScrollRestorationKey(location, matches.map(m => createUseMatchesMatch(m, state.loaderData)));
|
|
2449
|
+
return key || location.key;
|
|
2450
|
+
}
|
|
2451
|
+
return location.key;
|
|
2452
|
+
}
|
|
2545
2453
|
function saveScrollPosition(location, matches) {
|
|
2546
|
-
if (savedScrollPositions &&
|
|
2547
|
-
let
|
|
2548
|
-
let key = getScrollRestorationKey(location, userMatches) || location.key;
|
|
2454
|
+
if (savedScrollPositions && getScrollPosition) {
|
|
2455
|
+
let key = getScrollKey(location, matches);
|
|
2549
2456
|
savedScrollPositions[key] = getScrollPosition();
|
|
2550
2457
|
}
|
|
2551
2458
|
}
|
|
2552
2459
|
function getSavedScrollPosition(location, matches) {
|
|
2553
|
-
if (savedScrollPositions
|
|
2554
|
-
let
|
|
2555
|
-
let key = getScrollRestorationKey(location, userMatches) || location.key;
|
|
2460
|
+
if (savedScrollPositions) {
|
|
2461
|
+
let key = getScrollKey(location, matches);
|
|
2556
2462
|
let y = savedScrollPositions[key];
|
|
2557
2463
|
if (typeof y === "number") {
|
|
2558
2464
|
return y;
|
|
@@ -2827,7 +2733,11 @@ function createStaticHandler(routes, opts) {
|
|
|
2827
2733
|
error
|
|
2828
2734
|
};
|
|
2829
2735
|
} else {
|
|
2830
|
-
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename,
|
|
2736
|
+
result = await callLoaderOrAction("action", request, actionMatch, matches, manifest, mapRouteProperties, basename, {
|
|
2737
|
+
isStaticRequest: true,
|
|
2738
|
+
isRouteRequest,
|
|
2739
|
+
requestContext
|
|
2740
|
+
});
|
|
2831
2741
|
if (request.signal.aborted) {
|
|
2832
2742
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
2833
2743
|
throw new Error(method + "() call aborted");
|
|
@@ -2938,7 +2848,11 @@ function createStaticHandler(routes, opts) {
|
|
|
2938
2848
|
activeDeferreds: null
|
|
2939
2849
|
};
|
|
2940
2850
|
}
|
|
2941
|
-
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename,
|
|
2851
|
+
let results = await Promise.all([...matchesToLoad.map(match => callLoaderOrAction("loader", request, match, matches, manifest, mapRouteProperties, basename, {
|
|
2852
|
+
isStaticRequest: true,
|
|
2853
|
+
isRouteRequest,
|
|
2854
|
+
requestContext
|
|
2855
|
+
}))]);
|
|
2942
2856
|
if (request.signal.aborted) {
|
|
2943
2857
|
let method = isRouteRequest ? "queryRoute" : "query";
|
|
2944
2858
|
throw new Error(method + "() call aborted");
|
|
@@ -2982,7 +2896,7 @@ function getStaticContextFromError(routes, context, error) {
|
|
|
2982
2896
|
return newContext;
|
|
2983
2897
|
}
|
|
2984
2898
|
function isSubmissionNavigation(opts) {
|
|
2985
|
-
return opts != null && "formData" in opts;
|
|
2899
|
+
return opts != null && ("formData" in opts && opts.formData != null || "body" in opts && opts.body !== undefined);
|
|
2986
2900
|
}
|
|
2987
2901
|
function normalizeTo(location, matches, basename, prependBasename, to, fromRouteId, relative) {
|
|
2988
2902
|
let contextualMatches;
|
|
@@ -3043,26 +2957,101 @@ function normalizeNavigateOptions(normalizeFormMethod, isFetcher, path, opts) {
|
|
|
3043
2957
|
})
|
|
3044
2958
|
};
|
|
3045
2959
|
}
|
|
2960
|
+
let getInvalidBodyError = () => ({
|
|
2961
|
+
path,
|
|
2962
|
+
error: getInternalRouterError(400, {
|
|
2963
|
+
type: "invalid-body"
|
|
2964
|
+
})
|
|
2965
|
+
});
|
|
3046
2966
|
// Create a Submission on non-GET navigations
|
|
3047
|
-
let
|
|
3048
|
-
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3052
|
-
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
2967
|
+
let rawFormMethod = opts.formMethod || "get";
|
|
2968
|
+
let formMethod = normalizeFormMethod ? rawFormMethod.toUpperCase() : rawFormMethod.toLowerCase();
|
|
2969
|
+
let formAction = stripHashFromPath(path);
|
|
2970
|
+
if (opts.body !== undefined) {
|
|
2971
|
+
if (opts.formEncType === "text/plain") {
|
|
2972
|
+
// text only support POST/PUT/PATCH/DELETE submissions
|
|
2973
|
+
if (!isMutationMethod(formMethod)) {
|
|
2974
|
+
return getInvalidBodyError();
|
|
2975
|
+
}
|
|
2976
|
+
let text = typeof opts.body === "string" ? opts.body : opts.body instanceof FormData || opts.body instanceof URLSearchParams ?
|
|
2977
|
+
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#plain-text-form-data
|
|
2978
|
+
Array.from(opts.body.entries()).reduce((acc, _ref3) => {
|
|
2979
|
+
let [name, value] = _ref3;
|
|
2980
|
+
return "" + acc + name + "=" + value + "\n";
|
|
2981
|
+
}, "") : String(opts.body);
|
|
3057
2982
|
return {
|
|
3058
2983
|
path,
|
|
3059
|
-
submission
|
|
2984
|
+
submission: {
|
|
2985
|
+
formMethod,
|
|
2986
|
+
formAction,
|
|
2987
|
+
formEncType: opts.formEncType,
|
|
2988
|
+
formData: undefined,
|
|
2989
|
+
json: undefined,
|
|
2990
|
+
text
|
|
2991
|
+
}
|
|
3060
2992
|
};
|
|
2993
|
+
} else if (opts.formEncType === "application/json") {
|
|
2994
|
+
// json only supports POST/PUT/PATCH/DELETE submissions
|
|
2995
|
+
if (!isMutationMethod(formMethod)) {
|
|
2996
|
+
return getInvalidBodyError();
|
|
2997
|
+
}
|
|
2998
|
+
try {
|
|
2999
|
+
let json = typeof opts.body === "string" ? JSON.parse(opts.body) : opts.body;
|
|
3000
|
+
return {
|
|
3001
|
+
path,
|
|
3002
|
+
submission: {
|
|
3003
|
+
formMethod,
|
|
3004
|
+
formAction,
|
|
3005
|
+
formEncType: opts.formEncType,
|
|
3006
|
+
formData: undefined,
|
|
3007
|
+
json,
|
|
3008
|
+
text: undefined
|
|
3009
|
+
}
|
|
3010
|
+
};
|
|
3011
|
+
} catch (e) {
|
|
3012
|
+
return getInvalidBodyError();
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
}
|
|
3016
|
+
invariant(typeof FormData === "function", "FormData is not available in this environment");
|
|
3017
|
+
let searchParams;
|
|
3018
|
+
let formData;
|
|
3019
|
+
if (opts.formData) {
|
|
3020
|
+
searchParams = convertFormDataToSearchParams(opts.formData);
|
|
3021
|
+
formData = opts.formData;
|
|
3022
|
+
} else if (opts.body instanceof FormData) {
|
|
3023
|
+
searchParams = convertFormDataToSearchParams(opts.body);
|
|
3024
|
+
formData = opts.body;
|
|
3025
|
+
} else if (opts.body instanceof URLSearchParams) {
|
|
3026
|
+
searchParams = opts.body;
|
|
3027
|
+
formData = convertSearchParamsToFormData(searchParams);
|
|
3028
|
+
} else if (opts.body == null) {
|
|
3029
|
+
searchParams = new URLSearchParams();
|
|
3030
|
+
formData = new FormData();
|
|
3031
|
+
} else {
|
|
3032
|
+
try {
|
|
3033
|
+
searchParams = new URLSearchParams(opts.body);
|
|
3034
|
+
formData = convertSearchParamsToFormData(searchParams);
|
|
3035
|
+
} catch (e) {
|
|
3036
|
+
return getInvalidBodyError();
|
|
3061
3037
|
}
|
|
3062
3038
|
}
|
|
3039
|
+
let submission = {
|
|
3040
|
+
formMethod,
|
|
3041
|
+
formAction,
|
|
3042
|
+
formEncType: opts && opts.formEncType || "application/x-www-form-urlencoded",
|
|
3043
|
+
formData,
|
|
3044
|
+
json: undefined,
|
|
3045
|
+
text: undefined
|
|
3046
|
+
};
|
|
3047
|
+
if (isMutationMethod(submission.formMethod)) {
|
|
3048
|
+
return {
|
|
3049
|
+
path,
|
|
3050
|
+
submission
|
|
3051
|
+
};
|
|
3052
|
+
}
|
|
3063
3053
|
// Flatten submission onto URLSearchParams for GET submissions
|
|
3064
3054
|
let parsedPath = parsePath(path);
|
|
3065
|
-
let searchParams = convertFormDataToSearchParams(opts.formData);
|
|
3066
3055
|
// On GET navigation submissions we can drop the ?index param from the
|
|
3067
3056
|
// resulting location since all loaders will run. But fetcher GET submissions
|
|
3068
3057
|
// only run a single loader so we need to preserve any incoming ?index params
|
|
@@ -3087,7 +3076,7 @@ function getLoaderMatchesUntilBoundary(matches, boundaryId) {
|
|
|
3087
3076
|
}
|
|
3088
3077
|
return boundaryMatches;
|
|
3089
3078
|
}
|
|
3090
|
-
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, routesToUse, basename, pendingActionData, pendingError) {
|
|
3079
|
+
function getMatchesToLoad(history, state, matches, submission, location, isRevalidationRequired, cancelledDeferredRoutes, cancelledFetcherLoads, fetchLoadMatches, fetchRedirectIds, routesToUse, basename, pendingActionData, pendingError) {
|
|
3091
3080
|
let actionResult = pendingError ? Object.values(pendingError)[0] : pendingActionData ? Object.values(pendingActionData)[0] : undefined;
|
|
3092
3081
|
let currentUrl = history.createURL(state.location);
|
|
3093
3082
|
let nextUrl = history.createURL(location);
|
|
@@ -3149,30 +3138,29 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3149
3138
|
});
|
|
3150
3139
|
return;
|
|
3151
3140
|
}
|
|
3152
|
-
let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
|
|
3153
|
-
if (cancelledFetcherLoads.includes(key)) {
|
|
3154
|
-
revalidatingFetchers.push({
|
|
3155
|
-
key,
|
|
3156
|
-
routeId: f.routeId,
|
|
3157
|
-
path: f.path,
|
|
3158
|
-
matches: fetcherMatches,
|
|
3159
|
-
match: fetcherMatch,
|
|
3160
|
-
controller: new AbortController()
|
|
3161
|
-
});
|
|
3162
|
-
return;
|
|
3163
|
-
}
|
|
3164
3141
|
// Revalidating fetchers are decoupled from the route matches since they
|
|
3165
|
-
//
|
|
3166
|
-
//
|
|
3167
|
-
//
|
|
3168
|
-
|
|
3142
|
+
// load from a static href. They only set `defaultShouldRevalidate` on
|
|
3143
|
+
// explicit revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3144
|
+
//
|
|
3145
|
+
// They automatically revalidate without even calling shouldRevalidate if:
|
|
3146
|
+
// - They were cancelled
|
|
3147
|
+
// - They're in the middle of their first load and therefore this is still
|
|
3148
|
+
// an initial load and not a revalidation
|
|
3149
|
+
//
|
|
3150
|
+
// If neither of those is true, then they _always_ check shouldRevalidate
|
|
3151
|
+
let fetcher = state.fetchers.get(key);
|
|
3152
|
+
let isPerformingInitialLoad = fetcher && fetcher.state !== "idle" && fetcher.data === undefined &&
|
|
3153
|
+
// If a fetcher.load redirected then it'll be "loading" without any data
|
|
3154
|
+
// so ensure we're not processing the redirect from this fetcher
|
|
3155
|
+
!fetchRedirectIds.has(key);
|
|
3156
|
+
let fetcherMatch = getTargetMatch(fetcherMatches, f.path);
|
|
3157
|
+
let shouldRevalidate = cancelledFetcherLoads.includes(key) || isPerformingInitialLoad || shouldRevalidateLoader(fetcherMatch, _extends({
|
|
3169
3158
|
currentUrl,
|
|
3170
3159
|
currentParams: state.matches[state.matches.length - 1].params,
|
|
3171
3160
|
nextUrl,
|
|
3172
3161
|
nextParams: matches[matches.length - 1].params
|
|
3173
3162
|
}, submission, {
|
|
3174
3163
|
actionResult,
|
|
3175
|
-
// Forced revalidation due to submission, useRevalidator, or X-Remix-Revalidate
|
|
3176
3164
|
defaultShouldRevalidate: isRevalidationRequired
|
|
3177
3165
|
}));
|
|
3178
3166
|
if (shouldRevalidate) {
|
|
@@ -3267,12 +3255,9 @@ async function loadLazyRouteModule(route, mapRouteProperties, manifest) {
|
|
|
3267
3255
|
lazy: undefined
|
|
3268
3256
|
}));
|
|
3269
3257
|
}
|
|
3270
|
-
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename,
|
|
3271
|
-
if (
|
|
3272
|
-
|
|
3273
|
-
}
|
|
3274
|
-
if (isRouteRequest === void 0) {
|
|
3275
|
-
isRouteRequest = false;
|
|
3258
|
+
async function callLoaderOrAction(type, request, match, matches, manifest, mapRouteProperties, basename, opts) {
|
|
3259
|
+
if (opts === void 0) {
|
|
3260
|
+
opts = {};
|
|
3276
3261
|
}
|
|
3277
3262
|
let resultType;
|
|
3278
3263
|
let result;
|
|
@@ -3286,7 +3271,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
3286
3271
|
return Promise.race([handler({
|
|
3287
3272
|
request,
|
|
3288
3273
|
params: match.params,
|
|
3289
|
-
context: requestContext
|
|
3274
|
+
context: opts.requestContext
|
|
3290
3275
|
}), abortPromise]);
|
|
3291
3276
|
};
|
|
3292
3277
|
try {
|
|
@@ -3349,7 +3334,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
3349
3334
|
// Support relative routing in internal redirects
|
|
3350
3335
|
if (!ABSOLUTE_URL_REGEX.test(location)) {
|
|
3351
3336
|
location = normalizeTo(new URL(request.url), matches.slice(0, matches.indexOf(match) + 1), basename, true, location);
|
|
3352
|
-
} else if (!isStaticRequest) {
|
|
3337
|
+
} else if (!opts.isStaticRequest) {
|
|
3353
3338
|
// Strip off the protocol+origin for same-origin + same-basename absolute
|
|
3354
3339
|
// redirects. If this is a static request, we can let it go back to the
|
|
3355
3340
|
// browser as-is
|
|
@@ -3364,7 +3349,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
3364
3349
|
// Instead, throw the Response and let the server handle it with an HTTP
|
|
3365
3350
|
// redirect. We also update the Location header in place in this flow so
|
|
3366
3351
|
// basename and relative routing is taken into account
|
|
3367
|
-
if (isStaticRequest) {
|
|
3352
|
+
if (opts.isStaticRequest) {
|
|
3368
3353
|
result.headers.set("Location", location);
|
|
3369
3354
|
throw result;
|
|
3370
3355
|
}
|
|
@@ -3378,7 +3363,7 @@ async function callLoaderOrAction(type, request, match, matches, manifest, mapRo
|
|
|
3378
3363
|
// For SSR single-route requests, we want to hand Responses back directly
|
|
3379
3364
|
// without unwrapping. We do this with the QueryRouteResponse wrapper
|
|
3380
3365
|
// interface so we can know whether it was returned or thrown
|
|
3381
|
-
if (isRouteRequest) {
|
|
3366
|
+
if (opts.isRouteRequest) {
|
|
3382
3367
|
// eslint-disable-next-line no-throw-literal
|
|
3383
3368
|
throw {
|
|
3384
3369
|
type: resultType || ResultType.data,
|
|
@@ -3439,26 +3424,45 @@ function createClientSideRequest(history, location, signal, submission) {
|
|
|
3439
3424
|
if (submission && isMutationMethod(submission.formMethod)) {
|
|
3440
3425
|
let {
|
|
3441
3426
|
formMethod,
|
|
3442
|
-
formEncType
|
|
3443
|
-
formData
|
|
3427
|
+
formEncType
|
|
3444
3428
|
} = submission;
|
|
3445
3429
|
// Didn't think we needed this but it turns out unlike other methods, patch
|
|
3446
3430
|
// won't be properly normalized to uppercase and results in a 405 error.
|
|
3447
3431
|
// See: https://fetch.spec.whatwg.org/#concept-method
|
|
3448
3432
|
init.method = formMethod.toUpperCase();
|
|
3449
|
-
|
|
3433
|
+
if (formEncType === "application/json") {
|
|
3434
|
+
init.headers = new Headers({
|
|
3435
|
+
"Content-Type": formEncType
|
|
3436
|
+
});
|
|
3437
|
+
init.body = JSON.stringify(submission.json);
|
|
3438
|
+
} else if (formEncType === "text/plain") {
|
|
3439
|
+
// Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
|
|
3440
|
+
init.body = submission.text;
|
|
3441
|
+
} else if (formEncType === "application/x-www-form-urlencoded" && submission.formData) {
|
|
3442
|
+
// Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
|
|
3443
|
+
init.body = convertFormDataToSearchParams(submission.formData);
|
|
3444
|
+
} else {
|
|
3445
|
+
// Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
|
|
3446
|
+
init.body = submission.formData;
|
|
3447
|
+
}
|
|
3450
3448
|
}
|
|
3451
|
-
// Content-Type is inferred (https://fetch.spec.whatwg.org/#dom-request)
|
|
3452
3449
|
return new Request(url, init);
|
|
3453
3450
|
}
|
|
3454
3451
|
function convertFormDataToSearchParams(formData) {
|
|
3455
3452
|
let searchParams = new URLSearchParams();
|
|
3456
3453
|
for (let [key, value] of formData.entries()) {
|
|
3457
3454
|
// https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#converting-an-entry-list-to-a-list-of-name-value-pairs
|
|
3458
|
-
searchParams.append(key, value
|
|
3455
|
+
searchParams.append(key, typeof value === "string" ? value : value.name);
|
|
3459
3456
|
}
|
|
3460
3457
|
return searchParams;
|
|
3461
3458
|
}
|
|
3459
|
+
function convertSearchParamsToFormData(searchParams) {
|
|
3460
|
+
let formData = new FormData();
|
|
3461
|
+
for (let [key, value] of searchParams.entries()) {
|
|
3462
|
+
formData.append(key, value);
|
|
3463
|
+
}
|
|
3464
|
+
return formData;
|
|
3465
|
+
}
|
|
3462
3466
|
function processRouteLoaderData(matches, matchesToLoad, results, pendingError, activeDeferreds) {
|
|
3463
3467
|
// Fill in loaderData/errors from our loaders
|
|
3464
3468
|
let loaderData = {};
|
|
@@ -3564,15 +3568,7 @@ function processLoaderData(state, matches, matchesToLoad, results, pendingError,
|
|
|
3564
3568
|
// in resolveDeferredResults
|
|
3565
3569
|
invariant(false, "Unhandled fetcher deferred data");
|
|
3566
3570
|
} else {
|
|
3567
|
-
let doneFetcher =
|
|
3568
|
-
state: "idle",
|
|
3569
|
-
data: result.data,
|
|
3570
|
-
formMethod: undefined,
|
|
3571
|
-
formAction: undefined,
|
|
3572
|
-
formEncType: undefined,
|
|
3573
|
-
formData: undefined,
|
|
3574
|
-
" _hasFetcherDoneAnything ": true
|
|
3575
|
-
};
|
|
3571
|
+
let doneFetcher = getDoneFetcher(result.data);
|
|
3576
3572
|
state.fetchers.set(key, doneFetcher);
|
|
3577
3573
|
}
|
|
3578
3574
|
}
|
|
@@ -3638,6 +3634,8 @@ function getInternalRouterError(status, _temp4) {
|
|
|
3638
3634
|
errorMessage = "You made a " + method + " request to \"" + pathname + "\" but " + ("did not provide a `loader` for route \"" + routeId + "\", ") + "so there is no way to handle the request.";
|
|
3639
3635
|
} else if (type === "defer-action") {
|
|
3640
3636
|
errorMessage = "defer() is not supported in actions";
|
|
3637
|
+
} else if (type === "invalid-body") {
|
|
3638
|
+
errorMessage = "Unable to encode submission body";
|
|
3641
3639
|
}
|
|
3642
3640
|
} else if (status === 403) {
|
|
3643
3641
|
statusText = "Forbidden";
|
|
@@ -3804,6 +3802,144 @@ function getTargetMatch(matches, location) {
|
|
|
3804
3802
|
let pathMatches = getPathContributingMatches(matches);
|
|
3805
3803
|
return pathMatches[pathMatches.length - 1];
|
|
3806
3804
|
}
|
|
3805
|
+
function getSubmissionFromNavigation(navigation) {
|
|
3806
|
+
let {
|
|
3807
|
+
formMethod,
|
|
3808
|
+
formAction,
|
|
3809
|
+
formEncType,
|
|
3810
|
+
text,
|
|
3811
|
+
formData,
|
|
3812
|
+
json
|
|
3813
|
+
} = navigation;
|
|
3814
|
+
if (!formMethod || !formAction || !formEncType) {
|
|
3815
|
+
return;
|
|
3816
|
+
}
|
|
3817
|
+
if (text != null) {
|
|
3818
|
+
return {
|
|
3819
|
+
formMethod,
|
|
3820
|
+
formAction,
|
|
3821
|
+
formEncType,
|
|
3822
|
+
formData: undefined,
|
|
3823
|
+
json: undefined,
|
|
3824
|
+
text
|
|
3825
|
+
};
|
|
3826
|
+
} else if (formData != null) {
|
|
3827
|
+
return {
|
|
3828
|
+
formMethod,
|
|
3829
|
+
formAction,
|
|
3830
|
+
formEncType,
|
|
3831
|
+
formData,
|
|
3832
|
+
json: undefined,
|
|
3833
|
+
text: undefined
|
|
3834
|
+
};
|
|
3835
|
+
} else if (json !== undefined) {
|
|
3836
|
+
return {
|
|
3837
|
+
formMethod,
|
|
3838
|
+
formAction,
|
|
3839
|
+
formEncType,
|
|
3840
|
+
formData: undefined,
|
|
3841
|
+
json,
|
|
3842
|
+
text: undefined
|
|
3843
|
+
};
|
|
3844
|
+
}
|
|
3845
|
+
}
|
|
3846
|
+
function getLoadingNavigation(location, submission) {
|
|
3847
|
+
if (submission) {
|
|
3848
|
+
let navigation = {
|
|
3849
|
+
state: "loading",
|
|
3850
|
+
location,
|
|
3851
|
+
formMethod: submission.formMethod,
|
|
3852
|
+
formAction: submission.formAction,
|
|
3853
|
+
formEncType: submission.formEncType,
|
|
3854
|
+
formData: submission.formData,
|
|
3855
|
+
json: submission.json,
|
|
3856
|
+
text: submission.text
|
|
3857
|
+
};
|
|
3858
|
+
return navigation;
|
|
3859
|
+
} else {
|
|
3860
|
+
let navigation = {
|
|
3861
|
+
state: "loading",
|
|
3862
|
+
location,
|
|
3863
|
+
formMethod: undefined,
|
|
3864
|
+
formAction: undefined,
|
|
3865
|
+
formEncType: undefined,
|
|
3866
|
+
formData: undefined,
|
|
3867
|
+
json: undefined,
|
|
3868
|
+
text: undefined
|
|
3869
|
+
};
|
|
3870
|
+
return navigation;
|
|
3871
|
+
}
|
|
3872
|
+
}
|
|
3873
|
+
function getSubmittingNavigation(location, submission) {
|
|
3874
|
+
let navigation = {
|
|
3875
|
+
state: "submitting",
|
|
3876
|
+
location,
|
|
3877
|
+
formMethod: submission.formMethod,
|
|
3878
|
+
formAction: submission.formAction,
|
|
3879
|
+
formEncType: submission.formEncType,
|
|
3880
|
+
formData: submission.formData,
|
|
3881
|
+
json: submission.json,
|
|
3882
|
+
text: submission.text
|
|
3883
|
+
};
|
|
3884
|
+
return navigation;
|
|
3885
|
+
}
|
|
3886
|
+
function getLoadingFetcher(submission, data) {
|
|
3887
|
+
if (submission) {
|
|
3888
|
+
let fetcher = {
|
|
3889
|
+
state: "loading",
|
|
3890
|
+
formMethod: submission.formMethod,
|
|
3891
|
+
formAction: submission.formAction,
|
|
3892
|
+
formEncType: submission.formEncType,
|
|
3893
|
+
formData: submission.formData,
|
|
3894
|
+
json: submission.json,
|
|
3895
|
+
text: submission.text,
|
|
3896
|
+
data,
|
|
3897
|
+
" _hasFetcherDoneAnything ": true
|
|
3898
|
+
};
|
|
3899
|
+
return fetcher;
|
|
3900
|
+
} else {
|
|
3901
|
+
let fetcher = {
|
|
3902
|
+
state: "loading",
|
|
3903
|
+
formMethod: undefined,
|
|
3904
|
+
formAction: undefined,
|
|
3905
|
+
formEncType: undefined,
|
|
3906
|
+
formData: undefined,
|
|
3907
|
+
json: undefined,
|
|
3908
|
+
text: undefined,
|
|
3909
|
+
data,
|
|
3910
|
+
" _hasFetcherDoneAnything ": true
|
|
3911
|
+
};
|
|
3912
|
+
return fetcher;
|
|
3913
|
+
}
|
|
3914
|
+
}
|
|
3915
|
+
function getSubmittingFetcher(submission, existingFetcher) {
|
|
3916
|
+
let fetcher = {
|
|
3917
|
+
state: "submitting",
|
|
3918
|
+
formMethod: submission.formMethod,
|
|
3919
|
+
formAction: submission.formAction,
|
|
3920
|
+
formEncType: submission.formEncType,
|
|
3921
|
+
formData: submission.formData,
|
|
3922
|
+
json: submission.json,
|
|
3923
|
+
text: submission.text,
|
|
3924
|
+
data: existingFetcher ? existingFetcher.data : undefined,
|
|
3925
|
+
" _hasFetcherDoneAnything ": true
|
|
3926
|
+
};
|
|
3927
|
+
return fetcher;
|
|
3928
|
+
}
|
|
3929
|
+
function getDoneFetcher(data) {
|
|
3930
|
+
let fetcher = {
|
|
3931
|
+
state: "idle",
|
|
3932
|
+
formMethod: undefined,
|
|
3933
|
+
formAction: undefined,
|
|
3934
|
+
formEncType: undefined,
|
|
3935
|
+
formData: undefined,
|
|
3936
|
+
json: undefined,
|
|
3937
|
+
text: undefined,
|
|
3938
|
+
data,
|
|
3939
|
+
" _hasFetcherDoneAnything ": true
|
|
3940
|
+
};
|
|
3941
|
+
return fetcher;
|
|
3942
|
+
}
|
|
3807
3943
|
//#endregion
|
|
3808
3944
|
|
|
3809
3945
|
export { AbortedDeferredError, Action, ErrorResponse, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, convertRoutesToDataRoutes as UNSAFE_convertRoutesToDataRoutes, getPathContributingMatches as UNSAFE_getPathContributingMatches, invariant as UNSAFE_invariant, warning as UNSAFE_warning, createBrowserHistory, createHashHistory, createMemoryHistory, createPath, createRouter, createStaticHandler, defer, generatePath, getStaticContextFromError, getToPathname, isDeferredData, isRouteErrorResponse, joinPaths, json, matchPath, matchRoutes, normalizePathname, parsePath, redirect, resolvePath, resolveTo, stripBasename };
|