@remix-run/router 1.3.0-pre.0 → 1.3.0-pre.2
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 +12 -0
- package/dist/history.d.ts +4 -0
- package/dist/router.cjs.js +259 -33
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +49 -2
- package/dist/router.js +259 -34
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +259 -33
- 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/history.ts +56 -12
- package/package.json +1 -1
- package/router.ts +271 -14
- package/utils.ts +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# `@remix-run/router`
|
|
2
2
|
|
|
3
|
+
## 1.3.0-pre.2
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- Added support for navigation blocking APIs ([#9709](https://github.com/remix-run/react-router/pull/9709))
|
|
8
|
+
|
|
9
|
+
## 1.3.0-pre.1
|
|
10
|
+
|
|
11
|
+
### Patch Changes
|
|
12
|
+
|
|
13
|
+
- Fix scroll reset if a submission redirects ([#9886](https://github.com/remix-run/react-router/pull/9886))
|
|
14
|
+
|
|
3
15
|
## 1.3.0-pre.0
|
|
4
16
|
|
|
5
17
|
### Minor Changes
|
package/dist/history.d.ts
CHANGED
|
@@ -68,6 +68,10 @@ export interface Update {
|
|
|
68
68
|
* The new location.
|
|
69
69
|
*/
|
|
70
70
|
location: Location;
|
|
71
|
+
/**
|
|
72
|
+
* The delta between this location and the former location in the history stack
|
|
73
|
+
*/
|
|
74
|
+
delta: number;
|
|
71
75
|
}
|
|
72
76
|
/**
|
|
73
77
|
* A function that receives notifications about location changes.
|
package/dist/router.cjs.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.3.0-pre.
|
|
2
|
+
* @remix-run/router v1.3.0-pre.2
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -137,7 +137,8 @@ function createMemoryHistory(options) {
|
|
|
137
137
|
if (v5Compat && listener) {
|
|
138
138
|
listener({
|
|
139
139
|
action,
|
|
140
|
-
location: nextLocation
|
|
140
|
+
location: nextLocation,
|
|
141
|
+
delta: 1
|
|
141
142
|
});
|
|
142
143
|
}
|
|
143
144
|
},
|
|
@@ -150,19 +151,23 @@ function createMemoryHistory(options) {
|
|
|
150
151
|
if (v5Compat && listener) {
|
|
151
152
|
listener({
|
|
152
153
|
action,
|
|
153
|
-
location: nextLocation
|
|
154
|
+
location: nextLocation,
|
|
155
|
+
delta: 0
|
|
154
156
|
});
|
|
155
157
|
}
|
|
156
158
|
},
|
|
157
159
|
|
|
158
160
|
go(delta) {
|
|
159
161
|
action = exports.Action.Pop;
|
|
160
|
-
|
|
162
|
+
let nextIndex = clampIndex(index + delta);
|
|
163
|
+
let nextLocation = entries[nextIndex];
|
|
164
|
+
index = nextIndex;
|
|
161
165
|
|
|
162
166
|
if (listener) {
|
|
163
167
|
listener({
|
|
164
168
|
action,
|
|
165
|
-
location:
|
|
169
|
+
location: nextLocation,
|
|
170
|
+
delta
|
|
166
171
|
});
|
|
167
172
|
}
|
|
168
173
|
},
|
|
@@ -321,10 +326,11 @@ function createKey() {
|
|
|
321
326
|
*/
|
|
322
327
|
|
|
323
328
|
|
|
324
|
-
function getHistoryState(location) {
|
|
329
|
+
function getHistoryState(location, index) {
|
|
325
330
|
return {
|
|
326
331
|
usr: location.state,
|
|
327
|
-
key: location.key
|
|
332
|
+
key: location.key,
|
|
333
|
+
idx: index
|
|
328
334
|
};
|
|
329
335
|
}
|
|
330
336
|
/**
|
|
@@ -408,15 +414,45 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
408
414
|
let globalHistory = window.history;
|
|
409
415
|
let action = exports.Action.Pop;
|
|
410
416
|
let listener = null;
|
|
417
|
+
let index = getIndex(); // Index should only be null when we initialize. If not, it's because the
|
|
418
|
+
// user called history.pushState or history.replaceState directly, in which
|
|
419
|
+
// case we should log a warning as it will result in bugs.
|
|
420
|
+
|
|
421
|
+
if (index == null) {
|
|
422
|
+
index = 0;
|
|
423
|
+
globalHistory.replaceState(_extends({}, globalHistory.state, {
|
|
424
|
+
idx: index
|
|
425
|
+
}), "");
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function getIndex() {
|
|
429
|
+
let state = globalHistory.state || {
|
|
430
|
+
idx: null
|
|
431
|
+
};
|
|
432
|
+
return state.idx;
|
|
433
|
+
}
|
|
411
434
|
|
|
412
435
|
function handlePop() {
|
|
413
|
-
|
|
436
|
+
let nextAction = exports.Action.Pop;
|
|
437
|
+
let nextIndex = getIndex();
|
|
414
438
|
|
|
415
|
-
if (
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
439
|
+
if (nextIndex != null) {
|
|
440
|
+
let delta = nextIndex - index;
|
|
441
|
+
action = nextAction;
|
|
442
|
+
index = nextIndex;
|
|
443
|
+
|
|
444
|
+
if (listener) {
|
|
445
|
+
listener({
|
|
446
|
+
action,
|
|
447
|
+
location: history.location,
|
|
448
|
+
delta
|
|
449
|
+
});
|
|
450
|
+
}
|
|
451
|
+
} else {
|
|
452
|
+
warning$1(false, // TODO: Write up a doc that explains our blocking strategy in detail
|
|
453
|
+
// and link to it here so people can understand better what is going on
|
|
454
|
+
// and how to avoid it.
|
|
455
|
+
"You are trying to block a POP navigation to a location that was not " + "created by @remix-run/router. The block will fail silently in " + "production, but in general you should do all navigation with the " + "router (instead of using window.history.pushState directly) " + "to avoid this situation.");
|
|
420
456
|
}
|
|
421
457
|
}
|
|
422
458
|
|
|
@@ -424,7 +460,8 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
424
460
|
action = exports.Action.Push;
|
|
425
461
|
let location = createLocation(history.location, to, state);
|
|
426
462
|
if (validateLocation) validateLocation(location, to);
|
|
427
|
-
|
|
463
|
+
index = getIndex() + 1;
|
|
464
|
+
let historyState = getHistoryState(location, index);
|
|
428
465
|
let url = history.createHref(location); // try...catch because iOS limits us to 100 pushState calls :/
|
|
429
466
|
|
|
430
467
|
try {
|
|
@@ -438,7 +475,8 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
438
475
|
if (v5Compat && listener) {
|
|
439
476
|
listener({
|
|
440
477
|
action,
|
|
441
|
-
location: history.location
|
|
478
|
+
location: history.location,
|
|
479
|
+
delta: 1
|
|
442
480
|
});
|
|
443
481
|
}
|
|
444
482
|
}
|
|
@@ -447,14 +485,16 @@ function getUrlBasedHistory(getLocation, createHref, validateLocation, options)
|
|
|
447
485
|
action = exports.Action.Replace;
|
|
448
486
|
let location = createLocation(history.location, to, state);
|
|
449
487
|
if (validateLocation) validateLocation(location, to);
|
|
450
|
-
|
|
488
|
+
index = getIndex();
|
|
489
|
+
let historyState = getHistoryState(location, index);
|
|
451
490
|
let url = history.createHref(location);
|
|
452
491
|
globalHistory.replaceState(historyState, "", url);
|
|
453
492
|
|
|
454
493
|
if (v5Compat && listener) {
|
|
455
494
|
listener({
|
|
456
495
|
action,
|
|
457
|
-
location: history.location
|
|
496
|
+
location: history.location,
|
|
497
|
+
delta: 0
|
|
458
498
|
});
|
|
459
499
|
}
|
|
460
500
|
}
|
|
@@ -990,7 +1030,7 @@ function warning(cond, message) {
|
|
|
990
1030
|
if (typeof console !== "undefined") console.warn(message);
|
|
991
1031
|
|
|
992
1032
|
try {
|
|
993
|
-
// Welcome to debugging
|
|
1033
|
+
// Welcome to debugging @remix-run/router!
|
|
994
1034
|
//
|
|
995
1035
|
// This error is thrown as a convenience so you can more easily
|
|
996
1036
|
// find the source for a warning that appears in the console by
|
|
@@ -1433,6 +1473,12 @@ const IDLE_FETCHER = {
|
|
|
1433
1473
|
formEncType: undefined,
|
|
1434
1474
|
formData: undefined
|
|
1435
1475
|
};
|
|
1476
|
+
const IDLE_BLOCKER = {
|
|
1477
|
+
state: "unblocked",
|
|
1478
|
+
proceed: undefined,
|
|
1479
|
+
reset: undefined,
|
|
1480
|
+
location: undefined
|
|
1481
|
+
};
|
|
1436
1482
|
const isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined" && typeof window.document.createElement !== "undefined";
|
|
1437
1483
|
const isServer = !isBrowser; //#endregion
|
|
1438
1484
|
////////////////////////////////////////////////////////////////////////////////
|
|
@@ -1497,7 +1543,8 @@ function createRouter(init) {
|
|
|
1497
1543
|
loaderData: init.hydrationData && init.hydrationData.loaderData || {},
|
|
1498
1544
|
actionData: init.hydrationData && init.hydrationData.actionData || null,
|
|
1499
1545
|
errors: init.hydrationData && init.hydrationData.errors || initialErrors,
|
|
1500
|
-
fetchers: new Map()
|
|
1546
|
+
fetchers: new Map(),
|
|
1547
|
+
blockers: new Map()
|
|
1501
1548
|
}; // -- Stateful internal variables to manage navigations --
|
|
1502
1549
|
// Current navigation in progress (to be committed in completeNavigation)
|
|
1503
1550
|
|
|
@@ -1539,7 +1586,16 @@ function createRouter(init) {
|
|
|
1539
1586
|
// promise resolves we update loaderData. If a new navigation starts we
|
|
1540
1587
|
// cancel active deferreds for eliminated routes.
|
|
1541
1588
|
|
|
1542
|
-
let activeDeferreds = new Map(); //
|
|
1589
|
+
let activeDeferreds = new Map(); // We ony support a single active blocker at the moment since we don't have
|
|
1590
|
+
// any compelling use cases for multi-blocker yet
|
|
1591
|
+
|
|
1592
|
+
let activeBlocker = null; // Store blocker functions in a separate Map outside of router state since
|
|
1593
|
+
// we don't need to update UI state if they change
|
|
1594
|
+
|
|
1595
|
+
let blockerFunctions = new Map(); // Flag to ignore the next history update, so we can revert the URL change on
|
|
1596
|
+
// a POP navigation that was blocked by the user without touching router state
|
|
1597
|
+
|
|
1598
|
+
let ignoreNextHistoryUpdate = false; // Initialize the router, all side effects should be kicked off from here.
|
|
1543
1599
|
// Implemented as a Fluent API for ease of:
|
|
1544
1600
|
// let router = createRouter(init).initialize();
|
|
1545
1601
|
|
|
@@ -1549,8 +1605,54 @@ function createRouter(init) {
|
|
|
1549
1605
|
unlistenHistory = init.history.listen(_ref => {
|
|
1550
1606
|
let {
|
|
1551
1607
|
action: historyAction,
|
|
1552
|
-
location
|
|
1608
|
+
location,
|
|
1609
|
+
delta
|
|
1553
1610
|
} = _ref;
|
|
1611
|
+
|
|
1612
|
+
// Ignore this event if it was just us resetting the URL from a
|
|
1613
|
+
// blocked POP navigation
|
|
1614
|
+
if (ignoreNextHistoryUpdate) {
|
|
1615
|
+
ignoreNextHistoryUpdate = false;
|
|
1616
|
+
return;
|
|
1617
|
+
}
|
|
1618
|
+
|
|
1619
|
+
let blockerKey = shouldBlockNavigation({
|
|
1620
|
+
currentLocation: state.location,
|
|
1621
|
+
nextLocation: location,
|
|
1622
|
+
historyAction
|
|
1623
|
+
});
|
|
1624
|
+
|
|
1625
|
+
if (blockerKey) {
|
|
1626
|
+
// Restore the URL to match the current UI, but don't update router state
|
|
1627
|
+
ignoreNextHistoryUpdate = true;
|
|
1628
|
+
init.history.go(delta * -1); // Put the blocker into a blocked state
|
|
1629
|
+
|
|
1630
|
+
updateBlocker(blockerKey, {
|
|
1631
|
+
state: "blocked",
|
|
1632
|
+
location,
|
|
1633
|
+
|
|
1634
|
+
proceed() {
|
|
1635
|
+
updateBlocker(blockerKey, {
|
|
1636
|
+
state: "proceeding",
|
|
1637
|
+
proceed: undefined,
|
|
1638
|
+
reset: undefined,
|
|
1639
|
+
location
|
|
1640
|
+
}); // Re-do the same POP navigation we just blocked
|
|
1641
|
+
|
|
1642
|
+
init.history.go(delta);
|
|
1643
|
+
},
|
|
1644
|
+
|
|
1645
|
+
reset() {
|
|
1646
|
+
deleteBlocker(blockerKey);
|
|
1647
|
+
updateState({
|
|
1648
|
+
blockers: new Map(router.state.blockers)
|
|
1649
|
+
});
|
|
1650
|
+
}
|
|
1651
|
+
|
|
1652
|
+
});
|
|
1653
|
+
return;
|
|
1654
|
+
}
|
|
1655
|
+
|
|
1554
1656
|
return startNavigation(historyAction, location);
|
|
1555
1657
|
}); // Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1556
1658
|
|
|
@@ -1570,6 +1672,7 @@ function createRouter(init) {
|
|
|
1570
1672
|
subscribers.clear();
|
|
1571
1673
|
pendingNavigationController && pendingNavigationController.abort();
|
|
1572
1674
|
state.fetchers.forEach((_, key) => deleteFetcher(key));
|
|
1675
|
+
state.blockers.forEach((_, key) => deleteBlocker(key));
|
|
1573
1676
|
} // Subscribe to state updates for the router
|
|
1574
1677
|
|
|
1575
1678
|
|
|
@@ -1590,7 +1693,7 @@ function createRouter(init) {
|
|
|
1590
1693
|
|
|
1591
1694
|
|
|
1592
1695
|
function completeNavigation(location, newState) {
|
|
1593
|
-
var _location$state;
|
|
1696
|
+
var _location$state, _location$state2;
|
|
1594
1697
|
|
|
1595
1698
|
// Deduce if we're in a loading/actionReload state:
|
|
1596
1699
|
// - We have committed actionData in the store
|
|
@@ -1616,7 +1719,16 @@ function createRouter(init) {
|
|
|
1616
1719
|
} // Always preserve any existing loaderData from re-used routes
|
|
1617
1720
|
|
|
1618
1721
|
|
|
1619
|
-
let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData;
|
|
1722
|
+
let loaderData = newState.loaderData ? mergeLoaderData(state.loaderData, newState.loaderData, newState.matches || [], newState.errors) : state.loaderData; // On a successful navigation we can assume we got through all blockers
|
|
1723
|
+
// so we can start fresh
|
|
1724
|
+
|
|
1725
|
+
for (let [key] of blockerFunctions) {
|
|
1726
|
+
deleteBlocker(key);
|
|
1727
|
+
} // Always respect the user flag. Otherwise don't reset on mutation
|
|
1728
|
+
// submission navigations unless they redirect
|
|
1729
|
+
|
|
1730
|
+
|
|
1731
|
+
let preventScrollReset = pendingPreventScrollReset === true || state.navigation.formMethod != null && isMutationMethod(state.navigation.formMethod) && ((_location$state2 = location.state) == null ? void 0 : _location$state2._isRedirect) !== true;
|
|
1620
1732
|
updateState(_extends({}, newState, {
|
|
1621
1733
|
// matches, errors, fetchers go through as-is
|
|
1622
1734
|
actionData,
|
|
@@ -1626,9 +1738,9 @@ function createRouter(init) {
|
|
|
1626
1738
|
initialized: true,
|
|
1627
1739
|
navigation: IDLE_NAVIGATION,
|
|
1628
1740
|
revalidation: "idle",
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1741
|
+
restoreScrollPosition: getSavedScrollPosition(location, newState.matches || state.matches),
|
|
1742
|
+
preventScrollReset,
|
|
1743
|
+
blockers: new Map(state.blockers)
|
|
1632
1744
|
}));
|
|
1633
1745
|
|
|
1634
1746
|
if (isUninterruptedRevalidation) ; else if (pendingAction === exports.Action.Pop) ; else if (pendingAction === exports.Action.Push) {
|
|
@@ -1659,13 +1771,14 @@ function createRouter(init) {
|
|
|
1659
1771
|
submission,
|
|
1660
1772
|
error
|
|
1661
1773
|
} = normalizeNavigateOptions(to, opts);
|
|
1662
|
-
let
|
|
1774
|
+
let currentLocation = state.location;
|
|
1775
|
+
let nextLocation = createLocation(state.location, path, opts && opts.state); // When using navigate as a PUSH/REPLACE we aren't reading an already-encoded
|
|
1663
1776
|
// URL from window.location, so we need to encode it here so the behavior
|
|
1664
1777
|
// remains the same as POP and non-data-router usages. new URL() does all
|
|
1665
1778
|
// the same encoding we'd get from a history.pushState/window.location read
|
|
1666
1779
|
// without having to touch history
|
|
1667
1780
|
|
|
1668
|
-
|
|
1781
|
+
nextLocation = _extends({}, nextLocation, init.history.encodeLocation(nextLocation));
|
|
1669
1782
|
let userReplace = opts && opts.replace != null ? opts.replace : undefined;
|
|
1670
1783
|
let historyAction = exports.Action.Push;
|
|
1671
1784
|
|
|
@@ -1680,7 +1793,41 @@ function createRouter(init) {
|
|
|
1680
1793
|
}
|
|
1681
1794
|
|
|
1682
1795
|
let preventScrollReset = opts && "preventScrollReset" in opts ? opts.preventScrollReset === true : undefined;
|
|
1683
|
-
|
|
1796
|
+
let blockerKey = shouldBlockNavigation({
|
|
1797
|
+
currentLocation,
|
|
1798
|
+
nextLocation,
|
|
1799
|
+
historyAction
|
|
1800
|
+
});
|
|
1801
|
+
|
|
1802
|
+
if (blockerKey) {
|
|
1803
|
+
// Put the blocker into a blocked state
|
|
1804
|
+
updateBlocker(blockerKey, {
|
|
1805
|
+
state: "blocked",
|
|
1806
|
+
location: nextLocation,
|
|
1807
|
+
|
|
1808
|
+
proceed() {
|
|
1809
|
+
updateBlocker(blockerKey, {
|
|
1810
|
+
state: "proceeding",
|
|
1811
|
+
proceed: undefined,
|
|
1812
|
+
reset: undefined,
|
|
1813
|
+
location: nextLocation
|
|
1814
|
+
}); // Send the same navigation through
|
|
1815
|
+
|
|
1816
|
+
navigate(to, opts);
|
|
1817
|
+
},
|
|
1818
|
+
|
|
1819
|
+
reset() {
|
|
1820
|
+
deleteBlocker(blockerKey);
|
|
1821
|
+
updateState({
|
|
1822
|
+
blockers: new Map(state.blockers)
|
|
1823
|
+
});
|
|
1824
|
+
}
|
|
1825
|
+
|
|
1826
|
+
});
|
|
1827
|
+
return;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
return await startNavigation(historyAction, nextLocation, {
|
|
1684
1831
|
submission,
|
|
1685
1832
|
// Send through the formData serialization error if we have one so we can
|
|
1686
1833
|
// render at the right error boundary after we match routes
|
|
@@ -2452,7 +2599,9 @@ function createRouter(init) {
|
|
|
2452
2599
|
await startNavigation(redirectHistoryAction, redirectLocation, {
|
|
2453
2600
|
submission: _extends({}, submission, {
|
|
2454
2601
|
formAction: redirect.location
|
|
2455
|
-
})
|
|
2602
|
+
}),
|
|
2603
|
+
// Preserve this flag across redirects
|
|
2604
|
+
preventScrollReset: pendingPreventScrollReset
|
|
2456
2605
|
});
|
|
2457
2606
|
} else {
|
|
2458
2607
|
// Otherwise, we kick off a new loading navigation, preserving the
|
|
@@ -2465,7 +2614,9 @@ function createRouter(init) {
|
|
|
2465
2614
|
formAction: submission ? submission.formAction : undefined,
|
|
2466
2615
|
formEncType: submission ? submission.formEncType : undefined,
|
|
2467
2616
|
formData: submission ? submission.formData : undefined
|
|
2468
|
-
}
|
|
2617
|
+
},
|
|
2618
|
+
// Preserve this flag across redirects
|
|
2619
|
+
preventScrollReset: pendingPreventScrollReset
|
|
2469
2620
|
});
|
|
2470
2621
|
}
|
|
2471
2622
|
}
|
|
@@ -2584,6 +2735,78 @@ function createRouter(init) {
|
|
|
2584
2735
|
return yeetedKeys.length > 0;
|
|
2585
2736
|
}
|
|
2586
2737
|
|
|
2738
|
+
function getBlocker(key, fn) {
|
|
2739
|
+
let blocker = state.blockers.get(key) || IDLE_BLOCKER;
|
|
2740
|
+
|
|
2741
|
+
if (blockerFunctions.get(key) !== fn) {
|
|
2742
|
+
blockerFunctions.set(key, fn);
|
|
2743
|
+
|
|
2744
|
+
if (activeBlocker == null) {
|
|
2745
|
+
// This is now the active blocker
|
|
2746
|
+
activeBlocker = key;
|
|
2747
|
+
} else if (key !== activeBlocker) {
|
|
2748
|
+
warning(false, "A router only supports one blocker at a time");
|
|
2749
|
+
}
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
return blocker;
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
function deleteBlocker(key) {
|
|
2756
|
+
state.blockers.delete(key);
|
|
2757
|
+
blockerFunctions.delete(key);
|
|
2758
|
+
|
|
2759
|
+
if (activeBlocker === key) {
|
|
2760
|
+
activeBlocker = null;
|
|
2761
|
+
}
|
|
2762
|
+
} // Utility function to update blockers, ensuring valid state transitions
|
|
2763
|
+
|
|
2764
|
+
|
|
2765
|
+
function updateBlocker(key, newBlocker) {
|
|
2766
|
+
let blocker = state.blockers.get(key) || IDLE_BLOCKER; // Poor mans state machine :)
|
|
2767
|
+
// https://mermaid.live/edit#pako:eNqVkc9OwzAMxl8l8nnjAYrEtDIOHEBIgwvKJTReGy3_lDpIqO27k6awMG0XcrLlnz87nwdonESogKXXBuE79rq75XZO3-yHds0RJVuv70YrPlUrCEe2HfrORS3rubqZfuhtpg5C9wk5tZ4VKcRUq88q9Z8RS0-48cE1iHJkL0ugbHuFLus9L6spZy8nX9MP2CNdomVaposqu3fGayT8T8-jJQwhepo_UtpgBQaDEUom04dZhAN1aJBDlUKJBxE1ceB2Smj0Mln-IBW5AFU2dwUiktt_2Qaq2dBfaKdEup85UV7Yd-dKjlnkabl2Pvr0DTkTreM
|
|
2768
|
+
|
|
2769
|
+
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);
|
|
2770
|
+
state.blockers.set(key, newBlocker);
|
|
2771
|
+
updateState({
|
|
2772
|
+
blockers: new Map(state.blockers)
|
|
2773
|
+
});
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2776
|
+
function shouldBlockNavigation(_ref10) {
|
|
2777
|
+
let {
|
|
2778
|
+
currentLocation,
|
|
2779
|
+
nextLocation,
|
|
2780
|
+
historyAction
|
|
2781
|
+
} = _ref10;
|
|
2782
|
+
|
|
2783
|
+
if (activeBlocker == null) {
|
|
2784
|
+
return;
|
|
2785
|
+
} // We only allow a single blocker at the moment. This will need to be
|
|
2786
|
+
// updated if we enhance to support multiple blockers in the future
|
|
2787
|
+
|
|
2788
|
+
|
|
2789
|
+
let blockerFunction = blockerFunctions.get(activeBlocker);
|
|
2790
|
+
invariant(blockerFunction, "Could not find a function for the active blocker");
|
|
2791
|
+
let blocker = state.blockers.get(activeBlocker);
|
|
2792
|
+
|
|
2793
|
+
if (blocker && blocker.state === "proceeding") {
|
|
2794
|
+
// If the blocker is currently proceeding, we don't need to re-check
|
|
2795
|
+
// it and can let this navigation continue
|
|
2796
|
+
return;
|
|
2797
|
+
} // At this point, we know we're unblocked/blocked so we need to check the
|
|
2798
|
+
// user-provided blocker function
|
|
2799
|
+
|
|
2800
|
+
|
|
2801
|
+
if (blockerFunction({
|
|
2802
|
+
currentLocation,
|
|
2803
|
+
nextLocation,
|
|
2804
|
+
historyAction
|
|
2805
|
+
})) {
|
|
2806
|
+
return activeBlocker;
|
|
2807
|
+
}
|
|
2808
|
+
}
|
|
2809
|
+
|
|
2587
2810
|
function cancelActiveDeferreds(predicate) {
|
|
2588
2811
|
let cancelledRouteIds = [];
|
|
2589
2812
|
activeDeferreds.forEach((dfd, routeId) => {
|
|
@@ -2676,6 +2899,8 @@ function createRouter(init) {
|
|
|
2676
2899
|
getFetcher,
|
|
2677
2900
|
deleteFetcher,
|
|
2678
2901
|
dispose,
|
|
2902
|
+
getBlocker,
|
|
2903
|
+
deleteBlocker,
|
|
2679
2904
|
_internalFetchControllers: fetchControllers,
|
|
2680
2905
|
_internalActiveDeferreds: activeDeferreds
|
|
2681
2906
|
};
|
|
@@ -3196,8 +3421,8 @@ function getMatchesToLoad(history, state, matches, submission, location, isReval
|
|
|
3196
3421
|
cancelledDeferredRoutes.some(id => id === match.route.id) || shouldRevalidateLoader(history, state.location, state.matches[index], submission, location, match, isRevalidationRequired, actionResult))); // Pick fetcher.loads that need to be revalidated
|
|
3197
3422
|
|
|
3198
3423
|
let revalidatingFetchers = [];
|
|
3199
|
-
fetchLoadMatches && fetchLoadMatches.forEach((
|
|
3200
|
-
let [href, match, fetchMatches] =
|
|
3424
|
+
fetchLoadMatches && fetchLoadMatches.forEach((_ref11, key) => {
|
|
3425
|
+
let [href, match, fetchMatches] = _ref11;
|
|
3201
3426
|
|
|
3202
3427
|
// This fetcher was cancelled from a prior action submission - force reload
|
|
3203
3428
|
if (cancelledFetcherLoads.includes(key)) {
|
|
@@ -3799,6 +4024,7 @@ function getTargetMatch(matches, location) {
|
|
|
3799
4024
|
|
|
3800
4025
|
exports.AbortedDeferredError = AbortedDeferredError;
|
|
3801
4026
|
exports.ErrorResponse = ErrorResponse;
|
|
4027
|
+
exports.IDLE_BLOCKER = IDLE_BLOCKER;
|
|
3802
4028
|
exports.IDLE_FETCHER = IDLE_FETCHER;
|
|
3803
4029
|
exports.IDLE_NAVIGATION = IDLE_NAVIGATION;
|
|
3804
4030
|
exports.UNSAFE_DEFERRED_SYMBOL = UNSAFE_DEFERRED_SYMBOL;
|