diff --git a/Cargo.lock b/Cargo.lock
index bfe3995..9d49099 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -82,6 +82,7 @@ version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"react-reconciler",
+ "shared",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
@@ -93,6 +94,7 @@ version = "0.1.0"
dependencies = [
"console_error_panic_hook",
"react",
+ "shared",
"wasm-bindgen",
"wasm-bindgen-test",
"web-sys",
diff --git a/examples/hello-world/src/main.tsx b/examples/hello-world/src/main.tsx
index 78a90af..e70c233 100644
--- a/examples/hello-world/src/main.tsx
+++ b/examples/hello-world/src/main.tsx
@@ -2,6 +2,6 @@ import {createRoot} from 'react-dom'
const comp =
hello world
-console.log(comp)
-console.log(createRoot(document.getElementById("root")))
+const root = createRoot(document.getElementById("root"))
+root.render(comp)
diff --git a/packages/react-dom/Cargo.toml b/packages/react-dom/Cargo.toml
index d5289e9..78d0653 100644
--- a/packages/react-dom/Cargo.toml
+++ b/packages/react-dom/Cargo.toml
@@ -12,8 +12,9 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
-web-sys = { version = "0.3.69", features = ["console"] }
+web-sys = { version = "0.3.69", features = ["console", "Window", "Document", "Text", "Element"] }
react-reconciler = { path = "../react-reconciler" }
+shared = { path = "../shared" }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
diff --git a/packages/react-dom/src/host_config.rs b/packages/react-dom/src/host_config.rs
new file mode 100644
index 0000000..5921218
--- /dev/null
+++ b/packages/react-dom/src/host_config.rs
@@ -0,0 +1,41 @@
+use std::any::Any;
+use std::rc::Rc;
+
+use web_sys::{Element, Text, window};
+
+use react_reconciler::HostConfig;
+use shared::log;
+
+pub struct ReactDomHostConfig;
+
+impl HostConfig for ReactDomHostConfig {
+ fn create_text_instance(&self, content: String) -> Rc {
+ let window = window().expect("no global `window` exists");
+ let document = window.document().expect("should have a document on window");
+ Rc::new(document.create_text_node(content.as_str()))
+ }
+
+ fn create_instance(&self, _type: String) -> Rc {
+ let window = window().expect("no global `window` exists");
+ let document = window.document().expect("should have a document on window");
+ match document.create_element(_type.as_ref()) {
+ Ok(element) => Rc::new(element),
+ Err(_) => todo!(),
+ }
+ }
+
+ fn append_initial_child(&self, parent: Rc, child: Rc) {
+ let parent = parent.clone().downcast::().unwrap();
+ let child = child.downcast::().unwrap();
+ match parent.append_child(&child) {
+ Ok(_) => {
+ log!("append_initial_child successfully ele {:?} {:?}", parent, child);
+ }
+ Err(_) => todo!(),
+ }
+ }
+
+ fn append_child_to_container(&self, child: Rc, parent: Rc) {
+ todo!()
+ }
+}
\ No newline at end of file
diff --git a/packages/react-dom/src/lib.rs b/packages/react-dom/src/lib.rs
index 5a09ad6..4487e37 100644
--- a/packages/react-dom/src/lib.rs
+++ b/packages/react-dom/src/lib.rs
@@ -1,8 +1,20 @@
use wasm_bindgen::prelude::*;
+use react_reconciler::Reconciler;
+
+use crate::host_config::ReactDomHostConfig;
+use crate::renderer::Renderer;
+use crate::utils::set_panic_hook;
+
mod utils;
+mod renderer;
+mod host_config;
-#[wasm_bindgen]
-pub fn createRoot(container: &JsValue) -> JsValue {
- JsValue::null()
-}
+#[wasm_bindgen(js_name = createRoot)]
+pub fn create_root(container: &JsValue) -> Renderer {
+ set_panic_hook();
+ let reconciler = Reconciler::new(Box::new(ReactDomHostConfig));
+ let root = reconciler.create_container(container);
+ let renderer = Renderer::new(root, reconciler);
+ renderer
+}
\ No newline at end of file
diff --git a/packages/react-dom/src/renderer.rs b/packages/react-dom/src/renderer.rs
new file mode 100644
index 0000000..e744b61
--- /dev/null
+++ b/packages/react-dom/src/renderer.rs
@@ -0,0 +1,28 @@
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use wasm_bindgen::JsValue;
+use wasm_bindgen::prelude::*;
+use wasm_bindgen::prelude::wasm_bindgen;
+
+use react_reconciler::fiber::FiberRootNode;
+use react_reconciler::Reconciler;
+
+#[wasm_bindgen]
+pub struct Renderer {
+ root: Rc>,
+ reconciler: Reconciler,
+}
+
+impl Renderer {
+ pub fn new(root: Rc>, reconciler: Reconciler) -> Self {
+ Self { root, reconciler }
+ }
+}
+
+#[wasm_bindgen]
+impl Renderer {
+ pub fn render(&self, element: &JsValue) {
+ self.reconciler.update_container(Rc::new(element.clone()), self.root.clone())
+ }
+}
\ No newline at end of file
diff --git a/packages/react-reconciler/Cargo.toml b/packages/react-reconciler/Cargo.toml
index c225c52..e30daae 100644
--- a/packages/react-reconciler/Cargo.toml
+++ b/packages/react-reconciler/Cargo.toml
@@ -12,8 +12,9 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
-web-sys = { version = "0.3.69", features = ["console"] }
+web-sys = { version = "0.3.69", features = ["console", "Text", "Window", "Document", "HtmlElement"] }
react = { path = "../react" }
+shared = { path = "../shared" }
# The `console_error_panic_hook` crate provides better debugging of panics by
# logging them with `console.error`. This is great for development, but requires
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
diff --git a/packages/react-reconciler/src/fiber.rs b/packages/react-reconciler/src/fiber.rs
new file mode 100644
index 0000000..96c2bc7
--- /dev/null
+++ b/packages/react-reconciler/src/fiber.rs
@@ -0,0 +1,2 @@
+#[derive(Debug)]
+pub struct FiberRootNode {}
\ No newline at end of file
diff --git a/packages/react-reconciler/src/lib.rs b/packages/react-reconciler/src/lib.rs
index e69de29..31ddbf6 100644
--- a/packages/react-reconciler/src/lib.rs
+++ b/packages/react-reconciler/src/lib.rs
@@ -0,0 +1,46 @@
+use std::any::Any;
+use std::cell::RefCell;
+use std::rc::Rc;
+
+use wasm_bindgen::JsValue;
+use web_sys::{Element, window};
+use web_sys::js_sys::Reflect;
+
+use crate::fiber::FiberRootNode;
+
+pub mod fiber;
+
+pub trait HostConfig {
+ fn create_text_instance(&self, content: String) -> Rc;
+ fn create_instance(&self, _type: String) -> Rc;
+ fn append_initial_child(&self, parent: Rc, child: Rc);
+ fn append_child_to_container(&self, child: Rc, parent: Rc);
+}
+
+pub struct Reconciler {
+ host_config: Box,
+}
+
+impl Reconciler {
+ pub fn new(host_config: Box) -> Self {
+ Reconciler { host_config }
+ }
+ pub fn create_container(&self, container: &JsValue) -> Rc> {
+ Rc::new(RefCell::new(FiberRootNode {}))
+ }
+
+ pub fn update_container(&self, element: Rc, root: Rc>) {
+ let props = Reflect::get(&*element, &JsValue::from_str("props")).unwrap();
+ let _type = Reflect::get(&*element, &JsValue::from_str("type")).unwrap();
+ let children = Reflect::get(&props, &JsValue::from_str("children")).unwrap();
+ let text_instance = self.host_config.create_text_instance(children.as_string().unwrap());
+ let div_instance = self.host_config.create_instance(_type.as_string().unwrap());
+ self.host_config.append_initial_child(div_instance.clone(), text_instance);
+ let window = window().unwrap();
+ let document = window.document().unwrap();
+ let body = document.body().expect("document should have a body");
+ body.append_child(&*div_instance.clone().downcast::().unwrap());
+ }
+}
+
+
diff --git a/packages/shared/src/lib.rs b/packages/shared/src/lib.rs
index 433e5d7..3fd8ffe 100644
--- a/packages/shared/src/lib.rs
+++ b/packages/shared/src/lib.rs
@@ -1 +1,8 @@
-pub static REACT_ELEMENT_TYPE: &str = "react.element";
\ No newline at end of file
+pub static REACT_ELEMENT_TYPE: &str = "react.element";
+
+#[macro_export]
+macro_rules! log {
+ ( $( $t:tt )* ) => {
+ web_sys::console::log_1(&format!( $( $t )* ).into());
+ }
+}
\ No newline at end of file