@@ -6,9 +6,13 @@ import * as jsonpatch from "fast-json-patch";
66import serializeEvent from "./event-to-object" ;
77
88const html = htm . bind ( react . createElement ) ;
9- const alreadyImported = { } ;
9+ const LayoutConfigContext = react . createContext ( { } ) ;
1010
11- export function mountLayoutWithWebSocket ( mountElement , endpoint ) {
11+ export function mountLayoutWithWebSocket (
12+ mountElement ,
13+ endpoint ,
14+ importSourceUrl
15+ ) {
1216 if ( endpoint . startsWith ( "." ) || endpoint . startsWith ( "/" ) ) {
1317 let loc = window . location ;
1418 let protocol ;
@@ -42,70 +46,116 @@ export function mountLayoutWithWebSocket(mountElement, endpoint) {
4246 ) ;
4347 }
4448
45- return mountLayout ( mountElement , saveUpdateHook , sendCallback ) ;
49+ return mountLayout (
50+ mountElement ,
51+ saveUpdateHook ,
52+ sendCallback ,
53+ importSourceUrl
54+ ) ;
4655}
4756
48- export function mountLayout ( mountElement , saveUpdateHook , sendEvent ) {
57+ export function mountLayout (
58+ mountElement ,
59+ saveUpdateHook ,
60+ sendEvent ,
61+ importSourceUrl
62+ ) {
4963 reactDOM . render (
50- html `< ${ Layout } saveUpdateHook =${ saveUpdateHook } sendEvent=${ sendEvent } /> ` ,
64+ html `
65+ < ${ Layout }
66+ saveUpdateHook =${ saveUpdateHook }
67+ sendEvent=${ sendEvent }
68+ importSourceUrl=${ importSourceUrl }
69+ />
70+ ` ,
5171 mountElement
5272 ) ;
5373}
5474
55- export default function Layout ( { saveUpdateHook, sendEvent } ) {
75+ export default function Layout ( { saveUpdateHook, sendEvent, importSourceUrl } ) {
5676 const [ model , patchModel ] = useInplaceJsonPatch ( { } ) ;
5777
5878 react . useEffect ( ( ) => saveUpdateHook ( patchModel ) , [ patchModel ] ) ;
5979
6080 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+ ` ;
6291 } else {
6392 return html `< div /> ` ;
6493 }
6594}
6695
67- function Element ( { sendEvent , model } ) {
96+ function Element ( { model } ) {
6897 if ( model . importSource ) {
69- return html `< ${ LazyElement } sendEvent = ${ sendEvent } model=${ model } /> ` ;
98+ return html `< ${ ImportedElement } model =${ model } /> ` ;
7099 } 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 } /> ` ;
78101 }
79102}
80103
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+ ) ;
83110 if ( module ) {
84111 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 ) ;
87114 return html `< ${ cmpt } ...${ attributes } > ${ children } </ /> ` ;
88115 } 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 > ` ;
90140 }
91141}
92142
93- function elementChildren ( sendEvent , model ) {
143+ function elementChildren ( model ) {
94144 if ( ! model . children ) {
95145 return [ ] ;
96146 } else {
97147 return model . children . map ( ( child ) => {
98148 switch ( typeof child ) {
99149 case "object" :
100- return html `< ${ Element } model =${ child } sendEvent= ${ sendEvent } /> ` ;
150+ return html `< ${ Element } model =${ child } /> ` ;
101151 case "string" :
102152 return child ;
103153 }
104154 } ) ;
105155 }
106156}
107157
108- function elementAttributes ( sendEvent , model ) {
158+ function elementAttributes ( model , sendEvent ) {
109159 const attributes = Object . assign ( { } , model . attributes ) ;
110160
111161 if ( model . eventHandlers ) {
@@ -144,10 +194,12 @@ function eventHandler(sendEvent, eventSpec) {
144194 } ;
145195}
146196
147- function useLazyModule ( source ) {
148- const [ module , setModule ] = react . useState ( alreadyImported [ source ] ) ;
197+ function useLazyModule ( source , sourceUrl = "" ) {
198+ const [ module , setModule ] = react . useState ( null ) ;
149199 if ( ! module ) {
150- dynamicImport ( source ) . then ( setModule ) ;
200+ dynamicImport (
201+ source . startsWith ( "./" ) ? sourceUrl + source . slice ( 2 ) : source
202+ ) . then ( setModule ) ;
151203 }
152204 return module ;
153205}
@@ -161,7 +213,7 @@ function dynamicImport(source) {
161213 } else {
162214 console . log ( error ) ;
163215 return {
164- default : function Catch ( ) {
216+ default ( ) {
165217 return html `
166218 < pre >
167219 < h1 > Error</ h1 >
0 commit comments