@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.
|
|
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.
|
|
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.
|
|
52
|
+
"void": "0.21.0"
|
|
53
53
|
},
|
|
54
54
|
"scripts": {
|
|
55
55
|
"build": "vp pack",
|