diff --git a/src/idom/client/app/packages/idom-client-react/src/index.js b/src/idom/client/app/packages/idom-client-react/src/index.js index e5cc53bc0..d18d406ea 100644 --- a/src/idom/client/app/packages/idom-client-react/src/index.js +++ b/src/idom/client/app/packages/idom-client-react/src/index.js @@ -66,7 +66,7 @@ function ImportedElement({ model }) { model.importSource.source ); eval(`import("${importSource}")`).then((module) => { - mountImportSource(module, mountPoint.current, model, config); + mountImportSource(mountPoint.current, module, model, config); }); }); return html`
`; @@ -137,21 +137,26 @@ function eventHandler(sendEvent, eventSpec) { }; } -function mountImportSource(module, mountPoint, model, config) { - const mountFunction = model.importSource.hasMount - ? module.mount - : (element, component, props, children) => - reactDOM.render( - react.createElement(component, props, ...children), - element - ); - - const component = module[model.tagName]; - const children = elementChildren(model); - const attributes = elementAttributes(model, config.sendEvent); - const props = { key: model.key, ...attributes }; - - mountFunction(mountPoint, component, props, children); +function mountImportSource(element, module, model, config) { + if (model.importSource.hasMount) { + if (model.children) { + console.error("Mount function does not support children"); + } + module.mount( + element, + module[model.tagName], + elementAttributes(model, config.sendEvent) + ); + } else { + reactDOM.render( + react.createElement( + module[model.tagName], + elementAttributes(model, config.sendEvent), + ...elementChildren(model) + ), + element + ); + } } function useInplaceJsonPatch(doc) { diff --git a/src/idom/client/module.py b/src/idom/client/module.py index 0ed138382..09a7eec53 100644 --- a/src/idom/client/module.py +++ b/src/idom/client/module.py @@ -129,7 +129,7 @@ def __init__( def declare( self, name: str, - has_children: bool = True, + has_children: Optional[bool] = None, fallback: Optional[str] = None, ) -> Import: """Return an :class:`Import` for the given :class:`Module` and ``name`` @@ -147,10 +147,11 @@ def declare( raise ValueError( f"{self} does not export {name!r}, available options are {list(self.exports)}" ) + return Import( self.url, name, - has_children, + has_children=has_children, has_mount=self.has_mount, fallback=fallback or self.fallback, ) @@ -183,7 +184,7 @@ def __init__( self, module: str, name: str, - has_children: bool = True, + has_children: Optional[bool] = None, has_mount: bool = False, fallback: Optional[str] = None, ) -> None: @@ -192,6 +193,16 @@ def __init__( f"{IDOM_CLIENT_MODULES_MUST_HAVE_MOUNT} is set and {module} has no mount" ) + if has_mount: + if has_children is True: + raise ValueError( + f"Components of {module!r} do not support " + "children because has_mount=True" + ) + has_children = False + else: + has_children = bool(has_children) + self._name = name self._constructor = make_vdom_constructor(name, has_children) self._import_source = ImportSourceDict( diff --git a/tests/test_client/js/vanilla-js-component.js b/tests/test_client/js/vanilla-js-component.js index 6a9e45687..51e18c7e2 100644 --- a/tests/test_client/js/vanilla-js-component.js +++ b/tests/test_client/js/vanilla-js-component.js @@ -1,7 +1,7 @@ -export function mount(element, component, props, children) { - component(element, props, children); +export function mount(element, component, props) { + component(element, props); } -export function SetInnerHtml(element, props, children) { +export function SetInnerHtml(element, props) { element.innerHTML = props.innerHTML; } diff --git a/tests/test_client/test_module.py b/tests/test_client/test_module.py index 62d221737..e84b43c70 100644 --- a/tests/test_client/test_module.py +++ b/tests/test_client/test_module.py @@ -95,6 +95,21 @@ def test_idom_client_modules_must_have_mount(): IDOM_CLIENT_MODULES_MUST_HAVE_MOUNT.current = True try: with pytest.raises(RuntimeError, match="has no mount"): - idom.Module("https://some.url", has_mount=False).SomeComponent + idom.Import( + "https://some.url", + "SomeComponent", + has_mount=False, + ) finally: IDOM_CLIENT_MODULES_MUST_HAVE_MOUNT.current = old_opt + + +def test_no_children_if_import_has_mount(): + with pytest.raises(ValueError, match="do not support children"): + idom.Import( + "https://some.url", + "SomeComponent", + has_children=True, + has_mount=True, + fallback=None, + )