diff --git a/docs/source/about/changelog.rst b/docs/source/about/changelog.rst index ae54e44d5..10215f200 100644 --- a/docs/source/about/changelog.rst +++ b/docs/source/about/changelog.rst @@ -36,6 +36,14 @@ Unreleased - ``ServerFixture -> BackendFixture`` - ``DisplayFixture.server -> DisplayFixture.backend`` +- :pull:`765` - ``exports_default`` parameter is not longer required for + ``module_from_template`` when exporting ``default``. + +**Added** + +- :pull:`765` - ability to specify versions with module templates (e.g. + ``module_from_template("react@^17.0.0", ...)``). + v0.38.1 ------- diff --git a/docs/source/guides/escape-hatches/_examples/material_ui_button_no_action.py b/docs/source/guides/escape-hatches/_examples/material_ui_button_no_action.py index d8f57de08..55817f9dd 100644 --- a/docs/source/guides/escape-hatches/_examples/material_ui_button_no_action.py +++ b/docs/source/guides/escape-hatches/_examples/material_ui_button_no_action.py @@ -1,11 +1,17 @@ -import idom +from idom import component, run, web -mui = idom.web.module_from_template("react", "@material-ui/core@^5.0", fallback="⌛") -Button = idom.web.export(mui, "Button") - -idom.run( - idom.component( - lambda: Button({"color": "primary", "variant": "contained"}, "Hello World!") - ) +mui = web.module_from_template( + "react@^17.0.0", + "@material-ui/core@4.12.4", + fallback="⌛", ) +Button = web.export(mui, "Button") + + +@component +def HelloWorld(): + return Button({"color": "primary", "variant": "contained"}, "Hello World!") + + +run(HelloWorld) diff --git a/docs/source/guides/escape-hatches/_examples/material_ui_button_on_click.py b/docs/source/guides/escape-hatches/_examples/material_ui_button_on_click.py index 41a3b7c54..e7c327ba0 100644 --- a/docs/source/guides/escape-hatches/_examples/material_ui_button_on_click.py +++ b/docs/source/guides/escape-hatches/_examples/material_ui_button_on_click.py @@ -3,7 +3,11 @@ import idom -mui = idom.web.module_from_template("react", "@material-ui/core@^5.0", fallback="⌛") +mui = idom.web.module_from_template( + "react@^17.0.0", + "@material-ui/core@4.12.4", + fallback="⌛", +) Button = idom.web.export(mui, "Button") diff --git a/docs/source/guides/escape-hatches/_examples/super_simple_chart/super-simple-chart.js b/docs/source/guides/escape-hatches/_examples/super_simple_chart/super-simple-chart.js index 71f117860..486e5c363 100644 --- a/docs/source/guides/escape-hatches/_examples/super_simple_chart/super-simple-chart.js +++ b/docs/source/guides/escape-hatches/_examples/super_simple_chart/super-simple-chart.js @@ -48,10 +48,9 @@ function makePath(props, domain, data, options) { const getSvgX = (x) => ((x - xMin) / (xMax - xMin)) * width; const getSvgY = (y) => height - ((y - yMin) / (yMax - yMin)) * height; - let pathD = "M " + getSvgX(data[0].x) + " " + getSvgY(data[0].y) + " "; - pathD += data.map((point, i) => { - return "L " + getSvgX(point.x) + " " + getSvgY(point.y) + " "; - }); + let pathD = + `M ${getSvgX(data[0].x)} ${getSvgY(data[0].y)} ` + + data.map(({ x, y }, i) => `L ${getSvgX(x)} ${getSvgY(y)}`).join(" "); return html` - React.createElement(component, wrapEventHandlers(props), ...children), - render: (element) => ReactDOM.render(element, node), - unmount: () => ReactDOM.unmountComponentAtNode(node), - }; -} - -function wrapEventHandlers(props) { - const newProps = Object.assign({}, props); - for (const [key, value] of Object.entries(props)) { - if (typeof value === "function") { - newProps[key] = makeJsonSafeEventHandler(value); - } - } - return newProps; -} - -function makeJsonSafeEventHandler(oldHandler) { - // Since we can't really know what the event handlers get passed we have to check if - // they are JSON serializable or not. We can allow normal synthetic events to pass - // through since the original handler already knows how to serialize those for us. - return function safeEventHandler() { - oldHandler( - ...Array.from(arguments).filter((value) => { - if (typeof value === "object" && value.nativeEvent) { - // this is probably a standard React synthetic event - return true; - } else { - try { - JSON.stringify(value); - } catch (err) { - console.error("Failed to serialize some event data"); - return false; - } - return true; - } - }) - ); - }; -} diff --git a/src/idom/web/templates/react.js b/src/idom/web/templates/react.js index f4e2b091f..00924f85a 100644 --- a/src/idom/web/templates/react.js +++ b/src/idom/web/templates/react.js @@ -1,7 +1,20 @@ export * from "$CDN/$PACKAGE"; -import * as React from "$CDN/react"; -import * as ReactDOM from "$CDN/react-dom"; +import * as React from "$CDN/react$VERSION"; +import * as ReactDOM from "$CDN/react-dom$VERSION"; + +export default ({ children, ...props }) => { + const [{ component }, setComponent] = React.useState({}); + React.useEffect(() => { + import("$CDN/$PACKAGE").then((module) => { + // dynamically load the default export since we don't know if it's exported. + setComponent({ component: module.default }); + }); + }); + return component + ? React.createElement(component, props, ...(children || [])) + : null; +}; export function bind(node, config) { return { diff --git a/tests/test_server/__init__.py b/tests/test_backend/__init__.py similarity index 100% rename from tests/test_server/__init__.py rename to tests/test_backend/__init__.py diff --git a/tests/test_server/test_common.py b/tests/test_backend/test_common.py similarity index 100% rename from tests/test_server/test_common.py rename to tests/test_backend/test_common.py diff --git a/tests/test_server/test_utils.py b/tests/test_backend/test_utils.py similarity index 100% rename from tests/test_server/test_utils.py rename to tests/test_backend/test_utils.py diff --git a/tests/test_web/test_module.py b/tests/test_web/test_module.py index 48b981ba9..497b89787 100644 --- a/tests/test_web/test_module.py +++ b/tests/test_web/test_module.py @@ -83,7 +83,9 @@ def test_module_from_template_where_template_does_not_exist(): async def test_module_from_template(display: DisplayFixture): - victory = idom.web.module_from_template("react", "victory-bar@35.4.0") + victory = idom.web.module_from_template("react@18.2.0", "victory-bar@35.4.0") + + assert "react@18.2.0" in victory.file.read_text() VictoryBar = idom.web.export(victory, "VictoryBar") await display.show(VictoryBar)