@remix-run/router 1.9.0 → 1.10.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 +11 -0
- package/dist/router.cjs.js +103 -12
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +15 -1
- package/dist/router.js +96 -6
- package/dist/router.js.map +1 -1
- package/dist/router.umd.js +103 -12
- 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 +12 -4
- package/package.json +1 -1
- package/router.ts +168 -23
- package/utils.ts +13 -8
package/dist/router.d.ts
CHANGED
|
@@ -26,6 +26,13 @@ export interface Router {
|
|
|
26
26
|
* Return the routes for this router instance
|
|
27
27
|
*/
|
|
28
28
|
get routes(): AgnosticDataRouteObject[];
|
|
29
|
+
/**
|
|
30
|
+
* @internal
|
|
31
|
+
* PRIVATE - DO NOT USE
|
|
32
|
+
*
|
|
33
|
+
* Return the window associated with the router
|
|
34
|
+
*/
|
|
35
|
+
get window(): RouterInit["window"];
|
|
29
36
|
/**
|
|
30
37
|
* @internal
|
|
31
38
|
* PRIVATE - DO NOT USE
|
|
@@ -287,11 +294,17 @@ export interface StaticHandler {
|
|
|
287
294
|
requestContext?: unknown;
|
|
288
295
|
}): Promise<any>;
|
|
289
296
|
}
|
|
297
|
+
type ViewTransitionOpts = {
|
|
298
|
+
currentLocation: Location;
|
|
299
|
+
nextLocation: Location;
|
|
300
|
+
};
|
|
290
301
|
/**
|
|
291
302
|
* Subscriber function signature for changes to router state
|
|
292
303
|
*/
|
|
293
304
|
export interface RouterSubscriber {
|
|
294
|
-
(state: RouterState
|
|
305
|
+
(state: RouterState, opts: {
|
|
306
|
+
unstable_viewTransitionOpts?: ViewTransitionOpts;
|
|
307
|
+
}): void;
|
|
295
308
|
}
|
|
296
309
|
/**
|
|
297
310
|
* Function signature for determining the key to be used in scroll restoration
|
|
@@ -315,6 +328,7 @@ type BaseNavigateOptions = BaseNavigateOrFetchOptions & {
|
|
|
315
328
|
replace?: boolean;
|
|
316
329
|
state?: any;
|
|
317
330
|
fromRouteId?: string;
|
|
331
|
+
unstable_viewTransition?: boolean;
|
|
318
332
|
};
|
|
319
333
|
type BaseSubmissionOptions = {
|
|
320
334
|
formMethod?: HTMLFormMethod;
|
package/dist/router.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @remix-run/router v1.
|
|
2
|
+
* @remix-run/router v1.10.0
|
|
3
3
|
*
|
|
4
4
|
* Copyright (c) Remix Software Inc.
|
|
5
5
|
*
|
|
@@ -1203,6 +1203,10 @@ const redirectDocument = (url, init) => {
|
|
|
1203
1203
|
/**
|
|
1204
1204
|
* @private
|
|
1205
1205
|
* Utility class we use to hold auto-unwrapped 4xx/5xx Response bodies
|
|
1206
|
+
*
|
|
1207
|
+
* We don't export the class for public use since it's an implementation
|
|
1208
|
+
* detail, but we export the interface above so folks can build their own
|
|
1209
|
+
* abstractions around instances via isRouteErrorResponse()
|
|
1206
1210
|
*/
|
|
1207
1211
|
class ErrorResponseImpl {
|
|
1208
1212
|
constructor(status, statusText, data, internal) {
|
|
@@ -1264,6 +1268,7 @@ const ABSOLUTE_URL_REGEX = /^(?:[a-z][a-z0-9+.-]*:|\/\/)/i;
|
|
|
1264
1268
|
const defaultMapRouteProperties = route => ({
|
|
1265
1269
|
hasErrorBoundary: Boolean(route.hasErrorBoundary)
|
|
1266
1270
|
});
|
|
1271
|
+
const TRANSITIONS_STORAGE_KEY = "remix-router-transitions";
|
|
1267
1272
|
//#endregion
|
|
1268
1273
|
////////////////////////////////////////////////////////////////////////////////
|
|
1269
1274
|
//#region createRouter
|
|
@@ -1364,6 +1369,12 @@ function createRouter(init) {
|
|
|
1364
1369
|
let pendingPreventScrollReset = false;
|
|
1365
1370
|
// AbortController for the active navigation
|
|
1366
1371
|
let pendingNavigationController;
|
|
1372
|
+
// Should the current navigation enable document.startViewTransition?
|
|
1373
|
+
let pendingViewTransitionEnabled = false;
|
|
1374
|
+
// Store applied view transitions so we can apply them on POP
|
|
1375
|
+
let appliedViewTransitions = new Map();
|
|
1376
|
+
// Cleanup function for persisting applied transitions to sessionStorage
|
|
1377
|
+
let removePageHideEventListener = null;
|
|
1367
1378
|
// We use this to avoid touching history in completeNavigation if a
|
|
1368
1379
|
// revalidation is entirely uninterrupted
|
|
1369
1380
|
let isUninterruptedRevalidation = false;
|
|
@@ -1457,6 +1468,14 @@ function createRouter(init) {
|
|
|
1457
1468
|
}
|
|
1458
1469
|
return startNavigation(historyAction, location);
|
|
1459
1470
|
});
|
|
1471
|
+
if (isBrowser) {
|
|
1472
|
+
// FIXME: This feels gross. How can we cleanup the lines between
|
|
1473
|
+
// scrollRestoration/appliedTransitions persistance?
|
|
1474
|
+
restoreAppliedTransitions(routerWindow, appliedViewTransitions);
|
|
1475
|
+
let _saveAppliedTransitions = () => persistAppliedTransitions(routerWindow, appliedViewTransitions);
|
|
1476
|
+
routerWindow.addEventListener("pagehide", _saveAppliedTransitions);
|
|
1477
|
+
removePageHideEventListener = () => routerWindow.removeEventListener("pagehide", _saveAppliedTransitions);
|
|
1478
|
+
}
|
|
1460
1479
|
// Kick off initial data load if needed. Use Pop to avoid modifying history
|
|
1461
1480
|
// Note we don't do any handling of lazy here. For SPA's it'll get handled
|
|
1462
1481
|
// in the normal navigation flow. For SSR it's expected that lazy modules are
|
|
@@ -1472,6 +1491,9 @@ function createRouter(init) {
|
|
|
1472
1491
|
if (unlistenHistory) {
|
|
1473
1492
|
unlistenHistory();
|
|
1474
1493
|
}
|
|
1494
|
+
if (removePageHideEventListener) {
|
|
1495
|
+
removePageHideEventListener();
|
|
1496
|
+
}
|
|
1475
1497
|
subscribers.clear();
|
|
1476
1498
|
pendingNavigationController && pendingNavigationController.abort();
|
|
1477
1499
|
state.fetchers.forEach((_, key) => deleteFetcher(key));
|
|
@@ -1483,9 +1505,11 @@ function createRouter(init) {
|
|
|
1483
1505
|
return () => subscribers.delete(fn);
|
|
1484
1506
|
}
|
|
1485
1507
|
// Update our state and notify the calling context of the change
|
|
1486
|
-
function updateState(newState) {
|
|
1508
|
+
function updateState(newState, viewTransitionOpts) {
|
|
1487
1509
|
state = _extends({}, state, newState);
|
|
1488
|
-
subscribers.forEach(subscriber => subscriber(state
|
|
1510
|
+
subscribers.forEach(subscriber => subscriber(state, {
|
|
1511
|
+
unstable_viewTransitionOpts: viewTransitionOpts
|
|
1512
|
+
}));
|
|
1489
1513
|
}
|
|
1490
1514
|
// Complete a navigation returning the state.navigation back to the IDLE_NAVIGATION
|
|
1491
1515
|
// and setting state.[historyAction/location/matches] to the new route.
|
|
@@ -1536,6 +1560,38 @@ function createRouter(init) {
|
|
|
1536
1560
|
} else if (pendingAction === Action.Replace) {
|
|
1537
1561
|
init.history.replace(location, location.state);
|
|
1538
1562
|
}
|
|
1563
|
+
let viewTransitionOpts;
|
|
1564
|
+
// On POP, enable transitions if they were enabled on the original navigation
|
|
1565
|
+
if (pendingAction === Action.Pop) {
|
|
1566
|
+
// Forward takes precedence so they behave like the original navigation
|
|
1567
|
+
let priorPaths = appliedViewTransitions.get(state.location.pathname);
|
|
1568
|
+
if (priorPaths && priorPaths.has(location.pathname)) {
|
|
1569
|
+
viewTransitionOpts = {
|
|
1570
|
+
currentLocation: state.location,
|
|
1571
|
+
nextLocation: location
|
|
1572
|
+
};
|
|
1573
|
+
} else if (appliedViewTransitions.has(location.pathname)) {
|
|
1574
|
+
// If we don't have a previous forward nav, assume we're popping back to
|
|
1575
|
+
// the new location and enable if that location previously enabled
|
|
1576
|
+
viewTransitionOpts = {
|
|
1577
|
+
currentLocation: location,
|
|
1578
|
+
nextLocation: state.location
|
|
1579
|
+
};
|
|
1580
|
+
}
|
|
1581
|
+
} else if (pendingViewTransitionEnabled) {
|
|
1582
|
+
// Store the applied transition on PUSH/REPLACE
|
|
1583
|
+
let toPaths = appliedViewTransitions.get(state.location.pathname);
|
|
1584
|
+
if (toPaths) {
|
|
1585
|
+
toPaths.add(location.pathname);
|
|
1586
|
+
} else {
|
|
1587
|
+
toPaths = new Set([location.pathname]);
|
|
1588
|
+
appliedViewTransitions.set(state.location.pathname, toPaths);
|
|
1589
|
+
}
|
|
1590
|
+
viewTransitionOpts = {
|
|
1591
|
+
currentLocation: state.location,
|
|
1592
|
+
nextLocation: location
|
|
1593
|
+
};
|
|
1594
|
+
}
|
|
1539
1595
|
updateState(_extends({}, newState, {
|
|
1540
1596
|
actionData,
|
|
1541
1597
|
loaderData,
|
|
@@ -1547,10 +1603,11 @@ function createRouter(init) {
|
|
|
1547
1603
|
restoreScrollPosition: getSavedScrollPosition(location, newState.matches || state.matches),
|
|
1548
1604
|
preventScrollReset,
|
|
1549
1605
|
blockers
|
|
1550
|
-
}));
|
|
1606
|
+
}), viewTransitionOpts);
|
|
1551
1607
|
// Reset stateful navigation vars
|
|
1552
1608
|
pendingAction = Action.Pop;
|
|
1553
1609
|
pendingPreventScrollReset = false;
|
|
1610
|
+
pendingViewTransitionEnabled = false;
|
|
1554
1611
|
isUninterruptedRevalidation = false;
|
|
1555
1612
|
isRevalidationRequired = false;
|
|
1556
1613
|
cancelledDeferredRoutes = [];
|
|
@@ -1625,7 +1682,8 @@ function createRouter(init) {
|
|
|
1625
1682
|
// render at the right error boundary after we match routes
|
|
1626
1683
|
pendingError: error,
|
|
1627
1684
|
preventScrollReset,
|
|
1628
|
-
replace: opts && opts.replace
|
|
1685
|
+
replace: opts && opts.replace,
|
|
1686
|
+
enableViewTransition: opts && opts.unstable_viewTransition
|
|
1629
1687
|
});
|
|
1630
1688
|
}
|
|
1631
1689
|
// Revalidate all current loaders. If a navigation is in progress or if this
|
|
@@ -1672,6 +1730,7 @@ function createRouter(init) {
|
|
|
1672
1730
|
// and track whether we should reset scroll on completion
|
|
1673
1731
|
saveScrollPosition(state.location, state.matches);
|
|
1674
1732
|
pendingPreventScrollReset = (opts && opts.preventScrollReset) === true;
|
|
1733
|
+
pendingViewTransitionEnabled = (opts && opts.enableViewTransition) === true;
|
|
1675
1734
|
let routesToUse = inFlightDataRoutes || dataRoutes;
|
|
1676
1735
|
let loadingNavigation = opts && opts.overrideNavigation;
|
|
1677
1736
|
let matches = matchRoutes(routesToUse, location, basename);
|
|
@@ -2573,6 +2632,9 @@ function createRouter(init) {
|
|
|
2573
2632
|
get routes() {
|
|
2574
2633
|
return dataRoutes;
|
|
2575
2634
|
},
|
|
2635
|
+
get window() {
|
|
2636
|
+
return routerWindow;
|
|
2637
|
+
},
|
|
2576
2638
|
initialize,
|
|
2577
2639
|
subscribe,
|
|
2578
2640
|
enableScrollRestoration,
|
|
@@ -3717,7 +3779,7 @@ function findNearestBoundary(matches, routeId) {
|
|
|
3717
3779
|
}
|
|
3718
3780
|
function getShortCircuitMatches(routes) {
|
|
3719
3781
|
// Prefer a root layout route if present, otherwise shim in a route object
|
|
3720
|
-
let route = routes.find(r => r.index || !r.path || r.path === "/") || {
|
|
3782
|
+
let route = routes.length === 1 ? routes[0] : routes.find(r => r.index || !r.path || r.path === "/") || {
|
|
3721
3783
|
id: "__shim-error-route__"
|
|
3722
3784
|
};
|
|
3723
3785
|
return {
|
|
@@ -4034,6 +4096,34 @@ function getDoneFetcher(data) {
|
|
|
4034
4096
|
};
|
|
4035
4097
|
return fetcher;
|
|
4036
4098
|
}
|
|
4099
|
+
function restoreAppliedTransitions(_window, transitions) {
|
|
4100
|
+
try {
|
|
4101
|
+
let sessionPositions = _window.sessionStorage.getItem(TRANSITIONS_STORAGE_KEY);
|
|
4102
|
+
if (sessionPositions) {
|
|
4103
|
+
let json = JSON.parse(sessionPositions);
|
|
4104
|
+
for (let [k, v] of Object.entries(json || {})) {
|
|
4105
|
+
if (v && Array.isArray(v)) {
|
|
4106
|
+
transitions.set(k, new Set(v || []));
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
}
|
|
4110
|
+
} catch (e) {
|
|
4111
|
+
// no-op, use default empty object
|
|
4112
|
+
}
|
|
4113
|
+
}
|
|
4114
|
+
function persistAppliedTransitions(_window, transitions) {
|
|
4115
|
+
if (transitions.size > 0) {
|
|
4116
|
+
let json = {};
|
|
4117
|
+
for (let [k, v] of transitions) {
|
|
4118
|
+
json[k] = [...v];
|
|
4119
|
+
}
|
|
4120
|
+
try {
|
|
4121
|
+
_window.sessionStorage.setItem(TRANSITIONS_STORAGE_KEY, JSON.stringify(json));
|
|
4122
|
+
} catch (error) {
|
|
4123
|
+
warning(false, "Failed to save applied view transitions in sessionStorage (" + error + ").");
|
|
4124
|
+
}
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4037
4127
|
//#endregion
|
|
4038
4128
|
|
|
4039
4129
|
export { AbortedDeferredError, Action, IDLE_BLOCKER, IDLE_FETCHER, IDLE_NAVIGATION, UNSAFE_DEFERRED_SYMBOL, DeferredData as UNSAFE_DeferredData, ErrorResponseImpl as UNSAFE_ErrorResponseImpl, convertRouteMatchToUiMatch as UNSAFE_convertRouteMatchToUiMatch, 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, redirectDocument, resolvePath, resolveTo, stripBasename };
|