diff --git a/src/core/vdom.ts b/src/core/vdom.ts index c4ec32f64..47d945a69 100644 --- a/src/core/vdom.ts +++ b/src/core/vdom.ts @@ -1489,6 +1489,10 @@ export function renderer(renderer: () => RenderResult): Renderer { while (!insertBefore) { const nextSibling = _wrapperSiblingMap.get(searchNode); if (nextSibling) { + if (isBodyWrapper(nextSibling) || isHeadWrapper(nextSibling)) { + searchNode = nextSibling; + continue; + } let domNode = nextSibling.domNode; if (isWNodeWrapper(nextSibling) || isVirtualWrapper(nextSibling)) { if (!nextSibling.childDomWrapperId) { diff --git a/tests/core/unit/vdom.tsx b/tests/core/unit/vdom.tsx index 537f1a0cc..8bd2918a2 100644 --- a/tests/core/unit/vdom.tsx +++ b/tests/core/unit/vdom.tsx @@ -4848,6 +4848,74 @@ jsdomDescribe('vdom', () => { results = document.querySelectorAll('.body-span'); assert.lengthOf(results, 0); }); + + it('should support attaching body nodes in nested widgets', () => { + const factory = create({ icache }).properties(); + + const Foo = factory(function Foo() { + return ( +
+ +
+ +
+ ); + }); + + const Bar = factory(function Bar({ properties }) { + return ( +
+ properties().close()} /> + +
+ +
+ ); + }); + + const App = factory(function App({ middleware: { icache } }) { + const show = icache.getOrSet('show', false); + return ( +
+ + {show && ( + { + icache.set('show', false); + }} + /> + )} +

Start editing to see some magic happen

+
+ ); + }); + + const r = renderer(() => w(App, {})); + r.mount({ domNode: root }); + (root.children[0].children[0] as any).click(); + resolvers.resolve(); + assert.strictEqual( + root.innerHTML, + '

Start editing to see some magic happen

' + ); + assert.lengthOf(document.querySelectorAll('#body-1'), 1); + assert.lengthOf(document.querySelectorAll('#body-2'), 1); + (root.children[0].children[0] as any).click(); + resolvers.resolve(); + resolvers.resolve(); + assert.strictEqual( + root.innerHTML, + '

Start editing to see some magic happen

' + ); + assert.lengthOf(document.querySelectorAll('#body-1'), 0); + assert.lengthOf(document.querySelectorAll('#body-2'), 0); + }); }); describe('head node', () => { @@ -5100,6 +5168,74 @@ jsdomDescribe('vdom', () => { results = document.querySelectorAll('.head-span'); assert.lengthOf(results, 0); }); + + it('should support attaching head nodes in nested widgets', () => { + const factory = create({ icache }).properties(); + + const Foo = factory(function Foo() { + return ( +
+ +
+ +
+ ); + }); + + const Bar = factory(function Bar({ properties }) { + return ( +
+ properties().close()} /> + +
+ +
+ ); + }); + + const App = factory(function App({ middleware: { icache } }) { + const show = icache.getOrSet('show', false); + return ( +
+ + {show && ( + { + icache.set('show', false); + }} + /> + )} +

Start editing to see some magic happen

+
+ ); + }); + + const r = renderer(() => w(App, {})); + r.mount({ domNode: root }); + (root.children[0].children[0] as any).click(); + resolvers.resolve(); + assert.strictEqual( + root.innerHTML, + '

Start editing to see some magic happen

' + ); + assert.lengthOf(document.querySelectorAll('#head-1'), 1); + assert.lengthOf(document.querySelectorAll('#head-2'), 1); + (root.children[0].children[0] as any).click(); + resolvers.resolve(); + resolvers.resolve(); + assert.strictEqual( + root.innerHTML, + '

Start editing to see some magic happen

' + ); + assert.lengthOf(document.querySelectorAll('#head-1'), 0); + assert.lengthOf(document.querySelectorAll('#head-2'), 0); + }); }); describe('virtual node', () => {