@rangojs/router 0.0.0-experimental.39 → 0.0.0-experimental.40

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.
@@ -1745,7 +1745,7 @@ import { resolve } from "node:path";
1745
1745
  // package.json
1746
1746
  var package_default = {
1747
1747
  name: "@rangojs/router",
1748
- version: "0.0.0-experimental.39",
1748
+ version: "0.0.0-experimental.40",
1749
1749
  description: "Django-inspired RSC router with composable URL patterns",
1750
1750
  keywords: [
1751
1751
  "react",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rangojs/router",
3
- "version": "0.0.0-experimental.39",
3
+ "version": "0.0.0-experimental.40",
4
4
  "description": "Django-inspired RSC router with composable URL patterns",
5
5
  "keywords": [
6
6
  "react",
@@ -480,16 +480,14 @@ export function createNavigationBridge(
480
480
  addTransitionType("navigation-back");
481
481
  }
482
482
  onUpdate(popstateUpdate);
483
- // Restore inside the transition so React commits the new
484
- // content before scroll restoration measures scrollHeight.
485
- handleNavigationEnd({ restore: true, isStreaming });
486
483
  });
487
484
  } else {
488
485
  onUpdate(popstateUpdate);
489
- // Restore scroll position for back/forward navigation
490
- handleNavigationEnd({ restore: true, isStreaming });
491
486
  }
492
487
 
488
+ // Restore scroll position for back/forward navigation
489
+ handleNavigationEnd({ restore: true, isStreaming });
490
+
493
491
  // SWR: If stale, trigger background revalidation
494
492
  if (isStale) {
495
493
  debugLog("[Browser] Cache is stale, background revalidating...");
@@ -264,51 +264,35 @@ export function restoreScrollPosition(options?: {
264
264
  return false;
265
265
  }
266
266
 
267
- // Check if page is tall enough to scroll to saved position
268
- const maxScrollY = document.documentElement.scrollHeight - window.innerHeight;
269
- const canScrollToPosition = savedY <= maxScrollY;
270
-
271
- if (canScrollToPosition) {
272
- window.scrollTo(0, savedY);
273
- debugLog("[Scroll] Restored position:", savedY, "for key:", key);
274
- return true;
275
- }
276
-
277
- // Scroll as far as we can for now
278
- window.scrollTo(0, maxScrollY);
279
- debugLog("[Scroll] Partial restore to:", maxScrollY, "target:", savedY);
280
-
281
- // Poll until we can scroll to the target position.
282
- // This covers both streaming (content arriving incrementally) and
283
- // React's batched startTransition rendering (DOM updates are async
284
- // even for cached navigations with no streaming).
285
- if (options?.retryIfStreaming) {
267
+ // If streaming, poll until streaming ends then scroll to saved position
268
+ if (options?.retryIfStreaming && options?.isStreaming?.()) {
286
269
  const startTime = Date.now();
287
270
 
288
271
  pendingPollInterval = setInterval(() => {
289
- // Stop if we've exceeded the timeout
290
272
  if (Date.now() - startTime > SCROLL_POLL_TIMEOUT_MS) {
291
273
  debugLog("[Scroll] Polling timeout, giving up");
292
274
  cancelScrollRestorationPolling();
293
275
  return;
294
276
  }
295
277
 
296
- // Check if we can now scroll to the target position
297
- const currentMaxScrollY =
298
- document.documentElement.scrollHeight - window.innerHeight;
299
- if (savedY <= currentMaxScrollY) {
278
+ if (!options.isStreaming?.()) {
300
279
  window.scrollTo(0, savedY);
301
- debugLog("[Scroll] Poll restored position:", savedY);
280
+ debugLog("[Scroll] Restored after streaming:", savedY);
302
281
  cancelScrollRestorationPolling();
303
282
  }
304
283
  }, SCROLL_POLL_INTERVAL_MS);
305
284
 
306
- // Return true to prevent handleNavigationEnd from falling through
307
- // to scrollToTop(). The polling will handle the final scroll.
308
285
  return true;
309
286
  }
310
287
 
311
- return false;
288
+ // Not streaming — scroll after React commits and browser paints.
289
+ // startTransition defers the DOM commit, so scrolling synchronously
290
+ // would be overwritten when React replaces the content.
291
+ requestAnimationFrame(() => {
292
+ window.scrollTo(0, savedY);
293
+ debugLog("[Scroll] Restored position:", savedY, "for key:", key);
294
+ });
295
+ return true;
312
296
  }
313
297
 
314
298
  /**