import React from 'react' ; import ReactDOM from "react-dom" ; import { renderReact2Node , getPropsFromNode , sendPropsToReact , } from './prop-bridge' ; type Mode = 'open' | 'element' ; const getCustomElementFromReactComponent = ( RComponent , mode ? ) => { return class ReactAsCustomElement extends HTMLElement { targetNode : this | ShadowRoot = null ; propBridgeRef : any = null ; props = { } ; observer : MutationObserver = null ; constructor ( ) { super ( ) ; this . props = getPropsFromNode ( this ) ; this . observer = new MutationObserver ( this . _onMutation ) ; switch ( mode ) { case 'open' : this . targetNode = this . attachShadow ( { mode : 'open' } ) ; break ; case 'element' : this . targetNode = this ; break ; default : this . targetNode = this . attachShadow ( { mode : 'closed' } ) ; break ; } renderReact2Node ( RComponent , this . props , this . targetNode , this . _onReactMount ) ; } setProps = ( newProps ) => { this . props = { ... this . props , ... newProps } ; sendPropsToReact ( this . propBridgeRef , this . props ) ; } ; _onReactMount = ( propBridgeRef ) => { this . propBridgeRef = propBridgeRef ; this . setProps ( this . props ) ; } ; _onMutation = ( mutationsList ) => { const newProps = mutationsList . reduce ( ( props , mutation ) => { if ( mutation . type === 'attributes' ) { const propKey = mutation . attributeName ; props [ propKey ] = this . getAttribute ( propKey ) ; } return props ; } , { } ) ; this . setProps ( newProps ) ; } ; connectedCallback ( ) { this . observer . observe ( this , { attributes : true } ) ; } disconnectedCallback ( ) { ReactDOM . unmountComponentAtNode ( this . targetNode ) ; this . observer . disconnect ( ) ; } } ; } ; export const registerAsWebComponent = ( component , customElementName , mode ? ) => { const ReactCustomElement = getCustomElementFromReactComponent ( component , mode ) ; customElements . define ( customElementName , ReactCustomElement ) ; } ;