@@ -8,7 +8,7 @@ import type {
8
8
9
9
import React from "react"
10
10
11
- export { R2WCOptions }
11
+ export * from "./types"
12
12
13
13
const renderSymbol = Symbol . for ( "r2wc.reactRender" )
14
14
const shouldRenderSymbol = Symbol . for ( "r2wc.shouldRender" )
@@ -23,7 +23,7 @@ const shouldRenderSymbol = Symbol.for("r2wc.shouldRender")
23
23
export default function r2wc (
24
24
ReactComponent : FC < any > | ComponentClass < any > ,
25
25
config : R2WCOptions = { } ,
26
- renderer : Renderer < ReturnType < typeof React . createElement > > ,
26
+ renderer : Renderer ,
27
27
) : CustomElementConstructor {
28
28
const propTypes : Record < string , any > = { } // { [camelCasedProp]: String | Number | Boolean | Function | Object | Array }
29
29
const propAttrMap : Record < string , any > = { } // @TODO : add option to specify for asymetric mapping (eg "className" from "class")
@@ -49,7 +49,9 @@ export default function r2wc(
49
49
}
50
50
class WebCompClass extends HTMLElement {
51
51
rendering : boolean
52
- mounted : boolean ;
52
+ mounted : boolean
53
+ componentContainer : HTMLElement | null
54
+ reactComponent : FC < any > | ComponentClass < any > | null ;
53
55
[ renderSymbol ] : ( ) => void
54
56
getOwnPropertyDescriptor : (
55
57
key : string ,
@@ -73,6 +75,10 @@ export default function r2wc(
73
75
74
76
this . mounted = false
75
77
78
+ this . componentContainer = null
79
+
80
+ this . reactComponent = null
81
+
76
82
// Add custom getter and setter for each prop
77
83
for ( const key of propKeys ) {
78
84
if ( key in propTypes ) {
@@ -110,18 +116,33 @@ export default function r2wc(
110
116
111
117
this . rendering = true
112
118
// Container is either shadow DOM or light DOM depending on `shadow` option.
113
- const container = ( this . shadowRoot as unknown as HTMLElement ) || this
114
-
115
- const children = flattenIfOne ( mapChildren ( this ) )
119
+ const _container =
120
+ this . componentContainer ??
121
+ ( ( this . shadowRoot as unknown as HTMLElement ) || this )
116
122
117
- const element = React . createElement ( ReactComponent , data , children )
123
+ // const children = flattenIfOne(mapChildren(this) )
118
124
119
125
// Use react to render element in container
120
- renderer . mount ( container , element )
121
126
122
127
if ( ! this . mounted ) {
128
+ const { reactContainer, component } = renderer . mount (
129
+ _container ,
130
+ ReactComponent ,
131
+ data ,
132
+ )
133
+ this . componentContainer = reactContainer
134
+ this . reactComponent = component
123
135
this . mounted = true
124
136
} else {
137
+ if ( ! this . reactComponent )
138
+ throw new Error ( "React component is not mounted" )
139
+ if ( ! this . componentContainer )
140
+ throw new Error ( "React component container is not mounted" )
141
+ const updateContext = {
142
+ reactContainer : this . componentContainer ,
143
+ component : this . reactComponent ,
144
+ }
145
+ renderer . update ( updateContext , data )
125
146
renderer . onUpdated ?.( )
126
147
}
127
148
this . rendering = false
@@ -163,7 +184,13 @@ export default function r2wc(
163
184
164
185
disconnectedCallback ( ) {
165
186
this [ shouldRenderSymbol ] = false
166
- renderer . unmount ( this )
187
+ if ( this . componentContainer && this . reactComponent ) {
188
+ const context = {
189
+ reactContainer : this . componentContainer ,
190
+ component : this . reactComponent ,
191
+ }
192
+ renderer . unmount ( context )
193
+ }
167
194
this . mounted = false
168
195
}
169
196
@@ -221,47 +248,47 @@ function toDashedStyle(camelCase = "") {
221
248
return camelCase . replace ( / ( [ a - z 0 - 9 ] ) ( [ A - Z ] ) / g, "$1-$2" ) . toLowerCase ( )
222
249
}
223
250
224
- function isAllCaps ( word : string ) {
225
- return word . split ( "" ) . every ( ( c : string ) => c . toUpperCase ( ) === c )
226
- }
227
-
228
- function flattenIfOne ( arr : object ) {
229
- if ( ! Array . isArray ( arr ) ) {
230
- return arr
231
- }
232
- if ( arr . length === 1 ) {
233
- return arr [ 0 ]
234
- }
235
- return arr
236
- }
237
-
238
- function mapChildren ( node : Element ) {
239
- if ( node . nodeType === Node . TEXT_NODE ) {
240
- return node . textContent ?. toString ( )
241
- }
242
-
243
- const arr = Array . from ( node . children ) . map ( ( element ) => {
244
- if ( element . nodeType === Node . TEXT_NODE ) {
245
- return element . textContent ?. toString ( )
246
- }
247
- // BR = br, ReactElement = ReactElement
248
- const nodeName = isAllCaps ( element . nodeName )
249
- ? element . nodeName . toLowerCase ( )
250
- : element . nodeName
251
- const children = flattenIfOne ( mapChildren ( element ) )
252
-
253
- // we need to format c.attributes before passing it to createElement
254
- const attributes : Record < string , string | null > = { }
255
- for ( const attr of element . getAttributeNames ( ) ) {
256
- // handleTypeCasting.call(c, attr, c.getAttribute(attr), attributes)
257
- attributes [ attr ] = element . getAttribute ( attr )
258
- }
259
-
260
- return React . createElement ( nodeName , attributes , children )
261
- } )
262
-
263
- return flattenIfOne ( arr )
264
- }
251
+ // function isAllCaps(word: string) {
252
+ // return word.split("").every((c: string) => c.toUpperCase() === c)
253
+ // }
254
+
255
+ // function flattenIfOne(arr: object) {
256
+ // if (!Array.isArray(arr)) {
257
+ // return arr
258
+ // }
259
+ // if (arr.length === 1) {
260
+ // return arr[0]
261
+ // }
262
+ // return arr
263
+ // }
264
+
265
+ // function mapChildren(node: Element) {
266
+ // if (node.nodeType === Node.TEXT_NODE) {
267
+ // return node.textContent?.toString()
268
+ // }
269
+
270
+ // const arr = Array.from(node.children).map((element) => {
271
+ // if (element.nodeType === Node.TEXT_NODE) {
272
+ // return element.textContent?.toString()
273
+ // }
274
+ // // BR = br, ReactElement = ReactElement
275
+ // const nodeName = isAllCaps(element.nodeName)
276
+ // ? element.nodeName.toLowerCase()
277
+ // : element.nodeName
278
+ // const children = flattenIfOne(mapChildren(element))
279
+
280
+ // // we need to format c.attributes before passing it to createElement
281
+ // const attributes: Record<string, string | null> = {}
282
+ // for (const attr of element.getAttributeNames()) {
283
+ // // handleTypeCasting.call(c, attr, c.getAttribute(attr), attributes)
284
+ // attributes[attr] = element.getAttribute(attr)
285
+ // }
286
+
287
+ // return React.createElement(nodeName, attributes, children)
288
+ // })
289
+
290
+ // return flattenIfOne(arr)
291
+ // }
265
292
266
293
function handleTypeCasting (
267
294
this : HTMLElement ,
0 commit comments