diff --git a/craft/src/state/PageContext.tsx b/craft/src/state/PageContext.tsx index 9b73e15..f09d8b2 100644 --- a/craft/src/state/PageContext.tsx +++ b/craft/src/state/PageContext.tsx @@ -4,16 +4,13 @@ import { PageData } from '../types'; import { SerializedTreeNode } from '../types/sitesmith'; import { useSiteDesign, SiteDesign } from './SiteDesignContext'; -/** Layout components that accept children. Must match the .craft.rules.canMoveIn - * config of each component. Leaf components (Heading, TextBlock, ButtonLink, …) - * are NOT canvases and must serialize with isCanvas:false or their rendered - * content gets swallowed by an empty drop-target wrapper. */ -const CANVAS_TYPES = new Set([ - 'Container', 'Section', 'ColumnLayout', 'BackgroundSection', - 'HeaderZone', 'FooterZone', - 'HeroSimple', 'FeaturesGrid', 'CTASection', - 'FormContainer', 'Navbar', 'Footer', -]); +/** Only `Container` instances are "real" canvases in serialized state — they + * directly render whatever is in node.data.nodes. Layout-shell components + * (Section, HeroSimple, FeaturesGrid, ColumnLayout, CTASection, etc) use + * Craft.js linkedNodes internally; their own + * isCanvas must be FALSE or Craft.js's toNodeTree walker trips an Invariant + * because the shell claims to be a canvas but its render ignores `nodes`. */ +const CANVAS_TYPES = new Set(['Container']); interface PageContextValue { pages: PageData[]; diff --git a/craft/src/utils/apply-ai-response.ts b/craft/src/utils/apply-ai-response.ts index 99aadab..8c6e4f4 100644 --- a/craft/src/utils/apply-ai-response.ts +++ b/craft/src/utils/apply-ai-response.ts @@ -3,12 +3,12 @@ import type { NodeTree } from '@craftjs/core'; import { usePages } from '../state/PageContext'; import { SitesmithResponse, SerializedTreeNode } from '../types/sitesmith'; -/** Component types that act as drop targets (isCanvas = true) */ -const CANVAS_TYPES = new Set([ - 'Container', 'Section', 'ColumnLayout', 'BackgroundSection', - 'HeroSimple', 'FeaturesGrid', 'CTASection', - 'FormContainer', 'Navbar', 'Footer', -]); +/** Only Container is a "real" Craft.js canvas in serialized state. Layout + * shells (Section/HeroSimple/ColumnLayout/etc) use linkedNodes + * internally — their own node must serialize with isCanvas:false or + * toNodeTree's walker hits an Invariant because the shell claims to be a + * canvas but its render ignores `data.nodes`. */ +const CANVAS_TYPES = new Set(['Container']); /** * Flatten a SerializedTreeNode tree into a Craft.js node map ready for