@ionic/react-router 9.0.7-dev.11791381676.118a7a15 → 9.0.7-dev.11791478996.1b854592
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/dist/index.js
CHANGED
|
@@ -8,34 +8,6 @@ const IonRouteInner = ({ path, index, caseSensitive, element }) => {
|
|
|
8
8
|
return React.createElement(Route, { path: path, index: index, caseSensitive: caseSensitive, element: element });
|
|
9
9
|
};
|
|
10
10
|
|
|
11
|
-
/**
|
|
12
|
-
* Compares two route param objects by value, treating a missing object as empty.
|
|
13
|
-
*
|
|
14
|
-
* @param a The first params object.
|
|
15
|
-
* @param b The second params object.
|
|
16
|
-
* @returns True if both have the same keys with equal values.
|
|
17
|
-
*/
|
|
18
|
-
const areParamsEqual = (a, b) => {
|
|
19
|
-
const paramsA = a || {};
|
|
20
|
-
const paramsB = b || {};
|
|
21
|
-
const keysA = Object.keys(paramsA);
|
|
22
|
-
const keysB = Object.keys(paramsB);
|
|
23
|
-
if (keysA.length !== keysB.length) {
|
|
24
|
-
return false;
|
|
25
|
-
}
|
|
26
|
-
return keysA.every((key) => {
|
|
27
|
-
const valueA = paramsA[key];
|
|
28
|
-
const valueB = paramsB[key];
|
|
29
|
-
if (Array.isArray(valueA) && Array.isArray(valueB)) {
|
|
30
|
-
if (valueA.length !== valueB.length) {
|
|
31
|
-
return false;
|
|
32
|
-
}
|
|
33
|
-
return valueA.every((entry, idx) => entry === valueB[idx]);
|
|
34
|
-
}
|
|
35
|
-
return valueA === valueB;
|
|
36
|
-
});
|
|
37
|
-
};
|
|
38
|
-
|
|
39
11
|
/**
|
|
40
12
|
* The matchPath function is used only for matching paths, not rendering components or elements.
|
|
41
13
|
* @see https://reactrouter.com/v6/utils/match-path
|
|
@@ -722,42 +694,6 @@ const resolveIndexRouteMatch = (viewItem, pathname, parentPath) => {
|
|
|
722
694
|
const normalizedBase = normalizePathnameForComparison(previousMatch.pathnameBase || previousMatch.pathname || '');
|
|
723
695
|
return normalizedPathname === normalizedBase ? previousMatch : null;
|
|
724
696
|
};
|
|
725
|
-
const shallowEqual = (a, b) => {
|
|
726
|
-
const aRecord = a;
|
|
727
|
-
const bRecord = b;
|
|
728
|
-
const aKeys = Object.keys(aRecord);
|
|
729
|
-
return aKeys.length === Object.keys(bRecord).length && aKeys.every((key) => aRecord[key] === bRecord[key]);
|
|
730
|
-
};
|
|
731
|
-
const isSameMatch = (a, b) => a === b ||
|
|
732
|
-
(a.pathname === b.pathname &&
|
|
733
|
-
a.pathnameBase === b.pathnameBase &&
|
|
734
|
-
areParamsEqual(a.params, b.params) &&
|
|
735
|
-
(a.route === b.route || shallowEqual(a.route, b.route)));
|
|
736
|
-
/**
|
|
737
|
-
* The outlet rebuilds a view's RouteContext on every render, and it renders
|
|
738
|
-
* several times per navigation, so this compares by content to tell whether
|
|
739
|
-
* the view's route state actually changed.
|
|
740
|
-
*/
|
|
741
|
-
const isSameRouteContext = (a, b) => {
|
|
742
|
-
const { matches: aMatches, ...aRest } = a;
|
|
743
|
-
const { matches: bMatches, ...bRest } = b;
|
|
744
|
-
return (shallowEqual(aRest, bRest) &&
|
|
745
|
-
aMatches.length === bMatches.length &&
|
|
746
|
-
aMatches.every((match, i) => isSameMatch(match, bMatches[i])));
|
|
747
|
-
};
|
|
748
|
-
/**
|
|
749
|
-
* Provides a view's RouteContext, reusing the previous value while its content
|
|
750
|
-
* is unchanged or while `hold` is set (the view is not the one being shown), so
|
|
751
|
-
* RouteContext-only readers like useParams skip re-rendering. Kept in component
|
|
752
|
-
* state since two outlets with the same id share view items.
|
|
753
|
-
*/
|
|
754
|
-
const ViewRouteContextProvider = ({ value, hold, children }) => {
|
|
755
|
-
const [heldValue, setHeldValue] = React.useState(value);
|
|
756
|
-
if (!hold && heldValue !== value && !isSameRouteContext(heldValue, value)) {
|
|
757
|
-
setHeldValue(value);
|
|
758
|
-
}
|
|
759
|
-
return React.createElement(UNSAFE_RouteContext.Provider, { value: heldValue }, children);
|
|
760
|
-
};
|
|
761
697
|
class ReactRouterViewStack extends ViewStacks {
|
|
762
698
|
/**
|
|
763
699
|
* Stores the computed parent path for each outlet.
|
|
@@ -958,8 +894,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
958
894
|
viewItem.mount = true;
|
|
959
895
|
viewItem.routeData.match = match;
|
|
960
896
|
}
|
|
961
|
-
// Set when a more specific sibling owns the pathname, so this view is hidden even though it matches.
|
|
962
|
-
let hiddenBySpecificMatch = false;
|
|
963
897
|
// Deactivate wildcard (catch-all) and empty-path (default) routes when a more-specific route matches.
|
|
964
898
|
// This prevents "Not found" or fallback pages from showing alongside valid routes.
|
|
965
899
|
if (routePath === '*' || routePath === '/*' || routePath === '') {
|
|
@@ -1016,7 +950,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1016
950
|
}
|
|
1017
951
|
}
|
|
1018
952
|
if (hasSpecificMatch && !isSwipeRevealed(viewItem)) {
|
|
1019
|
-
hiddenBySpecificMatch = true;
|
|
1020
953
|
// A splat can be the outlet's container page rather than a "not found" fallback.
|
|
1021
954
|
// Pushed over it is the page underneath, so unmounting it destroys its state and
|
|
1022
955
|
// leaves nothing for back to reveal. Hiding it below covers that. A view with no
|
|
@@ -1039,11 +972,6 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1039
972
|
viewItem.routeData.match = match;
|
|
1040
973
|
}
|
|
1041
974
|
const routeMatch = shouldSkipForDifferentParam ? viewItem.routeData?.match : match || viewItem.routeData?.match;
|
|
1042
|
-
// Hold the RouteContext while the view isn't the one shown: a sibling owns the pathname, it's
|
|
1043
|
-
// parked on another param instance, or it doesn't match. A pathless default only strictly
|
|
1044
|
-
// matches at "/", so a missing match there doesn't mean it's hidden.
|
|
1045
|
-
const isPathlessDefault = !routePath && !viewItem.routeData?.childProps?.index;
|
|
1046
|
-
const holdRouteContext = hiddenBySpecificMatch || !!shouldSkipForDifferentParam || (!match && !isPathlessDefault);
|
|
1047
975
|
return (React.createElement(UNSAFE_RouteContext.Consumer, { key: `view-context-${viewItem.id}` }, (parentContext) => {
|
|
1048
976
|
const parentMatches = (parentContext?.matches ?? []);
|
|
1049
977
|
// Accumulate params from parent matches, with fallback to other outlets
|
|
@@ -1059,7 +987,7 @@ class ReactRouterViewStack extends ViewStacks {
|
|
|
1059
987
|
? { ...parentContext, matches: contextMatches }
|
|
1060
988
|
: { outlet: null, matches: contextMatches, isDataRoute: false };
|
|
1061
989
|
return (React.createElement(ViewLifeCycleManager, { key: `view-${viewItem.id}`, mount: viewItem.mount, removeView: () => this.remove(viewItem) },
|
|
1062
|
-
React.createElement(
|
|
990
|
+
React.createElement(UNSAFE_RouteContext.Provider, { value: routeContextValue }, componentElement)));
|
|
1063
991
|
}));
|
|
1064
992
|
};
|
|
1065
993
|
/**
|
|
@@ -2650,7 +2578,7 @@ class StackManager extends React.PureComponent {
|
|
|
2650
2578
|
return canStartSwipe;
|
|
2651
2579
|
};
|
|
2652
2580
|
const onStart = async () => {
|
|
2653
|
-
// Core
|
|
2581
|
+
// Core skips onEnd when an animated swipe ends without a progress animation, so a
|
|
2654
2582
|
// previous gesture can leave its mark behind. Drop any stale one before marking.
|
|
2655
2583
|
this.clearSwipeRevealedView();
|
|
2656
2584
|
const { routeInfo } = this.props;
|
|
@@ -2679,9 +2607,9 @@ class StackManager extends React.PureComponent {
|
|
|
2679
2607
|
revealIonPageForSwipeBack(enteringViewItem?.ionPageElement);
|
|
2680
2608
|
// When the gesture starts, kick off a transition controlled via swipe gesture
|
|
2681
2609
|
if (enteringViewItem && leavingViewItem) {
|
|
2682
|
-
// Without a leaving view there is no progress animation, and core
|
|
2683
|
-
// swipeHandler.onEnd
|
|
2684
|
-
// next transition.
|
|
2610
|
+
// Without a leaving view there is no progress animation, and core skips
|
|
2611
|
+
// swipeHandler.onEnd for an animated swipe without one, so nothing would clear the
|
|
2612
|
+
// mark until the next transition.
|
|
2685
2613
|
markSwipeRevealed(enteringViewItem);
|
|
2686
2614
|
this.swipeRevealedViewItem = enteringViewItem;
|
|
2687
2615
|
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
|
@@ -3178,6 +3106,26 @@ const checkIsMultiStepBack = (prevInfo, destinationPathname, history) => {
|
|
|
3178
3106
|
}
|
|
3179
3107
|
return false;
|
|
3180
3108
|
};
|
|
3109
|
+
const areParamsEqual = (a, b) => {
|
|
3110
|
+
const paramsA = a || {};
|
|
3111
|
+
const paramsB = b || {};
|
|
3112
|
+
const keysA = Object.keys(paramsA);
|
|
3113
|
+
const keysB = Object.keys(paramsB);
|
|
3114
|
+
if (keysA.length !== keysB.length) {
|
|
3115
|
+
return false;
|
|
3116
|
+
}
|
|
3117
|
+
return keysA.every((key) => {
|
|
3118
|
+
const valueA = paramsA[key];
|
|
3119
|
+
const valueB = paramsB[key];
|
|
3120
|
+
if (Array.isArray(valueA) && Array.isArray(valueB)) {
|
|
3121
|
+
if (valueA.length !== valueB.length) {
|
|
3122
|
+
return false;
|
|
3123
|
+
}
|
|
3124
|
+
return valueA.every((entry, idx) => entry === valueB[idx]);
|
|
3125
|
+
}
|
|
3126
|
+
return valueA === valueB;
|
|
3127
|
+
});
|
|
3128
|
+
};
|
|
3181
3129
|
const IonRouter = ({ children, registerHistoryListener }) => {
|
|
3182
3130
|
const location = useLocation();
|
|
3183
3131
|
const navigate = useNavigate();
|