@reblu/site-blocks 0.9.0 → 0.10.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/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # @reblu/site-blocks
2
2
 
3
+ ## 0.10.0
4
+
5
+ ### Minor Changes
6
+
7
+ - e78229a: REB-853 — rename the `Specialty` organism to the niche-agnostic `ParentPage` (a page with a linked grid of child pages), with props `childPages`, `childPageHref` and `childPagesLabel`.
8
+
9
+ `Specialty` / `SpecialtyProps` and the props `treatments`, `treatmentHref` and `treatmentsLabel` remain as `@deprecated` aliases — `Specialty` is the same reference as `ParentPage`, so rendering is unchanged. They will be removed in the next major, not before 2027-03-31.
10
+
3
11
  ## 0.9.0
4
12
 
5
13
  ### Minor Changes
package/README.md CHANGED
@@ -15,7 +15,7 @@ a different-looking site for every tenant, with zero forks.
15
15
  | `readingTime`, `formatPrice`, `buildShareUrls`, `markdownToSafeHtml` | `.` | Pure, framework-agnostic helpers (RSC-safe). |
16
16
  | `sanitizeHtml` | `.` | Sanitises an HTML string before `dangerouslySetInnerHTML` — the **HTML boundary**. See "Security boundaries" below. |
17
17
  | `MarkdownRenderer` | `.` | Canonical Blog renderer: `marked` → **hast-util-sanitize** (XSS) → component map, with a YouTube-domain allowlist. RSC-safe. |
18
- | `Treatment`, `Specialty`, `ProfileCard`, `ProductCard` | `.` | Presentational organisms over the SITE API contracts. RSC-safe. |
18
+ | `Treatment`, `ParentPage`, `ProfileCard`, `ProductCard` | `.` | Presentational organisms over the SITE API contracts. RSC-safe. `Specialty`: deprecated alias, see below. |
19
19
  | `ShopFilters` | `.` | Plug-and-play shop filter chrome over `GET /api/site/shop/facets`. RSC-safe. See "Shop filters" below. |
20
20
  | `CartLineList`, `CartSummary`, `AddedToCartToast`, `CheckoutLoginPrompt`, `CheckoutForm`, `OrderConfirmation` | `.` | Cart & checkout organisms. RSC-safe by construction. See "Cart & checkout" below. |
21
21
  | `PageBlocks`, `FaqAccordion` | `.` | Registry-block renderer (`PageDetail.blocks`) and native `<details>` FAQ. Server Components. See "Page blocks" below. |
@@ -380,6 +380,43 @@ Every title/description is overridable via `labels` (see
380
380
  "`useShopOrderStatus` — the order-confirmation flow" for the full wiring
381
381
  recipe.
382
382
 
383
+ ## `ParentPage` (formerly `Specialty`)
384
+
385
+ `ParentPage` renders a page that groups other pages: the hero and content
386
+ sections of a `PageDetail`, then an optional linked grid of its child pages
387
+ (`PageListItem[]` — cover image, title, excerpt).
388
+
389
+ ```tsx
390
+ import { ParentPage } from '@reblu/site-blocks'
391
+
392
+ export function ServicesHub({ page, services }) {
393
+ return (
394
+ <ParentPage
395
+ page={page}
396
+ childPages={services}
397
+ childPageHref={(slug) => `/services/${slug}`}
398
+ childPagesLabel='Services'
399
+ />
400
+ )
401
+ }
402
+ ```
403
+
404
+ **Deprecated (REB-853) — removed in the next major, not before 2027-03-31:**
405
+
406
+ | Deprecated | Use instead |
407
+ | ----------------- | ----------------- |
408
+ | `Specialty` | `ParentPage` |
409
+ | `SpecialtyProps` | `ParentPageProps` |
410
+ | `treatments` | `childPages` |
411
+ | `treatmentHref` | `childPageHref` |
412
+ | `treatmentsLabel` | `childPagesLabel` |
413
+
414
+ `Specialty` is the same component reference as `ParentPage`, not a copy, so
415
+ existing code renders exactly as before. When a new prop and its deprecated
416
+ counterpart are both passed, the new one wins. The default grid heading stays
417
+ `"Treatments"` and the root keeps `data-slot="specialty"` until that major, so
418
+ the rename changes no markup — pass `childPagesLabel` to set your own heading.
419
+
383
420
  ## Page blocks
384
421
 
385
422
  `PageBlocks` renders a page's registry blocks (`PageDetail.blocks` from
package/dist/index.cjs CHANGED
@@ -33,6 +33,7 @@ __export(src_exports, {
33
33
  MarkdownRenderer: () => MarkdownRenderer,
34
34
  OrderConfirmation: () => OrderConfirmation,
35
35
  PageBlocks: () => PageBlocks,
36
+ ParentPage: () => ParentPage,
36
37
  ProductCard: () => ProductCard,
37
38
  ProfileCard: () => ProfileCard,
38
39
  SafeHtml: () => SafeHtml,
@@ -13371,25 +13372,32 @@ function Treatment({ page, className }) {
13371
13372
  ] });
13372
13373
  }
