@reblu/site-blocks 0.15.0 → 0.16.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.d.cts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ShopErrorCode, PageDetail, PageListItem, ShopProductListItem, ShopProductTrustIcon, ShopProductTrustItem, TrustBadgeType, TrustBadge, BlockType, PageBlock, ResolvedEmbed, ShopFacets, ShopOrder, ShopBillingInput, ShopCheckoutInput, ShopOrderInvoice } from '@reblu/site-contracts';
2
+ export { DATA_REQUEST_TYPES } from '@reblu/site-contracts';
2
3
  import { FaqItem } from './seo.cjs';
3
4
  export { FaqPageJsonLd, MarkdownToPlainTextOptions, buildFaqPageJsonLd, collectFaqItems, markdownToPlainText } from './seo.cjs';
4
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -489,8 +490,14 @@ declare function FaqAccordion({ items, heading, headingLevel, questionHeadingLev
489
490
  * - Badges are grouped by type (in {@link DEFAULT_TRUST_BADGE_TYPE_ORDER}, or
490
491
  * the `types` prop), each group under an overridable heading, and ordered by
491
492
  * `sortOrder` inside it.
492
- * - A logo is an `<img>` whose `alt` is the badge name; a badge without a logo
493
+ * - A logo is an `<img>` whose `alt` is the badge name, rendered only when its
494
+ * URL is http(s) or root-relative (REB-1002); a badge without a usable logo
493
495
  * shows its name as text.
496
+ * - `heading` (optional) wraps everything in a `<section>` labelled by it
497
+ * (`headingId`), with the group headings one level below — so a SITE keeps
498
+ * its `<section aria-labelledby>` landmark (REB-1002).
499
+ * - Consumer classNames follow the REB-997 slot rule: `headingClassName` and
500
+ * `sectionHeadingClassName` REPLACE that heading's default typography.
494
501
  * - `url` links only when it is http(s), in a new window with
495
502
  * `rel="noopener noreferrer"` and a visually hidden new-window hint.
496
503
  */
@@ -505,7 +512,18 @@ interface TrustBadgesProps {
505
512
  headings?: Partial<Record<TrustBadgeType, string | null>>;
506
513
  /** Which groups to render, in this order. Defaults to every type. */
507
514
  types?: readonly TrustBadgeType[];
508
- /** Heading level of each group title. Defaults to `2`. */
515
+ /**
516
+ * Optional section title, e.g. «Nos avalan». When given, the root is a
517
+ * `<section aria-labelledby={headingId}>` and the group headings render one
518
+ * level below `headingLevel`.
519
+ */
520
+ heading?: ReactNode;
521
+ /** `id` of the section heading (the section's `aria-labelledby`). @default 'trust-badges-heading' */
522
+ headingId?: string;
523
+ /**
524
+ * Heading level of the section title when `heading` is given, otherwise of
525
+ * each group title. Defaults to `2`.
526
+ */
509
527
  headingLevel?: HeadingLevel;
510
528
  /** Visually hidden text appended to linked badges. */
511
529
  newWindowLabel?: string;
@@ -513,14 +531,22 @@ interface TrustBadgesProps {
513
531
  className?: string;
514
532
  /** Classes for each group. */
515
533
  groupClassName?: string;
516
- /** Classes for each group heading. */
534
+ /**
535
+ * Classes for each group heading. When given, they REPLACE the default
536
+ * `text-sm font-semibold uppercase tracking-widest` (REB-997).
537
+ */
517
538
  headingClassName?: string;
539
+ /**
540
+ * Classes for the section heading (only with `heading`). When given, they
541
+ * REPLACE the default `text-xl font-semibold` (REB-997).
542
+ */
543
+ sectionHeadingClassName?: string;
518
544
  /** Classes for each group's `<ul>`. */
519
545
  listClassName?: string;
520
546
  /** Classes for each logo `<img>`. */
521
547
  logoClassName?: string;
522
548
  }
523
- declare function TrustBadges({ badges, headings, types, headingLevel, newWindowLabel, className, groupClassName, headingClassName, listClassName, logoClassName, }: TrustBadgesProps): react_jsx_runtime.JSX.Element | null;
549
+ declare function TrustBadges({ badges, headings, types, heading, headingId, headingLevel, newWindowLabel, className, groupClassName, headingClassName, sectionHeadingClassName, listClassName, logoClassName, }: TrustBadgesProps): react_jsx_runtime.JSX.Element | null;
524
550
 
525
551
  /**
526
552
  * REB-850 — `PageBlocks`: the shared renderer for a page's registry blocks
package/dist/index.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { ShopErrorCode, PageDetail, PageListItem, ShopProductListItem, ShopProductTrustIcon, ShopProductTrustItem, TrustBadgeType, TrustBadge, BlockType, PageBlock, ResolvedEmbed, ShopFacets, ShopOrder, ShopBillingInput, ShopCheckoutInput, ShopOrderInvoice } from '@reblu/site-contracts';
2
+ export { DATA_REQUEST_TYPES } from '@reblu/site-contracts';
2
3
  import { FaqItem } from './seo.js';
3
4
  export { FaqPageJsonLd, MarkdownToPlainTextOptions, buildFaqPageJsonLd, collectFaqItems, markdownToPlainText } from './seo.js';
4
5
  import * as react_jsx_runtime from 'react/jsx-runtime';
@@ -489,8 +490,14 @@ declare function FaqAccordion({ items, heading, headingLevel, questionHeadingLev
489
490
  * - Badges are grouped by type (in {@link DEFAULT_TRUST_BADGE_TYPE_ORDER}, or
490
491
  * the `types` prop), each group under an overridable heading, and ordered by
491
492
  * `sortOrder` inside it.
492
- * - A logo is an `<img>` whose `alt` is the badge name; a badge without a logo
493
+ * - A logo is an `<img>` whose `alt` is the badge name, rendered only when its
494
+ * URL is http(s) or root-relative (REB-1002); a badge without a usable logo
493
495
  * shows its name as text.
496
+ * - `heading` (optional) wraps everything in a `<section>` labelled by it
497
+ * (`headingId`), with the group headings one level below — so a SITE keeps
498
+ * its `<section aria-labelledby>` landmark (REB-1002).
499
+ * - Consumer classNames follow the REB-997 slot rule: `headingClassName` and
500
+ * `sectionHeadingClassName` REPLACE that heading's default typography.
494
501
  * - `url` links only when it is http(s), in a new window with
495
502
  * `rel="noopener noreferrer"` and a visually hidden new-window hint.
496
503
  */
@@ -505,7 +512,18 @@ interface TrustBadgesProps {
505
512
  headings?: Partial<Record<TrustBadgeType, string | null>>;
506
513
  /** Which groups to render, in this order. Defaults to every type. */
507
514
  types?: readonly TrustBadgeType[];
508
- /** Heading level of each group title. Defaults to `2`. */
515
+ /**
516
+ * Optional section title, e.g. «Nos avalan». When given, the root is a
517
+ * `<section aria-labelledby={headingId}>` and the group headings render one
518
+ * level below `headingLevel`.
519
+ */
520
+ heading?: ReactNode;
521
+ /** `id` of the section heading (the section's `aria-labelledby`). @default 'trust-badges-heading' */
522
+ headingId?: string;
523
+ /**
524
+ * Heading level of the section title when `heading` is given, otherwise of
525
+ * each group title. Defaults to `2`.
526
+ */
509
527
  headingLevel?: HeadingLevel;
510
528
  /** Visually hidden text appended to linked badges. */
511
529
  newWindowLabel?: string;
@@ -513,14 +531,22 @@ interface TrustBadgesProps {
513
531
  className?: string;
514
532
  /** Classes for each group. */
515
533
  groupClassName?: string;
516
- /** Classes for each group heading. */
534
+ /**
535
+ * Classes for each group heading. When given, they REPLACE the default
536
+ * `text-sm font-semibold uppercase tracking-widest` (REB-997).
537
+ */
517
538
  headingClassName?: string;
539
+ /**
540
+ * Classes for the section heading (only with `heading`). When given, they
541
+ * REPLACE the default `text-xl font-semibold` (REB-997).
542
+ */
543
+ sectionHeadingClassName?: string;
518
544
  /** Classes for each group's `<ul>`. */
519
545
  listClassName?: string;
520
546
  /** Classes for each logo `<img>`. */
521
547
  logoClassName?: string;
522
548
  }
523
- declare function TrustBadges({ badges, headings, types, headingLevel, newWindowLabel, className, groupClassName, headingClassName, listClassName, logoClassName, }: TrustBadgesProps): react_jsx_runtime.JSX.Element | null;
549
+ declare function TrustBadges({ badges, headings, types, heading, headingId, headingLevel, newWindowLabel, className, groupClassName, headingClassName, sectionHeadingClassName, listClassName, logoClassName, }: TrustBadgesProps): react_jsx_runtime.JSX.Element | null;
524
550
 
525
551
  /**
526
552
  * REB-850 — `PageBlocks`: the shared renderer for a page's registry blocks
package/dist/index.js CHANGED
@@ -13925,14 +13925,20 @@ function safeHref(url) {
13925
13925
  return null;
13926
13926
  }
13927
13927
  }
13928
+ function safeLogoSrc(url) {
13929
+ if (typeof url !== "string" || url === "") return null;
13930
+ if (url.startsWith("/")) return url.startsWith("//") || url.startsWith("/\\") ? null : url;
13931
+ return safeHref(url);
13932
+ }
13928
13933
  function BadgeContent({ badge, logoClassName }) {
13929
- if (badge.logoUrl) {
13934
+ const src = safeLogoSrc(badge.logoUrl);
13935
+ if (src) {
13930
13936
  return (
13931
13937
  // eslint-disable-next-line @next/next/no-img-element -- framework-agnostic SDK; the SITE owns image optimisation
13932
13938
  /* @__PURE__ */ jsx12(
13933
13939
  "img",
13934
13940
  {
13935
- src: badge.logoUrl,
13941
+ src,
13936
13942
  alt: badge.name,
13937
13943
  loading: "lazy",
13938
13944
  className: cn9("h-12 w-auto object-contain", logoClassName)
@@ -13946,11 +13952,14 @@ function TrustBadges({
13946
13952
  badges,
13947
13953
  headings,
13948
13954
  types = DEFAULT_TRUST_BADGE_TYPE_ORDER,
13955
+ heading,
13956
+ headingId = "trust-badges-heading",
13949
13957
  headingLevel = 2,
13950
13958
  newWindowLabel = "(se abre en una ventana nueva)",
13951
13959
  className,
13952
13960
  groupClassName,
13953
13961
  headingClassName,
13962
+ sectionHeadingClassName,
13954
13963
  listClassName,
13955
13964
  logoClassName
13956
13965
  }) {
@@ -13959,46 +13968,66 @@ function TrustBadges({
13959
13968
  const groups = types.flatMap((type) => {
13960
13969
  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);
13961
13970
  if (items.length === 0) return [];
13962
- const heading = headings && Object.prototype.hasOwnProperty.call(headings, type) ? headings[type] : DEFAULT_TRUST_BADGE_HEADINGS[type];
13963
- return [{ type, heading, items }];
13971
+ const groupHeading = headings && Object.prototype.hasOwnProperty.call(headings, type) ? headings[type] : DEFAULT_TRUST_BADGE_HEADINGS[type];
13972
+ return [{ type, groupHeading, items }];
13964
13973
  });
13965
13974
  if (groups.length === 0) return null;
13966
- return /* @__PURE__ */ jsx12("div", { "data-slot": "trust-badges", className: cn9("space-y-6", className), children: groups.map(({ type, heading, items }) => /* @__PURE__ */ jsxs10(
13975
+ const hasHeading = heading !== void 0 && heading !== null && heading !== "";
13976
+ const groupHeadingLevel = hasHeading ? nextHeadingLevel(headingLevel) : headingLevel;
13977
+ const content = groups.map(({ type, groupHeading, items }) => /* @__PURE__ */ jsxs10(
13967
13978
  "div",
13968
13979
  {
13969
13980
  "data-slot": "trust-badge-group",
13970
13981
  "data-type": type,
13971
13982
  className: cn9("space-y-3", groupClassName),
13972
13983
  children: [
13973
- heading ? /* @__PURE__ */ jsx12(
13984
+ groupHeading ? /* @__PURE__ */ jsx12(
13974
13985
  Heading,
13975
13986
  {
13976
- level: headingLevel,
13977
- className: cn9("text-sm font-semibold uppercase tracking-widest", headingClassName),
13978
- children: heading
13987
+ level: groupHeadingLevel,
13988
+ className: slotClassName(
13989
+ "",
13990
+ "text-sm font-semibold uppercase tracking-widest",
13991
+ headingClassName
13992
+ ),
13993
+ children: groupHeading
13979
13994
  }
13980
13995
  ) : null,
13981
13996
  /* @__PURE__ */ jsx12("ul", { className: cn9("flex flex-wrap items-center gap-6", listClassName), children: items.map((badge) => {
13982
13997
  const href = safeHref(badge.url);
13983
- return /* @__PURE__ */ jsx12("li", { children: href ? /* @__PURE__ */ jsxs10(
13984
- "a",
13985
- {
13986
- href,
13987
- target: "_blank",
13988
- rel: "noopener noreferrer",
13989
- className: "inline-flex",
13990
- children: [
13991
- /* @__PURE__ */ jsx12(BadgeContent, { badge, logoClassName }),
13992
- " ",
13993
- /* @__PURE__ */ jsx12("span", { className: "sr-only", children: newWindowLabel })
13994
- ]
13995
- }
13996
- ) : /* @__PURE__ */ jsx12(BadgeContent, { badge, logoClassName }) }, badge.id);
13998
+ return /* @__PURE__ */ jsx12("li", { children: href ? /* @__PURE__ */ jsxs10("a", { href, target: "_blank", rel: "noopener noreferrer", className: "inline-flex", children: [
13999
+ /* @__PURE__ */ jsx12(BadgeContent, { badge, logoClassName }),
14000
+ " ",
14001
+ /* @__PURE__ */ jsx12("span", { className: "sr-only", children: newWindowLabel })
14002
+ ] }) : /* @__PURE__ */ jsx12(BadgeContent, { badge, logoClassName }) }, badge.id);
13997
14003
  }) })
13998
14004
  ]
13999
14005
  },
14000
14006
  type
14001
- )) });
14007
+ ));
14008
+ if (!hasHeading) {
14009
+ return /* @__PURE__ */ jsx12("div", { "data-slot": "trust-badges", className: cn9("space-y-6", className), children: content });
14010
+ }
14011
+ const Tag = `h${headingLevel}`;
14012
+ return /* @__PURE__ */ jsxs10(
14013
+ "section",
14014
+ {
14015
+ "data-slot": "trust-badges",
14016
+ "aria-labelledby": headingId,
14017
+ className: cn9("space-y-6", className),
14018
+ children: [
14019
+ /* @__PURE__ */ jsx12(
14020
+ Tag,
14021
+ {
14022
+ id: headingId,
14023
+ className: slotClassName("", "text-xl font-semibold", sectionHeadingClassName),
14024
+ children: heading
14025
+ }
14026
+ ),
14027
+ content
14028
+ ]
14029
+ }
14030
+ );
14002
14031
  }
14003
14032
 
14004
14033
  // src/components/page-blocks.tsx
@@ -15427,6 +15456,9 @@ function FullInvoiceFields({
15427
15456
  ] })
15428
15457
  ] });
15429
15458
  }
15459
+
15460
+ // src/index.ts
15461
+ import { DATA_REQUEST_TYPES } from "@reblu/site-contracts";
15430
15462
  export {
15431
15463
  ALLOWED_YOUTUBE_HOSTS,
15432
15464
  AddedToCartToast,
@@ -15436,6 +15468,7 @@ export {
15436
15468
  CheckoutForm,
15437
15469
  CheckoutLoginPrompt,
15438
15470
  CourseDescription,
15471
+ DATA_REQUEST_TYPES,
15439
15472
  DEFAULT_INVOICE_COUNTRIES,
15440
15473
  DEFAULT_SHOP_ERROR_FALLBACK_MESSAGE,
15441
15474
  DEFAULT_SHOP_ERROR_MESSAGES,