@bettercms-ai/next 0.6.0 → 0.7.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
@@ -283,7 +283,9 @@ function renderImage({ id, props }) {
283
283
  alt: props.alt,
284
284
  width: props.width,
285
285
  height: props.height,
286
- loading: "lazy"
286
+ loading: "lazy",
287
+ "data-bcms-field": `${id}__src`,
288
+ "data-bcms-kind": "image"
287
289
  }
288
290
  );
289
291
  if (!props.caption) {
@@ -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 />\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 type DeliveryForm,\n type DeliveryFormField,\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: string | boolean) =>\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 <form className={className} onSubmit={handleSubmit} noValidate>\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\"}>\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: string | boolean;\n error?: string;\n onChange: (value: string | boolean) => 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\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label className=\"bcms-field bcms-field--checkbox\" data-field={field.key}>\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 {field.label}\n {required ? \" *\" : \"\"}\n {errorNode}\n </label>\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}>\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}>\n <label>\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\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 { 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 type DeliveryForm,\n type DeliveryFormField,\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: string | boolean) =>\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 <form className={className} onSubmit={handleSubmit} noValidate>\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\"}>\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: string | boolean;\n error?: string;\n onChange: (value: string | boolean) => 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\n if (field.type === \"checkbox\" || field.type === \"consent\") {\n return (\n <label className=\"bcms-field bcms-field--checkbox\" data-field={field.key}>\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 {field.label}\n {required ? \" *\" : \"\"}\n {errorNode}\n </label>\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}>\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}>\n <label>\n {field.label}\n {required ? \" *\" : \"\"}\n </label>\n <br />\n {control}\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.6.0",
3
+ "version": "0.7.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.",
6
6
  "bin": {
@@ -56,7 +56,7 @@
56
56
  "@bettercms-ai/image-url": "^0.1.0",
57
57
  "@bettercms-ai/sdk": "^1.5.0",
58
58
  "@bettercms-ai/types": "^1.4.0",
59
- "@bettercms-ai/ui": "^0.3.0"
59
+ "@bettercms-ai/ui": "^0.4.0"
60
60
  },
61
61
  "peerDependencies": {
62
62
  "next": ">=14",