components/elements/registry.jsjavascript
/**
 * @module components/elements/registry
 * @description Single registration point for all content-block elements.
 * Each element folder exports its full definition
 * `{ type, region, required, properties, component, adapter }` from its
 * index.js (block contract in schema.js, component + props adapter next to
 * it). Adding a new element = add the folder, import it here - rendering
 * (ComponentRenderer), layout regions (SlidePage) and content validation
 * (scripts/validate-content.mjs via elements/schemas.js) all pick it up
 * from the registry.
 */

import storyTitle from "./StoryTitle";
import headline from "./Headline";
import disclaimer from "./Disclaimer";
import buttonList from "./ButtonList";
import buttonGrid from "./ButtonGrid";
import selectWidget from "./SelectWidget";
import quoteList from "./QuoteList";
import cardGrid from "./CardGrid";
import institutionBadge from "./InstitutionBadge";
import imageCardGrid from "./ImageCardGrid";
import textMediaWidget from "./TextMediaWidget";
import circleInfographic from "./CircleInfographic";
import bodyText from "./BodyText";
import stepTracker from "./StepTracker";
import chartGrid from "./ChartGrid";
import iconWheel from "./IconWheel";
import circleChain from "./CircleChain";
import processFlow from "./ProcessFlow";

/** All registered element definitions. */
export const ELEMENT_REGISTRY = [
  storyTitle,
  headline,
  disclaimer,
  buttonList,
  buttonGrid,
  selectWidget,
  quoteList,
  cardGrid,
  institutionBadge,
  imageCardGrid,
  textMediaWidget,
  circleInfographic,
  bodyText,
  stepTracker,
  chartGrid,
  iconWheel,
  circleChain,
  processFlow,
];

const byType = new Map(ELEMENT_REGISTRY.map((definition) => [definition.type, definition]));

/**
 * The registered definition for a block type, or null for unknown types.
 *
 * @param {string} type - A block's `type` value, e.g. "quoteList".
 * @returns {Object|null}
 */
export const getElementDefinition = (type) => byType.get(type) || null;

/**
 * The layout region a content block renders in: the block's own `region`
 * field if set, otherwise its element's default, otherwise "content".
 * SlidePage wraps each region ("storyTitle" | "headline" | "content") in its
 * own container.
 *
 * @param {Object} block - A content block, e.g. `{ type: "headline", text: "..." }`.
 * @returns {string}
 */
export const getBlockRegion = (block) =>
  block.region || byType.get(block.type)?.region || "content";