@uniweb/runtime 1.1.11 → 1.1.13
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 +55 -16
- package/dist/ssr.js.map +1 -1
- package/package.json +4 -4
- package/src/area-wrappers.js +36 -7
- package/src/components/BlockRenderer.jsx +7 -1
- package/src/components/Blocks.jsx +8 -2
- package/src/components/Layout.jsx +21 -4
- package/src/default-layout.js +14 -4
- package/src/ssr-renderer.js +29 -7
- package/src/sticky-check.js +68 -0
- package/src/sticky.js +76 -0
package/dist/ssr.js
CHANGED
|
@@ -290,6 +290,24 @@ function ensureThemeCss(uniweb, foundation) {
|
|
|
290
290
|
console.warn("[uniweb] theme CSS generation failed:", err?.message || err);
|
|
291
291
|
}
|
|
292
292
|
}
|
|
293
|
+
const STICKY_TOP = "0px";
|
|
294
|
+
function stickyStyle(top, zIndex) {
|
|
295
|
+
const style = { position: "sticky", top: top || STICKY_TOP };
|
|
296
|
+
if (zIndex != null) style.zIndex = zIndex;
|
|
297
|
+
return style;
|
|
298
|
+
}
|
|
299
|
+
function areaStickiness(blocks) {
|
|
300
|
+
const first = (blocks || []).find((block) => block?.sticky);
|
|
301
|
+
return first ? { top: first.stickyTop || STICKY_TOP } : null;
|
|
302
|
+
}
|
|
303
|
+
function layoutStickiness(areas) {
|
|
304
|
+
const sticky = {};
|
|
305
|
+
for (const [name, blocks] of Object.entries(areas || {})) sticky[name] = areaStickiness(blocks);
|
|
306
|
+
return sticky;
|
|
307
|
+
}
|
|
308
|
+
function sectionStickyStyle(block) {
|
|
309
|
+
return block?.sticky ? stickyStyle(block.stickyTop, 1) : null;
|
|
310
|
+
}
|
|
293
311
|
const NS = "uw-";
|
|
294
312
|
const toIdent = (name) => NS + String(name).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
295
313
|
function resolveLayoutTransitions(areaNames, explicit) {
|
|
@@ -298,18 +316,27 @@ function resolveLayoutTransitions(areaNames, explicit) {
|
|
|
298
316
|
for (const name of areaNames) transitions[name] = toIdent(name);
|
|
299
317
|
return explicit ? { ...transitions, ...explicit } : transitions;
|
|
300
318
|
}
|
|
301
|
-
function resolveLayoutLayers(areaNames, explicit) {
|
|
319
|
+
function resolveLayoutLayers(areaNames, explicit, sticky = null) {
|
|
302
320
|
if (explicit === false) return {};
|
|
303
|
-
const
|
|
304
|
-
for (const name of areaNames)
|
|
305
|
-
|
|
321
|
+
const layers = {};
|
|
322
|
+
for (const name of areaNames) layers[name] = 1;
|
|
323
|
+
if (explicit) Object.assign(layers, explicit);
|
|
324
|
+
const lifted = areaNames.filter((name) => sticky?.[name] && !(explicit && name in explicit));
|
|
325
|
+
if (lifted.length > 0) {
|
|
326
|
+
const under = Object.entries(layers).filter(([name, layer]) => !sticky?.[name] && Number.isFinite(layer)).map(([, layer]) => layer);
|
|
327
|
+
const above = Math.max(0, ...under) + 1;
|
|
328
|
+
for (const name of lifted) layers[name] = above;
|
|
329
|
+
}
|
|
330
|
+
return layers;
|
|
306
331
|
}
|
|
307
|
-
function areaWrapperStyle(region, transitions, layers) {
|
|
332
|
+
function areaWrapperStyle(region, transitions, layers, sticky = null) {
|
|
308
333
|
const style = {};
|
|
309
334
|
const name = transitions?.[region];
|
|
310
335
|
if (name) style.viewTransitionName = name;
|
|
311
336
|
const layer = layers?.[region];
|
|
312
|
-
if (
|
|
337
|
+
if (sticky) {
|
|
338
|
+
Object.assign(style, stickyStyle(sticky.top, layer));
|
|
339
|
+
} else if (layer != null) {
|
|
313
340
|
style.position = "relative";
|
|
314
341
|
style.zIndex = layer;
|
|
315
342
|
}
|
|
@@ -317,13 +344,14 @@ function areaWrapperStyle(region, transitions, layers) {
|
|
|
317
344
|
}
|
|
318
345
|
const COLUMN = { display: "flex", flexDirection: "column", minHeight: "100vh" };
|
|
319
346
|
const GROW = { flex: 1 };
|
|
320
|
-
function DefaultLayout({ header, body, footer }) {
|
|
347
|
+
function DefaultLayout({ header, body, footer, zones }) {
|
|
348
|
+
const zone = (name) => zones?.[name] ? { style: zones[name] } : null;
|
|
321
349
|
return React.createElement(
|
|
322
350
|
"div",
|
|
323
351
|
{ style: COLUMN },
|
|
324
|
-
header && React.createElement("header",
|
|
352
|
+
header && React.createElement("header", zone("header"), header),
|
|
325
353
|
body && React.createElement("main", { style: GROW }, body),
|
|
326
|
-
footer && React.createElement("footer",
|
|
354
|
+
footer && React.createElement("footer", zone("footer"), footer)
|
|
327
355
|
);
|
|
328
356
|
}
|
|
329
357
|
function applyBootScheme(respectSystem, fallback) {
|
|
@@ -501,7 +529,7 @@ function renderBackground(background) {
|
|
|
501
529
|
"aria-hidden": "true"
|
|
502
530
|
}, ...children);
|
|
503
531
|
}
|
|
504
|
-
function renderBlock(block, { as = "section" } = {}) {
|
|
532
|
+
function renderBlock(block, { as = "section", stickySelf = false } = {}) {
|
|
505
533
|
const Component = block.initComponent();
|
|
506
534
|
if (!Component) {
|
|
507
535
|
return React.createElement("div", {
|
|
@@ -524,6 +552,8 @@ function renderBlock(block, { as = "section" } = {}) {
|
|
|
524
552
|
return React.createElement(Component, componentProps);
|
|
525
553
|
}
|
|
526
554
|
const { background, ...wrapperProps } = getWrapperProps(block);
|
|
555
|
+
const sticky = stickySelf ? sectionStickyStyle(block) : null;
|
|
556
|
+
if (sticky) wrapperProps.style = { ...wrapperProps.style, ...sticky };
|
|
527
557
|
const componentClassName = Component.className;
|
|
528
558
|
if (componentClassName) {
|
|
529
559
|
wrapperProps.className = wrapperProps.className ? `${wrapperProps.className} ${componentClassName}` : componentClassName;
|
|
@@ -549,13 +579,13 @@ function renderBlock(block, { as = "section" } = {}) {
|
|
|
549
579
|
React.createElement(Component, componentProps)
|
|
550
580
|
);
|
|
551
581
|
}
|
|
552
|
-
function renderBlocks(blocks) {
|
|
582
|
+
function renderBlocks(blocks, { stickySelf = false } = {}) {
|
|
553
583
|
if (!blocks || blocks.length === 0) return null;
|
|
554
584
|
return blocks.map(
|
|
555
585
|
(block, index) => React.createElement(
|
|
556
586
|
React.Fragment,
|
|
557
587
|
{ key: block.id || index },
|
|
558
|
-
renderBlock(block)
|
|
588
|
+
renderBlock(block, { stickySelf })
|
|
559
589
|
)
|
|
560
590
|
);
|
|
561
591
|
}
|
|
@@ -565,14 +595,18 @@ function renderLayout(page, website) {
|
|
|
565
595
|
const layoutMeta = website.getLayoutMeta(layoutName);
|
|
566
596
|
const bodyBlocks = page.getBodyBlocks();
|
|
567
597
|
const areas = page.getLayoutAreas();
|
|
598
|
+
for (const blocks of [bodyBlocks, ...Object.values(areas)]) {
|
|
599
|
+
for (const block of blocks || []) block.initComponent();
|
|
600
|
+
}
|
|
568
601
|
const areaNames = Object.keys(areas);
|
|
569
602
|
const transitions = website.viewTransitions ? resolveLayoutTransitions(areaNames, layoutMeta?.transitions) : null;
|
|
570
|
-
const
|
|
603
|
+
const sticky = layoutStickiness(areas);
|
|
604
|
+
const layers = resolveLayoutLayers(areaNames, layoutMeta?.layers, sticky);
|
|
571
605
|
const wrapArea = (name, element) => {
|
|
572
|
-
const style = areaWrapperStyle(name, transitions, layers);
|
|
606
|
+
const style = areaWrapperStyle(name, transitions, layers, RemoteLayout ? sticky[name] : null);
|
|
573
607
|
return style ? React.createElement("div", { style }, element) : element;
|
|
574
608
|
};
|
|
575
|
-
const bodyElement = bodyBlocks ? wrapArea("body", renderBlocks(bodyBlocks)) : null;
|
|
609
|
+
const bodyElement = bodyBlocks ? wrapArea("body", renderBlocks(bodyBlocks, { stickySelf: true })) : null;
|
|
576
610
|
const areaElements = {};
|
|
577
611
|
for (const [name, blocks] of Object.entries(areas)) {
|
|
578
612
|
areaElements[name] = wrapArea(name, renderBlocks(blocks));
|
|
@@ -587,7 +621,12 @@ function renderLayout(page, website) {
|
|
|
587
621
|
...areaElements
|
|
588
622
|
});
|
|
589
623
|
}
|
|
590
|
-
|
|
624
|
+
const zone = (name) => sticky[name] ? stickyStyle(sticky[name].top, layers?.[name]) : null;
|
|
625
|
+
return React.createElement(DefaultLayout, {
|
|
626
|
+
body: bodyElement,
|
|
627
|
+
...areaElements,
|
|
628
|
+
zones: { header: zone("header"), footer: zone("footer") }
|
|
629
|
+
});
|
|
591
630
|
}
|
|
592
631
|
function initPrerenderForLocale(content, foundation, locale, extensionsOrOptions, maybeOptions) {
|
|
593
632
|
const localeContent = sliceContentForLocale(content, locale);
|