From 196f49a0e16f99ed39edbd656706fd54a6013230 Mon Sep 17 00:00:00 2001 From: "Hauke B." <14164004+hbroer@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:05:20 +0100 Subject: [PATCH] Feature: Shadow DOM without wrapping DIV element (#146) * webcomponent shadowroot without div container * remove type casting of parentNode * Update browser.yml * Update webComponent.html * Update webComponent.html --------- Co-authored-by: Hauke Broer Co-authored-by: yandeu <20306025+yandeu@users.noreply.github.com> --- .github/workflows/browser.yml | 2 +- src/component.ts | 2 +- src/customElementsMode.ts | 11 ++--------- test/browser/webComponent.html | 11 +++++++++-- test/nodejs/customElementsMode.test.tsx | 24 ++++++++++++------------ 5 files changed, 25 insertions(+), 25 deletions(-) diff --git a/.github/workflows/browser.yml b/.github/workflows/browser.yml index 1d5c0c1..e403375 100644 --- a/.github/workflows/browser.yml +++ b/.github/workflows/browser.yml @@ -37,7 +37,7 @@ jobs: rm -f package.json rm -f package-lock.json npm init -y - npm i -D rimraf typescript puppeteer + npm i -D rimraf typescript@5.1.6 puppeteer npm i -D webpack webpack-cli ts-loader nyc coverage-istanbul-loader - name: Prepare diff --git a/src/component.ts b/src/component.ts index 0ab7382..551e4f1 100644 --- a/src/component.ts +++ b/src/component.ts @@ -114,7 +114,7 @@ export class Component

{ // console.log('new: ', this.elements) // get valid parent node - const parent = oldElements[0].parentElement as HTMLElement + const parent = oldElements[0].parentNode // make sure we have a parent if (!parent) console.warn('Component needs a parent element to get updated!') diff --git a/src/customElementsMode.ts b/src/customElementsMode.ts index bd5c4d6..eb5dbb9 100644 --- a/src/customElementsMode.ts +++ b/src/customElementsMode.ts @@ -74,18 +74,11 @@ export const defineAsCustomElements: ( } private buildEl(contents: any) { - // because nano-jsx update needs parentElement, we need - // to wrap the element in a div when using shadow mode - return h(this.shadowRoot ? 'div' : 'template', null, contents) + return h('template', null, contents) } private appendEl(el: any) { - if (this.shadowRoot) { - // el.dataset.wcRoot = true - this.$root.append(el) - } else { - this.$root.append(...el.childNodes) - } + this.$root.append(...el.childNodes) } private removeChildren() { diff --git a/test/browser/webComponent.html b/test/browser/webComponent.html index 20754aa..51f3c0b 100644 --- a/test/browser/webComponent.html +++ b/test/browser/webComponent.html @@ -43,16 +43,23 @@ const myCustomElement = document.querySelector('my-custom-element') Test.error(myCustomElement.innerHTML === 'invisible', 'Should show text "invisible"') Test.error( - myCustomElement?.shadowRoot?.innerHTML === '

title

bye123
', + myCustomElement?.shadowRoot?.innerHTML === '

title

bye123
', 'Shadow should contain "title" and "bye123"' ) + + // update attribute hello + myCustomElement.setAttribute("hello", 456) + Test.error( + myCustomElement?.shadowRoot?.innerHTML === '

title

bye456
', + 'Shadow should contain "title" and "bye456"' + ) }) describe('slot-test', async () => { const myCustomElement = document.querySelector('slot-test') Test.error(myCustomElement.innerHTML === 'John Doe', 'Should show span') Test.error( - myCustomElement?.shadowRoot?.innerHTML === '

Hello:

', + myCustomElement?.shadowRoot?.innerHTML === '

Hello:

', 'Hello: John Doe' ) }) diff --git a/test/nodejs/customElementsMode.test.tsx b/test/nodejs/customElementsMode.test.tsx index 22e8407..ec41a5d 100644 --- a/test/nodejs/customElementsMode.test.tsx +++ b/test/nodejs/customElementsMode.test.tsx @@ -40,7 +40,7 @@ test('should render with correct content', async () => { await wait() const comp = document.querySelector('nano-test2') - expect(comp?.shadowRoot?.innerHTML).toEqual('
test text
') + expect(comp?.shadowRoot?.innerHTML).toEqual('
test text
') expect(spy).not.toHaveBeenCalled() }) @@ -65,7 +65,7 @@ test('should render with props', async () => { await wait() const comp = document.querySelector('nano-test3') - expect(comp?.shadowRoot?.innerHTML).toEqual('
test : fuga
') + expect(comp?.shadowRoot?.innerHTML).toEqual('
test : fuga
') expect(spy).not.toHaveBeenCalled() }) @@ -90,11 +90,11 @@ test('should update render result with props change', async () => { await wait() const comp = document.querySelector('nano-test4') - expect(comp?.shadowRoot?.innerHTML).toEqual('
test : fuga
') + expect(comp?.shadowRoot?.innerHTML).toEqual('
test : fuga
') document.body.innerHTML = '' const compChanged = document.querySelector('nano-test4') - expect(compChanged?.shadowRoot?.innerHTML).toEqual('
test : hoge
') + expect(compChanged?.shadowRoot?.innerHTML).toEqual('
test : hoge
') expect(spy).not.toHaveBeenCalled() }) @@ -123,10 +123,10 @@ test('should change render result with state change', async () => { await wait() const comp = document.querySelector('nano-test5') - expect(comp?.shadowRoot?.innerHTML).toEqual('
Counter: 0
') + expect(comp?.shadowRoot?.innerHTML).toEqual('
Counter: 0
') comp?.shadowRoot?.querySelector('button')?.click() - expect(comp?.shadowRoot?.innerHTML).toEqual('
Counter: 1
') + expect(comp?.shadowRoot?.innerHTML).toEqual('
Counter: 1
') expect(spy).not.toHaveBeenCalled() }) @@ -163,17 +163,17 @@ test('should keep state with props change', async () => { const comp = document.querySelector('nano-test6') expect(comp?.shadowRoot?.innerHTML).toEqual( - '
Counter: 0
props: 1
' + '
Counter: 0
props: 1
' ) comp?.shadowRoot?.querySelector('button')?.click() expect(comp?.shadowRoot?.innerHTML).toEqual( - '
Counter: 1
props: 1
' + '
Counter: 1
props: 1
' ) // @ts-ignore comp.attributes.value?.value = 2 expect(comp?.shadowRoot?.innerHTML).toEqual( - '
Counter: 1
props: 2
' + '
Counter: 1
props: 2
' ) expect(spy).not.toHaveBeenCalled() }) @@ -190,10 +190,10 @@ test('should render also with functional component', async () => { await wait() const comp = document.querySelector('nano-test7') - expect(comp?.shadowRoot?.innerHTML).toEqual('

hoge

') + expect(comp?.shadowRoot?.innerHTML).toEqual('

hoge

') // @ts-ignore comp.attributes.value?.value = 'bar' - expect(comp?.shadowRoot?.innerHTML).toEqual('

bar

') + expect(comp?.shadowRoot?.innerHTML).toEqual('

bar

') expect(spy).not.toHaveBeenCalled() }) @@ -225,6 +225,6 @@ test('should render also with slot', async () => { await wait() const comp = document.querySelector('nano-test8') - expect(comp?.shadowRoot?.innerHTML).toEqual('
nano jsx

hoge

') + expect(comp?.shadowRoot?.innerHTML).toEqual('
nano jsx

hoge

') expect(spy).not.toHaveBeenCalled() })