diff --git a/.github/workflows/auto-approve-maintainer-pr.yml b/.github/workflows/auto-approve-maintainer-pr.yml index b7efd1b4efd..62a7d119179 100644 --- a/.github/workflows/auto-approve-maintainer-pr.yml +++ b/.github/workflows/auto-approve-maintainer-pr.yml @@ -19,7 +19,7 @@ jobs: uses: JamesSingleton/is-organization-member@1.0.1 with: organization: "yewstack" - username: ${{ github.actor }} + username: ${{ github.event.pull_request.user.login }} token: ${{ secrets.GITHUB_TOKEN }} - name: Auto approve diff --git a/.github/workflows/benchmark-core.yml b/.github/workflows/benchmark-core.yml new file mode 100644 index 00000000000..f9277e4c385 --- /dev/null +++ b/.github/workflows/benchmark-core.yml @@ -0,0 +1,71 @@ +--- +name: Benchmark - core + +on: + pull_request: + branches: [master] + paths: + - .github/workflows/benchmark-core.yml + - "packages/yew/**" + - "tools/benchmark-core/**" + +jobs: + benchmark-core: + name: Benchmark - core + runs-on: ubuntu-latest + + steps: + - name: Checkout master + uses: actions/checkout@v3 + with: + repository: "yewstack/yew" + ref: master + path: yew-master + + - name: Checkout pull request + uses: actions/checkout@v3 + with: + path: current-pr + + - name: Setup toolchain + uses: dtolnay/rust-toolchain@master + with: + toolchain: stable + + - name: Restore Rust cache for master + uses: Swatinem/rust-cache@v2 + with: + working-directory: yew-master + key: master + + - name: Restore Rust cache for current pull request + uses: Swatinem/rust-cache@v2 + with: + working-directory: current-pr + key: pr + + - name: Run pull request benchmark + run: cargo bench -q > ../output.log + working-directory: current-pr/tools/benchmark-core + + - name: Run master benchmark + run: cargo bench -q > ../output.log + continue-on-error: true + working-directory: yew-master/tools/benchmark-core + + - name: Make sure master's output log exists + run: touch yew-master/tools/output.log + + - name: Write Pull Request ID + run: | + echo "${{ github.event.number }}" > .PR_NUMBER + + - name: Upload Artifact + uses: actions/upload-artifact@v3 + with: + name: benchmark-core + path: | + .PR_NUMBER + yew-master/tools/output.log + current-pr/tools/output.log + retention-days: 1 diff --git a/.github/workflows/post-benchmark-core.yml b/.github/workflows/post-benchmark-core.yml new file mode 100644 index 00000000000..a9f4b5b78c4 --- /dev/null +++ b/.github/workflows/post-benchmark-core.yml @@ -0,0 +1,100 @@ +--- +name: Post Comment for Benchmark - core + +on: + workflow_run: + workflows: ["Benchmark - core"] + types: + - completed + +jobs: + post-benchmark-core: + if: github.event.workflow_run.event == 'pull_request' + name: Post Comment on Pull Request + runs-on: ubuntu-latest + + steps: + - name: Download Repository + uses: actions/checkout@v3 + + - name: Download Artifact + uses: Legit-Labs/action-download-artifact@v2 + with: + github_token: "${{ secrets.GITHUB_TOKEN }}" + workflow: benchmark-core.yml + run_id: ${{ github.event.workflow_run.id }} + name: benchmark-core + path: "benchmark-core/" + + - name: Make pull request comment + run: | + cat - >>comment.txt <>comment.txt + cat - >>comment.txt <>comment.txt + cat - >>comment.txt <> $GITHUB_ENV + + - name: Post Comment + uses: actions/github-script@v6 + with: + script: | + const fs = require('fs'); + + const commentInfo = { + ...context.repo, + issue_number: ${{ env.PR_NUMBER }}, + }; + + const comment = { + ...commentInfo, + body: fs.readFileSync("comment.txt", 'utf-8'), + }; + + function isCommentByBot(comment) { + return comment.user.type === "Bot" && comment.body.includes("### Benchmark - core"); + } + + let commentId = null; + const comments = (await github.rest.issues.listComments(commentInfo)).data; + for (let i = comments.length; i--; ) { + const c = comments[i]; + if (isCommentByBot(c)) { + commentId = c.id; + break; + } + } + + if (commentId) { + try { + await github.rest.issues.updateComment({ + ...context.repo, + comment_id: commentId, + body: comment.body, + }); + } catch (e) { + commentId = null; + } + } + + if (!commentId) { + await github.rest.issues.createComment(comment); + } diff --git a/CHANGELOG.md b/CHANGELOG.md index ec5a20781a9..4a620e82cbb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ - Assert there are no circular references. [[@WorldSEnder](https://github.com/WorldSEnder), [#3025](https://github.com/yewstack/yew/pull/3025)] ## 🚨 Breaking changes - - Remove special handing of struct fields of type `Option` in `derive(Properties)`. [[@Tim Kurdov](https://github.com/Tim Kurdov), [#3398](https://github.com/yewstack/yew/pull/3398)] + - Remove special handling of struct fields of type `Option` in `derive(Properties)`. [[@Tim Kurdov](https://github.com/Tim Kurdov), [#3398](https://github.com/yewstack/yew/pull/3398)] - Agent v2. [[@Kaede Hoshikawa](https://github.com/Kaede Hoshikawa), [#2773](https://github.com/yewstack/yew/pull/2773)] - Update signature of use_prepared_state/use_transitive_state. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3376](https://github.com/yewstack/yew/pull/3376)] - Make signature of use_future_with consistent. [[@Muhammad Hamza](https://github.com/Muhammad Hamza), [#3372](https://github.com/yewstack/yew/pull/3372)] @@ -210,7 +210,7 @@ - Fix clippy lints from 1.54.0. [[@Xavientois](https://github.com/Xavientois), [#1976](https://github.com/yewstack/yew/pull/1976)] - Fix scheduler main queue delay (#1953). [[@intendednull](https://github.com/intendednull), [#1954](https://github.com/yewstack/yew/pull/1954)] - Fix case warning on derived properties. [[@nitnelave](https://github.com/nitnelave), [#1929](https://github.com/yewstack/yew/pull/1929)] - - yew-macro: fix inability to set the autoplay atribute. [[@bakape](https://github.com/bakape), [#1866](https://github.com/yewstack/yew/pull/1866)] + - yew-macro: fix inability to set the autoplay attribute. [[@bakape](https://github.com/bakape), [#1866](https://github.com/yewstack/yew/pull/1866)] - Fix duplicate `with props` error messages.. [[@teymour-aldridge](https://github.com/teymour-aldridge), [#1730](https://github.com/yewstack/yew/pull/1730)] - Remove extra braces in html_nested macro. [[@Madoshakalaka](https://github.com/Madoshakalaka), [#2169](https://github.com/yewstack/yew/pull/2169)] - Remove unused punct field from props. [[@Xavientois](https://github.com/Xavientois), [#1969](https://github.com/yewstack/yew/pull/1969)] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d7c4ebaf738..b3e09b36958 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -75,7 +75,7 @@ and follow the repository's README. ## Writing APIs -When building new APIs, think about what it would be like to use them. Would this API cause confusing and hard to pin error mesages? Would this API integrate well with other APIs? Is it intuitive to use this API? +When building new APIs, think about what it would be like to use them. Would this API cause confusing and hard to pin error messages? Would this API integrate well with other APIs? Is it intuitive to use this API? Below, you can find some useful guidance and best practices on how to write APIs. These are only _guidelines_ and while they are helpful and should be followed where possible, in some cases, it may not be possible to do so. diff --git a/Cargo.lock b/Cargo.lock index cc019a2dcaa..b560bd7eaef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -109,7 +109,7 @@ checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -117,7 +117,7 @@ name = "async_clock" version = "0.0.1" dependencies = [ "chrono", - "futures 0.3.28", + "futures 0.3.29", "gloo-net 0.4.0", "yew", ] @@ -220,9 +220,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9" [[package]] name = "base64ct" @@ -239,6 +239,14 @@ dependencies = [ "serde", ] +[[package]] +name = "benchmark-core" +version = "0.1.0" +dependencies = [ + "divan", + "yew", +] + [[package]] name = "benchmark-ssr" version = "0.1.0" @@ -384,9 +392,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956" +checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b" dependencies = [ "clap_builder", "clap_derive", @@ -394,33 +402,34 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.4.6" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45" +checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663" dependencies = [ "anstream", "anstyle", "clap_lex", "strsim", + "terminal_size", ] [[package]] name = "clap_derive" -version = "4.4.2" +version = "4.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873" +checksum = "cf9804afaaf59a91e75b022a30fb7229a7901f60c755489cc61c9b423b836442" dependencies = [ "heck", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "clap_lex" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b" +checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1" [[package]] name = "cobs" @@ -462,6 +471,12 @@ dependencies = [ "yew", ] +[[package]] +name = "condtype" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf0a07a401f374238ab8e2f11a104d2851bf9ce711ec69804834de8af45c7af" + [[package]] name = "console" version = "0.15.7" @@ -515,6 +530,17 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +[[package]] +name = "core_affinity" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622892f5635ce1fc38c8f16dfc938553ed64af482edb5e150bf4caedbfcb2304" +dependencies = [ + "libc", + "num_cpus", + "winapi", +] + [[package]] name = "counter" version = "0.1.1" @@ -600,9 +626,12 @@ checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "0f32d04922c60427da6f9fef14d042d9edddef64cb9d4ce0d64d0685fbeb1fd3" +dependencies = [ + "powerfmt", +] [[package]] name = "derive_builder" @@ -648,6 +677,12 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "deunicode" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a1abaf4d861455be59f64fd2b55606cb151fce304ede7165f410243ce96bde6" + [[package]] name = "digest" version = "0.10.7" @@ -658,6 +693,31 @@ dependencies = [ "crypto-common", ] +[[package]] +name = "divan" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9fe20b31e5a6a2c689cb9cd6b8ab3e1b417536b2369830b037acfee34b11469" +dependencies = [ + "clap", + "condtype", + "core_affinity", + "divan-macros", + "linkme", + "regex-lite", +] + +[[package]] +name = "divan-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c41656525d3cbca56bc91ca045ffb591b7b7d7bd7453750b63bacc35c46f3cc" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "dyn_create_destroy_apps" version = "0.1.0" @@ -742,12 +802,12 @@ dependencies = [ [[package]] name = "fake" -version = "2.8.0" +version = "2.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9af7b0c58ac9d03169e27f080616ce9f64004edca3d2ef4147a811c21b23b319" +checksum = "26221445034074d46b276e13eb97a265ebdb8ed8da705c4dddd3dd20b66b45d2" dependencies = [ + "deunicode", "rand", - "unidecode", ] [[package]] @@ -773,7 +833,7 @@ dependencies = [ name = "file_upload" version = "0.1.0" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "gloo 0.10.0", "js-sys", "web-sys", @@ -874,9 +934,9 @@ dependencies = [ [[package]] name = "futures" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "da0290714b38af9b4a7b094b8a37086d1b4e61f2df9122c3cad2577669145335" dependencies = [ "futures-channel", "futures-core", @@ -889,9 +949,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "ff4dd66668b557604244583e3e1e1eada8c5c2e96a6d0d6653ede395b78bbacb" dependencies = [ "futures-core", "futures-sink", @@ -899,15 +959,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "eb1d22c66e66d9d72e1758f0bd7d4fd0bee04cad842ee34587d68c07e45d088c" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "0f4fb8693db0cf099eadcca0efe2a5a22e4550f98ed16aba6c48700da29597bc" dependencies = [ "futures-core", "futures-task", @@ -916,38 +976,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "8bf34a163b5c4c52d0478a4d757da8fb65cabef42ba90515efee0f6f9fa45aaa" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "53b153fd91e4b0147f4aced87be237c98248656bb01050b96bf3ee89220a8ddb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "e36d3378ee38c2a36ad710c5d30c2911d752cb941c00c72dbabfb786a7970817" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "efd193069b0ddadc69c46389b740bbccdd97203899b48d09c5f7969591d6bae2" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "a19526d624e703a3179b3d322efec918b6246ea0fa51d41124525f00f1cc8104" dependencies = [ "futures-channel", "futures-core", @@ -1058,7 +1118,7 @@ dependencies = [ "gloo-storage 0.3.0", "gloo-timers 0.3.0", "gloo-utils 0.2.0", - "gloo-worker 0.4.0", + "gloo-worker 0.4.1", ] [[package]] @@ -1343,12 +1403,12 @@ dependencies = [ [[package]] name = "gloo-worker" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76495d3dd87de51da268fa3a593da118ab43eb7f8809e17eb38d3319b424e400" +checksum = "f2cbd4c35cc3a2b1fb792318acc06bd514193f6d058173da5cdbcdabe6514303" dependencies = [ "bincode", - "futures 0.3.28", + "futures 0.3.29", "gloo-utils 0.2.0", "gloo-worker-macros", "js-sys", @@ -1369,7 +1429,7 @@ dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -1408,9 +1468,9 @@ checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" [[package]] name = "hashbrown" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c6201b9ff9fd90a5a3bac2e56a830d0caa509576f0e503818ee82c181b3437a" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" [[package]] name = "headers" @@ -1619,7 +1679,7 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "af3d77000817fd9e7db159e8d52ed9b5941a2cdbfbdc8ca646e59887ae2b2dd1" dependencies = [ - "indexmap 2.0.1", + "indexmap 2.0.2", ] [[package]] @@ -1634,12 +1694,12 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad227c3af19d4914570ad36d30409928b75967c298feb9ea1969db3a610bb14e" +checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" dependencies = [ "equivalent", - "hashbrown 0.14.0", + "hashbrown 0.14.1", ] [[package]] @@ -1701,7 +1761,7 @@ checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f" dependencies = [ "hermit-abi 0.3.1", "io-lifetimes", - "rustix", + "rustix 0.37.25", "windows-sys 0.48.0", ] @@ -1863,12 +1923,38 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "linkme" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ed2ee9464ff9707af8e9ad834cffa4802f072caad90639c583dd3c62e6e608" +dependencies = [ + "linkme-impl", +] + +[[package]] +name = "linkme-impl" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba125974b109d512fccbc6c0244e7580143e460895dfd6ea7f8bbb692fd94396" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.38", +] + [[package]] name = "linux-raw-sys" version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "lipsum" version = "0.9.0" @@ -2079,7 +2165,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2170,7 +2256,7 @@ checksum = "39407670928234ebc5e6e580247dd567ad73a3578460c5990f9503df207e8f07" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2191,7 +2277,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a829027bd95e54cfe13e3e258a1ae7b645960553fb82b75ff852c29688ee595b" dependencies = [ - "futures 0.3.28", + "futures 0.3.29", "rustversion", "thiserror", ] @@ -2229,6 +2315,12 @@ dependencies = [ "serde", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2242,7 +2334,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" dependencies = [ "proc-macro2", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2287,9 +2379,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "134c189feb4956b20f6f547d2cf727d4c0fe06722b20a0eec87ed445a97f92da" dependencies = [ "unicode-ident", ] @@ -2309,7 +2401,7 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b55e106e5791fa5a13abd13c85d6127312e8e09098059ca2bc9b03ca4cf488" dependencies = [ - "futures 0.3.28", + "futures 0.3.29", "gloo 0.8.1", "num_cpus", "once_cell", @@ -2387,9 +2479,9 @@ dependencies = [ [[package]] name = "regex" -version = "1.9.5" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "697061221ea1b4a94a624f67d0ae2bfe4e22b8a17b6a192afb11046542cc8c47" +checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" dependencies = [ "aho-corasick", "memchr", @@ -2399,28 +2491,34 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.8" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2f401f4955220693b56f8ec66ee9c78abffd8d1c4f23dc41a23839eb88f0795" +checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" dependencies = [ "aho-corasick", "memchr", "regex-syntax", ] +[[package]] +name = "regex-lite" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30b661b2f27137bdbc16f00eda72866a92bb28af1753ffbd56744fb6e2e9cd8e" + [[package]] name = "regex-syntax" -version = "0.7.5" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] name = "reqwest" -version = "0.11.20" +version = "0.11.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e9ad3fe7488d7e34558a2033d45a0c90b72d97b4f80705666fea71472e2e6a1" +checksum = "046cd98826c46c2ac8ddecae268eb5c2e58628688a5fc7a2643704a73faba95b" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", "bytes", "encoding_rs", "futures-core", @@ -2441,6 +2539,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "system-configuration", "tokio", "tokio-native-tls", "tower-service", @@ -2491,15 +2590,28 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.20" +version = "0.37.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b96e891d04aa506a6d1f318d2771bcb1c7dfda84e126660ace067c9b474bb2c0" +checksum = "d4eb579851244c2c03e7c24f501c3432bed80b8f720af1d6e5b0e0f01555a035" dependencies = [ "bitflags 1.3.2", "errno", "io-lifetimes", "libc", - "linux-raw-sys", + "linux-raw-sys 0.3.8", + "windows-sys 0.48.0", +] + +[[package]] +name = "rustix" +version = "0.38.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7db8590df6dfcd144d22afd1b83b36c21a18d7cbc1dc4bb5295a8712e9eb662" +dependencies = [ + "bitflags 2.4.0", + "errno", + "libc", + "linux-raw-sys 0.4.10", "windows-sys 0.48.0", ] @@ -2509,7 +2621,7 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.4", + "base64 0.21.5", ] [[package]] @@ -2570,15 +2682,15 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7" dependencies = [ "serde_derive", ] @@ -2596,13 +2708,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.190" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2663,7 +2775,7 @@ version = "0.1.0" dependencies = [ "bytes", "clap", - "futures 0.3.28", + "futures 0.3.29", "log", "reqwest", "serde", @@ -2727,7 +2839,7 @@ dependencies = [ "clap", "env_logger", "function_router", - "futures 0.3.28", + "futures 0.3.29", "hyper", "jemallocator", "log", @@ -2762,15 +2874,15 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.25.2" +version = "0.25.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8d03b598d3d0fff69bf533ee3ef19b8eeb342729596df84bcc7e1f96ec4059" +checksum = "23dc1fa9ac9c169a78ba62f0b841814b7abae11bdd047b9c58f893439e309ea0" dependencies = [ "heck", "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -2797,9 +2909,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b" dependencies = [ "proc-macro2", "quote", @@ -2812,6 +2924,27 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" +[[package]] +name = "system-configuration" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "system-configuration-sys", +] + +[[package]] +name = "system-configuration-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +dependencies = [ + "core-foundation-sys", + "libc", +] + [[package]] name = "tabled" version = "0.14.0" @@ -2846,7 +2979,7 @@ dependencies = [ "cfg-if", "fastrand", "redox_syscall", - "rustix", + "rustix 0.37.25", "windows-sys 0.48.0", ] @@ -2859,33 +2992,44 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "terminal_size" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21bebf2b7c9e0a515f6e0f8c51dc0f8e4696391e6f1ff30379559f8365fb0df7" +dependencies = [ + "rustix 0.38.13", + "windows-sys 0.48.0", +] + [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.50" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "time" -version = "0.3.29" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "c4a34ab300f2dee6e562c10a046fc05e358b29f9bf92277f30c3c8d82275f6f5" dependencies = [ "deranged", + "powerfmt", "serde", "time-core", ] @@ -2945,9 +3089,9 @@ dependencies = [ [[package]] name = "tokio" -version = "1.32.0" +version = "1.33.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17ed6077ed6cd6c74735e21f37eb16dc3935f96878b1fe961074089cc80893f9" +checksum = "4f38200e3ef7995e5ef13baec2f432a6da0aa9ac495b2c0e8f3b7eec2c92d653" dependencies = [ "backtrace", "bytes", @@ -2970,7 +3114,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] @@ -3032,7 +3176,7 @@ version = "0.19.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a" dependencies = [ - "indexmap 2.0.1", + "indexmap 2.0.2", "toml_datetime", "winnow", ] @@ -3091,11 +3235,10 @@ checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.37" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -3104,20 +3247,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", ] [[package]] name = "tracing-core" -version = "0.1.31" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ "once_cell", ] @@ -3212,12 +3355,6 @@ version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" -[[package]] -name = "unidecode" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402bb19d8e03f1d1a7450e2bd613980869438e0666331be3e073089124aa1adc" - [[package]] name = "url" version = "2.4.0" @@ -3255,9 +3392,9 @@ checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" [[package]] name = "uuid" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +checksum = "88ad59a7560b41a70d191093a945f0b87bc1deeda46fb237479708a1d6b6cdfc" dependencies = [ "serde", ] @@ -3341,7 +3478,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-shared", ] @@ -3375,7 +3512,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.38", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -3694,11 +3831,11 @@ dependencies = [ "base64ct", "bincode", "console_error_panic_hook", - "futures 0.3.28", + "futures 0.3.29", "gloo 0.10.0", "html-escape", "implicit-clone", - "indexmap 2.0.1", + "indexmap 2.0.2", "js-sys", "prokio", "rustversion", @@ -3719,8 +3856,8 @@ dependencies = [ name = "yew-agent" version = "0.3.0" dependencies = [ - "futures 0.3.28", - "gloo-worker 0.4.0", + "futures 0.3.29", + "gloo-worker 0.4.1", "serde", "wasm-bindgen", "yew", @@ -3734,7 +3871,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.38", "trybuild", "yew-agent", ] @@ -3749,7 +3886,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.38", "trybuild", "yew", ] @@ -3779,7 +3916,7 @@ dependencies = [ "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.38", "trybuild", "yew-router", ] @@ -3801,7 +3938,7 @@ dependencies = [ name = "yew-worker-prime" version = "0.1.0" dependencies = [ - "futures 0.3.28", + "futures 0.3.29", "primes", "serde", "yew", diff --git a/examples/README.md b/examples/README.md index 1b5a01fa937..e196494df3e 100644 --- a/examples/README.md +++ b/examples/README.md @@ -3,7 +3,7 @@ ## How to Run The examples are built with [trunk](https://github.com/thedodd/trunk). -Once you have the development envrionment fully set up (see [documentation](https://yew.rs/docs/next/getting-started/introduction)), +Once you have the development environment fully set up (see [documentation](https://yew.rs/docs/next/getting-started/introduction)), running an example is as easy as running a single command: ```bash diff --git a/examples/file_upload/Cargo.toml b/examples/file_upload/Cargo.toml index 20adf651a4f..3c4d3817a5e 100644 --- a/examples/file_upload/Cargo.toml +++ b/examples/file_upload/Cargo.toml @@ -8,7 +8,7 @@ license = "MIT OR Apache-2.0" [dependencies] js-sys = "0.3" yew = { path = "../../packages/yew", features = ["csr"] } -base64 = "0.21.4" +base64 = "0.21.5" gloo = "0.10" [dependencies.web-sys] diff --git a/examples/function_todomvc/src/state.rs b/examples/function_todomvc/src/state.rs index 1a461b59e08..77a9a4ee500 100644 --- a/examples/function_todomvc/src/state.rs +++ b/examples/function_todomvc/src/state.rs @@ -2,6 +2,7 @@ use std::rc::Rc; use serde::{Deserialize, Serialize}; use strum_macros::{Display, EnumIter}; +use yew::html::IntoPropValue; use yew::prelude::*; #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)] @@ -42,8 +43,8 @@ impl Filter { } } -impl ToHtml for Filter { - fn to_html(&self) -> Html { +impl IntoPropValue for Filter { + fn into_prop_value(self) -> Html { html! {<>{self.to_string()}} } } diff --git a/examples/futures/src/markdown.rs b/examples/futures/src/markdown.rs index 5c85b7a55e4..afdad6bf98f 100644 --- a/examples/futures/src/markdown.rs +++ b/examples/futures/src/markdown.rs @@ -1,5 +1,7 @@ /// Original author of this code is [Nathan Ringo](https://github.com/remexre) /// Source: https://github.com/acmumn/mentoring/blob/master/web-client/src/view/markdown.rs +use std::rc::Rc; + use pulldown_cmark::{Alignment, CodeBlockKind, Event, Options, Parser, Tag}; use yew::virtual_dom::{VNode, VTag, VText}; use yew::{html, Classes, Html}; @@ -56,16 +58,22 @@ pub fn render_markdown(src: &str) -> Html { if let Some(top_children) = top.children_mut() { for r in top_children.to_vlist_mut().iter_mut() { if let VNode::VTag(ref mut vtag) = r { - if let Some(vtag_children) = vtag.children_mut() { + if let Some(vtag_children) = Rc::make_mut(vtag).children_mut() { for (i, c) in vtag_children.to_vlist_mut().iter_mut().enumerate() { if let VNode::VTag(ref mut vtag) = c { match aligns[i] { Alignment::None => {} - Alignment::Left => add_class(vtag, "text-left"), - Alignment::Center => add_class(vtag, "text-center"), - Alignment::Right => add_class(vtag, "text-right"), + Alignment::Left => { + add_class(Rc::make_mut(vtag), "text-left") + } + Alignment::Center => { + add_class(Rc::make_mut(vtag), "text-center") + } + Alignment::Right => { + add_class(Rc::make_mut(vtag), "text-right") + } } } } @@ -79,7 +87,7 @@ pub fn render_markdown(src: &str) -> Html { if let VNode::VTag(ref mut vtag) = c { // TODO // vtag.tag = "th".into(); - vtag.add_attribute("scope", "col"); + Rc::make_mut(vtag).add_attribute("scope", "col"); } } } @@ -99,7 +107,7 @@ pub fn render_markdown(src: &str) -> Html { } if elems.len() == 1 { - VNode::VTag(Box::new(elems.pop().unwrap())) + VNode::VTag(Rc::new(elems.pop().unwrap())) } else { html! {
{ for elems.into_iter() }
diff --git a/examples/keyed_list/Cargo.toml b/examples/keyed_list/Cargo.toml index 3273faed3c4..3b1b9eeb4c6 100644 --- a/examples/keyed_list/Cargo.toml +++ b/examples/keyed_list/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" license = "MIT OR Apache-2.0" [dependencies] -fake = "2.8.0" +fake = "2.9.1" getrandom = { version = "0.2", features = ["js"] } instant = { version = "0.1", features = ["wasm-bindgen"] } log = "0.4" diff --git a/examples/nested_list/src/item.rs b/examples/nested_list/src/item.rs index d93cc7a7670..1ae69579775 100644 --- a/examples/nested_list/src/item.rs +++ b/examples/nested_list/src/item.rs @@ -7,7 +7,7 @@ pub struct Props { #[prop_or_default] pub hide: bool, pub on_hover: Callback, - pub name: String, + pub name: AttrValue, #[prop_or_default] pub children: Children, } diff --git a/examples/nested_list/src/list.rs b/examples/nested_list/src/list.rs index 46570610a96..042227750df 100644 --- a/examples/nested_list/src/list.rs +++ b/examples/nested_list/src/list.rs @@ -73,9 +73,8 @@ impl List { .filter(|c| !c.props.hide) .enumerate() .map(|(i, mut c)| { - let mut props = (*c.props).clone(); - props.name = format!("#{} - {}", i + 1, props.name); - c.props = Rc::new(props); + let props = Rc::make_mut(&mut c.props); + props.name = format!("#{} - {}", i + 1, props.name).into(); c }) .collect::() diff --git a/examples/nested_list/src/main.rs b/examples/nested_list/src/main.rs index 3f8a93def78..480b680a3b7 100644 --- a/examples/nested_list/src/main.rs +++ b/examples/nested_list/src/main.rs @@ -8,7 +8,7 @@ use std::fmt; use std::ops::Deref; use std::rc::Rc; -use yew::html::{ImplicitClone, Scope}; +use yew::html::{ImplicitClone, IntoPropValue, Scope}; use yew::prelude::*; pub struct WeakComponentLink(Rc>>>); @@ -40,14 +40,16 @@ impl PartialEq for WeakComponentLink { } } -#[derive(Debug)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub enum Hovered { Header, - Item(String), + Item(AttrValue), List, None, } +impl ImplicitClone for Hovered {} + impl fmt::Display for Hovered { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( @@ -63,8 +65,8 @@ impl fmt::Display for Hovered { } } -impl ToHtml for Hovered { - fn to_html(&self) -> yew::Html { +impl IntoPropValue for &Hovered { + fn into_prop_value(self) -> Html { html! {<>{self.to_string()}} } } diff --git a/examples/password_strength/Cargo.toml b/examples/password_strength/Cargo.toml index 799ce8b2a60..a61491eec51 100644 --- a/examples/password_strength/Cargo.toml +++ b/examples/password_strength/Cargo.toml @@ -8,7 +8,7 @@ edition = "2021" [dependencies] yew = { path = "../../packages/yew", features = ["csr"] } zxcvbn = "2.2.2" -time = "0.3.29" +time = "0.3.30" js-sys = "0.3.64" web-sys = { version = "0.3", features = ["Event","EventTarget","InputEvent"] } wasm-bindgen = "0.2" diff --git a/examples/simple_ssr/Cargo.toml b/examples/simple_ssr/Cargo.toml index 0aaed6f6bc2..cb602eb4e70 100644 --- a/examples/simple_ssr/Cargo.toml +++ b/examples/simple_ssr/Cargo.toml @@ -14,9 +14,9 @@ required-features = ["ssr"] [dependencies] yew = { path = "../../packages/yew" } -reqwest = { version = "0.11.20", features = ["json"] } -serde = { version = "1.0.188", features = ["derive"] } -uuid = { version = "1.4.1", features = ["serde"] } +reqwest = { version = "0.11.22", features = ["json"] } +serde = { version = "1.0.190", features = ["derive"] } +uuid = { version = "1.5.0", features = ["serde"] } futures = "0.3" bytes = "1.5" @@ -26,7 +26,7 @@ wasm-logger = "0.2" log = "0.4" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio = { version = "1.32.0", features = ["full"] } +tokio = { version = "1.33.0", features = ["full"] } warp = "0.3" clap = { version = "4", features = ["derive"] } diff --git a/examples/ssr_router/Cargo.toml b/examples/ssr_router/Cargo.toml index 86f598cbf86..84a23c63653 100644 --- a/examples/ssr_router/Cargo.toml +++ b/examples/ssr_router/Cargo.toml @@ -24,13 +24,15 @@ wasm-bindgen-futures = "0.4" wasm-logger = "0.2" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] -tokio = { version = "1.32.0", features = ["full"] } +tokio = { version = "1.33.0", features = ["full"] } axum = "0.6" tower = { version = "0.4", features = ["make"] } tower-http = { version = "0.3", features = ["fs"] } env_logger = "0.10" clap = { version = "4", features = ["derive"] } hyper = { version = "0.14", features = ["server", "http1"] } + +[target.'cfg(unix)'.dependencies] jemallocator = "0.5" [features] diff --git a/examples/ssr_router/src/bin/ssr_router_server.rs b/examples/ssr_router/src/bin/ssr_router_server.rs index 2aa83880da4..9ecd2c57c99 100644 --- a/examples/ssr_router/src/bin/ssr_router_server.rs +++ b/examples/ssr_router/src/bin/ssr_router_server.rs @@ -20,6 +20,7 @@ use tower_http::services::ServeDir; use yew::platform::Runtime; // We use jemalloc as it produces better performance. +#[cfg(unix)] #[global_allocator] static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc; diff --git a/examples/timer/src/main.rs b/examples/timer/src/main.rs index 073c38d0ca3..241f86a9805 100644 --- a/examples/timer/src/main.rs +++ b/examples/timer/src/main.rs @@ -139,7 +139,7 @@ impl Component for App { { &self.time }
- { for self.messages.iter().map(|message| html! {

{ message }

}) } + { for self.messages.iter().map(|message| html! {

{ *message }

}) }
diff --git a/examples/timer_functional/src/main.rs b/examples/timer_functional/src/main.rs index 30da755dd0b..5a717cb5476 100644 --- a/examples/timer_functional/src/main.rs +++ b/examples/timer_functional/src/main.rs @@ -105,7 +105,7 @@ fn App() -> Html { .iter() .map(|message| { key += 1; - html! {

{ message }

} + html! {

{ *message }

} }) .collect(); diff --git a/examples/todomvc/src/state.rs b/examples/todomvc/src/state.rs index 251c4925e62..941ef4d963e 100644 --- a/examples/todomvc/src/state.rs +++ b/examples/todomvc/src/state.rs @@ -1,5 +1,6 @@ use serde_derive::{Deserialize, Serialize}; use strum_macros::{Display, EnumIter}; +use yew::html::IntoPropValue; use yew::prelude::*; #[derive(Debug, Serialize, Deserialize)] @@ -142,8 +143,8 @@ impl Filter { } } -impl ToHtml for Filter { - fn to_html(&self) -> yew::Html { +impl IntoPropValue for Filter { + fn into_prop_value(self) -> yew::Html { html! { <>{self.to_string()} } } } diff --git a/examples/web_worker_prime/Cargo.toml b/examples/web_worker_prime/Cargo.toml index 89076dfa7ff..f33cdccf54e 100644 --- a/examples/web_worker_prime/Cargo.toml +++ b/examples/web_worker_prime/Cargo.toml @@ -6,6 +6,6 @@ edition = "2021" [dependencies] yew-agent = { path = "../../packages/yew-agent" } yew = { path = "../../packages/yew", features = ["csr"] } -futures = "0.3.25" +futures = "0.3.29" primes = "0.3.0" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.190", features = ["derive"] } diff --git a/packages/yew-agent/Cargo.toml b/packages/yew-agent/Cargo.toml index 72891d4c590..2007b54f86f 100644 --- a/packages/yew-agent/Cargo.toml +++ b/packages/yew-agent/Cargo.toml @@ -20,4 +20,4 @@ futures = "0.3" yew-agent-macro = { version = "0.2", path = "../yew-agent-macro" } [dev-dependencies] -serde = "1.0.188" +serde = "1.0.190" diff --git a/packages/yew-agent/src/scope_ext.rs b/packages/yew-agent/src/scope_ext.rs index 6120062f9c6..eb36dc344b3 100644 --- a/packages/yew-agent/src/scope_ext.rs +++ b/packages/yew-agent/src/scope_ext.rs @@ -99,7 +99,7 @@ where W: Worker + 'static, { let inner = self - .context::>((|_| {}).into()) + .context::>>((|_| {}).into()) .expect_throw("failed to bridge to agent.") .0 .create_bridge(callback); diff --git a/packages/yew-agent/src/worker/hooks.rs b/packages/yew-agent/src/worker/hooks.rs index 19745e64dfd..fbe7d30906d 100644 --- a/packages/yew-agent/src/worker/hooks.rs +++ b/packages/yew-agent/src/worker/hooks.rs @@ -15,7 +15,7 @@ pub struct UseWorkerBridgeHandle where T: Worker, { - inner: WorkerBridge, + inner: Rc>, ctr: UseReducerDispatcher, } @@ -84,7 +84,7 @@ where { let ctr = use_reducer(BridgeIdState::default); - let worker_state = use_context::>() + let worker_state = use_context::>>() .expect_throw("cannot find a provider for current agent."); let on_output = Rc::new(on_output); @@ -106,7 +106,7 @@ where }); UseWorkerBridgeHandle { - inner: (*bridge).clone(), + inner: bridge, ctr: ctr.dispatcher(), } } diff --git a/packages/yew-agent/src/worker/provider.rs b/packages/yew-agent/src/worker/provider.rs index b452729d027..229acc248ea 100644 --- a/packages/yew-agent/src/worker/provider.rs +++ b/packages/yew-agent/src/worker/provider.rs @@ -46,7 +46,7 @@ where id: usize, spawn_bridge_fn: Rc WorkerBridge>, reach: Reach, - held_bridge: Rc>>>, + held_bridge: RefCell>>>, } impl fmt::Debug for WorkerProviderState @@ -63,13 +63,13 @@ where W: Worker, W::Output: 'static, { - fn get_held_bridge(&self) -> WorkerBridge { + fn get_held_bridge(&self) -> Rc> { let mut held_bridge = self.held_bridge.borrow_mut(); match held_bridge.as_mut() { Some(m) => m.clone(), None => { - let bridge = (self.spawn_bridge_fn)(); + let bridge = Rc::new((self.spawn_bridge_fn)()); *held_bridge = Some(bridge.clone()); bridge } @@ -88,20 +88,6 @@ where } } -impl Clone for WorkerProviderState -where - W: Worker, -{ - fn clone(&self) -> Self { - Self { - id: self.id, - spawn_bridge_fn: self.spawn_bridge_fn.clone(), - reach: self.reach, - held_bridge: self.held_bridge.clone(), - } - } -} - impl PartialEq for WorkerProviderState where W: Worker, @@ -141,7 +127,7 @@ where id: get_next_id(), spawn_bridge_fn, reach: *reach, - held_bridge: Rc::default(), + held_bridge: Default::default(), }; if *reach == Reach::Public && !*lazy { @@ -152,8 +138,8 @@ where }; html! { - > context={(*state).clone()}> + >> context={state.clone()}> {children} - >> + >>> } } diff --git a/packages/yew-macro/src/html_tree/html_element.rs b/packages/yew-macro/src/html_tree/html_element.rs index 0124dd0c0d7..ee588305de6 100644 --- a/packages/yew-macro/src/html_tree/html_element.rs +++ b/packages/yew-macro/src/html_tree/html_element.rs @@ -1,13 +1,13 @@ -use proc_macro2::{Delimiter, Span, TokenStream}; +use proc_macro2::{Delimiter, Group, Span, TokenStream}; use proc_macro_error::emit_warning; use quote::{quote, quote_spanned, ToTokens}; use syn::buffer::Cursor; use syn::parse::{Parse, ParseStream}; use syn::spanned::Spanned; -use syn::{Block, Expr, Ident, Lit, LitStr, Token}; +use syn::{Expr, Ident, Lit, LitStr, Token}; use super::{HtmlChildrenTree, HtmlDashedName, TagTokens}; -use crate::props::{ClassesForm, ElementProps, Prop, PropDirective}; +use crate::props::{ElementProps, Prop, PropDirective}; use crate::stringify::{Stringify, Value}; use crate::{is_ide_completion, non_capitalized_ascii, Peek, PeekValue}; @@ -190,39 +190,11 @@ impl ToTokens for HtmlElement { )) }, ); - let class_attr = classes.as_ref().and_then(|classes| match classes { - ClassesForm::Tuple(classes) => { - let span = classes.span(); - let classes: Vec<_> = classes.elems.iter().collect(); - let n = classes.len(); - - let deprecation_warning = quote_spanned! {span=> - #[deprecated( - note = "the use of `(...)` with the attribute `class` is deprecated and will be removed in version 0.19. Use the `classes!` macro instead." - )] - fn deprecated_use_of_class() {} - - if false { - deprecated_use_of_class(); - }; - }; - Some(( - LitStr::new("class", span), - Value::Dynamic(quote! { - { - #deprecation_warning - - let mut __yew_classes = ::yew::html::Classes::with_capacity(#n); - #(__yew_classes.push(#classes);)* - __yew_classes - } - }), - None, - )) - } - ClassesForm::Single(classes) => { - match classes.try_into_lit() { + let class_attr = + classes + .as_ref() + .and_then(|classes| match classes.value.try_into_lit() { Some(lit) => { if lit.value().is_empty() { None @@ -235,39 +207,46 @@ impl ToTokens for HtmlElement { } } None => { + let expr = &classes.value; Some(( - LitStr::new("class", classes.span()), + LitStr::new("class", classes.label.span()), Value::Dynamic(quote! { - ::std::convert::Into::<::yew::html::Classes>::into(#classes) + ::std::convert::Into::<::yew::html::Classes>::into(#expr) }), None, )) } - } - } - }); - - fn apply_as(directive: Option<&PropDirective>) -> TokenStream { - match directive { - Some(PropDirective::ApplyAsProperty(token)) => { - quote_spanned!(token.span()=> ::yew::virtual_dom::ApplyAttributeAs::Property) - } - None => quote!(::yew::virtual_dom::ApplyAttributeAs::Attribute), - } - } + }); /// Try to turn attribute list into a `::yew::virtual_dom::Attributes::Static` fn try_into_static( src: &[(LitStr, Value, Option)], ) -> Option { + if src + .iter() + .any(|(_, _, d)| matches!(d, Some(PropDirective::ApplyAsProperty(_)))) + { + // don't try to make a static attribute list if there are any properties to + // assign + return None; + } let mut kv = Vec::with_capacity(src.len()); for (k, v, directive) in src.iter() { let v = match v { Value::Static(v) => quote! { #v }, Value::Dynamic(_) => return None, }; - let apply_as = apply_as(directive.as_ref()); - kv.push(quote! { ( #k, #v, #apply_as ) }); + let v = match directive { + Some(PropDirective::ApplyAsProperty(token)) => { + quote_spanned!(token.span()=> ::yew::virtual_dom::AttributeOrProperty::Property( + ::std::convert::Into::into(#v) + )) + } + None => quote!(::yew::virtual_dom::AttributeOrProperty::Static( + #v + )), + }; + kv.push(quote! { ( #k, #v) }); } Some(quote! { ::yew::virtual_dom::Attributes::Static(&[#(#kv),*]) }) @@ -280,9 +259,22 @@ impl ToTokens for HtmlElement { try_into_static(&attrs).unwrap_or_else(|| { let keys = attrs.iter().map(|(k, ..)| quote! { #k }); let values = attrs.iter().map(|(_, v, directive)| { - let apply_as = apply_as(directive.as_ref()); - let value = wrap_attr_value(v); - quote! { ::std::option::Option::map(#value, |it| (it, #apply_as)) } + let value = match directive { + Some(PropDirective::ApplyAsProperty(token)) => { + quote_spanned!(token.span()=> ::std::option::Option::Some( + ::yew::virtual_dom::AttributeOrProperty::Property( + ::std::convert::Into::into(#v) + )) + ) + } + None => { + let value = wrap_attr_value(v); + quote! { + ::std::option::Option::map(#value, ::yew::virtual_dom::AttributeOrProperty::Attribute) + } + }, + }; + quote! { #value } }); quote! { ::yew::virtual_dom::Attributes::Dynamic{ @@ -359,7 +351,7 @@ impl ToTokens for HtmlElement { quote! { ::std::convert::Into::<::yew::virtual_dom::VNode>::into( ::yew::virtual_dom::VTag::__new_other( - ::std::borrow::Cow::<'static, ::std::primitive::str>::Borrowed(#name), + ::yew::virtual_dom::AttrValue::Static(#name), #node_ref, #key, #attributes, @@ -383,7 +375,7 @@ impl ToTokens for HtmlElement { } TagName::Expr(name) => { let vtag = Ident::new("__yew_vtag", name.span()); - let expr = &name.expr; + let expr = name.expr.as_ref().map(Group::stream); let vtag_name = Ident::new("__yew_vtag_name", expr.span()); let void_children = Ident::new("__yew_void_children", Span::mixed_site()); @@ -411,12 +403,8 @@ impl ToTokens for HtmlElement { // this way we get a nice error message (with the correct span) when the expression // doesn't return a valid value quote_spanned! {expr.span()=> { - #[allow(unused_braces)] - // e.g. html!{<@{"div"}/>} will set `#expr` to `{"div"}` - // (note the extra braces). Hence the need for the `allow`. - // Anyways to remove the braces? let mut #vtag_name = ::std::convert::Into::< - ::std::borrow::Cow::<'static, ::std::primitive::str> + ::yew::virtual_dom::AttrValue >::into(#expr); ::std::debug_assert!( #vtag_name.is_ascii(), @@ -500,7 +488,7 @@ fn wrap_attr_value(value: T) -> TokenStream { pub struct DynamicName { at: Token![@], - expr: Option, + expr: Option, } impl Peek<'_, ()> for DynamicName { @@ -524,12 +512,7 @@ impl Parse for DynamicName { fn parse(input: ParseStream) -> syn::Result { let at = input.parse()?; // the expression block is optional, closing tags don't have it. - let expr = if input.cursor().group(Delimiter::Brace).is_some() { - Some(input.parse()?) - } else { - None - }; - + let expr = input.parse().ok(); Ok(Self { at, expr }) } } diff --git a/packages/yew-macro/src/html_tree/html_list.rs b/packages/yew-macro/src/html_tree/html_list.rs index e48f250bfde..301b533a92c 100644 --- a/packages/yew-macro/src/html_tree/html_list.rs +++ b/packages/yew-macro/src/html_tree/html_list.rs @@ -78,9 +78,9 @@ impl ToTokens for HtmlList { }; tokens.extend(quote_spanned! {spanned.span()=> - ::yew::virtual_dom::VNode::VList( + ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( ::yew::virtual_dom::VList::with_children(#children, #key) - ) + )) }); } } diff --git a/packages/yew-macro/src/html_tree/mod.rs b/packages/yew-macro/src/html_tree/mod.rs index 0361231b6d4..266ea31bfd8 100644 --- a/packages/yew-macro/src/html_tree/mod.rs +++ b/packages/yew-macro/src/html_tree/mod.rs @@ -123,7 +123,7 @@ impl ToTokens for HtmlTree { lint::lint_all(self); match self { HtmlTree::Empty => tokens.extend(quote! { - ::yew::virtual_dom::VNode::VList(::yew::virtual_dom::VList::new()) + <::yew::virtual_dom::VNode as ::std::default::Default>::default() }), HtmlTree::Component(comp) => comp.to_tokens(tokens), HtmlTree::Element(tag) => tag.to_tokens(tokens), @@ -375,9 +375,9 @@ impl ToTokens for HtmlRootBraced { tokens.extend(quote_spanned! {brace.span.span()=> { - ::yew::virtual_dom::VNode::VList( + ::yew::virtual_dom::VNode::VList(::std::rc::Rc::new( ::yew::virtual_dom::VList::with_children(#children, ::std::option::Option::None) - ) + )) } }); } diff --git a/packages/yew-macro/src/props/element.rs b/packages/yew-macro/src/props/element.rs index cd50b71b692..17a90e3f9db 100644 --- a/packages/yew-macro/src/props/element.rs +++ b/packages/yew-macro/src/props/element.rs @@ -2,27 +2,13 @@ use std::collections::HashSet; use once_cell::sync::Lazy; use syn::parse::{Parse, ParseStream}; -use syn::{Expr, ExprTuple}; use super::{Prop, Props, SpecialProps}; -pub enum ClassesForm { - Tuple(ExprTuple), - Single(Box), -} -impl ClassesForm { - fn from_expr(expr: Expr) -> Self { - match expr { - Expr::Tuple(expr_tuple) => ClassesForm::Tuple(expr_tuple), - expr => ClassesForm::Single(Box::new(expr)), - } - } -} - pub struct ElementProps { pub attributes: Vec, pub listeners: Vec, - pub classes: Option, + pub classes: Option, pub booleans: Vec, pub value: Option, pub checked: Option, @@ -42,9 +28,7 @@ impl Parse for ElementProps { let booleans = props.drain_filter(|prop| BOOLEAN_SET.contains(prop.label.to_string().as_str())); - let classes = props - .pop("class") - .map(|prop| ClassesForm::from_expr(prop.value)); + let classes = props.pop("class"); let value = props.pop("value"); let checked = props.pop("checked"); let special = props.special; diff --git a/packages/yew-macro/tests/html_macro/block-pass.rs b/packages/yew-macro/tests/html_macro/block-pass.rs index d8f527e6e46..6a5bd15c632 100644 --- a/packages/yew-macro/tests/html_macro/block-pass.rs +++ b/packages/yew-macro/tests/html_macro/block-pass.rs @@ -37,27 +37,27 @@ pub struct u8; pub struct usize; fn main() { - ::yew::html! { <>{ "Hi" } }; - ::yew::html! { <>{ ::std::format!("Hello") } }; - ::yew::html! { <>{ ::std::string::ToString::to_string("Hello") } }; + _ = ::yew::html! { <>{ "Hi" } }; + _ = ::yew::html! { <>{ ::std::format!("Hello") } }; + _ = ::yew::html! { <>{ ::std::string::ToString::to_string("Hello") } }; let msg = "Hello"; - ::yew::html! {
{ msg }
}; + _ = ::yew::html! {
{ msg }
}; let subview = ::yew::html! { "subview!" }; - ::yew::html! {
{ subview }
}; + _ = ::yew::html! {
{ subview }
}; let subview = || ::yew::html! { "subview!" }; - ::yew::html! {
{ subview() }
}; + _ = ::yew::html! {
{ subview() }
}; - ::yew::html! { + _ = ::yew::html! {
    { for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { { num } }}) }
}; let item = |num| ::yew::html! {
  • { ::std::format!("item {}!", num) }
  • }; - ::yew::html! { + _ = ::yew::html! {
      { for ::std::iter::Iterator::map(0..3, item) }
    diff --git a/packages/yew-macro/tests/html_macro/component-any-children-pass.rs b/packages/yew-macro/tests/html_macro/component-any-children-pass.rs index cf5a924e506..d7b1ab3cb8e 100644 --- a/packages/yew-macro/tests/html_macro/component-any-children-pass.rs +++ b/packages/yew-macro/tests/html_macro/component-any-children-pass.rs @@ -83,12 +83,12 @@ impl ::std::convert::From<::yew::virtual_dom::VChild> for ChildrenVari 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::< + Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), - Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + >::into(comp))), + Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), + >::into(comp))), } } } @@ -159,10 +159,10 @@ pub fn RenderPropComp(_props: &RenderPropProps) -> ::yew::Html { } fn compile_pass() { - ::yew::html! { }; - ::yew::html! { }; + _ = ::yew::html! { }; + _ = ::yew::html! { }; - ::yew::html! { + _ = ::yew::html! { <> @@ -171,7 +171,7 @@ fn compile_pass() { let props = <::Properties as ::std::default::Default>::default(); let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -183,7 +183,7 @@ fn compile_pass() { }; - ::yew::html! { + _ = ::yew::html! { <> @@ -199,17 +199,17 @@ fn compile_pass() { }; let name_expr = "child"; - ::yew::html! { + _ = ::yew::html! { }; let string = "child"; let int = 1; - ::yew::html! { + _ = ::yew::html! { }; - ::yew::html! { + _ = ::yew::html! { <> as ::std::convert::From<_>>::from(|_| ()))} /> @@ -219,7 +219,7 @@ fn compile_pass() { }; let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -227,7 +227,7 @@ fn compile_pass() { let int = 1; let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -236,7 +236,7 @@ fn compile_pass() { let props = <::Properties as ::std::default::Default>::default(); let child_props = <::Properties as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -292,7 +292,7 @@ fn compile_pass() { ] }; - ::yew::html! { + _ = ::yew::html! { <> { ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>( @@ -321,9 +321,9 @@ fn compile_pass() { }; - ::yew::html_nested! { 1 }; + _ = ::yew::html_nested! { 1 }; - ::yew::html! { + _ = ::yew::html! { {|_arg| {}} diff --git a/packages/yew-macro/tests/html_macro/component-fail.stderr b/packages/yew-macro/tests/html_macro/component-fail.stderr index 6280ac8d37b..440ffed4c64 100644 --- a/packages/yew-macro/tests/html_macro/component-fail.stderr +++ b/packages/yew-macro/tests/html_macro/component-fail.stderr @@ -463,16 +463,7 @@ error[E0277]: the trait bound `(): IntoPropValue` is not satisfied | | | required by a bound introduced by this call | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` note: required by a bound in `ChildPropertiesBuilder::string` --> tests/html_macro/component-fail.rs:4:17 | @@ -706,7 +697,9 @@ error[E0277]: the trait bound `yew::virtual_dom::VText: IntoPropValue{ "Not allowed" } }; | ^^^^^^^^^^^^^^ the trait `IntoPropValue>>` is not implemented for `yew::virtual_dom::VText` | - = help: the trait `IntoPropValue>` is implemented for `yew::virtual_dom::VText` + = help: the following other types implement trait `IntoPropValue`: + >> + > note: required by a bound in `ChildContainerPropertiesBuilder::children` --> tests/html_macro/component-fail.rs:24:17 | diff --git a/packages/yew-macro/tests/html_macro/component-pass.rs b/packages/yew-macro/tests/html_macro/component-pass.rs index 61f0de060f8..5cc59c4208d 100644 --- a/packages/yew-macro/tests/html_macro/component-pass.rs +++ b/packages/yew-macro/tests/html_macro/component-pass.rs @@ -82,12 +82,12 @@ impl ::std::convert::From<::yew::virtual_dom::VChild> for ChildrenVari 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::< + Self::Child(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), - Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::convert::Into::< + >::into(comp))), + Self::AltChild(comp) => ::yew::virtual_dom::VNode::VComp(::std::rc::Rc::new(::std::convert::Into::< ::yew::virtual_dom::VComp, - >::into(comp)), + >::into(comp))), } } } @@ -167,10 +167,10 @@ mod scoped { } fn compile_pass() { - ::yew::html! { }; - ::yew::html! { }; + _ = ::yew::html! { }; + _ = ::yew::html! { }; - ::yew::html! { + _ = ::yew::html! { <> @@ -179,7 +179,7 @@ fn compile_pass() { let props = <::Properties as ::std::default::Default>::default(); let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -191,7 +191,7 @@ fn compile_pass() { }; - ::yew::html! { + _ = ::yew::html! { <> @@ -207,17 +207,17 @@ fn compile_pass() { }; let name_expr = "child"; - ::yew::html! { + _ = ::yew::html! { }; let string = "child"; let int = 1; - ::yew::html! { + _ = ::yew::html! { }; - ::yew::html! { + _ = ::yew::html! { <> as ::std::convert::From<_>>::from(|_| ()))} /> @@ -227,7 +227,7 @@ fn compile_pass() { }; let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -235,7 +235,7 @@ fn compile_pass() { let int = 1; let node_ref = <::yew::NodeRef as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -244,7 +244,7 @@ fn compile_pass() { let props = <::Properties as ::std::default::Default>::default(); let child_props = <::Properties as ::std::default::Default>::default(); - ::yew::html! { + _ = ::yew::html! { <> @@ -287,7 +287,7 @@ fn compile_pass() { }; - ::yew::html! { + _ = ::yew::html! { <> @@ -296,7 +296,7 @@ fn compile_pass() { }; - ::yew::html! { + _ = ::yew::html! { @@ -318,13 +318,13 @@ fn compile_pass() { ::yew::html_nested! { }, ::yew::html_nested! { }, ]; - ::yew::html! { + _ = ::yew::html! { { ::std::clone::Clone::clone(&children) } }; // https://github.com/yewstack/yew/issues/1527 - ::yew::html! { + _ = ::yew::html! { { for children } @@ -343,7 +343,7 @@ fn compile_pass() { ] }; - ::yew::html! { + _ = ::yew::html! { <> { ::std::iter::Iterator::collect::<::yew::virtual_dom::VNode>( @@ -372,7 +372,7 @@ fn compile_pass() { }; - ::yew::html_nested! { 1 }; + _ = ::yew::html_nested! { 1 }; } #[derive( diff --git a/packages/yew-macro/tests/html_macro/dyn-element-pass.rs b/packages/yew-macro/tests/html_macro/dyn-element-pass.rs index 27dd094c0f9..0ab298fe342 100644 --- a/packages/yew-macro/tests/html_macro/dyn-element-pass.rs +++ b/packages/yew-macro/tests/html_macro/dyn-element-pass.rs @@ -43,17 +43,16 @@ fn main() { move || ::std::option::Option::unwrap(::std::iter::Iterator::next(&mut it)) }; - ::yew::html! { + _ = ::yew::html! { <@{ dyn_tag() }> <@{ next_extra_tag() } class="extra-a"/> <@{ next_extra_tag() } class="extra-b"/> }; - ::yew::html! { + _ = ::yew::html! { <@{ - let tag = dyn_tag(); - if tag == "test" { + if dyn_tag() == "test" { "div" } else { "a" diff --git a/packages/yew-macro/tests/html_macro/element-fail.rs b/packages/yew-macro/tests/html_macro/element-fail.rs index ac8f217e0f1..52f494fc67f 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.rs +++ b/packages/yew-macro/tests/html_macro/element-fail.rs @@ -76,11 +76,7 @@ fn compile_fail() { // type mismatch html! { <@{55}> }; - // check for deprecation warning - html! {
    }; - // Missing curly braces - html! {
    }; html! { }; html! { }; html! { }; diff --git a/packages/yew-macro/tests/html_macro/element-fail.stderr b/packages/yew-macro/tests/html_macro/element-fail.stderr index d05a7cfad41..11f9e7d631a 100644 --- a/packages/yew-macro/tests/html_macro/element-fail.stderr +++ b/packages/yew-macro/tests/html_macro/element-fail.stderr @@ -142,38 +142,14 @@ error: dynamic closing tags must not have a body (hint: replace it with just ` }; | ^^^^^^^^ -error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple { - attrs: [], - paren_token: Paren, - elems: [ - Expr::Lit { - attrs: [], - lit: Lit::Str { - token: "deprecated", - }, - }, - Comma, - Expr::Lit { - attrs: [], - lit: Lit::Str { - token: "warning", - }, - }, - ], - } - --> tests/html_macro/element-fail.rs:83:24 - | -83 | html! {
    }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple { attrs: [], paren_token: Paren, elems: [], } - --> tests/html_macro/element-fail.rs:84:24 + --> tests/html_macro/element-fail.rs:80:24 | -84 | html! { }; +80 | html! { }; | ^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple { @@ -181,9 +157,9 @@ error: the property value must be either a literal or enclosed in braces. Consid paren_token: Paren, elems: [], } - --> tests/html_macro/element-fail.rs:85:24 + --> tests/html_macro/element-fail.rs:81:24 | -85 | html! { }; +81 | html! { }; | ^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call { @@ -197,7 +173,7 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "Some", - span: #0 bytes(2632..2636), + span: #0 bytes(2482..2486), }, arguments: PathArguments::None, }, @@ -214,9 +190,9 @@ error: the property value must be either a literal or enclosed in braces. Consid }, ], } - --> tests/html_macro/element-fail.rs:86:28 + --> tests/html_macro/element-fail.rs:82:28 | -86 | html! { }; +82 | html! { }; | ^^^^^^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Path { @@ -228,16 +204,16 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "NotToString", - span: #0 bytes(2672..2683), + span: #0 bytes(2522..2533), }, arguments: PathArguments::None, }, ], }, } - --> tests/html_macro/element-fail.rs:87:27 + --> tests/html_macro/element-fail.rs:83:27 | -87 | html! { }; +83 | html! { }; | ^^^^^^^^^^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call { @@ -251,7 +227,7 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "Some", - span: #0 bytes(2711..2715), + span: #0 bytes(2561..2565), }, arguments: PathArguments::None, }, @@ -269,7 +245,7 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "NotToString", - span: #0 bytes(2716..2727), + span: #0 bytes(2566..2577), }, arguments: PathArguments::None, }, @@ -278,9 +254,9 @@ error: the property value must be either a literal or enclosed in braces. Consid }, ], } - --> tests/html_macro/element-fail.rs:88:22 + --> tests/html_macro/element-fail.rs:84:22 | -88 | html! { }; +84 | html! { }; | ^^^^^^^^^^^^^^^^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Call { @@ -294,7 +270,7 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "Some", - span: #0 bytes(2755..2759), + span: #0 bytes(2605..2609), }, arguments: PathArguments::None, }, @@ -311,9 +287,9 @@ error: the property value must be either a literal or enclosed in braces. Consid }, ], } - --> tests/html_macro/element-fail.rs:89:21 + --> tests/html_macro/element-fail.rs:85:21 | -89 | html! { }; +85 | html! { }; | ^^^^^^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple { @@ -321,9 +297,9 @@ error: the property value must be either a literal or enclosed in braces. Consid paren_token: Paren, elems: [], } - --> tests/html_macro/element-fail.rs:90:25 + --> tests/html_macro/element-fail.rs:86:25 | -90 | html! { }; +86 | html! { }; | ^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Tuple { @@ -331,9 +307,9 @@ error: the property value must be either a literal or enclosed in braces. Consid paren_token: Paren, elems: [], } - --> tests/html_macro/element-fail.rs:91:26 + --> tests/html_macro/element-fail.rs:87:26 | -91 | html! { }; +87 | html! { }; | ^^ error: the property value must be either a literal or enclosed in braces. Consider adding braces around your expression.: Expr::Path { @@ -345,26 +321,18 @@ error: the property value must be either a literal or enclosed in braces. Consid PathSegment { ident: Ident { ident: "NotToString", - span: #0 bytes(2862..2873), + span: #0 bytes(2712..2723), }, arguments: PathArguments::None, }, ], }, } - --> tests/html_macro/element-fail.rs:92:27 + --> tests/html_macro/element-fail.rs:88:27 | -92 | html! { }; +88 | html! { }; | ^^^^^^^^^^^ -warning: use of deprecated function `compile_fail::deprecated_use_of_class`: the use of `(...)` with the attribute `class` is deprecated and will be removed in version 0.19. Use the `classes!` macro instead. - --> tests/html_macro/element-fail.rs:80:25 - | -80 | html! {
    }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = note: `#[warn(deprecated)]` on by default - error[E0308]: mismatched types --> tests/html_macro/element-fail.rs:36:28 | @@ -434,16 +402,7 @@ error[E0277]: the trait bound `(): IntoPropValue }; | ^^ the trait `IntoPropValue>` is not implemented for `()` | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:44:27 @@ -451,16 +410,7 @@ error[E0277]: the trait bound `(): IntoPropValue }; | ^^ the trait `IntoPropValue>` is not implemented for `()` | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` error[E0277]: the trait bound `(): IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:45:22 @@ -468,16 +418,7 @@ error[E0277]: the trait bound `(): IntoPropValue }; | ^^ the trait `IntoPropValue>` is not implemented for `()` | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` error[E0277]: the trait bound `NotToString: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:46:28 @@ -493,7 +434,7 @@ error[E0277]: the trait bound `NotToString: IntoPropValue>> <&'static str as IntoPropValue> <&'static str as IntoPropValue> - <&T as IntoPropValue>> + <&String as IntoPropValue> and $N others error[E0277]: the trait bound `Option: IntoPropValue>` is not satisfied @@ -510,6 +451,7 @@ error[E0277]: the trait bound `Option: IntoPropValue> as IntoPropValue>> as IntoPropValue>> > as IntoPropValue>>> + as IntoPropValue> error[E0277]: the trait bound `Option<{integer}>: IntoPropValue>` is not satisfied --> tests/html_macro/element-fail.rs:48:22 @@ -525,6 +467,7 @@ error[E0277]: the trait bound `Option<{integer}>: IntoPropValue> as IntoPropValue>> as IntoPropValue>> > as IntoPropValue>>> + as IntoPropValue> error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `{integer}` --> tests/html_macro/element-fail.rs:51:28 @@ -613,16 +556,7 @@ error[E0277]: the trait bound `(): IntoPropValue` is not satisfied 56 | html! { }; | ^^ the trait `IntoPropValue` is not implemented for `()` | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Option: IntoPropValue` is not satisfied @@ -639,6 +573,7 @@ error[E0277]: the trait bound `Option: IntoPropValue > as IntoPropValue>> as IntoPropValue>> > as IntoPropValue>>> + as IntoPropValue> = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: expected a `Fn<(MouseEvent,)>` closure, found `yew::Callback` @@ -682,7 +617,7 @@ error[E0277]: the trait bound `NotToString: IntoPropValue>> <&'static str as IntoPropValue> <&'static str as IntoPropValue> - <&T as IntoPropValue>> + <&String as IntoPropValue> and $N others error[E0277]: the trait bound `(): IntoPropValue` is not satisfied @@ -691,32 +626,18 @@ error[E0277]: the trait bound `(): IntoPropValue` is not satisfied 62 | html! { }; | ^^ the trait `IntoPropValue` is not implemented for `()` | - = help: the following other types implement trait `IntoPropValue`: - <&'static [(K, V)] as IntoPropValue>> - <&'static [T] as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue>> - <&'static str as IntoPropValue> - <&'static str as IntoPropValue> - <&T as IntoPropValue>> - and $N others + = help: the trait `IntoPropValue` is implemented for `()` = note: this error originates in the macro `html` (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Cow<'static, str>: From<{integer}>` is not satisfied - --> tests/html_macro/element-fail.rs:77:15 +error[E0277]: the trait bound `implicit_clone::unsync::IString: From<{integer}>` is not satisfied + --> tests/html_macro/element-fail.rs:77:16 | 77 | html! { <@{55}> }; - | ^^^^ the trait `From<{integer}>` is not implemented for `Cow<'static, str>` + | ^^ the trait `From<{integer}>` is not implemented for `implicit_clone::unsync::IString` | = help: the following other types implement trait `From`: - as From<&'a CStr>> - as From<&'a CString>> - as From> - as From<&'a OsStr>> - as From<&'a OsString>> - as From> - as From<&'a Path>> - as From<&'a PathBuf>> - and $N others - = note: required because of the requirements on the impl of `Into>` for `{integer}` + > + >> + >> + > + = note: required because of the requirements on the impl of `Into` for `{integer}` diff --git a/packages/yew-macro/tests/html_macro/generic-component-pass.rs b/packages/yew-macro/tests/html_macro/generic-component-pass.rs index 4aca8a05457..856fff40fd8 100644 --- a/packages/yew-macro/tests/html_macro/generic-component-pass.rs +++ b/packages/yew-macro/tests/html_macro/generic-component-pass.rs @@ -76,24 +76,24 @@ where } fn compile_pass() { - ::yew::html! { /> }; - ::yew::html! { /> }; - ::yew::html! { >> }; - ::yew::html! { >> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { >> }; + _ = ::yew::html! { >> }; - ::yew::html! { > /> }; - ::yew::html! { >>>> }; + _ = ::yew::html! { > /> }; + _ = ::yew::html! { >>>> }; - ::yew::html! { /> }; - ::yew::html! { >> }; - ::yew::html! { /> }; - ::yew::html! { >> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { >> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { >> }; - ::yew::html! { /> }; - ::yew::html! { >> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { >> }; - ::yew::html! { /> }; - ::yew::html! { >> }; + _ = ::yew::html! { /> }; + _ = ::yew::html! { >> }; } fn main() {} diff --git a/packages/yew-macro/tests/html_macro/html-element-pass.rs b/packages/yew-macro/tests/html_macro/html-element-pass.rs index dc81c66db22..5c05322b050 100644 --- a/packages/yew-macro/tests/html_macro/html-element-pass.rs +++ b/packages/yew-macro/tests/html_macro/html-element-pass.rs @@ -48,7 +48,7 @@ fn compile_pass() { let attr_val_none: ::std::option::Option<::yew::virtual_dom::AttrValue> = ::std::option::Option::None; - ::yew::html! { + _ = ::yew::html! {
    @@ -92,8 +92,7 @@ fn compile_pass() { <@{ - let tag = dyn_tag(); - if tag == "test" { + if dyn_tag() == "test" { "div" } else { "a" @@ -113,17 +112,17 @@ fn compile_pass() { ::yew::html! { { "Hello" } }, ::yew::html! { { "World" } }, ]; - ::yew::html! {
    {children}
    }; + _ = ::yew::html! {
    {children}
    }; // handle misleading angle brackets - ::yew::html! {
    ::default()}>
    }; - ::yew::html! {
    }; + _ = ::yew::html! {
    ::default()}>
    }; + _ = ::yew::html! {
    }; // test for https://github.com/yewstack/yew/issues/2810 - ::yew::html! {
    }; + _ = ::yew::html! {
    }; let option_vnode = ::std::option::Option::Some(::yew::html! {}); - ::yew::html! {
    {option_vnode}
    }; + _ = ::yew::html! {
    {option_vnode}
    }; } fn main() {} diff --git a/packages/yew-macro/tests/html_macro/html-if-pass.rs b/packages/yew-macro/tests/html_macro/html-if-pass.rs index aa95ba9d1d7..59ce730dcbf 100644 --- a/packages/yew-macro/tests/html_macro/html-if-pass.rs +++ b/packages/yew-macro/tests/html_macro/html-if-pass.rs @@ -1,35 +1,35 @@ #![no_implicit_prelude] fn compile_pass_lit() { - ::yew::html! { if true {} }; - ::yew::html! { if true {
    } }; - ::yew::html! { if true {
    } }; - ::yew::html! { if true { <>
    } }; - ::yew::html! { if true { { ::yew::html! {} } } }; - ::yew::html! { if true { { { let _x = 42; ::yew::html! {} } } } }; - ::yew::html! { if true {} else {} }; - ::yew::html! { if true {} else if true {} }; - ::yew::html! { if true {} else if true {} else {} }; - ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some("text") { { text } } }; - ::yew::html! { <>
    if true {}
    }; - ::yew::html! {
    if true {}
    }; + _ = ::yew::html! { if true {} }; + _ = ::yew::html! { if true {
    } }; + _ = ::yew::html! { if true {
    } }; + _ = ::yew::html! { if true { <>
    } }; + _ = ::yew::html! { if true { { ::yew::html! {} } } }; + _ = ::yew::html! { if true { { { let _x = 42; ::yew::html! {} } } } }; + _ = ::yew::html! { if true {} else {} }; + _ = ::yew::html! { if true {} else if true {} }; + _ = ::yew::html! { if true {} else if true {} else {} }; + _ = ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some("text") { { text } } }; + _ = ::yew::html! { <>
    if true {}
    }; + _ = ::yew::html! {
    if true {}
    }; } fn compile_pass_expr() { let condition = true; - ::yew::html! { if condition {} }; - ::yew::html! { if condition {
    } }; - ::yew::html! { if condition {
    } }; - ::yew::html! { if condition { <>
    } }; - ::yew::html! { if condition { { ::yew::html! {} } } }; - ::yew::html! { if condition { { { let _x = 42; ::yew::html! {} } } } }; - ::yew::html! { if condition {} else {} }; - ::yew::html! { if condition {} else if condition {} }; - ::yew::html! { if condition {} else if condition {} else {} }; - ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some("text") { { text } } }; - ::yew::html! { <>
    if condition {}
    }; - ::yew::html! {
    if condition {}
    }; + _ = ::yew::html! { if condition {} }; + _ = ::yew::html! { if condition {
    } }; + _ = ::yew::html! { if condition {
    } }; + _ = ::yew::html! { if condition { <>
    } }; + _ = ::yew::html! { if condition { { ::yew::html! {} } } }; + _ = ::yew::html! { if condition { { { let _x = 42; ::yew::html! {} } } } }; + _ = ::yew::html! { if condition {} else {} }; + _ = ::yew::html! { if condition {} else if condition {} }; + _ = ::yew::html! { if condition {} else if condition {} else {} }; + _ = ::yew::html! { if let ::std::option::Option::Some(text) = ::std::option::Option::Some("text") { { text } } }; + _ = ::yew::html! { <>
    if condition {}
    }; + _ = ::yew::html! {
    if condition {}
    }; } fn main() {} diff --git a/packages/yew-macro/tests/html_macro/html-node-pass.rs b/packages/yew-macro/tests/html_macro/html-node-pass.rs index a8c9dd1f7b3..d1a05d4c759 100644 --- a/packages/yew-macro/tests/html_macro/html-node-pass.rs +++ b/packages/yew-macro/tests/html_macro/html-node-pass.rs @@ -37,23 +37,23 @@ pub struct u8; pub struct usize; fn compile_pass() { - ::yew::html! { "" }; - ::yew::html! { 'a' }; - ::yew::html! { "hello" }; - ::yew::html! { 42 }; - ::yew::html! { 1.234 }; + _ = ::yew::html! { "" }; + _ = ::yew::html! { 'a' }; + _ = ::yew::html! { "hello" }; + _ = ::yew::html! { 42 }; + _ = ::yew::html! { 1.234 }; - ::yew::html! { { "" } }; - ::yew::html! { { 'a' } }; - ::yew::html! { { "hello" } }; - ::yew::html! { { 42 } }; - ::yew::html! { { 1.234 } }; + _ = ::yew::html! { { "" } }; + _ = ::yew::html! { { 'a' } }; + _ = ::yew::html! { { "hello" } }; + _ = ::yew::html! { { 42 } }; + _ = ::yew::html! { { 1.234 } }; - ::yew::html! { ::std::format!("Hello") }; - ::yew::html! { {<::std::string::String as ::std::convert::From<&::std::primitive::str>>::from("Hello") } }; + _ = ::yew::html! { ::std::format!("Hello") }; + _ = ::yew::html! { {<::std::string::String as ::std::convert::From<&::std::primitive::str>>::from("Hello") } }; let msg = "Hello"; - ::yew::html! { msg }; + _ = ::yew::html! { msg }; } fn main() {} diff --git a/packages/yew-macro/tests/html_macro/iterable-pass.rs b/packages/yew-macro/tests/html_macro/iterable-pass.rs index 18eadf7b042..1f41185f3a2 100644 --- a/packages/yew-macro/tests/html_macro/iterable-pass.rs +++ b/packages/yew-macro/tests/html_macro/iterable-pass.rs @@ -45,13 +45,13 @@ fn empty_iter() -> impl ::std::iter::Iterator { } fn main() { - ::yew::html! { for empty_iter() }; - ::yew::html! { for { empty_iter() } }; + _ = ::yew::html! { for empty_iter() }; + _ = ::yew::html! { for { empty_iter() } }; let empty = empty_vec(); - ::yew::html! { for empty }; + _ = ::yew::html! { for empty }; - ::yew::html! { for empty_vec() }; - ::yew::html! { for ::std::iter::IntoIterator::into_iter(empty_vec()) }; - ::yew::html! { for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { { num } } }) }; + _ = ::yew::html! { for empty_vec() }; + _ = ::yew::html! { for ::std::iter::IntoIterator::into_iter(empty_vec()) }; + _ = ::yew::html! { for ::std::iter::Iterator::map(0..3, |num| { ::yew::html! { { num } } }) }; } diff --git a/packages/yew-macro/tests/html_macro/list-pass.rs b/packages/yew-macro/tests/html_macro/list-pass.rs index 3cbe619eaeb..380e4792d1a 100644 --- a/packages/yew-macro/tests/html_macro/list-pass.rs +++ b/packages/yew-macro/tests/html_macro/list-pass.rs @@ -37,15 +37,15 @@ pub struct u8; pub struct usize; fn main() { - ::yew::html! {}; - ::yew::html! { <> }; - ::yew::html! { + _ = ::yew::html! {}; + _ = ::yew::html! { <> }; + _ = ::yew::html! { <> <> <> }; - ::yew::html! { + _ = ::yew::html! { }; @@ -54,5 +54,5 @@ fn main() { ::yew::html! { { "Hello" } }, ::yew::html! { { "World" } }, ]; - ::yew::html! { <>{ children } }; + _ = ::yew::html! { <>{ children } }; } diff --git a/packages/yew-macro/tests/html_macro/node-pass.rs b/packages/yew-macro/tests/html_macro/node-pass.rs index 4f9f2ceb7d7..38aad870ad3 100644 --- a/packages/yew-macro/tests/html_macro/node-pass.rs +++ b/packages/yew-macro/tests/html_macro/node-pass.rs @@ -37,23 +37,23 @@ pub struct u8; pub struct usize; fn main() { - ::yew::html! { b'b' }; - ::yew::html! { 'a' }; - ::yew::html! { "hello" }; - ::yew::html! { 42 }; - ::yew::html! { 1.234 }; - ::yew::html! { true }; + _ = ::yew::html! { b'b' }; + _ = ::yew::html! { 'a' }; + _ = ::yew::html! { "hello" }; + _ = ::yew::html! { 42 }; + _ = ::yew::html! { 1.234 }; + _ = ::yew::html! { true }; - ::yew::html! { { "" } }; - ::yew::html! { { 'a' } }; - ::yew::html! { { "hello" } }; - ::yew::html! { { "42" } }; - ::yew::html! { { "1.234" } }; - ::yew::html! { { "true" } }; + _ = ::yew::html! { { "" } }; + _ = ::yew::html! { { 'a' } }; + _ = ::yew::html! { { "hello" } }; + _ = ::yew::html! { { "42" } }; + _ = ::yew::html! { { "1.234" } }; + _ = ::yew::html! { { "true" } }; - ::yew::html! { ::std::format!("Hello") }; - ::yew::html! { ::std::string::ToString::to_string("Hello") }; + _ = ::yew::html! { ::std::format!("Hello") }; + _ = ::yew::html! { ::std::string::ToString::to_string("Hello") }; let msg = "Hello"; - ::yew::html! { msg }; + _ = ::yew::html! { msg }; } diff --git a/packages/yew-macro/tests/html_macro/svg-pass.rs b/packages/yew-macro/tests/html_macro/svg-pass.rs index eb1bb3a0963..f333c265203 100644 --- a/packages/yew-macro/tests/html_macro/svg-pass.rs +++ b/packages/yew-macro/tests/html_macro/svg-pass.rs @@ -39,7 +39,7 @@ pub struct usize; fn main() { // Ensure Rust keywords can be used as element names. // See: #1771 - ::yew::html! { + _ = ::yew::html! { @@ -49,7 +49,7 @@ fn main() { }; // some general SVG - ::yew::html! { + _ = ::yew::html! { diff --git a/packages/yew-router/Cargo.toml b/packages/yew-router/Cargo.toml index 1e5624e85b6..e5b7d68e18a 100644 --- a/packages/yew-router/Cargo.toml +++ b/packages/yew-router/Cargo.toml @@ -21,7 +21,7 @@ gloo = { version = "0.10", features = ["futures"] } route-recognizer = "0.3" serde = "1" serde_urlencoded = "0.7.1" -tracing = "0.1.37" +tracing = "0.1.40" urlencoding = "2.1.3" [dependencies.web-sys] diff --git a/packages/yew/Cargo.toml b/packages/yew/Cargo.toml index 1f9fba8c07b..89cd95b4c6c 100644 --- a/packages/yew/Cargo.toml +++ b/packages/yew/Cargo.toml @@ -31,7 +31,7 @@ implicit-clone = { version = "0.4.1", features = ["map"] } base64ct = { version = "1.6.0", features = ["std"], optional = true } bincode = { version = "1.3.3", optional = true } serde = { version = "1", features = ["derive"] } -tracing = "0.1.37" +tracing = "0.1.40" prokio = "0.1.0" rustversion = "1" @@ -40,7 +40,7 @@ wasm-bindgen-futures = "0.4" [target.'cfg(not(target_arch = "wasm32"))'.dependencies] # We still need tokio as we have docs linked to it. -tokio = { version = "1.32", features = ["rt"] } +tokio = { version = "1.33", features = ["rt"] } [dependencies.web-sys] version = "^0.3.64" @@ -79,7 +79,7 @@ features = [ ] [target.'cfg(not(target_arch = "wasm32"))'.dev-dependencies] -tokio = { version = "1.32", features = ["full"] } +tokio = { version = "1.33", features = ["full"] } [dev-dependencies] wasm-bindgen-test = "0.3" diff --git a/packages/yew/src/dom_bundle/blist.rs b/packages/yew/src/dom_bundle/blist.rs index 93a9af585a8..ddd909027ea 100644 --- a/packages/yew/src/dom_bundle/blist.rs +++ b/packages/yew/src/dom_bundle/blist.rs @@ -4,13 +4,13 @@ use std::cmp::Ordering; use std::collections::HashSet; use std::hash::Hash; use std::ops::Deref; -use std::rc::Rc; use web_sys::Element; use super::{test_log, BNode, BSubtree, DomSlot}; use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::html::AnyScope; +use crate::utils::RcExt; use crate::virtual_dom::{Key, VList, VNode, VText}; /// This struct represents a mounted [VList] @@ -30,10 +30,8 @@ impl VList { let children = self .children - .map(Rc::try_unwrap) - .unwrap_or_else(|| Ok(Vec::new())) - // Rc::unwrap_or_clone is not stable yet. - .unwrap_or_else(|m| m.to_vec()); + .map(RcExt::unwrap_or_clone) + .unwrap_or_default(); (self.key, fully_keyed, children) } diff --git a/packages/yew/src/dom_bundle/bnode.rs b/packages/yew/src/dom_bundle/bnode.rs index d6fdbe5aa47..2f59acfe47f 100644 --- a/packages/yew/src/dom_bundle/bnode.rs +++ b/packages/yew/src/dom_bundle/bnode.rs @@ -7,6 +7,7 @@ use web_sys::{Element, Node}; use super::{BComp, BList, BPortal, BRaw, BSubtree, BSuspense, BTag, BText, DomSlot}; use crate::dom_bundle::{Reconcilable, ReconcileTarget}; use crate::html::AnyScope; +use crate::utils::RcExt; use crate::virtual_dom::{Key, VNode}; /// The bundle implementation to [VNode]. @@ -95,7 +96,8 @@ impl Reconcilable for VNode { ) -> (DomSlot, Self::Bundle) { match self { VNode::VTag(vtag) => { - let (node_ref, tag) = vtag.attach(root, parent_scope, parent, slot); + let (node_ref, tag) = + RcExt::unwrap_or_clone(vtag).attach(root, parent_scope, parent, slot); (node_ref, tag.into()) } VNode::VText(vtext) => { @@ -103,11 +105,13 @@ impl Reconcilable for VNode { (node_ref, text.into()) } VNode::VComp(vcomp) => { - let (node_ref, comp) = vcomp.attach(root, parent_scope, parent, slot); + let (node_ref, comp) = + RcExt::unwrap_or_clone(vcomp).attach(root, parent_scope, parent, slot); (node_ref, comp.into()) } VNode::VList(vlist) => { - let (node_ref, list) = vlist.attach(root, parent_scope, parent, slot); + let (node_ref, list) = + RcExt::unwrap_or_clone(vlist).attach(root, parent_scope, parent, slot); (node_ref, list.into()) } VNode::VRef(node) => { @@ -115,11 +119,13 @@ impl Reconcilable for VNode { (DomSlot::at(node.clone()), BNode::Ref(node)) } VNode::VPortal(vportal) => { - let (node_ref, portal) = vportal.attach(root, parent_scope, parent, slot); + let (node_ref, portal) = + RcExt::unwrap_or_clone(vportal).attach(root, parent_scope, parent, slot); (node_ref, portal.into()) } VNode::VSuspense(vsuspsense) => { - let (node_ref, suspsense) = vsuspsense.attach(root, parent_scope, parent, slot); + let (node_ref, suspsense) = + RcExt::unwrap_or_clone(vsuspsense).attach(root, parent_scope, parent, slot); (node_ref, suspsense.into()) } VNode::VRaw(vraw) => { @@ -149,20 +155,46 @@ impl Reconcilable for VNode { bundle: &mut BNode, ) -> DomSlot { match self { - VNode::VTag(vtag) => vtag.reconcile_node(root, parent_scope, parent, slot, bundle), + VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VText(vtext) => vtext.reconcile_node(root, parent_scope, parent, slot, bundle), - VNode::VComp(vcomp) => vcomp.reconcile_node(root, parent_scope, parent, slot, bundle), - VNode::VList(vlist) => vlist.reconcile_node(root, parent_scope, parent, slot, bundle), + VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), + VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VRef(node) => match bundle { BNode::Ref(ref n) if &node == n => DomSlot::at(node), _ => VNode::VRef(node).replace(root, parent_scope, parent, slot, bundle), }, - VNode::VPortal(vportal) => { - vportal.reconcile_node(root, parent_scope, parent, slot, bundle) - } - VNode::VSuspense(vsuspsense) => { - vsuspsense.reconcile_node(root, parent_scope, parent, slot, bundle) - } + VNode::VPortal(vportal) => RcExt::unwrap_or_clone(vportal).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), + VNode::VSuspense(vsuspsense) => RcExt::unwrap_or_clone(vsuspsense).reconcile_node( + root, + parent_scope, + parent, + slot, + bundle, + ), VNode::VRaw(vraw) => vraw.reconcile_node(root, parent_scope, parent, slot, bundle), } } @@ -246,10 +278,16 @@ mod feat_hydration { fragment: &mut Fragment, ) -> Self::Bundle { match self { - VNode::VTag(vtag) => vtag.hydrate(root, parent_scope, parent, fragment).into(), + VNode::VTag(vtag) => RcExt::unwrap_or_clone(vtag) + .hydrate(root, parent_scope, parent, fragment) + .into(), VNode::VText(vtext) => vtext.hydrate(root, parent_scope, parent, fragment).into(), - VNode::VComp(vcomp) => vcomp.hydrate(root, parent_scope, parent, fragment).into(), - VNode::VList(vlist) => vlist.hydrate(root, parent_scope, parent, fragment).into(), + VNode::VComp(vcomp) => RcExt::unwrap_or_clone(vcomp) + .hydrate(root, parent_scope, parent, fragment) + .into(), + VNode::VList(vlist) => RcExt::unwrap_or_clone(vlist) + .hydrate(root, parent_scope, parent, fragment) + .into(), // You cannot hydrate a VRef. VNode::VRef(_) => { panic!( @@ -264,7 +302,7 @@ mod feat_hydration { use_effect." ) } - VNode::VSuspense(vsuspense) => vsuspense + VNode::VSuspense(vsuspense) => RcExt::unwrap_or_clone(vsuspense) .hydrate(root, parent_scope, parent, fragment) .into(), VNode::VRaw(vraw) => vraw.hydrate(root, parent_scope, parent, fragment).into(), diff --git a/packages/yew/src/dom_bundle/bportal.rs b/packages/yew/src/dom_bundle/bportal.rs index a7e5d76c9a0..9792383101b 100644 --- a/packages/yew/src/dom_bundle/bportal.rs +++ b/packages/yew/src/dom_bundle/bportal.rs @@ -123,6 +123,8 @@ impl BPortal { mod layout_tests { extern crate self as yew; + use std::rc::Rc; + use gloo::utils::document; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use web_sys::HtmlInputElement; @@ -151,10 +153,10 @@ mod layout_tests {
    {VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { {"PORTAL"} }, first_target.clone(), - ))} + )))} {"AFTER"}
    }, @@ -166,10 +168,10 @@ mod layout_tests {
    {VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { {"PORTAL"} }, second_target.clone(), - ))} + )))} {"AFTER"}
    }, @@ -181,10 +183,10 @@ mod layout_tests {
    {VNode::VRef(first_target.clone().into())} {VNode::VRef(second_target.clone().into())} - {VNode::VPortal(VPortal::new( + {VNode::VPortal(Rc::new(VPortal::new( html! { <> {"PORTAL"} }, second_target.clone(), - ))} + )))} {"AFTER"}
    }, @@ -207,11 +209,11 @@ mod layout_tests { node: html! {
    {VNode::VRef(target_with_child.clone().into())} - {VNode::VPortal(VPortal::new_before( + {VNode::VPortal(Rc::new(VPortal::new_before( html! { {"PORTAL"} }, target_with_child.clone(), Some(target_child.clone().into()), - ))} + )))}
    }, expected: "
    PORTAL
    ", diff --git a/packages/yew/src/dom_bundle/btag/attributes.rs b/packages/yew/src/dom_bundle/btag/attributes.rs index e2f41e11498..d56be61021d 100644 --- a/packages/yew/src/dom_bundle/btag/attributes.rs +++ b/packages/yew/src/dom_bundle/btag/attributes.rs @@ -9,7 +9,7 @@ use yew::AttrValue; use super::Apply; use crate::dom_bundle::BSubtree; use crate::virtual_dom::vtag::{InputFields, Value}; -use crate::virtual_dom::{ApplyAttributeAs, Attributes}; +use crate::virtual_dom::{AttributeOrProperty, Attributes}; impl Apply for Value { type Bundle = Self; @@ -92,23 +92,23 @@ impl Attributes { #[cold] fn apply_diff_index_maps( el: &Element, - new: &IndexMap, - old: &IndexMap, + new: &IndexMap, + old: &IndexMap, ) { for (key, value) in new.iter() { match old.get(key) { Some(old_value) => { if value != old_value { - Self::set(el, key, value.0.as_ref(), value.1); + Self::set(el, key, value); } } - None => Self::set(el, key, value.0.as_ref(), value.1), + None => Self::set(el, key, value), } } - for (key, (_, apply_as)) in old.iter() { + for (key, value) in old.iter() { if !new.contains_key(key) { - Self::remove(el, key, *apply_as); + Self::remove(el, key, value); } } } @@ -117,26 +117,17 @@ impl Attributes { /// Works with any [Attributes] variants. #[cold] fn apply_diff_as_maps<'a>(el: &Element, new: &'a Self, old: &'a Self) { - fn collect(src: &Attributes) -> HashMap<&str, (&str, ApplyAttributeAs)> { + fn collect(src: &Attributes) -> HashMap<&str, &AttributeOrProperty> { use Attributes::*; match src { - Static(arr) => (*arr) - .iter() - .map(|(k, v, apply_as)| (*k, (*v, *apply_as))) - .collect(), + Static(arr) => (*arr).iter().map(|(k, v)| (*k, v)).collect(), Dynamic { keys, values } => keys .iter() .zip(values.iter()) - .filter_map(|(k, v)| { - v.as_ref() - .map(|(v, apply_as)| (*k, (v.as_ref(), *apply_as))) - }) - .collect(), - IndexMap(m) => m - .iter() - .map(|(k, (v, apply_as))| (k.as_ref(), (v.as_ref(), *apply_as))) + .filter_map(|(k, v)| v.as_ref().map(|v| (*k, v))) .collect(), + IndexMap(m) => m.iter().map(|(k, v)| (k.as_ref(), v)).collect(), } } @@ -149,37 +140,39 @@ impl Attributes { Some(old) => old != new, None => true, } { - Self::set(el, k, new.0, new.1); + Self::set(el, k, new); } } // Remove missing - for (k, (_, apply_as)) in old.iter() { + for (k, old_value) in old.iter() { if !new.contains_key(k) { - Self::remove(el, k, *apply_as); + Self::remove(el, k, old_value); } } } - fn set(el: &Element, key: &str, value: &str, apply_as: ApplyAttributeAs) { - match apply_as { - ApplyAttributeAs::Attribute => el + fn set(el: &Element, key: &str, value: &AttributeOrProperty) { + match value { + AttributeOrProperty::Attribute(value) => el + .set_attribute(intern(key), value) + .expect("invalid attribute key"), + AttributeOrProperty::Static(value) => el .set_attribute(intern(key), value) .expect("invalid attribute key"), - ApplyAttributeAs::Property => { + AttributeOrProperty::Property(value) => { let key = JsValue::from_str(key); - let value = JsValue::from_str(value); - js_sys::Reflect::set(el.as_ref(), &key, &value).expect("could not set property"); + js_sys::Reflect::set(el.as_ref(), &key, value).expect("could not set property"); } } } - fn remove(el: &Element, key: &str, apply_as: ApplyAttributeAs) { - match apply_as { - ApplyAttributeAs::Attribute => el + fn remove(el: &Element, key: &str, old_value: &AttributeOrProperty) { + match old_value { + AttributeOrProperty::Attribute(_) | AttributeOrProperty::Static(_) => el .remove_attribute(intern(key)) .expect("could not remove attribute"), - ApplyAttributeAs::Property => { + AttributeOrProperty::Property(_) => { let key = JsValue::from_str(key); js_sys::Reflect::set(el.as_ref(), &key, &JsValue::UNDEFINED) .expect("could not remove property"); @@ -195,20 +188,20 @@ impl Apply for Attributes { fn apply(self, _root: &BSubtree, el: &Element) -> Self { match &self { Self::Static(arr) => { - for (k, v, apply_as) in arr.iter() { - Self::set(el, k, v, *apply_as); + for (k, v) in arr.iter() { + Self::set(el, k, v); } } Self::Dynamic { keys, values } => { for (k, v) in keys.iter().zip(values.iter()) { - if let Some((v, apply_as)) = v { - Self::set(el, k, v, *apply_as) + if let Some(v) = v { + Self::set(el, k, v) } } } Self::IndexMap(m) => { - for (k, (v, apply_as)) in m.iter() { - Self::set(el, k, v, *apply_as) + for (k, v) in m.iter() { + Self::set(el, k, v) } } } @@ -248,7 +241,7 @@ impl Apply for Attributes { } macro_rules! set { ($new:expr) => { - Self::set(el, key!(), $new.0.as_ref(), $new.1) + Self::set(el, key!(), $new) }; } @@ -260,7 +253,7 @@ impl Apply for Attributes { } (Some(new), None) => set!(new), (None, Some(old)) => { - Self::remove(el, key!(), old.1); + Self::remove(el, key!(), old); } (None, None) => (), } @@ -282,6 +275,7 @@ impl Apply for Attributes { #[cfg(target_arch = "wasm32")] #[cfg(test)] mod tests { + use std::rc::Rc; use std::time::Duration; use gloo::utils::document; @@ -303,10 +297,11 @@ mod tests { #[test] fn properties_are_set() { - let attrs = Attributes::Static(&[ - ("href", "https://example.com/", ApplyAttributeAs::Property), - ("alt", "somewhere", ApplyAttributeAs::Property), - ]); + let attrs = indexmap::indexmap! { + AttrValue::Static("href") => AttributeOrProperty::Property(JsValue::from_str("https://example.com/")), + AttrValue::Static("alt") => AttributeOrProperty::Property(JsValue::from_str("somewhere")), + }; + let attrs = Attributes::IndexMap(Rc::new(attrs)); let (element, btree) = create_element(); attrs.apply(&btree, &element); assert_eq!( @@ -329,10 +324,11 @@ mod tests { #[test] fn respects_apply_as() { - let attrs = Attributes::Static(&[ - ("href", "https://example.com/", ApplyAttributeAs::Attribute), - ("alt", "somewhere", ApplyAttributeAs::Property), - ]); + let attrs = indexmap::indexmap! { + AttrValue::Static("href") => AttributeOrProperty::Attribute(AttrValue::from("https://example.com/")), + AttrValue::Static("alt") => AttributeOrProperty::Property(JsValue::from_str("somewhere")), + }; + let attrs = Attributes::IndexMap(Rc::new(attrs)); let (element, btree) = create_element(); attrs.apply(&btree, &element); assert_eq!( @@ -352,7 +348,7 @@ mod tests { #[test] fn class_is_always_attrs() { - let attrs = Attributes::Static(&[("class", "thing", ApplyAttributeAs::Attribute)]); + let attrs = Attributes::Static(&[("class", AttributeOrProperty::Static("thing"))]); let (element, btree) = create_element(); attrs.apply(&btree, &element); @@ -363,10 +359,10 @@ mod tests { async fn macro_syntax_works() { #[function_component] fn Comp() -> Html { - html! {
    } + html! { } } - let output = gloo::utils::document().get_element_by_id("output").unwrap(); + let output = document().get_element_by_id("output").unwrap(); yew::Renderer::::with_root(output.clone()).render(); gloo::timers::future::sleep(Duration::from_secs(1)).await; @@ -384,5 +380,13 @@ mod tests { "abc", "property `alt` not set properly" ); + + assert!( + Reflect::get(element.as_ref(), &JsValue::from_str("data-bool")) + .expect("no alt") + .as_bool() + .expect("not a bool"), + "property `alt` not set properly" + ); } } diff --git a/packages/yew/src/dom_bundle/btag/mod.rs b/packages/yew/src/dom_bundle/btag/mod.rs index c590d6be6c5..a376d3b1fc9 100644 --- a/packages/yew/src/dom_bundle/btag/mod.rs +++ b/packages/yew/src/dom_bundle/btag/mod.rs @@ -3,7 +3,6 @@ mod attributes; mod listeners; -use std::borrow::Cow; use std::cell::RefCell; use std::collections::HashMap; use std::hint::unreachable_unchecked; @@ -18,7 +17,7 @@ use web_sys::{Element, HtmlTextAreaElement as TextAreaElement}; use super::{BNode, BSubtree, DomSlot, Reconcilable, ReconcileTarget}; use crate::html::AnyScope; use crate::virtual_dom::vtag::{InputFields, VTagInner, Value, MATHML_NAMESPACE, SVG_NAMESPACE}; -use crate::virtual_dom::{Attributes, Key, VTag}; +use crate::virtual_dom::{AttrValue, Attributes, Key, VTag}; use crate::NodeRef; /// Applies contained changes to DOM [web_sys::Element] @@ -51,7 +50,7 @@ enum BTagInner { /// Fields for all other kinds of [VTag]s Other { /// A tag of the element. - tag: Cow<'static, str>, + tag: AttrValue, /// Child node. child_bundle: BNode, }, @@ -407,6 +406,8 @@ mod feat_hydration { #[cfg(target_arch = "wasm32")] #[cfg(test)] mod tests { + use std::rc::Rc; + use wasm_bindgen::JsCast; use wasm_bindgen_test::{wasm_bindgen_test as test, wasm_bindgen_test_configure}; use web_sys::HtmlInputElement as InputElement; @@ -414,6 +415,7 @@ mod tests { use super::*; use crate::dom_bundle::utils::setup_parent; use crate::dom_bundle::{BNode, Reconcilable, ReconcileTarget}; + use crate::utils::RcExt; use crate::virtual_dom::vtag::{HTML_NAMESPACE, SVG_NAMESPACE}; use crate::virtual_dom::{AttrValue, VNode, VTag}; use crate::{html, Html, NodeRef}; @@ -564,7 +566,7 @@ mod tests { fn assert_vtag(node: VNode) -> VTag { if let VNode::VTag(vtag) = node { - return *vtag; + return RcExt::unwrap_or_clone(vtag); } panic!("should be vtag"); } @@ -828,11 +830,11 @@ mod tests { fn dynamic_tags_work() { let (root, scope, parent) = setup_parent(); - let elem = html! { <@{ + let elem = html! { <@{{ let mut builder = String::new(); builder.push('a'); builder - }/> }; + }}/> }; let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end()); let vtag = assert_btag_mut(&mut elem); @@ -971,7 +973,7 @@ mod tests { vtag.add_attribute("disabled", "disabled"); vtag.add_attribute("tabindex", "0"); - let elem = VNode::VTag(Box::new(vtag)); + let elem = VNode::VTag(Rc::new(vtag)); let (_, mut elem) = elem.attach(&root, &scope, &parent, DomSlot::at_end()); @@ -979,7 +981,7 @@ mod tests { let mut vtag = VTag::new("div"); vtag.node_ref = test_ref.clone(); vtag.add_attribute("tabindex", "0"); - let next_elem = VNode::VTag(Box::new(vtag)); + let next_elem = VNode::VTag(Rc::new(vtag)); let elem_vtag = assert_vtag(next_elem); // Sync happens here diff --git a/packages/yew/src/html/classes.rs b/packages/yew/src/html/classes.rs index 0a5bb9cc9b0..941ec617bf2 100644 --- a/packages/yew/src/html/classes.rs +++ b/packages/yew/src/html/classes.rs @@ -6,6 +6,7 @@ use implicit_clone::ImplicitClone; use indexmap::IndexSet; use super::IntoPropValue; +use crate::utils::RcExt; use crate::virtual_dom::AttrValue; /// A set of classes, cheap to clone. @@ -150,10 +151,7 @@ impl IntoIterator for Classes { #[inline] fn into_iter(self) -> Self::IntoIter { - // NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable - Rc::try_unwrap(self.set) - .unwrap_or_else(|rc| (*rc).clone()) - .into_iter() + RcExt::unwrap_or_clone(self.set).into_iter() } } diff --git a/packages/yew/src/html/component/children.rs b/packages/yew/src/html/component/children.rs index 94f6dc0d2e8..701f00fd9df 100644 --- a/packages/yew/src/html/component/children.rs +++ b/packages/yew/src/html/component/children.rs @@ -1,6 +1,7 @@ //! Component children module use std::fmt; +use std::rc::Rc; use crate::html::Html; use crate::virtual_dom::{VChild, VComp, VList, VNode}; @@ -152,7 +153,7 @@ pub type ChildrenWithProps = ChildrenRenderer>; /// A type used for rendering children html. #[derive(Clone)] pub struct ChildrenRenderer { - children: Vec, + pub(crate) children: Vec, } impl PartialEq for ChildrenRenderer { @@ -192,10 +193,11 @@ where /// ``` /// # let children = Children::new(Vec::new()); /// # use yew::{classes, html, Children}; + /// # let _ = /// children.map(|children| { /// html! { ///
    - /// {children} + /// {children.clone()} ///
    /// } /// }) @@ -241,7 +243,7 @@ impl From> for Html { } } - Html::VList(val.into()) + Html::VList(Rc::new(val.into())) } } diff --git a/packages/yew/src/html/conversion/into_prop_value.rs b/packages/yew/src/html/conversion/into_prop_value.rs index 57579415d33..9b2972b5b93 100644 --- a/packages/yew/src/html/conversion/into_prop_value.rs +++ b/packages/yew/src/html/conversion/into_prop_value.rs @@ -1,13 +1,13 @@ use std::borrow::Cow; use std::rc::Rc; +use std::sync::Arc; use implicit_clone::unsync::{IArray, IMap}; pub use implicit_clone::ImplicitClone; -use super::ToHtml; use crate::callback::Callback; use crate::html::{BaseComponent, ChildrenRenderer, Component, NodeRef, Scope}; -use crate::virtual_dom::{AttrValue, VChild, VNode, VText}; +use crate::virtual_dom::{AttrValue, VChild, VList, VNode, VText}; impl ImplicitClone for NodeRef {} impl ImplicitClone for Scope {} @@ -130,13 +130,40 @@ where } } -impl IntoPropValue for T +impl IntoPropValue for VChild where - T: ToHtml, + T: BaseComponent, { #[inline] fn into_prop_value(self) -> VNode { - self.into_html() + VNode::from(self) + } +} + +impl IntoPropValue for VList { + #[inline] + fn into_prop_value(self) -> VNode { + VNode::VList(Rc::new(self)) + } +} +impl IntoPropValue for VText { + #[inline] + fn into_prop_value(self) -> VNode { + VNode::VText(self) + } +} + +impl IntoPropValue for () { + #[inline] + fn into_prop_value(self) -> VNode { + VNode::default() + } +} + +impl IntoPropValue for ChildrenRenderer { + #[inline] + fn into_prop_value(self) -> VNode { + VNode::VList(Rc::new(self.into())) } } @@ -154,6 +181,40 @@ impl IntoPropValue> for VText { } } +impl IntoPropValue for ChildrenRenderer { + #[inline] + fn into_prop_value(self) -> VList { + VList::with_children(self.children, None) + } +} + +impl IntoPropValue for VChild { + #[inline] + fn into_prop_value(self) -> VList { + VList::with_children(vec![self.into()], None) + } +} + +impl IntoPropValue> for AttrValue { + fn into_prop_value(self) -> ChildrenRenderer { + ChildrenRenderer::new(vec![VNode::VText(VText::new(self))]) + } +} + +impl IntoPropValue for Vec { + #[inline] + fn into_prop_value(self) -> VNode { + VNode::VList(Rc::new(VList::with_children(self, None))) + } +} + +impl IntoPropValue for Option { + #[inline] + fn into_prop_value(self) -> VNode { + self.unwrap_or_default() + } +} + macro_rules! impl_into_prop { (|$value:ident: $from_ty:ty| -> $to_ty:ty { $conversion:expr }) => { // implement V -> T @@ -217,6 +278,57 @@ impl { + impl IntoPropValue for $from_ty { + #[inline(always)] + fn into_prop_value(self) -> VNode { + VText::from(self).into() + } + } + }; +} + +// go through AttrValue::from where possible +macro_rules! impl_into_prop_value_via_attr_value { + ($from_ty: ty) => { + impl IntoPropValue for $from_ty { + #[inline(always)] + fn into_prop_value(self) -> VNode { + VText::new(self).into() + } + } + }; +} + +// These are a selection of types implemented via display. +impl_into_prop_value_via_display!(bool); +impl_into_prop_value_via_display!(char); +impl_into_prop_value_via_display!(&String); +impl_into_prop_value_via_display!(&str); +impl_into_prop_value_via_display!(Arc); +impl_into_prop_value_via_display!(Arc); +impl_into_prop_value_via_display!(Rc); +impl_into_prop_value_via_display!(u8); +impl_into_prop_value_via_display!(u16); +impl_into_prop_value_via_display!(u32); +impl_into_prop_value_via_display!(u64); +impl_into_prop_value_via_display!(u128); +impl_into_prop_value_via_display!(usize); +impl_into_prop_value_via_display!(i8); +impl_into_prop_value_via_display!(i16); +impl_into_prop_value_via_display!(i32); +impl_into_prop_value_via_display!(i64); +impl_into_prop_value_via_display!(i128); +impl_into_prop_value_via_display!(isize); +impl_into_prop_value_via_display!(f32); +impl_into_prop_value_via_display!(f64); + +impl_into_prop_value_via_attr_value!(String); +impl_into_prop_value_via_attr_value!(AttrValue); +impl_into_prop_value_via_attr_value!(Rc); +impl_into_prop_value_via_attr_value!(Cow<'static, str>); + #[cfg(test)] mod test { use super::*; @@ -341,4 +453,83 @@ mod test { }; } + + #[test] + fn test_vlist_to_children_compiles() { + use crate::prelude::*; + use crate::virtual_dom::VList; + + #[function_component] + fn Foo() -> Html { + todo!() + } + + #[derive(PartialEq, Properties)] + pub struct ChildProps { + #[prop_or_default] + pub children: Html, + } + + #[function_component] + fn Child(_props: &ChildProps) -> Html { + html!() + } + + #[derive(PartialEq, Properties)] + pub struct ParentProps { + pub children: VList, + } + + #[function_component] + fn Parent(_props: &ParentProps) -> Html { + todo!() + } + + let _ = html! { + + + + }; + + let _ = html! { + + + + + }; + + let _ = html! { + + + + + + }; + } + + #[test] + fn attr_value_children() { + use crate::prelude::*; + + #[derive(PartialEq, Properties)] + pub struct ChildProps { + #[prop_or_default] + pub children: AttrValue, + } + + #[function_component] + fn Child(_props: &ChildProps) -> Html { + html!() + } + { + let attr_value = AttrValue::from("foo"); + + let _ = html! { {attr_value} }; + } + { + let attr_value = AttrValue::from("foo"); + + let _ = html! { {&attr_value} }; + } + } } diff --git a/packages/yew/src/html/conversion/mod.rs b/packages/yew/src/html/conversion/mod.rs index 70181c553a2..ff9f1401cb5 100644 --- a/packages/yew/src/html/conversion/mod.rs +++ b/packages/yew/src/html/conversion/mod.rs @@ -1,5 +1,2 @@ mod into_prop_value; -mod to_html; - pub use into_prop_value::*; -pub use to_html::*; diff --git a/packages/yew/src/html/conversion/to_html.rs b/packages/yew/src/html/conversion/to_html.rs deleted file mode 100644 index c7d3eeaa57b..00000000000 --- a/packages/yew/src/html/conversion/to_html.rs +++ /dev/null @@ -1,203 +0,0 @@ -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 ToHtml for Option -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 ToHtml for Vec -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 { - #[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 { - #[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 { - #[inline(always)] - fn to_html(&self) -> Html { - self.clone().into() - } - - #[inline(always)] - fn into_html(self) -> Html { - self.into() - } -} - -impl ToHtml for VChild -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 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> for $from_ty { - #[inline(always)] - fn into_prop_value(self) -> ChildrenRenderer { - 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); -impl_to_html_via_display!(Rc); -impl_to_html_via_display!(Arc); -impl_to_html_via_display!(Arc); -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); diff --git a/packages/yew/src/html/mod.rs b/packages/yew/src/html/mod.rs index 87e3cc03372..cbb0b1c5488 100644 --- a/packages/yew/src/html/mod.rs +++ b/packages/yew/src/html/mod.rs @@ -142,5 +142,5 @@ mod feat_csr { /// ## Relevant examples /// - [Portals](https://github.com/yewstack/yew/tree/master/examples/portals) pub fn create_portal(child: Html, host: Element) -> Html { - VNode::VPortal(VPortal::new(child, host)) + VNode::VPortal(Rc::new(VPortal::new(child, host))) } diff --git a/packages/yew/src/lib.rs b/packages/yew/src/lib.rs index 3e47e9a5c30..cd85d32af3e 100644 --- a/packages/yew/src/lib.rs +++ b/packages/yew/src/lib.rs @@ -336,7 +336,7 @@ pub mod prelude { pub use crate::functional::*; pub use crate::html::{ create_portal, BaseComponent, Children, ChildrenWithProps, Classes, Component, Context, - Html, HtmlResult, NodeRef, Properties, ToHtml, + Html, HtmlResult, NodeRef, Properties, }; pub use crate::macros::{classes, html, html_nested}; pub use crate::suspense::Suspense; diff --git a/packages/yew/src/utils/mod.rs b/packages/yew/src/utils/mod.rs index 98934ed054b..4f33ea672b2 100644 --- a/packages/yew/src/utils/mod.rs +++ b/packages/yew/src/utils/mod.rs @@ -64,3 +64,14 @@ pub fn print_node(n: &web_sys::Node) -> String { None => n.text_content().unwrap_or_default(), } } + +// NOTE: replace this by Rc::unwrap_or_clone() when it becomes stable +pub(crate) trait RcExt { + fn unwrap_or_clone(this: Self) -> T; +} + +impl RcExt for std::rc::Rc { + fn unwrap_or_clone(this: Self) -> T { + std::rc::Rc::try_unwrap(this).unwrap_or_else(|rc| (*rc).clone()) + } +} diff --git a/packages/yew/src/virtual_dom/listeners.rs b/packages/yew/src/virtual_dom/listeners.rs index caa0943d599..f96dead2f39 100644 --- a/packages/yew/src/virtual_dom/listeners.rs +++ b/packages/yew/src/virtual_dom/listeners.rs @@ -1,5 +1,7 @@ use std::rc::Rc; +use crate::html::ImplicitClone; + /// The [Listener] trait is an universal implementation of an event listener /// which is used to bind Rust-listener to JS-listener (DOM). pub trait Listener { @@ -168,6 +170,8 @@ pub enum Listeners { Pending(Box<[Option>]>), } +impl ImplicitClone for Listeners {} + impl PartialEq for Listeners { fn eq(&self, rhs: &Self) -> bool { use Listeners::*; diff --git a/packages/yew/src/virtual_dom/mod.rs b/packages/yew/src/virtual_dom/mod.rs index 940c46021f9..7b5aac47f5b 100644 --- a/packages/yew/src/virtual_dom/mod.rs +++ b/packages/yew/src/virtual_dom/mod.rs @@ -22,8 +22,10 @@ pub mod vtag; pub mod vtext; use std::hint::unreachable_unchecked; +use std::rc::Rc; use indexmap::IndexMap; +use wasm_bindgen::JsValue; #[doc(inline)] pub use self::key::Key; @@ -171,22 +173,29 @@ mod feat_ssr { } } -/// Defines if the [`Attributes`] is set as element's attribute or property +/// Defines if the [`Attributes`] is set as element's attribute or property and its value. #[allow(missing_docs)] -#[derive(PartialEq, Eq, Copy, Clone, Debug)] -pub enum ApplyAttributeAs { - Attribute, - Property, +#[derive(PartialEq, Clone, Debug)] +pub enum AttributeOrProperty { + // This exists as a workaround to support Rust <1.72 + // Previous versions of Rust did not See + // `AttributeOrProperty::Attribute(AttrValue::Static(_))` as `'static` that html! macro + // used, and thus failed with "temporary value dropped while borrowed" + // + // See: https://github.com/yewstack/yew/pull/3458#discussion_r1350362215 + Static(&'static str), + Attribute(AttrValue), + Property(JsValue), } /// A collection of attributes for an element -#[derive(PartialEq, Eq, Clone, Debug)] +#[derive(PartialEq, Clone, Debug)] pub enum Attributes { /// Static list of attributes. /// /// Allows optimizing comparison to a simple pointer equality check and reducing allocations, /// if the attributes do not change on a node. - Static(&'static [(&'static str, &'static str, ApplyAttributeAs)]), + Static(&'static [(&'static str, AttributeOrProperty)]), /// Static list of attribute keys with possibility to exclude attributes and dynamic attribute /// values. @@ -199,12 +208,12 @@ pub enum Attributes { /// Attribute values. Matches [keys](Attributes::Dynamic::keys). Optional attributes are /// designated by setting [None]. - values: Box<[Option<(AttrValue, ApplyAttributeAs)>]>, + values: Box<[Option]>, }, /// IndexMap is used to provide runtime attribute deduplication in cases where the html! macro /// was not used to guarantee it. - IndexMap(IndexMap), + IndexMap(Rc>), } impl Attributes { @@ -215,25 +224,35 @@ impl Attributes { /// Return iterator over attribute key-value pairs. /// This function is suboptimal and does not inline well. Avoid on hot paths. + /// + /// This function only returns attributes pub fn iter<'a>(&'a self) -> Box + 'a> { match self { - Self::Static(arr) => Box::new(arr.iter().map(|(k, v, _)| (*k, *v as &'a str))), - Self::Dynamic { keys, values } => Box::new( - keys.iter() - .zip(values.iter()) - .filter_map(|(k, v)| v.as_ref().map(|(v, _)| (*k, v.as_ref()))), - ), - Self::IndexMap(m) => Box::new(m.iter().map(|(k, (v, _))| (k.as_ref(), v.as_ref()))), + Self::Static(arr) => Box::new(arr.iter().filter_map(|(k, v)| match v { + AttributeOrProperty::Attribute(v) => Some((*k, v.as_ref())), + AttributeOrProperty::Property(_) => None, + AttributeOrProperty::Static(v) => Some((*k, v)), + })), + Self::Dynamic { keys, values } => { + Box::new(keys.iter().zip(values.iter()).filter_map(|(k, v)| match v { + Some(AttributeOrProperty::Attribute(v)) => Some((*k, v.as_ref())), + _ => None, + })) + } + Self::IndexMap(m) => Box::new(m.iter().filter_map(|(k, v)| match v { + AttributeOrProperty::Attribute(v) => Some((k.as_ref(), v.as_ref())), + _ => None, + })), } } /// Get a mutable reference to the underlying `IndexMap`. /// If the attributes are stored in the `Vec` variant, it will be converted. - pub fn get_mut_index_map(&mut self) -> &mut IndexMap { + pub fn get_mut_index_map(&mut self) -> &mut IndexMap { macro_rules! unpack { () => { match self { - Self::IndexMap(m) => m, + Self::IndexMap(m) => Rc::make_mut(m), // SAFETY: unreachable because we set self to the `IndexMap` variant above. _ => unsafe { unreachable_unchecked() }, } @@ -241,23 +260,21 @@ impl Attributes { } match self { - Self::IndexMap(m) => m, + Self::IndexMap(m) => Rc::make_mut(m), Self::Static(arr) => { - *self = Self::IndexMap( - arr.iter() - .map(|(k, v, ty)| ((*k).into(), ((*v).into(), *ty))) - .collect(), - ); + *self = Self::IndexMap(Rc::new( + arr.iter().map(|(k, v)| ((*k).into(), v.clone())).collect(), + )); unpack!() } Self::Dynamic { keys, values } => { - *self = Self::IndexMap( + *self = Self::IndexMap(Rc::new( std::mem::take(values) .iter_mut() .zip(keys.iter()) .filter_map(|(v, k)| v.take().map(|v| (AttrValue::from(*k), v))) .collect(), - ); + )); unpack!() } } @@ -268,9 +285,9 @@ impl From> for Attributes { fn from(map: IndexMap) -> Self { let v = map .into_iter() - .map(|(k, v)| (k, (v, ApplyAttributeAs::Attribute))) + .map(|(k, v)| (k, AttributeOrProperty::Attribute(v))) .collect(); - Self::IndexMap(v) + Self::IndexMap(Rc::new(v)) } } @@ -278,9 +295,19 @@ impl From> for Attributes { fn from(v: IndexMap<&'static str, AttrValue>) -> Self { let v = v .into_iter() - .map(|(k, v)| (AttrValue::Static(k), (v, ApplyAttributeAs::Attribute))) + .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Attribute(v)))) + .collect(); + Self::IndexMap(Rc::new(v)) + } +} + +impl From> for Attributes { + fn from(v: IndexMap<&'static str, JsValue>) -> Self { + let v = v + .into_iter() + .map(|(k, v)| (AttrValue::Static(k), (AttributeOrProperty::Property(v)))) .collect(); - Self::IndexMap(v) + Self::IndexMap(Rc::new(v)) } } diff --git a/packages/yew/src/virtual_dom/vcomp.rs b/packages/yew/src/virtual_dom/vcomp.rs index 55129017a02..07c5faba0a1 100644 --- a/packages/yew/src/virtual_dom/vcomp.rs +++ b/packages/yew/src/virtual_dom/vcomp.rs @@ -183,6 +183,8 @@ pub struct VChild { key: Option, } +impl implicit_clone::ImplicitClone for VChild {} + impl Clone for VChild { fn clone(&self) -> Self { VChild { diff --git a/packages/yew/src/virtual_dom/vlist.rs b/packages/yew/src/virtual_dom/vlist.rs index cd9459497f1..62dc5b14e0a 100644 --- a/packages/yew/src/virtual_dom/vlist.rs +++ b/packages/yew/src/virtual_dom/vlist.rs @@ -3,6 +3,7 @@ use std::ops::{Deref, DerefMut}; use std::rc::Rc; use super::{Key, VNode}; +use crate::html::ImplicitClone; #[derive(Clone, Copy, Debug, PartialEq)] enum FullyKeyedState { @@ -23,6 +24,8 @@ pub struct VList { pub key: Option, } +impl ImplicitClone for VList {} + impl PartialEq for VList { fn eq(&self, other: &Self) -> bool { self.key == other.key && self.children == other.children diff --git a/packages/yew/src/virtual_dom/vnode.rs b/packages/yew/src/virtual_dom/vnode.rs index 943081c2f3e..8ed18f29c9f 100644 --- a/packages/yew/src/virtual_dom/vnode.rs +++ b/packages/yew/src/virtual_dom/vnode.rs @@ -2,12 +2,13 @@ use std::cmp::PartialEq; use std::iter::FromIterator; +use std::rc::Rc; use std::{fmt, mem}; use web_sys::Node; use super::{Key, VChild, VComp, VList, VPortal, VSuspense, VTag, VText}; -use crate::html::BaseComponent; +use crate::html::{BaseComponent, ImplicitClone}; use crate::virtual_dom::VRaw; use crate::AttrValue; @@ -16,25 +17,27 @@ use crate::AttrValue; #[must_use = "html does not do anything unless returned to Yew for rendering."] pub enum VNode { /// A bind between `VTag` and `Element`. - VTag(Box), + VTag(Rc), /// A bind between `VText` and `TextNode`. VText(VText), /// A bind between `VComp` and `Element`. - VComp(VComp), + VComp(Rc), /// A holder for a list of other nodes. - VList(VList), + VList(Rc), /// A portal to another part of the document - VPortal(VPortal), + VPortal(Rc), /// A holder for any `Node` (necessary for replacing node). VRef(Node), /// A suspendible document fragment. - VSuspense(VSuspense), + VSuspense(Rc), /// A raw HTML string, represented by [`AttrValue`](crate::AttrValue). /// /// Also see: [`VNode::from_html_unchecked`] VRaw(VRaw), } +impl ImplicitClone for VNode {} + impl VNode { pub fn key(&self) -> Option<&Key> { match self { @@ -60,9 +63,10 @@ impl VNode { pub fn to_vlist_mut(&mut self) -> &mut VList { loop { match *self { - Self::VList(ref mut m) => return m, + Self::VList(ref mut m) => return Rc::make_mut(m), _ => { - *self = VNode::VList(VList::with_children(vec![mem::take(self)], None)); + *self = + VNode::VList(Rc::new(VList::with_children(vec![mem::take(self)], None))); } } } @@ -105,7 +109,7 @@ impl VNode { impl Default for VNode { fn default() -> Self { - VNode::VList(VList::default()) + VNode::VList(Rc::new(VList::default())) } } @@ -119,35 +123,35 @@ impl From for VNode { impl From for VNode { #[inline] fn from(vlist: VList) -> Self { - VNode::VList(vlist) + VNode::VList(Rc::new(vlist)) } } impl From for VNode { #[inline] fn from(vtag: VTag) -> Self { - VNode::VTag(Box::new(vtag)) + VNode::VTag(Rc::new(vtag)) } } impl From for VNode { #[inline] fn from(vcomp: VComp) -> Self { - VNode::VComp(vcomp) + VNode::VComp(Rc::new(vcomp)) } } impl From for VNode { #[inline] fn from(vsuspense: VSuspense) -> Self { - VNode::VSuspense(vsuspense) + VNode::VSuspense(Rc::new(vsuspense)) } } impl From for VNode { #[inline] fn from(vportal: VPortal) -> Self { - VNode::VPortal(vportal) + VNode::VPortal(Rc::new(vportal)) } } @@ -156,7 +160,7 @@ where COMP: BaseComponent, { fn from(vchild: VChild) -> Self { - VNode::VComp(VComp::from(vchild)) + VNode::VComp(Rc::new(VComp::from(vchild))) } } @@ -168,10 +172,10 @@ impl From for VNode { impl> FromIterator
    for VNode { fn from_iter>(iter: T) -> Self { - VNode::VList(VList::with_children( + VNode::VList(Rc::new(VList::with_children( iter.into_iter().map(|n| n.into()).collect(), None, - )) + ))) } } diff --git a/packages/yew/src/virtual_dom/vportal.rs b/packages/yew/src/virtual_dom/vportal.rs index b0b7b301f5a..ce39e82b9dd 100644 --- a/packages/yew/src/virtual_dom/vportal.rs +++ b/packages/yew/src/virtual_dom/vportal.rs @@ -8,10 +8,10 @@ use super::VNode; pub struct VPortal { /// The element under which the content is inserted. pub host: Element, - /// The next sibling after the inserted content. Most be a child of `host`. + /// The next sibling after the inserted content. Must be a child of `host`. pub inner_sibling: Option, /// The inserted node - pub node: Box, + pub node: VNode, } impl VPortal { @@ -20,7 +20,7 @@ impl VPortal { Self { host, inner_sibling: None, - node: Box::new(content), + node: content, } } @@ -31,7 +31,7 @@ impl VPortal { Self { host, inner_sibling, - node: Box::new(content), + node: content, } } } diff --git a/packages/yew/src/virtual_dom/vraw.rs b/packages/yew/src/virtual_dom/vraw.rs index 366e5248f00..9c8e7a3c46a 100644 --- a/packages/yew/src/virtual_dom/vraw.rs +++ b/packages/yew/src/virtual_dom/vraw.rs @@ -1,3 +1,4 @@ +use crate::html::ImplicitClone; use crate::AttrValue; /// A raw HTML string to be used in VDOM. @@ -6,6 +7,8 @@ pub struct VRaw { pub html: AttrValue, } +impl ImplicitClone for VRaw {} + impl From for VRaw { fn from(html: AttrValue) -> Self { Self { html } diff --git a/packages/yew/src/virtual_dom/vsuspense.rs b/packages/yew/src/virtual_dom/vsuspense.rs index 1ae97b8603a..8167f4fb2e1 100644 --- a/packages/yew/src/virtual_dom/vsuspense.rs +++ b/packages/yew/src/virtual_dom/vsuspense.rs @@ -1,23 +1,26 @@ use super::{Key, VNode}; +use crate::html::ImplicitClone; /// This struct represents a suspendable DOM fragment. #[derive(Clone, Debug, PartialEq)] pub struct VSuspense { /// Child nodes. - pub(crate) children: Box, + pub(crate) children: VNode, /// Fallback nodes when suspended. - pub(crate) fallback: Box, + pub(crate) fallback: VNode, /// Whether the current status is suspended. pub(crate) suspended: bool, /// The Key. pub(crate) key: Option, } +impl ImplicitClone for VSuspense {} + impl VSuspense { pub fn new(children: VNode, fallback: VNode, suspended: bool, key: Option) -> Self { Self { - children: children.into(), - fallback: fallback.into(), + children, + fallback, suspended, key, } diff --git a/packages/yew/src/virtual_dom/vtag.rs b/packages/yew/src/virtual_dom/vtag.rs index 266c1e8f339..0b0d9699049 100644 --- a/packages/yew/src/virtual_dom/vtag.rs +++ b/packages/yew/src/virtual_dom/vtag.rs @@ -1,16 +1,16 @@ //! This module contains the implementation of a virtual element node [VTag]. -use std::borrow::Cow; use std::cmp::PartialEq; use std::marker::PhantomData; use std::mem; use std::ops::{Deref, DerefMut}; use std::rc::Rc; +use wasm_bindgen::JsValue; use web_sys::{HtmlInputElement as InputElement, HtmlTextAreaElement as TextAreaElement}; -use super::{ApplyAttributeAs, AttrValue, Attributes, Key, Listener, Listeners, VNode}; -use crate::html::{IntoPropValue, NodeRef}; +use super::{AttrValue, AttributeOrProperty, Attributes, Key, Listener, Listeners, VNode}; +use crate::html::{ImplicitClone, IntoPropValue, NodeRef}; /// SVG namespace string used for creating svg elements pub const SVG_NAMESPACE: &str = "http://www.w3.org/2000/svg"; @@ -22,9 +22,17 @@ pub const MATHML_NAMESPACE: &str = "http://www.w3.org/1998/Math/MathML"; pub const HTML_NAMESPACE: &str = "http://www.w3.org/1999/xhtml"; /// Value field corresponding to an [Element]'s `value` property -#[derive(Clone, Debug, Eq, PartialEq)] +#[derive(Debug, Eq, PartialEq)] pub(crate) struct Value(Option, PhantomData); +impl Clone for Value { + fn clone(&self) -> Self { + Self::new(self.0.clone()) + } +} + +impl ImplicitClone for Value {} + impl Default for Value { fn default() -> Self { Self::new(None) @@ -68,6 +76,8 @@ pub(crate) struct InputFields { pub(crate) checked: Option, } +impl ImplicitClone for InputFields {} + impl Deref for InputFields { type Target = Value; @@ -111,12 +121,14 @@ pub(crate) enum VTagInner { /// Fields for all other kinds of [VTag]s Other { /// A tag of the element. - tag: Cow<'static, str>, + tag: AttrValue, /// children of the element. children: VNode, }, } +impl ImplicitClone for VTagInner {} + /// A type for a virtual /// [Element](https://developer.mozilla.org/en-US/docs/Web/API/Element) /// representation. @@ -133,10 +145,12 @@ pub struct VTag { pub key: Option, } +impl ImplicitClone for VTag {} + impl VTag { /// Creates a new [VTag] instance with `tag` name (cannot be changed later in DOM). - pub fn new(tag: impl Into>) -> Self { - let tag: Cow<'static, str> = tag.into(); + pub fn new(tag: impl Into) -> Self { + let tag = tag.into(); Self::new_base( match &*tag.to_ascii_lowercase() { "input" => VTagInner::Input(Default::default()), @@ -226,7 +240,7 @@ impl VTag { #[doc(hidden)] #[allow(clippy::too_many_arguments)] pub fn __new_other( - tag: Cow<'static, str>, + tag: AttrValue, node_ref: NodeRef, key: Option, // at bottom for more readable macro-expanded coded @@ -373,17 +387,17 @@ impl VTag { pub fn add_attribute(&mut self, key: &'static str, value: impl Into) { self.attributes.get_mut_index_map().insert( AttrValue::Static(key), - (value.into(), ApplyAttributeAs::Attribute), + AttributeOrProperty::Attribute(value.into()), ); } /// Set the given key as property on the element /// /// [`js_sys::Reflect`] is used for setting properties. - pub fn add_property(&mut self, key: &'static str, value: impl Into) { + pub fn add_property(&mut self, key: &'static str, value: impl Into) { self.attributes.get_mut_index_map().insert( AttrValue::Static(key), - (value.into(), ApplyAttributeAs::Property), + AttributeOrProperty::Property(value.into()), ); } @@ -399,7 +413,7 @@ impl VTag { pub fn __macro_push_attr(&mut self, key: &'static str, value: impl IntoPropValue) { self.attributes.get_mut_index_map().insert( AttrValue::from(key), - (value.into_prop_value(), ApplyAttributeAs::Property), + AttributeOrProperty::Attribute(value.into_prop_value()), ); } diff --git a/packages/yew/src/virtual_dom/vtext.rs b/packages/yew/src/virtual_dom/vtext.rs index beb89acdad7..c1a3d5f38c0 100644 --- a/packages/yew/src/virtual_dom/vtext.rs +++ b/packages/yew/src/virtual_dom/vtext.rs @@ -3,6 +3,7 @@ use std::cmp::PartialEq; use super::AttrValue; +use crate::html::ImplicitClone; /// A type for a virtual /// [`TextNode`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createTextNode) @@ -13,6 +14,8 @@ pub struct VText { pub text: AttrValue, } +impl ImplicitClone for VText {} + impl VText { /// Creates new virtual text node with a content. pub fn new(text: impl Into) -> Self { diff --git a/tools/benchmark-core/Cargo.toml b/tools/benchmark-core/Cargo.toml new file mode 100644 index 00000000000..871323c0700 --- /dev/null +++ b/tools/benchmark-core/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "benchmark-core" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[[bench]] +name = "vnode" +harness = false + +[dependencies] +divan = "0.1.0" +yew = { path = "../../packages/yew" } diff --git a/tools/benchmark-core/benches/vnode.rs b/tools/benchmark-core/benches/vnode.rs new file mode 100644 index 00000000000..ab42bbac211 --- /dev/null +++ b/tools/benchmark-core/benches/vnode.rs @@ -0,0 +1,30 @@ +use yew::prelude::*; + +fn main() { + divan::main(); +} + +#[function_component] +fn Stuff(_: &()) -> Html { + html! { +

    {"A custom component"}

    + } +} + +#[divan::bench(sample_size = 10000000)] +fn vnode_clone(bencher: divan::Bencher) { + let html = html! { +
    + {"Hello"} + {"World"} + + + + +
    + }; + + bencher.bench_local(move || { + let _ = divan::black_box(html.clone()); + }); +} diff --git a/tools/benchmark-ssr/Cargo.toml b/tools/benchmark-ssr/Cargo.toml index 4545148ce7d..4b6ad7e0e4d 100644 --- a/tools/benchmark-ssr/Cargo.toml +++ b/tools/benchmark-ssr/Cargo.toml @@ -8,11 +8,13 @@ edition = "2021" [dependencies] yew = { path = "../../packages/yew", features = ["ssr"] } function_router = { path = "../../examples/function_router" } -tokio = { version = "1.32", features = ["full"] } -jemallocator = "0.5.4" +tokio = { version = "1.33", features = ["full"] } average = "0.14.1" tabled = "0.14.0" indicatif = "0.17.7" -serde = { version = "1.0.188", features = ["derive"] } +serde = { version = "1.0.190", features = ["derive"] } serde_json = "1.0.107" clap = { version = "4", features = ["derive"] } + +[target.'cfg(unix)'.dependencies] +jemallocator = "0.5.4" diff --git a/tools/benchmark-ssr/src/main.rs b/tools/benchmark-ssr/src/main.rs index f2a0dcaad96..cf0ae56e529 100644 --- a/tools/benchmark-ssr/src/main.rs +++ b/tools/benchmark-ssr/src/main.rs @@ -14,6 +14,7 @@ use tokio::task::{spawn_local, LocalSet}; use yew::platform::time::sleep; use yew::prelude::*; +#[cfg(unix)] #[global_allocator] static GLOBAL: jemallocator::Jemalloc = jemallocator::Jemalloc; diff --git a/tools/website-test/Cargo.toml b/tools/website-test/Cargo.toml index a380cd9284d..e24d135286e 100644 --- a/tools/website-test/Cargo.toml +++ b/tools/website-test/Cargo.toml @@ -18,7 +18,7 @@ wasm-bindgen-futures = "0.4" weblog = "0.3.0" yew = { path = "../../packages/yew/", features = ["ssr", "csr"] } yew-router = { path = "../../packages/yew-router/" } -tokio = { version = "1.32.0", features = ["rt", "macros"] } +tokio = { version = "1.33.0", features = ["rt", "macros"] } [dev-dependencies.web-sys] version = "0.3" diff --git a/website/docs/concepts/function-components/generics.mdx b/website/docs/concepts/function-components/generics.mdx index 758757b5ad6..d36805704b1 100644 --- a/website/docs/concepts/function-components/generics.mdx +++ b/website/docs/concepts/function-components/generics.mdx @@ -10,7 +10,7 @@ The `#[function_component]` attribute also works with generic functions for crea ```rust use std::fmt::Display; -use yew::{function_component, html, Properties, Html, ToHtml}; +use yew::{function_component, html, Properties, Html}; #[derive(Properties, PartialEq)] pub struct Props @@ -23,11 +23,11 @@ where #[function_component] pub fn MyGenericComponent(props: &Props) -> Html where - T: PartialEq + ToHtml, + T: PartialEq + Clone + Into, { html! {

    - { &props.data } + { props.data.clone().into() }

    } } diff --git a/website/docs/concepts/html/introduction.mdx b/website/docs/concepts/html/introduction.mdx index 8886778e87d..729db102dd8 100644 --- a/website/docs/concepts/html/introduction.mdx +++ b/website/docs/concepts/html/introduction.mdx @@ -204,7 +204,7 @@ Read more at [Lists](./html/lists) ## Conditional Rendering -Markup can be rendered conditonally by using Rust's conditional structures. ' + +Markup can be rendered conditionally by using Rust's conditional structures. ' + 'Currently only `if` and `if let` are supported. ```rust @@ -218,5 +218,5 @@ html! { ``` :::info -Read more at [Conditonal Rendering](./conditional-rendering.mdx) +Read more at [Conditional Rendering](./conditional-rendering.mdx) ::: diff --git a/website/docs/getting-started/editor-setup.mdx b/website/docs/getting-started/editor-setup.mdx index 241d12e5f60..dc0fbf6f634 100644 --- a/website/docs/getting-started/editor-setup.mdx +++ b/website/docs/getting-started/editor-setup.mdx @@ -128,7 +128,7 @@ Utilities like Rename, Go to Declaration, Find Usages will work inside the macro > This is a **work in progress**, and **community maintained** project! [Please see details and direct related bug reports / issues / questions over to the extension's repository](https://github.com/TechTheAwesome/code-yew-server) -Rust-Yew extension is [avaliable on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlight, renames, hover, and more. +Rust-Yew extension is [available on VSC Marketplace](https://marketplace.visualstudio.com/items?itemName=TechTheAwesome.rust-yew), providing syntax highlight, renames, hover, and more. Emmet support should work out of the box, if not please fall back to edditing the `settings.json` file: diff --git a/website/docs/migration-guides/yew/from-0_20_0-to-0_21_0.mdx b/website/docs/migration-guides/yew/from-0_20_0-to-0_21_0.mdx index 92558ded8c3..980b59a43ad 100644 --- a/website/docs/migration-guides/yew/from-0_20_0-to-0_21_0.mdx +++ b/website/docs/migration-guides/yew/from-0_20_0-to-0_21_0.mdx @@ -25,8 +25,8 @@ sg --pattern 'use_callback($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_callback( sg --pattern 'use_memo($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_memo($$$DEPENDENCIES, $CALLBACK)' -l rs -i sg --pattern 'use_memo($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_memo($DEPENDENCIES,$$$CALLBACK)' -l rs -i -sg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_effect_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i -sg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_effect_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i +sg --pattern 'use_future_with_deps($CALLBACK,$$$DEPENDENCIES)' --rewrite 'use_future_with($$$DEPENDENCIES, $CALLBACK)' -l rs -i +sg --pattern 'use_future_with($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_future_with($DEPENDENCIES,$$$CALLBACK)' -l rs -i sg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i sg --pattern 'use_transitive_state!($DEPENDENCIES,,$$$CALLBACK)' --rewrite 'use_transitive_state!($DEPENDENCIES,$$$CALLBACK)' -l rs -i diff --git a/website/package-lock.json b/website/package-lock.json index efc8218e3b3..d4b1c425bdb 100644 --- a/website/package-lock.json +++ b/website/package-lock.json @@ -12,7 +12,6 @@ "@docusaurus/plugin-client-redirects": "^2.4.3", "@docusaurus/plugin-content-docs": "^2.4.3", "@docusaurus/plugin-content-pages": "^2.4.3", - "@docusaurus/plugin-google-analytics": "^2.4.3", "@docusaurus/plugin-google-gtag": "^2.4.3", "@docusaurus/theme-classic": "^2.4.3", "@easyops-cn/docusaurus-search-local": "^0.32.0", @@ -52,16 +51,81 @@ } }, "node_modules/@babel/code-frame": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.21.4.tgz", - "integrity": "sha512-LYvhNKfwWSPpocw8GI7gpK2nq3HSDuEPC/uSYaALSJu9xjsalaaYFOq0Pwt5KmVqwEbZlDu81aLXwBOmD/Fv9g==", + "version": "7.22.13", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz", + "integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==", "dependencies": { - "@babel/highlight": "^7.18.6" + "@babel/highlight": "^7.22.13", + "chalk": "^2.4.2" }, "engines": { "node": ">=6.9.0" } }, + "node_modules/@babel/code-frame/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/code-frame/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/@babel/code-frame/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/code-frame/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/@babel/compat-data": { "version": "7.21.4", "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.4.tgz", @@ -108,11 +172,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.4.tgz", - "integrity": "sha512-NieM3pVIYW2SwGzKoqfPrQsf4xGs9M9AIG3ThppsSRmO+m7eQhmI6amajKMUeIO37wFfsvnvcxQFx6x6iqxDnA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz", + "integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==", "dependencies": { - "@babel/types": "^7.21.4", + "@babel/types": "^7.23.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -244,9 +308,9 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.18.9", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz", - "integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", "engines": { "node": ">=6.9.0" } @@ -263,23 +327,23 @@ } }, "node_modules/@babel/helper-function-name": { - "version": "7.21.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz", - "integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", "dependencies": { - "@babel/template": "^7.20.7", - "@babel/types": "^7.21.0" + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz", - "integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" @@ -400,28 +464,28 @@ } }, "node_modules/@babel/helper-split-export-declaration": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz", - "integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==", + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", "dependencies": { - "@babel/types": "^7.18.6" + "@babel/types": "^7.22.5" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-string-parser": { - "version": "7.19.4", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz", - "integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==", + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz", + "integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==", "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.19.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz", - "integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", "engines": { "node": ">=6.9.0" } @@ -462,12 +526,12 @@ } }, "node_modules/@babel/highlight": { - "version": "7.18.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", - "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz", + "integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==", "dependencies": { - "@babel/helper-validator-identifier": "^7.18.6", - "chalk": "^2.0.0", + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", "js-tokens": "^4.0.0" }, "engines": { @@ -539,9 +603,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.4.tgz", - "integrity": "sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz", + "integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1789,31 +1853,31 @@ } }, "node_modules/@babel/template": { - "version": "7.20.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz", - "integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==", + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz", + "integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==", "dependencies": { - "@babel/code-frame": "^7.18.6", - "@babel/parser": "^7.20.7", - "@babel/types": "^7.20.7" + "@babel/code-frame": "^7.22.13", + "@babel/parser": "^7.22.15", + "@babel/types": "^7.22.15" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.4.tgz", - "integrity": "sha512-eyKrRHKdyZxqDm+fV1iqL9UAHMoIg0nDaGqfIOd8rKH17m5snv7Gn4qgjBoFfLz9APvjFU/ICT00NVCv1Epp8Q==", - "dependencies": { - "@babel/code-frame": "^7.21.4", - "@babel/generator": "^7.21.4", - "@babel/helper-environment-visitor": "^7.18.9", - "@babel/helper-function-name": "^7.21.0", - "@babel/helper-hoist-variables": "^7.18.6", - "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.4", - "@babel/types": "^7.21.4", + "version": "7.23.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz", + "integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==", + "dependencies": { + "@babel/code-frame": "^7.22.13", + "@babel/generator": "^7.23.0", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.23.0", + "@babel/types": "^7.23.0", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -1822,12 +1886,12 @@ } }, "node_modules/@babel/types": { - "version": "7.21.4", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.4.tgz", - "integrity": "sha512-rU2oY501qDxE8Pyo7i/Orqma4ziCOrby0/9mvbDUGEfvZjb279Nk9k19e2fiCxHbRRpY2ZyrgW1eq22mvmOIzA==", + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz", + "integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==", "dependencies": { - "@babel/helper-string-parser": "^7.19.4", - "@babel/helper-validator-identifier": "^7.19.1", + "@babel/helper-string-parser": "^7.22.5", + "@babel/helper-validator-identifier": "^7.22.20", "to-fast-properties": "^2.0.0" }, "engines": { @@ -2348,24 +2412,6 @@ "react-dom": "^16.8.4 || ^17.0.0" } }, - "node_modules/@docusaurus/plugin-google-analytics": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-analytics/-/plugin-google-analytics-2.4.3.tgz", - "integrity": "sha512-KzBV3k8lDkWOhg/oYGxlK5o9bOwX7KpPc/FTWoB+SfKhlHfhq7qcQdMi1elAaVEIop8tgK6gD1E58Q+XC6otSQ==", - "dependencies": { - "@docusaurus/core": "2.4.3", - "@docusaurus/types": "2.4.3", - "@docusaurus/utils-validation": "2.4.3", - "tslib": "^2.4.0" - }, - "engines": { - "node": ">=16.14" - }, - "peerDependencies": { - "react": "^16.8.4 || ^17.0.0", - "react-dom": "^16.8.4 || ^17.0.0" - } - }, "node_modules/@docusaurus/plugin-google-gtag": { "version": "2.4.3", "resolved": "https://registry.npmjs.org/@docusaurus/plugin-google-gtag/-/plugin-google-gtag-2.4.3.tgz", @@ -9750,9 +9796,9 @@ } }, "node_modules/postcss": { - "version": "8.4.21", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz", - "integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==", + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "funding": [ { "type": "opencollective", @@ -9761,10 +9807,14 @@ { "type": "tidelift", "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" } ], "dependencies": { - "nanoid": "^3.3.4", + "nanoid": "^3.3.6", "picocolors": "^1.0.0", "source-map-js": "^1.0.2" },