Skip to content

Commit 1a4fcaa

Browse files
committed
Refactor javascript
1 parent 16f076d commit 1a4fcaa

File tree

6 files changed

+71
-68
lines changed

6 files changed

+71
-68
lines changed

pyproject.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ installer = "uv"
7575
[[tool.hatch.build.hooks.build-scripts.scripts]]
7676
commands = [
7777
"bun install --cwd src/js",
78-
"bun build src/js/src/index.tsx --outfile src/reactpy_django/static/reactpy_django/client.js --minify",
78+
"bun build src/js/src/index.ts --outfile src/reactpy_django/static/reactpy_django/client.js --minify",
7979
'cd src/build_scripts && python copy_dir.py "src/js/node_modules/@pyscript/core/dist" "src/reactpy_django/static/reactpy_django/pyscript"',
8080
'cd src/build_scripts && python copy_dir.py "src/js/node_modules/morphdom/dist" "src/reactpy_django/static/reactpy_django/morphdom"',
8181
]

src/js/src/client.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -30,14 +30,14 @@ export class ReactPyDjangoClient
3030
this.prerenderElement.remove();
3131
this.prerenderElement = null;
3232
}
33-
if (this.offlineElement) {
33+
if (this.offlineElement && this.mountElement) {
3434
this.mountElement.hidden = true;
3535
this.offlineElement.hidden = false;
3636
}
3737
},
3838
onOpen: () => {
3939
// If offlineElement exists, hide it and show the mountElement
40-
if (this.offlineElement) {
40+
if (this.offlineElement && this.mountElement) {
4141
this.offlineElement.hidden = true;
4242
this.mountElement.hidden = false;
4343
}

src/js/src/components.ts

+64
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { DjangoFormProps } from "./types";
2+
import React from "react";
3+
import ReactDOM from "react-dom";
4+
/**
5+
* Interface used to bind a ReactPy node to React.
6+
*/
7+
export function bind(node) {
8+
return {
9+
create: (type, props, children) =>
10+
React.createElement(type, props, ...children),
11+
render: (element) => {
12+
ReactDOM.render(element, node);
13+
},
14+
unmount: () => ReactDOM.unmountComponentAtNode(node),
15+
};
16+
}
17+
18+
export function DjangoForm({
19+
onSubmitCallback,
20+
formId,
21+
}: DjangoFormProps): null {
22+
React.useEffect(() => {
23+
const form = document.getElementById(formId) as HTMLFormElement;
24+
25+
// Submission event function
26+
const onSubmitEvent = (event) => {
27+
event.preventDefault();
28+
const formData = new FormData(form);
29+
30+
// Convert the FormData object to a plain object by iterating through it
31+
// If duplicate keys are present, convert the value into an array of values
32+
const entries = formData.entries();
33+
const formDataArray = Array.from(entries);
34+
const formDataObject = formDataArray.reduce((acc, [key, value]) => {
35+
if (acc[key]) {
36+
if (Array.isArray(acc[key])) {
37+
acc[key].push(value);
38+
} else {
39+
acc[key] = [acc[key], value];
40+
}
41+
} else {
42+
acc[key] = value;
43+
}
44+
return acc;
45+
}, {});
46+
47+
onSubmitCallback(formDataObject);
48+
};
49+
50+
// Bind the event listener
51+
if (form) {
52+
form.addEventListener("submit", onSubmitEvent);
53+
}
54+
55+
// Unbind the event listener when the component dismounts
56+
return () => {
57+
if (form) {
58+
form.removeEventListener("submit", onSubmitEvent);
59+
}
60+
};
61+
}, []);
62+
63+
return null;
64+
}

src/js/src/index.ts

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export { DjangoForm, bind } from "./components";
2+
export { mountComponent } from "./mount";

src/js/src/index.tsx renamed to src/js/src/mount.tsx

+1-64
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,6 @@ import { ReactPyDjangoClient } from "./client";
22
import React from "react";
33
import ReactDOM from "react-dom";
44
import { Layout } from "@reactpy/client/src/components";
5-
import { DjangoFormProps } from "./types";
6-
7-
/**
8-
* Interface used to bind a ReactPy node to React.
9-
*/
10-
export function bind(node) {
11-
return {
12-
create: (type, props, children) =>
13-
React.createElement(type, props, ...children),
14-
render: (element) => {
15-
ReactDOM.render(element, node);
16-
},
17-
unmount: () => ReactDOM.unmountComponentAtNode(node),
18-
};
19-
}
205

216
export function mountComponent(
227
mountElement: HTMLElement,
@@ -84,7 +69,7 @@ export function mountComponent(
8469
// Replace the prerender element with the real element on the first layout update
8570
if (client.prerenderElement) {
8671
client.onMessage("layout-update", ({ path, model }) => {
87-
if (client.prerenderElement) {
72+
if (client.prerenderElement && client.mountElement) {
8873
client.prerenderElement.replaceWith(client.mountElement);
8974
client.prerenderElement = null;
9075
}
@@ -94,51 +79,3 @@ export function mountComponent(
9479
// Start rendering the component
9580
ReactDOM.render(<Layout client={client} />, client.mountElement);
9681
}
97-
98-
export function DjangoForm({
99-
onSubmitCallback,
100-
formId,
101-
}: DjangoFormProps): null {
102-
React.useEffect(() => {
103-
const form = document.getElementById(formId) as HTMLFormElement;
104-
105-
// Submission event function
106-
const onSubmitEvent = (event) => {
107-
event.preventDefault();
108-
const formData = new FormData(form);
109-
110-
// Convert the FormData object to a plain object by iterating through it
111-
// If duplicate keys are present, convert the value into an array of values
112-
const entries = formData.entries();
113-
const formDataArray = Array.from(entries);
114-
const formDataObject = formDataArray.reduce((acc, [key, value]) => {
115-
if (acc[key]) {
116-
if (Array.isArray(acc[key])) {
117-
acc[key].push(value);
118-
} else {
119-
acc[key] = [acc[key], value];
120-
}
121-
} else {
122-
acc[key] = value;
123-
}
124-
return acc;
125-
}, {});
126-
127-
onSubmitCallback(formDataObject);
128-
};
129-
130-
// Bind the event listener
131-
if (form) {
132-
form.addEventListener("submit", onSubmitEvent);
133-
}
134-
135-
// Unbind the event listener when the component dismounts
136-
return () => {
137-
if (form) {
138-
form.removeEventListener("submit", onSubmitEvent);
139-
}
140-
};
141-
}, []);
142-
143-
return null;
144-
}

tests/test_app/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
assert subprocess.run(["bun", "install"], cwd=str(js_dir), check=True).returncode == 0
99
assert (
1010
subprocess.run(
11-
["bun", "build", "./src/index.tsx", "--outfile", str(static_dir / "client.js")],
11+
["bun", "build", "./src/index.ts", "--outfile", str(static_dir / "client.js")],
1212
cwd=str(js_dir),
1313
check=True,
1414
).returncode

0 commit comments

Comments
 (0)