@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/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
- // ─── View Transition Wrappers ───────────────────────────────────────────────
42
- //
43
- // When the foundation enables viewTransitions, navigation is wrapped in
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
- * Prefetch split page content with a timeout.
50
- * Resolves when content is loaded or the timeout expires — whichever
51
- * comes first. This keeps the old-page screenshot from freezing too
52
- * long on slow connections. If the timeout wins, navigation proceeds
53
- * and the PageRenderer loading gate handles the rest.
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 ViewTransitionLink = React.forwardRef(function ViewTransitionLink(
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
- const vt = globalThis.uniweb?.foundationConfig?.viewTransitions
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
- navigateWithTransition(navigate, props.to, { replace, state, preventScrollReset })
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) => navigateWithTransition(navigate, 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: ViewTransitionLink,
94
+ Link: InAppLink,
134
95
  useNavigate,
135
96
  useParams,
136
97
  useLocation,