@bettercms-ai/next 0.9.0 β†’ 0.10.1

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 CHANGED
@@ -2,7 +2,11 @@
2
2
  "use client";
3
3
 
4
4
  // src/blocks.tsx
5
- import { useState as useState2 } from "react";
5
+ import {
6
+ cloneElement,
7
+ isValidElement,
8
+ useState as useState2
9
+ } from "react";
6
10
  import { blockStyleToCss } from "@bettercms-ai/types";
7
11
  import { applyOverrides } from "@bettercms-ai/ui/resolve";
8
12
 
@@ -272,7 +276,29 @@ function BcmsBlocks({
272
276
  const formsById = new Map((forms ?? []).map((f) => [f.id, f]));
273
277
  const componentsById = new Map((components ?? []).map((cmp) => [cmp.id, cmp]));
274
278
  const ctx = { formsById, componentsById, turnstileSiteKey, apiBase, depth: 0, seen: /* @__PURE__ */ new Set() };
275
- return /* @__PURE__ */ jsx2("div", { className, children: blocks.map((block) => renderBlock(block, ctx)) });
279
+ return (
280
+ /**
281
+ * πŸ”΄ `data-bcms-page` marks THIS SUBTREE as ours to edit β€” the SDK's equivalent of the hosted
282
+ * renderer's `<main class="bcms-page">` (render-page.ts).
283
+ *
284
+ * The Visual Editor decides whether to show section controls by asking the page what it is.
285
+ * Its only test was that hosted wrapper, which an SDK-rendered site never has β€” so every
286
+ * headless site was treated as "not ours", and move/duplicate/delete/reorder stayed hidden
287
+ * on pages that fully support them. Measured on a live SDK site: 34 blocks rendered,
288
+ * 0 recognised.
289
+ *
290
+ * It must sit on the CONTAINER rather than be inferred from the blocks, so that a page with
291
+ * NO blocks yet is still recognised β€” otherwise there is no way to add the first section,
292
+ * which is exactly the state a new page starts in.
293
+ */
294
+ /* @__PURE__ */ jsx2("div", { className, "data-bcms-page": "", children: blocks.map((block) => tagTopLevel(block, renderBlock(block, ctx))) })
295
+ );
296
+ }
297
+ function tagTopLevel(block, node) {
298
+ if (!isValidElement(node)) return node;
299
+ return cloneElement(node, {
300
+ "data-bcms-block": block.id
301
+ });
276
302
  }
277
303
  function renderBlock(block, ctx) {
278
304
  const node = renderBlockInner(block, ctx);
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/blocks.tsx","../src/form.tsx"],"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 { useState, type CSSProperties, type ReactElement, type ReactNode } 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 { applyOverrides } from \"@bettercms-ai/ui/resolve\";\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 <div className={className}>{blocks.map((block) => renderBlock(block, ctx))}</div>;\n}\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\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);\n case \"text\":\n return renderText(block);\n case \"image\":\n return renderImage(block);\n case \"button\":\n return renderButton(block);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block);\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);\n case \"footer\":\n return renderFooter(block);\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 null;\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" data-bcms-field={`${id}__text`}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock): ReactNode {\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n data-bcms-field={`${id}__html`}\n data-bcms-kind=\"richtext\"\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\nfunction renderImage({ id, props }: ImageBlock): 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 data-bcms-field={`${id}__src`}\n data-bcms-kind=\"image\"\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>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock): 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 data-bcms-field={`${id}__text`}\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): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\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 {props.maxWidth ? <div style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div> : inner}\n </section>\n );\n}\n\nfunction renderNavbar({ id, props }: NavbarBlock): 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 src={props.logo.src} alt={props.logo.alt} />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a key={i} href={l.href}>\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a className=\"bcms-button bcms-button--primary\" href={props.cta.href}>\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\nfunction renderFooter({ id, props }: FooterBlock): 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>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? <p className=\"bcms-footer-copy\">{props.copyright}</p> : null}\n </footer>\n );\n}\n\nfunction BcmsSlider({ block, ctx }: { 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\" }}>\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\nfunction BcmsTabs({ block, ctx }: { 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\">\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 >\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\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return null; // not delivered β€” fail-soft\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 const childCtx: RenderCtx = { ...ctx, depth: ctx.depth + 1, seen: new Set([...ctx.seen, def.id]) };\n return (\n <div key={id} className=\"bcms-block bcms-block--component\">\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\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 { 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// 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 {\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"],"mappings":"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","names":["useState","jsx","jsxs","useState"]}
1
+ {"version":3,"sources":["../src/blocks.tsx","../src/form.tsx"],"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 { applyOverrides } from \"@bettercms-ai/ui/resolve\";\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\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\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);\n case \"text\":\n return renderText(block);\n case \"image\":\n return renderImage(block);\n case \"button\":\n return renderButton(block);\n case \"spacer\":\n return renderSpacer(block);\n case \"video\":\n return renderVideo(block);\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);\n case \"footer\":\n return renderFooter(block);\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 null;\n }\n}\n\nfunction renderHeading({ id, props }: HeadingBlock): ReactNode {\n const Tag = `h${props.level ?? 2}` as \"h1\" | \"h2\" | \"h3\";\n return (\n <Tag key={id} className=\"bcms-block bcms-block--heading\" data-bcms-field={`${id}__text`}>\n {props.text}\n </Tag>\n );\n}\n\nfunction renderText({ id, props }: TextBlock): ReactNode {\n // `html` is sanitized server-side before storage.\n return (\n <div\n key={id}\n className=\"bcms-block bcms-block--text\"\n data-bcms-field={`${id}__html`}\n data-bcms-kind=\"richtext\"\n dangerouslySetInnerHTML={{ __html: props.html }}\n />\n );\n}\n\nfunction renderImage({ id, props }: ImageBlock): 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 data-bcms-field={`${id}__src`}\n data-bcms-kind=\"image\"\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>{props.caption}</figcaption>\n </figure>\n );\n}\n\nfunction renderButton({ id, props }: ButtonBlock): 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 data-bcms-field={`${id}__text`}\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): ReactNode {\n return (\n <video\n key={id}\n className=\"bcms-block bcms-block--video\"\n src={props.url}\n poster={props.poster}\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 {props.maxWidth ? <div style={{ maxWidth: props.maxWidth, margin: \"0 auto\" }}>{inner}</div> : inner}\n </section>\n );\n}\n\nfunction renderNavbar({ id, props }: NavbarBlock): 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 src={props.logo.src} alt={props.logo.alt} />\n </a>\n ) : null}\n <div className=\"bcms-navbar-links\">\n {props.links.map((l, i) => (\n <a key={i} href={l.href}>\n {l.label}\n </a>\n ))}\n </div>\n {props.cta ? (\n <a className=\"bcms-button bcms-button--primary\" href={props.cta.href}>\n {props.cta.text}\n </a>\n ) : null}\n </nav>\n );\n}\n\nfunction renderFooter({ id, props }: FooterBlock): 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>{col.heading}</h4> : null}\n <ul>\n {col.links.map((l, j) => (\n <li key={j}>\n <a href={l.href}>{l.label}</a>\n </li>\n ))}\n </ul>\n </div>\n ))}\n </div>\n {props.copyright ? <p className=\"bcms-footer-copy\">{props.copyright}</p> : null}\n </footer>\n );\n}\n\nfunction BcmsSlider({ block, ctx }: { 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\" }}>\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\nfunction BcmsTabs({ block, ctx }: { 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\">\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 >\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\nfunction renderComponent({ id, props }: ComponentBlock, ctx: RenderCtx): ReactNode {\n const def = ctx.componentsById.get(props.componentId);\n if (!def) return null; // not delivered β€” fail-soft\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 const childCtx: RenderCtx = { ...ctx, depth: ctx.depth + 1, seen: new Set([...ctx.seen, def.id]) };\n return (\n <div key={id} className=\"bcms-block bcms-block--component\">\n {resolved.map((child) => renderBlock(child, childCtx))}\n </div>\n );\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 { 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// 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 {\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"],"mappings":"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","names":["useState","jsx","jsxs","useState"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bettercms-ai/next",
3
- "version": "0.9.0",
3
+ "version": "0.10.1",
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": {
@@ -53,8 +53,8 @@
53
53
  "test:watch": "vitest"
54
54
  },
55
55
  "dependencies": {
56
- "@bettercms-ai/image-url": "^0.1.0",
57
- "@bettercms-ai/sdk": "^1.12.0",
56
+ "@bettercms-ai/image-url": "^0.2.0",
57
+ "@bettercms-ai/sdk": "^1.12.1",
58
58
  "@bettercms-ai/types": "^1.8.0",
59
59
  "@bettercms-ai/ui": "^0.4.0"
60
60
  },