@void/react 0.20.2 → 0.21.0

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.
@@ -1,6 +1,7 @@
1
1
  import { ComponentType } from "react";
2
2
  import { VoidRouter } from "void/pages-client";
3
3
  import { CacheForResult } from "void/pages-prefetch";
4
+ import { PageObject } from "void/pages-protocol";
4
5
  //#region src/runtime/pages-client.d.ts
5
6
  type ComponentModule = {
6
7
  default: ComponentType<any>;
@@ -17,6 +18,11 @@ export type ReactPagesConfig = Readonly<{
17
18
  viewTransitions: boolean;
18
19
  prefetchHoverDelay: number;
19
20
  prefetchDefaultCacheFor: CacheForResult;
21
+ cacheVisitedPageData?: boolean;
22
+ /** Show this fallback for client visits whose destination remains pending at the next paint. */
23
+ navigationFallback?: ComponentType<{
24
+ initialPageData: PageObject;
25
+ }>;
20
26
  }>;
21
27
  export type ReactPagesClient = Readonly<{
22
28
  router: VoidRouter;
@@ -66,7 +66,7 @@ function appReducer(state, action) {
66
66
  switch (action.type) {
67
67
  case "begin": return {
68
68
  resource: state.resource,
69
- rollbackResource: state.resource,
69
+ rollbackResource: state.rollbackResource || state.resource,
70
70
  pendingId: action.resource.id,
71
71
  routeUrl: state.routeUrl,
72
72
  navigation: action.navigation
@@ -90,6 +90,7 @@ function appReducer(state, action) {
90
90
  if (state.pendingId !== action.resource.id) return state;
91
91
  return {
92
92
  ...state,
93
+ resource: state.rollbackResource || state.resource,
93
94
  rollbackResource: null,
94
95
  pendingId: null,
95
96
  routeUrl: action.location,
@@ -190,7 +191,7 @@ function startViewTransition(resource, reveal, enabled) {
190
191
  return readyForCapture;
191
192
  });
192
193
  }
193
- function App({ engine, router, viewTransitions }) {
194
+ function App({ engine, router, viewTransitions, navigationFallback: NavigationFallback }) {
194
195
  const initialPageData = engine.initialPageData;
195
196
  const sharedStateRef = useRef(initialPageData.shared);
196
197
  const initialResource = useMemo(() => ({
@@ -308,7 +309,7 @@ function App({ engine, router, viewTransitions }) {
308
309
  pendingVisitSettlers.delete(prepared.id);
309
310
  if (activePendingNavigationId === prepared.id) activePendingNavigationId = null;
310
311
  dispatch({
311
- type: "finish",
312
+ type: NavigationFallback ? "abandon" : "finish",
312
313
  resource: prepared,
313
314
  location: currentUrl()
314
315
  });
@@ -328,7 +329,7 @@ function App({ engine, router, viewTransitions }) {
328
329
  if (prepared.method.toUpperCase() === "GET" && !prepared.options._resolveOnShell && isAbortError(error)) resolveVisit(void 0);
329
330
  else rejectVisit(error);
330
331
  if (activePendingNavigationId === prepared.id) activePendingNavigationId = null;
331
- if (prepared.options._resolveOnShell || isAbortError(error) || isCallSiteActionError(error)) {
332
+ if (NavigationFallback || prepared.options._resolveOnShell || isAbortError(error) || isCallSiteActionError(error)) {
332
333
  dispatch({
333
334
  type: "abandon",
334
335
  resource: prepared,
@@ -355,6 +356,30 @@ function App({ engine, router, viewTransitions }) {
355
356
  resource: next,
356
357
  navigation
357
358
  });
359
+ if (NavigationFallback) {
360
+ let shellSettled = false;
361
+ let revealed = false;
362
+ const reveal = (settled) => {
363
+ if (revealed || activePendingNavigationId !== next.id) return;
364
+ revealed = true;
365
+ if (settled) startTransition(() => dispatch({
366
+ type: "reveal",
367
+ resource: next
368
+ }));
369
+ else dispatch({
370
+ type: "reveal",
371
+ resource: next
372
+ });
373
+ };
374
+ next.shell.then((result) => {
375
+ shellSettled = true;
376
+ if (result) reveal(true);
377
+ });
378
+ requestAnimationFrame(() => {
379
+ if (!shellSettled) reveal(false);
380
+ });
381
+ return pagePromise;
382
+ }
358
383
  const reveal = () => {
359
384
  startTransition(() => {
360
385
  dispatch({
@@ -370,6 +395,7 @@ function App({ engine, router, viewTransitions }) {
370
395
  }, [
371
396
  engine,
372
397
  mergeShared,
398
+ NavigationFallback,
373
399
  startTransition,
374
400
  viewTransitions
375
401
  ]);
@@ -393,7 +419,7 @@ function App({ engine, router, viewTransitions }) {
393
419
  };
394
420
  }, [isTransitionPending, state.navigation]);
395
421
  const routerValue = useMemo(() => createRouterFacade(router, () => state.routeUrl), [router, state.routeUrl]);
396
- return React.createElement(RouterContext.Provider, { value: routerValue }, React.createElement(NavigationContext.Provider, { value: navigationValue }, React.createElement(Suspense, { fallback: null }, React.createElement(RouteResource, {
422
+ return React.createElement(RouterContext.Provider, { value: routerValue }, React.createElement(NavigationContext.Provider, { value: navigationValue }, React.createElement(Suspense, { fallback: NavigationFallback && state.pendingId !== null ? React.createElement(NavigationFallback, { initialPageData }) : null }, React.createElement(RouteResource, {
397
423
  resource: state.resource,
398
424
  onCommit: finishNavigation
399
425
  }))));
@@ -419,7 +445,8 @@ async function startReactPages(config) {
419
445
  staticPageDataFastPath: config.staticPageDataFastPath,
420
446
  viewTransitions: config.viewTransitions,
421
447
  prefetchHoverDelay: config.prefetchHoverDelay,
422
- prefetchDefaultCacheFor: config.prefetchDefaultCacheFor
448
+ prefetchDefaultCacheFor: config.prefetchDefaultCacheFor,
449
+ cacheVisitedPageData: config.cacheVisitedPageData
423
450
  });
424
451
  const router = createRouter(engine);
425
452
  setActionRouter(router);
@@ -428,7 +455,8 @@ async function startReactPages(config) {
428
455
  const appRoot = React.createElement(App, {
429
456
  engine,
430
457
  router,
431
- viewTransitions: config.viewTransitions
458
+ viewTransitions: config.viewTransitions,
459
+ navigationFallback: config.navigationFallback
432
460
  });
433
461
  const isSsr = appEl.getAttribute("data-void-ssr") !== "false";
434
462
  const hasDeferred = Boolean(engine.initialPageData.deferredKeys);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@void/react",
3
- "version": "0.20.2",
3
+ "version": "0.21.0",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/voidzero-dev/void.git",
@@ -43,13 +43,13 @@
43
43
  "react-dom": "^19.3.0",
44
44
  "vite": "npm:@voidzero-dev/vite-plus-core@0.3.1",
45
45
  "vite-plus": "0.3.1",
46
- "void": "0.20.2"
46
+ "void": "0.21.0"
47
47
  },
48
48
  "peerDependencies": {
49
49
  "react": "^19.0.0",
50
50
  "react-dom": "^19.0.0",
51
51
  "vite": "^8.0.0",
52
- "void": "0.20.2"
52
+ "void": "0.21.0"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "vp pack",