@uniweb/runtime 1.2.13 → 1.3.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.
- package/dist/ssr.js +2 -1
- package/dist/ssr.js.map +1 -1
- package/package.json +4 -4
- package/src/area-wrappers.js +20 -10
- package/src/components/BlockRenderer.jsx +2 -2
- package/src/components/Layout.jsx +2 -2
- package/src/ssr-renderer.js +3 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@uniweb/runtime",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Minimal runtime for loading Uniweb foundations",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -36,15 +36,15 @@
|
|
|
36
36
|
"node": ">=22.12"
|
|
37
37
|
},
|
|
38
38
|
"dependencies": {
|
|
39
|
-
"@uniweb/
|
|
40
|
-
"@uniweb/
|
|
39
|
+
"@uniweb/core": "~1.5.0",
|
|
40
|
+
"@uniweb/theming": "~1.2.1"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@vitejs/plugin-react": "^4.5.2",
|
|
44
44
|
"esbuild": "^0.21.0 || ^0.23.0 || ^0.24.0 || ^0.25.0 || ^0.27.0 || ^0.28.0",
|
|
45
45
|
"vite": "^7.3.1",
|
|
46
46
|
"vitest": "^4.1.7",
|
|
47
|
-
"@uniweb/build": "1.
|
|
47
|
+
"@uniweb/build": "1.12.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"react": "^19.0.0",
|
package/src/area-wrappers.js
CHANGED
|
@@ -2,11 +2,19 @@
|
|
|
2
2
|
* What the runtime puts on a layout-area wrapper.
|
|
3
3
|
*
|
|
4
4
|
* When a foundation enables view transitions (the default), the runtime gives
|
|
5
|
-
* each layout
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
5
|
+
* each layout area a `view-transition-name` so the browser animates it on its
|
|
6
|
+
* own — persistent chrome (header, sidebar, footer) morphs in place while
|
|
7
|
+
* everything else, the body included, crossfades as the page. With no names the
|
|
8
|
+
* whole layout (chrome included) would flicker on every navigation.
|
|
9
|
+
*
|
|
10
|
+
* ⛔ **The body takes no name by default, which is what keeps a phone usable.** A
|
|
11
|
+
* named element is captured as one image. WebKit captures it whole, off-screen part
|
|
12
|
+
* included, at device resolution, painting every filter in it on the main thread; the
|
|
13
|
+
* page itself is captured at the size of the viewport. Measured 2026-10-30 on a live
|
|
14
|
+
* site, in WebKit on a 3× phone viewport with a desktop CPU: a named body was a
|
|
15
|
+
* 1179 × 22710 capture, 107 MB against 9 MB, and a tap stalled the main thread for up to
|
|
16
|
+
* 842 ms, against 271 ms with no name. Chromium did not stall at all. On an iPhone, that
|
|
17
|
+
* site froze for about 30 s on a tap. The body still crossfades, with the page.
|
|
10
18
|
*
|
|
11
19
|
* Naming is only half of it. A `view-transition-name` **makes its element a
|
|
12
20
|
* stacking context**, so the moment the runtime adds these wrappers it has
|
|
@@ -41,13 +49,14 @@ const toIdent = (name) => NS + String(name).replace(/[^a-zA-Z0-9_-]/g, '-')
|
|
|
41
49
|
/**
|
|
42
50
|
* Build the effective view-transition-name map for a layout.
|
|
43
51
|
*
|
|
44
|
-
* Default: every rendered area
|
|
45
|
-
*
|
|
46
|
-
*
|
|
52
|
+
* Default: every rendered area gets a stable, namespaced name (`uw-<area>`), so
|
|
53
|
+
* same-named areas across layouts share a name and morph between layouts
|
|
54
|
+
* automatically. The body gets none and crossfades as the page (the header above).
|
|
47
55
|
*
|
|
48
56
|
* The layout's `meta.js` `transitions` value overrides this:
|
|
49
57
|
* - an object overrides per region (`{ left: 'sidebar' }` to group across
|
|
50
|
-
* layouts,
|
|
58
|
+
* layouts, `{ left: null }` to opt one region out, or `{ body: 'main' }` for a
|
|
59
|
+
* body that morphs between layouts, which WebKit captures whole);
|
|
51
60
|
* - `false` opts the whole layout out (back to the full-page crossfade).
|
|
52
61
|
*
|
|
53
62
|
* @param {string[]} areaNames - Names of the areas rendered for this page (excludes `body`).
|
|
@@ -58,7 +67,7 @@ const toIdent = (name) => NS + String(name).replace(/[^a-zA-Z0-9_-]/g, '-')
|
|
|
58
67
|
export function resolveLayoutTransitions(areaNames, explicit) {
|
|
59
68
|
if (explicit === false) return null
|
|
60
69
|
|
|
61
|
-
const transitions = {
|
|
70
|
+
const transitions = {}
|
|
62
71
|
for (const name of areaNames) transitions[name] = toIdent(name)
|
|
63
72
|
|
|
64
73
|
return explicit ? { ...transitions, ...explicit } : transitions
|
|
@@ -169,6 +178,7 @@ export function areaWrapperStyle(region, transitions, layers, sticky = null) {
|
|
|
169
178
|
|
|
170
179
|
const name = transitions?.[region]
|
|
171
180
|
if (name) style.viewTransitionName = name
|
|
181
|
+
else if (transitions && region === 'body') style.isolation = 'isolate'
|
|
172
182
|
|
|
173
183
|
const layer = layers?.[region]
|
|
174
184
|
if (sticky) {
|
|
@@ -139,8 +139,8 @@ export default function BlockRenderer({ block, as = 'section', stickySelf = fals
|
|
|
139
139
|
|
|
140
140
|
// Build content and params with runtime guarantees.
|
|
141
141
|
// prepareProps handles the full pipeline: entity data merge onto
|
|
142
|
-
// block.parsedContent.data, foundation content
|
|
143
|
-
// guaranteed content structure,
|
|
142
|
+
// block.parsedContent.data, foundation data and content handlers,
|
|
143
|
+
// param defaults, guaranteed content structure, and the props handler.
|
|
144
144
|
// See prepare-props.js for the pipeline details.
|
|
145
145
|
const prepared = prepareProps(block, meta, entityData)
|
|
146
146
|
const params = prepared.params
|
|
@@ -86,8 +86,8 @@ export default function Layout({ page, website }) {
|
|
|
86
86
|
// Pre-render each area as React elements.
|
|
87
87
|
// When the foundation enables view transitions, wrap areas in thin divs with
|
|
88
88
|
// view-transition-name so the browser can animate them independently. Names
|
|
89
|
-
// default to one per area
|
|
90
|
-
// `transitions` meta overrides or opts out.
|
|
89
|
+
// default to one per area and none for the body (see resolveLayoutTransitions);
|
|
90
|
+
// the layout's `transitions` meta overrides or opts out.
|
|
91
91
|
const areaNames = Object.keys(areas)
|
|
92
92
|
const transitions = website.viewTransitions
|
|
93
93
|
? resolveLayoutTransitions(areaNames, layoutMeta?.transitions)
|
package/src/ssr-renderer.js
CHANGED
|
@@ -157,8 +157,8 @@ export function renderBlock(block, { as = 'section', stickySelf = false } = {})
|
|
|
157
157
|
|
|
158
158
|
// Build content and params with runtime guarantees.
|
|
159
159
|
// prepareProps handles the full pipeline: entity data merge,
|
|
160
|
-
// foundation content
|
|
161
|
-
// structure,
|
|
160
|
+
// foundation data and content handlers, param defaults, guaranteed
|
|
161
|
+
// content structure, and the props handler.
|
|
162
162
|
// See prepare-props.js for the pipeline details.
|
|
163
163
|
const prepared = prepareProps(block, meta, entityData)
|
|
164
164
|
const params = prepared.params
|
|
@@ -247,7 +247,7 @@ export function renderLayout(page, website) {
|
|
|
247
247
|
for (const block of blocks || []) block.initComponent()
|
|
248
248
|
}
|
|
249
249
|
|
|
250
|
-
// Mirror Layout.jsx: wrap body
|
|
250
|
+
// Mirror Layout.jsx: wrap the body and each area in a thin div, an area's carrying its
|
|
251
251
|
// view-transition-name, so the prerendered HTML matches the page the SPA renders
|
|
252
252
|
// in its place and the browser can animate regions independently on client navigation.
|
|
253
253
|
const areaNames = Object.keys(areas)
|