@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(ViewRouteContextProvider, { value: routeContextValue, hold: holdRouteContext }, componentElement)));
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 only calls onEnd when a progress animation exists, so with animations off a
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 only calls
2683
- // swipeHandler.onEnd when one exists, so nothing would clear the mark until the
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();