@jsenv/navi 0.16.28 → 0.16.30

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.
@@ -7812,7 +7812,6 @@ const createRoutePattern = (pattern) => {
7812
7812
 
7813
7813
  const applyOn = (url) => {
7814
7814
  const result = matchUrl(parsedPattern, url, {
7815
- parameterDefaults,
7816
7815
  baseUrl,
7817
7816
  connections,
7818
7817
  patternObj: patternObject,
@@ -7841,6 +7840,14 @@ const createRoutePattern = (pattern) => {
7841
7840
  }
7842
7841
  }
7843
7842
 
7843
+ // Add static defaults for parameters that are still missing
7844
+ // This handles cases where the URL doesn't contain the parameter and there's no signal value
7845
+ for (const [paramName, defaultValue] of parameterDefaults) {
7846
+ if (!(paramName in resolvedParams)) {
7847
+ resolvedParams[paramName] = defaultValue;
7848
+ }
7849
+ }
7850
+
7844
7851
  // Include active non-default parameters from child routes for URL optimization
7845
7852
  // Only include from child routes that would actually match the current parameters
7846
7853
  const childPatternObjs = patternObject.children || [];
@@ -9584,7 +9591,7 @@ const checkIfLiteralCanBeOptionalWithPatternObj = (
9584
9591
  const matchUrl = (
9585
9592
  parsedPattern,
9586
9593
  url,
9587
- { parameterDefaults, baseUrl, connections = [], patternObj = null },
9594
+ { baseUrl, connections = [], patternObj = null },
9588
9595
  ) => {
9589
9596
  // Parse the URL
9590
9597
  const urlObj = new URL(url, baseUrl);
@@ -9668,23 +9675,15 @@ const matchUrl = (
9668
9675
  if (urlSegmentIndex >= urlSegments.length) {
9669
9676
  // No URL segment for this parameter
9670
9677
  if (patternSeg.optional) {
9671
- // Optional parameter - use default if available
9672
- const defaultValue = parameterDefaults.get(patternSeg.name);
9673
- if (defaultValue !== undefined) {
9674
- params[patternSeg.name] = defaultValue;
9675
- }
9678
+ // Optional parameter - don't add default here, let resolveParams handle it
9676
9679
  continue;
9677
9680
  }
9678
9681
  // Required parameter missing - but check if we can use trailing slash logic
9679
9682
  // If this is the last segment and we have a trailing slash difference, it might still match
9680
9683
  const isLastSegment = i === parsedPattern.segments.length - 1;
9681
9684
  if (isLastSegment && patternHasTrailingSlash && !urlHasTrailingSlash) {
9682
- // Pattern expects trailing slash segment, URL doesn't have it
9683
- const defaultValue = parameterDefaults.get(patternSeg.name);
9684
- if (defaultValue !== undefined) {
9685
- params[patternSeg.name] = defaultValue;
9686
- continue;
9687
- }
9685
+ // Pattern expects trailing slash segment, URL doesn't have it - allow missing optional param
9686
+ continue;
9688
9687
  }
9689
9688
  return null; // Required parameter missing
9690
9689
  }
@@ -9716,12 +9715,8 @@ const matchUrl = (
9716
9715
  const searchParams = extractSearchParams(urlObj, connections);
9717
9716
  Object.assign(params, searchParams);
9718
9717
 
9719
- // Apply remaining parameter defaults for unmatched parameters
9720
- for (const [paramName, defaultValue] of parameterDefaults) {
9721
- if (!(paramName in params)) {
9722
- params[paramName] = defaultValue;
9723
- }
9724
- }
9718
+ // Don't add defaults here - rawParams should only contain what's in the URL
9719
+ // Defaults are handled by resolveParams() to create the final merged parameters
9725
9720
 
9726
9721
  return params;
9727
9722
  };
@@ -10373,19 +10368,7 @@ const updateRoutes = (
10373
10368
  const params = routePrivateProperties.rawParamsSignal.value;
10374
10369
  const urlParamValue = params[paramName];
10375
10370
 
10376
- if (newMatching) {
10377
- // When route matches, sync signal with URL parameter value
10378
- // This ensures URL is the source of truth
10379
- const currentValue = stateSignal.peek();
10380
- if (currentValue !== urlParamValue) {
10381
- if (debug) {
10382
- console.debug(
10383
- `[route] Route matching: setting ${paramName} signal to URL value: ${urlParamValue}`,
10384
- );
10385
- }
10386
- stateSignal.value = urlParamValue;
10387
- }
10388
- } else {
10371
+ if (!newMatching) {
10389
10372
  // Route doesn't match - check if any matching route extracts this parameter
10390
10373
  let parameterExtractedByMatchingRoute = false;
10391
10374
  let matchingRouteInSameFamily = false;
@@ -10488,7 +10471,39 @@ const updateRoutes = (
10488
10471
  );
10489
10472
  }
10490
10473
  }
10474
+ continue;
10491
10475
  }
10476
+
10477
+ // URL -> Signal sync: When route matches, ensure signal matches URL state
10478
+ // URL is the source of truth for explicit parameters
10479
+ const value = stateSignal.peek();
10480
+ if (urlParamValue === undefined) {
10481
+ // No URL parameter - reset signal to its current default value
10482
+ // (handles both static fallback and dynamic default cases)
10483
+ const defaultValue = options.getDefaultValue();
10484
+ if (value === defaultValue) {
10485
+ // Signal already has correct default value, no sync needed
10486
+ continue;
10487
+ }
10488
+ if (debug) {
10489
+ console.debug(
10490
+ `[route] URL->Signal: ${paramName} not in URL, reset signal to default (${defaultValue})`,
10491
+ );
10492
+ }
10493
+ stateSignal.value = defaultValue;
10494
+ continue;
10495
+ }
10496
+ if (urlParamValue === value) {
10497
+ // Values already match, no sync needed
10498
+ continue;
10499
+ }
10500
+ if (debug) {
10501
+ console.debug(
10502
+ `[route] URL->Signal: ${paramName}=${urlParamValue} in url, sync signal with url`,
10503
+ );
10504
+ }
10505
+ stateSignal.value = urlParamValue;
10506
+ continue;
10492
10507
  }
10493
10508
  }
10494
10509
  });
@@ -10687,28 +10702,49 @@ const registerRoute = (routePattern) => {
10687
10702
 
10688
10703
  if (debug) {
10689
10704
  console.debug(
10690
- `[route] connecting param "${paramName}" to signal`,
10705
+ `[route] connecting url param "${paramName}" to signal`,
10691
10706
  stateSignal,
10692
10707
  );
10693
10708
  }
10694
10709
 
10695
10710
  // URL -> Signal synchronization now handled in updateRoutes() to eliminate circular dependency
10696
10711
 
10697
- // Signal -> URL synchronization
10712
+ // Signal -> URL sync: When signal changes, update URL to reflect meaningful state
10713
+ // Only sync non-default values to keep URLs clean (static fallbacks stay invisible)
10698
10714
  effect(() => {
10699
10715
  const value = stateSignal.value;
10700
10716
  const params = rawParamsSignal.value;
10701
10717
  const urlParamValue = params[paramName];
10702
10718
  const matching = matchingSignal.value;
10703
10719
 
10704
- if (!matching || value === urlParamValue) {
10720
+ if (!matching) {
10721
+ // Route not matching, no URL sync needed
10722
+ return;
10723
+ }
10724
+ if (urlParamValue === undefined) {
10725
+ // No URL parameter exists - check if signal has meaningful value to add
10726
+ const defaultValue = options.getDefaultValue();
10727
+ if (value === defaultValue) {
10728
+ // Signal using default value, keep URL clean (no parameter needed)
10729
+ return;
10730
+ }
10731
+ if (debug) {
10732
+ console.debug(
10733
+ `[route] Signal->URL: ${paramName} adding custom value ${value} to URL (default: ${defaultValue})`,
10734
+ );
10735
+ }
10736
+ route.replaceParams({ [paramName]: value });
10737
+ return;
10738
+ }
10739
+ if (value === urlParamValue) {
10740
+ // Values already match, no sync needed
10705
10741
  return;
10706
10742
  }
10707
-
10708
10743
  if (debug) {
10709
- console.debug(`[stateSignal] Signal -> URL: ${paramName}=${value}`);
10744
+ console.debug(
10745
+ `[route] Signal->URL: ${paramName} updating URL ${urlParamValue} -> ${value}`,
10746
+ );
10710
10747
  }
10711
-
10712
10748
  route.replaceParams({ [paramName]: value });
10713
10749
  });
10714
10750
  }