@jsenv/navi 0.29.508 → 0.29.509

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.
@@ -8918,7 +8918,7 @@ const route = (pattern, options = {}) => {
8918
8918
  };
8919
8919
  route.redirectTo = (
8920
8920
  params,
8921
- { callReason, history = "replace", debounceUrl } = {},
8921
+ { callReason, history = "replace", debounceUrl, isSignalChange } = {},
8922
8922
  ) => {
8923
8923
  if (!integration) {
8924
8924
  {
@@ -8933,6 +8933,7 @@ const route = (pattern, options = {}) => {
8933
8933
  replace: history !== "push",
8934
8934
  debounce: debounceUrl,
8935
8935
  callReason,
8936
+ fromSignal: isSignalChange,
8936
8937
  });
8937
8938
  };
8938
8939
  route.replaceParams = (
@@ -8947,52 +8948,18 @@ const route = (pattern, options = {}) => {
8947
8948
  return null;
8948
8949
  }
8949
8950
 
8950
- // Find all matching routes and update their actions, then delegate to most specific (deeper = more specific)
8951
- let mostSpecificRoute = route;
8952
- const routePrivateProperties = getRoutePrivateProperties(route);
8953
- let maxDepth = routePrivateProperties.routePattern.depth;
8954
- for (const routeCandidate of routeSet) {
8955
- if (routeCandidate === route) {
8956
- continue;
8957
- }
8958
- if (!routeCandidate.matching) {
8959
- continue;
8960
- }
8961
- const matchingRoute = routeCandidate;
8962
- const matchingRoutePrivateProperties =
8963
- getRoutePrivateProperties(matchingRoute);
8964
- const depth = matchingRoutePrivateProperties.routePattern.depth;
8965
- if (depth > maxDepth) {
8966
- maxDepth = depth;
8967
- mostSpecificRoute = matchingRoute;
8968
- }
8969
- }
8951
+ const mostSpecificRoute = findMostSpecificMatchingRoute(route, routeSet);
8970
8952
  const isMostSpecificRoute = mostSpecificRoute === route;
8971
8953
 
8972
- // If we found a more specific route, delegate to it; otherwise handle it ourselves
8954
+ // If we found a more specific route, delegate to it; otherwise handle it ourselves.
8955
+ // A signal change reaches this only when the more specific route does not
8956
+ // carry the param (see writeValueInUrl): left to it, the change would be dropped.
8973
8957
  if (!isMostSpecificRoute) {
8974
- // For signal-originated calls, only skip delegation if the more specific route
8975
- // has its own signal connection for the same params — meaning its own effect will
8976
- // fire and handle the redirect. If it doesn't have the connection, the signal
8977
- // change would be silently dropped, so we must delegate anyway.
8978
- if (isSignalChange) {
8979
- const mostSpecificRoutePrivateProperties =
8980
- getRoutePrivateProperties(mostSpecificRoute);
8981
- const { pathConnectionMap, queryConnectionMap } =
8982
- mostSpecificRoutePrivateProperties.routePattern;
8983
- const willHandleItself = Object.keys(newParams).every(
8984
- (paramName) =>
8985
- pathConnectionMap.has(paramName) ||
8986
- queryConnectionMap.has(paramName),
8987
- );
8988
- if (willHandleItself) {
8989
- return null;
8990
- }
8991
- }
8992
8958
  return mostSpecificRoute.redirectTo(newParams, {
8993
8959
  callReason: `replaceParams delegation from ${route} to ${mostSpecificRoute} (original reason: ${callReason})`,
8994
8960
  history,
8995
8961
  debounceUrl,
8962
+ isSignalChange,
8996
8963
  });
8997
8964
  }
8998
8965
 
@@ -9016,6 +8983,7 @@ const route = (pattern, options = {}) => {
9016
8983
  replace: history !== "push",
9017
8984
  debounce: debounceUrl,
9018
8985
  callReason,
8986
+ fromSignal: isSignalChange,
9019
8987
  });
9020
8988
  };
9021
8989
  route.matchesParams = (providedParams) => {
@@ -9078,7 +9046,7 @@ const route = (pattern, options = {}) => {
9078
9046
  });
9079
9047
  // Signal -> URL sync: When signal changes, update URL to reflect meaningful state
9080
9048
  // Only sync non-default values to keep URLs clean (static fallbacks stay invisible)
