@@ -6,9 +6,13 @@ import * as jsonpatch from "fast-json-patch";
6
6
import serializeEvent from "./event-to-object" ;
7
7
8
8
const html = htm . bind ( react . createElement ) ;
9
- const alreadyImported = { } ;
9
+ const LayoutConfigContext = react . createContext ( { } ) ;
10
10
11
- export function mountLayoutWithWebSocket ( mountElement , endpoint ) {
11
+ export function mountLayoutWithWebSocket (
12
+ mountElement ,
13
+ endpoint ,
14
+ importSourceUrl
15
+ ) {
12
16
if ( endpoint . startsWith ( "." ) || endpoint . startsWith ( "/" ) ) {
13
17
let loc = window . location ;
14
18
let protocol ;
@@ -42,70 +46,116 @@ export function mountLayoutWithWebSocket(mountElement, endpoint) {
42
46
) ;
43
47
}
44
48
45
- return mountLayout ( mountElement , saveUpdateHook , sendCallback ) ;
49
+ return mountLayout (
50
+ mountElement ,
51
+ saveUpdateHook ,
52
+ sendCallback ,
53
+ importSourceUrl
54
+ ) ;
46
55
}
47
56
48
- export function mountLayout ( mountElement , saveUpdateHook , sendEvent ) {
57
+ export function mountLayout (
58
+ mountElement ,
59
+ saveUpdateHook ,
60
+ sendEvent ,
61
+ importSourceUrl
62
+ ) {
49
63
reactDOM . render (
50
- html `< ${ Layout } saveUpdateHook =${ saveUpdateHook } sendEvent=${ sendEvent } /> ` ,
64
+ html `
65
+ < ${ Layout }
66
+ saveUpdateHook =${ saveUpdateHook }
67
+ sendEvent=${ sendEvent }
68
+ importSourceUrl=${ importSourceUrl }
69
+ />
70
+ ` ,
51
71
mountElement
52
72
) ;
53
73
}
54
74
55
- export default function Layout ( { saveUpdateHook, sendEvent } ) {
75
+ export default function Layout ( { saveUpdateHook, sendEvent, importSourceUrl } ) {
56
76
const [ model , patchModel ] = useInplaceJsonPatch ( { } ) ;
57
77
58
78
react . useEffect ( ( ) => saveUpdateHook ( patchModel ) , [ patchModel ] ) ;
59
79
60
80
if ( model . tagName ) {
61
- return html `< ${ Element } sendEvent =${ sendEvent } model=${ model } /> ` ;
81
+ return html `
82
+ < ${ LayoutConfigContext . Provider }
83
+ value =${ {
84
+ sendEvent : sendEvent ,
85
+ importSourceUrl : importSourceUrl ,
86
+ } }
87
+ >
88
+ < ${ Element } model =${ model } />
89
+ </ />
90
+ ` ;
62
91
} else {
63
92
return html `< div /> ` ;
64
93
}
65
94
}
66
95
67
- function Element ( { sendEvent , model } ) {
96
+ function Element ( { model } ) {
68
97
if ( model . importSource ) {
69
- return html `< ${ LazyElement } sendEvent = ${ sendEvent } model=${ model } /> ` ;
98
+ return html `< ${ ImportedElement } model =${ model } /> ` ;
70
99
} else {
71
- const children = elementChildren ( sendEvent , model ) ;
72
- const attributes = elementAttributes ( sendEvent , model ) ;
73
- if ( model . children && model . children . length ) {
74
- return html `< ${ model . tagName } ...${ attributes } > ${ children } </ /> ` ;
75
- } else {
76
- return html `< ${ model . tagName } ...${ attributes } /> ` ;
77
- }
100
+ return html `< ${ StandardElement } model =${ model } /> ` ;
78
101
}
79
102
}
80
103
81
- function LazyElement ( { sendEvent, model } ) {
82
- const module = useLazyModule ( model . importSource . source ) ;
104
+ function ImportedElement ( { model } ) {
105
+ const config = react . useContext ( LayoutConfigContext ) ;
106
+ const module = useLazyModule (
107
+ model . importSource . source ,
108
+ config . importSourceUrl
109
+ ) ;
83
110
if ( module ) {
84
111
const cmpt = getPathProperty ( module , model . tagName ) ;
85
- const children = elementChildren ( sendEvent , model ) ;
86
- const attributes = elementAttributes ( sendEvent , model ) ;
112
+ const children = elementChildren ( model ) ;
113
+ const attributes = elementAttributes ( model , config . sendEvent ) ;
87
114
return html `< ${ cmpt } ...${ attributes } > ${ children } </ /> ` ;
88
115
} else {
89
- return html `< div > ${ model . importSource . fallback } </ /> ` ;
116
+ return createElement ( model . importSource . fallback ) ;
117
+ }
118
+ }
119
+
120
+ function StandardElement ( { model } ) {
121
+ const config = react . useContext ( LayoutConfigContext ) ;
122
+ const children = elementChildren ( model ) ;
123
+ const attributes = elementAttributes ( model , config . sendEvent ) ;
124
+ if ( model . children && model . children . length ) {
125
+ return html `< ${ model . tagName } ...${ attributes } > ${ children } </ /> ` ;
126
+ } else {
127
+ return html `< ${ model . tagName } ...${ attributes } /> ` ;
128
+ }
129
+ }
130
+
131
+ function createElement ( value ) {
132
+ if ( ! value ) {
133
+ return html `< div /> ` ;
134
+ }
135
+ switch ( typeof value ) {
136
+ case "object" :
137
+ return html `< ${ Element } model =${ value } /> ` ;
138
+ case "string" :
139
+ return html `< div > ${ value } </ div > ` ;
90
140
}
91
141
}
92
142
93
- function elementChildren ( sendEvent , model ) {
143
+ function elementChildren ( model ) {
94
144
if ( ! model . children ) {
95
145
return [ ] ;
96
146
} else {
97
147
return model . children . map ( ( child ) => {
98
148
switch ( typeof child ) {
99
149
case "object" :
100
- return html `< ${ Element } model =${ child } sendEvent= ${ sendEvent } /> ` ;
150
+ return html `< ${ Element } model =${ child } /> ` ;
101
151
case "string" :
102
152
return child ;
103
153
}
104
154
} ) ;
105
155
}
106
156
}
107
157
108
- function elementAttributes ( sendEvent , model ) {
158
+ function elementAttributes ( model , sendEvent ) {
109
159
const attributes = Object . assign ( { } , model . attributes ) ;
110
160
111
161
if ( model . eventHandlers ) {
@@ -144,10 +194,12 @@ function eventHandler(sendEvent, eventSpec) {
144
194
} ;
145
195
}
146
196
147
- function useLazyModule ( source ) {
148
- const [ module , setModule ] = react . useState ( alreadyImported [ source ] ) ;
197
+ function useLazyModule ( source , sourceUrl = "" ) {
198
+ const [ module , setModule ] = react . useState ( null ) ;
149
199
if ( ! module ) {
150
- dynamicImport ( source ) . then ( setModule ) ;
200
+ dynamicImport (
201
+ source . startsWith ( "./" ) ? sourceUrl + source . slice ( 2 ) : source
202
+ ) . then ( setModule ) ;
151
203
}
152
204
return module ;
153
205
}
@@ -161,7 +213,7 @@ function dynamicImport(source) {
161
213
} else {
162
214
console . log ( error ) ;
163
215
return {
164
- default : function Catch ( ) {
216
+ default ( ) {
165
217
return html `
166
218
< pre >
167
219
< h1 > Error</ h1 >
0 commit comments