From 2da25b7e4fcf4ca21c2fbabda939851607bb8060 Mon Sep 17 00:00:00 2001 From: Matthias Devlamynck Date: Thu, 24 Oct 2019 11:56:47 +0200 Subject: [PATCH 1/2] Add support for wrapping elm rendered dom in shadow dom --- README.md | 11 +++++++++++ src/index.js | 16 ++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 731349b..5bcbb39 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,17 @@ And now in your HTML you can use the component: Any attributes are passed into your Elm app as Flags. +## Shadow Dom + +By default Elm will render inside your custom element directly, if you want to isolate the Elm renderer dom using shadow dom you can register the custom element like this: + +```js +import elmWebComponents from '@teamthread/elm-web-components' +import ElmApp from './Main.elm' + +elmWebComponents.register('demo-elm-component', ElmApp.Main, {useShadowDom: true}) +``` + ## Ports You can also hook up a component that uses ports. The third argument to `elmWebComponents.register` is an object that can take a function that will be called with the ports object that Elm provides, so you can then hook into it and `subscribe` and `send` to them as you would normally: diff --git a/src/index.js b/src/index.js index b97a6bd..f959bf5 100644 --- a/src/index.js +++ b/src/index.js @@ -42,6 +42,7 @@ const elmWebComponents = { onDetached = () => {}, mapFlags = flags => flags, onSetupError, + useShadowDom = false, } = {} ) { if (!this.__elmVersion) { @@ -70,15 +71,22 @@ const elmWebComponents = { const flags = mapFlags(props) context.flags = flags + var elmDiv = this; + var parentDiv = this; + + if (useShadowDom) { + parentDiv = this.attachShadow({mode: 'open'}); + } + if (elmVersion === '0.19') { /* a change in Elm 0.19 means that ElmComponent.init now replaces the node you give it * whereas in 0.18 it rendered into it. To avoid Elm therefore destroying our custom element * we create a div that we let Elm render into, and manually clear any pre-rendered contents. */ - const elmDiv = document.createElement('div') + elmDiv = document.createElement('div') - this.innerHTML = '' - this.appendChild(elmDiv) + parentDiv.innerHTML = '' + parentDiv.appendChild(elmDiv) const elmElement = ElmComponent.init({ flags, @@ -86,7 +94,7 @@ const elmWebComponents = { }) setupPorts(elmElement.ports) } else if (elmVersion === '0.18') { - const elmElement = ElmComponent.embed(this, flags) + const elmElement = ElmComponent.embed(elmDiv, flags) setupPorts(elmElement.ports) } } catch (error) { From 0a3ea6c54419399cf43c34aed6b255fab13529e7 Mon Sep 17 00:00:00 2001 From: Matthias Devlamynck Date: Tue, 14 Jan 2020 12:01:36 +0100 Subject: [PATCH 2/2] Fix elm 0.18 init when used with shadow dom, Clean code --- src/index.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index f959bf5..28015ae 100644 --- a/src/index.js +++ b/src/index.js @@ -71,19 +71,14 @@ const elmWebComponents = { const flags = mapFlags(props) context.flags = flags - var elmDiv = this; - var parentDiv = this; - - if (useShadowDom) { - parentDiv = this.attachShadow({mode: 'open'}); - } + const parentDiv = useShadowDom ? this.attachShadow({mode: 'open'}) : this; if (elmVersion === '0.19') { /* a change in Elm 0.19 means that ElmComponent.init now replaces the node you give it * whereas in 0.18 it rendered into it. To avoid Elm therefore destroying our custom element * we create a div that we let Elm render into, and manually clear any pre-rendered contents. */ - elmDiv = document.createElement('div') + const elmDiv = document.createElement('div') parentDiv.innerHTML = '' parentDiv.appendChild(elmDiv) @@ -94,7 +89,7 @@ const elmWebComponents = { }) setupPorts(elmElement.ports) } else if (elmVersion === '0.18') { - const elmElement = ElmComponent.embed(elmDiv, flags) + const elmElement = ElmComponent.embed(parentDiv, flags) setupPorts(elmElement.ports) } } catch (error) {