@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 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 defaults = {};
304
- for (const name of areaNames) defaults[name] = 1;
305
- return explicit ? { ...defaults, ...explicit } : defaults;
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 (layer != null) {
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", null, header),
352
+ header && React.createElement("header", zone("header"), header),
325
353
  body && React.createElement("main", { style: GROW }, body),
326
- footer && React.createElement("footer", null, 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 layers = resolveLayoutLayers(areaNames, layoutMeta?.layers);
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
- return React.createElement(DefaultLayout, { body: bodyElement, ...areaElements });
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);