@reblu/site-blocks 0.15.0 → 0.17.0

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/index.cjs CHANGED
@@ -28,6 +28,7 @@ __export(src_exports, {
28
28
  CheckoutForm: () => CheckoutForm,
29
29
  CheckoutLoginPrompt: () => CheckoutLoginPrompt,
30
30
  CourseDescription: () => CourseDescription,
31
+ DATA_REQUEST_TYPES: () => import_site_contracts.DATA_REQUEST_TYPES,
31
32
  DEFAULT_INVOICE_COUNTRIES: () => DEFAULT_INVOICE_COUNTRIES,
32
33
  DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE: () => DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE,
33
34
  DEFAULT_SHOP_ERROR_MESSAGES: () => DEFAULT_SHOP_ERROR_MESSAGES,
@@ -13195,6 +13196,16 @@ var HTML_TO_DOM_OPTIONS = { lowerCaseAttributeNames: false };
13195
13196
  function parse3(html5, options) {
13196
13197
  return (0, import_html_react_parser.domToReact)((0, import_html_react_parser.htmlToDOM)(html5, HTML_TO_DOM_OPTIONS), options);
13197
13198
  }
13199
+ function isAllowedImage(src, prefixes) {
13200
+ if (!src) return false;
13201
+ let url;
13202
+ try {
13203
+ url = new URL(src);
13204
+ } catch {
13205
+ return false;
13206
+ }
13207
+ return prefixes.some((prefix) => url.href.startsWith(prefix));
13208
+ }
13198
13209
  var HEADING_CLASSES = {
13199
13210
  1: "text-3xl font-bold mt-8 mb-4 first:mt-0",
13200
13211
  2: "text-2xl font-bold mt-7 mb-3 first:mt-0",
@@ -13244,10 +13255,49 @@ function authorAttributes(el) {
13244
13255
  function isExternalHref(href) {
13245
13256
  return !!href && /^(https?:)?\/\//.test(href);
13246
13257
  }
13247
- function buildOptions(headingOffset) {
13258
+ function soleImage(p2) {
13259
+ let image = null;
13260
+ for (const child of p2.children) {
13261
+ if (child instanceof import_html_react_parser.Element) {
13262
+ if (child.name !== "img" || image) return null;
13263
+ image = child;
13264
+ } else if (child.type !== "text" || child.data?.trim()) {
13265
+ return null;
13266
+ }
13267
+ }
13268
+ return image;
13269
+ }
13270
+ function buildOptions(headingOffset, images) {
13271
+ const renderImage = (img) => {
13272
+ if (!images || !isAllowedImage(img.attribs.src, images.allowedUrlPrefixes)) return null;
13273
+ const image = { src: img.attribs.src, alt: img.attribs.alt ?? "" };
13274
+ if (images.render) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: images.render(image) });
13275
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
13276
+ "img",
13277
+ {
13278
+ src: image.src,
13279
+ alt: image.alt,
13280
+ loading: "lazy",
13281
+ decoding: "async",
13282
+ className: "rounded-lg w-full h-auto"
13283
+ }
13284
+ );
13285
+ };
13248
13286
  const options = {
13249
13287
  replace: (node) => {
13250
13288
  if (!(node instanceof import_html_react_parser.Element)) return void 0;
13289
+ if (images && node.name === "p") {
13290
+ const img = soleImage(node);
13291
+ if (img) {
13292
+ const rendered = renderImage(img);
13293
+ if (rendered === null) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
13294
+ const caption = img.attribs.title?.trim();
13295
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("figure", { className: "my-8", children: [
13296
+ rendered,
13297
+ caption ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("figcaption", { className: "mt-2 text-center text-sm text-muted-foreground", children: caption }) : null
13298
+ ] });
13299
+ }
13300
+ }
13251
13301
  const children2 = () => (0, import_html_react_parser.domToReact)(node.children, options);
13252
13302
  const { name, attribs } = node;
13253
13303
  const author = authorAttributes(node);
@@ -13306,6 +13356,7 @@ function buildOptions(headingOffset) {
13306
13356
  );
13307
13357
  }
13308
13358
  case "img":
13359
+ if (images) return renderImage(node) ?? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
13309
13360
  if (!attribs.src) return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, {});
13310
13361
  return (
13311
13362
  // Plain <img> keeps the block portable — a distributable can't assume a
@@ -13349,10 +13400,15 @@ function buildOptions(headingOffset) {
13349
13400
  };
13350
13401
  return options;
13351
13402
  }
13352
- function MarkdownRenderer({ content, className, headingOffset = 0 }) {
13403
+ function MarkdownRenderer({
13404
+ content,
13405
+ className,
13406
+ headingOffset = 0,
13407
+ images
13408
+ }) {
13353
13409
  const html5 = markdownToSafeHtml(content);
13354
13410
  if (!html5) return null;
13355
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: slotClassName("max-w-none", "", className), "data-slot": "markdown", children: parse3(html5, buildOptions(headingOffset)) });
13411
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: slotClassName("max-w-none", "", className), "data-slot": "markdown", children: parse3(html5, buildOptions(headingOffset, images)) });
13356
13412
  }
