diff --git a/Cargo.lock b/Cargo.lock
index ec39ddf..5c73bd3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,6 +2,21 @@
# It is not intended for manual editing.
version = 3
+[[package]]
+name = "autocfg"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
[[package]]
name = "bitflags"
version = "2.5.0"
@@ -14,6 +29,12 @@ version = "3.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ff69b9dd49fd426c69a0db9fc04dd934cdb6645ff000864d98f7e2af8830eaa"
+[[package]]
+name = "bytes"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9"
+
[[package]]
name = "cfg-if"
version = "1.0.0"
@@ -30,6 +51,331 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "form_urlencoded"
+version = "1.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "futures"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-sink",
+ "futures-task",
+ "futures-util",
+]
+
+[[package]]
+name = "futures-channel"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78"
+dependencies = [
+ "futures-core",
+ "futures-sink",
+]
+
+[[package]]
+name = "futures-core"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d"
+
+[[package]]
+name = "futures-io"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1"
+
+[[package]]
+name = "futures-macro"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "futures-sink"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5"
+
+[[package]]
+name = "futures-task"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004"
+
+[[package]]
+name = "futures-util"
+version = "0.3.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-io",
+ "futures-macro",
+ "futures-sink",
+ "futures-task",
+ "memchr",
+ "pin-project-lite",
+ "pin-utils",
+ "slab",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gloo"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d15282ece24eaf4bd338d73ef580c6714c8615155c4190c781290ee3fa0fd372"
+dependencies = [
+ "gloo-console",
+ "gloo-dialogs",
+ "gloo-events",
+ "gloo-file",
+ "gloo-history",
+ "gloo-net",
+ "gloo-render",
+ "gloo-storage",
+ "gloo-timers",
+ "gloo-utils",
+ "gloo-worker",
+]
+
+[[package]]
+name = "gloo-console"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2a17868f56b4a24f677b17c8cb69958385102fa879418052d60b50bc1727e261"
+dependencies = [
+ "gloo-utils",
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-dialogs"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf4748e10122b01435750ff530095b1217cf6546173459448b83913ebe7815df"
+dependencies = [
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-events"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "27c26fb45f7c385ba980f5fa87ac677e363949e065a083722697ef1b2cc91e41"
+dependencies = [
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-file"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97563d71863fb2824b2e974e754a81d19c4a7ec47b09ced8a0e6656b6d54bd1f"
+dependencies = [
+ "gloo-events",
+ "js-sys",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-history"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "903f432be5ba34427eac5e16048ef65604a82061fe93789f2212afc73d8617d6"
+dependencies = [
+ "getrandom",
+ "gloo-events",
+ "gloo-utils",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_urlencoded",
+ "thiserror",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-net"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43aaa242d1239a8822c15c645f02166398da4f8b5c4bae795c1f5b44e9eee173"
+dependencies = [
+ "futures-channel",
+ "futures-core",
+ "futures-sink",
+ "gloo-utils",
+ "http",
+ "js-sys",
+ "pin-project",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-render"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "56008b6744713a8e8d98ac3dcb7d06543d5662358c9c805b4ce2167ad4649833"
+dependencies = [
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-storage"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fbc8031e8c92758af912f9bc08fbbadd3c6f3cfcbf6b64cdf3d6a81f0139277a"
+dependencies = [
+ "gloo-utils",
+ "js-sys",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-timers"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bbb143cf96099802033e0d4f4963b19fd2e0b728bcf076cd9cf7f6634f092994"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "gloo-utils"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b5555354113b18c547c1d3a98fbf7fb32a9ff4f6fa112ce823a21641a0ba3aa"
+dependencies = [
+ "js-sys",
+ "serde",
+ "serde_json",
+ "wasm-bindgen",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-worker"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "085f262d7604911c8150162529cefab3782e91adb20202e8658f7275d2aefe5d"
+dependencies = [
+ "bincode",
+ "futures",
+ "gloo-utils",
+ "gloo-worker-macros",
+ "js-sys",
+ "pinned",
+ "serde",
+ "thiserror",
+ "wasm-bindgen",
+ "wasm-bindgen-futures",
+ "web-sys",
+]
+
+[[package]]
+name = "gloo-worker-macros"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "956caa58d4857bc9941749d55e4bd3000032d8212762586fa5705632967140e7"
+dependencies = [
+ "proc-macro-crate",
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "http"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1"
+dependencies = [
+ "bytes",
+ "fnv",
+ "itoa",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
[[package]]
name = "js-sys"
version = "0.3.69"
@@ -39,18 +385,89 @@ dependencies = [
"wasm-bindgen",
]
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
[[package]]
name = "log"
version = "0.4.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+[[package]]
+name = "memchr"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+
[[package]]
name = "once_cell"
version = "1.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "pin-project"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3"
+dependencies = [
+ "pin-project-internal",
+]
+
+[[package]]
+name = "pin-project-internal"
+version = "1.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "pin-project-lite"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02"
+
+[[package]]
+name = "pin-utils"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
+
+[[package]]
+name = "pinned"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b"
+dependencies = [
+ "futures",
+ "rustversion",
+ "thiserror",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "1.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919"
+dependencies = [
+ "once_cell",
+ "toml_edit",
+]
+
[[package]]
name = "proc-macro2"
version = "1.0.79"
@@ -87,6 +504,8 @@ name = "react-dom"
version = "0.1.0"
dependencies = [
"console_error_panic_hook",
+ "gloo",
+ "js-sys",
"react-reconciler",
"shared",
"wasm-bindgen",
@@ -107,12 +526,78 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "rustversion"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
+
+[[package]]
+name = "ryu"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+
[[package]]
name = "scoped-tls"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294"
+[[package]]
+name = "serde"
+version = "1.0.199"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c9f6e76df036c77cd94996771fb40db98187f096dd0b9af39c6c6e452ba966a"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde-wasm-bindgen"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
+dependencies = [
+ "js-sys",
+ "serde",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.199"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11bd257a6541e141e42ca6d24ae26f7714887b47e89aa739099104c7e4d3b7fc"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.116"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3e17db7126d17feb94eb3fad46bf1a96b034e8aacbc2e775fe81505f8b0b2813"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_urlencoded"
+version = "0.7.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd"
+dependencies = [
+ "form_urlencoded",
+ "itoa",
+ "ryu",
+ "serde",
+]
+
[[package]]
name = "shared"
version = "0.1.0"
@@ -120,6 +605,15 @@ dependencies = [
"web-sys",
]
+[[package]]
+name = "slab"
+version = "0.4.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67"
+dependencies = [
+ "autocfg",
+]
+
[[package]]
name = "syn"
version = "2.0.53"
@@ -131,12 +625,55 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "thiserror"
+version = "1.0.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0126ad08bff79f29fc3ae6a55cc72352056dfff61e3ff8bb7129476d44b23aa"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+
+[[package]]
+name = "toml_edit"
+version = "0.19.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow",
+]
+
[[package]]
name = "unicode-ident"
version = "1.0.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
[[package]]
name = "wasm-bindgen"
version = "0.2.92"
@@ -237,3 +774,12 @@ dependencies = [
"js-sys",
"wasm-bindgen",
]
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
diff --git a/examples/hello-world/src/App.tsx b/examples/hello-world/src/App.tsx
index 862ad52..cbe2731 100644
--- a/examples/hello-world/src/App.tsx
+++ b/examples/hello-world/src/App.tsx
@@ -1,24 +1,31 @@
import {useState} from 'react'
-let n = 0
function App() {
- const [name, setName] = useState(() => false)
- const [age, setAge] = useState(() => 10)
- if (n === 0) {
- let tid = setTimeout(() => {
- n++
- setName(true)
- setAge(11)
- clearTimeout((tid))
- }, 1000)
- }
+ const [num, updateNum] = useState(0);
- return name ? {name + age} : 'N/A'
+ const isOdd = num % 2;
+
+ return (
+
{
+ e.stopPropagation()
+ console.log('click h3', e.currentTarget)
+ updateNum(prev => prev + 1);
+ }}
+ >
+ {
+ console.log('click div', e.currentTarget)
+ }}>
+ {isOdd ?
odd
:
even
}
+
+
+
+ );
}
-function Comp({children}) {
- return {`Hello world, ${children}`}
+function Child({num}: { num: number }) {
+ return {num}
;
}
export default App
diff --git a/examples/hello-world/src/main.tsx b/examples/hello-world/src/main.tsx
index 4f2a33c..fd0b0ef 100644
--- a/examples/hello-world/src/main.tsx
+++ b/examples/hello-world/src/main.tsx
@@ -1,8 +1,6 @@
import {createRoot} from 'react-dom'
-import App from './App.tsx'
+import App from "./App.tsx";
const root = createRoot(document.getElementById("root"))
-const a =
-console.log(a)
root.render()
diff --git a/package.json b/package.json
index 97d46ca..ba23706 100644
--- a/package.json
+++ b/package.json
@@ -7,7 +7,7 @@
"example": "examples"
},
"scripts": {
- "build": "node scripts/build.js",
+ "build:dev": "ENV=dev node scripts/build.js",
"build:test": "node scripts/build.js --test",
"test": "npm run build:test && jest"
},
diff --git a/packages/react-dom/Cargo.toml b/packages/react-dom/Cargo.toml
index 78d0653..23b4c4b 100644
--- a/packages/react-dom/Cargo.toml
+++ b/packages/react-dom/Cargo.toml
@@ -12,7 +12,7 @@ default = ["console_error_panic_hook"]
[dependencies]
wasm-bindgen = "0.2.84"
-web-sys = { version = "0.3.69", features = ["console", "Window", "Document", "Text", "Element"] }
+web-sys = { version = "0.3.69", features = ["console", "Window", "Document", "Text", "Element", "EventListener"] }
react-reconciler = { path = "../react-reconciler" }
shared = { path = "../shared" }
# The `console_error_panic_hook` crate provides better debugging of panics by
@@ -20,6 +20,8 @@ shared = { path = "../shared" }
# all the `std::fmt` and `std::panicking` infrastructure, so isn't great for
# code size when deploying.
console_error_panic_hook = { version = "0.1.7", optional = true }
+gloo = "0.11.0"
+js-sys = "0.3.69"
[dev-dependencies]
wasm-bindgen-test = "0.3.34"
diff --git a/packages/react-dom/src/host_config.rs b/packages/react-dom/src/host_config.rs
index a55ec95..701c5bd 100644
--- a/packages/react-dom/src/host_config.rs
+++ b/packages/react-dom/src/host_config.rs
@@ -1,25 +1,56 @@
use std::any::Any;
use std::rc::Rc;
+use js_sys::JSON::stringify;
+use wasm_bindgen::JsValue;
use web_sys::{Node, window};
use react_reconciler::HostConfig;
-use shared::log;
+use shared::{log, type_of};
+
+use crate::synthetic_event::update_event_props;
pub struct ReactDomHostConfig;
+pub fn to_string(js_value: &JsValue) -> String {
+ js_value.as_string().unwrap_or_else(|| {
+ if js_value.is_undefined() {
+ "undefined".to_owned()
+ } else if js_value.is_null() {
+ "null".to_owned()
+ } else if type_of(js_value, "boolean") {
+ let bool_value = js_value.as_bool().unwrap();
+ bool_value.to_string()
+ } else if js_value.as_f64().is_some() {
+ let num_value = js_value.as_f64().unwrap();
+ num_value.to_string()
+ } else {
+ let js_string = stringify(&js_value).unwrap();
+ js_string.into()
+ }
+ })
+}
+
impl HostConfig for ReactDomHostConfig {
- fn create_text_instance(&self, content: String) -> Rc {
+ fn create_text_instance(&self, content: &JsValue) -> Rc {
let window = window().expect("no global `window` exists");
let document = window.document().expect("should have a document on window");
- Rc::new(Node::from(document.create_text_node(content.as_str())))
+ Rc::new(Node::from(document.create_text_node(
+ to_string(content).as_str()
+ )))
}
- fn create_instance(&self, _type: String) -> Rc {
+ fn create_instance(&self, _type: String, props: Rc) -> 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(Node::from(element)),
+ Ok(element) => {
+ let element = update_event_props(
+ element.clone(),
+ &*props.clone().downcast::().unwrap(),
+ );
+ Rc::new(Node::from(element))
+ }
Err(_) => todo!(),
}
}
diff --git a/packages/react-dom/src/lib.rs b/packages/react-dom/src/lib.rs
index 0e4c3d6..9e8cca5 100644
--- a/packages/react-dom/src/lib.rs
+++ b/packages/react-dom/src/lib.rs
@@ -12,6 +12,7 @@ use crate::utils::set_panic_hook;
mod host_config;
mod renderer;
mod utils;
+mod synthetic_event;
#[wasm_bindgen(js_name = createRoot)]
pub fn create_root(container: &JsValue) -> Renderer {
@@ -24,6 +25,6 @@ pub fn create_root(container: &JsValue) -> Renderer {
}
};
let root = reconciler.create_container(Rc::new(node));
- let renderer = Renderer::new(root, reconciler);
+ let renderer = Renderer::new(root, reconciler, container);
renderer
}
diff --git a/packages/react-dom/src/renderer.rs b/packages/react-dom/src/renderer.rs
index a79090c..dbf697d 100644
--- a/packages/react-dom/src/renderer.rs
+++ b/packages/react-dom/src/renderer.rs
@@ -7,21 +7,25 @@ use wasm_bindgen::prelude::*;
use react_reconciler::fiber::FiberRootNode;
use react_reconciler::Reconciler;
+use crate::synthetic_event::init_event;
+
#[wasm_bindgen]
pub struct Renderer {
+ container: JsValue,
root: Rc>,
reconciler: Reconciler,
}
impl Renderer {
- pub fn new(root: Rc>, reconciler: Reconciler) -> Self {
- Self { root, reconciler }
+ pub fn new(root: Rc>, reconciler: Reconciler, container: &JsValue) -> Self {
+ Self { root, reconciler, container: container.clone() }
}
}
#[wasm_bindgen]
impl Renderer {
pub fn render(&self, element: &JsValue) -> JsValue {
+ init_event(self.container.clone(), "click".to_string());
self.reconciler
.update_container(element.clone(), self.root.clone())
}
diff --git a/packages/react-dom/src/synthetic_event.rs b/packages/react-dom/src/synthetic_event.rs
new file mode 100644
index 0000000..1803bef
--- /dev/null
+++ b/packages/react-dom/src/synthetic_event.rs
@@ -0,0 +1,173 @@
+use gloo::events::EventListener;
+use wasm_bindgen::{JsCast, JsValue};
+use wasm_bindgen::closure::Closure;
+use web_sys::{Element, Event};
+use web_sys::js_sys::{Function, Object, Reflect};
+
+use shared::{derive_from_js_value, is_dev, log};
+
+static VALID_EVENT_TYPE_LIST: [&str; 1] = ["click"];
+static ELEMENT_EVENT_PROPS_KEY: &str = "__props";
+
+struct Paths {
+ capture: Vec,
+ bubble: Vec,
+}
+
+impl Paths {
+ fn new() -> Self {
+ Paths {
+ capture: vec![],
+ bubble: vec![],
+ }
+ }
+}
+
+fn create_synthetic_event(e: Event) -> Event {
+ Reflect::set(&*e, &"__stopPropagation".into(), &JsValue::from_bool(false));
+
+ let e_cloned = e.clone();
+ let origin_stop_propagation = derive_from_js_value(&*e, "stopPropagation");
+ let closure = Closure::wrap(Box::new(move || {
+ Reflect::set(
+ &*e_cloned,
+ &"__stopPropagation".into(),
+ &JsValue::from_bool(true),
+ );
+ if origin_stop_propagation.is_function() {
+ let origin_stop_propagation = origin_stop_propagation.dyn_ref::().unwrap();
+ origin_stop_propagation.call0(&JsValue::null());
+ }
+ }) as Box);
+ let function = closure.as_ref().unchecked_ref::().clone();
+ closure.forget();
+ Reflect::set(&*e.clone(), &"stopPropagation".into(), &function.into());
+ e
+}
+
+fn trigger_event_flow(paths: Vec, se: &Event) {
+ for callback in paths {
+ callback.call1(&JsValue::null(), se);
+ if derive_from_js_value(se, "__stopPropagation")
+ .as_bool()
+ .unwrap()
+ {
+ break;
+ }
+ }
+}
+
+fn dispatch_event(container: &Element, event_type: String, e: &Event) {
+ if e.target().is_none() {
+ log!("Target is none");
+ return;
+ }
+
+ let target_element = e.target().unwrap().dyn_into::().unwrap();
+ let Paths { capture, bubble } =
+ collect_paths(Some(target_element), container, event_type.as_str());
+
+ let se = create_synthetic_event(e.clone());
+
+ if is_dev() {
+ log!("Event {} capture phase", event_type);
+ }
+
+ trigger_event_flow(capture, &se);
+ if !derive_from_js_value(&se, "__stopPropagation")
+ .as_bool()
+ .unwrap()
+ {
+ if is_dev() {
+ log!("Event {} bubble phase", event_type);
+ }
+ trigger_event_flow(bubble, &se);
+ }
+}
+
+fn collect_paths(
+ mut target_element: Option,
+ container: &Element,
+ event_type: &str,
+) -> Paths {
+ let mut paths = Paths::new();
+ while target_element.is_some() && !Object::is(target_element.as_ref().unwrap(), container) {
+ let event_props =
+ derive_from_js_value(target_element.as_ref().unwrap(), ELEMENT_EVENT_PROPS_KEY);
+ if event_props.is_object() {
+ let callback_name_list = get_event_callback_name_from_event_type(event_type);
+ if callback_name_list.is_some() {
+ for (i, callback_name) in callback_name_list.as_ref().unwrap().iter().enumerate() {
+ let event_callback = derive_from_js_value(&event_props, *callback_name);
+ if event_callback.is_function() {
+ let event_callback = event_callback.dyn_ref::().unwrap();
+ if i == 0 {
+ paths.capture.insert(0, event_callback.clone());
+ } else {
+ paths.bubble.push(event_callback.clone());
+ }
+ }
+ }
+ }
+ }
+ target_element = target_element.unwrap().parent_element();
+ }
+ paths
+}
+
+fn get_event_callback_name_from_event_type(event_type: &str) -> Option> {
+ if event_type == "click" {
+ return Some(vec!["onClickCapture", "onClick"]);
+ }
+ None
+}
+
+pub fn init_event(container: JsValue, event_type: String) {
+ if !VALID_EVENT_TYPE_LIST.contains(&event_type.clone().as_str()) {
+ log!("Unsupported event type: {:?}", event_type);
+ return;
+ }
+
+ if is_dev() {
+ log!("Init event {:?}", event_type);
+ }
+
+ let element = container
+ .clone()
+ .dyn_into::()
+ .expect("container is not element");
+ let on_click = EventListener::new(&element.clone(), event_type.clone(), move |event| {
+ dispatch_event(&element, event_type.clone(), event)
+ });
+ on_click.forget();
+}
+
+pub fn update_event_props(node: Element, props: &JsValue) -> Element {
+ let js_value = derive_from_js_value(&node, ELEMENT_EVENT_PROPS_KEY);
+ let element_event_props = if js_value.is_object() {
+ js_value.dyn_into::