@bettercms-ai/next 0.13.4 → 0.14.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/blocks.js +8 -3
- package/dist/blocks.js.map +1 -1
- package/dist/draft-bridge.js +8 -3
- package/dist/draft-bridge.js.map +1 -1
- package/package.json +4 -4
package/dist/blocks.js
CHANGED
|
@@ -11,7 +11,7 @@ import { blockStyleToCss } from "@bettercms-ai/types";
|
|
|
11
11
|
import { componentInstanceAddresses } from "@bettercms-ai/types";
|
|
12
12
|
import { applyOverrides } from "@bettercms-ai/ui/resolve";
|
|
13
13
|
import { PortableText } from "@bettercms-ai/ui/blocks";
|
|
14
|
-
import { readStructuredContent } from "@bettercms-ai/richtext";
|
|
14
|
+
import { embeddedComponentBlock, readStructuredContent } from "@bettercms-ai/richtext";
|
|
15
15
|
import { headingParts, richtextHeadingLevel } from "@bettercms-ai/richtext/heading";
|
|
16
16
|
|
|
17
17
|
// src/form.tsx
|
|
@@ -406,7 +406,11 @@ function renderText({ id, props }, ctx) {
|
|
|
406
406
|
const structured = readStructuredContent(props);
|
|
407
407
|
if (structured) {
|
|
408
408
|
const base = addressFor(id, "html", ctx);
|
|
409
|
-
|
|
409
|
+
const renderEmbed = (value) => {
|
|
410
|
+
const embed = embeddedComponentBlock(value);
|
|
411
|
+
return embed ? renderComponent(embed, { ...ctx, owner: base }) : void 0;
|
|
412
|
+
};
|
|
413
|
+
return /* @__PURE__ */ jsx2("div", { className: "bcms-block bcms-block--text", children: /* @__PURE__ */ jsx2(PortableText, { value: structured, ...base ? { bindingBase: base } : {}, renderBlock: renderEmbed }) }, id);
|
|
410
414
|
}
|
|
411
415
|
return /* @__PURE__ */ jsx2(
|
|
412
416
|
"div",
|
|
@@ -611,7 +615,8 @@ function renderComponent({ id, props }, ctx) {
|
|
|
611
615
|
...ctx,
|
|
612
616
|
depth: ctx.depth + 1,
|
|
613
617
|
seen: /* @__PURE__ */ new Set([...ctx.seen, def.id]),
|
|
614
|
-
fieldAddresses: componentInstanceAddresses(id, def.props)
|
|
618
|
+
fieldAddresses: ctx.owner === null ? /* @__PURE__ */ new Map() : componentInstanceAddresses(id, def.props, ctx.owner),
|
|
619
|
+
owner: void 0
|
|
615
620
|
};
|
|
616
621
|
return /* @__PURE__ */ jsx2(
|
|
617
622
|
"div",
|
package/dist/blocks.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/blocks.tsx","../src/form.tsx","../src/bindings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * <BcmsBlocks> — render a BetterCMS page's block_json natively in React.\n *\n * Pass the `blocks` from a page (delivery API `/content/:slug` → `entry.blocks`)\n * plus the `forms` you read with `readForms()`. Every block type renders to plain,\n * class-driven markup (the host site owns the styling); a `form` block resolves its\n * `formId` against `forms` and renders `<BcmsForm>` inline exactly where the user\n * placed it in the page builder. This is the turnkey \"Webflow\" path — forms show up\n * wherever they were dropped on the page, with no manual wiring.\n *\n * Ships from its own \"use client\" entry (like <BcmsForm>) so it can be rendered from\n * a Next App Router Server Component without breaking the RSC boundary.\n */\n\nimport {\n cloneElement,\n isValidElement,\n useState,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { blockStyleToCss } from \"@bettercms-ai/types\";\nimport type {\n ContentBlock,\n HeadingBlock,\n TextBlock,\n ImageBlock,\n ButtonBlock,\n SpacerBlock,\n VideoBlock,\n ColumnsBlock,\n FormBlock,\n SectionBlock,\n NavbarBlock,\n FooterBlock,\n SliderBlock,\n TabsBlock,\n ComponentBlock,\n DeliveryComponent,\n} from \"@bettercms-ai/types\";\nimport type { DeliveryForm } from \"@bettercms-ai/sdk\";\nimport { componentInstanceAddresses } from \"@bettercms-ai/types\";\nimport { applyOverrides } from \"@bettercms-ai/ui/resolve\";\nimport { PortableText } from \"@bettercms-ai/ui/blocks\";\nimport { readStructuredContent } from \"@bettercms-ai/richtext\";\nimport { headingParts, richtextHeadingLevel } from \"@bettercms-ai/richtext/heading\";\nimport { BcmsForm } from \"./form.js\";\n\nconst MAX_COMPONENT_DEPTH = 10;\n\nexport interface BcmsBlocksProps {\n /** A page's blocks (delivery API `/content/:slug` → `entry.blocks`). */\n blocks: ContentBlock[];\n /** Forms available to `form` blocks — from `readForms().forms`. */\n forms?: DeliveryForm[];\n /** Reusable components available to `component` blocks — from `readComponents()`. */\n components?: DeliveryComponent[];\n /** Turnstile site key — forwarded to `<BcmsForm>` for form blocks. */\n turnstileSiteKey?: string;\n /** API origin forwarded to `<BcmsForm>`. Defaults to the SDK default. */\n apiBase?: string;\n /** Class for the wrapping <div>. */\n className?: string;\n}\n\n/** Render a page's blocks. Unknown/empty blocks render nothing (fail-soft). */\nexport function BcmsBlocks({\n blocks,\n forms,\n components,\n turnstileSiteKey,\n apiBase,\n className,\n}: BcmsBlocksProps): ReactElement {\n const formsById = new Map((forms ?? []).map((f) => [f.id, f]));\n const componentsById = new Map((components ?? []).map((cmp) => [cmp.id, cmp]));\n const ctx: RenderCtx = { formsById, componentsById, turnstileSiteKey, apiBase, depth: 0, seen: new Set() };\n return (\n /**\n * 🔴 `data-bcms-page` marks THIS SUBTREE as ours to edit — the SDK's equivalent of the hosted\n * renderer's `<main class=\"bcms-page\">` (render-page.ts).\n *\n * The Visual Editor decides whether to show section controls by asking the page what it is.\n * Its only test was that hosted wrapper, which an SDK-rendered site never has — so every\n * headless site was treated as \"not ours\", and move/duplicate/delete/reorder stayed hidden\n * on pages that fully support them. Measured on a live SDK site: 34 blocks rendered,\n * 0 recognised.\n *\n * It must sit on the CONTAINER rather than be inferred from the blocks, so that a page with\n * NO blocks yet is still recognised — otherwise there is no way to add the first section,\n * which is exactly the state a new page starts in.\n */\n <div className={className} data-bcms-page=\"\">\n {blocks.map((block) => tagTopLevel(block, renderBlock(block, ctx)))}\n </div>\n );\n}\n\n/**\n * Stamp a TOP-LEVEL block's own id onto the element it rendered.\n *\n * The editor hit-tests `[data-bcms-block]` to find sections — for hover chrome, reorder targets,\n * drop indicators and per-section presence. Blocks already carried `bcms-block` CLASSES, which\n * look equivalent and are not: they are on every block at every depth and carry no id, so they\n * can identify neither which section you are pointing at nor which one to move.\n *\n * 🔴 `cloneElement`, NOT a wrapper `<div>`. The hosted renderer wraps because it assembles HTML\n * strings and has no other option; here an extra element would land inside the customer's own\n * layout, breaking `>` child selectors and any grid/flex parent that counts its children. This\n * adds an attribute and changes no structure.\n *\n * Only the top level is tagged, deliberately: a section is a top-level block, and tagging nested\n * ones would make a column's child look like a section you could drag out of its parent.\n */\nfunction tagTopLevel(block: ContentBlock, node: ReactNode): ReactNode {\n // A block that rendered nothing (unknown type, fail-soft) has nothing to stamp — and stamping\n // a fragment or string would throw.\n if (!isValidElement(node)) return node;\n return cloneElement(node as ReactElement<Record<string, unknown>>, {\n \"data-bcms-block\": block.id,\n });\n}\n\nimport { bind, bindProps, addressFor } from \"./bindings.js\";\n\ninterface RenderCtx {\n formsById: Map<string, DeliveryForm>;\n componentsById: Map<string, DeliveryComponent>;\n turnstileSiteKey?: string;\n apiBase?: string;\n depth: number;\n seen: Set<string>;\n /**\n * Present only inside a component instance, where it is AUTHORITATIVE: it maps the\n * DEFINITION's `<blockId>__<prop>` to this instance's `<id>__overrides.<key>`. A prop the\n * definition does not declare resolves to nothing and is left unannotated, rather than\n * carrying a definition-scoped address that binds to no field.\n */\n fieldAddresses?: Map<string, string>;\n}\n\nfunction renderBlock(block: ContentBlock, ctx: RenderCtx): ReactNode {\n const node = renderBlockInner(block, ctx);\n const style = blockStyleToCss(block.style);\n if (!style || node == null) return node;\n // FLO-264: honor the block's bounded style tokens in the headless render too, so\n // @bettercms-ai/next output matches the builder canvas + hosted site.\n return (\n <div key={block.id} style={style as CSSProperties}>\n {node}\n </div>\n );\n}\n\nfunction renderBlockInner(block: ContentBlock, ctx: RenderCtx): ReactNode {\n switch (block.type) {\n case \"heading\":\n return renderHeading(block, ctx);\n // `richtext` and `text` carry the same payload and differ only in the authoring surface,\n // so delivery renders them identically — Astro (BcmsBlocks.astro) and the hosted renderer\n // (render-page.ts) both alias them. Next did not, so `richtext` fell to `default: null`\n // and a richtext block rendered NOTHING on a Next site: 200 OK, green build, blank region.\n case \"text\":\n case \"richtext\":\n return renderText(block as TextBlock, ctx);\n case \"image\":\n return renderImage(block, ctx);\n case \"button\":\n return renderButton(block, ctx);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block, ctx);\n case \"columns\":\n return renderColumns(block, ctx);\n case \"form\":\n return renderForm(block, ctx);\n case \"section\":\n return renderSection(block, ctx);\n case \"navbar\":\n return renderNavbar(block, ctx);\n case \"footer\":\n return renderFooter(block, ctx);\n case \"slider\":\n return <BcmsSlider key={block.id} block={block} ctx={ctx} />;\n case \"tabs\":\n return <BcmsTabs key={block.id} block={block} ctx={ctx} />;\n case \"component\":\n return renderComponent(block, ctx);\n default:\n return renderUnhandledBlock(block);\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock, ctx: RenderCtx): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" {...bind(id, \"text\", \"text\", ctx)}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock, ctx: RenderCtx): ReactNode {\n /**\n * `props.level` renders the rich copy AS <hN> — the same markup the hosted renderer emits\n * (src/lib/richtext/heading.ts), assembled by the SAME shared helper so the three lanes cannot\n * drift. Absent ⇒ the ordinary container below, byte-identical to before. A value that is not\n * one line of inline copy falls through rather than nesting paragraphs inside a heading.\n *\n * The heading serialises its structured value to a STRING rather than mounting <PortableText>:\n * the hosted and Astro lanes both emit the string, and `parity.test.ts` compares the markup.\n */\n const level = richtextHeadingLevel(props.level);\n if (level) {\n const heading = headingParts(props, addressFor(id, \"html\", ctx));\n if (heading !== null) {\n const Tag = `h${level}` as \"h1\";\n const binding = heading.address\n ? { \"data-bcms-field\": heading.address, \"data-bcms-kind\": \"richtext\" }\n : {};\n return <Tag key={id} {...binding} dangerouslySetInnerHTML={{ __html: heading.inner }} />;\n }\n }\n\n /**\n * STRUCTURED CONTENT WINS, and until now this lane did not know it existed.\n *\n * The hosted renderer preferred `props.content` over `props.html` and the shared React\n * renderer did too, but this file read `html` unconditionally — so a block whose structured\n * value had diverged from its derived cache rendered the STALE cache on Next sites and the\n * fresh value everywhere else. Silent, per-lane, and green in CI, which is the same shape as\n * the bug that made `richtext` render nothing at all here for a whole release.\n *\n * `addressFor`, not a hand-built `${id}__html`: inside a placed component the address has to\n * be remapped to the instance, or the binding resolves to no field and two instances of one\n * component collide into a duplicate that drops both.\n */\n const structured = readStructuredContent(props);\n if (structured) {\n const base = addressFor(id, \"html\", ctx);\n return (\n <div key={id} className=\"bcms-block bcms-block--text\">\n <PortableText value={structured} {...(base ? { bindingBase: base } : {})} />\n </div>\n );\n }\n\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n {...bind(id, \"html\", \"richtext\", ctx)}\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\n\nfunction renderImage({ id, props }: ImageBlock, ctx: RenderCtx): ReactNode {\n const img = (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n loading=\"lazy\"\n // Heading/text/button have always been click-to-edit on the Visual Editor canvas because\n // they carry this attribute; the image block did not, so a block page's images were the\n // one thing you could only change from the dock. `kind=\"image\"` keeps it selection-only\n // (no contentEditable on an <img>) while letting the editor reflect a new src live.\n {...bind(id, \"src\", \"image\", ctx)}\n // `alt` rides the props lane: this <img> already carries the src binding and an element\n // cannot hold two addresses. It is also the one image property a screen-reader user\n // depends on, so leaving it dock-only made the canvas worse at the accessibility half.\n {...bindProps(id, [{ prop: \"alt\", kind: \"text\", attr: \"alt\", present: props.alt != null }], ctx)}\n />\n );\n if (!props.caption) {\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n </figure>\n );\n }\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n <figcaption {...bind(id, \"caption\", \"text\", ctx)}>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock, ctx: RenderCtx): ReactNode {\n return (\n <a\n key={id}\n href={props.href}\n className={`bcms-block bcms-block--button bcms-button--${props.variant ?? \"primary\"}`}\n {...bind(id, \"text\", \"text\", ctx)}\n // A URL never takes a caret — typing one onto the page has nowhere to report a malformed\n // value — so it is addressed here and edited in the element toolbar.\n {...bindProps(id, [{ prop: \"href\", kind: \"url\", attr: \"href\", present: props.href != null }], ctx)}\n >\n {props.text}\n </a>\n );\n}\n\nfunction renderSpacer({ id, props }: SpacerBlock): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--spacer\"\n style={{ height: props.height }}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction renderVideo({ id, props }: VideoBlock, ctx: RenderCtx): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\n // A video has no text node at all, so it was the one block a click could not reach: no\n // binding meant no `data-node-id` and nothing to hit-test. Both its values are attributes,\n // so the props lane carries the whole block.\n {...bindProps(\n id,\n [\n { prop: \"url\", kind: \"url\", attr: \"src\", present: props.url != null },\n { prop: \"poster\", kind: \"url\", attr: \"poster\", present: props.poster != null },\n ],\n ctx,\n )}\n autoPlay={props.autoplay}\n loop={props.loop}\n controls\n />\n );\n}\n\nfunction renderColumns({ id, props }: ColumnsBlock, ctx: RenderCtx): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--columns\"\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${props.columns.length || 1}, 1fr)`,\n gap: props.gap,\n }}\n >\n {props.columns.map((column, i) => (\n <div key={i} className=\"bcms-column\">\n {column.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderForm({ id, props }: FormBlock, ctx: RenderCtx): ReactNode {\n const form = ctx.formsById.get(props.formId);\n if (!form) return null; // form deleted or not delivered — render nothing\n return (\n <div key={id} className=\"bcms-block bcms-block--form\">\n <BcmsForm form={form} turnstileSiteKey={ctx.turnstileSiteKey} apiBase={ctx.apiBase} />\n </div>\n );\n}\n\nfunction renderSection({ id, props }: SectionBlock, ctx: RenderCtx): ReactNode {\n const inner = props.children.map((child) => renderBlock(child, ctx));\n return (\n <section\n key={id}\n className=\"bcms-block bcms-block--section\"\n style={{ background: props.background, padding: props.paddingY != null ? `${props.paddingY}px 0` : undefined }}\n >\n {/* 🔴 `bcms-section-inner` — the Astro package and the hosted renderer both class this\n wrapper; Next was the only lane that left it bare. That is not cosmetic: the wrapper\n is CONDITIONAL on `maxWidth`, so a host stylesheet that wants to reach a section's\n children has to target `> div`, which also matches every classed block that happens\n to render as a div (a columns grid, a text block) and restyles their internals. With\n the class there, one selector covers all three lanes and nothing reaches past it.\n Toggling `maxWidth` in the editor must not silently retune a section's rhythm. */}\n {props.maxWidth ? (\n <div className=\"bcms-section-inner\" style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div>\n ) : (\n inner\n )}\n </section>\n );\n}\n\n/**\n * Every link is addressed individually, by index. This was the flagship \"nested under arrays\"\n * exclusion, on the grounds that the writer could not reach it — but `parseFieldPath` and\n * `setFieldPath` have walked N indices since FLO-949 and `setValue` takes any path. Only the\n * offer was missing, so a site's navigation was uneditable on the canvas while being perfectly\n * writable through the dock.\n */\nfunction renderNavbar({ id, props }: NavbarBlock, ctx: RenderCtx): ReactNode {\n return (\n <nav key={id} className=\"bcms-block bcms-block--navbar\">\n {props.logo?.src ? (\n <a className=\"bcms-navbar-logo\" href={props.logo.href ?? \"/\"}>\n <img\n src={props.logo.src}\n alt={props.logo.alt}\n {...bind(id, \"logo.src\", \"image\", ctx)}\n {...bindProps(id, [{ prop: \"logo.alt\", kind: \"text\", attr: \"alt\", present: props.logo.alt != null }], ctx)}\n />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a\n key={i}\n href={l.href}\n {...bind(id, `links[${i}].label`, \"text\", ctx)}\n {...bindProps(id, [{ prop: `links[${i}].href`, kind: \"url\", attr: \"href\", present: l.href != null }], ctx)}\n >\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a\n className=\"bcms-button bcms-button--primary\"\n href={props.cta.href}\n {...bind(id, \"cta.text\", \"text\", ctx)}\n {...bindProps(id, [{ prop: \"cta.href\", kind: \"url\", attr: \"href\", present: props.cta.href != null }], ctx)}\n >\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\n/**\n * A footer link is the deepest addressable thing on a page: `columns[i].links[j].label`, two\n * indices. That is the shape the old grammar note called unaddressable, and the shape the ENTRY\n * lane still refuses — but the two are different problems. The entry cap is about resolving a\n * repeater row's `_id` identity; a block path is direct, so there is no identity to resolve.\n */\nfunction renderFooter({ id, props }: FooterBlock, ctx: RenderCtx): ReactNode {\n return (\n <footer key={id} className=\"bcms-block bcms-block--footer\">\n <div className=\"bcms-footer-cols\">\n {props.columns.map((col, i) => (\n <div key={i} className=\"bcms-footer-col\">\n {col.heading ? <h4 {...bind(id, `columns[${i}].heading`, \"text\", ctx)}>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a\n href={l.href}\n {...bind(id, `columns[${i}].links[${j}].label`, \"text\", ctx)}\n {...bindProps(\n id,\n [{ prop: `columns[${i}].links[${j}].href`, kind: \"url\", attr: \"href\", present: l.href != null }],\n ctx,\n )}\n >\n {l.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? (\n <p className=\"bcms-footer-copy\" {...bind(id, \"copyright\", \"text\", ctx)}>\n {props.copyright}\n </p>\n ) : null}\n </footer>\n );\n}\n\n/**\n * 🔴 `...rest` is load-bearing, not tidiness. `tagTopLevel` stamps a top-level block by\n * `cloneElement`, which sets `data-bcms-block` as a PROP on this component — and a component\n * that does not spread it drops the attribute with no error and no warning. A top-level slider\n * or tabs block then renders perfectly and is invisible to the Visual Editor's section lane:\n * no move, no duplicate, no delete, no presence. Intrinsic elements do not have this failure\n * mode, which is why every other block type was fine and these two were not.\n */\nfunction BcmsSlider({ block, ctx, ...rest }: { block: SliderBlock; ctx: RenderCtx }): ReactElement {\n const { slides } = block.props;\n const [i, setI] = useState(0);\n const go = (n: number) => setI((n + slides.length) % (slides.length || 1));\n return (\n <div className=\"bcms-block bcms-block--slider\" style={{ position: \"relative\" }} {...rest}>\n {slides.map((s, idx) => (\n <div key={s.id} className=\"bcms-slide\" hidden={idx !== i}>\n {s.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n <button type=\"button\" className=\"bcms-slider-prev\" aria-label=\"Previous\" onClick={() => go(i - 1)}>\n ‹\n </button>\n <button type=\"button\" className=\"bcms-slider-next\" aria-label=\"Next\" onClick={() => go(i + 1)}>\n ›\n </button>\n </div>\n );\n}\n\n/** `...rest` for the same reason as <BcmsSlider> above — see its comment. */\nfunction BcmsTabs({ block, ctx, ...rest }: { block: TabsBlock; ctx: RenderCtx }): ReactElement {\n const { tabs } = block.props;\n const [active, setActive] = useState(0);\n return (\n <div className=\"bcms-block bcms-block--tabs\" {...rest}>\n <div className=\"bcms-tablist\" role=\"tablist\">\n {tabs.map((t, idx) => (\n <button\n key={t.id}\n role=\"tab\"\n type=\"button\"\n className=\"bcms-tab\"\n aria-selected={idx === active}\n onClick={() => setActive(idx)}\n {...bind(block.id, `tabs[${idx}].label`, \"text\", ctx)}\n >\n {t.label}\n </button>\n ))}\n </div>\n {tabs.map((t, idx) => (\n <div key={t.id} role=\"tabpanel\" className=\"bcms-tabpanel\" hidden={idx !== active}>\n {t.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Missing-component ids already reported. Module-level so a page that places the same section\n * twenty times logs once, not twenty times — a wall of identical lines is skipped, and this\n * message has to be read.\n */\nconst warnedMissing = new Set<string>();\n\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return renderMissingComponent(props.componentId, ctx);\n if (ctx.depth >= MAX_COMPONENT_DEPTH || ctx.seen.has(def.id)) return null; // cycle/depth guard\n const resolved = applyOverrides<ContentBlock>(def.blockJson, def.props ?? [], props.overrides ?? {});\n // The instance's own addresses replace the definition's for the whole subtree. Without this\n // every stamp inside a component named a block shared by every instance of it: an orphan on\n // one placement, and a duplicate that drops BOTH on two.\n const childCtx: RenderCtx = {\n ...ctx,\n depth: ctx.depth + 1,\n seen: new Set([...ctx.seen, def.id]),\n fieldAddresses: componentInstanceAddresses(id, def.props),\n };\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--component\"\n data-bcms-component={def.id}\n data-bcms-variant=\"base\"\n data-bcms-instance={id}\n >\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\n}\n\n/**\n * A `component` block whose definition was not delivered.\n *\n * 🔴 This used to be `return null // fail-soft`, and that comment was the bug. A page authored\n * as SECTIONS is a list of `component` blocks and nothing else, so \"fail-soft\" meant the entire\n * page body rendered as nothing while the build stayed green and the site answered 200 — what\n * remained on screen was the layout's own nav and footer. Two live sites were replaced by that\n * on 2026-08-18, and the only reason it was caught is that a human looked at the page.\n *\n * The near-universal cause is a host site that never passes `components` — the SDK's own README\n * example omitted it — so the message names the fix rather than the symptom.\n *\n * Still renders nothing in production: a placeholder box would be worse than a gap on a live\n * customer site. The console line ships in BOTH modes, because it is emitted during the build\n * and the build log is the one place a headless deploy can be inspected after the fact.\n */\nconst warnedUnhandled = new Set<string>();\n\n/**\n * A block type this renderer has no case for.\n *\n * `default: return null` is how `richtext` rendered NOTHING on a Next site for a whole release\n * — 200 OK, green build, blank region, no error anywhere. `collection` is in that state today:\n * it is delivered, the hosted renderer draws it, and this one silently drops it. Saying so out\n * loud does not implement the missing renderer, but it converts an invisible blank into a\n * message that names the type, which is the difference between a bug you find and one you ship.\n */\nfunction renderUnhandledBlock(block: ContentBlock): ReactNode {\n if (!warnedUnhandled.has(block.type)) {\n warnedUnhandled.add(block.type);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] block type \"${block.type}\" has no renderer here, so it rendered NOTHING. ` +\n `The hosted renderer draws it; this SDK does not yet.`,\n );\n }\n return null;\n}\n\nfunction renderMissingComponent(componentId: string, ctx: RenderCtx): ReactNode {\n if (!warnedMissing.has(componentId)) {\n warnedMissing.add(componentId);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] component \"${componentId}\" was not delivered, so this section rendered NOTHING.` +\n (ctx.componentsById.size === 0\n ? ` No components were passed at all — add components={readComponents()} to <BcmsBlocks>.`\n : ` ${ctx.componentsById.size} component(s) were passed but none match. It is probably still a DRAFT: publish it, then rebuild.`),\n );\n }\n if (process.env.NODE_ENV === \"production\") return null;\n return (\n <div\n className=\"bcms-block bcms-block--component-missing\"\n data-bcms-missing-component={componentId}\n style={{\n padding: \"12px 16px\",\n border: \"1px dashed #d4d4d8\",\n borderRadius: 8,\n color: \"#71717a\",\n font: \"500 13px/1.5 system-ui, -apple-system, sans-serif\",\n }}\n >\n Section <code>{componentId}</code> was not delivered.{\" \"}\n {ctx.componentsById.size === 0\n ? \"Pass components={readComponents()} to <BcmsBlocks>.\"\n : \"Publish the component, then rebuild.\"}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsForm> — render a BetterCMS form natively in React, the headless way.\n *\n * Pass a form straight from your content snapshot (`readSnapshot().forms[n]`) or\n * the delivery API. It renders real inputs (no iframe), handles conditional\n * `showIf` fields, URL-query prefill, the honeypot, an optional Turnstile widget,\n * and submits via `@bettercms-ai/sdk`'s `submitForm`. All visible markup is\n * unstyled and class-driven, so the host site owns the look.\n */\n\nimport { lazy, Suspense, useEffect, useMemo, useState, type FormEvent, type ReactElement } from \"react\";\nimport {\n submitForm,\n shouldShowField,\n formInitialValues,\n asStringArray,\n toggleOption,\n type DeliveryForm,\n type DeliveryFormField,\n type FormValue,\n type FormValues,\n type FormSubmitError,\n} from \"@bettercms-ai/sdk\";\n\nconst TURNSTILE_SRC = \"https://challenges.cloudflare.com/turnstile/v0/api.js\";\n\n/**\n * The country-picker phone control, loaded only when a form actually has one.\n *\n * It carries libphonenumber's metadata (~80KB), which no form without a picker should pay\n * for. The import specifier must survive into `dist/form.js` rather than being inlined —\n * see the `external` entry in tsup.config.ts and the dist greps in the tests.\n */\nconst PhoneField = lazy(() => import(\"./phone-field.js\"));\n\n// Field type → native <input type>. Other types render their own element.\nconst INPUT_TYPES: Partial<Record<DeliveryFormField[\"type\"], string>> = {\n text: \"text\",\n email: \"email\",\n phone: \"tel\",\n url: \"url\",\n number: \"number\",\n date: \"date\",\n};\n\nexport interface BcmsFormProps {\n /** A form from your content snapshot or the delivery API. */\n form: DeliveryForm;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Turnstile site key — needed to render the widget when `form.turnstileEnabled`. */\n turnstileSiteKey?: string;\n /** Called with the new submission id after a successful submit (before any redirect). */\n onSubmitted?: (submissionId: string) => void;\n /** Class for the <form> element; field wrappers/status use `bcms-*` classes. */\n className?: string;\n}\n\ntype Status = { state: \"idle\" | \"submitting\" | \"error\" | \"success\"; message?: string };\n\nfunction readPrefill(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const out: Record<string, string> = {};\n new URLSearchParams(window.location.search).forEach((v, k) => {\n out[k] = v;\n });\n return out;\n}\n\nfunction resetTurnstile(): void {\n const t = (globalThis as { turnstile?: { reset: () => void } }).turnstile;\n if (t) {\n try {\n t.reset();\n } catch {\n /* widget not mounted yet */\n }\n }\n}\n\nexport function BcmsForm({\n form,\n apiBase,\n turnstileSiteKey,\n onSubmitted,\n className,\n}: BcmsFormProps): ReactElement {\n const showTurnstile = Boolean(form.turnstileEnabled && turnstileSiteKey);\n const [values, setValues] = useState<FormValues>(() => {\n const init = formInitialValues(form, readPrefill());\n if (form.honeypotField) init[form.honeypotField] = \"\";\n return init;\n });\n const [status, setStatus] = useState<Status>({ state: \"idle\" });\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n // Cloudflare auto-renders any `.cf-turnstile` element once its script is present.\n useEffect(() => {\n if (!showTurnstile || document.querySelector(`script[src=\"${TURNSTILE_SRC}\"]`)) return;\n const script = document.createElement(\"script\");\n script.src = TURNSTILE_SRC;\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n }, [showTurnstile]);\n\n const visibleFields = useMemo(\n () => form.fields.filter((f) => f.type !== \"hidden\" && shouldShowField(f, values)),\n [form.fields, values],\n );\n\n const setValue = (key: string, value: FormValue) =>\n setValues((prev) => ({ ...prev, [key]: value }));\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {\n e.preventDefault();\n setStatus({ state: \"submitting\" });\n setFieldErrors({});\n\n const tokenEl = e.currentTarget.querySelector<HTMLInputElement>(\n '[name=\"cf-turnstile-response\"]',\n );\n const turnstileToken = tokenEl?.value || undefined;\n\n // Drop conditionally-hidden fields so a hidden required field can't block submit;\n // keep hidden-type fields and the honeypot (the API classifies bots on it).\n const data: FormValues = {};\n for (const field of form.fields) {\n if (field.type === \"hidden\" || shouldShowField(field, values)) {\n data[field.key] = values[field.key];\n }\n }\n if (form.honeypotField) data[form.honeypotField] = values[form.honeypotField] ?? \"\";\n\n try {\n const { id } = await submitForm({ formId: form.id, data, turnstileToken, baseUrl: apiBase });\n onSubmitted?.(id);\n if (form.redirectUrl) {\n window.location.href = form.redirectUrl;\n return;\n }\n const reset = formInitialValues(form);\n if (form.honeypotField) reset[form.honeypotField] = \"\";\n setValues(reset);\n setStatus({\n state: \"success\",\n message: form.successMessage ?? \"Thanks! Your submission was received.\",\n });\n resetTurnstile();\n } catch (err) {\n const e2 = err as FormSubmitError;\n if (e2.fieldErrors) setFieldErrors(e2.fieldErrors);\n setStatus({ state: \"error\", message: e2.message || \"Something went wrong. Please try again.\" });\n resetTurnstile();\n }\n }\n\n return (\n // `data-bcms-form` carries the id so the Visual Editor can find THIS form in the\n // preview frame and patch its copy live. Valued rather than bare: the runtime\n // selectors are `form[data-bcms-form]`, which a valued attribute still matches.\n <form className={className} onSubmit={handleSubmit} noValidate data-bcms-form={form.id}>\n {visibleFields.map((field) => (\n <Field\n key={field.key}\n field={field}\n value={values[field.key]}\n error={fieldErrors[field.key]}\n onChange={(v) => setValue(field.key, v)}\n />\n ))}\n\n {form.honeypotField ? (\n <span aria-hidden=\"true\" style={{ position: \"absolute\", left: \"-9999px\" }}>\n <input\n type=\"text\"\n name={form.honeypotField}\n tabIndex={-1}\n autoComplete=\"off\"\n value={String(values[form.honeypotField] ?? \"\")}\n onChange={(e) => setValue(form.honeypotField as string, e.target.value)}\n />\n </span>\n ) : null}\n\n {showTurnstile ? <div className=\"cf-turnstile\" data-sitekey={turnstileSiteKey} /> : null}\n\n <button type=\"submit\" disabled={status.state === \"submitting\"} data-bcms-form-part=\"submit\">\n {status.state === \"submitting\" ? \"Submitting…\" : form.submitLabel ?? \"Submit\"}\n </button>\n\n {status.message ? (\n <p\n className={`bcms-form-status bcms-form-status--${status.state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {status.message}\n </p>\n ) : null}\n </form>\n );\n}\n\ninterface FieldProps {\n field: DeliveryFormField;\n value: FormValue;\n error?: string;\n onChange: (value: FormValue) => void;\n}\n\nfunction Field({ field, value, error, onChange }: FieldProps): ReactElement {\n const required = field.required;\n const errorNode = error ? (\n <span className=\"bcms-field-error\" role=\"alert\">\n {error}\n </span>\n ) : null;\n // Every author-editable string carries a `data-bcms-form-part` so the Visual Editor can\n // repaint it live. A string the dock can edit but cannot mark shows stale on the canvas.\n const helpNode = field.helpText ? (\n <span className=\"bcms-field-help\" data-bcms-form-part=\"help\">\n {field.helpText}\n </span>\n ) : null;\n\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label\n className=\"bcms-field bcms-field--checkbox\"\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <input\n type=\"checkbox\"\n name={field.key}\n required={required}\n checked={Boolean(value)}\n onChange={(e) => onChange(e.target.checked)}\n />{\" \"}\n <span data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </span>\n {helpNode}\n {errorNode}\n </label>\n );\n }\n\n // Pick-one and pick-many are groups of controls, not a single element, so they\n // return their own <fieldset> rather than flowing into the label+control shape\n // below. Without these two branches both fell through to `<input type=\"text\">`.\n if (field.type === \"radio\" || field.type === \"checkboxes\") {\n const multi = field.type === \"checkboxes\";\n const selected = asStringArray(value);\n return (\n <fieldset\n className={`bcms-field bcms-field--${multi ? \"checkboxes\" : \"radio\"}`}\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <legend data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </legend>\n {(field.options ?? []).map((opt) => (\n <label key={opt} className=\"bcms-option\">\n <input\n type={multi ? \"checkbox\" : \"radio\"}\n name={field.key}\n value={opt}\n // `required` on every radio in a group is the native way to demand one\n // choice. On checkboxes it would demand ALL of them, so it is omitted —\n // the API enforces non-empty instead.\n required={!multi && required}\n checked={multi ? selected.includes(opt) : value === opt}\n onChange={(e) =>\n onChange(multi ? toggleOption(value, opt, e.target.checked) : opt)\n }\n />{\" \"}\n <span data-bcms-form-part=\"option\">{opt}</span>\n </label>\n ))}\n {helpNode}\n {errorNode}\n </fieldset>\n );\n }\n\n const str = String(value ?? \"\");\n let control: ReactElement;\n if (field.type === \"textarea\") {\n control = (\n <textarea\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n } else if (field.type === \"select\") {\n control = (\n <select name={field.key} required={required} value={str} onChange={(e) => onChange(e.target.value)}>\n <option value=\"\" disabled>\n Choose…\n </option>\n {(field.options ?? []).map((opt) => (\n <option key={opt} value={opt} data-bcms-form-part=\"option\">\n {opt}\n </option>\n ))}\n </select>\n );\n } else if (field.type === \"phone\" && field.ui?.countryPicker) {\n // The fallback is a usable tel input inside the SAME wrapper, so the host's `.bcms-phone`\n // rules apply before and after the chunk lands and the swap is not a layout surprise.\n control = (\n <Suspense\n fallback={\n <span className=\"bcms-phone\">\n <input type=\"tel\" name={field.key} placeholder={field.placeholder} required={required} value={str} onChange={(e) => onChange(e.target.value)} autoComplete=\"tel\" dir=\"ltr\" />\n </span>\n }\n >\n <PhoneField\n name={field.key}\n value={str}\n onChange={onChange}\n placeholder={field.placeholder}\n required={required}\n defaultCountry={field.ui.defaultCountry}\n />\n </Suspense>\n );\n } else {\n control = (\n <input\n type={INPUT_TYPES[field.type] ?? \"text\"}\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n\n return (\n <p className=\"bcms-field\" data-field={field.key} data-bcms-form-field={field.key}>\n <label data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\n {helpNode}\n {errorNode}\n </p>\n );\n}\n","/**\n * Visual Editor addresses for the Next renderer.\n *\n * The attributes are ALWAYS on, deliberately — a headless site's HTML is the customer's own,\n * `data-bcms-*` is inert for visitors, and there is no request-time draft render to gate them\n * against. That has been true since they were introduced; what was wrong is WHICH address they\n * carried inside a component.\n *\n * A component's block ids belong to the DEFINITION and are shared by every instance of it, so a\n * definition-scoped `<defBlockId>__text` resolves to no field in the loaded entry — the editor\n * logs it as an orphan — and two instances of one component produce the SAME address twice, which\n * `stampNodeIds` numbers as two COPIES of that one orphan (`data-node-index`) rather than two\n * fields: editing either edits nothing, on both. The hosted renderer avoided this by rendering component\n * subtrees unannotated; this one had no equivalent, so it emitted live-looking attributes that\n * bound to nothing. `addresses` fixes it at the source instead: inside an instance the map is\n * authoritative and resolves each declared prop to `<instanceId>__overrides.<key>`.\n */\nimport type { BindingKind } from \"@bettercms-ai/types\";\nimport { formatPropsAttribute } from \"@bettercms-ai/types\";\n\n/** The subset of the render context binding needs. */\nexport interface BindingCtx {\n /** Present only inside a component instance, where it is AUTHORITATIVE. */\n fieldAddresses?: Map<string, string>;\n}\n\n/** The address a write lands on, or null when none exists and nothing should be advertised. */\nexport function addressFor(id: string | undefined, prop: string, ctx: BindingCtx): string | null {\n if (!id) return null;\n const key = `${id}__${prop}`;\n if (ctx.fieldAddresses) return ctx.fieldAddresses.get(key) ?? null;\n return key;\n}\n\n/**\n * Attributes for a value rendered as this element's own content — spread onto the JSX tag.\n * Returns an empty object when unaddressable, so it spreads to nothing.\n */\nexport function bind(\n id: string | undefined,\n prop: string,\n kind: BindingKind,\n ctx: BindingCtx,\n): Record<string, string> {\n const address = addressFor(id, prop, ctx);\n return address ? { \"data-bcms-field\": address, \"data-bcms-kind\": kind } : {};\n}\n\n/**\n * Attributes for values that live in an ATTRIBUTE of this element (`alt`, `href`, a video's\n * `src`). `data-bcms-field` addresses one element and an element cannot hold two, so these ride\n * `data-bcms-props`: `<address>|<kind>|<domAttribute>`, semicolon separated.\n *\n * Entries whose value is absent are dropped: `setFieldPath` refuses to create a final key, so\n * an address for a key the block does not carry is a write the editor would reject.\n */\nexport function bindProps(\n id: string | undefined,\n entries: readonly { prop: string; kind: BindingKind; attr: string; present: boolean }[],\n ctx: BindingCtx,\n): Record<string, string> {\n const resolved = entries.flatMap(({ prop, kind, attr, present }) => {\n if (!present) return [];\n const address = addressFor(id, prop, ctx);\n return address ? [{ address, kind, attr }] : [];\n });\n return resolved.length ? { \"data-bcms-props\": formatPropsAttribute(resolved) } : {};\n}\n"],"mappings":"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","names":["useState","jsx","jsxs","useState"]}
|
|
1
|
+
{"version":3,"sources":["../src/blocks.tsx","../src/form.tsx","../src/bindings.ts"],"sourcesContent":["\"use client\";\n\n/**\n * <BcmsBlocks> — render a BetterCMS page's block_json natively in React.\n *\n * Pass the `blocks` from a page (delivery API `/content/:slug` → `entry.blocks`)\n * plus the `forms` you read with `readForms()`. Every block type renders to plain,\n * class-driven markup (the host site owns the styling); a `form` block resolves its\n * `formId` against `forms` and renders `<BcmsForm>` inline exactly where the user\n * placed it in the page builder. This is the turnkey \"Webflow\" path — forms show up\n * wherever they were dropped on the page, with no manual wiring.\n *\n * Ships from its own \"use client\" entry (like <BcmsForm>) so it can be rendered from\n * a Next App Router Server Component without breaking the RSC boundary.\n */\n\nimport {\n cloneElement,\n isValidElement,\n useState,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { blockStyleToCss } from \"@bettercms-ai/types\";\nimport type {\n ContentBlock,\n HeadingBlock,\n TextBlock,\n ImageBlock,\n ButtonBlock,\n SpacerBlock,\n VideoBlock,\n ColumnsBlock,\n FormBlock,\n SectionBlock,\n NavbarBlock,\n FooterBlock,\n SliderBlock,\n TabsBlock,\n ComponentBlock,\n DeliveryComponent,\n} from \"@bettercms-ai/types\";\nimport type { DeliveryForm } from \"@bettercms-ai/sdk\";\nimport { componentInstanceAddresses } from \"@bettercms-ai/types\";\nimport { applyOverrides } from \"@bettercms-ai/ui/resolve\";\nimport { PortableText } from \"@bettercms-ai/ui/blocks\";\nimport { embeddedComponentBlock, readStructuredContent } from \"@bettercms-ai/richtext\";\nimport { headingParts, richtextHeadingLevel } from \"@bettercms-ai/richtext/heading\";\nimport { BcmsForm } from \"./form.js\";\n\nconst MAX_COMPONENT_DEPTH = 10;\n\nexport interface BcmsBlocksProps {\n /** A page's blocks (delivery API `/content/:slug` → `entry.blocks`). */\n blocks: ContentBlock[];\n /** Forms available to `form` blocks — from `readForms().forms`. */\n forms?: DeliveryForm[];\n /** Reusable components available to `component` blocks — from `readComponents()`. */\n components?: DeliveryComponent[];\n /** Turnstile site key — forwarded to `<BcmsForm>` for form blocks. */\n turnstileSiteKey?: string;\n /** API origin forwarded to `<BcmsForm>`. Defaults to the SDK default. */\n apiBase?: string;\n /** Class for the wrapping <div>. */\n className?: string;\n}\n\n/** Render a page's blocks. Unknown/empty blocks render nothing (fail-soft). */\nexport function BcmsBlocks({\n blocks,\n forms,\n components,\n turnstileSiteKey,\n apiBase,\n className,\n}: BcmsBlocksProps): ReactElement {\n const formsById = new Map((forms ?? []).map((f) => [f.id, f]));\n const componentsById = new Map((components ?? []).map((cmp) => [cmp.id, cmp]));\n const ctx: RenderCtx = { formsById, componentsById, turnstileSiteKey, apiBase, depth: 0, seen: new Set() };\n return (\n /**\n * 🔴 `data-bcms-page` marks THIS SUBTREE as ours to edit — the SDK's equivalent of the hosted\n * renderer's `<main class=\"bcms-page\">` (render-page.ts).\n *\n * The Visual Editor decides whether to show section controls by asking the page what it is.\n * Its only test was that hosted wrapper, which an SDK-rendered site never has — so every\n * headless site was treated as \"not ours\", and move/duplicate/delete/reorder stayed hidden\n * on pages that fully support them. Measured on a live SDK site: 34 blocks rendered,\n * 0 recognised.\n *\n * It must sit on the CONTAINER rather than be inferred from the blocks, so that a page with\n * NO blocks yet is still recognised — otherwise there is no way to add the first section,\n * which is exactly the state a new page starts in.\n */\n <div className={className} data-bcms-page=\"\">\n {blocks.map((block) => tagTopLevel(block, renderBlock(block, ctx)))}\n </div>\n );\n}\n\n/**\n * Stamp a TOP-LEVEL block's own id onto the element it rendered.\n *\n * The editor hit-tests `[data-bcms-block]` to find sections — for hover chrome, reorder targets,\n * drop indicators and per-section presence. Blocks already carried `bcms-block` CLASSES, which\n * look equivalent and are not: they are on every block at every depth and carry no id, so they\n * can identify neither which section you are pointing at nor which one to move.\n *\n * 🔴 `cloneElement`, NOT a wrapper `<div>`. The hosted renderer wraps because it assembles HTML\n * strings and has no other option; here an extra element would land inside the customer's own\n * layout, breaking `>` child selectors and any grid/flex parent that counts its children. This\n * adds an attribute and changes no structure.\n *\n * Only the top level is tagged, deliberately: a section is a top-level block, and tagging nested\n * ones would make a column's child look like a section you could drag out of its parent.\n */\nfunction tagTopLevel(block: ContentBlock, node: ReactNode): ReactNode {\n // A block that rendered nothing (unknown type, fail-soft) has nothing to stamp — and stamping\n // a fragment or string would throw.\n if (!isValidElement(node)) return node;\n return cloneElement(node as ReactElement<Record<string, unknown>>, {\n \"data-bcms-block\": block.id,\n });\n}\n\nimport { bind, bindProps, addressFor } from \"./bindings.js\";\n\ninterface RenderCtx {\n formsById: Map<string, DeliveryForm>;\n componentsById: Map<string, DeliveryComponent>;\n turnstileSiteKey?: string;\n apiBase?: string;\n depth: number;\n seen: Set<string>;\n /**\n * Present only inside a component instance, where it is AUTHORITATIVE: it maps the\n * DEFINITION's `<blockId>__<prop>` to this instance's `<id>__overrides.<key>`. A prop the\n * definition does not declare resolves to nothing and is left unannotated, rather than\n * carrying a definition-scoped address that binds to no field.\n */\n fieldAddresses?: Map<string, string>;\n /**\n * Set only for a component EMBEDDED in rich text: the rich-text field's address, which names\n * the instance (`<owner>#<_key>`), or null when that field has none — so the embed gets no\n * addresses rather than a bare `_key` that resolves to nothing.\n */\n owner?: string | null;\n}\n\nfunction renderBlock(block: ContentBlock, ctx: RenderCtx): ReactNode {\n const node = renderBlockInner(block, ctx);\n const style = blockStyleToCss(block.style);\n if (!style || node == null) return node;\n // FLO-264: honor the block's bounded style tokens in the headless render too, so\n // @bettercms-ai/next output matches the builder canvas + hosted site.\n return (\n <div key={block.id} style={style as CSSProperties}>\n {node}\n </div>\n );\n}\n\nfunction renderBlockInner(block: ContentBlock, ctx: RenderCtx): ReactNode {\n switch (block.type) {\n case \"heading\":\n return renderHeading(block, ctx);\n // `richtext` and `text` carry the same payload and differ only in the authoring surface,\n // so delivery renders them identically — Astro (BcmsBlocks.astro) and the hosted renderer\n // (render-page.ts) both alias them. Next did not, so `richtext` fell to `default: null`\n // and a richtext block rendered NOTHING on a Next site: 200 OK, green build, blank region.\n case \"text\":\n case \"richtext\":\n return renderText(block as TextBlock, ctx);\n case \"image\":\n return renderImage(block, ctx);\n case \"button\":\n return renderButton(block, ctx);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block, ctx);\n case \"columns\":\n return renderColumns(block, ctx);\n case \"form\":\n return renderForm(block, ctx);\n case \"section\":\n return renderSection(block, ctx);\n case \"navbar\":\n return renderNavbar(block, ctx);\n case \"footer\":\n return renderFooter(block, ctx);\n case \"slider\":\n return <BcmsSlider key={block.id} block={block} ctx={ctx} />;\n case \"tabs\":\n return <BcmsTabs key={block.id} block={block} ctx={ctx} />;\n case \"component\":\n return renderComponent(block, ctx);\n default:\n return renderUnhandledBlock(block);\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock, ctx: RenderCtx): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" {...bind(id, \"text\", \"text\", ctx)}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock, ctx: RenderCtx): ReactNode {\n /**\n * `props.level` renders the rich copy AS <hN> — the same markup the hosted renderer emits\n * (src/lib/richtext/heading.ts), assembled by the SAME shared helper so the three lanes cannot\n * drift. Absent ⇒ the ordinary container below, byte-identical to before. A value that is not\n * one line of inline copy falls through rather than nesting paragraphs inside a heading.\n *\n * The heading serialises its structured value to a STRING rather than mounting <PortableText>:\n * the hosted and Astro lanes both emit the string, and `parity.test.ts` compares the markup.\n */\n const level = richtextHeadingLevel(props.level);\n if (level) {\n const heading = headingParts(props, addressFor(id, \"html\", ctx));\n if (heading !== null) {\n const Tag = `h${level}` as \"h1\";\n const binding = heading.address\n ? { \"data-bcms-field\": heading.address, \"data-bcms-kind\": \"richtext\" }\n : {};\n return <Tag key={id} {...binding} dangerouslySetInnerHTML={{ __html: heading.inner }} />;\n }\n }\n\n /**\n * STRUCTURED CONTENT WINS, and until now this lane did not know it existed.\n *\n * The hosted renderer preferred `props.content` over `props.html` and the shared React\n * renderer did too, but this file read `html` unconditionally — so a block whose structured\n * value had diverged from its derived cache rendered the STALE cache on Next sites and the\n * fresh value everywhere else. Silent, per-lane, and green in CI, which is the same shape as\n * the bug that made `richtext` render nothing at all here for a whole release.\n *\n * `addressFor`, not a hand-built `${id}__html`: inside a placed component the address has to\n * be remapped to the instance, or the binding resolves to no field and two instances of one\n * component collide into a duplicate that drops both.\n */\n const structured = readStructuredContent(props);\n if (structured) {\n const base = addressFor(id, \"html\", ctx);\n // A component embedded in the text mounts through the ordinary `component` block.\n const renderEmbed = (value: Record<string, unknown>): ReactNode => {\n const embed = embeddedComponentBlock(value);\n return embed ? renderComponent(embed, { ...ctx, owner: base }) : undefined;\n };\n return (\n <div key={id} className=\"bcms-block bcms-block--text\">\n <PortableText value={structured} {...(base ? { bindingBase: base } : {})} renderBlock={renderEmbed} />\n </div>\n );\n }\n\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n {...bind(id, \"html\", \"richtext\", ctx)}\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\n\nfunction renderImage({ id, props }: ImageBlock, ctx: RenderCtx): ReactNode {\n const img = (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n loading=\"lazy\"\n // Heading/text/button have always been click-to-edit on the Visual Editor canvas because\n // they carry this attribute; the image block did not, so a block page's images were the\n // one thing you could only change from the dock. `kind=\"image\"` keeps it selection-only\n // (no contentEditable on an <img>) while letting the editor reflect a new src live.\n {...bind(id, \"src\", \"image\", ctx)}\n // `alt` rides the props lane: this <img> already carries the src binding and an element\n // cannot hold two addresses. It is also the one image property a screen-reader user\n // depends on, so leaving it dock-only made the canvas worse at the accessibility half.\n {...bindProps(id, [{ prop: \"alt\", kind: \"text\", attr: \"alt\", present: props.alt != null }], ctx)}\n />\n );\n if (!props.caption) {\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n </figure>\n );\n }\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n <figcaption {...bind(id, \"caption\", \"text\", ctx)}>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock, ctx: RenderCtx): ReactNode {\n return (\n <a\n key={id}\n href={props.href}\n className={`bcms-block bcms-block--button bcms-button--${props.variant ?? \"primary\"}`}\n {...bind(id, \"text\", \"text\", ctx)}\n // A URL never takes a caret — typing one onto the page has nowhere to report a malformed\n // value — so it is addressed here and edited in the element toolbar.\n {...bindProps(id, [{ prop: \"href\", kind: \"url\", attr: \"href\", present: props.href != null }], ctx)}\n >\n {props.text}\n </a>\n );\n}\n\nfunction renderSpacer({ id, props }: SpacerBlock): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--spacer\"\n style={{ height: props.height }}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction renderVideo({ id, props }: VideoBlock, ctx: RenderCtx): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\n // A video has no text node at all, so it was the one block a click could not reach: no\n // binding meant no `data-node-id` and nothing to hit-test. Both its values are attributes,\n // so the props lane carries the whole block.\n {...bindProps(\n id,\n [\n { prop: \"url\", kind: \"url\", attr: \"src\", present: props.url != null },\n { prop: \"poster\", kind: \"url\", attr: \"poster\", present: props.poster != null },\n ],\n ctx,\n )}\n autoPlay={props.autoplay}\n loop={props.loop}\n controls\n />\n );\n}\n\nfunction renderColumns({ id, props }: ColumnsBlock, ctx: RenderCtx): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--columns\"\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${props.columns.length || 1}, 1fr)`,\n gap: props.gap,\n }}\n >\n {props.columns.map((column, i) => (\n <div key={i} className=\"bcms-column\">\n {column.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderForm({ id, props }: FormBlock, ctx: RenderCtx): ReactNode {\n const form = ctx.formsById.get(props.formId);\n if (!form) return null; // form deleted or not delivered — render nothing\n return (\n <div key={id} className=\"bcms-block bcms-block--form\">\n <BcmsForm form={form} turnstileSiteKey={ctx.turnstileSiteKey} apiBase={ctx.apiBase} />\n </div>\n );\n}\n\nfunction renderSection({ id, props }: SectionBlock, ctx: RenderCtx): ReactNode {\n const inner = props.children.map((child) => renderBlock(child, ctx));\n return (\n <section\n key={id}\n className=\"bcms-block bcms-block--section\"\n style={{ background: props.background, padding: props.paddingY != null ? `${props.paddingY}px 0` : undefined }}\n >\n {/* 🔴 `bcms-section-inner` — the Astro package and the hosted renderer both class this\n wrapper; Next was the only lane that left it bare. That is not cosmetic: the wrapper\n is CONDITIONAL on `maxWidth`, so a host stylesheet that wants to reach a section's\n children has to target `> div`, which also matches every classed block that happens\n to render as a div (a columns grid, a text block) and restyles their internals. With\n the class there, one selector covers all three lanes and nothing reaches past it.\n Toggling `maxWidth` in the editor must not silently retune a section's rhythm. */}\n {props.maxWidth ? (\n <div className=\"bcms-section-inner\" style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div>\n ) : (\n inner\n )}\n </section>\n );\n}\n\n/**\n * Every link is addressed individually, by index. This was the flagship \"nested under arrays\"\n * exclusion, on the grounds that the writer could not reach it — but `parseFieldPath` and\n * `setFieldPath` have walked N indices since FLO-949 and `setValue` takes any path. Only the\n * offer was missing, so a site's navigation was uneditable on the canvas while being perfectly\n * writable through the dock.\n */\nfunction renderNavbar({ id, props }: NavbarBlock, ctx: RenderCtx): ReactNode {\n return (\n <nav key={id} className=\"bcms-block bcms-block--navbar\">\n {props.logo?.src ? (\n <a className=\"bcms-navbar-logo\" href={props.logo.href ?? \"/\"}>\n <img\n src={props.logo.src}\n alt={props.logo.alt}\n {...bind(id, \"logo.src\", \"image\", ctx)}\n {...bindProps(id, [{ prop: \"logo.alt\", kind: \"text\", attr: \"alt\", present: props.logo.alt != null }], ctx)}\n />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a\n key={i}\n href={l.href}\n {...bind(id, `links[${i}].label`, \"text\", ctx)}\n {...bindProps(id, [{ prop: `links[${i}].href`, kind: \"url\", attr: \"href\", present: l.href != null }], ctx)}\n >\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a\n className=\"bcms-button bcms-button--primary\"\n href={props.cta.href}\n {...bind(id, \"cta.text\", \"text\", ctx)}\n {...bindProps(id, [{ prop: \"cta.href\", kind: \"url\", attr: \"href\", present: props.cta.href != null }], ctx)}\n >\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\n/**\n * A footer link is the deepest addressable thing on a page: `columns[i].links[j].label`, two\n * indices. That is the shape the old grammar note called unaddressable, and the shape the ENTRY\n * lane still refuses — but the two are different problems. The entry cap is about resolving a\n * repeater row's `_id` identity; a block path is direct, so there is no identity to resolve.\n */\nfunction renderFooter({ id, props }: FooterBlock, ctx: RenderCtx): ReactNode {\n return (\n <footer key={id} className=\"bcms-block bcms-block--footer\">\n <div className=\"bcms-footer-cols\">\n {props.columns.map((col, i) => (\n <div key={i} className=\"bcms-footer-col\">\n {col.heading ? <h4 {...bind(id, `columns[${i}].heading`, \"text\", ctx)}>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a\n href={l.href}\n {...bind(id, `columns[${i}].links[${j}].label`, \"text\", ctx)}\n {...bindProps(\n id,\n [{ prop: `columns[${i}].links[${j}].href`, kind: \"url\", attr: \"href\", present: l.href != null }],\n ctx,\n )}\n >\n {l.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? (\n <p className=\"bcms-footer-copy\" {...bind(id, \"copyright\", \"text\", ctx)}>\n {props.copyright}\n </p>\n ) : null}\n </footer>\n );\n}\n\n/**\n * 🔴 `...rest` is load-bearing, not tidiness. `tagTopLevel` stamps a top-level block by\n * `cloneElement`, which sets `data-bcms-block` as a PROP on this component — and a component\n * that does not spread it drops the attribute with no error and no warning. A top-level slider\n * or tabs block then renders perfectly and is invisible to the Visual Editor's section lane:\n * no move, no duplicate, no delete, no presence. Intrinsic elements do not have this failure\n * mode, which is why every other block type was fine and these two were not.\n */\nfunction BcmsSlider({ block, ctx, ...rest }: { block: SliderBlock; ctx: RenderCtx }): ReactElement {\n const { slides } = block.props;\n const [i, setI] = useState(0);\n const go = (n: number) => setI((n + slides.length) % (slides.length || 1));\n return (\n <div className=\"bcms-block bcms-block--slider\" style={{ position: \"relative\" }} {...rest}>\n {slides.map((s, idx) => (\n <div key={s.id} className=\"bcms-slide\" hidden={idx !== i}>\n {s.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n <button type=\"button\" className=\"bcms-slider-prev\" aria-label=\"Previous\" onClick={() => go(i - 1)}>\n ‹\n </button>\n <button type=\"button\" className=\"bcms-slider-next\" aria-label=\"Next\" onClick={() => go(i + 1)}>\n ›\n </button>\n </div>\n );\n}\n\n/** `...rest` for the same reason as <BcmsSlider> above — see its comment. */\nfunction BcmsTabs({ block, ctx, ...rest }: { block: TabsBlock; ctx: RenderCtx }): ReactElement {\n const { tabs } = block.props;\n const [active, setActive] = useState(0);\n return (\n <div className=\"bcms-block bcms-block--tabs\" {...rest}>\n <div className=\"bcms-tablist\" role=\"tablist\">\n {tabs.map((t, idx) => (\n <button\n key={t.id}\n role=\"tab\"\n type=\"button\"\n className=\"bcms-tab\"\n aria-selected={idx === active}\n onClick={() => setActive(idx)}\n {...bind(block.id, `tabs[${idx}].label`, \"text\", ctx)}\n >\n {t.label}\n </button>\n ))}\n </div>\n {tabs.map((t, idx) => (\n <div key={t.id} role=\"tabpanel\" className=\"bcms-tabpanel\" hidden={idx !== active}>\n {t.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Missing-component ids already reported. Module-level so a page that places the same section\n * twenty times logs once, not twenty times — a wall of identical lines is skipped, and this\n * message has to be read.\n */\nconst warnedMissing = new Set<string>();\n\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return renderMissingComponent(props.componentId, ctx);\n if (ctx.depth >= MAX_COMPONENT_DEPTH || ctx.seen.has(def.id)) return null; // cycle/depth guard\n const resolved = applyOverrides<ContentBlock>(def.blockJson, def.props ?? [], props.overrides ?? {});\n // The instance's own addresses replace the definition's for the whole subtree. Without this\n // every stamp inside a component named a block shared by every instance of it: an orphan on\n // one placement, and a duplicate that drops BOTH on two.\n const childCtx: RenderCtx = {\n ...ctx,\n depth: ctx.depth + 1,\n seen: new Set([...ctx.seen, def.id]),\n fieldAddresses: ctx.owner === null ? new Map() : componentInstanceAddresses(id, def.props, ctx.owner),\n owner: undefined,\n };\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--component\"\n data-bcms-component={def.id}\n data-bcms-variant=\"base\"\n data-bcms-instance={id}\n >\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\n}\n\n/**\n * A `component` block whose definition was not delivered.\n *\n * 🔴 This used to be `return null // fail-soft`, and that comment was the bug. A page authored\n * as SECTIONS is a list of `component` blocks and nothing else, so \"fail-soft\" meant the entire\n * page body rendered as nothing while the build stayed green and the site answered 200 — what\n * remained on screen was the layout's own nav and footer. Two live sites were replaced by that\n * on 2026-08-18, and the only reason it was caught is that a human looked at the page.\n *\n * The near-universal cause is a host site that never passes `components` — the SDK's own README\n * example omitted it — so the message names the fix rather than the symptom.\n *\n * Still renders nothing in production: a placeholder box would be worse than a gap on a live\n * customer site. The console line ships in BOTH modes, because it is emitted during the build\n * and the build log is the one place a headless deploy can be inspected after the fact.\n */\nconst warnedUnhandled = new Set<string>();\n\n/**\n * A block type this renderer has no case for.\n *\n * `default: return null` is how `richtext` rendered NOTHING on a Next site for a whole release\n * — 200 OK, green build, blank region, no error anywhere. `collection` is in that state today:\n * it is delivered, the hosted renderer draws it, and this one silently drops it. Saying so out\n * loud does not implement the missing renderer, but it converts an invisible blank into a\n * message that names the type, which is the difference between a bug you find and one you ship.\n */\nfunction renderUnhandledBlock(block: ContentBlock): ReactNode {\n if (!warnedUnhandled.has(block.type)) {\n warnedUnhandled.add(block.type);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] block type \"${block.type}\" has no renderer here, so it rendered NOTHING. ` +\n `The hosted renderer draws it; this SDK does not yet.`,\n );\n }\n return null;\n}\n\nfunction renderMissingComponent(componentId: string, ctx: RenderCtx): ReactNode {\n if (!warnedMissing.has(componentId)) {\n warnedMissing.add(componentId);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] component \"${componentId}\" was not delivered, so this section rendered NOTHING.` +\n (ctx.componentsById.size === 0\n ? ` No components were passed at all — add components={readComponents()} to <BcmsBlocks>.`\n : ` ${ctx.componentsById.size} component(s) were passed but none match. It is probably still a DRAFT: publish it, then rebuild.`),\n );\n }\n if (process.env.NODE_ENV === \"production\") return null;\n return (\n <div\n className=\"bcms-block bcms-block--component-missing\"\n data-bcms-missing-component={componentId}\n style={{\n padding: \"12px 16px\",\n border: \"1px dashed #d4d4d8\",\n borderRadius: 8,\n color: \"#71717a\",\n font: \"500 13px/1.5 system-ui, -apple-system, sans-serif\",\n }}\n >\n Section <code>{componentId}</code> was not delivered.{\" \"}\n {ctx.componentsById.size === 0\n ? \"Pass components={readComponents()} to <BcmsBlocks>.\"\n : \"Publish the component, then rebuild.\"}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsForm> — render a BetterCMS form natively in React, the headless way.\n *\n * Pass a form straight from your content snapshot (`readSnapshot().forms[n]`) or\n * the delivery API. It renders real inputs (no iframe), handles conditional\n * `showIf` fields, URL-query prefill, the honeypot, an optional Turnstile widget,\n * and submits via `@bettercms-ai/sdk`'s `submitForm`. All visible markup is\n * unstyled and class-driven, so the host site owns the look.\n */\n\nimport { lazy, Suspense, useEffect, useMemo, useState, type FormEvent, type ReactElement } from \"react\";\nimport {\n submitForm,\n shouldShowField,\n formInitialValues,\n asStringArray,\n toggleOption,\n type DeliveryForm,\n type DeliveryFormField,\n type FormValue,\n type FormValues,\n type FormSubmitError,\n} from \"@bettercms-ai/sdk\";\n\nconst TURNSTILE_SRC = \"https://challenges.cloudflare.com/turnstile/v0/api.js\";\n\n/**\n * The country-picker phone control, loaded only when a form actually has one.\n *\n * It carries libphonenumber's metadata (~80KB), which no form without a picker should pay\n * for. The import specifier must survive into `dist/form.js` rather than being inlined —\n * see the `external` entry in tsup.config.ts and the dist greps in the tests.\n */\nconst PhoneField = lazy(() => import(\"./phone-field.js\"));\n\n// Field type → native <input type>. Other types render their own element.\nconst INPUT_TYPES: Partial<Record<DeliveryFormField[\"type\"], string>> = {\n text: \"text\",\n email: \"email\",\n phone: \"tel\",\n url: \"url\",\n number: \"number\",\n date: \"date\",\n};\n\nexport interface BcmsFormProps {\n /** A form from your content snapshot or the delivery API. */\n form: DeliveryForm;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Turnstile site key — needed to render the widget when `form.turnstileEnabled`. */\n turnstileSiteKey?: string;\n /** Called with the new submission id after a successful submit (before any redirect). */\n onSubmitted?: (submissionId: string) => void;\n /** Class for the <form> element; field wrappers/status use `bcms-*` classes. */\n className?: string;\n}\n\ntype Status = { state: \"idle\" | \"submitting\" | \"error\" | \"success\"; message?: string };\n\nfunction readPrefill(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const out: Record<string, string> = {};\n new URLSearchParams(window.location.search).forEach((v, k) => {\n out[k] = v;\n });\n return out;\n}\n\nfunction resetTurnstile(): void {\n const t = (globalThis as { turnstile?: { reset: () => void } }).turnstile;\n if (t) {\n try {\n t.reset();\n } catch {\n /* widget not mounted yet */\n }\n }\n}\n\nexport function BcmsForm({\n form,\n apiBase,\n turnstileSiteKey,\n onSubmitted,\n className,\n}: BcmsFormProps): ReactElement {\n const showTurnstile = Boolean(form.turnstileEnabled && turnstileSiteKey);\n const [values, setValues] = useState<FormValues>(() => {\n const init = formInitialValues(form, readPrefill());\n if (form.honeypotField) init[form.honeypotField] = \"\";\n return init;\n });\n const [status, setStatus] = useState<Status>({ state: \"idle\" });\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n // Cloudflare auto-renders any `.cf-turnstile` element once its script is present.\n useEffect(() => {\n if (!showTurnstile || document.querySelector(`script[src=\"${TURNSTILE_SRC}\"]`)) return;\n const script = document.createElement(\"script\");\n script.src = TURNSTILE_SRC;\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n }, [showTurnstile]);\n\n const visibleFields = useMemo(\n () => form.fields.filter((f) => f.type !== \"hidden\" && shouldShowField(f, values)),\n [form.fields, values],\n );\n\n const setValue = (key: string, value: FormValue) =>\n setValues((prev) => ({ ...prev, [key]: value }));\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {\n e.preventDefault();\n setStatus({ state: \"submitting\" });\n setFieldErrors({});\n\n const tokenEl = e.currentTarget.querySelector<HTMLInputElement>(\n '[name=\"cf-turnstile-response\"]',\n );\n const turnstileToken = tokenEl?.value || undefined;\n\n // Drop conditionally-hidden fields so a hidden required field can't block submit;\n // keep hidden-type fields and the honeypot (the API classifies bots on it).\n const data: FormValues = {};\n for (const field of form.fields) {\n if (field.type === \"hidden\" || shouldShowField(field, values)) {\n data[field.key] = values[field.key];\n }\n }\n if (form.honeypotField) data[form.honeypotField] = values[form.honeypotField] ?? \"\";\n\n try {\n const { id } = await submitForm({ formId: form.id, data, turnstileToken, baseUrl: apiBase });\n onSubmitted?.(id);\n if (form.redirectUrl) {\n window.location.href = form.redirectUrl;\n return;\n }\n const reset = formInitialValues(form);\n if (form.honeypotField) reset[form.honeypotField] = \"\";\n setValues(reset);\n setStatus({\n state: \"success\",\n message: form.successMessage ?? \"Thanks! Your submission was received.\",\n });\n resetTurnstile();\n } catch (err) {\n const e2 = err as FormSubmitError;\n if (e2.fieldErrors) setFieldErrors(e2.fieldErrors);\n setStatus({ state: \"error\", message: e2.message || \"Something went wrong. Please try again.\" });\n resetTurnstile();\n }\n }\n\n return (\n // `data-bcms-form` carries the id so the Visual Editor can find THIS form in the\n // preview frame and patch its copy live. Valued rather than bare: the runtime\n // selectors are `form[data-bcms-form]`, which a valued attribute still matches.\n <form className={className} onSubmit={handleSubmit} noValidate data-bcms-form={form.id}>\n {visibleFields.map((field) => (\n <Field\n key={field.key}\n field={field}\n value={values[field.key]}\n error={fieldErrors[field.key]}\n onChange={(v) => setValue(field.key, v)}\n />\n ))}\n\n {form.honeypotField ? (\n <span aria-hidden=\"true\" style={{ position: \"absolute\", left: \"-9999px\" }}>\n <input\n type=\"text\"\n name={form.honeypotField}\n tabIndex={-1}\n autoComplete=\"off\"\n value={String(values[form.honeypotField] ?? \"\")}\n onChange={(e) => setValue(form.honeypotField as string, e.target.value)}\n />\n </span>\n ) : null}\n\n {showTurnstile ? <div className=\"cf-turnstile\" data-sitekey={turnstileSiteKey} /> : null}\n\n <button type=\"submit\" disabled={status.state === \"submitting\"} data-bcms-form-part=\"submit\">\n {status.state === \"submitting\" ? \"Submitting…\" : form.submitLabel ?? \"Submit\"}\n </button>\n\n {status.message ? (\n <p\n className={`bcms-form-status bcms-form-status--${status.state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {status.message}\n </p>\n ) : null}\n </form>\n );\n}\n\ninterface FieldProps {\n field: DeliveryFormField;\n value: FormValue;\n error?: string;\n onChange: (value: FormValue) => void;\n}\n\nfunction Field({ field, value, error, onChange }: FieldProps): ReactElement {\n const required = field.required;\n const errorNode = error ? (\n <span className=\"bcms-field-error\" role=\"alert\">\n {error}\n </span>\n ) : null;\n // Every author-editable string carries a `data-bcms-form-part` so the Visual Editor can\n // repaint it live. A string the dock can edit but cannot mark shows stale on the canvas.\n const helpNode = field.helpText ? (\n <span className=\"bcms-field-help\" data-bcms-form-part=\"help\">\n {field.helpText}\n </span>\n ) : null;\n\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label\n className=\"bcms-field bcms-field--checkbox\"\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <input\n type=\"checkbox\"\n name={field.key}\n required={required}\n checked={Boolean(value)}\n onChange={(e) => onChange(e.target.checked)}\n />{\" \"}\n <span data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </span>\n {helpNode}\n {errorNode}\n </label>\n );\n }\n\n // Pick-one and pick-many are groups of controls, not a single element, so they\n // return their own <fieldset> rather than flowing into the label+control shape\n // below. Without these two branches both fell through to `<input type=\"text\">`.\n if (field.type === \"radio\" || field.type === \"checkboxes\") {\n const multi = field.type === \"checkboxes\";\n const selected = asStringArray(value);\n return (\n <fieldset\n className={`bcms-field bcms-field--${multi ? \"checkboxes\" : \"radio\"}`}\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <legend data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </legend>\n {(field.options ?? []).map((opt) => (\n <label key={opt} className=\"bcms-option\">\n <input\n type={multi ? \"checkbox\" : \"radio\"}\n name={field.key}\n value={opt}\n // `required` on every radio in a group is the native way to demand one\n // choice. On checkboxes it would demand ALL of them, so it is omitted —\n // the API enforces non-empty instead.\n required={!multi && required}\n checked={multi ? selected.includes(opt) : value === opt}\n onChange={(e) =>\n onChange(multi ? toggleOption(value, opt, e.target.checked) : opt)\n }\n />{\" \"}\n <span data-bcms-form-part=\"option\">{opt}</span>\n </label>\n ))}\n {helpNode}\n {errorNode}\n </fieldset>\n );\n }\n\n const str = String(value ?? \"\");\n let control: ReactElement;\n if (field.type === \"textarea\") {\n control = (\n <textarea\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n } else if (field.type === \"select\") {\n control = (\n <select name={field.key} required={required} value={str} onChange={(e) => onChange(e.target.value)}>\n <option value=\"\" disabled>\n Choose…\n </option>\n {(field.options ?? []).map((opt) => (\n <option key={opt} value={opt} data-bcms-form-part=\"option\">\n {opt}\n </option>\n ))}\n </select>\n );\n } else if (field.type === \"phone\" && field.ui?.countryPicker) {\n // The fallback is a usable tel input inside the SAME wrapper, so the host's `.bcms-phone`\n // rules apply before and after the chunk lands and the swap is not a layout surprise.\n control = (\n <Suspense\n fallback={\n <span className=\"bcms-phone\">\n <input type=\"tel\" name={field.key} placeholder={field.placeholder} required={required} value={str} onChange={(e) => onChange(e.target.value)} autoComplete=\"tel\" dir=\"ltr\" />\n </span>\n }\n >\n <PhoneField\n name={field.key}\n value={str}\n onChange={onChange}\n placeholder={field.placeholder}\n required={required}\n defaultCountry={field.ui.defaultCountry}\n />\n </Suspense>\n );\n } else {\n control = (\n <input\n type={INPUT_TYPES[field.type] ?? \"text\"}\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n\n return (\n <p className=\"bcms-field\" data-field={field.key} data-bcms-form-field={field.key}>\n <label data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\n {helpNode}\n {errorNode}\n </p>\n );\n}\n","/**\n * Visual Editor addresses for the Next renderer.\n *\n * The attributes are ALWAYS on, deliberately — a headless site's HTML is the customer's own,\n * `data-bcms-*` is inert for visitors, and there is no request-time draft render to gate them\n * against. That has been true since they were introduced; what was wrong is WHICH address they\n * carried inside a component.\n *\n * A component's block ids belong to the DEFINITION and are shared by every instance of it, so a\n * definition-scoped `<defBlockId>__text` resolves to no field in the loaded entry — the editor\n * logs it as an orphan — and two instances of one component produce the SAME address twice, which\n * `stampNodeIds` numbers as two COPIES of that one orphan (`data-node-index`) rather than two\n * fields: editing either edits nothing, on both. The hosted renderer avoided this by rendering component\n * subtrees unannotated; this one had no equivalent, so it emitted live-looking attributes that\n * bound to nothing. `addresses` fixes it at the source instead: inside an instance the map is\n * authoritative and resolves each declared prop to `<instanceId>__overrides.<key>`.\n */\nimport type { BindingKind } from \"@bettercms-ai/types\";\nimport { formatPropsAttribute } from \"@bettercms-ai/types\";\n\n/** The subset of the render context binding needs. */\nexport interface BindingCtx {\n /** Present only inside a component instance, where it is AUTHORITATIVE. */\n fieldAddresses?: Map<string, string>;\n}\n\n/** The address a write lands on, or null when none exists and nothing should be advertised. */\nexport function addressFor(id: string | undefined, prop: string, ctx: BindingCtx): string | null {\n if (!id) return null;\n const key = `${id}__${prop}`;\n if (ctx.fieldAddresses) return ctx.fieldAddresses.get(key) ?? null;\n return key;\n}\n\n/**\n * Attributes for a value rendered as this element's own content — spread onto the JSX tag.\n * Returns an empty object when unaddressable, so it spreads to nothing.\n */\nexport function bind(\n id: string | undefined,\n prop: string,\n kind: BindingKind,\n ctx: BindingCtx,\n): Record<string, string> {\n const address = addressFor(id, prop, ctx);\n return address ? { \"data-bcms-field\": address, \"data-bcms-kind\": kind } : {};\n}\n\n/**\n * Attributes for values that live in an ATTRIBUTE of this element (`alt`, `href`, a video's\n * `src`). `data-bcms-field` addresses one element and an element cannot hold two, so these ride\n * `data-bcms-props`: `<address>|<kind>|<domAttribute>`, semicolon separated.\n *\n * Entries whose value is absent are dropped: `setFieldPath` refuses to create a final key, so\n * an address for a key the block does not carry is a write the editor would reject.\n */\nexport function bindProps(\n id: string | undefined,\n entries: readonly { prop: string; kind: BindingKind; attr: string; present: boolean }[],\n ctx: BindingCtx,\n): Record<string, string> {\n const resolved = entries.flatMap(({ prop, kind, attr, present }) => {\n if (!present) return [];\n const address = addressFor(id, prop, ctx);\n return address ? [{ address, kind, attr }] : [];\n });\n return resolved.length ? { \"data-bcms-props\": formatPropsAttribute(resolved) } : {};\n}\n"],"mappings":"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","names":["useState","jsx","jsxs","useState"]}
|
package/dist/draft-bridge.js
CHANGED
|
@@ -14,7 +14,7 @@ import { blockStyleToCss } from "@bettercms-ai/types";
|
|
|
14
14
|
import { componentInstanceAddresses } from "@bettercms-ai/types";
|
|
15
15
|
import { applyOverrides } from "@bettercms-ai/ui/resolve";
|
|
16
16
|
import { PortableText } from "@bettercms-ai/ui/blocks";
|
|
17
|
-
import { readStructuredContent } from "@bettercms-ai/richtext";
|
|
17
|
+
import { embeddedComponentBlock, readStructuredContent } from "@bettercms-ai/richtext";
|
|
18
18
|
import { headingParts, richtextHeadingLevel } from "@bettercms-ai/richtext/heading";
|
|
19
19
|
|
|
20
20
|
// src/form.tsx
|
|
@@ -409,7 +409,11 @@ function renderText({ id, props }, ctx) {
|
|
|
409
409
|
const structured = readStructuredContent(props);
|
|
410
410
|
if (structured) {
|
|
411
411
|
const base = addressFor(id, "html", ctx);
|
|
412
|
-
|
|
412
|
+
const renderEmbed = (value) => {
|
|
413
|
+
const embed = embeddedComponentBlock(value);
|
|
414
|
+
return embed ? renderComponent(embed, { ...ctx, owner: base }) : void 0;
|
|
415
|
+
};
|
|
416
|
+
return /* @__PURE__ */ jsx2("div", { className: "bcms-block bcms-block--text", children: /* @__PURE__ */ jsx2(PortableText, { value: structured, ...base ? { bindingBase: base } : {}, renderBlock: renderEmbed }) }, id);
|
|
413
417
|
}
|
|
414
418
|
return /* @__PURE__ */ jsx2(
|
|
415
419
|
"div",
|
|
@@ -614,7 +618,8 @@ function renderComponent({ id, props }, ctx) {
|
|
|
614
618
|
...ctx,
|
|
615
619
|
depth: ctx.depth + 1,
|
|
616
620
|
seen: /* @__PURE__ */ new Set([...ctx.seen, def.id]),
|
|
617
|
-
fieldAddresses: componentInstanceAddresses(id, def.props)
|
|
621
|
+
fieldAddresses: ctx.owner === null ? /* @__PURE__ */ new Map() : componentInstanceAddresses(id, def.props, ctx.owner),
|
|
622
|
+
owner: void 0
|
|
618
623
|
};
|
|
619
624
|
return /* @__PURE__ */ jsx2(
|
|
620
625
|
"div",
|
package/dist/draft-bridge.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/draft-bridge.tsx","../src/blocks.tsx","../src/form.tsx","../src/bindings.ts"],"sourcesContent":["\"use client\";\n/**\n * BcmsDraftBridge — the site half of the visual editor's draft bridge (FLO-1178).\n *\n * Wrap your page's blocks in this instead of calling <BcmsBlocks> directly and the BetterCMS\n * visual editor can re-render your DRAFTS — structure included — with YOUR components and CSS,\n * so the canvas never falls back to the platform's approximate renderer for this site:\n *\n * import { BcmsDraftBridge } from \"@bettercms-ai/next/draft-bridge\";\n * <BcmsDraftBridge slug={slug} blocks={page.blocks} components={readComponents()} … />\n *\n * Standalone (not framed) it renders what <BcmsBlocks> renders inside one marker <div> — the\n * bridge never wakes. Inside the editor, the EDITOR feeds the bridge over postMessage (Storyblok's\n * model): the site never fetches drafts itself, so no credentials ever enter the page.\n *\n * Protocol, all same-origin (the editor serves the site through a same-origin proxy):\n *\n * editor → site { type: \"bcms:bridge-init\" }\n * site → editor { type: \"bcms:bridge-ready\", slug }\n * editor → site { type: \"bcms:draft-doc\", slug, blocks, components? }\n *\n * The acceptance predicate has three parts, all required — (i) `event.origin` equals this\n * page's own origin, (ii) the sender IS the parent frame, (iii) a draft doc is accepted only\n * after this component's own init→ready handshake. A third-party page that iframes the live\n * site sits on a foreign origin, so every message fails (i): the bridge adds zero attack\n * surface to visitors. Draft content riding a push is the same trust tier the site already\n * renders from the CMS snapshot — the editor is the same author surface.\n *\n * Hydration-safe by construction: initial state IS the server-rendered snapshot; a draft doc\n * can only arrive after mount.\n */\nimport { useEffect, useState, type ReactElement } from \"react\";\nimport { BcmsBlocks, type BcmsBlocksProps } from \"./blocks.js\";\n\ntype Doc = { blocks: BcmsBlocksProps[\"blocks\"]; components?: BcmsBlocksProps[\"components\"] };\n\nexport function BcmsDraftBridge({\n slug,\n blocks,\n components,\n ...rest\n}: BcmsBlocksProps & { slug: string }): ReactElement {\n const [doc, setDoc] = useState<Doc>({ blocks, components });\n\n useEffect(() => {\n if (window.parent === window) return;\n let handshaken = false;\n const onMessage = (e: MessageEvent) => {\n if (e.origin !== window.location.origin) return;\n if (e.source !== window.parent) return;\n const d = e.data as { type?: unknown; slug?: unknown; blocks?: unknown; components?: unknown } | null;\n if (!d || typeof d !== \"object\") return;\n if (d.type === \"bcms:bridge-init\") {\n handshaken = true;\n window.parent.postMessage({ type: \"bcms:bridge-ready\", slug }, e.origin);\n return;\n }\n if (!handshaken) return;\n if (d.type === \"bcms:draft-doc\" && d.slug === slug && Array.isArray(d.blocks)) {\n setDoc({\n blocks: d.blocks as Doc[\"blocks\"],\n components: Array.isArray(d.components) ? (d.components as Doc[\"components\"]) : components,\n });\n }\n };\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, [slug, components]);\n\n /**\n * The wrapper is the LANE MARKER, not decoration: the release annotator records this marker as\n * `canvas.lane = \"bridge\"` on the project, which is how the visual editor knows it may frame the\n * real site and push drafts instead of falling back to the platform's approximate renderer. It is\n * emitted framed OR not — a marker that only appeared inside the editor could never be found in\n * the HTML on disk.\n *\n * `display: contents` because the marker must not change the LAYOUT of a page that had no wrapper\n * before. A flex or grid parent lays out its direct children, so a plain <div> here would collapse\n * a row of sections into one item — a visible regression on the very page this is meant to make\n * editable. The annotator greps the attribute, never the box.\n */\n return (\n <div data-bcms-canvas=\"bridge\" style={{ display: \"contents\" }}>\n <BcmsBlocks blocks={doc.blocks} components={doc.components} {...rest} />\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsBlocks> — render a BetterCMS page's block_json natively in React.\n *\n * Pass the `blocks` from a page (delivery API `/content/:slug` → `entry.blocks`)\n * plus the `forms` you read with `readForms()`. Every block type renders to plain,\n * class-driven markup (the host site owns the styling); a `form` block resolves its\n * `formId` against `forms` and renders `<BcmsForm>` inline exactly where the user\n * placed it in the page builder. This is the turnkey \"Webflow\" path — forms show up\n * wherever they were dropped on the page, with no manual wiring.\n *\n * Ships from its own \"use client\" entry (like <BcmsForm>) so it can be rendered from\n * a Next App Router Server Component without breaking the RSC boundary.\n */\n\nimport {\n cloneElement,\n isValidElement,\n useState,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { blockStyleToCss } from \"@bettercms-ai/types\";\nimport type {\n ContentBlock,\n HeadingBlock,\n TextBlock,\n ImageBlock,\n ButtonBlock,\n SpacerBlock,\n VideoBlock,\n ColumnsBlock,\n FormBlock,\n SectionBlock,\n NavbarBlock,\n FooterBlock,\n SliderBlock,\n TabsBlock,\n ComponentBlock,\n DeliveryComponent,\n} from \"@bettercms-ai/types\";\nimport type { DeliveryForm } from \"@bettercms-ai/sdk\";\nimport { componentInstanceAddresses } from \"@bettercms-ai/types\";\nimport { applyOverrides } from \"@bettercms-ai/ui/resolve\";\nimport { PortableText } from \"@bettercms-ai/ui/blocks\";\nimport { readStructuredContent } from \"@bettercms-ai/richtext\";\nimport { headingParts, richtextHeadingLevel } from \"@bettercms-ai/richtext/heading\";\nimport { BcmsForm } from \"./form.js\";\n\nconst MAX_COMPONENT_DEPTH = 10;\n\nexport interface BcmsBlocksProps {\n /** A page's blocks (delivery API `/content/:slug` → `entry.blocks`). */\n blocks: ContentBlock[];\n /** Forms available to `form` blocks — from `readForms().forms`. */\n forms?: DeliveryForm[];\n /** Reusable components available to `component` blocks — from `readComponents()`. */\n components?: DeliveryComponent[];\n /** Turnstile site key — forwarded to `<BcmsForm>` for form blocks. */\n turnstileSiteKey?: string;\n /** API origin forwarded to `<BcmsForm>`. Defaults to the SDK default. */\n apiBase?: string;\n /** Class for the wrapping <div>. */\n className?: string;\n}\n\n/** Render a page's blocks. Unknown/empty blocks render nothing (fail-soft). */\nexport function BcmsBlocks({\n blocks,\n forms,\n components,\n turnstileSiteKey,\n apiBase,\n className,\n}: BcmsBlocksProps): ReactElement {\n const formsById = new Map((forms ?? []).map((f) => [f.id, f]));\n const componentsById = new Map((components ?? []).map((cmp) => [cmp.id, cmp]));\n const ctx: RenderCtx = { formsById, componentsById, turnstileSiteKey, apiBase, depth: 0, seen: new Set() };\n return (\n /**\n * 🔴 `data-bcms-page` marks THIS SUBTREE as ours to edit — the SDK's equivalent of the hosted\n * renderer's `<main class=\"bcms-page\">` (render-page.ts).\n *\n * The Visual Editor decides whether to show section controls by asking the page what it is.\n * Its only test was that hosted wrapper, which an SDK-rendered site never has — so every\n * headless site was treated as \"not ours\", and move/duplicate/delete/reorder stayed hidden\n * on pages that fully support them. Measured on a live SDK site: 34 blocks rendered,\n * 0 recognised.\n *\n * It must sit on the CONTAINER rather than be inferred from the blocks, so that a page with\n * NO blocks yet is still recognised — otherwise there is no way to add the first section,\n * which is exactly the state a new page starts in.\n */\n <div className={className} data-bcms-page=\"\">\n {blocks.map((block) => tagTopLevel(block, renderBlock(block, ctx)))}\n </div>\n );\n}\n\n/**\n * Stamp a TOP-LEVEL block's own id onto the element it rendered.\n *\n * The editor hit-tests `[data-bcms-block]` to find sections — for hover chrome, reorder targets,\n * drop indicators and per-section presence. Blocks already carried `bcms-block` CLASSES, which\n * look equivalent and are not: they are on every block at every depth and carry no id, so they\n * can identify neither which section you are pointing at nor which one to move.\n *\n * 🔴 `cloneElement`, NOT a wrapper `<div>`. The hosted renderer wraps because it assembles HTML\n * strings and has no other option; here an extra element would land inside the customer's own\n * layout, breaking `>` child selectors and any grid/flex parent that counts its children. This\n * adds an attribute and changes no structure.\n *\n * Only the top level is tagged, deliberately: a section is a top-level block, and tagging nested\n * ones would make a column's child look like a section you could drag out of its parent.\n */\nfunction tagTopLevel(block: ContentBlock, node: ReactNode): ReactNode {\n // A block that rendered nothing (unknown type, fail-soft) has nothing to stamp — and stamping\n // a fragment or string would throw.\n if (!isValidElement(node)) return node;\n return cloneElement(node as ReactElement<Record<string, unknown>>, {\n \"data-bcms-block\": block.id,\n });\n}\n\nimport { bind, bindProps, addressFor } from \"./bindings.js\";\n\ninterface RenderCtx {\n formsById: Map<string, DeliveryForm>;\n componentsById: Map<string, DeliveryComponent>;\n turnstileSiteKey?: string;\n apiBase?: string;\n depth: number;\n seen: Set<string>;\n /**\n * Present only inside a component instance, where it is AUTHORITATIVE: it maps the\n * DEFINITION's `<blockId>__<prop>` to this instance's `<id>__overrides.<key>`. A prop the\n * definition does not declare resolves to nothing and is left unannotated, rather than\n * carrying a definition-scoped address that binds to no field.\n */\n fieldAddresses?: Map<string, string>;\n}\n\nfunction renderBlock(block: ContentBlock, ctx: RenderCtx): ReactNode {\n const node = renderBlockInner(block, ctx);\n const style = blockStyleToCss(block.style);\n if (!style || node == null) return node;\n // FLO-264: honor the block's bounded style tokens in the headless render too, so\n // @bettercms-ai/next output matches the builder canvas + hosted site.\n return (\n <div key={block.id} style={style as CSSProperties}>\n {node}\n </div>\n );\n}\n\nfunction renderBlockInner(block: ContentBlock, ctx: RenderCtx): ReactNode {\n switch (block.type) {\n case \"heading\":\n return renderHeading(block, ctx);\n // `richtext` and `text` carry the same payload and differ only in the authoring surface,\n // so delivery renders them identically — Astro (BcmsBlocks.astro) and the hosted renderer\n // (render-page.ts) both alias them. Next did not, so `richtext` fell to `default: null`\n // and a richtext block rendered NOTHING on a Next site: 200 OK, green build, blank region.\n case \"text\":\n case \"richtext\":\n return renderText(block as TextBlock, ctx);\n case \"image\":\n return renderImage(block, ctx);\n case \"button\":\n return renderButton(block, ctx);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block, ctx);\n case \"columns\":\n return renderColumns(block, ctx);\n case \"form\":\n return renderForm(block, ctx);\n case \"section\":\n return renderSection(block, ctx);\n case \"navbar\":\n return renderNavbar(block, ctx);\n case \"footer\":\n return renderFooter(block, ctx);\n case \"slider\":\n return <BcmsSlider key={block.id} block={block} ctx={ctx} />;\n case \"tabs\":\n return <BcmsTabs key={block.id} block={block} ctx={ctx} />;\n case \"component\":\n return renderComponent(block, ctx);\n default:\n return renderUnhandledBlock(block);\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock, ctx: RenderCtx): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" {...bind(id, \"text\", \"text\", ctx)}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock, ctx: RenderCtx): ReactNode {\n /**\n * `props.level` renders the rich copy AS <hN> — the same markup the hosted renderer emits\n * (src/lib/richtext/heading.ts), assembled by the SAME shared helper so the three lanes cannot\n * drift. Absent ⇒ the ordinary container below, byte-identical to before. A value that is not\n * one line of inline copy falls through rather than nesting paragraphs inside a heading.\n *\n * The heading serialises its structured value to a STRING rather than mounting <PortableText>:\n * the hosted and Astro lanes both emit the string, and `parity.test.ts` compares the markup.\n */\n const level = richtextHeadingLevel(props.level);\n if (level) {\n const heading = headingParts(props, addressFor(id, \"html\", ctx));\n if (heading !== null) {\n const Tag = `h${level}` as \"h1\";\n const binding = heading.address\n ? { \"data-bcms-field\": heading.address, \"data-bcms-kind\": \"richtext\" }\n : {};\n return <Tag key={id} {...binding} dangerouslySetInnerHTML={{ __html: heading.inner }} />;\n }\n }\n\n /**\n * STRUCTURED CONTENT WINS, and until now this lane did not know it existed.\n *\n * The hosted renderer preferred `props.content` over `props.html` and the shared React\n * renderer did too, but this file read `html` unconditionally — so a block whose structured\n * value had diverged from its derived cache rendered the STALE cache on Next sites and the\n * fresh value everywhere else. Silent, per-lane, and green in CI, which is the same shape as\n * the bug that made `richtext` render nothing at all here for a whole release.\n *\n * `addressFor`, not a hand-built `${id}__html`: inside a placed component the address has to\n * be remapped to the instance, or the binding resolves to no field and two instances of one\n * component collide into a duplicate that drops both.\n */\n const structured = readStructuredContent(props);\n if (structured) {\n const base = addressFor(id, \"html\", ctx);\n return (\n <div key={id} className=\"bcms-block bcms-block--text\">\n <PortableText value={structured} {...(base ? { bindingBase: base } : {})} />\n </div>\n );\n }\n\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n {...bind(id, \"html\", \"richtext\", ctx)}\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\n\nfunction renderImage({ id, props }: ImageBlock, ctx: RenderCtx): ReactNode {\n const img = (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n loading=\"lazy\"\n // Heading/text/button have always been click-to-edit on the Visual Editor canvas because\n // they carry this attribute; the image block did not, so a block page's images were the\n // one thing you could only change from the dock. `kind=\"image\"` keeps it selection-only\n // (no contentEditable on an <img>) while letting the editor reflect a new src live.\n {...bind(id, \"src\", \"image\", ctx)}\n // `alt` rides the props lane: this <img> already carries the src binding and an element\n // cannot hold two addresses. It is also the one image property a screen-reader user\n // depends on, so leaving it dock-only made the canvas worse at the accessibility half.\n {...bindProps(id, [{ prop: \"alt\", kind: \"text\", attr: \"alt\", present: props.alt != null }], ctx)}\n />\n );\n if (!props.caption) {\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n </figure>\n );\n }\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n <figcaption {...bind(id, \"caption\", \"text\", ctx)}>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock, ctx: RenderCtx): ReactNode {\n return (\n <a\n key={id}\n href={props.href}\n className={`bcms-block bcms-block--button bcms-button--${props.variant ?? \"primary\"}`}\n {...bind(id, \"text\", \"text\", ctx)}\n // A URL never takes a caret — typing one onto the page has nowhere to report a malformed\n // value — so it is addressed here and edited in the element toolbar.\n {...bindProps(id, [{ prop: \"href\", kind: \"url\", attr: \"href\", present: props.href != null }], ctx)}\n >\n {props.text}\n </a>\n );\n}\n\nfunction renderSpacer({ id, props }: SpacerBlock): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--spacer\"\n style={{ height: props.height }}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction renderVideo({ id, props }: VideoBlock, ctx: RenderCtx): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\n // A video has no text node at all, so it was the one block a click could not reach: no\n // binding meant no `data-node-id` and nothing to hit-test. Both its values are attributes,\n // so the props lane carries the whole block.\n {...bindProps(\n id,\n [\n { prop: \"url\", kind: \"url\", attr: \"src\", present: props.url != null },\n { prop: \"poster\", kind: \"url\", attr: \"poster\", present: props.poster != null },\n ],\n ctx,\n )}\n autoPlay={props.autoplay}\n loop={props.loop}\n controls\n />\n );\n}\n\nfunction renderColumns({ id, props }: ColumnsBlock, ctx: RenderCtx): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--columns\"\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${props.columns.length || 1}, 1fr)`,\n gap: props.gap,\n }}\n >\n {props.columns.map((column, i) => (\n <div key={i} className=\"bcms-column\">\n {column.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderForm({ id, props }: FormBlock, ctx: RenderCtx): ReactNode {\n const form = ctx.formsById.get(props.formId);\n if (!form) return null; // form deleted or not delivered — render nothing\n return (\n <div key={id} className=\"bcms-block bcms-block--form\">\n <BcmsForm form={form} turnstileSiteKey={ctx.turnstileSiteKey} apiBase={ctx.apiBase} />\n </div>\n );\n}\n\nfunction renderSection({ id, props }: SectionBlock, ctx: RenderCtx): ReactNode {\n const inner = props.children.map((child) => renderBlock(child, ctx));\n return (\n <section\n key={id}\n className=\"bcms-block bcms-block--section\"\n style={{ background: props.background, padding: props.paddingY != null ? `${props.paddingY}px 0` : undefined }}\n >\n {/* 🔴 `bcms-section-inner` — the Astro package and the hosted renderer both class this\n wrapper; Next was the only lane that left it bare. That is not cosmetic: the wrapper\n is CONDITIONAL on `maxWidth`, so a host stylesheet that wants to reach a section's\n children has to target `> div`, which also matches every classed block that happens\n to render as a div (a columns grid, a text block) and restyles their internals. With\n the class there, one selector covers all three lanes and nothing reaches past it.\n Toggling `maxWidth` in the editor must not silently retune a section's rhythm. */}\n {props.maxWidth ? (\n <div className=\"bcms-section-inner\" style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div>\n ) : (\n inner\n )}\n </section>\n );\n}\n\n/**\n * Every link is addressed individually, by index. This was the flagship \"nested under arrays\"\n * exclusion, on the grounds that the writer could not reach it — but `parseFieldPath` and\n * `setFieldPath` have walked N indices since FLO-949 and `setValue` takes any path. Only the\n * offer was missing, so a site's navigation was uneditable on the canvas while being perfectly\n * writable through the dock.\n */\nfunction renderNavbar({ id, props }: NavbarBlock, ctx: RenderCtx): ReactNode {\n return (\n <nav key={id} className=\"bcms-block bcms-block--navbar\">\n {props.logo?.src ? (\n <a className=\"bcms-navbar-logo\" href={props.logo.href ?? \"/\"}>\n <img\n src={props.logo.src}\n alt={props.logo.alt}\n {...bind(id, \"logo.src\", \"image\", ctx)}\n {...bindProps(id, [{ prop: \"logo.alt\", kind: \"text\", attr: \"alt\", present: props.logo.alt != null }], ctx)}\n />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a\n key={i}\n href={l.href}\n {...bind(id, `links[${i}].label`, \"text\", ctx)}\n {...bindProps(id, [{ prop: `links[${i}].href`, kind: \"url\", attr: \"href\", present: l.href != null }], ctx)}\n >\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a\n className=\"bcms-button bcms-button--primary\"\n href={props.cta.href}\n {...bind(id, \"cta.text\", \"text\", ctx)}\n {...bindProps(id, [{ prop: \"cta.href\", kind: \"url\", attr: \"href\", present: props.cta.href != null }], ctx)}\n >\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\n/**\n * A footer link is the deepest addressable thing on a page: `columns[i].links[j].label`, two\n * indices. That is the shape the old grammar note called unaddressable, and the shape the ENTRY\n * lane still refuses — but the two are different problems. The entry cap is about resolving a\n * repeater row's `_id` identity; a block path is direct, so there is no identity to resolve.\n */\nfunction renderFooter({ id, props }: FooterBlock, ctx: RenderCtx): ReactNode {\n return (\n <footer key={id} className=\"bcms-block bcms-block--footer\">\n <div className=\"bcms-footer-cols\">\n {props.columns.map((col, i) => (\n <div key={i} className=\"bcms-footer-col\">\n {col.heading ? <h4 {...bind(id, `columns[${i}].heading`, \"text\", ctx)}>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a\n href={l.href}\n {...bind(id, `columns[${i}].links[${j}].label`, \"text\", ctx)}\n {...bindProps(\n id,\n [{ prop: `columns[${i}].links[${j}].href`, kind: \"url\", attr: \"href\", present: l.href != null }],\n ctx,\n )}\n >\n {l.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? (\n <p className=\"bcms-footer-copy\" {...bind(id, \"copyright\", \"text\", ctx)}>\n {props.copyright}\n </p>\n ) : null}\n </footer>\n );\n}\n\n/**\n * 🔴 `...rest` is load-bearing, not tidiness. `tagTopLevel` stamps a top-level block by\n * `cloneElement`, which sets `data-bcms-block` as a PROP on this component — and a component\n * that does not spread it drops the attribute with no error and no warning. A top-level slider\n * or tabs block then renders perfectly and is invisible to the Visual Editor's section lane:\n * no move, no duplicate, no delete, no presence. Intrinsic elements do not have this failure\n * mode, which is why every other block type was fine and these two were not.\n */\nfunction BcmsSlider({ block, ctx, ...rest }: { block: SliderBlock; ctx: RenderCtx }): ReactElement {\n const { slides } = block.props;\n const [i, setI] = useState(0);\n const go = (n: number) => setI((n + slides.length) % (slides.length || 1));\n return (\n <div className=\"bcms-block bcms-block--slider\" style={{ position: \"relative\" }} {...rest}>\n {slides.map((s, idx) => (\n <div key={s.id} className=\"bcms-slide\" hidden={idx !== i}>\n {s.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n <button type=\"button\" className=\"bcms-slider-prev\" aria-label=\"Previous\" onClick={() => go(i - 1)}>\n ‹\n </button>\n <button type=\"button\" className=\"bcms-slider-next\" aria-label=\"Next\" onClick={() => go(i + 1)}>\n ›\n </button>\n </div>\n );\n}\n\n/** `...rest` for the same reason as <BcmsSlider> above — see its comment. */\nfunction BcmsTabs({ block, ctx, ...rest }: { block: TabsBlock; ctx: RenderCtx }): ReactElement {\n const { tabs } = block.props;\n const [active, setActive] = useState(0);\n return (\n <div className=\"bcms-block bcms-block--tabs\" {...rest}>\n <div className=\"bcms-tablist\" role=\"tablist\">\n {tabs.map((t, idx) => (\n <button\n key={t.id}\n role=\"tab\"\n type=\"button\"\n className=\"bcms-tab\"\n aria-selected={idx === active}\n onClick={() => setActive(idx)}\n {...bind(block.id, `tabs[${idx}].label`, \"text\", ctx)}\n >\n {t.label}\n </button>\n ))}\n </div>\n {tabs.map((t, idx) => (\n <div key={t.id} role=\"tabpanel\" className=\"bcms-tabpanel\" hidden={idx !== active}>\n {t.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Missing-component ids already reported. Module-level so a page that places the same section\n * twenty times logs once, not twenty times — a wall of identical lines is skipped, and this\n * message has to be read.\n */\nconst warnedMissing = new Set<string>();\n\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return renderMissingComponent(props.componentId, ctx);\n if (ctx.depth >= MAX_COMPONENT_DEPTH || ctx.seen.has(def.id)) return null; // cycle/depth guard\n const resolved = applyOverrides<ContentBlock>(def.blockJson, def.props ?? [], props.overrides ?? {});\n // The instance's own addresses replace the definition's for the whole subtree. Without this\n // every stamp inside a component named a block shared by every instance of it: an orphan on\n // one placement, and a duplicate that drops BOTH on two.\n const childCtx: RenderCtx = {\n ...ctx,\n depth: ctx.depth + 1,\n seen: new Set([...ctx.seen, def.id]),\n fieldAddresses: componentInstanceAddresses(id, def.props),\n };\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--component\"\n data-bcms-component={def.id}\n data-bcms-variant=\"base\"\n data-bcms-instance={id}\n >\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\n}\n\n/**\n * A `component` block whose definition was not delivered.\n *\n * 🔴 This used to be `return null // fail-soft`, and that comment was the bug. A page authored\n * as SECTIONS is a list of `component` blocks and nothing else, so \"fail-soft\" meant the entire\n * page body rendered as nothing while the build stayed green and the site answered 200 — what\n * remained on screen was the layout's own nav and footer. Two live sites were replaced by that\n * on 2026-08-18, and the only reason it was caught is that a human looked at the page.\n *\n * The near-universal cause is a host site that never passes `components` — the SDK's own README\n * example omitted it — so the message names the fix rather than the symptom.\n *\n * Still renders nothing in production: a placeholder box would be worse than a gap on a live\n * customer site. The console line ships in BOTH modes, because it is emitted during the build\n * and the build log is the one place a headless deploy can be inspected after the fact.\n */\nconst warnedUnhandled = new Set<string>();\n\n/**\n * A block type this renderer has no case for.\n *\n * `default: return null` is how `richtext` rendered NOTHING on a Next site for a whole release\n * — 200 OK, green build, blank region, no error anywhere. `collection` is in that state today:\n * it is delivered, the hosted renderer draws it, and this one silently drops it. Saying so out\n * loud does not implement the missing renderer, but it converts an invisible blank into a\n * message that names the type, which is the difference between a bug you find and one you ship.\n */\nfunction renderUnhandledBlock(block: ContentBlock): ReactNode {\n if (!warnedUnhandled.has(block.type)) {\n warnedUnhandled.add(block.type);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] block type \"${block.type}\" has no renderer here, so it rendered NOTHING. ` +\n `The hosted renderer draws it; this SDK does not yet.`,\n );\n }\n return null;\n}\n\nfunction renderMissingComponent(componentId: string, ctx: RenderCtx): ReactNode {\n if (!warnedMissing.has(componentId)) {\n warnedMissing.add(componentId);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] component \"${componentId}\" was not delivered, so this section rendered NOTHING.` +\n (ctx.componentsById.size === 0\n ? ` No components were passed at all — add components={readComponents()} to <BcmsBlocks>.`\n : ` ${ctx.componentsById.size} component(s) were passed but none match. It is probably still a DRAFT: publish it, then rebuild.`),\n );\n }\n if (process.env.NODE_ENV === \"production\") return null;\n return (\n <div\n className=\"bcms-block bcms-block--component-missing\"\n data-bcms-missing-component={componentId}\n style={{\n padding: \"12px 16px\",\n border: \"1px dashed #d4d4d8\",\n borderRadius: 8,\n color: \"#71717a\",\n font: \"500 13px/1.5 system-ui, -apple-system, sans-serif\",\n }}\n >\n Section <code>{componentId}</code> was not delivered.{\" \"}\n {ctx.componentsById.size === 0\n ? \"Pass components={readComponents()} to <BcmsBlocks>.\"\n : \"Publish the component, then rebuild.\"}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsForm> — render a BetterCMS form natively in React, the headless way.\n *\n * Pass a form straight from your content snapshot (`readSnapshot().forms[n]`) or\n * the delivery API. It renders real inputs (no iframe), handles conditional\n * `showIf` fields, URL-query prefill, the honeypot, an optional Turnstile widget,\n * and submits via `@bettercms-ai/sdk`'s `submitForm`. All visible markup is\n * unstyled and class-driven, so the host site owns the look.\n */\n\nimport { lazy, Suspense, useEffect, useMemo, useState, type FormEvent, type ReactElement } from \"react\";\nimport {\n submitForm,\n shouldShowField,\n formInitialValues,\n asStringArray,\n toggleOption,\n type DeliveryForm,\n type DeliveryFormField,\n type FormValue,\n type FormValues,\n type FormSubmitError,\n} from \"@bettercms-ai/sdk\";\n\nconst TURNSTILE_SRC = \"https://challenges.cloudflare.com/turnstile/v0/api.js\";\n\n/**\n * The country-picker phone control, loaded only when a form actually has one.\n *\n * It carries libphonenumber's metadata (~80KB), which no form without a picker should pay\n * for. The import specifier must survive into `dist/form.js` rather than being inlined —\n * see the `external` entry in tsup.config.ts and the dist greps in the tests.\n */\nconst PhoneField = lazy(() => import(\"./phone-field.js\"));\n\n// Field type → native <input type>. Other types render their own element.\nconst INPUT_TYPES: Partial<Record<DeliveryFormField[\"type\"], string>> = {\n text: \"text\",\n email: \"email\",\n phone: \"tel\",\n url: \"url\",\n number: \"number\",\n date: \"date\",\n};\n\nexport interface BcmsFormProps {\n /** A form from your content snapshot or the delivery API. */\n form: DeliveryForm;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Turnstile site key — needed to render the widget when `form.turnstileEnabled`. */\n turnstileSiteKey?: string;\n /** Called with the new submission id after a successful submit (before any redirect). */\n onSubmitted?: (submissionId: string) => void;\n /** Class for the <form> element; field wrappers/status use `bcms-*` classes. */\n className?: string;\n}\n\ntype Status = { state: \"idle\" | \"submitting\" | \"error\" | \"success\"; message?: string };\n\nfunction readPrefill(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const out: Record<string, string> = {};\n new URLSearchParams(window.location.search).forEach((v, k) => {\n out[k] = v;\n });\n return out;\n}\n\nfunction resetTurnstile(): void {\n const t = (globalThis as { turnstile?: { reset: () => void } }).turnstile;\n if (t) {\n try {\n t.reset();\n } catch {\n /* widget not mounted yet */\n }\n }\n}\n\nexport function BcmsForm({\n form,\n apiBase,\n turnstileSiteKey,\n onSubmitted,\n className,\n}: BcmsFormProps): ReactElement {\n const showTurnstile = Boolean(form.turnstileEnabled && turnstileSiteKey);\n const [values, setValues] = useState<FormValues>(() => {\n const init = formInitialValues(form, readPrefill());\n if (form.honeypotField) init[form.honeypotField] = \"\";\n return init;\n });\n const [status, setStatus] = useState<Status>({ state: \"idle\" });\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n // Cloudflare auto-renders any `.cf-turnstile` element once its script is present.\n useEffect(() => {\n if (!showTurnstile || document.querySelector(`script[src=\"${TURNSTILE_SRC}\"]`)) return;\n const script = document.createElement(\"script\");\n script.src = TURNSTILE_SRC;\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n }, [showTurnstile]);\n\n const visibleFields = useMemo(\n () => form.fields.filter((f) => f.type !== \"hidden\" && shouldShowField(f, values)),\n [form.fields, values],\n );\n\n const setValue = (key: string, value: FormValue) =>\n setValues((prev) => ({ ...prev, [key]: value }));\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {\n e.preventDefault();\n setStatus({ state: \"submitting\" });\n setFieldErrors({});\n\n const tokenEl = e.currentTarget.querySelector<HTMLInputElement>(\n '[name=\"cf-turnstile-response\"]',\n );\n const turnstileToken = tokenEl?.value || undefined;\n\n // Drop conditionally-hidden fields so a hidden required field can't block submit;\n // keep hidden-type fields and the honeypot (the API classifies bots on it).\n const data: FormValues = {};\n for (const field of form.fields) {\n if (field.type === \"hidden\" || shouldShowField(field, values)) {\n data[field.key] = values[field.key];\n }\n }\n if (form.honeypotField) data[form.honeypotField] = values[form.honeypotField] ?? \"\";\n\n try {\n const { id } = await submitForm({ formId: form.id, data, turnstileToken, baseUrl: apiBase });\n onSubmitted?.(id);\n if (form.redirectUrl) {\n window.location.href = form.redirectUrl;\n return;\n }\n const reset = formInitialValues(form);\n if (form.honeypotField) reset[form.honeypotField] = \"\";\n setValues(reset);\n setStatus({\n state: \"success\",\n message: form.successMessage ?? \"Thanks! Your submission was received.\",\n });\n resetTurnstile();\n } catch (err) {\n const e2 = err as FormSubmitError;\n if (e2.fieldErrors) setFieldErrors(e2.fieldErrors);\n setStatus({ state: \"error\", message: e2.message || \"Something went wrong. Please try again.\" });\n resetTurnstile();\n }\n }\n\n return (\n // `data-bcms-form` carries the id so the Visual Editor can find THIS form in the\n // preview frame and patch its copy live. Valued rather than bare: the runtime\n // selectors are `form[data-bcms-form]`, which a valued attribute still matches.\n <form className={className} onSubmit={handleSubmit} noValidate data-bcms-form={form.id}>\n {visibleFields.map((field) => (\n <Field\n key={field.key}\n field={field}\n value={values[field.key]}\n error={fieldErrors[field.key]}\n onChange={(v) => setValue(field.key, v)}\n />\n ))}\n\n {form.honeypotField ? (\n <span aria-hidden=\"true\" style={{ position: \"absolute\", left: \"-9999px\" }}>\n <input\n type=\"text\"\n name={form.honeypotField}\n tabIndex={-1}\n autoComplete=\"off\"\n value={String(values[form.honeypotField] ?? \"\")}\n onChange={(e) => setValue(form.honeypotField as string, e.target.value)}\n />\n </span>\n ) : null}\n\n {showTurnstile ? <div className=\"cf-turnstile\" data-sitekey={turnstileSiteKey} /> : null}\n\n <button type=\"submit\" disabled={status.state === \"submitting\"} data-bcms-form-part=\"submit\">\n {status.state === \"submitting\" ? \"Submitting…\" : form.submitLabel ?? \"Submit\"}\n </button>\n\n {status.message ? (\n <p\n className={`bcms-form-status bcms-form-status--${status.state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {status.message}\n </p>\n ) : null}\n </form>\n );\n}\n\ninterface FieldProps {\n field: DeliveryFormField;\n value: FormValue;\n error?: string;\n onChange: (value: FormValue) => void;\n}\n\nfunction Field({ field, value, error, onChange }: FieldProps): ReactElement {\n const required = field.required;\n const errorNode = error ? (\n <span className=\"bcms-field-error\" role=\"alert\">\n {error}\n </span>\n ) : null;\n // Every author-editable string carries a `data-bcms-form-part` so the Visual Editor can\n // repaint it live. A string the dock can edit but cannot mark shows stale on the canvas.\n const helpNode = field.helpText ? (\n <span className=\"bcms-field-help\" data-bcms-form-part=\"help\">\n {field.helpText}\n </span>\n ) : null;\n\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label\n className=\"bcms-field bcms-field--checkbox\"\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <input\n type=\"checkbox\"\n name={field.key}\n required={required}\n checked={Boolean(value)}\n onChange={(e) => onChange(e.target.checked)}\n />{\" \"}\n <span data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </span>\n {helpNode}\n {errorNode}\n </label>\n );\n }\n\n // Pick-one and pick-many are groups of controls, not a single element, so they\n // return their own <fieldset> rather than flowing into the label+control shape\n // below. Without these two branches both fell through to `<input type=\"text\">`.\n if (field.type === \"radio\" || field.type === \"checkboxes\") {\n const multi = field.type === \"checkboxes\";\n const selected = asStringArray(value);\n return (\n <fieldset\n className={`bcms-field bcms-field--${multi ? \"checkboxes\" : \"radio\"}`}\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <legend data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </legend>\n {(field.options ?? []).map((opt) => (\n <label key={opt} className=\"bcms-option\">\n <input\n type={multi ? \"checkbox\" : \"radio\"}\n name={field.key}\n value={opt}\n // `required` on every radio in a group is the native way to demand one\n // choice. On checkboxes it would demand ALL of them, so it is omitted —\n // the API enforces non-empty instead.\n required={!multi && required}\n checked={multi ? selected.includes(opt) : value === opt}\n onChange={(e) =>\n onChange(multi ? toggleOption(value, opt, e.target.checked) : opt)\n }\n />{\" \"}\n <span data-bcms-form-part=\"option\">{opt}</span>\n </label>\n ))}\n {helpNode}\n {errorNode}\n </fieldset>\n );\n }\n\n const str = String(value ?? \"\");\n let control: ReactElement;\n if (field.type === \"textarea\") {\n control = (\n <textarea\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n } else if (field.type === \"select\") {\n control = (\n <select name={field.key} required={required} value={str} onChange={(e) => onChange(e.target.value)}>\n <option value=\"\" disabled>\n Choose…\n </option>\n {(field.options ?? []).map((opt) => (\n <option key={opt} value={opt} data-bcms-form-part=\"option\">\n {opt}\n </option>\n ))}\n </select>\n );\n } else if (field.type === \"phone\" && field.ui?.countryPicker) {\n // The fallback is a usable tel input inside the SAME wrapper, so the host's `.bcms-phone`\n // rules apply before and after the chunk lands and the swap is not a layout surprise.\n control = (\n <Suspense\n fallback={\n <span className=\"bcms-phone\">\n <input type=\"tel\" name={field.key} placeholder={field.placeholder} required={required} value={str} onChange={(e) => onChange(e.target.value)} autoComplete=\"tel\" dir=\"ltr\" />\n </span>\n }\n >\n <PhoneField\n name={field.key}\n value={str}\n onChange={onChange}\n placeholder={field.placeholder}\n required={required}\n defaultCountry={field.ui.defaultCountry}\n />\n </Suspense>\n );\n } else {\n control = (\n <input\n type={INPUT_TYPES[field.type] ?? \"text\"}\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n\n return (\n <p className=\"bcms-field\" data-field={field.key} data-bcms-form-field={field.key}>\n <label data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\n {helpNode}\n {errorNode}\n </p>\n );\n}\n","/**\n * Visual Editor addresses for the Next renderer.\n *\n * The attributes are ALWAYS on, deliberately — a headless site's HTML is the customer's own,\n * `data-bcms-*` is inert for visitors, and there is no request-time draft render to gate them\n * against. That has been true since they were introduced; what was wrong is WHICH address they\n * carried inside a component.\n *\n * A component's block ids belong to the DEFINITION and are shared by every instance of it, so a\n * definition-scoped `<defBlockId>__text` resolves to no field in the loaded entry — the editor\n * logs it as an orphan — and two instances of one component produce the SAME address twice, which\n * `stampNodeIds` numbers as two COPIES of that one orphan (`data-node-index`) rather than two\n * fields: editing either edits nothing, on both. The hosted renderer avoided this by rendering component\n * subtrees unannotated; this one had no equivalent, so it emitted live-looking attributes that\n * bound to nothing. `addresses` fixes it at the source instead: inside an instance the map is\n * authoritative and resolves each declared prop to `<instanceId>__overrides.<key>`.\n */\nimport type { BindingKind } from \"@bettercms-ai/types\";\nimport { formatPropsAttribute } from \"@bettercms-ai/types\";\n\n/** The subset of the render context binding needs. */\nexport interface BindingCtx {\n /** Present only inside a component instance, where it is AUTHORITATIVE. */\n fieldAddresses?: Map<string, string>;\n}\n\n/** The address a write lands on, or null when none exists and nothing should be advertised. */\nexport function addressFor(id: string | undefined, prop: string, ctx: BindingCtx): string | null {\n if (!id) return null;\n const key = `${id}__${prop}`;\n if (ctx.fieldAddresses) return ctx.fieldAddresses.get(key) ?? null;\n return key;\n}\n\n/**\n * Attributes for a value rendered as this element's own content — spread onto the JSX tag.\n * Returns an empty object when unaddressable, so it spreads to nothing.\n */\nexport function bind(\n id: string | undefined,\n prop: string,\n kind: BindingKind,\n ctx: BindingCtx,\n): Record<string, string> {\n const address = addressFor(id, prop, ctx);\n return address ? { \"data-bcms-field\": address, \"data-bcms-kind\": kind } : {};\n}\n\n/**\n * Attributes for values that live in an ATTRIBUTE of this element (`alt`, `href`, a video's\n * `src`). `data-bcms-field` addresses one element and an element cannot hold two, so these ride\n * `data-bcms-props`: `<address>|<kind>|<domAttribute>`, semicolon separated.\n *\n * Entries whose value is absent are dropped: `setFieldPath` refuses to create a final key, so\n * an address for a key the block does not carry is a write the editor would reject.\n */\nexport function bindProps(\n id: string | undefined,\n entries: readonly { prop: string; kind: BindingKind; attr: string; present: boolean }[],\n ctx: BindingCtx,\n): Record<string, string> {\n const resolved = entries.flatMap(({ prop, kind, attr, present }) => {\n if (!present) return [];\n const address = addressFor(id, prop, ctx);\n return address ? [{ address, kind, attr }] : [];\n });\n return resolved.length ? { \"data-bcms-props\": formatPropsAttribute(resolved) } : {};\n}\n"],"mappings":"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","names":["useEffect","useState","useState","jsx","jsxs","useState","jsx","useState","useEffect"]}
|
|
1
|
+
{"version":3,"sources":["../src/draft-bridge.tsx","../src/blocks.tsx","../src/form.tsx","../src/bindings.ts"],"sourcesContent":["\"use client\";\n/**\n * BcmsDraftBridge — the site half of the visual editor's draft bridge (FLO-1178).\n *\n * Wrap your page's blocks in this instead of calling <BcmsBlocks> directly and the BetterCMS\n * visual editor can re-render your DRAFTS — structure included — with YOUR components and CSS,\n * so the canvas never falls back to the platform's approximate renderer for this site:\n *\n * import { BcmsDraftBridge } from \"@bettercms-ai/next/draft-bridge\";\n * <BcmsDraftBridge slug={slug} blocks={page.blocks} components={readComponents()} … />\n *\n * Standalone (not framed) it renders what <BcmsBlocks> renders inside one marker <div> — the\n * bridge never wakes. Inside the editor, the EDITOR feeds the bridge over postMessage (Storyblok's\n * model): the site never fetches drafts itself, so no credentials ever enter the page.\n *\n * Protocol, all same-origin (the editor serves the site through a same-origin proxy):\n *\n * editor → site { type: \"bcms:bridge-init\" }\n * site → editor { type: \"bcms:bridge-ready\", slug }\n * editor → site { type: \"bcms:draft-doc\", slug, blocks, components? }\n *\n * The acceptance predicate has three parts, all required — (i) `event.origin` equals this\n * page's own origin, (ii) the sender IS the parent frame, (iii) a draft doc is accepted only\n * after this component's own init→ready handshake. A third-party page that iframes the live\n * site sits on a foreign origin, so every message fails (i): the bridge adds zero attack\n * surface to visitors. Draft content riding a push is the same trust tier the site already\n * renders from the CMS snapshot — the editor is the same author surface.\n *\n * Hydration-safe by construction: initial state IS the server-rendered snapshot; a draft doc\n * can only arrive after mount.\n */\nimport { useEffect, useState, type ReactElement } from \"react\";\nimport { BcmsBlocks, type BcmsBlocksProps } from \"./blocks.js\";\n\ntype Doc = { blocks: BcmsBlocksProps[\"blocks\"]; components?: BcmsBlocksProps[\"components\"] };\n\nexport function BcmsDraftBridge({\n slug,\n blocks,\n components,\n ...rest\n}: BcmsBlocksProps & { slug: string }): ReactElement {\n const [doc, setDoc] = useState<Doc>({ blocks, components });\n\n useEffect(() => {\n if (window.parent === window) return;\n let handshaken = false;\n const onMessage = (e: MessageEvent) => {\n if (e.origin !== window.location.origin) return;\n if (e.source !== window.parent) return;\n const d = e.data as { type?: unknown; slug?: unknown; blocks?: unknown; components?: unknown } | null;\n if (!d || typeof d !== \"object\") return;\n if (d.type === \"bcms:bridge-init\") {\n handshaken = true;\n window.parent.postMessage({ type: \"bcms:bridge-ready\", slug }, e.origin);\n return;\n }\n if (!handshaken) return;\n if (d.type === \"bcms:draft-doc\" && d.slug === slug && Array.isArray(d.blocks)) {\n setDoc({\n blocks: d.blocks as Doc[\"blocks\"],\n components: Array.isArray(d.components) ? (d.components as Doc[\"components\"]) : components,\n });\n }\n };\n window.addEventListener(\"message\", onMessage);\n return () => window.removeEventListener(\"message\", onMessage);\n }, [slug, components]);\n\n /**\n * The wrapper is the LANE MARKER, not decoration: the release annotator records this marker as\n * `canvas.lane = \"bridge\"` on the project, which is how the visual editor knows it may frame the\n * real site and push drafts instead of falling back to the platform's approximate renderer. It is\n * emitted framed OR not — a marker that only appeared inside the editor could never be found in\n * the HTML on disk.\n *\n * `display: contents` because the marker must not change the LAYOUT of a page that had no wrapper\n * before. A flex or grid parent lays out its direct children, so a plain <div> here would collapse\n * a row of sections into one item — a visible regression on the very page this is meant to make\n * editable. The annotator greps the attribute, never the box.\n */\n return (\n <div data-bcms-canvas=\"bridge\" style={{ display: \"contents\" }}>\n <BcmsBlocks blocks={doc.blocks} components={doc.components} {...rest} />\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsBlocks> — render a BetterCMS page's block_json natively in React.\n *\n * Pass the `blocks` from a page (delivery API `/content/:slug` → `entry.blocks`)\n * plus the `forms` you read with `readForms()`. Every block type renders to plain,\n * class-driven markup (the host site owns the styling); a `form` block resolves its\n * `formId` against `forms` and renders `<BcmsForm>` inline exactly where the user\n * placed it in the page builder. This is the turnkey \"Webflow\" path — forms show up\n * wherever they were dropped on the page, with no manual wiring.\n *\n * Ships from its own \"use client\" entry (like <BcmsForm>) so it can be rendered from\n * a Next App Router Server Component without breaking the RSC boundary.\n */\n\nimport {\n cloneElement,\n isValidElement,\n useState,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n} from \"react\";\nimport { blockStyleToCss } from \"@bettercms-ai/types\";\nimport type {\n ContentBlock,\n HeadingBlock,\n TextBlock,\n ImageBlock,\n ButtonBlock,\n SpacerBlock,\n VideoBlock,\n ColumnsBlock,\n FormBlock,\n SectionBlock,\n NavbarBlock,\n FooterBlock,\n SliderBlock,\n TabsBlock,\n ComponentBlock,\n DeliveryComponent,\n} from \"@bettercms-ai/types\";\nimport type { DeliveryForm } from \"@bettercms-ai/sdk\";\nimport { componentInstanceAddresses } from \"@bettercms-ai/types\";\nimport { applyOverrides } from \"@bettercms-ai/ui/resolve\";\nimport { PortableText } from \"@bettercms-ai/ui/blocks\";\nimport { embeddedComponentBlock, readStructuredContent } from \"@bettercms-ai/richtext\";\nimport { headingParts, richtextHeadingLevel } from \"@bettercms-ai/richtext/heading\";\nimport { BcmsForm } from \"./form.js\";\n\nconst MAX_COMPONENT_DEPTH = 10;\n\nexport interface BcmsBlocksProps {\n /** A page's blocks (delivery API `/content/:slug` → `entry.blocks`). */\n blocks: ContentBlock[];\n /** Forms available to `form` blocks — from `readForms().forms`. */\n forms?: DeliveryForm[];\n /** Reusable components available to `component` blocks — from `readComponents()`. */\n components?: DeliveryComponent[];\n /** Turnstile site key — forwarded to `<BcmsForm>` for form blocks. */\n turnstileSiteKey?: string;\n /** API origin forwarded to `<BcmsForm>`. Defaults to the SDK default. */\n apiBase?: string;\n /** Class for the wrapping <div>. */\n className?: string;\n}\n\n/** Render a page's blocks. Unknown/empty blocks render nothing (fail-soft). */\nexport function BcmsBlocks({\n blocks,\n forms,\n components,\n turnstileSiteKey,\n apiBase,\n className,\n}: BcmsBlocksProps): ReactElement {\n const formsById = new Map((forms ?? []).map((f) => [f.id, f]));\n const componentsById = new Map((components ?? []).map((cmp) => [cmp.id, cmp]));\n const ctx: RenderCtx = { formsById, componentsById, turnstileSiteKey, apiBase, depth: 0, seen: new Set() };\n return (\n /**\n * 🔴 `data-bcms-page` marks THIS SUBTREE as ours to edit — the SDK's equivalent of the hosted\n * renderer's `<main class=\"bcms-page\">` (render-page.ts).\n *\n * The Visual Editor decides whether to show section controls by asking the page what it is.\n * Its only test was that hosted wrapper, which an SDK-rendered site never has — so every\n * headless site was treated as \"not ours\", and move/duplicate/delete/reorder stayed hidden\n * on pages that fully support them. Measured on a live SDK site: 34 blocks rendered,\n * 0 recognised.\n *\n * It must sit on the CONTAINER rather than be inferred from the blocks, so that a page with\n * NO blocks yet is still recognised — otherwise there is no way to add the first section,\n * which is exactly the state a new page starts in.\n */\n <div className={className} data-bcms-page=\"\">\n {blocks.map((block) => tagTopLevel(block, renderBlock(block, ctx)))}\n </div>\n );\n}\n\n/**\n * Stamp a TOP-LEVEL block's own id onto the element it rendered.\n *\n * The editor hit-tests `[data-bcms-block]` to find sections — for hover chrome, reorder targets,\n * drop indicators and per-section presence. Blocks already carried `bcms-block` CLASSES, which\n * look equivalent and are not: they are on every block at every depth and carry no id, so they\n * can identify neither which section you are pointing at nor which one to move.\n *\n * 🔴 `cloneElement`, NOT a wrapper `<div>`. The hosted renderer wraps because it assembles HTML\n * strings and has no other option; here an extra element would land inside the customer's own\n * layout, breaking `>` child selectors and any grid/flex parent that counts its children. This\n * adds an attribute and changes no structure.\n *\n * Only the top level is tagged, deliberately: a section is a top-level block, and tagging nested\n * ones would make a column's child look like a section you could drag out of its parent.\n */\nfunction tagTopLevel(block: ContentBlock, node: ReactNode): ReactNode {\n // A block that rendered nothing (unknown type, fail-soft) has nothing to stamp — and stamping\n // a fragment or string would throw.\n if (!isValidElement(node)) return node;\n return cloneElement(node as ReactElement<Record<string, unknown>>, {\n \"data-bcms-block\": block.id,\n });\n}\n\nimport { bind, bindProps, addressFor } from \"./bindings.js\";\n\ninterface RenderCtx {\n formsById: Map<string, DeliveryForm>;\n componentsById: Map<string, DeliveryComponent>;\n turnstileSiteKey?: string;\n apiBase?: string;\n depth: number;\n seen: Set<string>;\n /**\n * Present only inside a component instance, where it is AUTHORITATIVE: it maps the\n * DEFINITION's `<blockId>__<prop>` to this instance's `<id>__overrides.<key>`. A prop the\n * definition does not declare resolves to nothing and is left unannotated, rather than\n * carrying a definition-scoped address that binds to no field.\n */\n fieldAddresses?: Map<string, string>;\n /**\n * Set only for a component EMBEDDED in rich text: the rich-text field's address, which names\n * the instance (`<owner>#<_key>`), or null when that field has none — so the embed gets no\n * addresses rather than a bare `_key` that resolves to nothing.\n */\n owner?: string | null;\n}\n\nfunction renderBlock(block: ContentBlock, ctx: RenderCtx): ReactNode {\n const node = renderBlockInner(block, ctx);\n const style = blockStyleToCss(block.style);\n if (!style || node == null) return node;\n // FLO-264: honor the block's bounded style tokens in the headless render too, so\n // @bettercms-ai/next output matches the builder canvas + hosted site.\n return (\n <div key={block.id} style={style as CSSProperties}>\n {node}\n </div>\n );\n}\n\nfunction renderBlockInner(block: ContentBlock, ctx: RenderCtx): ReactNode {\n switch (block.type) {\n case \"heading\":\n return renderHeading(block, ctx);\n // `richtext` and `text` carry the same payload and differ only in the authoring surface,\n // so delivery renders them identically — Astro (BcmsBlocks.astro) and the hosted renderer\n // (render-page.ts) both alias them. Next did not, so `richtext` fell to `default: null`\n // and a richtext block rendered NOTHING on a Next site: 200 OK, green build, blank region.\n case \"text\":\n case \"richtext\":\n return renderText(block as TextBlock, ctx);\n case \"image\":\n return renderImage(block, ctx);\n case \"button\":\n return renderButton(block, ctx);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block, ctx);\n case \"columns\":\n return renderColumns(block, ctx);\n case \"form\":\n return renderForm(block, ctx);\n case \"section\":\n return renderSection(block, ctx);\n case \"navbar\":\n return renderNavbar(block, ctx);\n case \"footer\":\n return renderFooter(block, ctx);\n case \"slider\":\n return <BcmsSlider key={block.id} block={block} ctx={ctx} />;\n case \"tabs\":\n return <BcmsTabs key={block.id} block={block} ctx={ctx} />;\n case \"component\":\n return renderComponent(block, ctx);\n default:\n return renderUnhandledBlock(block);\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock, ctx: RenderCtx): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" {...bind(id, \"text\", \"text\", ctx)}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock, ctx: RenderCtx): ReactNode {\n /**\n * `props.level` renders the rich copy AS <hN> — the same markup the hosted renderer emits\n * (src/lib/richtext/heading.ts), assembled by the SAME shared helper so the three lanes cannot\n * drift. Absent ⇒ the ordinary container below, byte-identical to before. A value that is not\n * one line of inline copy falls through rather than nesting paragraphs inside a heading.\n *\n * The heading serialises its structured value to a STRING rather than mounting <PortableText>:\n * the hosted and Astro lanes both emit the string, and `parity.test.ts` compares the markup.\n */\n const level = richtextHeadingLevel(props.level);\n if (level) {\n const heading = headingParts(props, addressFor(id, \"html\", ctx));\n if (heading !== null) {\n const Tag = `h${level}` as \"h1\";\n const binding = heading.address\n ? { \"data-bcms-field\": heading.address, \"data-bcms-kind\": \"richtext\" }\n : {};\n return <Tag key={id} {...binding} dangerouslySetInnerHTML={{ __html: heading.inner }} />;\n }\n }\n\n /**\n * STRUCTURED CONTENT WINS, and until now this lane did not know it existed.\n *\n * The hosted renderer preferred `props.content` over `props.html` and the shared React\n * renderer did too, but this file read `html` unconditionally — so a block whose structured\n * value had diverged from its derived cache rendered the STALE cache on Next sites and the\n * fresh value everywhere else. Silent, per-lane, and green in CI, which is the same shape as\n * the bug that made `richtext` render nothing at all here for a whole release.\n *\n * `addressFor`, not a hand-built `${id}__html`: inside a placed component the address has to\n * be remapped to the instance, or the binding resolves to no field and two instances of one\n * component collide into a duplicate that drops both.\n */\n const structured = readStructuredContent(props);\n if (structured) {\n const base = addressFor(id, \"html\", ctx);\n // A component embedded in the text mounts through the ordinary `component` block.\n const renderEmbed = (value: Record<string, unknown>): ReactNode => {\n const embed = embeddedComponentBlock(value);\n return embed ? renderComponent(embed, { ...ctx, owner: base }) : undefined;\n };\n return (\n <div key={id} className=\"bcms-block bcms-block--text\">\n <PortableText value={structured} {...(base ? { bindingBase: base } : {})} renderBlock={renderEmbed} />\n </div>\n );\n }\n\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n {...bind(id, \"html\", \"richtext\", ctx)}\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\n\nfunction renderImage({ id, props }: ImageBlock, ctx: RenderCtx): ReactNode {\n const img = (\n <img\n src={props.src}\n alt={props.alt}\n width={props.width}\n height={props.height}\n loading=\"lazy\"\n // Heading/text/button have always been click-to-edit on the Visual Editor canvas because\n // they carry this attribute; the image block did not, so a block page's images were the\n // one thing you could only change from the dock. `kind=\"image\"` keeps it selection-only\n // (no contentEditable on an <img>) while letting the editor reflect a new src live.\n {...bind(id, \"src\", \"image\", ctx)}\n // `alt` rides the props lane: this <img> already carries the src binding and an element\n // cannot hold two addresses. It is also the one image property a screen-reader user\n // depends on, so leaving it dock-only made the canvas worse at the accessibility half.\n {...bindProps(id, [{ prop: \"alt\", kind: \"text\", attr: \"alt\", present: props.alt != null }], ctx)}\n />\n );\n if (!props.caption) {\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n </figure>\n );\n }\n return (\n <figure key={id} className=\"bcms-block bcms-block--image\">\n {img}\n <figcaption {...bind(id, \"caption\", \"text\", ctx)}>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock, ctx: RenderCtx): ReactNode {\n return (\n <a\n key={id}\n href={props.href}\n className={`bcms-block bcms-block--button bcms-button--${props.variant ?? \"primary\"}`}\n {...bind(id, \"text\", \"text\", ctx)}\n // A URL never takes a caret — typing one onto the page has nowhere to report a malformed\n // value — so it is addressed here and edited in the element toolbar.\n {...bindProps(id, [{ prop: \"href\", kind: \"url\", attr: \"href\", present: props.href != null }], ctx)}\n >\n {props.text}\n </a>\n );\n}\n\nfunction renderSpacer({ id, props }: SpacerBlock): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--spacer\"\n style={{ height: props.height }}\n aria-hidden=\"true\"\n />\n );\n}\n\nfunction renderVideo({ id, props }: VideoBlock, ctx: RenderCtx): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\n // A video has no text node at all, so it was the one block a click could not reach: no\n // binding meant no `data-node-id` and nothing to hit-test. Both its values are attributes,\n // so the props lane carries the whole block.\n {...bindProps(\n id,\n [\n { prop: \"url\", kind: \"url\", attr: \"src\", present: props.url != null },\n { prop: \"poster\", kind: \"url\", attr: \"poster\", present: props.poster != null },\n ],\n ctx,\n )}\n autoPlay={props.autoplay}\n loop={props.loop}\n controls\n />\n );\n}\n\nfunction renderColumns({ id, props }: ColumnsBlock, ctx: RenderCtx): ReactNode {\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--columns\"\n style={{\n display: \"grid\",\n gridTemplateColumns: `repeat(${props.columns.length || 1}, 1fr)`,\n gap: props.gap,\n }}\n >\n {props.columns.map((column, i) => (\n <div key={i} className=\"bcms-column\">\n {column.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\nfunction renderForm({ id, props }: FormBlock, ctx: RenderCtx): ReactNode {\n const form = ctx.formsById.get(props.formId);\n if (!form) return null; // form deleted or not delivered — render nothing\n return (\n <div key={id} className=\"bcms-block bcms-block--form\">\n <BcmsForm form={form} turnstileSiteKey={ctx.turnstileSiteKey} apiBase={ctx.apiBase} />\n </div>\n );\n}\n\nfunction renderSection({ id, props }: SectionBlock, ctx: RenderCtx): ReactNode {\n const inner = props.children.map((child) => renderBlock(child, ctx));\n return (\n <section\n key={id}\n className=\"bcms-block bcms-block--section\"\n style={{ background: props.background, padding: props.paddingY != null ? `${props.paddingY}px 0` : undefined }}\n >\n {/* 🔴 `bcms-section-inner` — the Astro package and the hosted renderer both class this\n wrapper; Next was the only lane that left it bare. That is not cosmetic: the wrapper\n is CONDITIONAL on `maxWidth`, so a host stylesheet that wants to reach a section's\n children has to target `> div`, which also matches every classed block that happens\n to render as a div (a columns grid, a text block) and restyles their internals. With\n the class there, one selector covers all three lanes and nothing reaches past it.\n Toggling `maxWidth` in the editor must not silently retune a section's rhythm. */}\n {props.maxWidth ? (\n <div className=\"bcms-section-inner\" style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div>\n ) : (\n inner\n )}\n </section>\n );\n}\n\n/**\n * Every link is addressed individually, by index. This was the flagship \"nested under arrays\"\n * exclusion, on the grounds that the writer could not reach it — but `parseFieldPath` and\n * `setFieldPath` have walked N indices since FLO-949 and `setValue` takes any path. Only the\n * offer was missing, so a site's navigation was uneditable on the canvas while being perfectly\n * writable through the dock.\n */\nfunction renderNavbar({ id, props }: NavbarBlock, ctx: RenderCtx): ReactNode {\n return (\n <nav key={id} className=\"bcms-block bcms-block--navbar\">\n {props.logo?.src ? (\n <a className=\"bcms-navbar-logo\" href={props.logo.href ?? \"/\"}>\n <img\n src={props.logo.src}\n alt={props.logo.alt}\n {...bind(id, \"logo.src\", \"image\", ctx)}\n {...bindProps(id, [{ prop: \"logo.alt\", kind: \"text\", attr: \"alt\", present: props.logo.alt != null }], ctx)}\n />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a\n key={i}\n href={l.href}\n {...bind(id, `links[${i}].label`, \"text\", ctx)}\n {...bindProps(id, [{ prop: `links[${i}].href`, kind: \"url\", attr: \"href\", present: l.href != null }], ctx)}\n >\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a\n className=\"bcms-button bcms-button--primary\"\n href={props.cta.href}\n {...bind(id, \"cta.text\", \"text\", ctx)}\n {...bindProps(id, [{ prop: \"cta.href\", kind: \"url\", attr: \"href\", present: props.cta.href != null }], ctx)}\n >\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\n/**\n * A footer link is the deepest addressable thing on a page: `columns[i].links[j].label`, two\n * indices. That is the shape the old grammar note called unaddressable, and the shape the ENTRY\n * lane still refuses — but the two are different problems. The entry cap is about resolving a\n * repeater row's `_id` identity; a block path is direct, so there is no identity to resolve.\n */\nfunction renderFooter({ id, props }: FooterBlock, ctx: RenderCtx): ReactNode {\n return (\n <footer key={id} className=\"bcms-block bcms-block--footer\">\n <div className=\"bcms-footer-cols\">\n {props.columns.map((col, i) => (\n <div key={i} className=\"bcms-footer-col\">\n {col.heading ? <h4 {...bind(id, `columns[${i}].heading`, \"text\", ctx)}>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a\n href={l.href}\n {...bind(id, `columns[${i}].links[${j}].label`, \"text\", ctx)}\n {...bindProps(\n id,\n [{ prop: `columns[${i}].links[${j}].href`, kind: \"url\", attr: \"href\", present: l.href != null }],\n ctx,\n )}\n >\n {l.label}\n </a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? (\n <p className=\"bcms-footer-copy\" {...bind(id, \"copyright\", \"text\", ctx)}>\n {props.copyright}\n </p>\n ) : null}\n </footer>\n );\n}\n\n/**\n * 🔴 `...rest` is load-bearing, not tidiness. `tagTopLevel` stamps a top-level block by\n * `cloneElement`, which sets `data-bcms-block` as a PROP on this component — and a component\n * that does not spread it drops the attribute with no error and no warning. A top-level slider\n * or tabs block then renders perfectly and is invisible to the Visual Editor's section lane:\n * no move, no duplicate, no delete, no presence. Intrinsic elements do not have this failure\n * mode, which is why every other block type was fine and these two were not.\n */\nfunction BcmsSlider({ block, ctx, ...rest }: { block: SliderBlock; ctx: RenderCtx }): ReactElement {\n const { slides } = block.props;\n const [i, setI] = useState(0);\n const go = (n: number) => setI((n + slides.length) % (slides.length || 1));\n return (\n <div className=\"bcms-block bcms-block--slider\" style={{ position: \"relative\" }} {...rest}>\n {slides.map((s, idx) => (\n <div key={s.id} className=\"bcms-slide\" hidden={idx !== i}>\n {s.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n <button type=\"button\" className=\"bcms-slider-prev\" aria-label=\"Previous\" onClick={() => go(i - 1)}>\n ‹\n </button>\n <button type=\"button\" className=\"bcms-slider-next\" aria-label=\"Next\" onClick={() => go(i + 1)}>\n ›\n </button>\n </div>\n );\n}\n\n/** `...rest` for the same reason as <BcmsSlider> above — see its comment. */\nfunction BcmsTabs({ block, ctx, ...rest }: { block: TabsBlock; ctx: RenderCtx }): ReactElement {\n const { tabs } = block.props;\n const [active, setActive] = useState(0);\n return (\n <div className=\"bcms-block bcms-block--tabs\" {...rest}>\n <div className=\"bcms-tablist\" role=\"tablist\">\n {tabs.map((t, idx) => (\n <button\n key={t.id}\n role=\"tab\"\n type=\"button\"\n className=\"bcms-tab\"\n aria-selected={idx === active}\n onClick={() => setActive(idx)}\n {...bind(block.id, `tabs[${idx}].label`, \"text\", ctx)}\n >\n {t.label}\n </button>\n ))}\n </div>\n {tabs.map((t, idx) => (\n <div key={t.id} role=\"tabpanel\" className=\"bcms-tabpanel\" hidden={idx !== active}>\n {t.children.map((child) => renderBlock(child, ctx))}\n </div>\n ))}\n </div>\n );\n}\n\n/**\n * Missing-component ids already reported. Module-level so a page that places the same section\n * twenty times logs once, not twenty times — a wall of identical lines is skipped, and this\n * message has to be read.\n */\nconst warnedMissing = new Set<string>();\n\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return renderMissingComponent(props.componentId, ctx);\n if (ctx.depth >= MAX_COMPONENT_DEPTH || ctx.seen.has(def.id)) return null; // cycle/depth guard\n const resolved = applyOverrides<ContentBlock>(def.blockJson, def.props ?? [], props.overrides ?? {});\n // The instance's own addresses replace the definition's for the whole subtree. Without this\n // every stamp inside a component named a block shared by every instance of it: an orphan on\n // one placement, and a duplicate that drops BOTH on two.\n const childCtx: RenderCtx = {\n ...ctx,\n depth: ctx.depth + 1,\n seen: new Set([...ctx.seen, def.id]),\n fieldAddresses: ctx.owner === null ? new Map() : componentInstanceAddresses(id, def.props, ctx.owner),\n owner: undefined,\n };\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--component\"\n data-bcms-component={def.id}\n data-bcms-variant=\"base\"\n data-bcms-instance={id}\n >\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\n}\n\n/**\n * A `component` block whose definition was not delivered.\n *\n * 🔴 This used to be `return null // fail-soft`, and that comment was the bug. A page authored\n * as SECTIONS is a list of `component` blocks and nothing else, so \"fail-soft\" meant the entire\n * page body rendered as nothing while the build stayed green and the site answered 200 — what\n * remained on screen was the layout's own nav and footer. Two live sites were replaced by that\n * on 2026-08-18, and the only reason it was caught is that a human looked at the page.\n *\n * The near-universal cause is a host site that never passes `components` — the SDK's own README\n * example omitted it — so the message names the fix rather than the symptom.\n *\n * Still renders nothing in production: a placeholder box would be worse than a gap on a live\n * customer site. The console line ships in BOTH modes, because it is emitted during the build\n * and the build log is the one place a headless deploy can be inspected after the fact.\n */\nconst warnedUnhandled = new Set<string>();\n\n/**\n * A block type this renderer has no case for.\n *\n * `default: return null` is how `richtext` rendered NOTHING on a Next site for a whole release\n * — 200 OK, green build, blank region, no error anywhere. `collection` is in that state today:\n * it is delivered, the hosted renderer draws it, and this one silently drops it. Saying so out\n * loud does not implement the missing renderer, but it converts an invisible blank into a\n * message that names the type, which is the difference between a bug you find and one you ship.\n */\nfunction renderUnhandledBlock(block: ContentBlock): ReactNode {\n if (!warnedUnhandled.has(block.type)) {\n warnedUnhandled.add(block.type);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] block type \"${block.type}\" has no renderer here, so it rendered NOTHING. ` +\n `The hosted renderer draws it; this SDK does not yet.`,\n );\n }\n return null;\n}\n\nfunction renderMissingComponent(componentId: string, ctx: RenderCtx): ReactNode {\n if (!warnedMissing.has(componentId)) {\n warnedMissing.add(componentId);\n // eslint-disable-next-line no-console\n console.warn(\n `[BcmsBlocks] component \"${componentId}\" was not delivered, so this section rendered NOTHING.` +\n (ctx.componentsById.size === 0\n ? ` No components were passed at all — add components={readComponents()} to <BcmsBlocks>.`\n : ` ${ctx.componentsById.size} component(s) were passed but none match. It is probably still a DRAFT: publish it, then rebuild.`),\n );\n }\n if (process.env.NODE_ENV === \"production\") return null;\n return (\n <div\n className=\"bcms-block bcms-block--component-missing\"\n data-bcms-missing-component={componentId}\n style={{\n padding: \"12px 16px\",\n border: \"1px dashed #d4d4d8\",\n borderRadius: 8,\n color: \"#71717a\",\n font: \"500 13px/1.5 system-ui, -apple-system, sans-serif\",\n }}\n >\n Section <code>{componentId}</code> was not delivered.{\" \"}\n {ctx.componentsById.size === 0\n ? \"Pass components={readComponents()} to <BcmsBlocks>.\"\n : \"Publish the component, then rebuild.\"}\n </div>\n );\n}\n","\"use client\";\n\n/**\n * <BcmsForm> — render a BetterCMS form natively in React, the headless way.\n *\n * Pass a form straight from your content snapshot (`readSnapshot().forms[n]`) or\n * the delivery API. It renders real inputs (no iframe), handles conditional\n * `showIf` fields, URL-query prefill, the honeypot, an optional Turnstile widget,\n * and submits via `@bettercms-ai/sdk`'s `submitForm`. All visible markup is\n * unstyled and class-driven, so the host site owns the look.\n */\n\nimport { lazy, Suspense, useEffect, useMemo, useState, type FormEvent, type ReactElement } from \"react\";\nimport {\n submitForm,\n shouldShowField,\n formInitialValues,\n asStringArray,\n toggleOption,\n type DeliveryForm,\n type DeliveryFormField,\n type FormValue,\n type FormValues,\n type FormSubmitError,\n} from \"@bettercms-ai/sdk\";\n\nconst TURNSTILE_SRC = \"https://challenges.cloudflare.com/turnstile/v0/api.js\";\n\n/**\n * The country-picker phone control, loaded only when a form actually has one.\n *\n * It carries libphonenumber's metadata (~80KB), which no form without a picker should pay\n * for. The import specifier must survive into `dist/form.js` rather than being inlined —\n * see the `external` entry in tsup.config.ts and the dist greps in the tests.\n */\nconst PhoneField = lazy(() => import(\"./phone-field.js\"));\n\n// Field type → native <input type>. Other types render their own element.\nconst INPUT_TYPES: Partial<Record<DeliveryFormField[\"type\"], string>> = {\n text: \"text\",\n email: \"email\",\n phone: \"tel\",\n url: \"url\",\n number: \"number\",\n date: \"date\",\n};\n\nexport interface BcmsFormProps {\n /** A form from your content snapshot or the delivery API. */\n form: DeliveryForm;\n /** API origin. Defaults to the SDK default (https://api.bettercms.ai). */\n apiBase?: string;\n /** Turnstile site key — needed to render the widget when `form.turnstileEnabled`. */\n turnstileSiteKey?: string;\n /** Called with the new submission id after a successful submit (before any redirect). */\n onSubmitted?: (submissionId: string) => void;\n /** Class for the <form> element; field wrappers/status use `bcms-*` classes. */\n className?: string;\n}\n\ntype Status = { state: \"idle\" | \"submitting\" | \"error\" | \"success\"; message?: string };\n\nfunction readPrefill(): Record<string, string> {\n if (typeof window === \"undefined\") return {};\n const out: Record<string, string> = {};\n new URLSearchParams(window.location.search).forEach((v, k) => {\n out[k] = v;\n });\n return out;\n}\n\nfunction resetTurnstile(): void {\n const t = (globalThis as { turnstile?: { reset: () => void } }).turnstile;\n if (t) {\n try {\n t.reset();\n } catch {\n /* widget not mounted yet */\n }\n }\n}\n\nexport function BcmsForm({\n form,\n apiBase,\n turnstileSiteKey,\n onSubmitted,\n className,\n}: BcmsFormProps): ReactElement {\n const showTurnstile = Boolean(form.turnstileEnabled && turnstileSiteKey);\n const [values, setValues] = useState<FormValues>(() => {\n const init = formInitialValues(form, readPrefill());\n if (form.honeypotField) init[form.honeypotField] = \"\";\n return init;\n });\n const [status, setStatus] = useState<Status>({ state: \"idle\" });\n const [fieldErrors, setFieldErrors] = useState<Record<string, string>>({});\n\n // Cloudflare auto-renders any `.cf-turnstile` element once its script is present.\n useEffect(() => {\n if (!showTurnstile || document.querySelector(`script[src=\"${TURNSTILE_SRC}\"]`)) return;\n const script = document.createElement(\"script\");\n script.src = TURNSTILE_SRC;\n script.async = true;\n script.defer = true;\n document.head.appendChild(script);\n }, [showTurnstile]);\n\n const visibleFields = useMemo(\n () => form.fields.filter((f) => f.type !== \"hidden\" && shouldShowField(f, values)),\n [form.fields, values],\n );\n\n const setValue = (key: string, value: FormValue) =>\n setValues((prev) => ({ ...prev, [key]: value }));\n\n async function handleSubmit(e: FormEvent<HTMLFormElement>): Promise<void> {\n e.preventDefault();\n setStatus({ state: \"submitting\" });\n setFieldErrors({});\n\n const tokenEl = e.currentTarget.querySelector<HTMLInputElement>(\n '[name=\"cf-turnstile-response\"]',\n );\n const turnstileToken = tokenEl?.value || undefined;\n\n // Drop conditionally-hidden fields so a hidden required field can't block submit;\n // keep hidden-type fields and the honeypot (the API classifies bots on it).\n const data: FormValues = {};\n for (const field of form.fields) {\n if (field.type === \"hidden\" || shouldShowField(field, values)) {\n data[field.key] = values[field.key];\n }\n }\n if (form.honeypotField) data[form.honeypotField] = values[form.honeypotField] ?? \"\";\n\n try {\n const { id } = await submitForm({ formId: form.id, data, turnstileToken, baseUrl: apiBase });\n onSubmitted?.(id);\n if (form.redirectUrl) {\n window.location.href = form.redirectUrl;\n return;\n }\n const reset = formInitialValues(form);\n if (form.honeypotField) reset[form.honeypotField] = \"\";\n setValues(reset);\n setStatus({\n state: \"success\",\n message: form.successMessage ?? \"Thanks! Your submission was received.\",\n });\n resetTurnstile();\n } catch (err) {\n const e2 = err as FormSubmitError;\n if (e2.fieldErrors) setFieldErrors(e2.fieldErrors);\n setStatus({ state: \"error\", message: e2.message || \"Something went wrong. Please try again.\" });\n resetTurnstile();\n }\n }\n\n return (\n // `data-bcms-form` carries the id so the Visual Editor can find THIS form in the\n // preview frame and patch its copy live. Valued rather than bare: the runtime\n // selectors are `form[data-bcms-form]`, which a valued attribute still matches.\n <form className={className} onSubmit={handleSubmit} noValidate data-bcms-form={form.id}>\n {visibleFields.map((field) => (\n <Field\n key={field.key}\n field={field}\n value={values[field.key]}\n error={fieldErrors[field.key]}\n onChange={(v) => setValue(field.key, v)}\n />\n ))}\n\n {form.honeypotField ? (\n <span aria-hidden=\"true\" style={{ position: \"absolute\", left: \"-9999px\" }}>\n <input\n type=\"text\"\n name={form.honeypotField}\n tabIndex={-1}\n autoComplete=\"off\"\n value={String(values[form.honeypotField] ?? \"\")}\n onChange={(e) => setValue(form.honeypotField as string, e.target.value)}\n />\n </span>\n ) : null}\n\n {showTurnstile ? <div className=\"cf-turnstile\" data-sitekey={turnstileSiteKey} /> : null}\n\n <button type=\"submit\" disabled={status.state === \"submitting\"} data-bcms-form-part=\"submit\">\n {status.state === \"submitting\" ? \"Submitting…\" : form.submitLabel ?? \"Submit\"}\n </button>\n\n {status.message ? (\n <p\n className={`bcms-form-status bcms-form-status--${status.state}`}\n role=\"status\"\n aria-live=\"polite\"\n >\n {status.message}\n </p>\n ) : null}\n </form>\n );\n}\n\ninterface FieldProps {\n field: DeliveryFormField;\n value: FormValue;\n error?: string;\n onChange: (value: FormValue) => void;\n}\n\nfunction Field({ field, value, error, onChange }: FieldProps): ReactElement {\n const required = field.required;\n const errorNode = error ? (\n <span className=\"bcms-field-error\" role=\"alert\">\n {error}\n </span>\n ) : null;\n // Every author-editable string carries a `data-bcms-form-part` so the Visual Editor can\n // repaint it live. A string the dock can edit but cannot mark shows stale on the canvas.\n const helpNode = field.helpText ? (\n <span className=\"bcms-field-help\" data-bcms-form-part=\"help\">\n {field.helpText}\n </span>\n ) : null;\n\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label\n className=\"bcms-field bcms-field--checkbox\"\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <input\n type=\"checkbox\"\n name={field.key}\n required={required}\n checked={Boolean(value)}\n onChange={(e) => onChange(e.target.checked)}\n />{\" \"}\n <span data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </span>\n {helpNode}\n {errorNode}\n </label>\n );\n }\n\n // Pick-one and pick-many are groups of controls, not a single element, so they\n // return their own <fieldset> rather than flowing into the label+control shape\n // below. Without these two branches both fell through to `<input type=\"text\">`.\n if (field.type === \"radio\" || field.type === \"checkboxes\") {\n const multi = field.type === \"checkboxes\";\n const selected = asStringArray(value);\n return (\n <fieldset\n className={`bcms-field bcms-field--${multi ? \"checkboxes\" : \"radio\"}`}\n data-field={field.key}\n data-bcms-form-field={field.key}\n >\n <legend data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </legend>\n {(field.options ?? []).map((opt) => (\n <label key={opt} className=\"bcms-option\">\n <input\n type={multi ? \"checkbox\" : \"radio\"}\n name={field.key}\n value={opt}\n // `required` on every radio in a group is the native way to demand one\n // choice. On checkboxes it would demand ALL of them, so it is omitted —\n // the API enforces non-empty instead.\n required={!multi && required}\n checked={multi ? selected.includes(opt) : value === opt}\n onChange={(e) =>\n onChange(multi ? toggleOption(value, opt, e.target.checked) : opt)\n }\n />{\" \"}\n <span data-bcms-form-part=\"option\">{opt}</span>\n </label>\n ))}\n {helpNode}\n {errorNode}\n </fieldset>\n );\n }\n\n const str = String(value ?? \"\");\n let control: ReactElement;\n if (field.type === \"textarea\") {\n control = (\n <textarea\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n } else if (field.type === \"select\") {\n control = (\n <select name={field.key} required={required} value={str} onChange={(e) => onChange(e.target.value)}>\n <option value=\"\" disabled>\n Choose…\n </option>\n {(field.options ?? []).map((opt) => (\n <option key={opt} value={opt} data-bcms-form-part=\"option\">\n {opt}\n </option>\n ))}\n </select>\n );\n } else if (field.type === \"phone\" && field.ui?.countryPicker) {\n // The fallback is a usable tel input inside the SAME wrapper, so the host's `.bcms-phone`\n // rules apply before and after the chunk lands and the swap is not a layout surprise.\n control = (\n <Suspense\n fallback={\n <span className=\"bcms-phone\">\n <input type=\"tel\" name={field.key} placeholder={field.placeholder} required={required} value={str} onChange={(e) => onChange(e.target.value)} autoComplete=\"tel\" dir=\"ltr\" />\n </span>\n }\n >\n <PhoneField\n name={field.key}\n value={str}\n onChange={onChange}\n placeholder={field.placeholder}\n required={required}\n defaultCountry={field.ui.defaultCountry}\n />\n </Suspense>\n );\n } else {\n control = (\n <input\n type={INPUT_TYPES[field.type] ?? \"text\"}\n name={field.key}\n placeholder={field.placeholder}\n required={required}\n value={str}\n onChange={(e) => onChange(e.target.value)}\n />\n );\n }\n\n return (\n <p className=\"bcms-field\" data-field={field.key} data-bcms-form-field={field.key}>\n <label data-bcms-form-part=\"label\">\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\n {helpNode}\n {errorNode}\n </p>\n );\n}\n","/**\n * Visual Editor addresses for the Next renderer.\n *\n * The attributes are ALWAYS on, deliberately — a headless site's HTML is the customer's own,\n * `data-bcms-*` is inert for visitors, and there is no request-time draft render to gate them\n * against. That has been true since they were introduced; what was wrong is WHICH address they\n * carried inside a component.\n *\n * A component's block ids belong to the DEFINITION and are shared by every instance of it, so a\n * definition-scoped `<defBlockId>__text` resolves to no field in the loaded entry — the editor\n * logs it as an orphan — and two instances of one component produce the SAME address twice, which\n * `stampNodeIds` numbers as two COPIES of that one orphan (`data-node-index`) rather than two\n * fields: editing either edits nothing, on both. The hosted renderer avoided this by rendering component\n * subtrees unannotated; this one had no equivalent, so it emitted live-looking attributes that\n * bound to nothing. `addresses` fixes it at the source instead: inside an instance the map is\n * authoritative and resolves each declared prop to `<instanceId>__overrides.<key>`.\n */\nimport type { BindingKind } from \"@bettercms-ai/types\";\nimport { formatPropsAttribute } from \"@bettercms-ai/types\";\n\n/** The subset of the render context binding needs. */\nexport interface BindingCtx {\n /** Present only inside a component instance, where it is AUTHORITATIVE. */\n fieldAddresses?: Map<string, string>;\n}\n\n/** The address a write lands on, or null when none exists and nothing should be advertised. */\nexport function addressFor(id: string | undefined, prop: string, ctx: BindingCtx): string | null {\n if (!id) return null;\n const key = `${id}__${prop}`;\n if (ctx.fieldAddresses) return ctx.fieldAddresses.get(key) ?? null;\n return key;\n}\n\n/**\n * Attributes for a value rendered as this element's own content — spread onto the JSX tag.\n * Returns an empty object when unaddressable, so it spreads to nothing.\n */\nexport function bind(\n id: string | undefined,\n prop: string,\n kind: BindingKind,\n ctx: BindingCtx,\n): Record<string, string> {\n const address = addressFor(id, prop, ctx);\n return address ? { \"data-bcms-field\": address, \"data-bcms-kind\": kind } : {};\n}\n\n/**\n * Attributes for values that live in an ATTRIBUTE of this element (`alt`, `href`, a video's\n * `src`). `data-bcms-field` addresses one element and an element cannot hold two, so these ride\n * `data-bcms-props`: `<address>|<kind>|<domAttribute>`, semicolon separated.\n *\n * Entries whose value is absent are dropped: `setFieldPath` refuses to create a final key, so\n * an address for a key the block does not carry is a write the editor would reject.\n */\nexport function bindProps(\n id: string | undefined,\n entries: readonly { prop: string; kind: BindingKind; attr: string; present: boolean }[],\n ctx: BindingCtx,\n): Record<string, string> {\n const resolved = entries.flatMap(({ prop, kind, attr, present }) => {\n if (!present) return [];\n const address = addressFor(id, prop, ctx);\n return address ? [{ address, kind, attr }] : [];\n });\n return resolved.length ? { \"data-bcms-props\": formatPropsAttribute(resolved) } : {};\n}\n"],"mappings":"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","names":["useEffect","useState","useState","jsx","jsxs","useState","jsx","useState","useEffect"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bettercms-ai/next",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.14.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "The BetterCMS adapter for Next.js — typed, cache-aware content reads (getEntry/listEntries), draft preview, build-time content snapshot, and llms.txt generation for the App Router. The /blocks, /form, /field, /search and /visual-editing entries are framework-free React and work in any React app (see the React+TS starter), which is why `next` is an OPTIONAL peer.",
|
|
6
6
|
"bin": {
|
|
@@ -59,10 +59,10 @@
|
|
|
59
59
|
},
|
|
60
60
|
"dependencies": {
|
|
61
61
|
"@bettercms-ai/image-url": "^0.3.0",
|
|
62
|
-
"@bettercms-ai/richtext": "^0.
|
|
62
|
+
"@bettercms-ai/richtext": "^0.7.0",
|
|
63
63
|
"@bettercms-ai/sdk": "^1.22.0",
|
|
64
|
-
"@bettercms-ai/types": "^1.
|
|
65
|
-
"@bettercms-ai/ui": "^0.
|
|
64
|
+
"@bettercms-ai/types": "^1.20.0",
|
|
65
|
+
"@bettercms-ai/ui": "^0.9.0",
|
|
66
66
|
"react-phone-number-input": "^3.4.18"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|