/** * Public types for the Prenta section renderer. * * A page/post's renderable content is the ordered `PageSection[]` stored on a * document's `data.sections` JSON (the canonical content contract — see * ADR 0001). This package turns that array into server-rendered React. * * The wire shape here is intentionally permissive (`content`/`settings` are * open records) because it comes off the network as JSON. The authoritative * field schemas live in `@prenta/core/page-sections`. */ import type { ReactNode } from 'react'; import type { PublicForm } from '@prenta/core'; import type { LcpController } from './lcp.js'; /** A single section as delivered by the CMS (`data.sections[]`). */ export interface PublicSection { id: string; /** Keys into the section registry; unknown types render via the fallback. */ sectionType: string; name?: string; /** Hidden sections are skipped by ``. Absent means visible. */ visible?: boolean; content?: Record; settings?: Record; } /** * Per-request context for post-oriented sections (article body, author bio, * related posts) and the post header. Supplied by the consumer's data layer; * never trusted for HTML unless sanitized (see {@link RenderOptions}). */ export interface PostContext { title?: string; excerpt?: string; /** Post body HTML — used by the `article-body` section in `source: 'field'` mode. */ body?: string; featuredImageUrl?: string; /** Intrinsic featured-image dimensions (from `/resolve` enrichment) — avoids CLS. */ featuredImageWidth?: number | null; featuredImageHeight?: number | null; publishDate?: string | null; category?: string; author?: { name?: string; bio?: string; avatarUrl?: string; }; relatedPosts?: Array<{ title: string; url?: string; excerpt?: string; }>; } /** * Options threaded to every section renderer. * * `sanitizeHtml` is applied to author-supplied HTML (e.g. the `article-body` * section) before it is injected via `dangerouslySetInnerHTML`. * * SECURITY: the default is the identity function because Prenta sanitizes * rich text on **write** (cms-core `sanitizeHtml`, the allow-list source of * truth). If you render HTML from an untrusted or third-party source, OR want * defense-in-depth, pass a sanitizer here — e.g. * `import { sanitizeHtml } from '@prenta/core'` in a server * component, or any DOMPurify-style function. */ /** Props passed to a {@link RenderImage} renderer. */ export interface RenderImageProps { src: string; alt: string; /** Intrinsic dimensions from the media library, when known (helps avoid CLS). */ width?: number | null; height?: number | null; className?: string; /** Above-the-fold images opt out of lazy-loading. */ priority?: boolean; /** Responsive `sizes` hint, forwarded to image components that support it. */ sizes?: string; } /** * Pluggable image renderer. The default emits a plain `` with native * lazy-loading; a Next.js consumer can pass a `next/image`-backed renderer to * get responsive `srcset` + optimization without coupling this package to Next. */ export type RenderImage = (props: RenderImageProps) => ReactNode; export interface RenderOptions { sanitizeHtml?: (html: string) => string; /** * Origin of the CMS API used by data-driven sections (e.g. the `form` * section's ``). Defaults to `''` (same-origin relative URLs), * correct for a Next.js app mounting the Prenta API at `/api/cms`. */ baseUrl?: string; /** Custom image renderer (e.g. `next/image`). Defaults to a lazy ``. */ renderImage?: RenderImage; /** Shared LCP (priority-image) budget. Pass ONE controller to both * `PostHeader` and `Sections` so a post's featured image and its body * sections compete for the same single priority slot. When omitted, each * component creates its own (correct when only one is rendered). */ lcp?: LcpController; /** * Pre-fetched public form schemas keyed by slug. When a `form` section * references a slug present here, the server renders {@link PrentaFormHtml} * (zero-JS + WebMCP) instead of the client {@link PrentaForm} island. */ prefetchedForms?: Record; } /** Internal: options with all defaults resolved. */ export interface ResolvedRenderOptions { sanitizeHtml: (html: string) => string; baseUrl: string; renderImage: RenderImage; lcp: LcpController; prefetchedForms: Record; } /** Props every section renderer receives. */ export interface SectionRendererProps { section: PublicSection; ctx?: PostContext; options: ResolvedRenderOptions; } /** * A section renderer: maps one section's content to React. Renderers must be * SSR-safe (no browser-only APIs at module/render time) so they work in React * Server Components. */ export type SectionRenderer = (props: SectionRendererProps) => ReactNode; /** A map of section-type id → renderer (used for overrides + the defaults). */ export type SectionRendererMap = Record; //# sourceMappingURL=types.d.ts.map