13357
13413
  function SafeHtml({ html: html5, className, headingOffset = 0 }) {
13358
13414
  if (!html5) return null;
@@ -13989,12 +14045,18 @@ function safeHref(url) {
13989
14045
  return null;
13990
14046
  }
13991
14047
  }
14048
+ function safeLogoSrc(url) {
14049
+ if (typeof url !== "string" || url === "") return null;
14050
+ if (url.startsWith("/")) return url.startsWith("//") || url.startsWith("/\\") ? null : url;
14051
+ return safeHref(url);
14052
+ }
13992
14053
  function BadgeContent({ badge, logoClassName }) {
13993
- if (badge.logoUrl) {
14054
+ const src = safeLogoSrc(badge.logoUrl);
14055
+ if (src) {
13994
14056
  return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
13995
14057
  "img",
13996
14058
  {
13997
- src: badge.logoUrl,
14059
+ src,
13998
14060
  alt: badge.name,
13999
14061
  loading: "lazy",
14000
14062
  className: (0, import_utils11.cn)("h-12 w-auto object-contain", logoClassName)
@@ -14007,11 +14069,14 @@ function TrustBadges({
14007
14069
  badges,
14008
14070
  headings,
14009
14071
  types = DEFAULT_TRUST_BADGE_TYPE_ORDER,
14072
+ heading,
14073
+ headingId = "trust-badges-heading",
14010
14074
  headingLevel = 2,
14011
14075
  newWindowLabel = "(se abre en una ventana nueva)",
14012
14076
  className,
14013
14077
  groupClassName,
14014
14078
  headingClassName,
14079
+ sectionHeadingClassName,
14015
14080
  listClassName,
14016
14081
  logoClassName
14017
14082
  }) {
@@ -14020,46 +14085,66 @@ function TrustBadges({
14020
14085
  const groups = types.flatMap((type) => {
14021
14086
  const items = usable.filter((b2) => b2.type === type).map((b2, index) => ({ b: b2, index })).sort((x2, y2) => (x2.b.sortOrder ?? 0) - (y2.b.sortOrder ?? 0) || x2.index - y2.index).map(({ b: b2 }) => b2);
14022
14087
  if (items.length === 0) return [];
14023
- const heading = headings && Object.prototype.hasOwnProperty.call(headings, type) ? headings[type] : DEFAULT_TRUST_BADGE_HEADINGS[type];
14024
- return [{ type, heading, items }];
14088
+ const groupHeading = headings && Object.prototype.hasOwnProperty.call(headings, type) ? headings[type] : DEFAULT_TRUST_BADGE_HEADINGS[type];
14089
+ return [{ type, groupHeading, items }];
14025
14090
  });
14026
14091
  if (groups.length === 0) return null;
14027
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { "data-slot": "trust-badges", className: (0, import_utils11.cn)("space-y-6", className), children: groups.map(({ type, heading, items }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
14092
+ const hasHeading = heading !== void 0 && heading !== null && heading !== "";
14093
+ const groupHeadingLevel = hasHeading ? nextHeadingLevel(headingLevel) : headingLevel;
14094
+ const content = groups.map(({ type, groupHeading, items }) => /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
14028
14095
  "div",
14029
14096
  {
14030
14097
  "data-slot": "trust-badge-group",
14031
14098
  "data-type": type,
14032
14099
  className: (0, import_utils11.cn)("space-y-3", groupClassName),
14033
14100
  children: [
14034
- heading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
14101
+ groupHeading ? /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
14035
14102
  Heading,
14036
14103
  {
14037
- level: headingLevel,
14038
- className: (0, import_utils11.cn)("text-sm font-semibold uppercase tracking-widest", headingClassName),
14039
- children: heading
14104
+ level: groupHeadingLevel,
14105
+ className: slotClassName(
14106
+ "",
14107
+ "text-sm font-semibold uppercase tracking-widest",
14108
+ headingClassName
14109
+ ),
14110
+ children: groupHeading
14040
14111
  }
14041
14112
  ) : null,
14042
14113
  /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("ul", { className: (0, import_utils11.cn)("flex flex-wrap items-center gap-6", listClassName), children: items.map((badge) => {
14043
14114
  const href = safeHref(badge.url);
14044
- return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: href ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
14045
- "a",
14046
- {
14047
- href,
14048
- target: "_blank",
14049
- rel: "noopener noreferrer",
14050
- className: "inline-flex",
14051
- children: [
14052
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BadgeContent, { badge, logoClassName }),
14053
- " ",
14054
- /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "sr-only", children: newWindowLabel })
14055
- ]
14056
- }
14057
- ) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BadgeContent, { badge, logoClassName }) }, badge.id);
14115
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("li", { children: href ? /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)("a", { href, target: "_blank", rel: "noopener noreferrer", className: "inline-flex", children: [
14116
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BadgeContent, { badge, logoClassName }),
14117
+ " ",
14118
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("span", { className: "sr-only", children: newWindowLabel })
14119
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(BadgeContent, { badge, logoClassName }) }, badge.id);
14058
14120
  }) })
14059
14121
  ]
14060
14122
  },
14061
14123
  type
14062
- )) });
14124
+ ));
14125
+ if (!hasHeading) {
14126
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsx)("div", { "data-slot": "trust-badges", className: (0, import_utils11.cn)("space-y-6", className), children: content });
14127
+ }
14128
+ const Tag = `h${headingLevel}`;
14129
+ return /* @__PURE__ */ (0, import_jsx_runtime12.jsxs)(
14130
+ "section",
14131
+ {
14132
+ "data-slot": "trust-badges",
14133
+ "aria-labelledby": headingId,
14134
+ className: (0, import_utils11.cn)("space-y-6", className),
14135
+ children: [
14136
+ /* @__PURE__ */ (0, import_jsx_runtime12.jsx)(
14137
+ Tag,
14138
+ {
14139
+ id: headingId,
14140
+ className: slotClassName("", "text-xl font-semibold", sectionHeadingClassName),
14141
+ children: heading
14142
+ }
14143
+ ),
14144
+ content
14145
+ ]
14146
+ }
14147
+ );
14063
14148
  }
14064
14149
 
14065
14150
  // src/components/page-blocks.tsx
@@ -15490,6 +15575,9 @@ function FullInvoiceFields({
15490
15575
  ] })
15491
15576
  ] });
15492
15577
  }
15578
+
15579
+ // src/index.ts
15580
+ var import_site_contracts = require("@reblu/site-contracts");
15493
15581
  // Annotate the CommonJS export names for ESM import in node:
15494
15582
  0 && (module.exports = {
15495
15583
  ALLOWED_YOUTUBE_HOSTS,
@@ -15500,6 +15588,7 @@ function FullInvoiceFields({
15500
15588
  CheckoutForm,
15501
15589
  CheckoutLoginPrompt,
15502
15590
  CourseDescription,
15591
+ DATA_REQUEST_TYPES,
15503
15592
  DEFAULT_INVOICE_COUNTRIES,
15504
15593
  DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE,
15505
15594
  DEFAULT_SHOP_ERROR_MESSAGES,