Allow any type to be used as Children (take 2) (#3289)

* Partially copy useful implementation.

* Adjust conversion.

* Temporary fix iterator.

* Add ToString implementation.

* Add Renderable trait.

* Make Macro tests pass.

* Add tests for render_prop as Children.

* Update benchmark and Children used in yew packages.

* Selective suppress lints.

* Rollback unintentional rollback.

* Fix rustfmt.

* Remove unneeded implementation.

* Update Comment.

* Rollback more changes.

* Rollback more changes.

* Fix website.

* Fix documentation tests.

* Add prelude.

* Fix test.

* Blanket Implementation for &'_ T for Renderable types.

* Implement Renderable for &str.

* Update signature.

* Update children to Html in examples.

* Remove unnecessary dereferencing.

* Rollback nested_list example.

* Fix comment.

* Convert to Pattern Matching.

* Add tracing issue.

* Rename Renderable to ToHtml.

* Move ToHtml to yew::html.

* Convert more to match pattern.
This commit is contained in:
Kaede Hoshikawa 2023-06-11 19:33:39 +09:00 committed by GitHub
parent 40514a91d9
commit 71b0f206a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 1022 additions and 379 deletions

325
Cargo.lock generated
View File

@ -11,6 +11,12 @@ dependencies = [
"memchr", "memchr",
] ]
[[package]]
name = "android-tzdata"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0"
[[package]] [[package]]
name = "android_system_properties" name = "android_system_properties"
version = "0.1.5" version = "0.1.5"
@ -22,9 +28,9 @@ dependencies = [
[[package]] [[package]]
name = "anstream" name = "anstream"
version = "0.3.1" version = "0.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6342bd4f5a1205d7f41e94a41a901f5647c938cdfa96036338e8533c9d6c2450" checksum = "0ca84f3628370c59db74ee214b3263d58f9aadd9b4fe7e711fd87dc452b7f163"
dependencies = [ dependencies = [
"anstyle", "anstyle",
"anstyle-parse", "anstyle-parse",
@ -89,7 +95,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -176,9 +182,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8"
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.21.0" version = "0.21.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d"
[[package]] [[package]]
name = "base64ct" name = "base64ct"
@ -271,9 +277,9 @@ checksum = "cfa8873f51c92e232f9bac4065cddef41b714152812bfc5f7672ba16d6ef8cd9"
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.12.1" version = "3.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b1ce199063694f33ffb7dd4e0ee620741495c32833cde5aa08f02a0bf96f0c8" checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]] [[package]]
name = "bytecount" name = "bytecount"
@ -326,13 +332,13 @@ dependencies = [
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.24" version = "0.4.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e3c5919066adf22df73762e50cffcde3a758f2a848b113b586d1f86728b673b" checksum = "ec837a71355b28f6556dbd569b37b3f363091c0bd4b2e735674521b4c5fd9bc5"
dependencies = [ dependencies = [
"android-tzdata",
"iana-time-zone", "iana-time-zone",
"js-sys", "js-sys",
"num-integer",
"num-traits", "num-traits",
"time 0.1.45", "time 0.1.45",
"wasm-bindgen", "wasm-bindgen",
@ -341,9 +347,9 @@ dependencies = [
[[package]] [[package]]
name = "clap" name = "clap"
version = "4.2.7" version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "34d21f9bf1b425d2968943631ec91202fe5e837264063503708b83013f8fc938" checksum = "93aae7a4192245f70fe75dd9157fc7b4a5bf53e88d30bd4396f7d8f9284d5acc"
dependencies = [ dependencies = [
"clap_builder", "clap_builder",
"clap_derive", "clap_derive",
@ -352,9 +358,9 @@ dependencies = [
[[package]] [[package]]
name = "clap_builder" name = "clap_builder"
version = "4.2.7" version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "914c8c79fb560f238ef6429439a30023c862f7a28e688c58f7203f12b29970bd" checksum = "4f423e341edefb78c9caba2d9c7f7687d0e72e89df3ce3394554754393ac3990"
dependencies = [ dependencies = [
"anstream", "anstream",
"anstyle", "anstyle",
@ -365,31 +371,21 @@ dependencies = [
[[package]] [[package]]
name = "clap_derive" name = "clap_derive"
version = "4.2.0" version = "4.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4" checksum = "191d9573962933b4027f932c600cd252ce27a8ad5979418fe78e43c07996f27b"
dependencies = [ dependencies = [
"heck", "heck",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
name = "clap_lex" name = "clap_lex"
version = "0.4.1" version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
[[package]]
name = "codespan-reporting"
version = "0.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
dependencies = [
"termcolor",
"unicode-width",
]
[[package]] [[package]]
name = "colorchoice" name = "colorchoice"
@ -427,15 +423,15 @@ dependencies = [
[[package]] [[package]]
name = "console" name = "console"
version = "0.15.5" version = "0.15.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3d79fbe8970a77e3e34151cc13d3b3e248aa0faaecb9f6091fa07ebefe5ad60" checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8"
dependencies = [ dependencies = [
"encode_unicode", "encode_unicode",
"lazy_static", "lazy_static",
"libc", "libc",
"unicode-width", "unicode-width",
"windows-sys 0.42.0", "windows-sys 0.45.0",
] ]
[[package]] [[package]]
@ -515,50 +511,6 @@ dependencies = [
"typenum", "typenum",
] ]
[[package]]
name = "cxx"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f61f1b6389c3fe1c316bf8a4dccc90a38208354b330925bce1f74a6c4756eb93"
dependencies = [
"cc",
"cxxbridge-flags",
"cxxbridge-macro",
"link-cplusplus",
]
[[package]]
name = "cxx-build"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12cee708e8962df2aeb38f594aae5d827c022b6460ac71a7a3e2c3c2aae5a07b"
dependencies = [
"cc",
"codespan-reporting",
"once_cell",
"proc-macro2",
"quote",
"scratch",
"syn 2.0.15",
]
[[package]]
name = "cxxbridge-flags"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7944172ae7e4068c533afbb984114a56c46e9ccddda550499caa222902c7f7bb"
[[package]]
name = "cxxbridge-macro"
version = "1.0.94"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2345488264226bf682893e25de0769f3360aac9957980ec49361b083ddaa5bc5"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.15",
]
[[package]] [[package]]
name = "darling" name = "darling"
version = "0.14.4" version = "0.14.4"
@ -640,9 +592,9 @@ dependencies = [
[[package]] [[package]]
name = "digest" name = "digest"
version = "0.10.6" version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [ dependencies = [
"block-buffer", "block-buffer",
"crypto-common", "crypto-common",
@ -757,7 +709,7 @@ dependencies = [
name = "file_upload" name = "file_upload"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"base64 0.21.0", "base64 0.21.2",
"gloo", "gloo",
"js-sys", "js-sys",
"web-sys", "web-sys",
@ -912,7 +864,7 @@ checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -982,9 +934,9 @@ dependencies = [
[[package]] [[package]]
name = "git2" name = "git2"
version = "0.17.1" version = "0.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b7905cdfe33d31a88bb2e8419ddd054451f5432d1da9eaf2ac7804ee1ea12d5" checksum = "7b989d6a7ca95a362cf2cfc5ad688b3a467be1f87e480b8dad07fee8c79b0044"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"libc", "libc",
@ -1188,9 +1140,9 @@ dependencies = [
[[package]] [[package]]
name = "h2" name = "h2"
version = "0.3.18" version = "0.3.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "17f8a914c2987b688368b5138aa05321db91f4090cf26118185672ad588bce21" checksum = "d357c7ae988e7d2182f7d7871d0b963962420b0678b0997ce7de72001aeab782"
dependencies = [ dependencies = [
"bytes", "bytes",
"fnv", "fnv",
@ -1365,12 +1317,11 @@ dependencies = [
[[package]] [[package]]
name = "iana-time-zone-haiku" name = "iana-time-zone-haiku"
version = "0.1.1" version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca" checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f"
dependencies = [ dependencies = [
"cxx", "cc",
"cxx-build",
] ]
[[package]] [[package]]
@ -1420,11 +1371,12 @@ dependencies = [
[[package]] [[package]]
name = "indicatif" name = "indicatif"
version = "0.17.3" version = "0.17.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cef509aa9bc73864d6756f0d34d35504af3cf0844373afe9b8669a5b8005a729" checksum = "db45317f37ef454e6519b6c3ed7d377e5f23346f0823f86e65ca36912d1d0ef8"
dependencies = [ dependencies = [
"console", "console",
"instant",
"number_prefix", "number_prefix",
"portable-atomic", "portable-atomic",
"unicode-width", "unicode-width",
@ -1453,9 +1405,9 @@ dependencies = [
[[package]] [[package]]
name = "io-lifetimes" name = "io-lifetimes"
version = "1.0.10" version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2"
dependencies = [ dependencies = [
"hermit-abi 0.3.1", "hermit-abi 0.3.1",
"libc", "libc",
@ -1588,15 +1540,15 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.142" version = "0.2.144"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317" checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1"
[[package]] [[package]]
name = "libgit2-sys" name = "libgit2-sys"
version = "0.15.1+1.6.4" version = "0.15.2+1.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb4577bde8cdfc7d6a2a4bcb7b049598597de33ffd337276e9c7db6cd4a2cee7" checksum = "a80df2e11fb4a61f4ba2ab42dbe7f74468da143f1a75c74e11dee7c813f694fa"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1608,9 +1560,9 @@ dependencies = [
[[package]] [[package]]
name = "libm" name = "libm"
version = "0.2.6" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" checksum = "f7012b1bbb0719e1097c47611d3898568c546d597c2e74d66f6087edd5233ff4"
[[package]] [[package]]
name = "libssh2-sys" name = "libssh2-sys"
@ -1638,20 +1590,11 @@ dependencies = [
"vcpkg", "vcpkg",
] ]
[[package]]
name = "link-cplusplus"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
dependencies = [
"cc",
]
[[package]] [[package]]
name = "linux-raw-sys" name = "linux-raw-sys"
version = "0.3.6" version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b64f40e5e03e0d54f03845c8197d0291253cdbedfb1cb46b13c2c117554a9f4c" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519"
[[package]] [[package]]
name = "lipsum" name = "lipsum"
@ -1675,12 +1618,9 @@ dependencies = [
[[package]] [[package]]
name = "log" name = "log"
version = "0.4.17" version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de"
dependencies = [
"cfg-if",
]
[[package]] [[package]]
name = "matchit" name = "matchit"
@ -1712,14 +1652,13 @@ dependencies = [
[[package]] [[package]]
name = "mio" name = "mio"
version = "0.8.6" version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b9d9a46eff5b4ff64b45a9e316a6d1e0bc719ef429cbec4dc630684212bfdf9" checksum = "927a765cd3fc26206e66b296465fa9d3e5ab003e651c1b3c060e7956d96b19d2"
dependencies = [ dependencies = [
"libc", "libc",
"log",
"wasi 0.11.0+wasi-snapshot-preview1", "wasi 0.11.0+wasi-snapshot-preview1",
"windows-sys 0.45.0", "windows-sys 0.48.0",
] ]
[[package]] [[package]]
@ -1794,16 +1733,6 @@ dependencies = [
"yew", "yew",
] ]
[[package]]
name = "num-integer"
version = "0.1.45"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
dependencies = [
"autocfg",
"num-traits",
]
[[package]] [[package]]
name = "num-traits" name = "num-traits"
version = "0.2.15" version = "0.2.15"
@ -1832,15 +1761,15 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]] [[package]]
name = "once_cell" name = "once_cell"
version = "1.17.1" version = "1.17.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b"
[[package]] [[package]]
name = "openssl" name = "openssl"
version = "0.10.52" version = "0.10.54"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "01b8574602df80f7b85fdfc5392fa884a4e3b3f4f35402c070ab34c3d3f78d56" checksum = "69b3f656a17a6cbc115b5c7a40c616947d213ba182135b014d6051b73ab6f019"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cfg-if", "cfg-if",
@ -1859,7 +1788,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -1870,9 +1799,9 @@ checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf"
[[package]] [[package]]
name = "openssl-sys" name = "openssl-sys"
version = "0.9.87" version = "0.9.88"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e17f59264b2809d77ae94f0e1ebabc434773f370d6ca667bd223ea10e06cc7e" checksum = "c2ce0f250f34a308dcfdbb351f511359857d4ed2134ba715a4eadd46e1ffd617"
dependencies = [ dependencies = [
"cc", "cc",
"libc", "libc",
@ -1920,7 +1849,7 @@ version = "0.1.0"
dependencies = [ dependencies = [
"chrono", "chrono",
"js-sys", "js-sys",
"time 0.3.20", "time 0.3.21",
"wasm-bindgen", "wasm-bindgen",
"web-sys", "web-sys",
"yew", "yew",
@ -1935,22 +1864,22 @@ checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e"
[[package]] [[package]]
name = "pin-project" name = "pin-project"
version = "1.0.12" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ad29a609b6bcd67fee905812e544992d216af9d755757c05ed2d0e15a74c6ecc" checksum = "c95a7476719eab1e366eaf73d0260af3021184f18177925b07f54b30089ceead"
dependencies = [ dependencies = [
"pin-project-internal", "pin-project-internal",
] ]
[[package]] [[package]]
name = "pin-project-internal" name = "pin-project-internal"
version = "1.0.12" version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "069bdb1e05adc7a8990dce9cc75370895fbe4e3d58b9b73bf1aee56359344a55" checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 1.0.109", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -1978,15 +1907,15 @@ dependencies = [
[[package]] [[package]]
name = "pkg-config" name = "pkg-config"
version = "0.3.26" version = "0.3.27"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964"
[[package]] [[package]]
name = "portable-atomic" name = "portable-atomic"
version = "0.3.19" version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26f6a7b87c2e435a3241addceeeff740ff8b7e76b74c13bf9acb17fa454ea00b" checksum = "767eb9f07d4a5ebcb39bbf2d452058a93c011373abf6832e24194a1c3f004794"
[[package]] [[package]]
name = "portals" name = "portals"
@ -2006,12 +1935,12 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]] [[package]]
name = "prettyplease" name = "prettyplease"
version = "0.2.4" version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ceca8aaf45b5c46ec7ed39fff75f57290368c1846d33d24a122ca81416ab058" checksum = "3b69d39aab54d069e7f2fe8cb970493e7834601ca2d8c65fd7bbd183578080d1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -2040,9 +1969,9 @@ dependencies = [
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.56" version = "1.0.59"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2b63bdb0cd06f1f4dedf69b254734f9b45af66e4a031e42a7480257d9898b435" checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
@ -2075,9 +2004,9 @@ dependencies = [
[[package]] [[package]]
name = "pulldown-cmark" name = "pulldown-cmark"
version = "0.9.2" version = "0.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" checksum = "77a1a2f1f0a7ecff9c31abbe177637be0e97a0aef46cf8738ece09327985d998"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"memchr", "memchr",
@ -2149,9 +2078,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.8.1" version = "1.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af83e617f331cc6ae2da5443c602dfa5af81e517212d9d611a5b3ba1777b5370" checksum = "81ca098a9821bd52d6b24fd8b10bd081f47d39c22778cafaa75a2857a62c6390"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -2160,17 +2089,17 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.1" version = "0.7.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a5996294f19bd3aae0453a862ad728f60e6600695733dd5df01da90c54363a3c" checksum = "436b050e76ed2903236f032a59761c1eb99e1b0aead2c257922771dab1fc8c78"
[[package]] [[package]]
name = "reqwest" name = "reqwest"
version = "0.11.17" version = "0.11.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" checksum = "cde824a14b7c14f85caff81225f411faacc04a2013f41670f41443742b1c1c55"
dependencies = [ dependencies = [
"base64 0.21.0", "base64 0.21.2",
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-core", "futures-core",
@ -2235,9 +2164,9 @@ dependencies = [
[[package]] [[package]]
name = "rustix" name = "rustix"
version = "0.37.17" version = "0.37.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc809f704c03a812ac71f22456c857be34185cac691a4316f27ab0f633bb9009" checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"errno", "errno",
@ -2253,7 +2182,7 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b"
dependencies = [ dependencies = [
"base64 0.21.0", "base64 0.21.2",
] ]
[[package]] [[package]]
@ -2289,17 +2218,11 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
[[package]]
name = "scratch"
version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1792db035ce95be60c3f8853017b3999209281c24e2ba5bc8e59bf97a0c590c1"
[[package]] [[package]]
name = "security-framework" name = "security-framework"
version = "2.8.2" version = "2.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"core-foundation", "core-foundation",
@ -2310,9 +2233,9 @@ dependencies = [
[[package]] [[package]]
name = "security-framework-sys" name = "security-framework-sys"
version = "2.8.0" version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7"
dependencies = [ dependencies = [
"core-foundation-sys", "core-foundation-sys",
"libc", "libc",
@ -2326,9 +2249,9 @@ checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.162" version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "71b2f6e1ab5c2b98c05f0f35b236b22e8df7ead6ffbf51d7808da7f8817e7ab6" checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -2346,13 +2269,13 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.162" version = "1.0.163"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2a0814352fd64b58489904a44ea8d90cb1a91dcb6b4f5ebabc32c8318e93cb6" checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -2528,9 +2451,9 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.15" version = "2.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a34fcf3e8b60f57e6a14301a2e916d323af98b0ea63c599441eec8558660c822" checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -2606,7 +2529,7 @@ checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -2622,9 +2545,9 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.20" version = "0.3.21"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc"
dependencies = [ dependencies = [
"serde", "serde",
"time-core", "time-core",
@ -2632,9 +2555,9 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.0" version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb"
[[package]] [[package]]
name = "timer" name = "timer"
@ -2685,9 +2608,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.28.1" version = "1.28.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0aa32867d44e6f2ce3385e89dceb990188b8bb0fb25b0cf576647a6f98ac5105" checksum = "94d7b1cfd2aa4011f2de74c2c4c63665e27a71006b0a192dcd2710272e73dfa2"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"bytes", "bytes",
@ -2710,7 +2633,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
@ -2833,14 +2756,14 @@ checksum = "0f57e3ca2a01450b1a921183a9c9cbfda207fd822cef4ccb00a65402cbba7a74"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
] ]
[[package]] [[package]]
name = "tracing-core" name = "tracing-core"
version = "0.1.30" version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a" checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
dependencies = [ dependencies = [
"once_cell", "once_cell",
] ]
@ -2916,9 +2839,9 @@ checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460"
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.8" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0"
[[package]] [[package]]
name = "unicode-normalization" name = "unicode-normalization"
@ -2972,9 +2895,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.3.2" version = "1.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4dad5567ad0cf5b760e5665964bec1b47dfd077ba8a2544b513f3556d3d239a2" checksum = "345444e32442451b267fc254ae85a209c64be56d2890e601a0c37ff0c3c5ecd2"
dependencies = [ dependencies = [
"serde", "serde",
] ]
@ -3065,7 +2988,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3099,7 +3022,7 @@ checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn 2.0.15", "syn 2.0.18",
"wasm-bindgen-backend", "wasm-bindgen-backend",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -3147,9 +3070,9 @@ dependencies = [
[[package]] [[package]]
name = "web-sys" name = "web-sys"
version = "0.3.61" version = "0.3.63"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" checksum = "3bdd9ef4e984da1187bf8110c5cf5b845fbc87a23602cdf912386a76fcd3a7c2"
dependencies = [ dependencies = [
"js-sys", "js-sys",
"wasm-bindgen", "wasm-bindgen",
@ -3450,7 +3373,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 2.0.15", "syn 2.0.18",
"trybuild", "trybuild",
"yew", "yew",
] ]
@ -3479,7 +3402,7 @@ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"rustversion", "rustversion",
"syn 2.0.15", "syn 2.0.18",
"trybuild", "trybuild",
"yew-router", "yew-router",
] ]
@ -3509,5 +3432,5 @@ dependencies = [
"lazy_static", "lazy_static",
"quick-error", "quick-error",
"regex", "regex",
"time 0.3.20", "time 0.3.21",
] ]

View File

@ -20,7 +20,7 @@ pub type MessageContext = UseReducerHandle<Message>;
#[derive(Properties, Debug, PartialEq)] #[derive(Properties, Debug, PartialEq)]
pub struct MessageProviderProps { pub struct MessageProviderProps {
#[prop_or_default] #[prop_or_default]
pub children: Children, pub children: Html,
} }
#[function_component] #[function_component]

View File

@ -42,6 +42,12 @@ impl Filter {
} }
} }
impl ToHtml for Filter {
fn to_html(&self) -> Html {
html! {<>{self.to_string()}</>}
}
}
pub enum Action { pub enum Action {
Add(String), Add(String),
Edit((usize, String)), Edit((usize, String)),

View File

@ -54,10 +54,12 @@ pub fn render_markdown(src: &str) -> Html {
top = pre; top = pre;
} else if let Tag::Table(aligns) = tag { } else if let Tag::Table(aligns) = tag {
if let Some(top_children) = top.children_mut() { if let Some(top_children) = top.children_mut() {
for r in top_children.iter_mut() { for r in top_children.to_vlist_mut().iter_mut() {
if let VNode::VTag(ref mut vtag) = r { if let VNode::VTag(ref mut vtag) = r {
if let Some(vtag_children) = vtag.children_mut() { if let Some(vtag_children) = vtag.children_mut() {
for (i, c) in vtag_children.iter_mut().enumerate() { for (i, c) in
vtag_children.to_vlist_mut().iter_mut().enumerate()
{
if let VNode::VTag(ref mut vtag) = c { if let VNode::VTag(ref mut vtag) = c {
match aligns[i] { match aligns[i] {
Alignment::None => {} Alignment::None => {}
@ -73,7 +75,7 @@ pub fn render_markdown(src: &str) -> Html {
} }
} else if let Tag::TableHead = tag { } else if let Tag::TableHead = tag {
if let Some(top_children) = top.children_mut() { if let Some(top_children) = top.children_mut() {
for c in top_children.iter_mut() { for c in top_children.to_vlist_mut().iter_mut() {
if let VNode::VTag(ref mut vtag) = c { if let VNode::VTag(ref mut vtag) = c {
// TODO // TODO
// vtag.tag = "th".into(); // vtag.tag = "th".into();

View File

@ -8,7 +8,8 @@ use std::fmt;
use std::ops::Deref; use std::ops::Deref;
use std::rc::Rc; use std::rc::Rc;
use yew::html::{Component, ImplicitClone, Scope}; use yew::html::{ImplicitClone, Scope};
use yew::prelude::*;
pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>); pub struct WeakComponentLink<COMP: Component>(Rc<RefCell<Option<Scope<COMP>>>>);
@ -62,6 +63,12 @@ impl fmt::Display for Hovered {
} }
} }
impl ToHtml for Hovered {
fn to_html(&self) -> yew::Html {
html! {<>{self.to_string()}</>}
}
}
fn main() { fn main() {
wasm_logger::init(wasm_logger::Config::default()); wasm_logger::init(wasm_logger::Config::default());
yew::Renderer::<app::App>::new().render(); yew::Renderer::<app::App>::new().render();

View File

@ -1,11 +1,11 @@
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::{Element, ShadowRootInit, ShadowRootMode}; use web_sys::{Element, ShadowRootInit, ShadowRootMode};
use yew::{create_portal, html, Children, Component, Context, Html, NodeRef, Properties}; use yew::{create_portal, html, Component, Context, Html, NodeRef, Properties};
#[derive(Properties, PartialEq)] #[derive(Properties, PartialEq)]
pub struct ShadowDOMProps { pub struct ShadowDOMProps {
#[prop_or_default] #[prop_or_default]
pub children: Children, pub children: Html,
} }
pub struct ShadowDOMHost { pub struct ShadowDOMHost {
@ -50,12 +50,7 @@ impl Component for ShadowDOMHost {
fn view(&self, ctx: &Context<Self>) -> Html { fn view(&self, ctx: &Context<Self>) -> Html {
let contents = if let Some(ref inner_host) = self.inner_host { let contents = if let Some(ref inner_host) = self.inner_host {
create_portal( create_portal(ctx.props().children.clone(), inner_host.clone())
html! {
{for ctx.props().children.iter()}
},
inner_host.clone(),
)
} else { } else {
html! { <></> } html! { <></> }
}; };

View File

@ -1,5 +1,6 @@
use serde_derive::{Deserialize, Serialize}; use serde_derive::{Deserialize, Serialize};
use strum_macros::{Display, EnumIter}; use strum_macros::{Display, EnumIter};
use yew::prelude::*;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct State { pub struct State {
@ -140,3 +141,9 @@ impl Filter {
} }
} }
} }
impl ToHtml for Filter {
fn to_html(&self) -> yew::Html {
html! { <>{self.to_string()}</> }
}
}

View File

@ -133,11 +133,7 @@ impl ToTokens for HtmlComponent {
let ty_span = ty.span().resolved_at(Span::call_site()); let ty_span = ty.span().resolved_at(Span::call_site());
let props_ty = quote_spanned!(ty_span=> <#ty as ::yew::html::BaseComponent>::Properties); let props_ty = quote_spanned!(ty_span=> <#ty as ::yew::html::BaseComponent>::Properties);
let children_renderer = if children.is_empty() { let children_renderer = children.to_children_renderer_tokens();
None
} else {
Some(quote! { ::yew::html::ChildrenRenderer::new(#children) })
};
let build_props = props.build_properties_tokens(&props_ty, children_renderer); let build_props = props.build_properties_tokens(&props_ty, children_renderer);
let key = props.special().wrap_key_attr(); let key = props.special().wrap_key_attr();
let use_close_tag = close let use_close_tag = close

View File

@ -313,12 +313,7 @@ impl ToTokens for HtmlElement {
// TODO: if none of the children have possibly None expressions or literals as keys, we can // TODO: if none of the children have possibly None expressions or literals as keys, we can
// compute `VList.fully_keyed` at compile time. // compute `VList.fully_keyed` at compile time.
let child_list = quote! { let children = children.to_vnode_tokens();
::yew::virtual_dom::VList::with_children(
#children,
::std::option::Option::None,
)
};
tokens.extend(match &name { tokens.extend(match &name {
TagName::Lit(dashedname) => { TagName::Lit(dashedname) => {
@ -370,7 +365,7 @@ impl ToTokens for HtmlElement {
#key, #key,
#attributes, #attributes,
#listeners, #listeners,
#child_list, #children,
), ),
) )
} }
@ -392,6 +387,8 @@ impl ToTokens for HtmlElement {
let expr = &name.expr; let expr = &name.expr;
let vtag_name = Ident::new("__yew_vtag_name", expr.span()); let vtag_name = Ident::new("__yew_vtag_name", expr.span());
let void_children = Ident::new("__yew_void_children", Span::mixed_site());
// handle special attribute value // handle special attribute value
let handle_value_attr = props.value.as_ref().map(|prop| { let handle_value_attr = props.value.as_ref().map(|prop| {
let v = prop.value.optimize_literals(); let v = prop.value.optimize_literals();
@ -455,7 +452,7 @@ impl ToTokens for HtmlElement {
#key, #key,
#attributes, #attributes,
#listeners, #listeners,
#child_list, #children,
); );
#handle_value_attr #handle_value_attr
@ -468,7 +465,10 @@ impl ToTokens for HtmlElement {
// For literal tags this is already done at compile-time. // For literal tags this is already done at compile-time.
// //
// check void element // check void element
if !#vtag.children().is_empty() { if !::std::matches!(
::yew::virtual_dom::VTag::children(&#vtag),
::std::option::Option::Some(::yew::virtual_dom::VNode::VList(ref #void_children)) if ::std::vec::Vec::is_empty(#void_children)
) {
::std::debug_assert!( ::std::debug_assert!(
!::std::matches!(#vtag.tag().to_ascii_lowercase().as_str(), !::std::matches!(#vtag.tag().to_ascii_lowercase().as_str(),
"area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input" "area" | "base" | "br" | "col" | "embed" | "hr" | "img" | "input"

View File

@ -29,6 +29,8 @@ use html_list::HtmlList;
use html_node::HtmlNode; use html_node::HtmlNode;
use tag::TagTokens; use tag::TagTokens;
use self::html_block::BlockContent;
pub enum HtmlType { pub enum HtmlType {
Block, Block,
Component, Component,
@ -280,6 +282,64 @@ impl HtmlChildrenTree {
Ok(children) Ok(children)
} }
pub fn to_children_renderer_tokens(&self) -> Option<TokenStream> {
match self.0[..] {
[] => None,
[HtmlTree::Component(ref children)] => Some(quote! { #children }),
[HtmlTree::Element(ref children)] => Some(quote! { #children }),
[HtmlTree::Block(ref m)] => {
// We only want to process `{vnode}` and not `{for vnodes}`.
// This should be converted into a if let guard once https://github.com/rust-lang/rust/issues/51114 is stable.
// Or further nested once deref pattern (https://github.com/rust-lang/rust/issues/87121) is stable.
if let HtmlBlock {
content: BlockContent::Node(children),
..
} = m.as_ref()
{
Some(quote! { #children })
} else {
Some(quote! { ::yew::html::ChildrenRenderer::new(#self) })
}
}
_ => Some(quote! { ::yew::html::ChildrenRenderer::new(#self) }),
}
}
pub fn to_vnode_tokens(&self) -> TokenStream {
match self.0[..] {
[] => quote! {::std::default::Default::default() },
[HtmlTree::Component(ref children)] => {
quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }
}
[HtmlTree::Element(ref children)] => {
quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }
}
[HtmlTree::Block(ref m)] => {
// We only want to process `{vnode}` and not `{for vnodes}`.
// This should be converted into a if let guard once https://github.com/rust-lang/rust/issues/51114 is stable.
// Or further nested once deref pattern (https://github.com/rust-lang/rust/issues/87121) is stable.
if let HtmlBlock {
content: BlockContent::Node(children),
..
} = m.as_ref()
{
quote! { ::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(#children) }
} else {
quote! {
::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(
::yew::html::ChildrenRenderer::new(#self)
)
}
}
}
_ => quote! {
::yew::html::IntoPropValue::<::yew::virtual_dom::VNode>::into_prop_value(
::yew::html::ChildrenRenderer::new(#self)
)
},
}
}
} }
impl ToTokens for HtmlChildrenTree { impl ToTokens for HtmlChildrenTree {

View File

@ -131,7 +131,7 @@ impl ComponentProps {
}); });
let set_children = children_renderer.map(|children| { let set_children = children_renderer.map(|children| {
quote_spanned! {props_ty.span()=> quote_spanned! {props_ty.span()=>
#ident.children = #children; #ident.children = ::yew::html::IntoPropValue::into_prop_value(#children);
} }
}); });
let init_base = quote_spanned! {expr.span().resolved_at(Span::call_site())=> let init_base = quote_spanned! {expr.span().resolved_at(Span::call_site())=>

View File

@ -13,21 +13,6 @@ error[E0277]: `()` doesn't implement `std::fmt::Display`
= note: required because of the requirements on the impl of `Into<NodeSeq<(), VNode>>` for `()` = note: required because of the requirements on the impl of `Into<NodeSeq<(), VNode>>` for `()`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `()` doesn't implement `std::fmt::Display`
--> tests/html_macro/block-fail.rs:12:16
|
12 | <div>{ not_tree() }</div>
| ^^^^^^^^ `()` cannot be formatted with the default formatter
|
= help: the trait `std::fmt::Display` is not implemented for `()`
= note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead
= note: required because of the requirements on the impl of `ToString` for `()`
= note: required because of the requirements on the impl of `From<()>` for `VNode`
= note: required because of the requirements on the impl of `Into<VNode>` for `()`
= note: 2 redundant requirements hidden
= note: required because of the requirements on the impl of `Into<NodeSeq<(), VNode>>` for `()`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: `()` doesn't implement `std::fmt::Display` error[E0277]: `()` doesn't implement `std::fmt::Display`
--> tests/html_macro/block-fail.rs:15:17 --> tests/html_macro/block-fail.rs:15:17
| |

View File

@ -0,0 +1,332 @@
#![no_implicit_prelude]
// Shadow primitives
#[allow(non_camel_case_types)]
pub struct bool;
#[allow(non_camel_case_types)]
pub struct char;
#[allow(non_camel_case_types)]
pub struct f32;
#[allow(non_camel_case_types)]
pub struct f64;
#[allow(non_camel_case_types)]
pub struct i128;
#[allow(non_camel_case_types)]
pub struct i16;
#[allow(non_camel_case_types)]
pub struct i32;
#[allow(non_camel_case_types)]
pub struct i64;
#[allow(non_camel_case_types)]
pub struct i8;
#[allow(non_camel_case_types)]
pub struct isize;
#[allow(non_camel_case_types)]
pub struct str;
#[allow(non_camel_case_types)]
pub struct u128;
#[allow(non_camel_case_types)]
pub struct u16;
#[allow(non_camel_case_types)]
pub struct u32;
#[allow(non_camel_case_types)]
pub struct u64;
#[allow(non_camel_case_types)]
pub struct u8;
#[allow(non_camel_case_types)]
pub struct usize;
#[derive(
::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,
)]
pub struct ContainerProperties {
pub int: ::std::primitive::i32,
// You can use Html as Children.
#[prop_or_default]
pub children: ::yew::Html,
#[prop_or_default]
pub header: ::yew::Html,
}
pub struct Container;
impl ::yew::Component for Container {
type Message = ();
type Properties = ContainerProperties;
fn create(_ctx: &::yew::Context<Self>) -> Self {
::std::unimplemented!()
}
fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {
::std::unimplemented!()
}
}
#[derive(::std::clone::Clone, ::std::cmp::PartialEq)]
pub enum ChildrenVariants {
Child(::yew::virtual_dom::VChild<Child>),
AltChild(::yew::virtual_dom::VChild<AltChild>),
}
impl ::std::convert::From<::yew::virtual_dom::VChild<Child>> for ChildrenVariants {
fn from(comp: ::yew::virtual_dom::VChild<Child>) -> Self {
ChildrenVariants::Child(comp)
}
}
impl ::std::convert::From<::yew::virtual_dom::VChild<AltChild>> for ChildrenVariants {
fn from(comp: ::yew::virtual_dom::VChild<AltChild>) -> Self {
ChildrenVariants::AltChild(comp)
}
}
impl ::std::convert::Into<::yew::virtual_dom::VNode> for ChildrenVariants {
fn into(self) -> ::yew::virtual_dom::VNode {
match self {
Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::<
::yew::virtual_dom::VComp,
>::into(comp)),
Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::<
::yew::virtual_dom::VComp,
>::into(comp)),
}
}
}
#[derive(
::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,
)]
pub struct ChildProperties {
#[prop_or_default]
pub string: ::std::string::String,
#[prop_or_default]
pub r#fn: ::std::primitive::i32,
#[prop_or_default]
pub r#ref: ::yew::NodeRef,
pub int: ::std::primitive::i32,
#[prop_or_default]
pub opt_str: ::std::option::Option<::std::string::String>,
#[prop_or_default]
pub vec: ::std::vec::Vec<::std::primitive::i32>,
#[prop_or_default]
pub optional_callback: ::std::option::Option<::yew::Callback<()>>,
}
pub struct Child;
impl ::yew::Component for Child {
type Message = ();
type Properties = ChildProperties;
fn create(_ctx: &::yew::Context<Self>) -> Self {
::std::unimplemented!()
}
fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {
::std::unimplemented!()
}
}
pub struct AltChild;
impl ::yew::Component for AltChild {
type Message = ();
type Properties = ();
fn create(_ctx: &::yew::Context<Self>) -> Self {
::std::unimplemented!()
}
fn view(&self, _ctx: &::yew::Context<Self>) -> ::yew::Html {
::std::unimplemented!()
}
}
mod scoped {
pub use super::{Child, Container};
}
#[derive(
::std::clone::Clone, ::yew::Properties, ::std::default::Default, ::std::cmp::PartialEq,
)]
pub struct RenderPropProps {
// You can use Callback<()> as Children.
#[prop_or_default]
pub children: ::yew::Callback<()>,
}
#[::yew::function_component]
pub fn RenderPropComp(_props: &RenderPropProps) -> ::yew::Html {
::yew::html! {}
}
fn compile_pass() {
::yew::html! { <Child int=1 /> };
::yew::html! { <Child int=1 r#fn=1 /> };
::yew::html! {
<>
<Child int=1 />
<scoped::Child int=1 />
</>
};
let props = <<Child as ::yew::Component>::Properties as ::std::default::Default>::default();
let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
::yew::html! {
<>
<Child ..::std::clone::Clone::clone(&props) />
<Child int={1} ..props />
<Child r#ref={::std::clone::Clone::clone(&node_ref)} int={2} ..::yew::props!(Child::Properties { int: 5 }) />
<Child int=3 r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />
<Child r#ref={::std::clone::Clone::clone(&node_ref)} ..::yew::props!(Child::Properties { int: 5 }) />
<Child r#ref={&node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />
<Child r#ref={node_ref} ..<<Child as ::yew::Component>::Properties as ::std::default::Default>::default() />
</>
};
::yew::html! {
<>
<Child int=1 string="child" />
<Child int=1 />
<Child int={1+1} />
<Child int=1 vec={::std::vec![1]} />
<Child string={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from("child")} int=1 />
<Child opt_str="child" int=1 />
<Child opt_str={<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from("child")} int=1 />
<Child opt_str={::std::option::Option::Some("child")} int=1 />
<Child opt_str={::std::option::Option::Some(<::std::string::String as ::std::convert::From<&'static ::std::primitive::str>>::from("child"))} int=1 />
</>
};
let name_expr = "child";
::yew::html! {
<Child int=1 string={name_expr} />
};
let string = "child";
let int = 1;
::yew::html! {
<Child {int} {string} />
};
::yew::html! {
<>
<Child int=1 />
<Child int=1 optional_callback={::std::option::Option::Some(<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ()))} />
<Child int=1 optional_callback={<::yew::Callback<()> as ::std::convert::From<_>>::from(|_| ())} />
<Child int=1 optional_callback={::std::option::Option::None::<::yew::Callback<_>>} />
</>
};
let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
::yew::html! {
<>
<Child int=1 r#ref={node_ref} />
</>
};
let int = 1;
let node_ref = <::yew::NodeRef as ::std::default::Default>::default();
::yew::html! {
<>
<Child {int} r#ref={node_ref} />
</>
};
let props = <<Container as ::yew::Component>::Properties as ::std::default::Default>::default();
let child_props =
<<Child as ::yew::Component>::Properties as ::std::default::Default>::default();
::yew::html! {
<>
<Container int=1 />
<Container int=1></Container>
<Container ..::std::clone::Clone::clone(&props)>
<div>{ "hello world" }</div>
</Container>
<Container int=1 ..::std::clone::Clone::clone(&props)>
<div>{ "hello world" }</div>
</Container>
<Container int=1 ..::std::clone::Clone::clone(&props)>
<Child int=2 opt_str="hello" ..::std::clone::Clone::clone(&child_props) />
</Container>
<Container int=1 ..::std::clone::Clone::clone(&props)>
<Child int=2 vec={::std::vec![0]} ..::std::clone::Clone::clone(&child_props) />
</Container>
<Container int=1 ..props>
<Child int=2 string="hello" ..child_props />
</Container>
<Container int=1>
<Child int=2 />
</Container>
<scoped::Container int=1>
<scoped::Container int=2/>
</scoped::Container>
<Container int=1 children={::yew::html::ChildrenRenderer::new(
::std::vec![::yew::html!{ "::std::string::String" }]
)} />
<Container int=1 header={::yew::html!{
<Child int=2 />
}} />
</>
};
let variants = || -> ::std::vec::Vec<ChildrenVariants> {
::std::vec![
ChildrenVariants::Child(::yew::virtual_dom::VChild::new(
<ChildProperties as ::std::default::Default>::default(),
::std::option::Option::None,
)),
ChildrenVariants::AltChild(::yew::virtual_dom::VChild::new(
(),
::std::option::Option::None
)),
]
};
::yew::html! {
<>
{
::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(
::std::iter::Iterator::filter(
::std::iter::IntoIterator::into_iter(variants()),
|c| match c {
ChildrenVariants::Child(_) => true,
_ => false,
}
)
)
}
<div>
{
::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>(
::std::iter::Iterator::filter(
::std::iter::IntoIterator::into_iter(variants()),
|c| match c {
ChildrenVariants::AltChild(_) => true,
_ => false,
}
)
)
}
</div>
</>
};
::yew::html_nested! { 1 };
::yew::html! {
<RenderPropComp>
{|_arg| {}}
</RenderPropComp>
};
}
fn main() {}

View File

@ -481,6 +481,12 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: the following implementations were found:
<f32 as IntoPropValue<ChildrenRenderer<VNode>>>
<f64 as IntoPropValue<ChildrenRenderer<VNode>>>
<i128 as IntoPropValue<ChildrenRenderer<VNode>>>
<i16 as IntoPropValue<ChildrenRenderer<VNode>>>
and $N others
note: required by a bound in `ChildPropertiesBuilder::string` note: required by a bound in `ChildPropertiesBuilder::string`
--> tests/html_macro/component-fail.rs:4:17 --> tests/html_macro/component-fail.rs:4:17
| |
@ -499,6 +505,12 @@ error[E0277]: the trait bound `{integer}: IntoPropValue<String>` is not satisfie
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: the following implementations were found:
<f32 as IntoPropValue<ChildrenRenderer<VNode>>>
<f64 as IntoPropValue<ChildrenRenderer<VNode>>>
<i128 as IntoPropValue<ChildrenRenderer<VNode>>>
<i16 as IntoPropValue<ChildrenRenderer<VNode>>>
and $N others
note: required by a bound in `ChildPropertiesBuilder::string` note: required by a bound in `ChildPropertiesBuilder::string`
--> tests/html_macro/component-fail.rs:4:17 --> tests/html_macro/component-fail.rs:4:17
| |
@ -534,6 +546,12 @@ error[E0277]: the trait bound `u32: IntoPropValue<i32>` is not satisfied
| | | |
| required by a bound introduced by this call | required by a bound introduced by this call
| |
= help: the following implementations were found:
<u32 as IntoPropValue<ChildrenRenderer<VNode>>>
<f32 as IntoPropValue<ChildrenRenderer<VNode>>>
<f64 as IntoPropValue<ChildrenRenderer<VNode>>>
<i128 as IntoPropValue<ChildrenRenderer<VNode>>>
and $N others
note: required by a bound in `ChildPropertiesBuilder::int` note: required by a bound in `ChildPropertiesBuilder::int`
--> tests/html_macro/component-fail.rs:4:17 --> tests/html_macro/component-fail.rs:4:17
| |
@ -630,13 +648,25 @@ note: required by a bound in `yew::html::component::properties::__macro::PreBuil
| ^^^^^^^^^^^^^^^^^^^ required by this bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build` | ^^^^^^^^^^^^^^^^^^^ required by this bound in `yew::html::component::properties::__macro::PreBuild::<Token, B>::build`
= note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `VChild<Child>: From<yew::virtual_dom::VText>` is not satisfied error[E0277]: the trait bound `yew::virtual_dom::VText: IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not satisfied
--> tests/html_macro/component-fail.rs:117:31 --> tests/html_macro/component-fail.rs:117:31
| |
117 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> }; 117 | html! { <ChildContainer>{ "Not allowed" }</ChildContainer> };
| ^^^^^^^^^^^^^ the trait `From<yew::virtual_dom::VText>` is not implemented for `VChild<Child>` | -------------- ^^^^^^^^^^^^^ the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `yew::virtual_dom::VText`
| |
| required by a bound introduced by this call
| |
= note: required because of the requirements on the impl of `Into<VChild<Child>>` for `yew::virtual_dom::VText` = help: the following implementations were found:
<yew::virtual_dom::VText as IntoPropValue<ChildrenRenderer<VNode>>>
note: required by a bound in `ChildContainerPropertiesBuilder::children`
--> tests/html_macro/component-fail.rs:24:17
|
24 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^ required by this bound in `ChildContainerPropertiesBuilder::children`
25 | pub struct ChildContainerProperties {
26 | pub children: ChildrenWithProps<Child>,
| -------- required by a bound in this
= note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)
error[E0277]: the trait bound `VChild<Child>: From<VNode>` is not satisfied error[E0277]: the trait bound `VChild<Child>: From<VNode>` is not satisfied
--> tests/html_macro/component-fail.rs:118:29 --> tests/html_macro/component-fail.rs:118:29
@ -646,10 +676,22 @@ error[E0277]: the trait bound `VChild<Child>: From<VNode>` is not satisfied
| |
= note: required because of the requirements on the impl of `Into<VChild<Child>>` for `VNode` = note: required because of the requirements on the impl of `Into<VChild<Child>>` for `VNode`
error[E0277]: the trait bound `VChild<Child>: From<VNode>` is not satisfied error[E0277]: the trait bound `VNode: IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not satisfied
--> tests/html_macro/component-fail.rs:119:30 --> tests/html_macro/component-fail.rs:119:30
| |
119 | html! { <ChildContainer><other /></ChildContainer> }; 119 | html! { <ChildContainer><other /></ChildContainer> };
| ^^^^^ the trait `From<VNode>` is not implemented for `VChild<Child>` | -------------- ^^^^^ the trait `IntoPropValue<ChildrenRenderer<VChild<Child>>>` is not implemented for `VNode`
| |
| required by a bound introduced by this call
| |
= note: required because of the requirements on the impl of `Into<VChild<Child>>` for `VNode` = help: the following implementations were found:
<VNode as IntoPropValue<ChildrenRenderer<VNode>>>
note: required by a bound in `ChildContainerPropertiesBuilder::children`
--> tests/html_macro/component-fail.rs:24:17
|
24 | #[derive(Clone, Properties, PartialEq)]
| ^^^^^^^^^^ required by this bound in `ChildContainerPropertiesBuilder::children`
25 | pub struct ChildContainerProperties {
26 | pub children: ChildrenWithProps<Child>,
| -------- required by a bound in this
= note: this error originates in the derive macro `Properties` (in Nightly builds, run with -Z macro-backtrace for more info)

View File

@ -436,9 +436,9 @@ error[E0277]: the trait bound `Option<NotToString>: IntoPropValue<Option<implici
| |
= help: the following implementations were found: = help: the following implementations were found:
<Option<&'static str> as IntoPropValue<Option<String>>> <Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<VNode>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>> <Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>> <Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
and $N others and $N others
error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_clone::unsync::IString>>` is not satisfied
@ -452,9 +452,9 @@ error[E0277]: the trait bound `Option<{integer}>: IntoPropValue<Option<implicit_
| |
= help: the following implementations were found: = help: the following implementations were found:
<Option<&'static str> as IntoPropValue<Option<String>>> <Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<VNode>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>> <Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>> <Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
and $N others and $N others
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}` error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}`
@ -550,9 +550,9 @@ error[E0277]: the trait bound `Option<yew::NodeRef>: IntoPropValue<yew::NodeRef>
| |
= help: the following implementations were found: = help: the following implementations were found:
<Option<&'static str> as IntoPropValue<Option<String>>> <Option<&'static str> as IntoPropValue<Option<String>>>
<Option<&'static str> as IntoPropValue<Option<VNode>>>
<Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>> <Option<&'static str> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
<Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>> <Option<F> as IntoPropValue<Option<yew::Callback<I, O>>>>
<Option<Rc<str>> as IntoPropValue<Option<implicit_clone::unsync::IString>>>
and $N others and $N others
error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>` error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback<String>`

View File

@ -28,7 +28,7 @@ where
#[prop_or_default] #[prop_or_default]
pub anchor_ref: NodeRef, pub anchor_ref: NodeRef,
#[prop_or_default] #[prop_or_default]
pub children: Children, pub children: Html,
} }
/// A wrapper around `<a>` tag to be used with [`Router`](crate::Router) /// A wrapper around `<a>` tag to be used with [`Router`](crate::Router)

View File

@ -11,7 +11,8 @@ use crate::utils::{base_url, strip_slash_suffix};
/// Props for [`Router`]. /// Props for [`Router`].
#[derive(Properties, PartialEq, Clone)] #[derive(Properties, PartialEq, Clone)]
pub struct RouterProps { pub struct RouterProps {
pub children: Children, #[prop_or_default]
pub children: Html,
pub history: AnyHistory, pub history: AnyHistory,
#[prop_or_default] #[prop_or_default]
pub basename: Option<AttrValue>, pub basename: Option<AttrValue>,
@ -129,7 +130,7 @@ pub fn router(props: &RouterProps) -> Html {
/// Props for [`BrowserRouter`] and [`HashRouter`]. /// Props for [`BrowserRouter`] and [`HashRouter`].
#[derive(Properties, PartialEq, Clone)] #[derive(Properties, PartialEq, Clone)]
pub struct ConcreteRouterProps { pub struct ConcreteRouterProps {
pub children: Children, pub children: Html,
#[prop_or_default] #[prop_or_default]
pub basename: Option<AttrValue>, pub basename: Option<AttrValue>,
} }

View File

@ -5,7 +5,7 @@ use std::cell::RefCell;
use slab::Slab; use slab::Slab;
use crate::html::Scope; use crate::html::Scope;
use crate::{html, Callback, Children, Component, Context, Html, Properties}; use crate::{Callback, Component, Context, Html, Properties};
/// Props for [`ContextProvider`] /// Props for [`ContextProvider`]
#[derive(Debug, Clone, PartialEq, Properties)] #[derive(Debug, Clone, PartialEq, Properties)]
@ -13,7 +13,7 @@ pub struct ContextProviderProps<T: Clone + PartialEq> {
/// Context value to be passed down /// Context value to be passed down
pub context: T, pub context: T,
/// Children /// Children
pub children: Children, pub children: Html,
} }
/// The context provider component. /// The context provider component.
@ -103,6 +103,6 @@ impl<T: Clone + PartialEq + 'static> Component for ContextProvider<T> {
} }
fn view(&self, ctx: &Context<Self>) -> Html { fn view(&self, ctx: &Context<Self>) -> Html {
html! { <>{ ctx.props().children.clone() }</> } ctx.props().children.clone()
} }
} }

View File

@ -15,7 +15,7 @@ pub use listeners::Registry;
use wasm_bindgen::JsCast; use wasm_bindgen::JsCast;
use web_sys::{Element, HtmlTextAreaElement as TextAreaElement}; use web_sys::{Element, HtmlTextAreaElement as TextAreaElement};
use super::{BList, BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget}; use super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget};
use crate::html::AnyScope; use crate::html::AnyScope;
use crate::virtual_dom::vtag::{InputFields, VTagInner, Value, MATHML_NAMESPACE, SVG_NAMESPACE}; use crate::virtual_dom::vtag::{InputFields, VTagInner, Value, MATHML_NAMESPACE, SVG_NAMESPACE};
use crate::virtual_dom::{Attributes, Key, VTag}; use crate::virtual_dom::{Attributes, Key, VTag};
@ -52,8 +52,8 @@ enum BTagInner {
Other { Other {
/// A tag of the element. /// A tag of the element.
tag: Cow<'static, str>, tag: Cow<'static, str>,
/// List of child nodes /// Child node.
child_bundle: BList, child_bundle: BNode,
}, },
} }
@ -297,10 +297,10 @@ impl BTag {
#[cfg(target_arch = "wasm32")] #[cfg(target_arch = "wasm32")]
#[cfg(test)] #[cfg(test)]
fn children(&self) -> &[BNode] { fn children(&self) -> Option<&BNode> {
match &self.inner { match &self.inner {
BTagInner::Other { child_bundle, .. } => child_bundle, BTagInner::Other { child_bundle, .. } => Some(child_bundle),
_ => &[], _ => None,
} }
} }
@ -610,7 +610,7 @@ mod tests {
let svg_tag = assert_vtag(svg_node); let svg_tag = assert_vtag(svg_node);
let (_, svg_tag) = svg_tag.attach(&root, &scope, &parent, DomSlot::at_end()); let (_, svg_tag) = svg_tag.attach(&root, &scope, &parent, DomSlot::at_end());
assert_namespace(&svg_tag, SVG_NAMESPACE); assert_namespace(&svg_tag, SVG_NAMESPACE);
let path_tag = assert_btag_ref(svg_tag.children().get(0).unwrap()); let path_tag = assert_btag_ref(svg_tag.children().unwrap());
assert_namespace(path_tag, SVG_NAMESPACE); assert_namespace(path_tag, SVG_NAMESPACE);
let g_tag = assert_vtag(g_node.clone()); let g_tag = assert_vtag(g_node.clone());
@ -631,7 +631,7 @@ mod tests {
let math_tag = assert_vtag(math_node); let math_tag = assert_vtag(math_node);
let (_, math_tag) = math_tag.attach(&root, &scope, &parent, DomSlot::at_end()); let (_, math_tag) = math_tag.attach(&root, &scope, &parent, DomSlot::at_end());
assert_namespace(&math_tag, MATHML_NAMESPACE); assert_namespace(&math_tag, MATHML_NAMESPACE);
let mfrac_tag = assert_btag_ref(math_tag.children().get(0).unwrap()); let mfrac_tag = assert_btag_ref(math_tag.children().unwrap());
assert_namespace(mfrac_tag, MATHML_NAMESPACE); assert_namespace(mfrac_tag, MATHML_NAMESPACE);
} }

View File

@ -3,8 +3,8 @@
use std::fmt; use std::fmt;
use crate::html::Html; use crate::html::Html;
use crate::virtual_dom::VChild; use crate::virtual_dom::{VChild, VComp, VList, VNode};
use crate::Properties; use crate::{BaseComponent, Properties};
/// A type used for accepting children elements in Component::Properties. /// A type used for accepting children elements in Component::Properties.
/// ///
@ -233,12 +233,48 @@ impl<T> IntoIterator for ChildrenRenderer<T> {
} }
} }
impl From<ChildrenRenderer<Html>> for Html {
fn from(mut val: ChildrenRenderer<Html>) -> Self {
if val.children.len() == 1 {
if let Some(m) = val.children.pop() {
return m;
}
}
Html::VList(val.into())
}
}
impl From<ChildrenRenderer<Html>> for VList {
fn from(val: ChildrenRenderer<Html>) -> Self {
if val.is_empty() {
return VList::new();
}
VList::with_children(val.children, None)
}
}
impl<COMP> From<ChildrenRenderer<VChild<COMP>>> for ChildrenRenderer<Html>
where
COMP: BaseComponent,
{
fn from(value: ChildrenRenderer<VChild<COMP>>) -> Self {
Self::new(
value
.into_iter()
.map(VComp::from)
.map(VNode::from)
.collect(),
)
}
}
/// A [Properties] type with Children being the only property. /// A [Properties] type with Children being the only property.
#[derive(Debug, Properties, PartialEq)] #[derive(Debug, Properties, PartialEq)]
pub struct ChildrenProps { pub struct ChildrenProps {
/// The Children of a Component. /// The Children of a Component.
#[prop_or_default] #[prop_or_default]
pub children: Children, pub children: Html,
} }
#[cfg(test)] #[cfg(test)]

View File

@ -1,7 +1,7 @@
//! Primitive Components & Properties Types //! Primitive Components & Properties Types
use crate::function_component;
use crate::html::{BaseComponent, ChildrenProps, Html}; use crate::html::{BaseComponent, ChildrenProps, Html};
use crate::{function_component, html};
/// A Component to represent a component that does not exist in current implementation. /// A Component to represent a component that does not exist in current implementation.
/// ///
@ -142,5 +142,5 @@ pub fn PhantomComponent<T>(props: &ChildrenProps) -> Html
where where
T: BaseComponent, T: BaseComponent,
{ {
html! { <>{props.children.clone()}</> } props.children.clone()
} }

View File

@ -3,9 +3,10 @@ use std::rc::Rc;
use implicit_clone::unsync::{IArray, IMap}; use implicit_clone::unsync::{IArray, IMap};
pub use implicit_clone::ImplicitClone; pub use implicit_clone::ImplicitClone;
use super::super::callback::Callback; use super::ToHtml;
use super::{BaseComponent, Children, ChildrenRenderer, Component, NodeRef, Scope}; use crate::callback::Callback;
use crate::virtual_dom::{AttrValue, VChild, VNode}; use crate::html::{BaseComponent, ChildrenRenderer, Component, NodeRef, Scope};
use crate::virtual_dom::{AttrValue, VChild, VNode, VText};
impl ImplicitClone for NodeRef {} impl ImplicitClone for NodeRef {}
impl<Comp: Component> ImplicitClone for Scope<Comp> {} impl<Comp: Component> ImplicitClone for Scope<Comp> {}
@ -81,63 +82,74 @@ where
} }
} }
impl<T> IntoPropValue<ChildrenRenderer<VChild<T>>> for VChild<T> impl<T, C> IntoPropValue<ChildrenRenderer<C>> for VChild<T>
where where
T: BaseComponent, T: BaseComponent,
C: Clone + Into<VNode>,
VChild<T>: Into<C>,
{ {
#[inline] #[inline]
fn into_prop_value(self) -> ChildrenRenderer<VChild<T>> { fn into_prop_value(self) -> ChildrenRenderer<C> {
ChildrenRenderer::new(vec![self.into()])
}
}
impl<T, C> IntoPropValue<Option<ChildrenRenderer<C>>> for VChild<T>
where
T: BaseComponent,
C: Clone + Into<VNode>,
VChild<T>: Into<C>,
{
#[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<C>> {
Some(ChildrenRenderer::new(vec![self.into()]))
}
}
impl<T, C> IntoPropValue<Option<ChildrenRenderer<C>>> for Option<VChild<T>>
where
T: BaseComponent,
C: Clone + Into<VNode>,
VChild<T>: Into<C>,
{
#[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<C>> {
self.map(|m| ChildrenRenderer::new(vec![m.into()]))
}
}
impl<T, R> IntoPropValue<ChildrenRenderer<R>> for Vec<T>
where
T: Into<R>,
R: Clone + Into<VNode>,
{
#[inline]
fn into_prop_value(self) -> ChildrenRenderer<R> {
ChildrenRenderer::new(self.into_iter().map(|m| m.into()).collect())
}
}
impl<T> IntoPropValue<VNode> for T
where
T: ToHtml,
{
#[inline]
fn into_prop_value(self) -> VNode {
self.into_html()
}
}
impl IntoPropValue<ChildrenRenderer<VNode>> for VNode {
#[inline]
fn into_prop_value(self) -> ChildrenRenderer<VNode> {
ChildrenRenderer::new(vec![self]) ChildrenRenderer::new(vec![self])
} }
} }
impl<T> IntoPropValue<Option<ChildrenRenderer<VChild<T>>>> for VChild<T> impl IntoPropValue<ChildrenRenderer<VNode>> for VText {
where
T: BaseComponent,
{
#[inline] #[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<VChild<T>>> { fn into_prop_value(self) -> ChildrenRenderer<VNode> {
Some(ChildrenRenderer::new(vec![self])) ChildrenRenderer::new(vec![self.into()])
}
}
impl<T> IntoPropValue<Option<ChildrenRenderer<VChild<T>>>> for Option<VChild<T>>
where
T: BaseComponent,
{
#[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<VChild<T>>> {
self.map(|m| ChildrenRenderer::new(vec![m]))
}
}
impl<T> IntoPropValue<ChildrenRenderer<VChild<T>>> for Vec<VChild<T>>
where
T: BaseComponent,
{
#[inline]
fn into_prop_value(self) -> ChildrenRenderer<VChild<T>> {
ChildrenRenderer::new(self)
}
}
impl<T> IntoPropValue<Option<ChildrenRenderer<VChild<T>>>> for Vec<VChild<T>>
where
T: BaseComponent,
{
#[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<VChild<T>>> {
Some(ChildrenRenderer::new(self))
}
}
impl<T> IntoPropValue<Option<ChildrenRenderer<VChild<T>>>> for Option<Vec<VChild<T>>>
where
T: BaseComponent,
{
#[inline]
fn into_prop_value(self) -> Option<ChildrenRenderer<VChild<T>>> {
self.map(ChildrenRenderer::new)
} }
} }
@ -171,14 +183,9 @@ macro_rules! impl_into_prop {
// implemented with literals in mind // implemented with literals in mind
impl_into_prop!(|value: &'static str| -> String { value.to_owned() }); impl_into_prop!(|value: &'static str| -> String { value.to_owned() });
impl_into_prop!(|value: &'static str| -> AttrValue { AttrValue::Static(value) }); impl_into_prop!(|value: &'static str| -> AttrValue { AttrValue::Static(value) });
impl_into_prop!(|value: String| -> AttrValue { AttrValue::Rc(Rc::from(value)) }); impl_into_prop!(|value: String| -> AttrValue { AttrValue::Rc(Rc::from(value)) });
impl_into_prop!(|value: Rc<str>| -> AttrValue { AttrValue::Rc(value) }); impl_into_prop!(|value: Rc<str>| -> AttrValue { AttrValue::Rc(value) });
impl_into_prop!(|value: VNode| -> Children { Children::new(vec![value]) });
impl_into_prop!(|value: &'static str| -> VNode { crate::html!(value) });
impl_into_prop!(|value: String| -> VNode { crate::html!(value) });
impl_into_prop!(|value: AttrValue| -> VNode { crate::html!(value) });
impl<T: ImplicitClone + 'static> IntoPropValue<IArray<T>> for &'static [T] { impl<T: ImplicitClone + 'static> IntoPropValue<IArray<T>> for &'static [T] {
fn into_prop_value(self) -> IArray<T> { fn into_prop_value(self) -> IArray<T> {
@ -309,13 +316,13 @@ mod test {
html! { html! {
<div> <div>
<header> <header>
{header} {for header}
</header> </header>
<main> <main>
{children} {children}
</main> </main>
<footer> <footer>
{footer} {for footer}
</footer> </footer>
</div> </div>
} }

View File

@ -0,0 +1,5 @@
mod into_prop_value;
mod to_html;
pub use into_prop_value::*;
pub use to_html::*;

View File

@ -0,0 +1,203 @@
use std::borrow::Cow;
use std::rc::Rc;
use std::sync::Arc;
use crate::html::{ChildrenRenderer, IntoPropValue};
use crate::virtual_dom::{VChild, VList, VNode, VText};
use crate::{AttrValue, BaseComponent, Html};
/// A trait implemented for types be rendered as a part of a Html.
///
/// Types that implements this trait can define a virtual dom layout that itself should be rendered
/// into via `html!` and can be referenced / consumed as `{value}` in an `html!` macro invocation.
pub trait ToHtml {
/// Converts this type to a [`Html`].
fn to_html(&self) -> Html;
/// Converts this type into a [`Html`].
fn into_html(self) -> Html
where
Self: Sized,
{
self.to_html()
}
}
// Implementations for common data types.
impl<T> ToHtml for Option<T>
where
T: ToHtml,
{
#[inline(always)]
fn to_html(&self) -> Html {
self.as_ref().map(ToHtml::to_html).unwrap_or_default()
}
#[inline(always)]
fn into_html(self) -> Html {
self.map(ToHtml::into_html).unwrap_or_default()
}
}
impl<T> ToHtml for Vec<T>
where
T: ToHtml,
{
#[inline(always)]
fn to_html(&self) -> Html {
Html::VList(VList::with_children(
self.iter().map(ToHtml::to_html).collect(),
None,
))
}
#[inline(always)]
fn into_html(self) -> Html {
Html::VList(VList::with_children(
self.into_iter().map(ToHtml::into_html).collect(),
None,
))
}
}
impl ToHtml for Option<VNode> {
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into_html()
}
#[inline(always)]
fn into_html(self) -> Html {
self.unwrap_or_default()
}
}
impl ToHtml for Vec<VNode> {
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into_html()
}
#[inline(always)]
fn into_html(self) -> Html {
Html::VList(VList::with_children(self, None))
}
}
impl ToHtml for VText {
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into()
}
#[inline(always)]
fn into_html(self) -> Html {
Html::VText(self)
}
}
impl ToHtml for VList {
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into()
}
#[inline(always)]
fn into_html(self) -> Html {
Html::VList(self)
}
}
impl ToHtml for ChildrenRenderer<VNode> {
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into()
}
#[inline(always)]
fn into_html(self) -> Html {
self.into()
}
}
impl<T> ToHtml for VChild<T>
where
T: BaseComponent,
{
#[inline(always)]
fn to_html(&self) -> Html {
self.clone().into()
}
#[inline(always)]
fn into_html(self) -> Html {
VNode::VComp(self.into())
}
}
impl ToHtml for () {
#[inline(always)]
fn to_html(&self) -> Html {
VNode::default()
}
#[inline(always)]
fn into_html(self) -> Html {
VNode::default()
}
}
impl<T> ToHtml for &'_ T
where
T: ToHtml,
{
fn to_html(&self) -> Html {
(*self).to_html()
}
}
macro_rules! impl_to_html_via_display {
($from_ty: ty) => {
impl ToHtml for $from_ty {
#[inline(always)]
fn to_html(&self) -> Html {
Html::VText(VText::from(self))
}
}
// Mirror ToHtml to Children implementation.
impl IntoPropValue<ChildrenRenderer<VNode>> for $from_ty {
#[inline(always)]
fn into_prop_value(self) -> ChildrenRenderer<VNode> {
ChildrenRenderer::new(vec![VText::from(self).into()])
}
}
};
}
// These are a selection of types implemented via display.
impl_to_html_via_display!(bool);
impl_to_html_via_display!(char);
impl_to_html_via_display!(String);
impl_to_html_via_display!(&str);
impl_to_html_via_display!(Rc<str>);
impl_to_html_via_display!(Rc<String>);
impl_to_html_via_display!(Arc<str>);
impl_to_html_via_display!(Arc<String>);
impl_to_html_via_display!(AttrValue);
impl_to_html_via_display!(Cow<'_, str>);
impl_to_html_via_display!(u8);
impl_to_html_via_display!(u16);
impl_to_html_via_display!(u32);
impl_to_html_via_display!(u64);
impl_to_html_via_display!(u128);
impl_to_html_via_display!(usize);
impl_to_html_via_display!(i8);
impl_to_html_via_display!(i16);
impl_to_html_via_display!(i32);
impl_to_html_via_display!(i64);
impl_to_html_via_display!(i128);
impl_to_html_via_display!(isize);
impl_to_html_via_display!(f32);
impl_to_html_via_display!(f64);

View File

@ -336,7 +336,7 @@ pub mod prelude {
pub use crate::functional::*; pub use crate::functional::*;
pub use crate::html::{ pub use crate::html::{
create_portal, BaseComponent, Children, ChildrenWithProps, Classes, Component, Context, create_portal, BaseComponent, Children, ChildrenWithProps, Classes, Component, Context,
Html, HtmlResult, NodeRef, Properties, Html, HtmlResult, NodeRef, Properties, ToHtml,
}; };
pub use crate::macros::{classes, html, html_nested}; pub use crate::macros::{classes, html, html_nested};
pub use crate::suspense::Suspense; pub use crate::suspense::Suspense;

View File

@ -91,14 +91,7 @@ where
} }
} }
/// Renders Yew Application into a string Stream fn render_stream_inner(self) -> impl Stream<Item = String> {
#[tracing::instrument(
level = tracing::Level::DEBUG,
name = "render",
skip(self),
fields(hydratable = self.hydratable),
)]
pub fn render_stream(self) -> impl Stream<Item = String> {
let scope = Scope::<COMP>::new(None); let scope = Scope::<COMP>::new(None);
let outer_span = tracing::Span::current(); let outer_span = tracing::Span::current();
@ -111,6 +104,36 @@ where
.await; .await;
}) })
} }
// The duplicate implementation below is to selectively suppress clippy lints.
// These implementations should be merged once https://github.com/tokio-rs/tracing/issues/2503 is resolved.
/// Renders Yew Application into a string Stream
#[rustversion::since(1.70)]
#[allow(clippy::let_with_type_underscore)]
#[tracing::instrument(
level = tracing::Level::DEBUG,
name = "render_stream",
skip(self),
fields(hydratable = self.hydratable),
)]
#[inline(always)]
pub fn render_stream(self) -> impl Stream<Item = String> {
self.render_stream_inner()
}
/// Renders Yew Application into a string Stream
#[rustversion::before(1.70)]
#[tracing::instrument(
level = tracing::Level::DEBUG,
name = "render_stream",
skip(self),
fields(hydratable = self.hydratable),
)]
#[inline(always)]
pub fn render_stream(self) -> impl Stream<Item = String> {
self.render_stream_inner()
}
} }
/// A Yew Server-side Renderer. /// A Yew Server-side Renderer.

View File

@ -1,11 +1,11 @@
use crate::html::{Children, Html, Properties}; use crate::html::{Html, Properties};
/// Properties for [Suspense]. /// Properties for [Suspense].
#[derive(Properties, PartialEq, Debug, Clone)] #[derive(Properties, PartialEq, Debug, Clone)]
pub struct SuspenseProps { pub struct SuspenseProps {
/// The Children of the current Suspense Component. /// The Children of the current Suspense Component.
#[prop_or_default] #[prop_or_default]
pub children: Children, pub children: Html,
/// The Fallback UI of the current Suspense Component. /// The Fallback UI of the current Suspense Component.
#[prop_or_default] #[prop_or_default]
@ -15,7 +15,7 @@ pub struct SuspenseProps {
#[cfg(any(feature = "csr", feature = "ssr"))] #[cfg(any(feature = "csr", feature = "ssr"))]
mod feat_csr_ssr { mod feat_csr_ssr {
use super::*; use super::*;
use crate::html::{Children, Component, Context, Html, Scope}; use crate::html::{Component, Context, Html, Scope};
use crate::suspense::Suspension; use crate::suspense::Suspension;
#[cfg(feature = "hydration")] #[cfg(feature = "hydration")]
use crate::suspense::SuspensionHandle; use crate::suspense::SuspensionHandle;
@ -24,7 +24,7 @@ mod feat_csr_ssr {
#[derive(Properties, PartialEq, Debug, Clone)] #[derive(Properties, PartialEq, Debug, Clone)]
pub(crate) struct BaseSuspenseProps { pub(crate) struct BaseSuspenseProps {
pub children: Children, pub children: Html,
pub fallback: Option<Html>, pub fallback: Option<Html>,
} }

View File

@ -41,15 +41,6 @@ impl<IN: Into<OUT>, OUT> From<Vec<IN>> for NodeSeq<IN, OUT> {
} }
} }
impl<IN: Into<OUT>, OUT> From<ChildrenRenderer<IN>> for NodeSeq<IN, OUT> {
fn from(val: ChildrenRenderer<IN>) -> Self {
Self(
val.into_iter().map(|x| x.into()).collect(),
PhantomData::default(),
)
}
}
impl<IN: Into<OUT> + Clone, OUT> From<&ChildrenRenderer<IN>> for NodeSeq<IN, OUT> { impl<IN: Into<OUT> + Clone, OUT> From<&ChildrenRenderer<IN>> for NodeSeq<IN, OUT> {
fn from(val: &ChildrenRenderer<IN>) -> Self { fn from(val: &ChildrenRenderer<IN>) -> Self {
Self( Self(

View File

@ -1,8 +1,8 @@
//! This module contains the implementation of abstract virtual node. //! This module contains the implementation of abstract virtual node.
use std::cmp::PartialEq; use std::cmp::PartialEq;
use std::fmt;
use std::iter::FromIterator; use std::iter::FromIterator;
use std::{fmt, mem};
use web_sys::Node; use web_sys::Node;
@ -53,6 +53,20 @@ impl VNode {
self.key().is_some() self.key().is_some()
} }
/// Acquires a mutable reference of current VNode as a VList.
///
/// Creates a VList with the current node as the first child if current VNode is not a VList.
pub fn to_vlist_mut(&mut self) -> &mut VList {
loop {
match *self {
Self::VList(ref mut m) => return m,
_ => {
*self = VNode::VList(VList::with_children(vec![mem::take(self)], None));
}
}
}
}
/// Create a [`VNode`] from a string of HTML /// Create a [`VNode`] from a string of HTML
/// ///
/// # Behavior in browser /// # Behavior in browser

View File

@ -9,7 +9,7 @@ use std::rc::Rc;
use web_sys::{HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement}; use web_sys::{HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement};
use super::{ApplyAttributeAs, AttrValue, Attributes, Key, Listener, Listeners, VList, VNode}; use super::{ApplyAttributeAs, AttrValue, Attributes, Key, Listener, Listeners, VNode};
use crate::html::{IntoPropValue, NodeRef}; use crate::html::{IntoPropValue, NodeRef};
/// SVG namespace string used for creating svg elements /// SVG namespace string used for creating svg elements
@ -112,8 +112,8 @@ pub(crate) enum VTagInner {
Other { Other {
/// A tag of the element. /// A tag of the element.
tag: Cow<'static, str>, tag: Cow<'static, str>,
/// List of child nodes /// children of the element.
children: VList, children: VNode,
}, },
} }
@ -232,7 +232,7 @@ impl VTag {
// at bottom for more readable macro-expanded coded // at bottom for more readable macro-expanded coded
attributes: Attributes, attributes: Attributes,
listeners: Listeners, listeners: Listeners,
children: VList, children: VNode,
) -> Self { ) -> Self {
VTag::new_base( VTag::new_base(
VTagInner::Other { tag, children }, VTagInner::Other { tag, children },
@ -274,45 +274,41 @@ impl VTag {
/// Add [VNode] child. /// Add [VNode] child.
pub fn add_child(&mut self, child: VNode) { pub fn add_child(&mut self, child: VNode) {
if let VTagInner::Other { children, .. } = &mut self.inner { if let VTagInner::Other { children, .. } = &mut self.inner {
children.add_child(child) children.to_vlist_mut().add_child(child)
} }
} }
/// Add multiple [VNode] children. /// Add multiple [VNode] children.
pub fn add_children(&mut self, children: impl IntoIterator<Item = VNode>) { pub fn add_children(&mut self, children: impl IntoIterator<Item = VNode>) {
if let VTagInner::Other { children: dst, .. } = &mut self.inner { if let VTagInner::Other { children: dst, .. } = &mut self.inner {
dst.add_children(children) dst.to_vlist_mut().add_children(children)
} }
} }
/// Returns a reference to the children of this [VTag] /// Returns a reference to the children of this [VTag], if the node can have
pub fn children(&self) -> &VList { /// children
pub fn children(&self) -> Option<&VNode> {
match &self.inner { match &self.inner {
VTagInner::Other { children, .. } => children, VTagInner::Other { children, .. } => Some(children),
_ => { _ => None,
// This is mutable because the VList is not Sync
static mut EMPTY: VList = VList::new();
// SAFETY: The EMPTY value is always read-only
unsafe { &EMPTY }
}
} }
} }
/// Returns a mutable reference to the children of this [VTag], if the node can have /// Returns a mutable reference to the children of this [VTag], if the node can have
/// children /// children
pub fn children_mut(&mut self) -> Option<&mut VList> { pub fn children_mut(&mut self) -> Option<&mut VNode> {
match &mut self.inner { match &mut self.inner {
VTagInner::Other { children, .. } => Some(children), VTagInner::Other { children, .. } => Some(children),
_ => None, _ => None,
} }
} }
/// Returns the children of this [VTag] /// Returns the children of this [VTag], if the node can have
pub fn into_children(self) -> VList { /// children
pub fn into_children(self) -> Option<VNode> {
match self.inner { match self.inner {
VTagInner::Other { children, .. } => children, VTagInner::Other { children, .. } => Some(children),
_ => VList::new(), _ => None,
} }
} }
@ -530,7 +526,13 @@ mod feat_ssr {
let _ = w.write_str(">"); let _ = w.write_str(">");
} else { } else {
// We don't write children of void elements nor closing tags. // We don't write children of void elements nor closing tags.
debug_assert!(children.is_empty(), "{tag} cannot have any children!"); debug_assert!(
match children {
VNode::VList(m) => m.is_empty(),
_ => false,
},
"{tag} cannot have any children!"
);
} }
} }
} }

View File

@ -32,6 +32,12 @@ impl PartialEq for VText {
} }
} }
impl<T: ToString> From<T> for VText {
fn from(value: T) -> Self {
VText::new(value.to_string())
}
}
#[cfg(feature = "ssr")] #[cfg(feature = "ssr")]
mod feat_ssr { mod feat_ssr {

View File

@ -88,14 +88,14 @@ async fn bench_many_providers() -> Duration {
#[derive(Properties, PartialEq, Clone)] #[derive(Properties, PartialEq, Clone)]
struct ProviderProps { struct ProviderProps {
children: Children, children: Html,
} }
#[function_component] #[function_component]
fn Provider(props: &ProviderProps) -> Html { fn Provider(props: &ProviderProps) -> Html {
let ProviderProps { children } = props.clone(); let ProviderProps { children } = props.clone();
html! {<>{children}</>} children
} }
#[function_component] #[function_component]

View File

@ -10,7 +10,7 @@ The `#[function_component]` attribute also works with generic functions for crea
```rust ```rust
use std::fmt::Display; use std::fmt::Display;
use yew::{function_component, html, Properties, Html}; use yew::{function_component, html, Properties, Html, ToHtml};
#[derive(Properties, PartialEq)] #[derive(Properties, PartialEq)]
pub struct Props<T> pub struct Props<T>
@ -23,7 +23,7 @@ where
#[function_component] #[function_component]
pub fn MyGenericComponent<T>(props: &Props<T>) -> Html pub fn MyGenericComponent<T>(props: &Props<T>) -> Html
where where
T: PartialEq + Display, T: PartialEq + ToHtml,
{ {
html! { html! {
<p> <p>