@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 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 defaults = {};
304
- for (const name of areaNames) defaults[name] = 1;
305
- return explicit ? { ...defaults, ...explicit } : defaults;
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 (layer != null) {
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 layers = resolveLayoutLayers(areaNames, layoutMeta?.layers);
618
+ const sticky = layoutStickiness(areas);
619
+ const layers = resolveLayoutLayers(areaNames, layoutMeta?.layers, sticky);
571
620
  const wrapArea = (name, element) => {
572
- const style = areaWrapperStyle(name, transitions, layers);
573
- return style ? React.createElement("div", { style }, element) : element;
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
- return React.createElement(DefaultLayout, { body: bodyElement, ...areaElements });
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
  };