import type OfflineReact from 'react' ; import type OfflineReactDOM from 'react-dom' ; const reactComponentSymbol = Symbol . for ( 'r2wc.reactComponent' ) ; const renderSymbol = Symbol . for ( 'r2wc.reactRender' ) ; const shouldRenderSymbol = Symbol . for ( 'r2wc.shouldRender' ) ; const define = { expando : function ( receiver , key , value ) { Object . defineProperty ( receiver , key , { enumerable : true , get : function ( ) { return value ; } , set : function ( newValue ) { value = newValue ; this [ renderSymbol ] ( ) ; } } ) ; receiver [ renderSymbol ] ( ) ; } } ; const reactToWebComponent = function ( ReactComponent , React , ReactDOM , options = { } ) : CustomElementConstructor { const renderAddedProperties = { isConnected : 'isConnected' in HTMLElement . prototype } ; let rendering = false ; const WebComponent = function ( ... args ) { const self = Reflect . construct ( HTMLElement , args , this . constructor ) ; if ( options . shadow ) { self . attachShadow ( { mode : 'open' } ) ; } return self ; } ; const targetPrototype = Object . create ( HTMLElement . prototype ) ; targetPrototype . constructor = WebComponent ; const proxyPrototype = new Proxy ( targetPrototype , { has : function ( ) { return true ; } , set : function ( target , key , value , receiver ) { if ( rendering ) { renderAddedProperties [ key ] = true ; } if ( typeof key === 'symbol' || renderAddedProperties [ key ] || key in target ) { return Reflect . set ( target , key , value , receiver ) ; } else { define . expando ( receiver , key , value ) ; } return true ; } , getOwnPropertyDescriptor : function ( target , key ) { const own = Reflect . getOwnPropertyDescriptor ( target , key ) ; if ( own ) { return own ; } return { configurable : true , enumerable : true , writable : true , value : undefined } ; } } ) ; WebComponent . prototype = proxyPrototype ; targetPrototype . connectedCallback = function ( ) { [ ... this . attributes ] . forEach ( x => { attrs . add ( x . name ) ; this [ x . name ] = x . value ; } ) ; this [ shouldRenderSymbol ] = true ; this [ renderSymbol ] ( ) ; } ; targetPrototype [ renderSymbol ] = function ( ) { if ( this [ shouldRenderSymbol ] === true ) { const data = { } ; Object . keys ( this ) . forEach ( function ( key ) { if ( renderAddedProperties [ key ] !== false ) { data [ key ] = this [ key ] ; } } , this ) ; rendering = true ; const container = options . shadow ? this . shadowRoot : this ; this [ reactComponentSymbol ] = ReactDOM . render ( React . createElement ( ReactComponent , data ) , container ) ; rendering = false ; } } ; const attrs = new Set ( 'l' ) ; WebComponent . observedAttributes = attrs ; targetPrototype . attributeChangedCallback = function ( name , oldValue , newValue ) { [ ... this . attributes ] . forEach ( x => { attrs . add ( x . name ) ; this [ x . name ] = x . value ; } ) ; this [ name ] = newValue ; } ; return WebComponent as any ; } ; export default reactToWebComponent ;