@uniweb/runtime 1.2.0 → 1.2.2

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
@@ -222,9 +222,12 @@ function siteUrl(url) {
222
222
  function withOpacity(color, opacity) {
223
223
  if (typeof color !== "string" || !color) return color;
224
224
  if (color.startsWith("#")) {
225
- const r = parseInt(color.slice(1, 3), 16);
226
- const g = parseInt(color.slice(3, 5), 16);
227
- const b = parseInt(color.slice(5, 7), 16);
225
+ let hex = color.slice(1);
226
+ if (hex.length === 3 || hex.length === 4) hex = [...hex].map((c) => c + c).join("");
227
+ if (!/^[0-9a-f]{6}([0-9a-f]{2})?$/i.test(hex)) return color;
228
+ const r = parseInt(hex.slice(0, 2), 16);
229
+ const g = parseInt(hex.slice(2, 4), 16);
230
+ const b = parseInt(hex.slice(4, 6), 16);
228
231
  return `rgba(${r}, ${g}, ${b}, ${opacity})`;
229
232
  }
230
233
  if (color.startsWith("rgb")) {
@@ -233,6 +236,76 @@ function withOpacity(color, opacity) {
233
236
  }
234
237
  return color;
235
238
  }
239
+ const h = React.createElement;
240
+ const FILL = { position: "absolute", inset: 0 };
241
+ function ColorLayer({ color }) {
242
+ if (!color) return null;
243
+ return h("div", { className: "background-color", style: { ...FILL, backgroundColor: color }, "aria-hidden": "true" });
244
+ }
245
+ function GradientLayer({ gradient }) {
246
+ if (!gradient) return null;
247
+ if (typeof gradient === "string") {
248
+ return h("div", { className: "background-gradient", style: { ...FILL, background: gradient }, "aria-hidden": "true" });
249
+ }
250
+ const start = gradient.start ?? "transparent";
251
+ const end = gradient.end ?? "transparent";
252
+ const startOpacity = gradient.startOpacity ?? 1;
253
+ const endOpacity = gradient.endOpacity ?? 1;
254
+ const startColor = startOpacity < 1 ? withOpacity(start, startOpacity) : start;
255
+ const endColor = endOpacity < 1 ? withOpacity(end, endOpacity) : end;
256
+ const background = `linear-gradient(${gradient.angle ?? 0}deg, ${startColor} ${gradient.startPosition ?? 0}%, ${endColor} ${gradient.endPosition ?? 100}%)`;
257
+ return h("div", { className: "background-gradient", style: { ...FILL, background }, "aria-hidden": "true" });
258
+ }
259
+ function ImageLayer({ image }) {
260
+ if (!image?.src) return null;
261
+ const style = {
262
+ ...FILL,
263
+ backgroundImage: `url(${siteUrl(image.src)})`,
264
+ backgroundPosition: image.position ?? "center",
265
+ backgroundSize: image.size ?? "cover",
266
+ backgroundRepeat: "no-repeat"
267
+ };
268
+ return h("div", { className: "background-image", style, "aria-hidden": "true" });
269
+ }
270
+ function VideoPoster({ video }) {
271
+ if (!video?.src || !video.poster) return null;
272
+ return h(ImageLayer, { image: { src: video.poster, size: "cover", position: "center" } });
273
+ }
274
+ function Overlay({ overlay }) {
275
+ if (!overlay?.enabled) return null;
276
+ const opacity = overlay.opacity ?? 0.5;
277
+ if (overlay.gradient) {
278
+ const g = overlay.gradient;
279
+ const background = `linear-gradient(${g.angle ?? 180}deg, ${g.start ?? "rgba(0,0,0,0.7)"} ${g.startPosition ?? 0}%, ${g.end ?? "rgba(0,0,0,0)"} ${g.endPosition ?? 100}%)`;
280
+ return h("div", {
281
+ className: "background-overlay background-overlay--gradient",
282
+ style: { ...FILL, background, opacity, pointerEvents: "none" },
283
+ "aria-hidden": "true"
284
+ });
285
+ }
286
+ const base = overlay.type === "light" ? "255, 255, 255" : "0, 0, 0";
287
+ return h("div", {
288
+ className: "background-overlay background-overlay--solid",
289
+ style: { ...FILL, backgroundColor: `rgba(${base}, ${opacity})`, pointerEvents: "none" },
290
+ "aria-hidden": "true"
291
+ });
292
+ }
293
+ function Background({ mode, color, gradient, image, video, overlay, className = "", Video = VideoPoster }) {
294
+ if (!mode) return null;
295
+ return h(
296
+ "div",
297
+ {
298
+ className: `background background--${mode} ${className}`.trim(),
299
+ style: { ...FILL, overflow: "hidden", zIndex: 0 },
300
+ "aria-hidden": "true"
301
+ },
302
+ mode === "color" ? h(ColorLayer, { color }) : null,
303
+ mode === "gradient" ? h(GradientLayer, { gradient }) : null,
304
+ mode === "image" ? h(ImageLayer, { image }) : null,
305
+ mode === "video" ? h(Video, { video }) : null,
306
+ h(Overlay, { overlay })
307
+ );
308
+ }
236
309
  function default404Html(basePath = "") {
237
310
  const homeHref = basePath ? `${basePath}/` : "/";
238
311
  return `<div class="page-not-found" style="min-height:80vh;display:flex;flex-direction:column;align-items:center;justify-content:center;padding:2rem;text-align:center"><h1 style="font-size:3rem;font-weight:bold;color:#1f2937;margin-bottom:1rem">404</h1><p style="color:#64748b;margin-bottom:2rem">Page not found</p><a href="${homeHref}" style="color:#3b82f6;text-decoration:underline">Go to homepage</a></div>`;
@@ -452,105 +525,7 @@ function getWrapperProps(block) {
452
525
  }
453
526
  function renderBackground(background) {
454
527
  if (!background?.mode) return null;
455
- const containerStyle = {
456
- position: "absolute",
457
- inset: "0",
458
- overflow: "hidden",
459
- zIndex: 0
460
- };
461
- const children = [];
462
- if (background.mode === "color" && background.color) {
463
- children.push(
464
- React.createElement("div", {
465
- key: "bg-color",
466
- className: "background-color",
467
- style: { position: "absolute", inset: "0", backgroundColor: background.color },
468
- "aria-hidden": "true"
469
- })
470
- );
471
- }
472
- if (background.mode === "gradient" && background.gradient) {
473
- const g = background.gradient;
474
- let bgValue;
475
- if (typeof g === "string") {
476
- bgValue = g;
477
- } else {
478
- const {
479
- start = "transparent",
480
- end = "transparent",
481
- angle = 0,
482
- startPosition = 0,
483
- endPosition = 100,
484
- startOpacity = 1,
485
- endOpacity = 1
486
- } = g;
487
- const startColor = startOpacity < 1 ? withOpacity(start, startOpacity) : start;
488
- const endColor = endOpacity < 1 ? withOpacity(end, endOpacity) : end;
489
- bgValue = `linear-gradient(${angle}deg, ${startColor} ${startPosition}%, ${endColor} ${endPosition}%)`;
490
- }
491
- children.push(
492
- React.createElement("div", {
493
- key: "bg-gradient",
494
- className: "background-gradient",
495
- style: { position: "absolute", inset: "0", background: bgValue },
496
- "aria-hidden": "true"
497
- })
498
- );
499
- }
500
- if (background.mode === "image" && background.image?.src) {
501
- const img = background.image;
502
- children.push(
503
- React.createElement("div", {
504
- key: "bg-image",
505
- className: "background-image",
506
- style: {
507
- position: "absolute",
508
- inset: "0",
509
- backgroundImage: `url(${siteUrl(img.src)})`,
510
- backgroundPosition: img.position || "center",
511
- backgroundSize: img.size || "cover",
512
- backgroundRepeat: "no-repeat"
513
- },
514
- "aria-hidden": "true"
515
- })
516
- );
517
- }
518
- if (background.overlay?.enabled) {
519
- const ov = background.overlay;
520
- let overlayStyle;
521
- if (ov.gradient) {
522
- const g = ov.gradient;
523
- overlayStyle = {
524
- position: "absolute",
525
- inset: "0",
526
- pointerEvents: "none",
527
- background: `linear-gradient(${g.angle || 180}deg, ${g.start || "rgba(0,0,0,0.7)"} ${g.startPosition || 0}%, ${g.end || "rgba(0,0,0,0)"} ${g.endPosition || 100}%)`,
528
- opacity: ov.opacity ?? 0.5
529
- };
530
- } else {
531
- const baseColor = ov.type === "light" ? "255, 255, 255" : "0, 0, 0";
532
- overlayStyle = {
533
- position: "absolute",
534
- inset: "0",
535
- pointerEvents: "none",
536
- backgroundColor: `rgba(${baseColor}, ${ov.opacity ?? 0.5})`
537
- };
538
- }
539
- children.push(
540
- React.createElement("div", {
541
- key: "bg-overlay",
542
- className: ov.gradient ? "background-overlay background-overlay--gradient" : "background-overlay background-overlay--solid",
543
- style: overlayStyle,
544
- "aria-hidden": "true"
545
- })
546
- );
547
- }
548
- if (children.length === 0) return null;
549
- return React.createElement("div", {
550
- className: `background background--${background.mode}`,
551
- style: containerStyle,
552
- "aria-hidden": "true"
553
- }, ...children);
528
+ return React.createElement(Background, background);
554
529
  }
555
530
  function renderBlock(block, { as = "section", stickySelf = false } = {}) {
556
531
  const Component = block.initComponent();
@@ -563,10 +538,13 @@ function renderBlock(block, { as = "section", stickySelf = false } = {}) {
563
538
  const meta = getComponentMeta(block.type);
564
539
  const entityStore = block.website?.entityStore;
565
540
  let entityData = null;
541
+ let pending = false;
566
542
  if (entityStore) {
567
543
  const resolved = entityStore.resolve(block, meta);
568
544
  if (resolved.status === "ready") entityData = resolved.data;
545
+ pending = resolved.status === "pending";
569
546
  }
547
+ block.dataLoading = pending;
570
548
  const prepared = prepareProps(block, meta, entityData);
571
549
  const params = prepared.params;
572
550
  const content = { ...prepared.content, ...block.properties };
@@ -691,9 +669,7 @@ function initPrerender(content, foundation, extensionsOrOptions, maybeOptions) {
691
669
  )
692
670
  );
693
671
  };
694
- uniweb.backgroundRenderer = function InlineBackground(background) {
695
- return renderBackground(background);
696
- };
672
+ uniweb.backgroundRenderer = Background;
697
673
  wireFoundationCapabilities(uniweb, foundation);
698
674
  ensureThemeCss(uniweb, foundation);
699
675
  const website = uniweb.activeWebsite;
@@ -1227,15 +1203,19 @@ async function loadPageData({ website, route, fetch: fetch2, dev = false, locale
1227
1203
  const key = deriveCacheKey$1(request);
1228
1204
  if (!entries.has(key)) entries.set(key, entry);
1229
1205
  };
1206
+ const answered = new DataStore();
1230
1207
  const recording = {
1231
1208
  peek: (request, ctx) => dispatcher.peek(request, ctx),
1232
- peekRecord: (id) => dispatcher.peekRecord(id),
1209
+ peekRecord: (id) => answered.getRecord(id),
1233
1210
  dispatch: async (request, ctx) => {
1234
1211
  if (prerender === "author" && request?.prerender === false) {
1235
1212
  record(request, { config: request, outcome: "skipped", data: null });
1236
1213
  return { data: null };
1237
1214
  }
1238
1215
  const result = await dispatcher.dispatch(request, ctx);
1216
+ if (!result?.error && result?.data != null) {
1217
+ answered.set(deriveCacheKey$1(request), result.meta ? { data: result.data, meta: result.meta } : { data: result.data });
1218
+ }
1239
1219
  record(request, result?.error ? { config: request, outcome: "failed", data: null, error: result.error } : { config: request, outcome: "fetched", data: result?.data ?? null, ...result?.meta ? { meta: result.meta } : {} });
1240
1220
  return result;
1241
1221
  }