Skip to content

Commit 570096b

Browse files
committed
Allow generic ReactJS component bindings (fix #1001)
1 parent e218929 commit 570096b

File tree

4 files changed

+45
-5
lines changed

4 files changed

+45
-5
lines changed

.prettierrc

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{
22
"proseWrap": "never",
3-
"trailingComma": "all"
3+
"trailingComma": "all",
4+
"endOfLine": "auto"
45
}

src/js/packages/@reactpy/client/src/vdom.tsx

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import type { ReactPyClientInterface } from "./types";
22
import eventToObject from "event-to-object";
3+
import * as preact from "preact";
34
import type {
45
ReactPyVdom,
56
ReactPyVdomImportSource,
@@ -20,14 +21,18 @@ export async function loadImportSource(
2021
} else {
2122
module = await client.loadModule(vdomImportSource.source);
2223
}
23-
if (typeof module.bind !== "function") {
24-
throw new Error(
25-
`${vdomImportSource.source} did not export a function 'bind'`,
24+
25+
let { bind } = module;
26+
if (typeof bind !== "function") {
27+
console.debug(
28+
"Using generic ReactJS binding for components in module",
29+
module,
2630
);
31+
bind = generic_reactjs_bind;
2732
}
2833

2934
return (node: HTMLElement) => {
30-
const binding = module.bind(node, {
35+
const binding = bind(node, {
3136
sendMessage: client.sendMessage,
3237
onMessage: client.onMessage,
3338
});
@@ -254,3 +259,14 @@ function createInlineJavaScript(
254259
wrappedExecutable.isHandler = false;
255260
return [name, wrappedExecutable];
256261
}
262+
263+
function generic_reactjs_bind(node: HTMLElement) {
264+
return {
265+
create: (type: any, props: any, children?: any[]) =>
266+
preact.createElement(type, props, ...(children || [])),
267+
render: (element: any) => {
268+
preact.render(element, node);
269+
},
270+
unmount: () => preact.render(null, node),
271+
};
272+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { h } from "https://unpkg.com/preact?module";
2+
3+
export function GenericComponent(props) {
4+
return h("div", { id: props.id }, props.text);
5+
}

tests/test_web/test_module.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,3 +529,21 @@ def test_reactjs_component_from_string_with_no_name():
529529

530530
reactpy.web.reactjs_component_from_string(content, "Component")
531531
assert len(reactpy.web.module._STRING_WEB_MODULE_CACHE) == initial_length
532+
533+
534+
async def test_module_without_bind(display: DisplayFixture):
535+
GenericComponent = reactpy.web.module._vdom_from_web_module(
536+
reactpy.web.module._module_from_file(
537+
"generic-module", JS_FIXTURES_DIR / "generic-module.js"
538+
),
539+
"GenericComponent",
540+
)
541+
542+
await display.show(
543+
lambda: GenericComponent({"id": "my-generic-component", "text": "Hello World"})
544+
)
545+
546+
element = await display.page.wait_for_selector(
547+
"#my-generic-component", state="attached"
548+
)
549+
assert await element.inner_text() == "Hello World"

0 commit comments

Comments
 (0)