13373
13374
 
13374
- // src/components/specialty.tsx
13375
+ // src/components/parent-page.tsx
13375
13376
  var import_utils4 = require("@reblu/site-ui/utils");
13376
13377
  var import_jsx_runtime4 = require("react/jsx-runtime");
13377
- function Specialty({
13378
+ var defaultChildPageHref = (slug) => `/${slug}`;
13379
+ function ParentPage({
13378
13380
  page,
13379
- treatments = [],
13380
- treatmentHref = (slug) => `/${slug}`,
13381
- treatmentsLabel = "Treatments",
13381
+ childPages,
13382
+ childPageHref,
13383
+ childPagesLabel,
13384
+ treatments,
13385
+ treatmentHref,
13386
+ treatmentsLabel,
13382
13387
  className
13383
13388
  }) {
13389
+ const pages = childPages ?? treatments ?? [];
13390
+ const hrefFor = childPageHref ?? treatmentHref ?? defaultChildPageHref;
13391
+ const label = childPagesLabel ?? treatmentsLabel ?? "Treatments";
13384
13392
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("article", { className: (0, import_utils4.cn)("space-y-12", className), "data-slot": "specialty", children: [
13385
13393
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PageHero, { page }),
13386
13394
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(PageSectionList, { sections: page.sections }),
13387
- treatments.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "space-y-6", children: [
13388
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "text-2xl font-bold", children: treatmentsLabel }),
13389
- /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "grid list-none grid-cols-1 gap-6 p-0 sm:grid-cols-2 lg:grid-cols-3", children: treatments.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
13395
+ pages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("section", { className: "space-y-6", children: [
13396
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("h2", { className: "text-2xl font-bold", children: label }),
13397
+ /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("ul", { className: "grid list-none grid-cols-1 gap-6 p-0 sm:grid-cols-2 lg:grid-cols-3", children: pages.map((t) => /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("li", { children: /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
13390
13398
  "a",
13391
13399
  {
13392
- href: treatmentHref(t.slug),
13400
+ href: hrefFor(t.slug),
13393
13401
  className: "group flex h-full flex-col overflow-hidden rounded-lg border bg-card transition-shadow hover:shadow-lg",
13394
13402
  children: [
13395
13403
  t.coverImageUrl && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "relative aspect-video overflow-hidden bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
@@ -13412,6 +13420,9 @@ function Specialty({
13412
13420
  ] });
13413
13421
  }
13414
13422
 
13423
+ // src/components/specialty.tsx
13424
+ var Specialty = ParentPage;
13425
+
13415
13426
  // src/components/profile-card.tsx
13416
13427
  var import_utils5 = require("@reblu/site-ui/utils");
13417
13428
  var import_jsx_runtime5 = require("react/jsx-runtime");
@@ -14640,6 +14651,7 @@ function OrderConfirmation({
14640
14651
  MarkdownRenderer,
14641
14652
  OrderConfirmation,
14642
14653
  PageBlocks,
14654
+ ParentPage,
14643
14655
  ProductCard,
14644
14656
  ProfileCard,
14645
14657
  SafeHtml,