treeToState() was setting isCanvas:true on every node, including leaf
components (Heading, TextBlock, ButtonLink, Spacer, ImageBlock). Craft.js
then renders those as empty drop-canvas wrappers instead of their actual
content, so the canvas appears blank after applying an AI-generated
'replace' response.
Now uses a CANVAS_TYPES set matching the apply-ai-response utility:
only the layout wrappers (Container, Section, ColumnLayout, Hero/Features/
CTA sections, FormContainer, Navbar, Footer, etc.) are canvases. ROOT is
forced to be a canvas regardless of source type so children render.
Also defensively normalizes props.style: AI sometimes emits an empty
array instead of an object, which can confuse downstream consumers.
Rebuilt the visual site builder from scratch using Craft.js, React 18,
and TypeScript. The new editor renders directly in the DOM (no iframe),
supports 40+ components, multi-page with shared header/footer, 16
templates, full-spectrum color/gradient controls, custom head code
injection, save/publish workflow, and auto-save.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>