Root cause: TemplateModal.addTemplateComponents() built each template component via React.createElement(Component, comp.props) and never passed comp.children — so loading ANY template silently dropped all nested content (nav links, footer, section contents) from the editor state AND from published output. Fable surfaced it as empty header/footer zone previews; it was actually every template.
Fix: extract templates/apply-template.ts (recursively builds comp.children into the node tree) and route it through the shared buildNodeTree, which was moved into craft-tree.ts and repaired (two latent bugs: data.type must be a real component reference not a {resolvedName} object; synthesized SHELL_INNER needs data.name). Same repair also fixes a pre-existing latent no-op in the AI apply-response section-replace/insert paths. No component toHtml changed. 580 tests + a real template-export regression test.
Root cause: `TemplateModal.addTemplateComponents()` built each template component via `React.createElement(Component, comp.props)` and never passed `comp.children` — so loading ANY template silently dropped all nested content (nav links, footer, section contents) from the editor state AND from published output. Fable surfaced it as empty header/footer zone previews; it was actually every template.
Fix: extract `templates/apply-template.ts` (recursively builds `comp.children` into the node tree) and route it through the shared `buildNodeTree`, which was moved into `craft-tree.ts` and repaired (two latent bugs: `data.type` must be a real component reference not a `{resolvedName}` object; synthesized SHELL_INNER needs `data.name`). Same repair also fixes a pre-existing latent no-op in the AI apply-response section-replace/insert paths. No component `toHtml` changed. 580 tests + a real template-export regression test.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
TemplateModal's addTemplateComponents() built each template component via
React.createElement(Component, comp.props) without ever passing
comp.children, silently dropping every nested children array authored in
templates/definitions.ts (header/footer Container > Logo/Menu/TextBlock,
page Section > Heading/TextBlock/ButtonLink). The resulting Craft.js node had
nodes: [], so the header/footer zone preview (ZonePreview -> exportBodyHtml)
rendered as an empty strip, and published output was affected the same way.
Fix converts each TemplateComponent to a SerializedTreeNode and reuses
craft-tree.ts's buildNodeTree (sanitize -> flatten -> materialize) -- the
same tested tree pipeline already used for AI-generated content -- instead
of hand-rolling a React-element tree, since a naive nested-children fix via
parseReactElement crashes any component with an internal SHELL_INNER linked
canvas (Section/BackgroundSection/FormContainer) or linked columns
(ColumnLayout). Also fixes two latent bugs in buildNodeTree itself, only
surfaced by exercising it against a real Craft.js editor for the first time:
data.type must be the actual resolved component reference (not a string or
{resolvedName} object) for correct rendering, and the synthesized SHELL_INNER
node needs data.name set for actions.addNodeTree's own validation.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
jknapp
merged commit 329a782052 into main2026-07-13 13:28:39 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Root cause:
TemplateModal.addTemplateComponents()built each template component viaReact.createElement(Component, comp.props)and never passedcomp.children— so loading ANY template silently dropped all nested content (nav links, footer, section contents) from the editor state AND from published output. Fable surfaced it as empty header/footer zone previews; it was actually every template.Fix: extract
templates/apply-template.ts(recursively buildscomp.childreninto the node tree) and route it through the sharedbuildNodeTree, which was moved intocraft-tree.tsand repaired (two latent bugs:data.typemust be a real component reference not a{resolvedName}object; synthesized SHELL_INNER needsdata.name). Same repair also fixes a pre-existing latent no-op in the AI apply-response section-replace/insert paths. No componenttoHtmlchanged. 580 tests + a real template-export regression test.🤖 Generated with Claude Code
TemplateModal's addTemplateComponents() built each template component via React.createElement(Component, comp.props) without ever passing comp.children, silently dropping every nested children array authored in templates/definitions.ts (header/footer Container > Logo/Menu/TextBlock, page Section > Heading/TextBlock/ButtonLink). The resulting Craft.js node had nodes: [], so the header/footer zone preview (ZonePreview -> exportBodyHtml) rendered as an empty strip, and published output was affected the same way. Fix converts each TemplateComponent to a SerializedTreeNode and reuses craft-tree.ts's buildNodeTree (sanitize -> flatten -> materialize) -- the same tested tree pipeline already used for AI-generated content -- instead of hand-rolling a React-element tree, since a naive nested-children fix via parseReactElement crashes any component with an internal SHELL_INNER linked canvas (Section/BackgroundSection/FormContainer) or linked columns (ColumnLayout). Also fixes two latent bugs in buildNodeTree itself, only surfaced by exercising it against a real Craft.js editor for the first time: data.type must be the actual resolved component reference (not a string or {resolvedName} object) for correct rendering, and the synthesized SHELL_INNER node needs data.name set for actions.addNodeTree's own validation. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>