@uniweb/runtime 1.2.7 → 1.2.9
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.
- package/dist/ssr.js +5 -1
- package/dist/ssr.js.map +1 -1
- package/package.json +3 -3
- package/src/components/PageRenderer.jsx +12 -5
- package/src/hooks/useLinkInterceptor.js +68 -51
- package/src/link-intent.js +77 -0
- package/src/load-page-data.js +6 -21
- package/src/navigation.js +229 -0
- package/src/page-blocks.js +26 -0
- package/src/setup.js +19 -58
package/src/setup.js
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
import { ChildBlocks } from './components/PageRenderer.jsx'
|
|
32
32
|
import Background from './components/Background.jsx'
|
|
33
33
|
import { wireFoundationCapabilities, hydrateDataStore, ensureThemeCss } from './wire-foundation.js'
|
|
34
|
+
import { navigateInApp } from './navigation.js'
|
|
34
35
|
|
|
35
36
|
// Re-export so existing consumers importing hydrateDataStore from
|
|
36
37
|
// setup.js keep working. The implementation moved to wire-foundation.js
|
|
@@ -38,56 +39,18 @@ import { wireFoundationCapabilities, hydrateDataStore, ensureThemeCss } from './
|
|
|
38
39
|
// without dragging react-dom/server into the SPA bundle.
|
|
39
40
|
export { hydrateDataStore }
|
|
40
41
|
|
|
41
|
-
//
|
|
42
|
-
//
|
|
43
|
-
|
|
44
|
-
// document.startViewTransition() to animate page changes. Split content
|
|
45
|
-
// is prefetched inside the transition callback so the user never sees
|
|
46
|
-
// a blank or loading state.
|
|
42
|
+
// `@uniweb/runtime/setup` has exported these since view transitions landed. They live with the
|
|
43
|
+
// navigation that uses them now.
|
|
44
|
+
export { prefetchContent, prefersReducedMotion } from './navigation.js'
|
|
47
45
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
*/
|
|
55
|
-
const CONTENT_PREFETCH_TIMEOUT = 1000
|
|
56
|
-
export const prefersReducedMotion =
|
|
57
|
-
typeof window !== 'undefined'
|
|
58
|
-
&& window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
59
|
-
|
|
60
|
-
export function prefetchContent(route) {
|
|
61
|
-
const website = globalThis.uniweb?.activeWebsite
|
|
62
|
-
if (!route || !website) return
|
|
63
|
-
|
|
64
|
-
const targetPage = website.getPage(route)
|
|
65
|
-
if (!targetPage?.hasContent?.() || targetPage.isContentLoaded?.()) return
|
|
66
|
-
|
|
67
|
-
return Promise.race([
|
|
68
|
-
targetPage.loadContent(),
|
|
69
|
-
new Promise((resolve) => setTimeout(resolve, CONTENT_PREFETCH_TIMEOUT)),
|
|
70
|
-
])
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/**
|
|
74
|
-
* Prefetch split content and navigate inside a view transition.
|
|
75
|
-
* Falls back to plain navigation when transitions are not available.
|
|
76
|
-
*/
|
|
77
|
-
function navigateWithTransition(navigate, to, options) {
|
|
78
|
-
const vt = globalThis.uniweb?.foundationConfig?.viewTransitions
|
|
79
|
-
if (vt && document.startViewTransition && !prefersReducedMotion) {
|
|
80
|
-
document.startViewTransition(async () => {
|
|
81
|
-
const route = typeof to === 'string' ? to : to?.pathname
|
|
82
|
-
await prefetchContent(route)
|
|
83
|
-
navigate(to, options)
|
|
84
|
-
})
|
|
85
|
-
} else {
|
|
86
|
-
navigate(to, options)
|
|
87
|
-
}
|
|
88
|
-
}
|
|
46
|
+
// ─── In-app navigation ──────────────────────────────────────────────────────
|
|
47
|
+
//
|
|
48
|
+
// Kit's <Link> and useRouting().useNavigate() reach the router through these, so every
|
|
49
|
+
// navigation they make goes through `navigateInApp` (`navigation.js`): the current page is
|
|
50
|
+
// held until the next one's content is here, and the swap is animated when view transitions
|
|
51
|
+
// apply.
|
|
89
52
|
|
|
90
|
-
const
|
|
53
|
+
const InAppLink = React.forwardRef(function InAppLink(
|
|
91
54
|
{ onClick, replace, state, preventScrollReset, ...props },
|
|
92
55
|
ref,
|
|
93
56
|
) {
|
|
@@ -98,12 +61,13 @@ const ViewTransitionLink = React.forwardRef(function ViewTransitionLink(
|
|
|
98
61
|
if (e.defaultPrevented) return
|
|
99
62
|
if (e.metaKey || e.altKey || e.ctrlKey || e.shiftKey) return
|
|
100
63
|
if (e.button !== 0) return
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
if (!vt || !document.startViewTransition || prefersReducedMotion) return
|
|
64
|
+
// Another tab or frame is the browser's to open. Kit passes a link's `target` on.
|
|
65
|
+
if (props.target && props.target !== '_self') return
|
|
104
66
|
|
|
105
67
|
e.preventDefault()
|
|
106
|
-
|
|
68
|
+
// A link to the page already shown replaces its history entry, as React Router's own does.
|
|
69
|
+
const here = e.currentTarget.href === window.location.href
|
|
70
|
+
navigateInApp(navigate, props.to, { replace: replace ?? here, state, preventScrollReset })
|
|
107
71
|
}
|
|
108
72
|
|
|
109
73
|
return React.createElement(RouterLink, {
|
|
@@ -116,13 +80,10 @@ const ViewTransitionLink = React.forwardRef(function ViewTransitionLink(
|
|
|
116
80
|
})
|
|
117
81
|
})
|
|
118
82
|
|
|
119
|
-
/**
|
|
120
|
-
* View-transition-aware useNavigate hook.
|
|
121
|
-
* The returned function wraps navigation in startViewTransition() when enabled.
|
|
122
|
-
*/
|
|
83
|
+
/** React Router's `useNavigate`, its navigations made through `navigateInApp`. */
|
|
123
84
|
function useNavigate() {
|
|
124
85
|
const navigate = useRouterNavigate()
|
|
125
|
-
return (to, options) =>
|
|
86
|
+
return (to, options) => navigateInApp(navigate, to, options)
|
|
126
87
|
}
|
|
127
88
|
|
|
128
89
|
/**
|
|
@@ -130,7 +91,7 @@ function useNavigate() {
|
|
|
130
91
|
* its own when it wraps DynamicApp in a MemoryRouter.
|
|
131
92
|
*/
|
|
132
93
|
const DEFAULT_ROUTING_COMPONENTS = {
|
|
133
|
-
Link:
|
|
94
|
+
Link: InAppLink,
|
|
134
95
|
useNavigate,
|
|
135
96
|
useParams,
|
|
136
97
|
useLocation,
|