@uniweb/runtime 1.1.12 → 1.1.14
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 +72 -18
- package/dist/ssr.js.map +1 -1
- package/package.json +4 -4
- package/src/area-wrappers.js +53 -7
- package/src/components/BlockRenderer.jsx +14 -1
- package/src/components/Blocks.jsx +8 -2
- package/src/components/Layout.jsx +28 -6
- package/src/components/PageRenderer.jsx +1 -1
- package/src/default-layout.js +13 -4
- package/src/ssr-renderer.js +36 -10
- package/src/sticky-check.js +110 -0
- package/src/sticky-top.js +100 -0
- package/src/sticky.js +124 -0
package/dist/ssr.js
CHANGED
|
@@ -290,6 +290,32 @@ 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
|
+
const STICKY_SECTION_TOP = "var(--uw-sticky-top, 0px)";
|
|
295
|
+
function stickyStyle(top, zIndex) {
|
|
296
|
+
const style = { position: "sticky", top: top || STICKY_TOP };
|
|
297
|
+
if (zIndex != null) style.zIndex = zIndex;
|
|
298
|
+
return style;
|
|
299
|
+
}
|
|
300
|
+
function areaStickiness(blocks) {
|
|
301
|
+
const first = (blocks || []).find((block) => block?.sticky);
|
|
302
|
+
return first ? { top: first.stickyTop || STICKY_TOP } : null;
|
|
303
|
+
}
|
|
304
|
+
function layoutStickiness(areas) {
|
|
305
|
+
const sticky = {};
|
|
306
|
+
for (const [name, blocks] of Object.entries(areas || {})) sticky[name] = areaStickiness(blocks);
|
|
307
|
+
return sticky;
|
|
308
|
+
}
|
|
309
|
+
function zoneProps(stickiness, layer) {
|
|
310
|
+
return stickiness ? { style: stickyStyle(stickiness.top, layer), "data-uw-sticky": "area" } : null;
|
|
311
|
+
}
|
|
312
|
+
function sectionStickyStyle(block) {
|
|
313
|
+
return block?.sticky ? { ...stickyStyle(block.stickyTop || STICKY_SECTION_TOP, 1), alignSelf: "start" } : null;
|
|
314
|
+
}
|
|
315
|
+
function sectionStickyProps(block, kind) {
|
|
316
|
+
const style = kind ? sectionStickyStyle(block) : null;
|
|
317
|
+
return style ? { style, "data-uw-sticky": kind === "child" ? "child" : "section" } : null;
|
|
318
|
+
}
|
|
293
319
|
const NS = "uw-";
|
|
294
320
|
const toIdent = (name) => NS + String(name).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
295
321
|
function resolveLayoutTransitions(areaNames, explicit) {
|
|
@@ -298,32 +324,46 @@ function resolveLayoutTransitions(areaNames, explicit) {
|
|
|
298
324
|
for (const name of areaNames) transitions[name] = toIdent(name);
|
|
299
325
|
return explicit ? { ...transitions, ...explicit } : transitions;
|
|
300
326
|
}
|
|
301
|
-
function resolveLayoutLayers(areaNames, explicit) {
|
|
327
|
+
function resolveLayoutLayers(areaNames, explicit, sticky = null) {
|
|
302
328
|
if (explicit === false) return {};
|
|
303
|
-
const
|
|
304
|
-
for (const name of areaNames)
|
|
305
|
-
|
|
329
|
+
const layers = {};
|
|
330
|
+
for (const name of areaNames) layers[name] = 1;
|
|
331
|
+
if (explicit) Object.assign(layers, explicit);
|
|
332
|
+
const lifted = areaNames.filter((name) => sticky?.[name] && !(explicit && name in explicit));
|
|
333
|
+
if (lifted.length > 0) {
|
|
334
|
+
const under = Object.entries(layers).filter(([name, layer]) => !sticky?.[name] && Number.isFinite(layer)).map(([, layer]) => layer);
|
|
335
|
+
const above = Math.max(0, ...under) + 1;
|
|
336
|
+
for (const name of lifted) layers[name] = above;
|
|
337
|
+
}
|
|
338
|
+
return layers;
|
|
306
339
|
}
|
|
307
|
-
function areaWrapperStyle(region, transitions, layers) {
|
|
340
|
+
function areaWrapperStyle(region, transitions, layers, sticky = null) {
|
|
308
341
|
const style = {};
|
|
309
342
|
const name = transitions?.[region];
|
|
310
343
|
if (name) style.viewTransitionName = name;
|
|
311
344
|
const layer = layers?.[region];
|
|
312
|
-
if (
|
|
345
|
+
if (sticky) {
|
|
346
|
+
Object.assign(style, stickyStyle(sticky.top, layer));
|
|
347
|
+
} else if (layer != null) {
|
|
313
348
|
style.position = "relative";
|
|
314
349
|
style.zIndex = layer;
|
|
315
350
|
}
|
|
316
351
|
return Object.keys(style).length > 0 ? style : null;
|
|
317
352
|
}
|
|
353
|
+
function areaWrapperProps(region, transitions, layers, sticky = null) {
|
|
354
|
+
const style = areaWrapperStyle(region, transitions, layers, sticky);
|
|
355
|
+
if (!style) return null;
|
|
356
|
+
return sticky ? { style, "data-uw-sticky": "area" } : { style };
|
|
357
|
+
}
|
|
318
358
|
const COLUMN = { display: "flex", flexDirection: "column", minHeight: "100vh" };
|
|
319
359
|
const GROW = { flex: 1 };
|
|
320
|
-
function DefaultLayout({ header, body, footer }) {
|
|
360
|
+
function DefaultLayout({ header, body, footer, zones }) {
|
|
321
361
|
return React.createElement(
|
|
322
362
|
"div",
|
|
323
363
|
{ style: COLUMN },
|
|
324
|
-
header && React.createElement("header", null, header),
|
|
364
|
+
header && React.createElement("header", zones?.header || null, header),
|
|
325
365
|
body && React.createElement("main", { style: GROW }, body),
|
|
326
|
-
footer && React.createElement("footer", null, footer)
|
|
366
|
+
footer && React.createElement("footer", zones?.footer || null, footer)
|
|
327
367
|
);
|
|
328
368
|
}
|
|
329
369
|
function applyBootScheme(respectSystem, fallback) {
|
|
@@ -501,7 +541,7 @@ function renderBackground(background) {
|
|
|
501
541
|
"aria-hidden": "true"
|
|
502
542
|
}, ...children);
|
|
503
543
|
}
|
|
504
|
-
function renderBlock(block, { as = "section" } = {}) {
|
|
544
|
+
function renderBlock(block, { as = "section", stickySelf = false } = {}) {
|
|
505
545
|
const Component = block.initComponent();
|
|
506
546
|
if (!Component) {
|
|
507
547
|
return React.createElement("div", {
|
|
@@ -524,6 +564,11 @@ function renderBlock(block, { as = "section" } = {}) {
|
|
|
524
564
|
return React.createElement(Component, componentProps);
|
|
525
565
|
}
|
|
526
566
|
const { background, ...wrapperProps } = getWrapperProps(block);
|
|
567
|
+
const sticky = sectionStickyProps(block, stickySelf);
|
|
568
|
+
if (sticky) {
|
|
569
|
+
wrapperProps.style = { ...wrapperProps.style, ...sticky.style };
|
|
570
|
+
wrapperProps["data-uw-sticky"] = sticky["data-uw-sticky"];
|
|
571
|
+
}
|
|
527
572
|
const componentClassName = Component.className;
|
|
528
573
|
if (componentClassName) {
|
|
529
574
|
wrapperProps.className = wrapperProps.className ? `${wrapperProps.className} ${componentClassName}` : componentClassName;
|
|
@@ -549,13 +594,13 @@ function renderBlock(block, { as = "section" } = {}) {
|
|
|
549
594
|
React.createElement(Component, componentProps)
|
|
550
595
|
);
|
|
551
596
|
}
|
|
552
|
-
function renderBlocks(blocks) {
|
|
597
|
+
function renderBlocks(blocks, { stickySelf = false } = {}) {
|
|
553
598
|
if (!blocks || blocks.length === 0) return null;
|
|
554
599
|
return blocks.map(
|
|
555
600
|
(block, index) => React.createElement(
|
|
556
601
|
React.Fragment,
|
|
557
602
|
{ key: block.id || index },
|
|
558
|
-
renderBlock(block)
|
|
603
|
+
renderBlock(block, { stickySelf })
|
|
559
604
|
)
|
|
560
605
|
);
|
|
561
606
|
}
|
|
@@ -565,14 +610,18 @@ function renderLayout(page, website) {
|
|
|
565
610
|
const layoutMeta = website.getLayoutMeta(layoutName);
|
|
566
611
|
const bodyBlocks = page.getBodyBlocks();
|
|
567
612
|
const areas = page.getLayoutAreas();
|
|
613
|
+
for (const blocks of [bodyBlocks, ...Object.values(areas)]) {
|
|
614
|
+
for (const block of blocks || []) block.initComponent();
|
|
615
|
+
}
|
|
568
616
|
const areaNames = Object.keys(areas);
|
|
569
617
|
const transitions = website.viewTransitions ? resolveLayoutTransitions(areaNames, layoutMeta?.transitions) : null;
|
|
570
|
-
const
|
|
618
|
+
const sticky = layoutStickiness(areas);
|
|
619
|
+
const layers = resolveLayoutLayers(areaNames, layoutMeta?.layers, sticky);
|
|
571
620
|
const wrapArea = (name, element) => {
|
|
572
|
-
const
|
|
573
|
-
return
|
|
621
|
+
const props = areaWrapperProps(name, transitions, layers, RemoteLayout ? sticky[name] : null);
|
|
622
|
+
return props ? React.createElement("div", props, element) : element;
|
|
574
623
|
};
|
|
575
|
-
const bodyElement = bodyBlocks ? wrapArea("body", renderBlocks(bodyBlocks)) : null;
|
|
624
|
+
const bodyElement = bodyBlocks ? wrapArea("body", renderBlocks(bodyBlocks, { stickySelf: "section" })) : null;
|
|
576
625
|
const areaElements = {};
|
|
577
626
|
for (const [name, blocks] of Object.entries(areas)) {
|
|
578
627
|
areaElements[name] = wrapArea(name, renderBlocks(blocks));
|
|
@@ -587,7 +636,12 @@ function renderLayout(page, website) {
|
|
|
587
636
|
...areaElements
|
|
588
637
|
});
|
|
589
638
|
}
|
|
590
|
-
|
|
639
|
+
const zone = (name) => zoneProps(sticky[name], layers?.[name]);
|
|
640
|
+
return React.createElement(DefaultLayout, {
|
|
641
|
+
body: bodyElement,
|
|
642
|
+
...areaElements,
|
|
643
|
+
zones: { header: zone("header"), footer: zone("footer") }
|
|
644
|
+
});
|
|
591
645
|
}
|
|
592
646
|
function initPrerenderForLocale(content, foundation, locale, extensionsOrOptions, maybeOptions) {
|
|
593
647
|
const localeContent = sliceContentForLocale(content, locale);
|
|
@@ -620,7 +674,7 @@ function initPrerender(content, foundation, extensionsOrOptions, maybeOptions) {
|
|
|
620
674
|
(childBlock, index) => React.createElement(
|
|
621
675
|
React.Fragment,
|
|
622
676
|
{ key: childBlock.id || index },
|
|
623
|
-
renderBlock(childBlock, { as: wrapAs || null })
|
|
677
|
+
renderBlock(childBlock, { as: wrapAs || null, stickySelf: wrapAs ? "child" : false })
|
|
624
678
|
)
|
|
625
679
|
);
|
|
626
680
|
};
|