9081
- registerSetup(() => {
9049
+ registerSetup(({ routeSet }) => {
9082
9050
  const cleanupSignalUrlEffectSet = new Set();
9083
9051
  // important: read connections at setup time so it includes query connections
9084
9052
  // inherited from ancestor patterns
@@ -9117,6 +9085,24 @@ const route = (pattern, options = {}) => {
9117
9085
  // Route not matching, no URL sync needed
9118
9086
  return;
9119
9087
  }
9088
+ // A param declared on an ancestor is carried by every route below it,
9089
+ // each with its own connection: all of them hear the write, the most
9090
+ // specific one makes it. The others step aside before the history is
9091
+ // read — a stateSignalGroup's push goes to the first write reading it.
9092
+ const mostSpecificRoute = findMostSpecificMatchingRoute(
9093
+ route,
9094
+ routeSet,
9095
+ );
9096
+ if (mostSpecificRoute !== route) {
9097
+ const { pathConnectionMap, queryConnectionMap } =
9098
+ getRoutePrivateProperties(mostSpecificRoute).routePattern;
9099
+ if (
9100
+ pathConnectionMap.has(paramName) ||
9101
+ queryConnectionMap.has(paramName)
9102
+ ) {
9103
+ return;
9104
+ }
9105
+ }
9120
9106
  if (urlParamValue === undefined) {
9121
9107
  // No URL parameter exists - check if signal has meaningful value to add
9122
9108
  if (connection.isDefaultValue(value)) {
@@ -9909,6 +9895,27 @@ const urlWithoutSearchAndHash = (url) => {
9909
9895
  return `${urlObject.origin}${urlObject.pathname}`;
9910
9896
  };
9911
9897
 
9898
+ // Deeper is more specific: among the routes matching the address, the one a
9899
+ // params write lands on.
9900
+ const findMostSpecificMatchingRoute = (route, routeSet) => {
9901
+ let mostSpecificRoute = route;
9902
+ let maxDepth = getRoutePrivateProperties(route).routePattern.depth;
9903
+ for (const routeCandidate of routeSet) {
9904
+ if (routeCandidate === route) {
9905
+ continue;
9906
+ }
9907
+ if (!routeCandidate.matching) {
9908
+ continue;
9909
+ }
9910
+ const depth = getRoutePrivateProperties(routeCandidate).routePattern.depth;
9911
+ if (depth > maxDepth) {
9912
+ maxDepth = depth;
9913
+ mostSpecificRoute = routeCandidate;
9914
+ }
9915
+ }
9916
+ return mostSpecificRoute;
9917
+ };
9918
+
9912
9919
  // Every route action, with whether it asks something of the address at the
9913
9920
  // moment: its route matches and its params getter returns something.
9914
9921
  const routeActionEntriesSignal = signal([]);
@@ -14496,11 +14503,15 @@ const setupBrowserIntegrationViaHistory = ({
14496
14503
  // browser answers — a before/after cycle here would be about a navigation
14497
14504
  // that never happens. A push with something of its own for its entry — a
14498
14505
  // state, what the press handed over (see carryByLinkNavigation) — is a
14499
- // new entry, never one standing there already.
14506
+ // new entry, never one standing there already. So is a push a signal write
14507
+ // makes: the writes after it in the same move (a layer, then what is open
14508
+ // inside it) build on its address at once, and a traversal would only land
14509
+ // after they went to the entry being left.
14500
14510
  if (
14501
14511
  options.navigationType === "push" &&
14502
14512
  options.state === undefined &&
14503
14513
  !options.pressWrites &&
14514
+ !options.fromSignal &&
14504
14515
  url !== readAddress()
14505
14516
  ) {
14506
14517
  const delta = adjacentEntryDelta(url);
@@ -14923,12 +14934,23 @@ const setupBrowserIntegrationViaHistory = ({
14923
14934
 
14924
14935
  const navTo = async (
14925
14936
  url,
14926
- { replace, state, routeTransition, debounce, asReturn, open } = {},
14937
+ {
14938
+ replace,
14939
+ state,
14940
+ routeTransition,
14941
+ debounce,
14942
+ asReturn,
14943
+ open,
14944
+ fromSignal,
14945
+ } = {},
14927
14946
  ) => {
14928
14947
  const routingOptions = {
14929
14948
  reason: `navTo called with "${url}"`,
14930
14949
  navigationType: replace ? "replace" : "push",
14931
14950
  state,
14951
+ // Made by a signal written into the url (see route.js writeValueInUrl):
14952
+ // such a push is never turned into a traversal (see handleRoutingTask).
14953
+ fromSignal,
14932
14954
  // A push that lands where its address was last left (see
14933
14955
  // link_return.js).
14934
14956
  asReturn,